Warning, /frameworks/ktexttemplate/docs/generictypes.dox is written in an unsupported language. File is not indexed.

0001 namespace KTextTemplate
0002 {
0003 
0004 /**
0005 
0006   @page generic_types_and_templates Generic type and template support
0007 
0008   @section generic_types Generic type support
0009 
0010   %KTextTemplate offers powerful support for using any type or container in a QVariant as part of the Context.
0011   %Qt introspection based on Q_PROPERTY is the most convenient way to access properties on QObject derived type or types decorated with the <tt>Q_GADGET</tt> macro.
0012   However, sometimes it is necessary to use classes which do can't have Q_PROPERTY macros (perhaps because they are defined in third-party headers)
0013   and where it would not be practical to create QObject/<tt>Q_GADGET</tt> wrappers around all related classes.
0014 
0015   In such cases the metatype can be registered with %KTextTemplate and an introspection method can be written.
0016 
0017   @code
0018     // Non-QObject
0019     class Person
0020     {
0021     public:
0022       Person() :age(0) {}
0023       Person(const QString &name, int age)
0024         : m_name(name), m_age(age)
0025       {
0026       }
0027 
0028       QString name() const
0029       {
0030         return m_name;
0031       }
0032 
0033       int age() const
0034       {
0035         return m_age;
0036       }
0037 
0038     private:
0039       QString m_name;
0040       int m_age;
0041     };
0042 
0043     // Make it possible to put Person in a QVariant.
0044     Q_DECLARE_METATYPE(Person)
0045 
0046     // Read-only introspection of Person object.
0047     KTEXTTEMPLATE_BEGIN_LOOKUP(Person)
0048       if ( property == "name" )
0049         return object.name();
0050       else if ( property == "age" )
0051         return object.age();
0052     KTEXTTEMPLATE_END_LOOKUP
0053 
0054     void someInitializer()
0055     {
0056       // Register the Person type with the %KTextTemplate introspection system.
0057       KTextTemplate::registerMetaType<Person>();
0058     }
0059 
0060     KTextTemplate::Context getContext()
0061     {
0062       KTextTemplate::Context c;
0063       Person leader("The Leader", 19);
0064 
0065       QList<Person> followers;
0066       for (int i = 0; i < 3; ++i)
0067       {
0068         Person follower("Follower" + QString::number(i), 18);
0069         people.append(follower);
0070       }
0071 
0072       c.insert("leader", QVariant::fromValue(leader));
0073       c.insert("followers", QVariant::fromValue(followers));
0074       return c;
0075     }
0076 
0077     QString createOutput()
0078     {
0079       Template t = m_engine->newTemplate(
0080         "<h1>{{ leader.name }}</h1>"
0081         "<ul>"
0082         "{% for person in followers %}"
0083           "<li>{{ person.name }}, {{ person.age }}</li>"
0084         "{% endfor %}"
0085         "</ul>"
0086         );
0087 
0088       Context c = getContext();
0089 
0090       return t->render(&c);
0091     }
0092   @endcode
0093 
0094   There are several necessary steps and consequences.
0095   @li The type must be registered as a QMetaType with <tt>Q_DECLARE_METATYPE</tt>. Note that this is not needed for QObject derived types.
0096   @li All containers are supported. (See @ref generic_containers)
0097   @li The <tt>KTEXTTEMPLATE_BEGIN_LOOKUP</tt> and <tt>KTEXTTEMPLATE_END_LOOKUP</tt> macros help to define the introspection of the type. Between them is the definition of a method with the signature <tt>QVariant&nbsp;getProperty(const&nbsp;Type&nbsp;&object,&nbsp;const&nbsp;QString&nbsp;&property)</tt>.
0098   @li KTextTemplate::registerMetaType must be called at some point in the program before attempting to use the type in a Context.
0099   @li The Context is created and used as normal.
0100 
0101   @section generic_containers Generic container support
0102 
0103   %KTextTemplate supports most %Qt and STL containers by default if they are registered with the QMetaType system as shown in @ref generic_types.
0104   Where a container does not have built in support it can easily be added (See @ref third_party_containers).
0105 
0106   The following containers have built in support:
0107 
0108   @li QList&lt;T&gt;
0109   @li QList&lt;T&gt;
0110   @li QSet&lt;T&gt;
0111   @li QLinkedList&lt;T&gt;
0112   @li QStack&lt;T&gt;
0113   @li QQueue&lt;T&gt;
0114   @li std::vector&lt;T&gt;
0115   @li std::deque&lt;T&gt;
0116   @li std::list&lt;T&gt;
0117   @li QHash&lt;QString, T&gt;
0118   @li QHash&lt;qint16, T&gt;
0119   @li QHash&lt;qint32, T&gt;
0120   @li QHash&lt;qint64, T&gt;
0121   @li QHash&lt;quint16, T&gt;
0122   @li QHash&lt;quint32, T&gt;
0123   @li QHash&lt;quint64, T&gt;
0124   @li QMap&lt;QString, T&gt;
0125   @li QMap&lt;qint16, T&gt;
0126   @li QMap&lt;qint32, T&gt;
0127   @li QMap&lt;qint64, T&gt;
0128   @li QMap&lt;quint16, T&gt;
0129   @li QMap&lt;quint32, T&gt;
0130   @li QMap&lt;quint64, T&gt;
0131   @li std::map&lt;QString, T&gt;
0132   @li std::map&lt;qint16, T&gt;
0133   @li std::map&lt;qint32, T&gt;
0134   @li std::map&lt;qint64, T&gt;
0135   @li std::map&lt;quint16, T&gt;
0136   @li std::map&lt;quint32, T&gt;
0137   @li std::map&lt;quint64, T&gt;
0138 
0139   where T is one of
0140 
0141   @li bool
0142   @li qint16
0143   @li qint32
0144   @li qint64
0145   @li quint16
0146   @li quint32
0147   @li quint64
0148   @li float
0149   @li double
0150   @li QVariant
0151   @li QString
0152   @li QDateTime
0153   @li A pointer to a type which inherits QObject
0154   @li Any type registered with KTextTemplate::registerMetaType
0155   @li Any supported container
0156 
0157   Note that QSet&lt;T&gt; is an exception and will only work with types for which <tt>qHash(T)</tt> is defined. This means that QSet&lt;QVariant&gt;
0158   is not possible for example.
0159 
0160   Note also that containers of pointers to QObject derived types can be stored in containers, and they do not need to be explicitly
0161   registered with %KTextTemplate. Where the class has sufficient <tt>Q_PROPERTY</tt>s defined, the introspection method described above with
0162   <tt>KTEXTTEMPLATE_BEGIN_LOOKUP</tt> and <tt>KTEXTTEMPLATE_END_LOOKUP</tt> is also not necessary. Note also that any type or container can be used through a <tt>Q_PROPERTY</tt>.
0163 
0164   @code
0165     class PersonObject : public QObject
0166     {
0167       Q_OBJECT
0168       Q_PROPERTY(QString name READ name)
0169       Q_PROPERTY(int age READ age)
0170     public:
0171       PersonObject(const QString &name, int age, QObject *parent = 0);
0172 
0173       QString name() const;
0174       int age() const;
0175     };
0176 
0177     class SportsClub : public QObject
0178     {
0179       Q_OBJECT
0180       Q_PROPERTY(QString name READ name)
0181       Q_PROPERTY(QString sport READ sport)
0182       Q_PROPERTY(std::vector<QObject*> members READ members)
0183     public:
0184       SportsClub(const QString &name, const QString &sport, QObject *parent = 0);
0185 
0186       QString name() const;
0187       QString sport() const;
0188       std::vector<QObject*> members() const;
0189       void setMembers(std::vector<QObject*> members);
0190     };
0191 
0192     void someInitializer()
0193     {
0194       // QObject* already has built in support. No need to register the types
0195       // with KTextTemplate::registerMetaType
0196     }
0197 
0198     KTextTemplate::Context SomeClass::getContext()
0199     {
0200       KTextTemplate::Context c;
0201 
0202       QSet<QObject*> clubs;
0203       {
0204         auto club = new SportsClub("Smithfield Tennis Club", "Tennis", this);
0205 
0206         std::vector<QObject*> members;
0207         {
0208           auto member = new PersonObject("Alice", 21, this);
0209           members.push_back(member);
0210         }
0211         {
0212           auto member = new PersonObject("Bob", 22, this);
0213           members.push_back(member);
0214         }
0215         club.setMembers(members);
0216       }
0217 
0218       // ... specify other clubs and members
0219 
0220       c.insert("sportsClubs", QVariant::fromValue(clubs));
0221       return c;
0222     }
0223 
0224     QString createOutput()
0225     {
0226       auto t = m_engine->newTemplate(
0227         "{% regroup sportsClubs by sport as groupedSports %}"
0228         "{% for groupedClub in groupedSports %}"
0229           "<h1>{{ groupedClub.grouper }}</h1>"
0230           "{% for club in groupedClub.list %}"
0231             "<h2>{{ club.name }}</h2>"
0232             "<ul>"
0233             "{% for member in club.members %}"
0234               "<li>{{ member.name, }}, {{ member.age }}"
0235             "{% endfor %}"
0236           "</ul>"
0237           "{% endfor %}"
0238         "{% endfor %}"
0239         );
0240 
0241       auto c = getContext();
0242 
0243       return t->render(&c);
0244     }
0245   @endcode
0246 
0247   @see <a href="http://docs.djangoproject.com/en/1.9/ref/templates/builtins/#regroup">The regroup tag</a>
0248 
0249   The output would be something like
0250 
0251   @verbatim
0252     <h1>Tennis</h1>
0253       <h2>Smithfield Tennis Club</h2>
0254       <ul>
0255         <li>Alice, 21</li>
0256         <li>Bob, 22</li>
0257       </ul>
0258       <h2>Greenore Lawn Tennis and Fitness Club</h2>
0259       <ul>
0260         <li>Charlie, 23</li>
0261         <li>David, 24</li>
0262         <li>Elaine, 25</li>
0263         <li>Frank, 26</li>
0264       </ul>
0265     <h1>Basketball</h1>
0266       <h2>Sandyford Basketball Club</h2>
0267       <ul>
0268         <li>Gilian, 27</li>
0269         <li>Henry, 28</li>
0270       </ul>
0271   @endverbatim
0272 
0273   Of course, it is possible to use containers of pointers to concrete QObject subclasses, such as QSet&lt;PersonObject*&gt; and std::vector&lt;SportsClub*&gt; too.
0274 
0275   Because any supported container can also be used as a contained type, nested containers such as <tt>QList<QList<PersonObject*>></tt> are also supported.
0276 
0277   Note that if a type is registered with KTextTemplate::registerMetaType, built in containers of that type do not also need to be registered.
0278   Third party containers do need to be registered however (See @ref third_party_containers)
0279 
0280   @code
0281     Q_DECLARE_METATYPE(Person)
0282 
0283     void someInitializer()
0284     {
0285       KTextTemplate::registerMetaType<Person>();
0286 
0287       // Now any of the nested containers can be put 
0288       // in a Context and used in a Template.
0289     }
0290   @endcode
0291 
0292   @section third_party_containers Third party containers
0293 
0294   To support another, non-built in container it is necessary to use some macros to register it with %KTextTemplate.
0295 
0296   For a sequential container, <tt>Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE</tt>,
0297   and <tt>Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE</tt> are needed.
0298 
0299   @code
0300     #include <boost/circular_buffer>
0301 
0302     // Enable looping over the contents of the container
0303     Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(boost::circular_buffer)
0304 
0305     Q_DECLARE_METATYPE(boost::circular_buffer<Person>)
0306 
0307     void someInitializer()
0308     {
0309       KTextTemplate::registerMetaType<Person>();
0310     }
0311 
0312     KTextTemplate::Context getContext()
0313     {
0314       KTextTemplate::Context c;
0315 
0316       boost::circular_buffer<Person> buffer(5);
0317       // loop
0318       {
0319         Person p("Grant", 21);
0320         b.push_back(p);
0321       }
0322       c.insert("people", QVariant::fromValue(buffer));
0323     }
0324   @endcode
0325 
0326   @see @ref lookups
0327 
0328   For associative containers <tt>Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE</tt> is needed.
0329 
0330   @section smart_pointers Smart Pointers
0331 
0332   Shared pointer types containing a custom type should be introspected as normal using <tt>KTEXTTEMPLATE_BEGIN_LOOKUP</tt> and <tt>KTEXTTEMPLATE_END_LOOKUP</tt>
0333 
0334   @code
0335     Q_DECLARE_METATYPE(QSharedPointer<Person>)
0336 
0337     void someInitializer()
0338     {
0339       KTextTemplate::registerMetaType<QSharedPointer<Person> >();
0340     }
0341 
0342     KTEXTTEMPLATE_BEGIN_LOOKUP(QSharedPointer<Person>)
0343       if (property == "name")
0344         return object->name();
0345     KTEXTTEMPLATE_END_LOOKUP
0346   @endcode
0347 
0348   Note that if only shared pointers to the type is in your introspectable API you only need to define the property access for the
0349   shared pointer. In the case above, there is no need to use <tt>Q_DECLARE_METATYPE</tt> or <tt>KTEXTTEMPLATE_BEGIN_LOOKUP</tt> with <tt>Person</tt> or <tt>Person*</tt>.
0350 
0351   This is of course true of any smart pointer:
0352 
0353   @code
0354     Q_DECLARE_METATYPE(boost::shared_ptr<Person>)
0355 
0356     KTEXTTEMPLATE_BEGIN_LOOKUP(boost::shared_ptr<Person>)
0357       if (property == "name")
0358         return object->name();
0359     KTEXTTEMPLATE_END_LOOKUP
0360   @endcode
0361 
0362   QSharedPointers containing QObject derived types get special treatment.
0363 
0364   QObjects are automatically introspected for their <tt>Q_PROPERTY</tt>s (See @ref custom_objects).
0365 
0366   If you have QSharedPointer&lt;PersonObject&gt; where <tt>PersonObject</tt> is derived from QObject it will be automatically
0367   introspected just like a QObject* is without requiring the <tt>KTEXTTEMPLATE_BEGIN_LOOKUP</tt> and <tt>KTEXTTEMPLATE_END_LOOKUP</tt> macros,
0368   the <tt>Q_DECLARE_METATYPE</tt> macro, or registration with the %KTextTemplate metatype system. All of the access registration
0369   is handled by %Qt.
0370 
0371   @code
0372     void getContext()
0373     {
0374       KTextTemplate::Context c;
0375       auto p = QSharedPointer<PersonObject>::create();
0376       c.insert("person", QVariant::fromValue(p));
0377       return c;
0378     }
0379 
0380     QString createOutput()
0381     {
0382       // Uses Q_PROPERTYs defined on PersonObject for name and age
0383       auto t = m_engine->newTemplate( "{{ person.name }}, {{ person.age }}" );
0384 
0385       auto c = getContext();
0386 
0387       return t->render(&c);
0388     }
0389   @endcode
0390 
0391   The same technique can be used to support QObject derived types in third party shared pointers, but that requires
0392   an extra macro, <tt>Q_DECLARE_SMART_POINTER_METATYPE</tt>.
0393 
0394   @code
0395     Q_DECLARE_SMART_POINTER_METATYPE(boost::shared_ptr)
0396 
0397     void getContext()
0398     {
0399       KTextTemplate::Context c;
0400       boost::shared_ptr<PersonObject> p( new PersonObject );
0401       c.insert("person", QVariant::fromValue(p));
0402       return c;
0403     }
0404   @endcode
0405 
0406 */
0407 
0408 }