1 /***************************************************************************
2  *   file klfpobj.h
3  *   This file is part of the KLatexFormula Project.
4  *   Copyright (C) 2011 by Philippe Faist
5  *   philippe.faist at bluewin.ch
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21  ***************************************************************************/
22 /* $Id: klfpobj.h 991 2017-01-04 09:15:43Z phfaist $ */
23 
24 
25 #ifndef KLFPOBJ_H
26 #define KLFPOBJ_H
27 
28 #include <QDebug>
29 #include <QVariant>
30 #include <QByteArray>
31 #include <QDataStream>
32 #include <QTextStream>
33 #include <QVector>
34 #include <QList>
35 #include <QMap>
36 #include <QStringList>
37 
38 #include <klfdefs.h>
39 
40 
41 
42 
43 /** \brief An abstract object characterized by properties
44  *
45  * This class is an interface to get and set property values for objects like
46  * KLFPropertizedObject, QObject, QVariantMap-based, which store their information
47  * as logical properties.
48  *
49  * Such objects should either inherit explicitely this class, or should provide
50  * an adapter class (eg. as for QObject).
51  *
52  * This class was developed in the general idea of trying to avoid version issues
53  * in data formats, and storing everything as properties in a coherent form, eg. XML.
54  * See klfSave() and klfLoad().
55  *
56  * QDataStream operators are implemented for this object.
57  */
58 class KLF_EXPORT KLFAbstractPropertizedObject
59 {
60 public:
61   KLFAbstractPropertizedObject();
62   virtual ~KLFAbstractPropertizedObject();
63 
64   /** \brief A string representing this object type
65    *
66    * The string should be short, and contain only alphanumeric characters (a good idea
67    * is to give the class name here).
68    *
69    * This is used for example as node name in XML exports.
70    */
71   virtual QString objectKind() const = 0;
72 
73   /** \brief get a property's value
74    *
75    * \returns the value of the given property, as a QVariant.
76    */
77   virtual QVariant property(const QString& propName) const = 0;
78 
79   /** \brief Queries what property are (or can be) set
80    *
81    * This function should return a list of property names that have been explicitely
82    * set on this object.
83    */
84   virtual QStringList propertyNameList() const = 0;
85 
86   /** \brief Assign a value to a property
87    *
88    * It is up to the subclasse to implement this function.
89    *
90    * This function checks that the given property \c pname is allowed to be modified to
91    * the new value \c value. If this is not the case, returns FALSE. Otherwise, this
92    * function tries to save the new value for the given property.
93    *
94    * \returns TRUE if the property was successfully saved, FALSE if the property was not
95    *   allowed to be modified or if the new value could not be set.
96    */
97   virtual bool setProperty(const QString& pname, const QVariant& value) = 0;
98 
99 
100   /** \brief Convenience function to retrieve all properties
101    *
102    * This function returns all the properties that have been set on this object with
103    * their corresponding values.
104    *
105    * The default implementation uses propertyNameList() and property() to generate
106    * the required return value. It should be enough for most cases. If you really want
107    * to however, you can reimplement this function for your needs. */
108   virtual QMap<QString,QVariant> allProperties() const;
109 
110   /** \brief Convenience function to load a set of property values
111    *
112    * This function tries to set all the properties given in \c data. If one or more
113    * \c setProperty() call failed, then this function returns FALSE. TRUE is returned
114    * when all properties were set successfully.
115    *
116    * The default implementation uses propertyNameList() and setProperty() to set all the
117    * given properties.
118    *
119    * Subclasses may be interested in reimplementing this function in order to garantee
120    * the the properties are set in a correct order. This might be necessary in some cases
121    * where you are allowed to set a given property depending on the value of another, for
122    * example a "Locked" property.
123    */
124   virtual bool setAllProperties(const QMap<QString,QVariant>& data);
125 
126   /** \returns TRUE if a all properties have fixed types, i.e. a given property can only
127    * contain a value of a certain type.
128    */
hasFixedTypes()129   virtual bool hasFixedTypes() const { return false; }
130 
131   /** \brief Corresonding type for the given property
132    *
133    * This function is only relevant if hasFixedTypes() returns TRUE.
134    */
typeNameFor(const QString & property)135   virtual QByteArray typeNameFor(const QString& property) const { Q_UNUSED(property); return QByteArray(); }
136 
137   /** \brief A type specification for the given property
138    *
139    * A type specification is some additional data that specifies further the type. For example,
140    * a type KLFEnumType has to be specified to which enum values are allowed.
141    *
142    * This is only used for types that derive KLFSpecifyableType.
143    */
typeSpecificationFor(const QString & property)144   virtual QByteArray typeSpecificationFor(const QString& property) const { Q_UNUSED(property); return QByteArray(); }
145 };
146 
147 
148 class KLF_EXPORT KLFSpecifyableType
149 {
150 public:
151   KLFSpecifyableType();
152   virtual ~KLFSpecifyableType();
153 
154   virtual QByteArray specification() const = 0;
155   virtual bool setSpecification(const QByteArray& data) = 0;
156 };
157 
158 
159 class KLF_EXPORT KLFEnumType : public KLFSpecifyableType
160 {
161   int val;
162   QStringList enumVals;
163 public:
val(initvalue)164   KLFEnumType(int initvalue = 0) : val(initvalue), enumVals()
165   {
166   }
KLFEnumType(const KLFEnumType & copy)167   KLFEnumType(const KLFEnumType& copy) : KLFSpecifyableType(), val(copy.val), enumVals(copy.enumVals)
168   {
169   }
~KLFEnumType()170   virtual ~KLFEnumType() { }
171 
value()172   inline int value() const
173   {
174     return val;
175   }
setValue(int v)176   inline void setValue(int v)
177   {
178     val = v;
179   }
180 
enumValue()181   inline QString enumValue() const
182   {
183     if (val < 0 || val >= enumVals.size()) {
184       klfWarning("Invalid value: "<<val<<" for enum values "<<enumVals) ;
185       return QString();
186     }
187     return enumVals[val];
188   }
189 
190 
enumValues()191   inline QStringList enumValues() const
192   {
193     return enumVals;
194   }
setEnumValues(const QStringList & list)195   inline void setEnumValues(const QStringList& list)
196   {
197     enumVals = list;
198   }
199 
specification()200   QByteArray specification() const
201   {
202     return enumVals.join(":").toUtf8();
203   }
204 
setSpecification(const QByteArray & data)205   bool setSpecification(const QByteArray& data)
206   {
207     // parse enum values
208     setEnumValues(QString::fromUtf8(data).split(QRegExp(":")));
209     return true;
210   }
211 
212 };
213 
214 
215 Q_DECLARE_METATYPE(KLFEnumType) ;
216 
217 KLF_EXPORT QDataStream& operator<<(QDataStream& stream, const KLFEnumType& e);
218 KLF_EXPORT QDataStream& operator>>(QDataStream& stream, KLFEnumType& e);
219 // exact matches
220 inline bool operator==(const KLFEnumType& a, const KLFEnumType& b)
221 { return a.value() == b.value(); }
222 
223 
224 
225 
226 class KLFPObjPropRefHelper;
227 
228 
229 /** \brief A class that holds properties.
230  *
231  * This class is meant to be subclassed to create objects that need to store
232  * properties. For an example, see KLFLibEntry in the klfapp library.
233  *
234  * Properties are stored in \ref QVariant "QVariant"s, are referenced either by an
235  * integer ID or a QString name.
236  *
237  * A subclass will be an object of a given logical type, say a library entry. It may
238  * want to store a few standard properties (Latex string, Preview image, Category and
239  * Tags string, etc.). However, eg. plugins may be able to store and understand
240  * more advanced properties (say the icon's position when viewed in an icon view) than
241  * what the base class KLFLibEntry had anticipated. In that case, the property needs
242  * to be registered statically with \ref registerProperty() or
243  * \ref registerBuiltInProperty(). Properties are registered statically, that means
244  * that all instances of, say a KLFLibEntry, always share the same property ID and names,
245  * even though they each store different values for them.
246  *
247  * Property values may be queried with property(const QString&) const or
248  * property(int propId) const , and may be set with \ref setProperty().
249  *
250  * Subclasses should override setProperty() to add checks as to whether the user is indeed
251  * allowed to set the given property to the given value, and then calling the protected
252  * doSetProperty() or doLoadProperty() functions. Subclasses may also provide their
253  * own public API for setting and/or registering property values, which could directly call
254  * setProperty() with the relevant property name.
255  *
256  * All instances of a given subclass, say a KLFLibEntry, have values assigned to all
257  * registered properties. By default, their values are an invalid QVariant: <tt>QVariant()</tt>.
258  *
259  * \warning the IDs may not be conserved between two instances or versions of KLatexFormula,
260  *   because they may be attributed dynamically, or values in a static enum may change from one
261  *   version of, say a KLFLibEntry, to another. When exporting property values, always use the
262  *   string identifier (see for example \ref allProperties())
263  *
264  * <b>What is the <i>Property Name Space</i>?</b> The Property Name Space is a string identifying
265  * the type of object an instance belongs to. This will typically be the subclass name. Since
266  * all registered properties are stored (the names and IDs, not the values (!)) statically in this
267  * object, different subclasses must access different registered properties, and that is what the
268  * &quot;property name spaces&quot; are meant for. Subclasses specify once and for all the property
269  * name space to the \ref KLFPropertizedObject(const QString&) constructor, then they can forget
270  * about it. Other classes than the direct subclass don't have to know about property name spaces.
271  *
272  * \note For fast access, the property values are stored in a \ref QVector&lt;\ref QVariant&gt;.
273  *   The \c propId is just an index in that vector. Keep that in mind before defining static
274  *   high property IDs. Since property IDs are not fixed, it is better to have the static property
275  *   IDs defined contiguously in an enum.
276  */
277 class KLF_EXPORT KLFPropertizedObject : public KLFAbstractPropertizedObject
278 {
279 public:
280   /** Constructs a KLFPropertizedObject, that implements an object of the kind
281    * \c propertyNameSpace. See the \ref KLFPropertizedObject "Class Documentation" for more
282    * information on property name spaces. */
283   explicit KLFPropertizedObject(const QString& propertyNameSpace);
284   virtual ~KLFPropertizedObject();
285 
286   /** Returns the value of the property designated by the name \c propName, in this current
287    * object instance.
288    *
289    * If the property has not been registered, a warning is printed and this function returns
290    * an invalid QVariant.
291    *
292    * If the property has not yet been set, an invalid QVariant() is returned.
293    */
294   virtual QVariant property(const QString& propName) const;
295   /** Returns the value of the property designated by its ID \c propId in this current object
296    * instance.
297    *
298    * If no value was previously set for the given property, and the property has been registered,
299    * returns an invalid QVariant().
300    *
301    * This function does not check that \c propId has been registered. However the worst that
302    * can happen is that an invalid QVariant() is returned.
303    */
304   virtual QVariant property(int propId) const;
305   /** \brief Get value of a property, with default value
306    *
307    * Returns the value of the property \c propName, if this property name has been registered and
308    * a value set.
309    *
310    * If the property name has not been registered, or if the property value is not valid
311    * (see \ref QVariant::isValid()), then the value \c defaultValue is returned as is.
312    *
313    * This function does not fail or emit warnings.
314    */
315   virtual QVariant property(const QString& propName, const QVariant& defaultValue) const;
316   /** \brief Tests if a property was set
317    *
318    * Returns TRUE if the property \c propName was registered and a non-invalid value set; returns
319    * FALSE otherwise.
320    *
321    * This function does not fail or emit warnings. This function calls property(const QString&, const QVariant&).
322    */
323   virtual bool hasPropertyValue(const QString& propName) const;
324   /** \brief Tests if a property was set
325    *
326    * Returns TRUE if the property \c propId was registered and a non-invalid value set; returns
327    * FALSE otherwise.
328    *
329    * This function does not fail or emit warnings. This function calls hasPropertyValue(const QString&).
330    */
331   virtual bool hasPropertyValue(int propId) const;
332 
333   /** \brief A list of properties that have been set.
334    *
335    * \returns list of the IDs of all properties that have been set on this object. The
336    *   values of these properties are NOT included in the returned list.
337    *
338    * More exactly: returns all property IDs that have a valid (see \ref QVariant::isValid())
339    * value in this object.
340    */
341   QList<int> propertyIdList() const;
342 
343   /** \brief A list of properties that have been set.
344    *
345    * Similar to \ref propertyIdList() but returns property names.
346    *
347    * \returns list of the names of all properties that have been set on this object.
348    *   values of these properties are not included in the list... */
349   QStringList propertyNameList() const;
350 
351   /** \brief Returns all properties that have been set.
352    *
353    * \returns a QMap of all properties (and their values) that have been set on this
354    * object, values stored by property name. */
355   QMap<QString,QVariant> allProperties() const;
356 
357   /** \brief Sets the given property to the given value
358    *
359    * If propname is not registered, this function tries to register the property.
360    *
361    * Subclasses should reimplement this function to provide tests as to whether the user
362    * is allowed to modify the given property with the given value, and then actually
363    * set the property and register it if needed.
364    *
365    * The default implementation just calls doLoadProperty() without any checks.
366    *
367    * This function is an implementation of the KLFAbstractPropertizedObject::setProperty()
368    * pure virtual function. */
369   virtual bool setProperty(const QString& propname, const QVariant& value);
370 
371   /** \brief Sets the given property to the given value
372    *
373    * Calls setProperty(const QString&, const QVariant&) with the relevant property
374    * name. Thus, in principle, subclasses only need to reimplement the other method.
375    */
376   virtual bool setProperty(int propId, const QVariant& value);
377 
378   /** \brief Initializes properties to given values
379    *
380    * Clears all properties that have been set and replaces them with those given
381    * in argument. Any property name in \c propValues that doesn't exist in registered
382    * properties, is registered.
383    *
384    * This function bypasses all checks by calling loadProperty() directly. Reimplement
385    * this function for property name and value checking.
386    * */
387   virtual bool setAllProperties(const QMap<QString, QVariant>& propValues);
388 
389 
390   /** \brief Explicit function name for the simple \c "operator<<".
391    * \code
392    *   QDataStream stream(...);
393    *   pobj.streamInto(stream); // is equivalent to:
394    *   stream << pobj;
395    * \endcode
396    *
397    * For more advanced saving/loading techniques, see klfLoad() and klfSave().
398    */
399   QDataStream& streamInto(QDataStream& stream) const;
400 
401   /** \brief Explicit function name for the simple \c "operator>>".
402    *
403    * Somewhat the opposite of streamInto().
404    *
405    * For more advanced saving/loading techniques, see klfLoad() and klfSave().
406    */
407   QDataStream& streamFrom(QDataStream& stream);
408 
409 
410   /** \brief Saves all the properties in binary form.
411    *
412    * Basically flushes the output of allProperties() into a QByteArray.
413    *
414    * For more advanced saving/loading techniques, see klfLoad() and klfSave().
415    */
416   QByteArray allPropertiesToByteArray() const;
417 
418   /** \brief Loads all properties saved by \ref allPropertiesToByteArray()
419    *
420    * Reads the properties from \c data and calls setAllProperties().
421    *
422    * For more advanced saving/loading techniques, see klfLoad() and klfSave().
423    */
424   void setAllPropertiesFromByteArray(const QByteArray& data);
425 
426   /*
427   / ** \brief Parses a string representation of a property
428    *
429    * Subclasses should reimplement this function to parse the actual string into a value. Note
430    * that this function should NOT set the property, it should just parse the string in a way
431    * depending on what kind of information the property \c propId is supposed to store.
432    *
433    * The formatting is left to the implementation. It could be user input, for example.
434    *
435    * The default implementation calls \ref parsePropertyValue(const QString&, const QString&) .
436    * It is thus enough for subclasses to reimplement the other method.
437    * /
438    virtual QVariant parsePropertyValue(int propId, const QString& strvalue);
439 
440    / ** \brief Parses a string representation of a property
441    *
442    * Subclasses should reimplement this function to parse the actual string into a value. Note
443    * that this function should NOT set the property, it should just parse the string in a way
444    * depending on what kind of information the property \c propName is supposed to store.
445    *
446    * The formatting is left to the implementation. It could be user input, for example.
447    *
448    * Since the base implementation has no idea what kind of information \c propId is supposed
449    * to store, the default implementation returns a null \c QVariant().
450    * /
451    virtual QVariant parsePropertyValue(const QString& propName, const QString& strvalue);
452   */
453 
454 
455   /** \brief Flags for tuning the \ref toString() method.
456    */
457   enum ToStringFlag {
458     ToStringUseHtml = 0x0001, //!< Encapsulates output in an HTML &lt;table&gt; and escapes strings.
459     ToStringUseHtmlDiv = 0x0002, //!< Uses &lt;div&gt; with CSS classes instead of a table (HTML only)
460     ToStringQuoteValues = 0x0004, //!< Ensures that non-html output is machine parsable.
461     ToStringAllProperties = 0x0008 //!< Include also all non-explicitely-set properties
462   };
463   /** \brief Formats the property contents in a (human and/or parsable) string
464    *
465    * \param toStringFlags is a binary OR value of flags defined in \ref ToStringFlag.
466    */
467   virtual QString toString(uint toStringFlags = 0) const;
468 
469   //! See the corresponding protected static method
470   /** Shortcut for the corresponding (protected) static method propertyMaxId(const QString&).
471    * The property name space is automatically detected. */
472   int propertyMaxId() const;
473   //! See the corresponding protected static method
474   /** Shortcut for the corresponding (protected) static method
475    * propertyIdRegistered(const QString&, int). The property name space is automatically
476    * detected. */
477   bool propertyIdRegistered(int propId) const;
478   //! See the corresponding protected static method
479   /** Shortcut for the corresponding (protected) static method
480    * propertyNameRegistered(const QString&, const QString&). The property name space is
481    * automatically detected. */
482   bool propertyNameRegistered(const QString& propertyName) const;
483   //! See the corresponding protected static method
484   /** Shortcut for the corresponding (protected) static method
485    * propertyIdForName(const QString&, const QString&); the property name space is
486    * automatically detected. */
487   int propertyIdForName(const QString& propertyName) const;
488   //! See the corresponding protected static method
489   /** Shortcut for the corresponding (protected) static method
490    * propertyNameForId(const QString&, int); the property name space is automatically
491    * detected. */
492   QString propertyNameForId(int propId) const;
493   //! See the corresponding protected static method
494   /** Shortcut for the corresponding (protected) static method
495    * registeredPropertyIdList(const QString&); the property name space is automatically
496    * detected. */
497   QList<int> registeredPropertyIdList() const;
498   //! See the corresponding protected static method
499   /** Shortcut for the corresponding (protected) static method
500    * registeredPropertyNameList(const QString); the property name space is automatically
501    * detected. */
502   QStringList registeredPropertyNameList() const;
503   //! See the corresponding protected static method
504   /** Shortcut for the corresponding (protected) static method
505    * registeredProperties(const QString&);
506    * the property name space is automatically detected. */
507   QMap<QString, int> registeredProperties() const;
508 
objectKind()509   virtual QString objectKind() const { return pPropNameSpace; }
510 
511 protected:
512 
513   /** This method is called whenever the value of a given property changes.
514    *
515    * Subclasses may reimplement to watch the properties for changes. The default
516    * implementation does nothing.
517    *
518    * \param propId the property ID that changed
519    * \param oldValue the previous value of the property
520    * \param newValue the new value of the property
521    */
522   virtual void propertyValueChanged(int propId, const QVariant& oldValue,
523 				    const QVariant& newValue);
524 
525 
526   /** Sets the given property to \c value. If propname is not registered,
527    * this function fails.
528    *
529    * \returns TRUE for success. */
530   virtual bool doSetProperty(const QString& propname, const QVariant& value);
531 
532   /** Sets the property identified by propId to the value \c value.
533    * Fails if the property \c propId is not registered.
534    *
535    * \returns TRUE for success. */
536   virtual bool doSetProperty(int propId, const QVariant& value);
537 
538   /** Like \c doSetProperty(), except the property name \c propname is registered
539    * with \ref registerProperty() if it is not registered.
540    *
541    * \returns The property ID that was set or -1 for failure.
542    */
543   virtual int doLoadProperty(const QString& propname, const QVariant& value);
544 
545   /** shortcut for the corresponding static method. Detects the correct property
546    * name space and calls registerBuiltInProperty(const QString&, int, const QString&)
547    */
548   void registerBuiltInProperty(int propId, const QString& propName) const;
549 
550   /** shortcut for the corresponding static method. Detects the correct property
551    * name space and calls
552    * \ref registerProperty(const QString& propNameSpace, const QString& propName).
553    */
554   int registerProperty(const QString& propertyName) const;
555 
556   /** Registers the property named \c name with the fixed ID \c propId.
557    *
558    * If the property is already registered with the exact same name and ID, then this
559    * function does nothing.
560    *
561    * If the given property name or the given property ID is already registered, but
562    * the name or the ID doesn't match exactly, then a warning is printed and the
563    * property is not registered.
564    *
565    * The property name has to be non-empty (\ref QString::isEmpty()), or a warning is
566    * printed and the property is not registered.
567    *
568    * Subclasses should call this function _once_ per built-in property they want to
569    * register. For example this could be achieved with the following code:
570    * \code
571    * // mybook.h
572    * class MyBook : public KLFPropertizedObject {
573    * public:
574    *   enum { PropTitle, PropAuthor, PropEditor, PropYear };
575    *   MyBook();
576    *
577    *   ... // API to access/write properties
578    *
579    * private:
580    *   static void initBuiltInProperties();
581    * };
582    *
583    * MyBook::MyBook() : KLFPropertizedObject("MyBook") {
584    *   initBuiltInProperties();
585    * }
586    * void MyBook::initBuiltInProperties() {
587    *   KLF_FUNC_SINGLE_RUN ;
588    *
589    *   registerBuiltInProperty(PropTitle, "Title");
590    *   registerBuiltInProperty(PropAuthor, "Author");
591    *   registerBuiltInProperty(PropEditor, "Editor");
592    *   registerBuiltInProperty(PropYear, "Year");
593    * }
594    *
595    * ... // other function definitions
596    *
597    * \endcode
598    *
599    * \note If property name space does not exist, it is created.
600    *
601    * Subclasses may prefer to use the more convenient function
602    * registerBuiltInProperty(int propId, const QString& propName), which automatically uses
603    * the correct property name space.
604    */
605   static void registerBuiltInProperty(const QString& propNameSpace, int propId,
606 				      const QString& name);
607 
608   /** Registers the property \c propertyName and assigns a new unused ID for that property,
609    * and returns the newly assigned ID.
610    *
611    * If the property name is already registered, this function prints a warning and returns
612    * \c -1.
613    *
614    * The property name must be non-empty (see \ref QString::isEmpty()), or this function
615    * will print a warning and return \c -1.
616    *
617    * Subclasses may prefer to use the more convenient function
618    * registerProperty(const QString&) const,
619    * which automatically uses the correct property name space.
620    */
621   static int registerProperty(const QString& propNameSpace, const QString& propertyName);
622 
623   /** Returns a number that is guaranteed higher or equal to all registered property IDs in
624    * the given property name space.
625    *
626    * Subclasses may prefer to use the more convenient function
627    * propertyMaxId() const, which automatically uses the correct property
628    * name space.
629    */
630   static int propertyMaxId(const QString& propNameSpace);
631 
632   /** \returns true if a property with ID \c propId exists (=has been registered) in the
633    * property name space \c propNameSpace .
634    *
635    * Subclasses may prefer to use the more convenient function
636    * propertyIdRegistered(int) const, which automatically uses the correct property
637    * name space.
638    */
639   static bool propertyIdRegistered(const QString& propNameSpace, int propId);
640 
641   /** \returns true if a property of name \c propertyName exists (=has been registered) in the
642    * property name space \c propNameSpace .
643    *
644    * Subclasses may prefer to use the more convenient function
645    * propertyNameRegistered(const QString&) const,
646    * which automatically uses the correct property name space.
647    * */
648   static bool propertyNameRegistered(const QString& propNameSpace, const QString& propertyName);
649 
650   /** \returns the ID corresponding to property name \c propertyName in property name
651    * space \c propNameSpace.
652    *
653    * If the property name space does not exist, or if the property does not exist in that
654    * name space, \c -1 is returned (silently).
655    *
656    * The property name space \c propNameSpace must exist or a warning message is issued.
657    *
658    * Subclasses may prefer to use the more convenient function
659    * propertyIdForName(const QString&) const, which automatically uses the correct property
660    * name space.
661    */
662   static int propertyIdForName(const QString& propNameSpace, const QString& propertyName);
663 
664   /** Reverse operation of propertyIdForName(), with similar behavior.
665    *
666    * This function silently returns <tt>QString()</tt> on failure.
667    *
668    * Subclasses may prefer to use the more convenient function propertyNameForId(int) const,
669    * which automatically uses the correct property name space.
670    */
671   static QString propertyNameForId(const QString& propNameSpace, int propId);
672 
673   /** Returns a list of all registered property IDs in the given property name space.
674    *
675    * Subclasses may prefer to use the more convenient function
676    * \ref registeredPropertyIdList(),
677    * which automatically uses the correct property name space.
678    * */
679   static QList<int> registeredPropertyIdList(const QString& propNameSpace);
680 
681   /** Returns a list of all registered property names in the given property name space.
682    *
683    * Subclasses may prefer to use the more convenient function
684    * \ref registeredPropertyNameList(),
685    * which automatically uses the correct property name space.
686    * */
687   static QStringList registeredPropertyNameList(const QString& propNameSpace);
688 
689   /** Returns a map of all registered properties, with the property names as map keys and
690    * the property IDs as map values, in the given property name space.
691    *
692    * Subclasses may prefer to use the more convenient function \ref registeredProperties(),
693    * which automatically uses the correct property name space.
694    * */
695   static QMap<QString, int> registeredProperties(const QString& propNameSpace);
696 
propertyNameSpace()697   QString propertyNameSpace() const { return pPropNameSpace; }
698 
propertyVector()699   QVector<QVariant> propertyVector() const { return pProperties; }
700 
701 
702   friend class KLFPObjPropRefHelper;
703 
704 private:
705   /** No default constructor. */
KLFPropertizedObject()706   KLFPropertizedObject() { }
707 
708   QString pPropNameSpace;
709 
710   QVector<QVariant> pProperties;
711 
712   /** Creates \c propNameSpace property name space if it doesn't exist.
713    * \returns the property ID (\c propId or a new property ID if \c propId
714    * is \c -1) */
715   static int internalRegisterProperty(const QString& propNameSpace, const QString& name,
716 				      int propId = -1);
717   static QMap<QString, QMap<QString, int> > pRegisteredProperties;
718   static QMap<QString, int> pRegisteredPropertiesMaxId;
719 
720   friend bool operator==(const KLFPropertizedObject& a, const KLFPropertizedObject& b);
721 };
722 
723 /** \returns TRUE if all values for all registered properties of this object are equal.
724  * \relates KLFPropertizedObject
725  */
726 bool operator==(const KLFPropertizedObject& a, const KLFPropertizedObject& b);
727 
728 /**
729  * \note For more advanced saving/loading techniques, see klfLoad() and klfSave().
730  */
731 KLF_EXPORT QDataStream& operator<<(QDataStream& stream, const KLFPropertizedObject& obj);
732 /**
733  * \note For more advanced saving/loading techniques, see klfLoad() and klfSave().
734  */
735 KLF_EXPORT QDataStream& operator>>(QDataStream& stream, KLFPropertizedObject& obj);
736 
737 KLF_EXPORT QTextStream& operator<<(QTextStream& stream, const KLFPropertizedObject& obj);
738 
739 KLF_EXPORT QDebug& operator<<(QDebug& stream, const KLFPropertizedObject& obj);
740 
741 
742 /** \internal
743  *
744  * Helper class because of friend declaration not liking templates (??)
745  */
746 class KLFPObjPropRefHelper
747 {
748 protected:
registerbuiltinprop(KLFPropertizedObject * obj,int propid,const QString & pname)749   void registerbuiltinprop(KLFPropertizedObject *obj, int propid, const QString& pname)
750   {
751     obj->registerBuiltInProperty(propid, pname);
752   }
propertyNameSpace(KLFPropertizedObject * obj)753   QString propertyNameSpace(KLFPropertizedObject *obj) const { return obj->propertyNameSpace(); }
754 };
755 
756 template<class T>
757 class KLF_EXPORT KLFPObjPropRef : private KLFPObjPropRefHelper
758 {
759   KLFPropertizedObject *pPObj;
760   int pPropId;
761 public:
762   typedef T Type;
763 
KLFPObjPropRef(KLFPropertizedObject * pobj,int propId)764   KLFPObjPropRef(KLFPropertizedObject *pobj, int propId)
765     : pPObj(pobj), pPropId(propId)
766   {
767   }
KLFPObjPropRef(const KLFPObjPropRef & other)768   KLFPObjPropRef(const KLFPObjPropRef& other)
769     : pPObj(other.pPObj), pPropId(other.pPropId)
770   {
771   }
772   /** Constructs the object and automatically registers the given property in \c pobj
773    * as a built-in property.
774    *
775    * \warning Should ONLY be used by KLFPropertizedObject subclasses in their constructor,
776    *   for KLFPObjPropRef objects that are declared as members.
777    */
KLFPObjPropRef(KLFPropertizedObject * pobj,int builtInPropId,const QString & pname)778   KLFPObjPropRef(KLFPropertizedObject *pobj, int builtInPropId, const QString& pname)
779     : pPObj(pobj), pPropId(builtInPropId)
780   {
781     init(pname);
782   }
783   /** Constructs the object and automatically registers the given property in \c pobj
784    * as a built-in property. Initializes the property's value to \c value.
785    *
786    * \warning Should ONLY be used by KLFPropertizedObject subclasses in their constructor,
787    *   for KLFPObjPropRef objects that are declared as members.
788    */
KLFPObjPropRef(KLFPropertizedObject * pobj,int builtInPropId,const QString & pname,const T & value)789   KLFPObjPropRef(KLFPropertizedObject *pobj, int builtInPropId, const QString& pname, const T& value)
790     : pPObj(pobj), pPropId(builtInPropId)
791   {
792     init(pname);
793     set(value);
794   }
795 
QVariant()796   operator QVariant() const
797   {
798     return variantValue();
799   }
T()800   operator T() const
801   {
802     return value<T>();
803   }
operator()804   const T operator ()() const
805   {
806     return value<T>();
807   }
808   const KLFPObjPropRef& operator=(const QVariant& v)
809   {
810     pPObj->setProperty(pPropId, v);
811     return *this;
812   }
813   const KLFPObjPropRef& operator=(const T& value)
814   {
815     pPObj->setProperty(pPropId, QVariant::fromValue<T>(value));
816     return *this;
817   }
818   /** \note This assigns the value; it does NOT change the property reference! */
819   const KLFPObjPropRef& operator=(const KLFPObjPropRef& value)
820   {
821     return this->operator=(value.value());
822   }
823 
variantValue()824   QVariant variantValue() const
825   {
826     return pPObj->property(pPropId);
827   }
828 
value()829   const T value() const
830   {
831     return value<T>();
832   }
833 
834   template<class VariantType>
value()835   const T value() const
836   {
837     QVariant v = pPObj->property(pPropId);
838     return T(v.value<VariantType>());
839   }
840 
841   template<class VariantType>
set(const T & value)842   void set(const T& value)
843   {
844     pPObj->setProperty(pPropId, QVariant::fromValue<VariantType>(value));
845   }
set(const T & value)846   void set(const T& value)
847   {
848     set<T>(value);
849   }
850 
851   template<class VariantType>
equals(const KLFPObjPropRef & other)852   bool equals(const KLFPObjPropRef& other) const
853   {
854     return (value<VariantType>() == other.value<VariantType>());
855   }
equals(const KLFPObjPropRef & other)856   bool equals(const KLFPObjPropRef& other) const
857   {
858     return equals<T>(other);
859   }
860 
861   bool operator==(const T& val) const
862   {
863     return (value() == val);
864   }
865   bool operator==(const KLFPObjPropRef& other) const
866   {
867     return (value() == other.value());
868   }
869 
870 private:
init(const QString & pname)871   void init(const QString& pname)
872   {
873     if (!pPObj->propertyIdRegistered(pPropId)) {
874       // from our helper base class
875       registerbuiltinprop(pPObj, pPropId, pname);
876     } else {
877       // make sure the correct name was registered
878       KLF_ASSERT_CONDITION(pPObj->propertyNameForId(pPropId) == pname,
879 			   qPrintable(propertyNameSpace(pPObj))<<": Built-In property ID "<<pPropId
880 			   <<" does not have name "<<pname<<" !",
881 			   ; ) ;
882     }
883   }
884 
885 };
886 
887 template<typename T>
888 inline QDebug & operator<<(QDebug & str, const KLFPObjPropRef<T> & p)
889 {
890   return str << p();
891 }
892 
893 
894 
895 // ----
896 
897 /** \internal */
898 class KLFPObjRegisteredType {
899 public:
KLFPObjRegisteredType(const char * name)900   KLFPObjRegisteredType(const char *name)
901   {
902     doregister(Register, name);
903   }
904 
isRegistered(const char * name)905   static bool isRegistered(const char *name)
906   {
907     return doregister(Query, name);
908   }
909 
910 private:
911   enum Action { Query, Register };
doregister(Action action,const char * name)912   static int doregister(Action action, const char * name)
913   {
914     static QList<QByteArray> registered_types;
915     bool x;
916     switch (action) {
917     case Query: // is querying the existance of a registered type
918       x = registered_types.contains(QByteArray(name));
919       return x;
920     case Register: // want to register the given type
921       registered_types.append(QByteArray(name));
922       return 0;
923     default:
924       fprintf(stderr, "ERRORORROOERROR: %s: what is your action?? `%d' for name `%s'\n",
925 	      KLF_FUNC_NAME, (int)action, name);
926     }
927     return -1;
928   }
929 };
930 
931 /** Put this in the .cpp for the given type.
932  *
933  * \todo ###: Which type? any abstractobj or just klfproperitzedobject?
934  *       ###:                 ^^^^^^^^^^^ this one it seems (see klfuserscript.h)
935  */
936 #define KLF_DECLARE_POBJ_TYPE(TYPE)					\
937   static KLFPObjRegisteredType __klf_pobj_regtype_##TYPE = KLFPObjRegisteredType(#TYPE) ;
938 
939 /** \internal */
940 class KLFSpecifyableRegisteredType {
941 public:
KLFSpecifyableRegisteredType(const char * name)942   KLFSpecifyableRegisteredType(const char *name)
943   {
944     doregister(Register, name);
945   }
946 
isRegistered(const char * name)947   static bool isRegistered(const char *name)
948   {
949     return doregister(Query, name);
950   }
951 
952 private:
953   enum Action { Query, Register };
doregister(Action action,const char * name)954   static int doregister(Action action, const char * name)
955   {
956     static QList<QByteArray> registered_types;
957     bool x;
958     switch (action) {
959     case Query: // is querying the existance of a registered type
960       x = registered_types.contains(QByteArray(name));
961       return x;
962     case Register: // want to register the given type
963       registered_types.append(QByteArray(name));
964       return 0;
965     default:
966       fprintf(stderr, "ERRORORROORORR: %s: what is your action?? `%d' for name `%s'\n",
967 	      KLF_FUNC_NAME, (int)action, name);
968     }
969     return -1;
970   }
971 };
972 
973 /** Put this in the .cpp for the given type */
974 #define KLF_DECLARE_SPECIFYABLE_TYPE(TYPE)					\
975   static KLFSpecifyableRegisteredType __klf_specifyable_regtype_##TYPE = KLFSpecifyableRegisteredType(#TYPE) ;
976 
977 
978 
979 #endif
980