Merge remote-tracking branch 'origin/master' into api_changes
[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<QString, 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 QString &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         QString 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 QHash<QString, 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 qHash(v.uri) ^ 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     QString 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     QString name = QString::fromUtf8(type.uri);
223     if (type.uri) name += QLatin1Char('/');
224     name += QString::fromUtf8(type.elementName);
225
226     d->m_module = QString::fromUtf8(type.uri);
227     d->m_name = name;
228     d->m_version_maj = type.versionMajor;
229     d->m_version_min = type.versionMinor;
230     if (type.version >= 1) // revisions added in version 1
231         d->m_revision = type.revision;
232     d->m_typeId = type.typeId;
233     d->m_listId = type.listId;
234     d->m_allocationSize = type.objectSize;
235     d->m_newFunc = type.create;
236     d->m_noCreationReason = type.noCreationReason;
237     d->m_baseMetaObject = type.metaObject;
238     d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
239     d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
240     if (d->m_attachedPropertiesType) {
241         QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
242         if (iter == d->m_attachedPropertyIds.end())
243             iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
244         d->m_attachedPropertiesId = *iter;
245     } else {
246         d->m_attachedPropertiesId = -1;
247     }
248     d->m_parserStatusCast = type.parserStatusCast;
249     d->m_propertyValueSourceCast = type.valueSourceCast;
250     d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
251     d->m_extFunc = type.extensionObjectCreate;
252     d->m_index = index;
253     d->m_customParser = type.customParser;
254
255     if (type.extensionMetaObject)
256         d->m_extMetaObject = type.extensionMetaObject;
257 }
258
259 QQmlType::~QQmlType()
260 {
261     delete d->m_customParser;
262     delete d;
263 }
264
265 QString QQmlType::module() const
266 {
267     return d->m_module;
268 }
269
270 int QQmlType::majorVersion() const
271 {
272     return d->m_version_maj;
273 }
274
275 int QQmlType::minorVersion() const
276 {
277     return d->m_version_min;
278 }
279
280 bool QQmlType::availableInVersion(int vmajor, int vminor) const
281 {
282     Q_ASSERT(vmajor >= 0 && vminor >= 0);
283     return vmajor == d->m_version_maj && vminor >= d->m_version_min;
284 }
285
286 bool QQmlType::availableInVersion(const QString &module, int vmajor, int vminor) const
287 {
288     Q_ASSERT(vmajor >= 0 && vminor >= 0);
289     return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
290 }
291
292 // returns the nearest _registered_ super class
293 QQmlType *QQmlType::superType() const
294 {
295     if (!d->m_haveSuperType) {
296         const QMetaObject *mo = d->m_baseMetaObject->superClass();
297         while (mo && !d->m_superType) {
298             d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
299             mo = mo->superClass();
300         }
301         d->m_haveSuperType = true;
302     }
303
304     return d->m_superType;
305 }
306
307 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, 
308                   const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
309 {
310     // Set classname
311     builder.setClassName(ignoreEnd->className());
312
313     // Clone Q_CLASSINFO
314     for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
315         QMetaClassInfo info = mo->classInfo(ii);
316
317         int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
318         if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
319             // Skip 
320         } else {
321             builder.addClassInfo(info.name(), info.value());
322         }
323     }
324
325     // Clone Q_PROPERTY
326     for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
327         QMetaProperty property = mo->property(ii);
328
329         int otherIndex = ignoreEnd->indexOfProperty(property.name());
330         if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
331             builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
332             // Skip 
333         } else {
334             builder.addProperty(property);
335         }
336     }
337
338     // Clone Q_METHODS
339     for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
340         QMetaMethod method = mo->method(ii);
341
342         // More complex - need to search name
343         QByteArray name = method.name();
344
345
346         bool found = false;
347
348         for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); 
349              !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
350              ++ii) {
351
352             QMetaMethod other = ignoreEnd->method(ii);
353
354             found = name == other.name();
355         }
356
357         QMetaMethodBuilder m = builder.addMethod(method);
358         if (found) // SKIP
359             m.setAccess(QMetaMethod::Private);
360     }
361
362     // Clone Q_ENUMS
363     for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
364         QMetaEnum enumerator = mo->enumerator(ii);
365
366         int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
367         if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
368             // Skip 
369         } else {
370             builder.addEnumerator(enumerator);
371         }
372     }
373 }
374
375 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
376 {
377     int i = index;
378     i -= mo->propertyOffset();
379     if (i < 0 && mo->d.superdata)
380         return isPropertyRevisioned(mo->d.superdata, index);
381
382     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
383     if (i >= 0 && i < mop->propertyCount) {
384         int handle = mop->propertyData + 3*i;
385         int flags = mo->d.data[handle + 2];
386
387         return (flags & Revisioned);
388     }
389
390     return false;
391 }
392
393 void QQmlTypePrivate::init() const
394 {
395     if (m_isSetup) return;
396
397     QWriteLocker lock(metaTypeDataLock());
398     if (m_isSetup)
399         return;
400
401     // Setup extended meta object
402     // XXX - very inefficient
403     const QMetaObject *mo = m_baseMetaObject;
404     if (m_extFunc) {
405         QMetaObjectBuilder builder;
406         clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
407         builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
408         QMetaObject *mmo = builder.toMetaObject();
409         mmo->d.superdata = mo;
410         QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
411         m_metaObjects << data;
412     }
413
414     mo = mo->d.superdata;
415     while(mo) {
416         QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
417         if (t) {
418             if (t->d->m_extFunc) {
419                 QMetaObjectBuilder builder;
420                 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
421                 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
422                 QMetaObject *mmo = builder.toMetaObject();
423                 mmo->d.superdata = m_baseMetaObject;
424                 if (!m_metaObjects.isEmpty())
425                     m_metaObjects.last().metaObject->d.superdata = mmo;
426                 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
427                 m_metaObjects << data;
428             }
429         }
430         mo = mo->d.superdata;
431     }
432
433     for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
434         m_metaObjects[ii].propertyOffset =
435             m_metaObjects.at(ii).metaObject->propertyOffset();
436         m_metaObjects[ii].methodOffset =
437             m_metaObjects.at(ii).metaObject->methodOffset();
438     }
439     
440     // Check for revisioned details
441     {
442         const QMetaObject *mo = 0;
443         if (m_metaObjects.isEmpty())
444             mo = m_baseMetaObject;
445         else
446             mo = m_metaObjects.first().metaObject;
447
448         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
449             if (isPropertyRevisioned(mo, ii))
450                 m_containsRevisionedAttributes = true;
451         }
452
453         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
454             if (mo->method(ii).revision() != 0)
455                 m_containsRevisionedAttributes = true;
456         }
457     }
458
459     m_isSetup = true;
460     lock.unlock();
461 }
462
463 void QQmlTypePrivate::initEnums() const
464 {
465     if (m_isEnumSetup) return;
466
467     init();
468
469     QWriteLocker lock(metaTypeDataLock());
470     if (m_isEnumSetup) return;
471
472     const QMetaObject *metaObject = m_baseMetaObject;
473     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
474
475         QMetaEnum e = metaObject->enumerator(ii);
476
477         for (int jj = 0; jj < e.keyCount(); ++jj) 
478             m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
479     }
480
481     m_isEnumSetup = true;
482 }
483
484 QByteArray QQmlType::typeName() const
485 {
486     if (d->m_baseMetaObject)
487         return d->m_baseMetaObject->className();
488     else
489         return QByteArray();
490 }
491
492 const QString &QQmlType::elementName() const
493 {
494     if (d->m_elementName.isEmpty()) {
495         QString n = qmlTypeName();
496         int idx = n.lastIndexOf(QLatin1Char('/'));
497         d->m_elementName = n.mid(idx + 1);
498     }
499     return d->m_elementName;
500 }
501
502 const QString &QQmlType::qmlTypeName() const
503 {
504     return d->m_name;
505 }
506
507 QObject *QQmlType::create() const
508 {
509     d->init();
510
511     QObject *rv = (QObject *)operator new(d->m_allocationSize);
512     d->m_newFunc(rv);
513
514     if (rv && !d->m_metaObjects.isEmpty())
515         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
516
517     return rv;
518 }
519
520 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
521 {
522     d->init();
523
524     QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
525     d->m_newFunc(rv);
526
527     if (rv && !d->m_metaObjects.isEmpty())
528         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
529
530     *out = rv;
531     *memory = ((char *)rv) + d->m_allocationSize;
532 }
533
534 QQmlCustomParser *QQmlType::customParser() const
535 {
536     return d->m_customParser;
537 }
538
539 QQmlType::CreateFunc QQmlType::createFunction() const
540 {
541     return d->m_newFunc;
542 }
543
544 QString QQmlType::noCreationReason() const
545 {
546     return d->m_noCreationReason;
547 }
548
549 int QQmlType::createSize() const
550 {
551     return d->m_allocationSize;
552 }
553
554 bool QQmlType::isCreatable() const
555 {
556     return d->m_newFunc != 0;
557 }
558
559 bool QQmlType::isExtendedType() const
560 {
561     d->init();
562
563     return !d->m_metaObjects.isEmpty();
564 }
565
566 bool QQmlType::isInterface() const
567 {
568     return d->m_isInterface;
569 }
570
571 int QQmlType::typeId() const
572 {
573     return d->m_typeId;
574 }
575
576 int QQmlType::qListTypeId() const
577 {
578     return d->m_listId;
579 }
580
581 const QMetaObject *QQmlType::metaObject() const
582 {
583     d->init();
584
585     if (d->m_metaObjects.isEmpty())
586         return d->m_baseMetaObject;
587     else
588         return d->m_metaObjects.first().metaObject;
589
590 }
591
592 const QMetaObject *QQmlType::baseMetaObject() const
593 {
594     return d->m_baseMetaObject;
595 }
596
597 bool QQmlType::containsRevisionedAttributes() const
598 {
599     d->init();
600
601     return d->m_containsRevisionedAttributes;
602 }
603
604 int QQmlType::metaObjectRevision() const
605 {
606     return d->m_revision;
607 }
608
609 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
610 {
611     return d->m_attachedPropertiesFunc;
612 }
613
614 const QMetaObject *QQmlType::attachedPropertiesType() const
615 {
616     return d->m_attachedPropertiesType;
617 }
618
619 /*
620 This is the id passed to qmlAttachedPropertiesById().  This is different from the index
621 for the case that a single class is registered under two or more names (eg. Item in 
622 Qt 4.7 and QtQuick 1.0).
623 */
624 int QQmlType::attachedPropertiesId() const
625 {
626     return d->m_attachedPropertiesId;
627 }
628
629 int QQmlType::parserStatusCast() const
630 {
631     return d->m_parserStatusCast;
632 }
633
634 int QQmlType::propertyValueSourceCast() const
635 {
636     return d->m_propertyValueSourceCast;
637 }
638
639 int QQmlType::propertyValueInterceptorCast() const
640 {
641     return d->m_propertyValueInterceptorCast;
642 }
643
644 const char *QQmlType::interfaceIId() const
645 {
646     return d->m_iid;
647 }
648
649 int QQmlType::index() const
650 {
651     return d->m_index;
652 }
653
654 int QQmlType::enumValue(const QHashedStringRef &name) const
655 {
656     d->initEnums();
657
658     int *rv = d->m_enums.value(name);
659     return rv?*rv:-1;
660 }
661
662 int QQmlType::enumValue(const QHashedV8String &name) const
663 {
664     d->initEnums();
665
666     int *rv = d->m_enums.value(name);
667     return rv?*rv:-1;
668 }
669
670 QQmlTypeModule::QQmlTypeModule()
671 : d(new QQmlTypeModulePrivate)
672 {
673 }
674
675 QQmlTypeModule::~QQmlTypeModule()
676 {
677     delete d; d = 0;
678 }
679
680 QString QQmlTypeModule::module() const
681 {
682     return d->uri.uri;
683 }
684
685 int QQmlTypeModule::majorVersion() const
686 {
687     return d->uri.majorVersion;
688 }
689
690 int QQmlTypeModule::minimumMinorVersion() const
691 {
692     return d->minMinorVersion;
693 }
694
695 int QQmlTypeModule::maximumMinorVersion() const
696 {
697     return d->maxMinorVersion;
698 }
699
700 void QQmlTypeModulePrivate::add(QQmlType *type)
701 {
702     types << type;
703
704     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
705     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
706
707     QList<QQmlType *> &list = typeHash[type->elementName()];
708     for (int ii = 0; ii < list.count(); ++ii) {
709         if (list.at(ii)->minorVersion() < type->minorVersion()) {
710             list.insert(ii, type);
711             return;
712         }
713     }
714     list.append(type);
715 }
716
717 QList<QQmlType *> QQmlTypeModule::types()
718 {
719     QList<QQmlType *> rv;
720     QReadLocker lock(metaTypeDataLock());
721     rv = d->types;
722     return rv;
723 }
724
725 QList<QQmlType *> QQmlTypeModule::type(const QString &name)
726 {
727     QReadLocker lock(metaTypeDataLock());
728     QList<QQmlType *> rv;
729     for (int ii = 0; ii < d->types.count(); ++ii) {
730         if (d->types.at(ii)->elementName() == name)
731             rv << d->types.at(ii);
732     }
733     return rv;
734 }
735
736 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
737 {
738     QReadLocker lock(metaTypeDataLock());
739
740     QList<QQmlType *> *types = d->typeHash.value(name);
741     if (!types) return 0;
742
743     for (int ii = 0; ii < types->count(); ++ii)
744         if (types->at(ii)->minorVersion() <= minor)
745             return types->at(ii);
746
747     return 0;
748 }
749
750 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
751 {
752     QReadLocker lock(metaTypeDataLock());
753
754     QList<QQmlType *> *types = d->typeHash.value(name);
755     if (!types) return 0;
756
757     for (int ii = 0; ii < types->count(); ++ii)
758         if (types->at(ii)->minorVersion() <= minor)
759             return types->at(ii);
760
761     return 0;
762 }
763
764
765 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
766 : m_module(0), m_minor(0)
767 {
768 }
769
770 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
771 : m_module(module), m_minor(minor)
772 {
773     Q_ASSERT(m_module);
774     Q_ASSERT(m_minor >= 0);
775 }
776
777 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
778 : m_module(o.m_module), m_minor(o.m_minor)
779 {
780 }
781
782 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
783 {
784     m_module = o.m_module;
785     m_minor = o.m_minor;
786     return *this;
787 }
788
789 QQmlTypeModule *QQmlTypeModuleVersion::module() const
790 {
791     return m_module;
792 }
793
794 int QQmlTypeModuleVersion::minorVersion() const
795 {
796     return m_minor;
797 }
798
799 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
800 {
801     if (m_module) return m_module->type(name, m_minor);
802     else return 0;
803 }
804
805 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
806 {
807     if (m_module) return m_module->type(name, m_minor);
808     else return 0;
809 }
810
811
812 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
813 {
814     QWriteLocker lock(metaTypeDataLock());
815     QQmlMetaTypeData *data = metaTypeData();
816
817     data->parentFunctions.append(autoparent.function);
818
819     return data->parentFunctions.count() - 1;
820 }
821
822 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
823 {
824     if (interface.version > 0) 
825         qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
826
827     QWriteLocker lock(metaTypeDataLock());
828     QQmlMetaTypeData *data = metaTypeData();
829
830     int index = data->types.count();
831
832     QQmlType *type = new QQmlType(index, interface);
833
834     data->types.append(type);
835     data->idToType.insert(type->typeId(), type);
836     data->idToType.insert(type->qListTypeId(), type);
837     // XXX No insertMulti, so no multi-version interfaces?
838     if (!type->qmlTypeName().isEmpty())
839         data->nameToType.insert(type->qmlTypeName(), type);
840
841     if (data->interfaces.size() <= interface.typeId)
842         data->interfaces.resize(interface.typeId + 16);
843     if (data->lists.size() <= interface.listId)
844         data->lists.resize(interface.listId + 16);
845     data->interfaces.setBit(interface.typeId, true);
846     data->lists.setBit(interface.listId, true);
847
848     return index;
849 }
850
851 int registerType(const QQmlPrivate::RegisterType &type)
852 {
853     if (type.elementName) {
854         for (int ii = 0; type.elementName[ii]; ++ii) {
855             if (!isalnum(type.elementName[ii])) {
856                 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
857                 return -1;
858             }
859         }
860     }
861
862     QWriteLocker lock(metaTypeDataLock());
863     QQmlMetaTypeData *data = metaTypeData();
864     int index = data->types.count();
865
866     QQmlType *dtype = new QQmlType(index, type);
867
868     data->types.append(dtype);
869     data->idToType.insert(dtype->typeId(), dtype);
870     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
871
872     if (!dtype->qmlTypeName().isEmpty())
873         data->nameToType.insertMulti(dtype->qmlTypeName(), dtype);
874
875     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
876
877     if (data->objects.size() <= type.typeId)
878         data->objects.resize(type.typeId + 16);
879     if (data->lists.size() <= type.listId)
880         data->lists.resize(type.listId + 16);
881     data->objects.setBit(type.typeId, true);
882     if (type.listId) data->lists.setBit(type.listId, true);
883
884     if (type.uri) {
885         QString mod = QString::fromUtf8(type.uri);
886
887         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
888         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
889         if (!module) {
890             module = new QQmlTypeModule;
891             module->d->uri = versionedUri;
892             data->uriToModule.insert(versionedUri, module);
893         }
894         module->d->add(dtype);
895     }
896
897     return index;
898 }
899
900 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
901 {
902     QWriteLocker lock(metaTypeDataLock());
903
904     QQmlMetaTypeData *data = metaTypeData();
905     QString uri = QString::fromUtf8(api.uri);
906     QQmlMetaType::ModuleApi import;
907     import.major = api.versionMajor;
908     import.minor = api.versionMinor;
909     import.script = api.scriptApi;
910     import.qobject = api.qobjectApi;
911     import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
912
913     if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO.
914         qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!";
915
916     int index = data->moduleApiCount++;
917
918     QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
919     if (iter == data->moduleApis.end()) {
920         QQmlMetaTypeData::ModuleApiList apis;
921         apis.moduleApis << import;
922         data->moduleApis.insert(uri, apis);
923     } else {
924         iter->moduleApis << import;
925         iter->sorted = false;
926     }
927
928     return index;
929 }
930
931
932 /*
933 This method is "over generalized" to allow us to (potentially) register more types of things in
934 the future without adding exported symbols.
935 */
936 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
937 {
938     if (type == TypeRegistration) {
939         return registerType(*reinterpret_cast<RegisterType *>(data));
940     } else if (type == InterfaceRegistration) {
941         return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
942     } else if (type == AutoParentRegistration) {
943         return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
944     } else if (type == ModuleApiRegistration) {
945         return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
946     }
947     return -1;
948 }
949
950 /*
951     Returns true if a module \a uri of any version is installed.
952 */
953 bool QQmlMetaType::isAnyModule(const QString &uri)
954 {
955     QReadLocker lock(metaTypeDataLock());
956     QQmlMetaTypeData *data = metaTypeData();
957
958     for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
959          iter != data->uriToModule.end(); ++iter) {
960         if ((*iter)->module() == uri)
961             return true;
962     }
963
964     return false;
965 }
966
967 /*
968     Returns true if any type or API has been registered for the given \a module with at least
969     versionMajor.versionMinor, or if types have been registered for \a module with at most
970     versionMajor.versionMinor.
971
972     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.
973 */
974 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
975 {
976     Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
977     QReadLocker lock(metaTypeDataLock());
978
979     QQmlMetaTypeData *data = metaTypeData();
980
981     // first, check Types
982     QQmlTypeModule *tm = 
983         data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
984     if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
985         return true;
986
987     // then, check ModuleApis
988     foreach (const QQmlMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
989         if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
990             return true;
991     }
992
993     return false;
994 }
995
996 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
997 {
998     QReadLocker lock(metaTypeDataLock());
999     QQmlMetaTypeData *data = metaTypeData();
1000     return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1001 }
1002
1003 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1004 {
1005     QReadLocker lock(metaTypeDataLock());
1006     QQmlMetaTypeData *data = metaTypeData();
1007     return data->parentFunctions;
1008 }
1009
1010 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1011 {
1012     return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1013 }
1014
1015 QQmlMetaType::ModuleApi
1016 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1017 {
1018     QReadLocker lock(metaTypeDataLock());
1019     QQmlMetaTypeData *data = metaTypeData();
1020
1021     QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
1022     if (iter == data->moduleApis.end())
1023         return ModuleApi();
1024
1025     if (iter->sorted == false) {
1026         qSort(iter->moduleApis.begin(), iter->moduleApis.end());
1027         iter->sorted = true;
1028     }
1029
1030     for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
1031         const ModuleApi &import = iter->moduleApis.at(ii);
1032         if (import.major == versionMajor && import.minor <= versionMinor)
1033             return import;
1034     }
1035
1036     return ModuleApi();
1037 }
1038
1039 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1040 {
1041     QReadLocker lock(metaTypeDataLock());
1042     QQmlMetaTypeData *data = metaTypeData();
1043
1044     QHash<QString, QList<ModuleApi> > moduleApis;
1045     QHashIterator<QString, QQmlMetaTypeData::ModuleApiList> it(data->moduleApis);
1046     while (it.hasNext()) {
1047         it.next();
1048         moduleApis[it.key()] = it.value().moduleApis;
1049     }
1050
1051     return moduleApis;
1052 }
1053
1054 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1055 {
1056     if (!isQObject(v.userType())) {
1057         if (ok) *ok = false;
1058         return 0;
1059     }
1060
1061     if (ok) *ok = true;
1062
1063     return *(QObject **)v.constData();
1064 }
1065
1066 bool QQmlMetaType::isQObject(int userType)
1067 {
1068     if (userType == QMetaType::QObjectStar)
1069         return true;
1070
1071     QReadLocker lock(metaTypeDataLock());
1072     QQmlMetaTypeData *data = metaTypeData();
1073     return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1074 }
1075
1076 /*
1077     Returns the item type for a list of type \a id.
1078  */
1079 int QQmlMetaType::listType(int id)
1080 {
1081     QReadLocker lock(metaTypeDataLock());
1082     QQmlMetaTypeData *data = metaTypeData();
1083     QQmlType *type = data->idToType.value(id);
1084     if (type && type->qListTypeId() == id)
1085         return type->typeId();
1086     else
1087         return 0;
1088 }
1089
1090 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1091 {
1092     QReadLocker lock(metaTypeDataLock());
1093     QQmlMetaTypeData *data = metaTypeData();
1094
1095     QQmlType *type = data->metaObjectToType.value(mo);
1096     if (type && type->attachedPropertiesFunction())
1097         return type->attachedPropertiesId();
1098     else
1099         return -1;
1100 }
1101
1102 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1103 {
1104     if (id < 0)
1105         return 0;
1106     QReadLocker lock(metaTypeDataLock());
1107     QQmlMetaTypeData *data = metaTypeData();
1108     return data->types.at(id)->attachedPropertiesFunction();
1109 }
1110
1111 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1112 {
1113     int idx = metaObject->indexOfClassInfo("DefaultProperty");
1114     if (-1 == idx)
1115         return QMetaProperty();
1116
1117     QMetaClassInfo info = metaObject->classInfo(idx);
1118     if (!info.value())
1119         return QMetaProperty();
1120
1121     idx = metaObject->indexOfProperty(info.value());
1122     if (-1 == idx)
1123         return QMetaProperty();
1124
1125     return metaObject->property(idx);
1126 }
1127
1128 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1129 {
1130     if (!obj)
1131         return QMetaProperty();
1132
1133     const QMetaObject *metaObject = obj->metaObject();
1134     return defaultProperty(metaObject);
1135 }
1136
1137 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1138 {
1139     int idx = metaObject->indexOfClassInfo("DefaultMethod");
1140     if (-1 == idx)
1141         return QMetaMethod();
1142
1143     QMetaClassInfo info = metaObject->classInfo(idx);
1144     if (!info.value())
1145         return QMetaMethod();
1146
1147     idx = metaObject->indexOfMethod(info.value());
1148     if (-1 == idx)
1149         return QMetaMethod();
1150
1151     return metaObject->method(idx);
1152 }
1153
1154 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1155 {
1156     if (!obj)
1157         return QMetaMethod();
1158
1159     const QMetaObject *metaObject = obj->metaObject();
1160     return defaultMethod(metaObject);
1161 }
1162
1163 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1164 {
1165     if (userType < 0)
1166         return Unknown;
1167     if (userType == QMetaType::QObjectStar)
1168         return Object;
1169
1170     QReadLocker lock(metaTypeDataLock());
1171     QQmlMetaTypeData *data = metaTypeData();
1172     if (userType < data->objects.size() && data->objects.testBit(userType))
1173         return Object;
1174     else if (userType < data->lists.size() && data->lists.testBit(userType))
1175         return List;
1176     else
1177         return Unknown;
1178 }
1179
1180 bool QQmlMetaType::isInterface(int userType)
1181 {
1182     QReadLocker lock(metaTypeDataLock());
1183     QQmlMetaTypeData *data = metaTypeData();
1184     return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1185 }
1186
1187 const char *QQmlMetaType::interfaceIId(int userType)
1188 {
1189     QReadLocker lock(metaTypeDataLock());
1190     QQmlMetaTypeData *data = metaTypeData();
1191     QQmlType *type = data->idToType.value(userType);
1192     lock.unlock();
1193     if (type && type->isInterface() && type->typeId() == userType)
1194         return type->interfaceIId();
1195     else
1196         return 0;
1197 }
1198
1199 bool QQmlMetaType::isList(int userType)
1200 {
1201     QReadLocker lock(metaTypeDataLock());
1202     QQmlMetaTypeData *data = metaTypeData();
1203     return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1204 }
1205
1206 /*!
1207     A custom string convertor allows you to specify a function pointer that
1208     returns a variant of \a type. For example, if you have written your own icon
1209     class that you want to support as an object property assignable in QML:
1210
1211     \code
1212     int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1213     QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1214     \endcode
1215
1216     The function pointer must be of the form:
1217     \code
1218     QVariant (*StringConverter)(const QString &);
1219     \endcode
1220  */
1221 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1222 {
1223     QWriteLocker lock(metaTypeDataLock());
1224
1225     QQmlMetaTypeData *data = metaTypeData();
1226     if (data->stringConverters.contains(type))
1227         return;
1228     data->stringConverters.insert(type, converter);
1229 }
1230
1231 /*!
1232     Return the custom string converter for \a type, previously installed through
1233     registerCustomStringConverter()
1234  */
1235 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1236 {
1237     QReadLocker lock(metaTypeDataLock());
1238
1239     QQmlMetaTypeData *data = metaTypeData();
1240     return data->stringConverters.value(type);
1241 }
1242
1243 /*!
1244     Returns the type (if any) of URI-qualified named \a name in version specified
1245     by \a version_major and \a version_minor.
1246 */
1247 QQmlType *QQmlMetaType::qmlType(const QString &name, int version_major, int version_minor)
1248 {
1249     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1250     QReadLocker lock(metaTypeDataLock());
1251     QQmlMetaTypeData *data = metaTypeData();
1252
1253     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1254     while (it != data->nameToType.end()) {
1255         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1256         if (it.key() == name && (version_major<0 || (*it)->availableInVersion(version_major,version_minor)))
1257             return (*it);
1258         ++it;
1259     }
1260
1261     return 0;
1262 }
1263
1264 /*!
1265     Returns the type (if any) that corresponds to the \a metaObject.  Returns null if no
1266     type is registered.
1267 */
1268 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1269 {
1270     QReadLocker lock(metaTypeDataLock());
1271     QQmlMetaTypeData *data = metaTypeData();
1272
1273     return data->metaObjectToType.value(metaObject);
1274 }
1275
1276 /*!
1277     Returns the type (if any) that corresponds to the \a metaObject in version specified
1278     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
1279     type is registered.
1280 */
1281 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor)
1282 {
1283     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1284     QReadLocker lock(metaTypeDataLock());
1285     QQmlMetaTypeData *data = metaTypeData();
1286
1287     QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1288     while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1289         QQmlType *t = *it;
1290         if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1291             return t;
1292         ++it;
1293     }
1294
1295     return 0;
1296 }
1297
1298 /*!
1299     Returns the type (if any) that corresponds to the QVariant::Type \a userType.  
1300     Returns null if no type is registered.
1301 */
1302 QQmlType *QQmlMetaType::qmlType(int userType)
1303 {
1304     QReadLocker lock(metaTypeDataLock());
1305     QQmlMetaTypeData *data = metaTypeData();
1306
1307     QQmlType *type = data->idToType.value(userType);
1308     if (type && type->typeId() == userType)
1309         return type;
1310     else
1311         return 0;
1312 }
1313
1314 /*!
1315     Returns the list of registered QML type names.
1316 */
1317 QList<QString> QQmlMetaType::qmlTypeNames()
1318 {
1319     QReadLocker lock(metaTypeDataLock());
1320     QQmlMetaTypeData *data = metaTypeData();
1321
1322     return data->nameToType.keys();
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