1 /***************************************************************************
2                           rkcomponent  -  description
3                              -------------------
4     begin                : Tue Dec 13 2005
5     copyright            : (C) 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2014 by Thomas Friedrichsmeier
6     email                : thomas.friedrichsmeier@kdemail.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef RKCOMPONENT_H
19 #define RKCOMPONENT_H
20 
21 #include <QHash>
22 #include <qmap.h>
23 #include <qwidget.h>
24 
25 class RKComponentPropertyBase;
26 class RKStandardComponent;
27 
28 /** a very low level base for RKComponent and RKComponentProperty. */
29 class RKComponentBase {
30 public:
31 /** constructor */
RKComponentBase()32 	RKComponentBase () { required=true; is_internal=false; };
33 /** destructor */
~RKComponentBase()34 	virtual ~RKComponentBase () {};
35 /** enum of types of properties. Used from RTTI. Don't change the values, as there are some range checks in the code (see isProperty ()) */
36 	enum RKComponentTypes {
37 		PropertyBase = 1,
38 		PropertyBool = 2,
39 		PropertyInt = 3,
40 		PropertyDouble = 4,
41 		PropertyRObjects = 5,
42 		PropertyCode = 6,
43 		PropertyConvert = 7,
44 		PropertyStringList = 8,
45 		PropertySwitch = 9,
46 		PropertyUser = 1000,		/**< for user expansion */
47 		PropertyEnd = 1999,
48 		ComponentBase = 2001,
49 		Component = 2002,
50 		ComponentVarSelector = 2003,
51 		ComponentVarSlot = 2004,
52 		ComponentFormula = 2005,
53 		ComponentRadio = 2006,
54 		ComponentCheckBox = 2007,
55 		ComponentSpinBox = 2008,
56 		ComponentInput = 2009,
57 		ComponentBrowser = 2010,
58 		ComponentText = 2011,
59 		ComponentTab = 2012,
60 		ComponentDropDown = 2013,
61 		ComponentPreviewBox = 2014,
62 		ComponentSaveObject = 2015,
63 		ComponentFrame = 2016,
64 		ComponentOptionSet = 2017,
65 		ComponentMatrixInput = 2018,
66 		ComponentValueSelector = 2019,
67 		ComponentStandard = 2100,
68 		ComponentContextHandler = 2900,
69 		ComponentUser = 3000	/**< for user expansion */
70 	};
71 	enum UnserializeError {
72 		NoError,
73 		BadFormat,
74 		NotAllSettingsApplied,
75 		NoSuchComponent
76 	};
77 	enum ComponentStatus {
78 		Dead,		/**< one or more components are dead */
79 		Processing,		/**< one or more components are still processing. */
80 		Unsatisfied,		/**< the component is required, but it or one of its (required) children are not valid. */
81 		Satisfied		/**< the component is not required, or it, and all of its children are satisfied. */
82 	};
83 /** for RTTI. see RKComponentBase::RKComponentTypes */
84 	virtual int type () = 0;
85 /** tries to locate a component (or property) described by identifier as a child (of any generation) of this RKComponentBase. If found, a pointer to this is returned. Also, the modifier parameter is set to hold any remaining modifier contained in the identifier.
86 @param identifier The identifier string to look for (including a potential modifier suffix).
87 @param remainder If a non null pointer to QString is given, this will be set to the value of the remaining modifier
88 @returns a pointer to the RKComponentBase, if found, or the nearest parent that could be looked up */
89 	virtual RKComponentBase* lookupComponent (const QString &identifier, QString *remainder);
90 /** Convenience wrapper around lookupComponent(), which will only return properties or 0, and optionally warn, if no prop could be found
91 @param remainder In contrast to lookupComponent, this can be 0. In this case only exact matches are returned. */
92 	RKComponentPropertyBase* lookupProperty (const QString &identifier, QString *remainder=0, bool warn=true);
93 /** Locate the component.subcomponent.property.value described by identifier and return its value as a string. Especially useful as a callback in code templates! Recursively walks subcomponents/properties until the requested value is found. @See RKComponentBase::lookupComponent */
94 	QString fetchStringValue (const QString &identifier);
95 	static QString fetchStringValue (RKComponentBase* prop, const QString &modifier=QString ());
96 /** returns the "value" of this component or property. Properties generally return their value, components typically return the value of their "most important" property. Default implementation returns QString (), and writes a debug message */
97 	virtual QVariant value (const QString &modifier=QString ());
98 	enum ValueTypeHint {
99 		TraditionalValue,
100 		BooleanValue,
101 		StringValue,
102 		StringlistValue,
103 		NumericValue,
104 		UiLabelPair
105 	};
106 	QVariant fetchValue (const QString &identifier, const int type_hint);
getUiLabelPair()107 	virtual QStringList getUiLabelPair () const { return QStringList (); };
108 /** returns true, if this is a property */
isProperty()109 	bool isProperty () { return (type () <= PropertyEnd); };
isComponent()110 	bool isComponent () { return (type () >= ComponentBase); };
111 /** shorthand for recursiveStatus () == Satisfied */
isSatisfied()112 	bool isSatisfied () { return (recursiveStatus () == Satisfied); };
113 /** returns state of the component. @see ComponentStatus */
114 	virtual ComponentStatus recursiveStatus ();
115 /** currently valid? default implementation always returns true. @see recursiveStatus()
116   * reimplement this in subclasses, if components may become invalid.
117   *
118   * @note: A component will be "satisfied" even when invalid, if is is not required. Also, a required component is implicitly not satisfied, if any of its children are not satisfied.
119   * In general, use isSatisfied() to query the status of components, not isValid(). */
isValid()120 	virtual bool isValid () { return true; };
121 /** set to required: will only be satisfied if it is valid (and all it's children). Else: always satisfied (but subclasses might override to always be dissatisfied on really bad values. By default RKComponentBase is required at construction */
setRequired(bool require)122 	void setRequired (bool require) { required = require; };
123 /** simple convenience function to add a child to the map of children */
124 	virtual void addChild (const QString &id, RKComponentBase *child);
125 
126 	typedef QMap<QString, QString> PropertyValueMap;
127 	static QString valueMapToString (const PropertyValueMap &map);
128 	static bool stringListToValueMap (const QStringList &strings, PropertyValueMap *map);
129 /** serialize the state of this component / property and all its children. Note: Only the non-internal property-values are serialized, not the components / properties themselves. @see fetchPropertyValuesRecursive() */
serializeState(PropertyValueMap * map)130 	void serializeState (PropertyValueMap *map) const { fetchPropertyValuesRecursive (map, true); };
131 /** set values from a map as created with serializeState(). @see serializeState (), @see setPropertyValues ().
132 @returns status code */
applyState(const PropertyValueMap & state)133 	void applyState (const PropertyValueMap &state) { setPropertyValues (&state, true); };
134 	QStringList matchAgainstState (const PropertyValueMap &state);
135 
136 /** Some properties/components will be marked as internal, such as visibility properties, which are not meant to be set directly by the user. These will be ignored in RKComponent::fetchPropertyValuesRecursive() */
setInternal(bool internal)137 	void setInternal (bool internal) { is_internal = internal; };
isInternal()138 	bool isInternal () const { return is_internal; };
139 protected:
140 friend class RKOptionSet;
141 	QHash<QString, RKComponentBase*> child_map;
142 	bool required;
143 /** recursively fetch the current values of all properties present as direct or indirect children of this component. Used to transfer values e.g. when switching interfaces (or to store settings per plugin in the future). Values are placed in the dictionary provided (be sure to create one first!). Internal properties are ignored (@see RKComponentPropertyBase::isInternal ());
144 @param list the list to store the object values in
145 @param include_top_level include direct properties of the component in the list (or only properties of children)
146 @param prefix used during recursion to provide full ids for the added objects
147 @param include_inactive_elements by default, disabled / hidden elements are omitted from the value map. */
148 	virtual void fetchPropertyValuesRecursive (PropertyValueMap *list, bool include_top_level=false, const QString &prefix=QString (), bool include_inactive_elements=false) const;
149 	friend class RKComponentBuilder;
150 /** counterpart to fetchPropertyValuesRecursive (). Tries to apply all values from the list to properties of the given names. If some keys can not be found, or do not resolve to properties, they are ignored.
151 @param list a list of id->value such as generated by fetchPropertyValuesRecursive () */
152 	void setPropertyValues (const PropertyValueMap *list, bool warn = false);
153 private:
154 	bool is_internal;
155 };
156 
157 #include "rkcomponentproperties.h"
158 
159 class XMLHelper;
160 /** abstract base class of all RKComponents, including component widgets */
161 class RKComponent : public QWidget, public RKComponentBase {
162 	Q_OBJECT
163 public:
164 /** constructor.
165 @param parent_component The parent RKComponent. If 0, this RKComponent will be a top-level component
166 @param parent_widget The parent QWidget. This may be the same as the parent_component or a different specific widget.. If 0, this RKComponent will be represented by a top-level widget */
167 	RKComponent (RKComponent *parent_component, QWidget *parent_widget);
168 /** destructor */
169 	virtual ~RKComponent ();
type()170 	int type () override { return Component; };
171 /** change notification mechanism. Call this, if something in the component changed that could result in a change in code/values/satisfaction state. Default implementation propagates the change upwards to parent components, if any, but does not do anything further. Reimplement, for instance, to regenerate code */
172 	virtual void changed ();
173 /** The component as a wizardish (multi-page) interface. Default implementation returns false */
174 	virtual bool isWizardish ();
175 /** If the component isWizardish (), returns true, if it has a next/previous page
176 @param next if true, returns true, if there is a next page (i.e. not at last page). If false, returns true if there is a previous page (i.e. not at first page). False otherwise. Default implementation returns false at all times. */
177 	virtual bool havePage (bool next);
178 /** go to page
179 @param next if true, go to next (shown) page, if false go to previous (shown) page. Default implementation does nothing */
180 	virtual void movePage (bool next);
181 /** returns true, if the current page is satisfied (see isWizardish ()). Default implementation returns isSatisfied () */
currentPageSatisfied()182 	virtual bool currentPageSatisfied () { return (isSatisfied ()); };
183 /** add a Page to the component. Don't worry, you'll only have to implement this is a meaningful way, if your component isWizardish (). Default implementation simply returns a new RKComponent (and raises an assert). */
184 	virtual RKComponent *addPage ();
185 /** For wizardish guis: this gets called to register a component on the current page during construction. The component does not get reparented. It will have to be satisfied in order to move to the next page in the wizard. See isWizardish () see addPage (). Default implementation does nothing. */
186 	virtual void addComponentToCurrentPage (RKComponent *component);
187 /** @returns true if the component is inactive, i.e. disabled, or hidden in the GUI */
188 	bool isInactive ();
189 public slots:
190 /** This handles changes in the default properties (enabledness, visibility, requiredness). You will use similar slots in derived classes to handle
191 specialized properties */
192 	void propertyValueChanged (RKComponentPropertyBase *property);
193 /** If you add an outside property to a component, connect it to this slot, so the component will update itself. used in RKComponentBuilder::parseLogic () */
outsideValueChanged(RKComponentPropertyBase *)194 	void outsideValueChanged (RKComponentPropertyBase *) { changed (); }
195 public:
196 /** standard property controlling visibility */
visibilityProperty()197 	RKComponentPropertyBool *visibilityProperty () { return visibility_property; };
198 /** standard property controlling enabledness */
enablednessProperty()199 	RKComponentPropertyBool *enablednessProperty () { return enabledness_property; };
200 /** standard property controlling requiredness */
requirednessProperty()201 	RKComponentPropertyBool *requirednessProperty ()  { return requiredness_property; };
202 
203 /** convenience call to set requiredness property (and hence requiredness of this component) */
204 	void setRequired (bool required);
205 
206 /** The parent of this component. Should be notified, whenever isSatisfied () or recursiveStatus () changed. */
parentComponent()207 	RKComponent *parentComponent () const { return _parent; };
208 /** The standard component containing this component (if any). If @param id_adjust is given, it will be set to a relative path to the standard component. */
209 	RKStandardComponent *standardComponent (QString *id_adjust=0) const;
210 /** Like standardcomponent, but will return the topmost component in case of embedding. */
211 	RKStandardComponent *topmostStandardComponent ();
212 /** Return a properly initialize helper for parsing XML in this component. */
213 	XMLHelper *xmlHelper () const;
214 
215 /** Find the id of this component. NOTE: this is slow. Better to store the id in the first place, if needed */
216 	QString getIdInParent () const;
217 protected slots:
218 /** if a child component self-destructs, it should remove itself from its parent *before* destructing. Don't use in a regular destructor. Call only if the child dies unexpectedly */
219 	void removeFromParent ();
220 signals:
221 /** emitted from changed() */
222 	void componentChanged (RKComponent* component);
223 protected:
224 	RKComponentPropertyBool *visibility_property;
225 	RKComponentPropertyBool *enabledness_property;
226 	RKComponentPropertyBool *requiredness_property;
227 	RKComponent *_parent;
228 /** usually happens during construction, so you don't need to call this - unless you're RKStandardComponent, and discard the children at some point of time */
229 	void createDefaultProperties ();
230 /** This function is needed internally, to set the Qt enabledness of this widget, and all child component widgets. Note that the enabledness as stored in the enabledness_property is not necessarily the same as the enabledness in the GUI (and is not affected by this call). In general, a component is enabled in the GUI, if and only if a) it's enabledness_property is set to true, b) its parent widget is enabled in Qt, and c) it's parent component is also enabled. */
231 	void updateEnablednessRecursive (bool parent_component_enabled);
232 /** Helper for getUiLabelPair(): Strips accelerator key markup ("&") from strings */
233 	static QString stripAccelerators (const QString &in);
234 };
235 
236 #endif
237 
238