Grantlee 0.1.9
templates/lib/metatype.h
Go to the documentation of this file.
00001 /*
00002   This file is part of the Grantlee template system.
00003 
00004   Copyright (c) 2010 Michael Jansen <kde@michael-jansen.biz>
00005   Copyright (c) 2010 Stephen Kelly <steveire@gmail.com>
00006 
00007   This library is free software; you can redistribute it and/or
00008   modify it under the terms of the GNU Lesser General Public
00009   License as published by the Free Software Foundation; either version
00010   2.1 of the Licence, or (at your option) any later version.
00011 
00012   This library is distributed in the hope that it will be useful,
00013   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015   Lesser General Public License for more details.
00016 
00017   You should have received a copy of the GNU Lesser General Public
00018   License along with this library.  If not, see <http://www.gnu.org/licenses/>.
00019 
00020 */
00021 
00022 #ifndef GRANTLEE_METATYPE_H
00023 #define GRANTLEE_METATYPE_H
00024 
00025 #include "grantlee_core_export.h"
00026 
00027 #include "typeaccessor.h"
00028 
00029 #include <QtCore/QVariant>
00030 #include <QtCore/QStringList>
00031 #include <QtCore/QStack>
00032 #include <QtCore/QQueue>
00033 
00034 #include <deque>
00035 #include <list>
00036 #include <map>
00037 #include <vector>
00038 
00040 
00041 namespace Grantlee
00042 {
00043 
00045 
00046 #ifndef Q_QDOC
00047 
00058 class GRANTLEE_CORE_EXPORT MetaType
00059 {
00060 public:
00064   typedef QVariant ( *LookupFunction )( const QVariant &, const QString & );
00065 
00069   typedef QVariantList ( *ToVariantListFunction )( const QVariant & );
00070 
00074   static void registerLookUpOperator( int id, LookupFunction f );
00075 
00079   static void registerToVariantListOperator( int id, ToVariantListFunction f );
00080 
00084   static void internalLock();
00085 
00089   static void internalUnlock();
00090 
00094   static QVariant lookup( const QVariant &object, const QString &property );
00095 
00099   static QVariantList toVariantList( const QVariant &obj );
00100 
00104   static bool lookupAlreadyRegistered( int id );
00105 
00109   static bool toListAlreadyRegistered( int id );
00110 
00114   static inline int init();
00115 
00119   static int initBuiltins() { return init(); }
00120 
00121 private:
00122   MetaType();
00123 };
00124 #endif
00125 
00126 namespace
00127 {
00128 
00129 /*
00130  * This is a helper to select an appropriate overload of indexAccess
00131  */
00132 template<typename RealType, typename HandleAs>
00133 struct LookupTrait
00134 {
00135   static QVariant doLookUp( const QVariant &object, const QString &property )
00136   {
00137     typedef typename Grantlee::TypeAccessor<HandleAs> Accessor;
00138     return Accessor::lookUp( static_cast<HandleAs>( object.value<RealType>() ), property );
00139   }
00140 };
00141 
00142 template<typename T>
00143 struct IsQObjectStar
00144 {
00145   enum { Yes = false };
00146 };
00147 
00148 template<typename T>
00149 struct IsQObjectStar<T*>
00150 {
00151   typedef int yes_type;
00152   typedef char no_type;
00153 
00154   static yes_type check(QObject*);
00155   static no_type check(...);
00156   enum { Yes = sizeof(check(static_cast<T*>(0))) == sizeof(yes_type) };
00157 };
00158 
00159 template<typename T, bool>
00160 struct LookupPointer
00161 {
00162   static QVariant doLookUp( const QVariant &object, const QString &property )
00163   {
00164     typedef typename Grantlee::TypeAccessor<T> Accessor;
00165     return Accessor::lookUp( object.value<T>(), property );
00166   }
00167 };
00168 
00169 template<typename T>
00170 struct LookupPointer<T, true>
00171 {
00172   static QVariant doLookUp( const QVariant &object, const QString &property )
00173   {
00174     typedef typename Grantlee::TypeAccessor<QObject*> Accessor;
00175     return Accessor::lookUp( object.value<T>(), property );
00176   }
00177 };
00178 
00179 template<typename RealType>
00180 struct LookupTrait<RealType*, RealType*>
00181 {
00182   static QVariant doLookUp( const QVariant &object, const QString &property )
00183   {
00184     return LookupPointer<RealType*, IsQObjectStar<RealType*>::Yes>::doLookUp(object, property);
00185   }
00186 };
00187 
00188 template<typename RealType, typename HandleAs>
00189 struct LookupTrait<RealType&, HandleAs&>
00190 {
00191   static QVariant doLookUp( const QVariant &object, const QString &property )
00192   {
00193     typedef typename Grantlee::TypeAccessor<HandleAs&> Accessor;
00194     return Accessor::lookUp( static_cast<HandleAs>( object.value<RealType>() ), property );
00195   }
00196 };
00197 
00198 template<typename RealType, typename HandleAs>
00199 static int doRegister( int id )
00200 {
00201   if ( MetaType::lookupAlreadyRegistered( id ) )
00202     return id;
00203 
00204   QVariant ( *lf )( const QVariant&, const QString& ) = LookupTrait<RealType, HandleAs>::doLookUp;
00205 
00206   MetaType::registerLookUpOperator( id, reinterpret_cast<MetaType::LookupFunction>( lf ) );
00207 
00208   return id;
00209 }
00210 
00211 /*
00212  * Register a type so grantlee knows how to handle it.
00213  */
00214 template<typename RealType, typename HandleAs>
00215 struct InternalRegisterType
00216 {
00217   static int doReg() {
00218     const int id = qMetaTypeId<RealType>();
00219     return doRegister<RealType&, HandleAs&>( id );
00220   }
00221 };
00222 
00223 template<typename RealType, typename HandleAs>
00224 struct InternalRegisterType<RealType*, HandleAs*>
00225 {
00226   static int doReg() {
00227     const int id = qMetaTypeId<RealType*>();
00228     return doRegister<RealType*, HandleAs*>( id );
00229   }
00230 };
00231 
00232 template<typename Container, typename HandleAs>
00233 int registerSequentialContainer()
00234 {
00235   const int id = InternalRegisterType<Container, HandleAs>::doReg();
00236 
00237   if ( MetaType::toListAlreadyRegistered( id ) )
00238     return id;
00239 
00240   QVariantList ( *tlf )( const QVariant& ) = SequentialContainerAccessor<Container>::doToList;
00241   MetaType::registerToVariantListOperator( id, reinterpret_cast<MetaType::ToVariantListFunction>( tlf ) );
00242   return id;
00243 }
00244 
00245 template<typename Container>
00246 int registerSequentialContainer()
00247 {
00248   return registerSequentialContainer<Container, Container>();
00249 }
00250 
00251 template<typename Container, typename HandleAs>
00252 int registerAssociativeContainer()
00253 {
00254   const int id = InternalRegisterType<Container, HandleAs>::doReg();
00255 
00256   if ( MetaType::toListAlreadyRegistered( id ) )
00257     return id;
00258 
00259   QVariantList ( *tlf )( const QVariant& ) = AssociativeContainerAccessor<Container>::doToList;
00260   MetaType::registerToVariantListOperator( id, reinterpret_cast<MetaType::ToVariantListFunction>( tlf ) );
00261   return id;
00262 }
00263 
00264 template<typename Container>
00265 int registerAssociativeContainer()
00266 {
00267   return registerAssociativeContainer<Container, Container>();
00268 }
00269 
00270 }
00271 
00272 #ifndef Q_QDOC
00273 
00279 template<typename RealType, int n>
00280 struct RegisterTypeContainer
00281 {
00282   static void reg()
00283   {
00284   }
00285 };
00286 #endif
00287 
00293 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(Container, Type)                                   \
00294   Grantlee::RegisterTypeContainer<Container<Type>, QMetaTypeId2<Container<Type> >::Defined>::reg();  \
00295 
00296 #ifndef Q_QDOC
00297 
00300 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, Key, Type)                                   \
00301   Grantlee::RegisterTypeContainer<Container<Key, Type>, QMetaTypeId2<Container<Key, Type> >::Defined>::reg();  \
00302 
00303 #endif
00304 
00320 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF(Container,          Type)     \
00321     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, QString, Type)     \
00322     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint16,  Type)     \
00323     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint32,  Type)     \
00324     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint64,  Type)     \
00325     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint16, Type)     \
00326     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint32, Type)     \
00327     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint64, Type)     \
00328 
00329 namespace
00330 {
00331 
00332 template<typename T>
00333 void registerContainers()
00334 {
00335   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QList,          T )
00336   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QQueue,         T )
00337   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QVector,        T )
00338   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QStack,         T )
00339   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QSet,           T )
00340   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QLinkedList,    T )
00341 
00342   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( QHash,          T )
00343   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( QMap,           T )
00344 
00345   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::deque,     T )
00346   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::vector,    T )
00347   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::list,      T )
00348   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( std::map,       T )
00349 }
00350 
00351 struct BuiltinRegister
00352 {
00353   void registerBuiltinContainers() const
00354   {
00355     Grantlee::MetaType::internalLock();
00356 
00357     registerContainers< bool      >();
00358     registerContainers< qint16    >();
00359     registerContainers< qint32    >();
00360     registerContainers< qint64    >();
00361     registerContainers< quint16   >();
00362     registerContainers< quint32   >();
00363     registerContainers< quint64   >();
00364     registerContainers< float     >();
00365     registerContainers< double    >();
00366     registerContainers< QString   >();
00367     registerContainers< QVariant  >();
00368     registerContainers< QDateTime >();
00369     registerContainers< QObject*  >();
00370 
00371     registerSequentialContainer<QStringList, QList<QString> >();
00372     Grantlee::MetaType::internalUnlock();
00373   }
00374 };
00375 
00376 Q_GLOBAL_STATIC( BuiltinRegister, builtinRegister )
00377 
00378 }
00379 
00380 #ifndef Q_QDOC
00381 struct MetaTypeInitializer {
00382   static inline int initialize()
00383   {
00384       static const BuiltinRegister *br = builtinRegister();
00385       br->registerBuiltinContainers();
00386       return 0;
00387   }
00388 };
00389 #endif
00390 
00396 #define GRANTLEE_METATYPE_INITIALIZE static const int i = Grantlee::MetaTypeInitializer::initialize(); Q_UNUSED(i)
00397 
00398 #ifndef Q_QDOC
00399 inline int MetaType::init()
00400 {
00401   GRANTLEE_METATYPE_INITIALIZE
00402   return 0;
00403 }
00404 #endif
00405 
00441 template<typename RealType, typename HandleAs>
00442 int registerMetaType()
00443 {
00444   {
00445     GRANTLEE_METATYPE_INITIALIZE
00446     Q_UNUSED( i )
00447   }
00448   MetaType::internalLock();
00449 
00450   const int id = InternalRegisterType<RealType, HandleAs>::doReg();
00451 
00452   registerContainers<RealType>();
00453 
00454   MetaType::internalUnlock();
00455 
00456   return id;
00457 }
00458 
00459 #ifndef Q_QDOC
00460 
00466 template<typename Type>
00467 int registerMetaType()
00468 {
00469   return registerMetaType<Type, Type>();
00470 }
00471 
00472 // http://catb.org/jargon/html/magic-story.html
00473 enum {
00474   Magic,
00475   MoreMagic
00476 };
00477 
00478 #endif
00479 } // namespace Grantlee
00480 
00486 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER(Container)             \
00487 namespace Grantlee {                                                  \
00488 template<typename T>                                                  \
00489 struct RegisterTypeContainer<Container<T>, MoreMagic>                 \
00490 {                                                                     \
00491   static int reg()                                                    \
00492   {                                                                   \
00493     const int id = registerSequentialContainer<Container<T> >();      \
00494     registerContainers<Container<T> >();                              \
00495     return id;                                                        \
00496   }                                                                   \
00497 };                                                                    \
00498 }                                                                     \
00499 
00500 
00505 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER(Container)                     \
00506 namespace Grantlee {                                                           \
00507 template<typename T, typename U>                                               \
00508 struct RegisterTypeContainer<Container<T, U>, MoreMagic>                       \
00509 {                                                                              \
00510   static int reg()                                                             \
00511   {                                                                            \
00512     const int id = registerAssociativeContainer<Container<T, U> >();           \
00513     registerContainers<Container<T, U> >();                                    \
00514     return id;                                                                 \
00515   }                                                                            \
00516 };                                                                             \
00517 }                                                                              \
00518 
00519 #ifndef Q_QDOC
00520 
00523 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS(Container, As)               \
00524 namespace Grantlee {                                                           \
00525 template<typename T>                                                           \
00526 struct RegisterTypeContainer<Container<T>, MoreMagic>                          \
00527 {                                                                              \
00528   static int reg()                                                             \
00529   {                                                                            \
00530     return registerSequentialContainer<Container<T>, As<T> >();                \
00531   }                                                                            \
00532 };                                                                             \
00533 }                                                                              \
00534 
00535 #endif
00536 
00542 #define GRANTLEE_BEGIN_LOOKUP(Type)                                                        \
00543 namespace Grantlee                                                                         \
00544 {                                                                                          \
00545 template<>                                                                                 \
00546 inline QVariant TypeAccessor<Type&>::lookUp( const Type &object, const QString &property ) \
00547 {                                                                                          \
00548 
00549 
00554 #define GRANTLEE_BEGIN_LOOKUP_PTR(Type)                                                            \
00555 namespace Grantlee                                                                                 \
00556 {                                                                                                  \
00557 template<>                                                                                         \
00558 inline QVariant TypeAccessor<Type*>::lookUp( const Type * const object, const QString &property )  \
00559 {                                                                                                  \
00560 
00561 
00566 #define GRANTLEE_END_LOOKUP                                                              \
00567   return QVariant();                                                                     \
00568 }                                                                                        \
00569 }                                                                                        \
00570 
00571 
00572 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QList)
00573 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS (QQueue, QList)
00574 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QVector)
00575 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS (QStack, QVector)
00576 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QSet) // Actually associative, but iterated as a sequential.
00577 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QLinkedList)
00578 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (QHash)
00579 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (QMap)
00580 
00581 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::deque)
00582 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::vector)
00583 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::list)
00584 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (std::map)
00585 
00586 
00587 #endif // #define GRANTLEE_METATYPE_H
00588