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 }