Grantlee  0.4.0
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 
00290 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(Container, Type)                                   \
00291   Grantlee::RegisterTypeContainer<Container<Type>, QMetaTypeId2<Container<Type> >::Defined>::reg();  \
00292 
00293 #ifndef Q_QDOC
00294 
00297 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, Key, Type)                                   \
00298   Grantlee::RegisterTypeContainer<Container<Key, Type>, QMetaTypeId2<Container<Key, Type> >::Defined>::reg();  \
00299 
00300 #endif
00301 
00317 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF(Container,          Type)     \
00318     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, QString, Type)     \
00319     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint16,  Type)     \
00320     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint32,  Type)     \
00321     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, qint64,  Type)     \
00322     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint16, Type)     \
00323     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint32, Type)     \
00324     GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_KEY_IF(Container, quint64, Type)     \
00325 
00326 namespace
00327 {
00328 
00329 template<typename T>
00330 void registerContainers()
00331 {
00332   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QList,          T )
00333   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QQueue,         T )
00334   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QVector,        T )
00335   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QStack,         T )
00336   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QSet,           T )
00337   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  QLinkedList,    T )
00338 
00339   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( QHash,          T )
00340   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( QMap,           T )
00341 
00342   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::deque,     T )
00343   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::vector,    T )
00344   GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_IF(  std::list,      T )
00345   GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER_IF( std::map,       T )
00346 }
00347 
00348 struct BuiltinRegister
00349 {
00350   void registerBuiltinContainers() const
00351   {
00352     Grantlee::MetaType::internalLock();
00353 
00354     registerContainers< bool      >();
00355     registerContainers< qint16    >();
00356     registerContainers< qint32    >();
00357     registerContainers< qint64    >();
00358     registerContainers< quint16   >();
00359     registerContainers< quint32   >();
00360     registerContainers< quint64   >();
00361     registerContainers< float     >();
00362     registerContainers< double    >();
00363     registerContainers< QString   >();
00364     registerContainers< QVariant  >();
00365     registerContainers< QDateTime >();
00366     registerContainers< QObject*  >();
00367 
00368     registerSequentialContainer<QStringList, QList<QString> >();
00369     Grantlee::MetaType::internalUnlock();
00370   }
00371 };
00372 
00373 Q_GLOBAL_STATIC( BuiltinRegister, builtinRegister )
00374 
00375 }
00376 
00377 #ifndef Q_QDOC
00378 struct MetaTypeInitializer {
00379   static inline int initialize()
00380   {
00381       static const BuiltinRegister *br = builtinRegister();
00382       br->registerBuiltinContainers();
00383       return 0;
00384   }
00385 };
00386 #endif
00387 
00393 #define GRANTLEE_METATYPE_INITIALIZE static const int i = Grantlee::MetaTypeInitializer::initialize(); Q_UNUSED(i)
00394 
00395 #ifndef Q_QDOC
00396 inline int MetaType::init()
00397 {
00398   GRANTLEE_METATYPE_INITIALIZE
00399   return 0;
00400 }
00401 #endif
00402 
00438 template<typename RealType, typename HandleAs>
00439 int registerMetaType()
00440 {
00441   {
00442     GRANTLEE_METATYPE_INITIALIZE
00443     Q_UNUSED( i )
00444   }
00445   MetaType::internalLock();
00446 
00447   const int id = InternalRegisterType<RealType, HandleAs>::doReg();
00448 
00449   registerContainers<RealType>();
00450 
00451   MetaType::internalUnlock();
00452 
00453   return id;
00454 }
00455 
00456 #ifndef Q_QDOC
00457 
00463 template<typename Type>
00464 int registerMetaType()
00465 {
00466   return registerMetaType<Type, Type>();
00467 }
00468 
00469 // http://catb.org/jargon/html/magic-story.html
00470 enum {
00471   Magic,
00472   MoreMagic
00473 };
00474 
00475 #endif
00476 } // namespace Grantlee
00477 
00483 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER(Container)             \
00484 namespace Grantlee {                                                  \
00485 template<typename T>                                                  \
00486 struct RegisterTypeContainer<Container<T>, MoreMagic>                 \
00487 {                                                                     \
00488   static int reg()                                                    \
00489   {                                                                   \
00490     const int id = registerSequentialContainer<Container<T> >();      \
00491     registerContainers<Container<T> >();                              \
00492     return id;                                                        \
00493   }                                                                   \
00494 };                                                                    \
00495 }                                                                     \
00496 
00497 
00502 #define GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER(Container)                     \
00503 namespace Grantlee {                                                           \
00504 template<typename T, typename U>                                               \
00505 struct RegisterTypeContainer<Container<T, U>, MoreMagic>                       \
00506 {                                                                              \
00507   static int reg()                                                             \
00508   {                                                                            \
00509     const int id = registerAssociativeContainer<Container<T, U> >();           \
00510     registerContainers<Container<T, U> >();                                    \
00511     return id;                                                                 \
00512   }                                                                            \
00513 };                                                                             \
00514 }                                                                              \
00515 
00516 #ifndef Q_QDOC
00517 
00520 #define GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS(Container, As)               \
00521 namespace Grantlee {                                                           \
00522 template<typename T>                                                           \
00523 struct RegisterTypeContainer<Container<T>, MoreMagic>                          \
00524 {                                                                              \
00525   static int reg()                                                             \
00526   {                                                                            \
00527     return registerSequentialContainer<Container<T>, As<T> >();                \
00528   }                                                                            \
00529 };                                                                             \
00530 }                                                                              \
00531 
00532 #endif
00533 
00539 #define GRANTLEE_BEGIN_LOOKUP(Type)                                                        \
00540 namespace Grantlee                                                                         \
00541 {                                                                                          \
00542 template<>                                                                                 \
00543 inline QVariant TypeAccessor<Type&>::lookUp( const Type &object, const QString &property ) \
00544 {                                                                                          \
00545 
00546 
00551 #define GRANTLEE_BEGIN_LOOKUP_PTR(Type)                                                            \
00552 namespace Grantlee                                                                                 \
00553 {                                                                                                  \
00554 template<>                                                                                         \
00555 inline QVariant TypeAccessor<Type*>::lookUp( const Type * const object, const QString &property )  \
00556 {                                                                                                  \
00557 
00558 
00563 #define GRANTLEE_END_LOOKUP                                                              \
00564   return QVariant();                                                                     \
00565 }                                                                                        \
00566 }                                                                                        \
00567 
00568 
00569 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QList)
00570 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS (QQueue, QList)
00571 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QVector)
00572 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER_AS (QStack, QVector)
00573 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QSet) // Actually associative, but iterated as a sequential.
00574 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (QLinkedList)
00575 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (QHash)
00576 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (QMap)
00577 
00578 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::deque)
00579 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::vector)
00580 GRANTLEE_REGISTER_SEQUENTIAL_CONTAINER    (std::list)
00581 GRANTLEE_REGISTER_ASSOCIATIVE_CONTAINER   (std::map)
00582 
00583 
00584 #endif // #define GRANTLEE_METATYPE_H
00585