Grantlee  0.5.1
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 #include <QtCore/QDateTime>
00034 
00035 #include <deque>
00036 #include <list>
00037 #include <map>
00038 #include <vector>
00039 
00041 
00042 namespace Grantlee
00043 {
00044 
00046 
00047 #ifndef Q_QDOC
00048 
00059 class GRANTLEE_CORE_EXPORT MetaType
00060 {
00061 public:
00065   typedef QVariant ( *LookupFunction )( const QVariant &, const QString & );
00066 
00070   typedef QVariantList ( *ToVariantListFunction )( const QVariant & );
00071 
00075   static void registerLookUpOperator( int id, LookupFunction f );
00076 
00080   static void registerToVariantListOperator( int id, ToVariantListFunction f );
00081 
00085   static void internalLock();
00086 
00090   static void internalUnlock();
00091 
00095   static QVariant lookup( const QVariant &object, const QString &property );
00096 
00100   static QVariantList toVariantList( const QVariant &obj );
00101 
00105   static bool lookupAlreadyRegistered( int id );
00106 
00110   static bool toListAlreadyRegistered( int id );
00111 
00115   static inline int init();
00116 
00120   static int initBuiltins() { return init(); }
00121 
00122 private:
00123   MetaType();
00124 };
00125 #endif
00126 
00127 namespace
00128 {
00129 
00130 /*
00131  * This is a helper to select an appropriate overload of indexAccess
00132  */
00133 template<typename RealType, typename HandleAs>
00134 struct LookupTrait
00135 {
00136   static QVariant doLookUp( const QVariant &object, const QString &property );
00137 };
00138 
00139 template<typename T>
00140 struct IsQObjectStar
00141 {
00142   enum { Yes = false };
00143 };
00144 
00145 template<typename T>
00146 struct IsQObjectStar<T*>
00147 {
00148   typedef int yes_type;
00149   typedef char no_type;
00150 
00151   static yes_type check(QObject*);
00152   static no_type check(...);
00153   enum { Yes = sizeof(check(static_cast<T*>(0))) == sizeof(yes_type) };
00154 };
00155 
00156 template<typename T, bool>
00157 struct LookupPointer
00158 {
00159   static QVariant doLookUp( const QVariant &object, const QString &property )
00160   {
00161     typedef typename Grantlee::TypeAccessor<T> Accessor;
00162     return Accessor::lookUp( object.value<T>(), property );
00163   }
00164 };
00165 
00166 template<typename T>
00167 struct LookupPointer<T, true>
00168 {
00169   static QVariant doLookUp( const QVariant &object, const QString &property )
00170   {
00171     typedef typename Grantlee::TypeAccessor<QObject*> Accessor;
00172     return Accessor::lookUp( object.value<T>(), property );
00173   }
00174 };
00175 
00176 template<typename RealType>
00177 struct LookupTrait<RealType*, RealType*>
00178 {
00179   static QVariant doLookUp( const QVariant &object, const QString &property )
00180   {
00181     return LookupPointer<RealType*, IsQObjectStar<RealType*>::Yes>::doLookUp(object, property);
00182   }
00183 };
00184 
00185 template<typename RealType, typename HandleAs>
00186 struct LookupTrait<RealType&, HandleAs&>
00187 {
00188   static QVariant doLookUp( const QVariant &object, const QString &property )
00189   {
00190     typedef typename Grantlee::TypeAccessor<HandleAs&> Accessor;
00191     return Accessor::lookUp( static_cast<HandleAs>( object.value<RealType>() ), property );
00192   }
00193 };
00194 
00195 template<typename RealType, typename HandleAs>
00196 static int doRegister( int id )
00197 {
00198   if ( MetaType::lookupAlreadyRegistered( id ) )
00199     return id;
00200 
00201   QVariant ( *lf )( const QVariant&, const QString& ) = LookupTrait<RealType, HandleAs>::doLookUp;
00202 
00203   MetaType::registerLookUpOperator( id, reinterpret_cast<MetaType::LookupFunction>( lf ) );
00204 
00205   return id;
00206 }
00207 
00208 /*
00209  * Register a type so grantlee knows how to handle it.
00210  */
00211 template<typename RealType, typename HandleAs>
00212 struct InternalRegisterType
00213 {
00214   static int doReg() {
00215     const int id = qMetaTypeId<RealType>();
00216     return doRegister<RealType&, HandleAs&>( id );
00217   }
00218 };
00219 
00220 template<typename RealType, typename HandleAs>
00221 struct InternalRegisterType<RealType*, HandleAs*>
00222 {
00223   static int doReg() {
00224     const int id = qMetaTypeId<RealType*>();
00225     return doRegister<RealType*, HandleAs*>( id );
00226   }
00227 };
00228 
00229 template<typename Container, typename HandleAs>
00230 int registerSequentialContainer()
00231 {
00232   const int id = InternalRegisterType<Container, HandleAs>::doReg();
00233 
00234   if ( MetaType::toListAlreadyRegistered( id ) )
00235     return id;
00236 
00237   QVariantList ( *tlf )( const QVariant& ) = SequentialContainerAccessor<Container>::doToList;
00238   MetaType::registerToVariantListOperator( id, reinterpret_cast<MetaType::ToVariantListFunction>( tlf ) );
00239   return id;
00240 }
00241 
00242 template<typename Container>
00243 int registerSequentialContainer()
00244 {
00245   return registerSequentialContainer<Container, Container>();
00246 }
00247 
00248 template<typename Container, typename HandleAs>
00249 int registerAssociativeContainer()
00250 {
00251   const int id = InternalRegisterType<Container, HandleAs>::doReg();
00252 
00253   if ( MetaType::toListAlreadyRegistered( id ) )
00254     return id;
00255 
00256   QVariantList ( *tlf )( const QVariant& ) = AssociativeContainerAccessor<Container>::doToList;
00257   MetaType::registerToVariantListOperator( id, reinterpret_cast<MetaType::ToVariantListFunction>( tlf ) );
00258   return id;
00259 }
00260 
00261 template<typename Container>
00262 int registerAssociativeContainer()
00263 {
00264   return registerAssociativeContainer<Container, Container>();
00265 }
00266 
00267 }
00268 
00269 #ifndef Q_QDOC
00270 
00276 template<typename RealType, int n>
00277 struct RegisterTypeContainer
00278 {
00279   static void reg()
00280   {
00281   }
00282 };
00283 #endif
00284 
00285 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
00286 
00287 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(Container, Type)
00288 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, Key, Type)
00289 
00290 #else
00291 
00297 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(Container, Type)                                   \
00298   Grantlee::RegisterTypeContainer<Container<Type>, QMetaTypeId2<Container<Type> >::Defined>::reg();  \
00299 
00300 #ifndef Q_QDOC
00301 
00304 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, Key, Type)                                   \
00305   Grantlee::RegisterTypeContainer<Container<Key, Type>, QMetaTypeId2<Container<Key, Type> >::Defined>::reg();  \
00306 
00307 #endif
00308 
00309 #endif
00310 
00326 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF(Container,          Type)     \
00327     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, QString, Type)     \
00328     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint16,  Type)     \
00329     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint32,  Type)     \
00330     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint64,  Type)     \
00331     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint16, Type)     \
00332     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint32, Type)     \
00333     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint64, Type)     \
00334 
00335 namespace
00336 {
00337 
00338 template<typename T>
00339 void registerContainers()
00340 {
00341   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QList,          T )
00342   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QQueue,         T )
00343   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QVector,        T )
00344   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QStack,         T )
00345   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QSet,           T )
00346   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QLinkedList,    T )
00347 
00348   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( QHash,          T )
00349   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( QMap,           T )
00350 
00351   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::deque,     T )
00352   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::vector,    T )
00353   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::list,      T )
00354   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( std::map,       T )
00355 }
00356 
00357 struct BuiltinRegister
00358 {
00359   void registerBuiltinContainers() const
00360   {
00361     Grantlee::MetaType::internalLock();
00362 
00363     registerContainers< bool      >();
00364     registerContainers< qint16    >();
00365     registerContainers< qint32    >();
00366     registerContainers< qint64    >();
00367     registerContainers< quint16   >();
00368     registerContainers< quint32   >();
00369     registerContainers< quint64   >();
00370     registerContainers< float     >();
00371     registerContainers< double    >();
00372     registerContainers< QString   >();
00373     registerContainers< QVariant  >();
00374     registerContainers< QDateTime >();
00375     registerContainers< QObject*  >();
00376 
00377     registerSequentialContainer<QStringList, QList<QString> >();
00378     Grantlee::MetaType::internalUnlock();
00379   }
00380 };
00381 
00382 Q_GLOBAL_STATIC( BuiltinRegister, builtinRegister )
00383 
00384 }
00385 
00386 #ifndef Q_QDOC
00387 struct MetaTypeInitializer {
00388   static inline int initialize()
00389   {
00390       static const BuiltinRegister *br = builtinRegister();
00391       br->registerBuiltinContainers();
00392       return 0;
00393   }
00394 };
00395 #endif
00396 
00402 #define GRANTLEE_METATYPE_INITIALIZE static const int i = Grantlee::MetaTypeInitializer::initialize(); Q_UNUSED(i)
00403 
00404 #ifndef Q_QDOC
00405 inline int MetaType::init()
00406 {
00407   GRANTLEE_METATYPE_INITIALIZE
00408   return 0;
00409 }
00410 #endif
00411 
00447 template<typename RealType, typename HandleAs>
00448 int registerMetaType()
00449 {
00450   {
00451     GRANTLEE_METATYPE_INITIALIZE
00452     Q_UNUSED( i )
00453   }
00454   MetaType::internalLock();
00455 
00456   const int id = InternalRegisterType<RealType, HandleAs>::doReg();
00457 
00458   registerContainers<RealType>();
00459 
00460   MetaType::internalUnlock();
00461 
00462   return id;
00463 }
00464 
00465 #ifndef Q_QDOC
00466 
00472 template<typename Type>
00473 int registerMetaType()
00474 {
00475   return registerMetaType<Type, Type>();
00476 }
00477 
00478 // http://catb.org/jargon/html/magic-story.html
00479 enum {
00480   Magic,
00481   MoreMagic
00482 };
00483 
00484 #endif
00485 } // namespace Grantlee
00486 
00492 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER(Container)             \
00493 namespace Grantlee {                                                  \
00494 template<typename T>                                                  \
00495 struct RegisterTypeContainer<Container<T>, MoreMagic>                 \
00496 {                                                                     \
00497   static int reg()                                                    \
00498   {                                                                   \
00499     const int id = registerSequentialContainer<Container<T> >();      \
00500     registerContainers<Container<T> >();                              \
00501     return id;                                                        \
00502   }                                                                   \
00503 };                                                                    \
00504 }                                                                     \
00505 
00506 
00511 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER(Container)                     \
00512 namespace Grantlee {                                                           \
00513 template<typename T, typename U>                                               \
00514 struct RegisterTypeContainer<Container<T, U>, MoreMagic>                       \
00515 {                                                                              \
00516   static int reg()                                                             \
00517   {                                                                            \
00518     const int id = registerAssociativeContainer<Container<T, U> >();           \
00519     registerContainers<Container<T, U> >();                                    \
00520     return id;                                                                 \
00521   }                                                                            \
00522 };                                                                             \
00523 }                                                                              \
00524 
00525 #ifndef Q_QDOC
00526 
00529 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS(Container, As)               \
00530 namespace Grantlee {                                                           \
00531 template<typename T>                                                           \
00532 struct RegisterTypeContainer<Container<T>, MoreMagic>                          \
00533 {                                                                              \
00534   static int reg()                                                             \
00535   {                                                                            \
00536     return registerSequentialContainer<Container<T>, As<T> >();                \
00537   }                                                                            \
00538 };                                                                             \
00539 }                                                                              \
00540 
00541 #endif
00542 
00548 #define GRANTLEE_BEGIN_LOOKUP(Type)                                                        \
00549 namespace Grantlee                                                                         \
00550 {                                                                                          \
00551 template<>                                                                                 \
00552 inline QVariant TypeAccessor<Type&>::lookUp( const Type &object, const QString &property ) \
00553 {                                                                                          \
00554 
00555 
00560 #define GRANTLEE_BEGIN_LOOKUP_PTR(Type)                                                            \
00561 namespace Grantlee                                                                                 \
00562 {                                                                                                  \
00563 template<>                                                                                         \
00564 inline QVariant TypeAccessor<Type*>::lookUp( const Type * const object, const QString &property )  \
00565 {                                                                                                  \
00566 
00567 
00572 #define GRANTLEE_END_LOOKUP                                                              \
00573   return QVariant();                                                                     \
00574 }                                                                                        \
00575 }                                                                                        \
00576 
00577 
00578 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QList)
00579 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS (QQueue, QList)
00580 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QVector)
00581 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS (QStack, QVector)
00582 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QSet) // Actually associative, but iterated as a sequential.
00583 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QLinkedList)
00584 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (QHash)
00585 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (QMap)
00586 
00587 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::deque)
00588 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::vector)
00589 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::list)
00590 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (std::map)
00591 
00592 
00593 #endif // #define GRANTLEE_METATYPE_H