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 * "property name spaces" 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<\ref QVariant>. 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 <table> and escapes strings. 459 ToStringUseHtmlDiv = 0x0002, //!< Uses <div> 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