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 getProperty(const Type &object, const QString &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<T>
0109 @li QList<T>
0110 @li QSet<T>
0111 @li QLinkedList<T>
0112 @li QStack<T>
0113 @li QQueue<T>
0114 @li std::vector<T>
0115 @li std::deque<T>
0116 @li std::list<T>
0117 @li QHash<QString, T>
0118 @li QHash<qint16, T>
0119 @li QHash<qint32, T>
0120 @li QHash<qint64, T>
0121 @li QHash<quint16, T>
0122 @li QHash<quint32, T>
0123 @li QHash<quint64, T>
0124 @li QMap<QString, T>
0125 @li QMap<qint16, T>
0126 @li QMap<qint32, T>
0127 @li QMap<qint64, T>
0128 @li QMap<quint16, T>
0129 @li QMap<quint32, T>
0130 @li QMap<quint64, T>
0131 @li std::map<QString, T>
0132 @li std::map<qint16, T>
0133 @li std::map<qint32, T>
0134 @li std::map<qint64, T>
0135 @li std::map<quint16, T>
0136 @li std::map<quint32, T>
0137 @li std::map<quint64, T>
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<T> is an exception and will only work with types for which <tt>qHash(T)</tt> is defined. This means that QSet<QVariant>
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<PersonObject*> and std::vector<SportsClub*> 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<PersonObject> 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 }