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