Optimize type resolution
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlmetatype.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtQml/qqmlprivate.h>
43 #include "qqmlmetatype_p.h"
44
45 #include <private/qqmlproxymetaobject_p.h>
46 #include <private/qqmlcustomparser_p.h>
47 #include <private/qqmlguard_p.h>
48 #include <private/qhashedstring_p.h>
49
50 #include <QtCore/qdebug.h>
51 #include <QtCore/qstringlist.h>
52 #include <QtCore/qmetaobject.h>
53 #include <QtCore/qbitarray.h>
54 #include <QtCore/qreadwritelock.h>
55 #include <QtCore/private/qmetaobject_p.h>
56
57 #include <qmetatype.h>
58 #include <qobjectdefs.h>
59 #include <qbytearray.h>
60 #include <qreadwritelock.h>
61 #include <qstring.h>
62 #include <qstringlist.h>
63 #include <qvector.h>
64
65 #include <ctype.h>
66
67 QT_BEGIN_NAMESPACE
68
69 struct QQmlMetaTypeData
70 {
71     QQmlMetaTypeData();
72     ~QQmlMetaTypeData();
73     QList<QQmlType *> types;
74     typedef QHash<int, QQmlType *> Ids;
75     Ids idToType;
76     typedef QHash<QHashedStringRef,QQmlType *> Names;
77     Names nameToType;
78     typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
79     MetaObjects metaObjectToType;
80     typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
81     StringConverters stringConverters;
82
83     struct VersionedUri {
84         VersionedUri()
85         : majorVersion(0) {}
86         VersionedUri(const QHashedString &uri, int majorVersion)
87         : uri(uri), majorVersion(majorVersion) {}
88         bool operator==(const VersionedUri &other) const {
89             return other.majorVersion == majorVersion && other.uri == uri;
90         }
91         QHashedString uri;
92         int majorVersion;
93     };
94     typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
95     TypeModules uriToModule;
96
97     struct ModuleApiList {
98         ModuleApiList() : sorted(true) {}
99         QList<QQmlMetaType::ModuleApi> moduleApis;
100         bool sorted;
101     };
102     typedef QStringHash<ModuleApiList> ModuleApis;
103     ModuleApis moduleApis;
104     int moduleApiCount;
105
106     QBitArray objects;
107     QBitArray interfaces;
108     QBitArray lists;
109
110     QList<QQmlPrivate::AutoParentFunction> parentFunctions;
111 };
112
113 class QQmlTypeModulePrivate
114 {
115 public:
116     QQmlTypeModulePrivate() 
117     : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
118
119     QQmlMetaTypeData::VersionedUri uri;
120
121     int minMinorVersion;
122     int maxMinorVersion;
123
124     void add(QQmlType *);
125
126     QStringHash<QList<QQmlType *> > typeHash;
127     QList<QQmlType *> types;
128 };
129
130 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
131 Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
132
133 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
134 {
135     return v.uri.hash() ^ qHash(v.majorVersion);
136 }
137
138 QQmlMetaTypeData::QQmlMetaTypeData()
139 : moduleApiCount(0)
140 {
141 }
142
143 QQmlMetaTypeData::~QQmlMetaTypeData()
144 {
145     for (int i = 0; i < types.count(); ++i)
146         delete types.at(i);
147 }
148
149 class QQmlTypePrivate
150 {
151 public:
152     QQmlTypePrivate();
153
154     void init() const;
155     void initEnums() const;
156
157     bool m_isInterface : 1;
158     const char *m_iid;
159     QHashedString m_module;
160     QString m_name;
161     QString m_elementName;
162     int m_version_maj;
163     int m_version_min;
164     int m_typeId; int m_listId; 
165     int m_revision;
166     mutable bool m_containsRevisionedAttributes;
167     mutable QQmlType *m_superType;
168
169     int m_allocationSize;
170     void (*m_newFunc)(void *);
171     QString m_noCreationReason;
172
173     const QMetaObject *m_baseMetaObject;
174     QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
175     const QMetaObject *m_attachedPropertiesType;
176     int m_attachedPropertiesId;
177     int m_parserStatusCast;
178     int m_propertyValueSourceCast;
179     int m_propertyValueInterceptorCast;
180     QObject *(*m_extFunc)(QObject *);
181     const QMetaObject *m_extMetaObject;
182     int m_index;
183     QQmlCustomParser *m_customParser;
184     mutable volatile bool m_isSetup:1;
185     mutable volatile bool m_isEnumSetup:1;
186     mutable bool m_haveSuperType:1;
187     mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
188     mutable QStringHash<int> m_enums;
189
190     static QHash<const QMetaObject *, int> m_attachedPropertyIds;
191 };
192
193 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
194
195 QQmlTypePrivate::QQmlTypePrivate()
196 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
197   m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), 
198   m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), 
199   m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), 
200   m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
201 {
202 }
203
204
205 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
206 : d(new QQmlTypePrivate)
207 {
208     d->m_isInterface = true;
209     d->m_iid = interface.iid;
210     d->m_typeId = interface.typeId;
211     d->m_listId = interface.listId;
212     d->m_newFunc = 0;
213     d->m_index = index;
214     d->m_isSetup = true;
215     d->m_version_maj = 0;
216     d->m_version_min = 0;
217 }
218
219 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
220 : d(new QQmlTypePrivate)
221 {
222     d->m_module = QString::fromUtf8(type.uri);
223     d->m_elementName = QString::fromUtf8(type.elementName);
224
225     if (!d->m_module.isEmpty())
226         d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
227     else
228         d->m_name = d->m_elementName;
229
230     d->m_version_maj = type.versionMajor;
231     d->m_version_min = type.versionMinor;
232     if (type.version >= 1) // revisions added in version 1
233         d->m_revision = type.revision;
234     d->m_typeId = type.typeId;
235     d->m_listId = type.listId;
236     d->m_allocationSize = type.objectSize;
237     d->m_newFunc = type.create;
238     d->m_noCreationReason = type.noCreationReason;
239     d->m_baseMetaObject = type.metaObject;
240     d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
241     d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
242     if (d->m_attachedPropertiesType) {
243         QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
244         if (iter == d->m_attachedPropertyIds.end())
245             iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
246         d->m_attachedPropertiesId = *iter;
247     } else {
248         d->m_attachedPropertiesId = -1;
249     }
250     d->m_parserStatusCast = type.parserStatusCast;
251     d->m_propertyValueSourceCast = type.valueSourceCast;
252     d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
253     d->m_extFunc = type.extensionObjectCreate;
254     d->m_index = index;
255     d->m_customParser = type.customParser;
256
257     if (type.extensionMetaObject)
258         d->m_extMetaObject = type.extensionMetaObject;
259 }
260
261 QQmlType::~QQmlType()
262 {
263     delete d->m_customParser;
264     delete d;
265 }
266
267 const QHashedString &QQmlType::module() const
268 {
269     return d->m_module;
270 }
271
272 int QQmlType::majorVersion() const
273 {
274     return d->m_version_maj;
275 }
276
277 int QQmlType::minorVersion() const
278 {
279     return d->m_version_min;
280 }
281
282 bool QQmlType::availableInVersion(int vmajor, int vminor) const
283 {
284     Q_ASSERT(vmajor >= 0 && vminor >= 0);
285     return vmajor == d->m_version_maj && vminor >= d->m_version_min;
286 }
287
288 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
289 {
290     Q_ASSERT(vmajor >= 0 && vminor >= 0);
291     return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
292 }
293
294 // returns the nearest _registered_ super class
295 QQmlType *QQmlType::superType() const
296 {
297     if (!d->m_haveSuperType) {
298         const QMetaObject *mo = d->m_baseMetaObject->superClass();
299         while (mo && !d->m_superType) {
300             d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
301             mo = mo->superClass();
302         }
303         d->m_haveSuperType = true;
304     }
305
306     return d->m_superType;
307 }
308
309 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, 
310                   const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
311 {
312     // Set classname
313     builder.setClassName(ignoreEnd->className());
314
315     // Clone Q_CLASSINFO
316     for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
317         QMetaClassInfo info = mo->classInfo(ii);
318
319         int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
320         if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
321             // Skip 
322         } else {
323             builder.addClassInfo(info.name(), info.value());
324         }
325     }
326
327     // Clone Q_PROPERTY
328     for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
329         QMetaProperty property = mo->property(ii);
330
331         int otherIndex = ignoreEnd->indexOfProperty(property.name());
332         if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
333             builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
334             // Skip 
335         } else {
336             builder.addProperty(property);
337         }
338     }
339
340     // Clone Q_METHODS
341     for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
342         QMetaMethod method = mo->method(ii);
343
344         // More complex - need to search name
345         QByteArray name = method.name();
346
347
348         bool found = false;
349
350         for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); 
351              !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
352              ++ii) {
353
354             QMetaMethod other = ignoreEnd->method(ii);
355
356             found = name == other.name();
357         }
358
359         QMetaMethodBuilder m = builder.addMethod(method);
360         if (found) // SKIP
361             m.setAccess(QMetaMethod::Private);
362     }
363
364     // Clone Q_ENUMS
365     for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
366         QMetaEnum enumerator = mo->enumerator(ii);
367
368         int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
369         if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
370             // Skip 
371         } else {
372             builder.addEnumerator(enumerator);
373         }
374     }
375 }
376
377 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
378 {
379     int i = index;
380     i -= mo->propertyOffset();
381     if (i < 0 && mo->d.superdata)
382         return isPropertyRevisioned(mo->d.superdata, index);
383
384     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
385     if (i >= 0 && i < mop->propertyCount) {
386         int handle = mop->propertyData + 3*i;
387         int flags = mo->d.data[handle + 2];
388
389         return (flags & Revisioned);
390     }
391
392     return false;
393 }
394
395 void QQmlTypePrivate::init() const
396 {
397     if (m_isSetup) return;
398
399     QWriteLocker lock(metaTypeDataLock());
400     if (m_isSetup)
401         return;
402
403     // Setup extended meta object
404     // XXX - very inefficient
405     const QMetaObject *mo = m_baseMetaObject;
406     if (m_extFunc) {
407         QMetaObjectBuilder builder;
408         clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
409         builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
410         QMetaObject *mmo = builder.toMetaObject();
411         mmo->d.superdata = mo;
412         QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
413         m_metaObjects << data;
414     }
415
416     mo = mo->d.superdata;
417     while(mo) {
418         QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
419         if (t) {
420             if (t->d->m_extFunc) {
421                 QMetaObjectBuilder builder;
422                 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
423                 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
424                 QMetaObject *mmo = builder.toMetaObject();
425                 mmo->d.superdata = m_baseMetaObject;
426                 if (!m_metaObjects.isEmpty())
427                     m_metaObjects.last().metaObject->d.superdata = mmo;
428                 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
429                 m_metaObjects << data;
430             }
431         }
432         mo = mo->d.superdata;
433     }
434
435     for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
436         m_metaObjects[ii].propertyOffset =
437             m_metaObjects.at(ii).metaObject->propertyOffset();
438         m_metaObjects[ii].methodOffset =
439             m_metaObjects.at(ii).metaObject->methodOffset();
440     }
441     
442     // Check for revisioned details
443     {
444         const QMetaObject *mo = 0;
445         if (m_metaObjects.isEmpty())
446             mo = m_baseMetaObject;
447         else
448             mo = m_metaObjects.first().metaObject;
449
450         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
451             if (isPropertyRevisioned(mo, ii))
452                 m_containsRevisionedAttributes = true;
453         }
454
455         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
456             if (mo->method(ii).revision() != 0)
457                 m_containsRevisionedAttributes = true;
458         }
459     }
460
461     m_isSetup = true;
462     lock.unlock();
463 }
464
465 void QQmlTypePrivate::initEnums() const
466 {
467     if (m_isEnumSetup) return;
468
469     init();
470
471     QWriteLocker lock(metaTypeDataLock());
472     if (m_isEnumSetup) return;
473
474     const QMetaObject *metaObject = m_baseMetaObject;
475     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
476
477         QMetaEnum e = metaObject->enumerator(ii);
478
479         for (int jj = 0; jj < e.keyCount(); ++jj) 
480             m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
481     }
482
483     m_isEnumSetup = true;
484 }
485
486 QByteArray QQmlType::typeName() const
487 {
488     if (d->m_baseMetaObject)
489         return d->m_baseMetaObject->className();
490     else
491         return QByteArray();
492 }
493
494 const QString &QQmlType::elementName() const
495 {
496     return d->m_elementName;
497 }
498
499 const QString &QQmlType::qmlTypeName() const
500 {
501     return d->m_name;
502 }
503
504 QObject *QQmlType::create() const
505 {
506     d->init();
507
508     QObject *rv = (QObject *)operator new(d->m_allocationSize);
509     d->m_newFunc(rv);
510
511     if (rv && !d->m_metaObjects.isEmpty())
512         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
513
514     return rv;
515 }
516
517 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
518 {
519     d->init();
520
521     QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
522     d->m_newFunc(rv);
523
524     if (rv && !d->m_metaObjects.isEmpty())
525         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
526
527     *out = rv;
528     *memory = ((char *)rv) + d->m_allocationSize;
529 }
530
531 QQmlCustomParser *QQmlType::customParser() const
532 {
533     return d->m_customParser;
534 }
535
536 QQmlType::CreateFunc QQmlType::createFunction() const
537 {
538     return d->m_newFunc;
539 }
540
541 QString QQmlType::noCreationReason() const
542 {
543     return d->m_noCreationReason;
544 }
545
546 int QQmlType::createSize() const
547 {
548     return d->m_allocationSize;
549 }
550
551 bool QQmlType::isCreatable() const
552 {
553     return d->m_newFunc != 0;
554 }
555
556 bool QQmlType::isExtendedType() const
557 {
558     d->init();
559
560     return !d->m_metaObjects.isEmpty();
561 }
562
563 bool QQmlType::isInterface() const
564 {
565     return d->m_isInterface;
566 }
567
568 int QQmlType::typeId() const
569 {
570     return d->m_typeId;
571 }
572
573 int QQmlType::qListTypeId() const
574 {
575     return d->m_listId;
576 }
577
578 const QMetaObject *QQmlType::metaObject() const
579 {
580     d->init();
581
582     if (d->m_metaObjects.isEmpty())
583         return d->m_baseMetaObject;
584     else
585         return d->m_metaObjects.first().metaObject;
586
587 }
588
589 const QMetaObject *QQmlType::baseMetaObject() const
590 {
591     return d->m_baseMetaObject;
592 }
593
594 bool QQmlType::containsRevisionedAttributes() const
595 {
596     d->init();
597
598     return d->m_containsRevisionedAttributes;
599 }
600
601 int QQmlType::metaObjectRevision() const
602 {
603     return d->m_revision;
604 }
605
606 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
607 {
608     return d->m_attachedPropertiesFunc;
609 }
610
611 const QMetaObject *QQmlType::attachedPropertiesType() const
612 {
613     return d->m_attachedPropertiesType;
614 }
615
616 /*
617 This is the id passed to qmlAttachedPropertiesById().  This is different from the index
618 for the case that a single class is registered under two or more names (eg. Item in 
619 Qt 4.7 and QtQuick 1.0).
620 */
621 int QQmlType::attachedPropertiesId() const
622 {
623     return d->m_attachedPropertiesId;
624 }
625
626 int QQmlType::parserStatusCast() const
627 {
628     return d->m_parserStatusCast;
629 }
630
631 int QQmlType::propertyValueSourceCast() const
632 {
633     return d->m_propertyValueSourceCast;
634 }
635
636 int QQmlType::propertyValueInterceptorCast() const
637 {
638     return d->m_propertyValueInterceptorCast;
639 }
640
641 const char *QQmlType::interfaceIId() const
642 {
643     return d->m_iid;
644 }
645
646 int QQmlType::index() const
647 {
648     return d->m_index;
649 }
650
651 int QQmlType::enumValue(const QHashedStringRef &name) const
652 {
653     d->initEnums();
654
655     int *rv = d->m_enums.value(name);
656     return rv?*rv:-1;
657 }
658
659 int QQmlType::enumValue(const QHashedV8String &name) const
660 {
661     d->initEnums();
662
663     int *rv = d->m_enums.value(name);
664     return rv?*rv:-1;
665 }
666
667 QQmlTypeModule::QQmlTypeModule()
668 : d(new QQmlTypeModulePrivate)
669 {
670 }
671
672 QQmlTypeModule::~QQmlTypeModule()
673 {
674     delete d; d = 0;
675 }
676
677 QString QQmlTypeModule::module() const
678 {
679     return d->uri.uri;
680 }
681
682 int QQmlTypeModule::majorVersion() const
683 {
684     return d->uri.majorVersion;
685 }
686
687 int QQmlTypeModule::minimumMinorVersion() const
688 {
689     return d->minMinorVersion;
690 }
691
692 int QQmlTypeModule::maximumMinorVersion() const
693 {
694     return d->maxMinorVersion;
695 }
696
697 void QQmlTypeModulePrivate::add(QQmlType *type)
698 {
699     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
700     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
701
702     QList<QQmlType *> &list = typeHash[type->elementName()];
703     for (int ii = 0; ii < list.count(); ++ii) {
704         if (list.at(ii)->minorVersion() < type->minorVersion()) {
705             list.insert(ii, type);
706             return;
707         }
708     }
709     list.append(type);
710 }
711
712 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
713 {
714     QReadLocker lock(metaTypeDataLock());
715
716     QList<QQmlType *> *types = d->typeHash.value(name);
717     if (!types) return 0;
718
719     for (int ii = 0; ii < types->count(); ++ii)
720         if (types->at(ii)->minorVersion() <= minor)
721             return types->at(ii);
722
723     return 0;
724 }
725
726 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
727 {
728     QReadLocker lock(metaTypeDataLock());
729
730     QList<QQmlType *> *types = d->typeHash.value(name);
731     if (!types) return 0;
732
733     for (int ii = 0; ii < types->count(); ++ii)
734         if (types->at(ii)->minorVersion() <= minor)
735             return types->at(ii);
736
737     return 0;
738 }
739
740
741 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
742 : m_module(0), m_minor(0)
743 {
744 }
745
746 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
747 : m_module(module), m_minor(minor)
748 {
749     Q_ASSERT(m_module);
750     Q_ASSERT(m_minor >= 0);
751 }
752
753 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
754 : m_module(o.m_module), m_minor(o.m_minor)
755 {
756 }
757
758 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
759 {
760     m_module = o.m_module;
761     m_minor = o.m_minor;
762     return *this;
763 }
764
765 QQmlTypeModule *QQmlTypeModuleVersion::module() const
766 {
767     return m_module;
768 }
769
770 int QQmlTypeModuleVersion::minorVersion() const
771 {
772     return m_minor;
773 }
774
775 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
776 {
777     if (m_module) return m_module->type(name, m_minor);
778     else return 0;
779 }
780
781 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
782 {
783     if (m_module) return m_module->type(name, m_minor);
784     else return 0;
785 }
786
787
788 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
789 {
790     QWriteLocker lock(metaTypeDataLock());
791     QQmlMetaTypeData *data = metaTypeData();
792
793     data->parentFunctions.append(autoparent.function);
794
795     return data->parentFunctions.count() - 1;
796 }
797
798 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
799 {
800     if (interface.version > 0) 
801         qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
802
803     QWriteLocker lock(metaTypeDataLock());
804     QQmlMetaTypeData *data = metaTypeData();
805
806     int index = data->types.count();
807
808     QQmlType *type = new QQmlType(index, interface);
809
810     data->types.append(type);
811     data->idToType.insert(type->typeId(), type);
812     data->idToType.insert(type->qListTypeId(), type);
813     // XXX No insertMulti, so no multi-version interfaces?
814     if (!type->elementName().isEmpty())
815         data->nameToType.insert(type->elementName(), type);
816
817     if (data->interfaces.size() <= interface.typeId)
818         data->interfaces.resize(interface.typeId + 16);
819     if (data->lists.size() <= interface.listId)
820         data->lists.resize(interface.listId + 16);
821     data->interfaces.setBit(interface.typeId, true);
822     data->lists.setBit(interface.listId, true);
823
824     return index;
825 }
826
827 int registerType(const QQmlPrivate::RegisterType &type)
828 {
829     if (type.elementName) {
830         for (int ii = 0; type.elementName[ii]; ++ii) {
831             if (!isalnum(type.elementName[ii])) {
832                 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
833                 return -1;
834             }
835         }
836     }
837
838     QWriteLocker lock(metaTypeDataLock());
839     QQmlMetaTypeData *data = metaTypeData();
840     int index = data->types.count();
841
842     QQmlType *dtype = new QQmlType(index, type);
843
844     data->types.append(dtype);
845     data->idToType.insert(dtype->typeId(), dtype);
846     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
847
848     if (!dtype->elementName().isEmpty())
849         data->nameToType.insertMulti(dtype->elementName(), dtype);
850
851     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
852
853     if (data->objects.size() <= type.typeId)
854         data->objects.resize(type.typeId + 16);
855     if (data->lists.size() <= type.listId)
856         data->lists.resize(type.listId + 16);
857     data->objects.setBit(type.typeId, true);
858     if (type.listId) data->lists.setBit(type.listId, true);
859
860     if (!dtype->module().isEmpty()) {
861         const QHashedString &mod = dtype->module();
862
863         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
864         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
865         if (!module) {
866             module = new QQmlTypeModule;
867             module->d->uri = versionedUri;
868             data->uriToModule.insert(versionedUri, module);
869         }
870         module->d->add(dtype);
871     }
872
873     return index;
874 }
875
876 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
877 {
878     QWriteLocker lock(metaTypeDataLock());
879
880     QQmlMetaTypeData *data = metaTypeData();
881     QString uri = QString::fromUtf8(api.uri);
882     QQmlMetaType::ModuleApi import;
883     import.major = api.versionMajor;
884     import.minor = api.versionMinor;
885     import.script = api.scriptApi;
886     import.qobject = api.qobjectApi;
887     import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
888
889     if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO.
890         qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!";
891
892     int index = data->moduleApiCount++;
893
894     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
895     if (!apiList) {
896         QQmlMetaTypeData::ModuleApiList apis;
897         apis.moduleApis << import;
898         data->moduleApis.insert(uri, apis);
899     } else {
900         apiList->moduleApis << import;
901         apiList->sorted = false;
902     }
903
904     return index;
905 }
906
907
908 /*
909 This method is "over generalized" to allow us to (potentially) register more types of things in
910 the future without adding exported symbols.
911 */
912 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
913 {
914     if (type == TypeRegistration) {
915         return registerType(*reinterpret_cast<RegisterType *>(data));
916     } else if (type == InterfaceRegistration) {
917         return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
918     } else if (type == AutoParentRegistration) {
919         return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
920     } else if (type == ModuleApiRegistration) {
921         return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
922     }
923     return -1;
924 }
925
926 /*
927     Returns true if a module \a uri of any version is installed.
928 */
929 bool QQmlMetaType::isAnyModule(const QString &uri)
930 {
931     QReadLocker lock(metaTypeDataLock());
932     QQmlMetaTypeData *data = metaTypeData();
933
934     for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
935          iter != data->uriToModule.end(); ++iter) {
936         if ((*iter)->module() == uri)
937             return true;
938     }
939
940     return false;
941 }
942
943 /*
944     Returns true if any type or API has been registered for the given \a module with at least
945     versionMajor.versionMinor, or if types have been registered for \a module with at most
946     versionMajor.versionMinor.
947
948     So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
949 */
950 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
951 {
952     Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
953     QReadLocker lock(metaTypeDataLock());
954
955     QQmlMetaTypeData *data = metaTypeData();
956
957     // first, check Types
958     QQmlTypeModule *tm = 
959         data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
960     if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
961         return true;
962
963     // then, check ModuleApis
964     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
965     if (apiList) {
966         foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
967             if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
968                 return true;
969         }
970     }
971
972     return false;
973 }
974
975 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
976 {
977     QReadLocker lock(metaTypeDataLock());
978     QQmlMetaTypeData *data = metaTypeData();
979     return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
980 }
981
982 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
983 {
984     QReadLocker lock(metaTypeDataLock());
985     QQmlMetaTypeData *data = metaTypeData();
986     return data->parentFunctions;
987 }
988
989 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
990 {
991     return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
992 }
993
994 QQmlMetaType::ModuleApi
995 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
996 {
997     QReadLocker lock(metaTypeDataLock());
998     QQmlMetaTypeData *data = metaTypeData();
999
1000     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1001     if (!apiList)
1002         return ModuleApi();
1003
1004     if (apiList->sorted == false) {
1005         qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1006         apiList->sorted = true;
1007     }
1008
1009     for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1010         const ModuleApi &import = apiList->moduleApis.at(ii);
1011         if (import.major == versionMajor && import.minor <= versionMinor)
1012             return import;
1013     }
1014
1015     return ModuleApi();
1016 }
1017
1018 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1019 {
1020     QReadLocker lock(metaTypeDataLock());
1021     QQmlMetaTypeData *data = metaTypeData();
1022
1023     QHash<QString, QList<ModuleApi> > moduleApis;
1024     QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1025     for (; it != data->moduleApis.end(); ++it)
1026         moduleApis[it.key()] = it.value().moduleApis;
1027
1028     return moduleApis;
1029 }
1030
1031 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1032 {
1033     if (!isQObject(v.userType())) {
1034         if (ok) *ok = false;
1035         return 0;
1036     }
1037
1038     if (ok) *ok = true;
1039
1040     return *(QObject **)v.constData();
1041 }
1042
1043 bool QQmlMetaType::isQObject(int userType)
1044 {
1045     if (userType == QMetaType::QObjectStar)
1046         return true;
1047
1048     QReadLocker lock(metaTypeDataLock());
1049     QQmlMetaTypeData *data = metaTypeData();
1050     return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1051 }
1052
1053 /*
1054     Returns the item type for a list of type \a id.
1055  */
1056 int QQmlMetaType::listType(int id)
1057 {
1058     QReadLocker lock(metaTypeDataLock());
1059     QQmlMetaTypeData *data = metaTypeData();
1060     QQmlType *type = data->idToType.value(id);
1061     if (type && type->qListTypeId() == id)
1062         return type->typeId();
1063     else
1064         return 0;
1065 }
1066
1067 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1068 {
1069     QReadLocker lock(metaTypeDataLock());
1070     QQmlMetaTypeData *data = metaTypeData();
1071
1072     QQmlType *type = data->metaObjectToType.value(mo);
1073     if (type && type->attachedPropertiesFunction())
1074         return type->attachedPropertiesId();
1075     else
1076         return -1;
1077 }
1078
1079 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1080 {
1081     if (id < 0)
1082         return 0;
1083     QReadLocker lock(metaTypeDataLock());
1084     QQmlMetaTypeData *data = metaTypeData();
1085     return data->types.at(id)->attachedPropertiesFunction();
1086 }
1087
1088 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1089 {
1090     int idx = metaObject->indexOfClassInfo("DefaultProperty");
1091     if (-1 == idx)
1092         return QMetaProperty();
1093
1094     QMetaClassInfo info = metaObject->classInfo(idx);
1095     if (!info.value())
1096         return QMetaProperty();
1097
1098     idx = metaObject->indexOfProperty(info.value());
1099     if (-1 == idx)
1100         return QMetaProperty();
1101
1102     return metaObject->property(idx);
1103 }
1104
1105 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1106 {
1107     if (!obj)
1108         return QMetaProperty();
1109
1110     const QMetaObject *metaObject = obj->metaObject();
1111     return defaultProperty(metaObject);
1112 }
1113
1114 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1115 {
1116     int idx = metaObject->indexOfClassInfo("DefaultMethod");
1117     if (-1 == idx)
1118         return QMetaMethod();
1119
1120     QMetaClassInfo info = metaObject->classInfo(idx);
1121     if (!info.value())
1122         return QMetaMethod();
1123
1124     idx = metaObject->indexOfMethod(info.value());
1125     if (-1 == idx)
1126         return QMetaMethod();
1127
1128     return metaObject->method(idx);
1129 }
1130
1131 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1132 {
1133     if (!obj)
1134         return QMetaMethod();
1135
1136     const QMetaObject *metaObject = obj->metaObject();
1137     return defaultMethod(metaObject);
1138 }
1139
1140 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1141 {
1142     if (userType < 0)
1143         return Unknown;
1144     if (userType == QMetaType::QObjectStar)
1145         return Object;
1146
1147     QReadLocker lock(metaTypeDataLock());
1148     QQmlMetaTypeData *data = metaTypeData();
1149     if (userType < data->objects.size() && data->objects.testBit(userType))
1150         return Object;
1151     else if (userType < data->lists.size() && data->lists.testBit(userType))
1152         return List;
1153     else
1154         return Unknown;
1155 }
1156
1157 bool QQmlMetaType::isInterface(int userType)
1158 {
1159     QReadLocker lock(metaTypeDataLock());
1160     QQmlMetaTypeData *data = metaTypeData();
1161     return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1162 }
1163
1164 const char *QQmlMetaType::interfaceIId(int userType)
1165 {
1166     QReadLocker lock(metaTypeDataLock());
1167     QQmlMetaTypeData *data = metaTypeData();
1168     QQmlType *type = data->idToType.value(userType);
1169     lock.unlock();
1170     if (type && type->isInterface() && type->typeId() == userType)
1171         return type->interfaceIId();
1172     else
1173         return 0;
1174 }
1175
1176 bool QQmlMetaType::isList(int userType)
1177 {
1178     QReadLocker lock(metaTypeDataLock());
1179     QQmlMetaTypeData *data = metaTypeData();
1180     return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1181 }
1182
1183 /*!
1184     A custom string convertor allows you to specify a function pointer that
1185     returns a variant of \a type. For example, if you have written your own icon
1186     class that you want to support as an object property assignable in QML:
1187
1188     \code
1189     int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1190     QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1191     \endcode
1192
1193     The function pointer must be of the form:
1194     \code
1195     QVariant (*StringConverter)(const QString &);
1196     \endcode
1197  */
1198 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1199 {
1200     QWriteLocker lock(metaTypeDataLock());
1201
1202     QQmlMetaTypeData *data = metaTypeData();
1203     if (data->stringConverters.contains(type))
1204         return;
1205     data->stringConverters.insert(type, converter);
1206 }
1207
1208 /*!
1209     Return the custom string converter for \a type, previously installed through
1210     registerCustomStringConverter()
1211  */
1212 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1213 {
1214     QReadLocker lock(metaTypeDataLock());
1215
1216     QQmlMetaTypeData *data = metaTypeData();
1217     return data->stringConverters.value(type);
1218 }
1219
1220 /*!
1221     Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1222     by \a version_major and \a version_minor.
1223 */
1224 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1225 {
1226     int slash = qualifiedName.indexOf(QLatin1Char('/'));
1227     if (slash <= 0)
1228         return 0;
1229
1230     QHashedStringRef module(qualifiedName.constData(), slash);
1231     QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1232
1233     return qmlType(name, module, version_major, version_minor);
1234 }
1235
1236 /*!
1237     Returns the type (if any) of \a name in \a module and version specified
1238     by \a version_major and \a version_minor.
1239 */
1240 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1241 {
1242     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1243     QReadLocker lock(metaTypeDataLock());
1244     QQmlMetaTypeData *data = metaTypeData();
1245
1246     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1247     while (it != data->nameToType.end() && it.key() == name) {
1248         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1249         if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1250             return (*it);
1251         ++it;
1252     }
1253
1254     return 0;
1255 }
1256
1257 /*!
1258     Returns the type (if any) that corresponds to the \a metaObject.  Returns null if no
1259     type is registered.
1260 */
1261 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1262 {
1263     QReadLocker lock(metaTypeDataLock());
1264     QQmlMetaTypeData *data = metaTypeData();
1265
1266     return data->metaObjectToType.value(metaObject);
1267 }
1268
1269 /*!
1270     Returns the type (if any) that corresponds to the \a metaObject in version specified
1271     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
1272     type is registered.
1273 */
1274 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1275 {
1276     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1277     QReadLocker lock(metaTypeDataLock());
1278     QQmlMetaTypeData *data = metaTypeData();
1279
1280     QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1281     while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1282         QQmlType *t = *it;
1283         if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1284             return t;
1285         ++it;
1286     }
1287
1288     return 0;
1289 }
1290
1291 /*!
1292     Returns the type (if any) that corresponds to the QVariant::Type \a userType.  
1293     Returns null if no type is registered.
1294 */
1295 QQmlType *QQmlMetaType::qmlType(int userType)
1296 {
1297     QReadLocker lock(metaTypeDataLock());
1298     QQmlMetaTypeData *data = metaTypeData();
1299
1300     QQmlType *type = data->idToType.value(userType);
1301     if (type && type->typeId() == userType)
1302         return type;
1303     else
1304         return 0;
1305 }
1306
1307 /*!
1308     Returns the list of registered QML type names.
1309 */
1310 QList<QString> QQmlMetaType::qmlTypeNames()
1311 {
1312     QReadLocker lock(metaTypeDataLock());
1313     QQmlMetaTypeData *data = metaTypeData();
1314
1315     QList<QString> names;
1316     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1317     while (it != data->nameToType.end()) {
1318         names += (*it)->qmlTypeName();
1319         ++it;
1320     }
1321
1322     return names;
1323 }
1324
1325 /*!
1326     Returns the list of registered QML types.
1327 */
1328 QList<QQmlType*> QQmlMetaType::qmlTypes()
1329 {
1330     QReadLocker lock(metaTypeDataLock());
1331     QQmlMetaTypeData *data = metaTypeData();
1332
1333     return data->nameToType.values();
1334 }
1335
1336 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1337 {
1338     static int id = 0;
1339     if (!id) {
1340         id = QMetaType::type("QQuickAnchorLine");
1341     }
1342     return id;
1343 }
1344
1345 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1346
1347 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1348 {
1349     anchorLineCompareFunction = fun;
1350 }
1351
1352 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1353 {
1354     Q_ASSERT(anchorLineCompareFunction != 0);
1355     return anchorLineCompareFunction(p1, p2);
1356 }
1357
1358 QT_END_NAMESPACE