Fixed memory leak of registered QML modules
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlmetatype.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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     QBitArray objects;
98     QBitArray interfaces;
99     QBitArray lists;
100
101     QList<QQmlPrivate::AutoParentFunction> parentFunctions;
102
103     QSet<QString> protectedNamespaces;
104
105     QString typeRegistrationNamespace;
106     QStringList typeRegistrationFailures;
107 };
108
109 class QQmlTypeModulePrivate
110 {
111 public:
112     QQmlTypeModulePrivate() 
113     : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
114
115     QQmlMetaTypeData::VersionedUri uri;
116
117     int minMinorVersion;
118     int maxMinorVersion;
119
120     void add(QQmlType *);
121
122     QStringHash<QList<QQmlType *> > typeHash;
123     QList<QQmlType *> types;
124 };
125
126 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
127 Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, metaTypeDataLock, (QReadWriteLock::Recursive))
128
129 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
130 {
131     return v.uri.hash() ^ qHash(v.majorVersion);
132 }
133
134 QQmlMetaTypeData::QQmlMetaTypeData()
135 {
136 }
137
138 QQmlMetaTypeData::~QQmlMetaTypeData()
139 {
140     for (int i = 0; i < types.count(); ++i)
141         delete types.at(i);
142
143     TypeModules::const_iterator i = uriToModule.constBegin();
144     for (; i != uriToModule.constEnd(); ++i)
145         delete *i;
146 }
147
148 class QQmlTypePrivate
149 {
150 public:
151     QQmlTypePrivate();
152     ~QQmlTypePrivate();
153
154     void init() const;
155     void initEnums() const;
156     void insertEnums(const QMetaObject *metaObject) const;
157
158     bool m_isInterface : 1;
159     const char *m_iid;
160     QHashedString m_module;
161     QString m_name;
162     QString m_elementName;
163     int m_version_maj;
164     int m_version_min;
165     int m_typeId; int m_listId; 
166     int m_revision;
167     mutable bool m_containsRevisionedAttributes;
168     mutable QQmlType *m_superType;
169
170     int m_allocationSize;
171     void (*m_newFunc)(void *);
172     QString m_noCreationReason;
173
174     const QMetaObject *m_baseMetaObject;
175     QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
176     const QMetaObject *m_attachedPropertiesType;
177     int m_attachedPropertiesId;
178     int m_parserStatusCast;
179     int m_propertyValueSourceCast;
180     int m_propertyValueInterceptorCast;
181     QObject *(*m_extFunc)(QObject *);
182     const QMetaObject *m_extMetaObject;
183     int m_index;
184     QQmlCustomParser *m_customParser;
185     mutable volatile bool m_isSetup:1;
186     mutable volatile bool m_isEnumSetup:1;
187     mutable bool m_haveSuperType:1;
188     mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
189     mutable QStringHash<int> m_enums;
190     QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo;
191
192     static QHash<const QMetaObject *, int> m_attachedPropertyIds;
193 };
194
195 // Avoid multiple fromUtf8(), copies and hashing of the module name.
196 // This is only called when metaTypeDataLock is locked.
197 static QHashedString moduleFromUtf8(const char *module)
198 {
199     if (!module)
200         return QHashedString();
201
202     static const char *lastModule = 0;
203     static QHashedString lastModuleStr;
204
205     // Separate plugins may have different strings at the same address
206     QHashedCStringRef currentModule(module, ::strlen(module));
207     if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
208         lastModuleStr = QString::fromUtf8(module);
209         lastModuleStr.hash();
210         lastModule = module;
211     }
212
213     return lastModuleStr;
214 }
215
216 void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
217 {
218     if (scriptCallback && scriptApi(e).isUndefined()) {
219         setScriptApi(e, scriptCallback(e, e));
220     } else if (qobjectCallback && !qobjectApi(e)) {
221         setQObjectApi(e, qobjectCallback(e, e));
222     }
223 }
224
225 void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
226 {
227     // cleans up the engine-specific singleton instances if they exist.
228     scriptApis.remove(e);
229     QObject *o = qobjectApis.take(e);
230     delete o;
231 }
232
233 void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
234 {
235     qobjectApis.insert(e, o);
236 }
237
238 QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
239 {
240     return qobjectApis.value(e);
241 }
242
243 void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v)
244 {
245     scriptApis.insert(e, v);
246 }
247
248 QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
249 {
250     return scriptApis.value(e);
251 }
252
253 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
254
255 QQmlTypePrivate::QQmlTypePrivate()
256 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
257   m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), 
258   m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), 
259   m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), 
260   m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0)
261 {
262 }
263
264 QQmlTypePrivate::~QQmlTypePrivate()
265 {
266     delete m_singletonInstanceInfo;
267 }
268
269 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
270 : d(new QQmlTypePrivate)
271 {
272     d->m_isInterface = true;
273     d->m_iid = interface.iid;
274     d->m_typeId = interface.typeId;
275     d->m_listId = interface.listId;
276     d->m_newFunc = 0;
277     d->m_index = index;
278     d->m_isSetup = true;
279     d->m_version_maj = 0;
280     d->m_version_min = 0;
281 }
282
283 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
284 : d(new QQmlTypePrivate)
285 {
286     d->m_elementName = elementName;
287     d->m_module = moduleFromUtf8(type.uri);
288
289     d->m_version_maj = type.versionMajor;
290     d->m_version_min = type.versionMinor;
291
292     if (type.qobjectApi) {
293         if (type.version >= 1) // static metaobject added in version 1
294             d->m_baseMetaObject = type.instanceMetaObject;
295         if (type.version >= 2) // typeId added in version 2
296             d->m_typeId = type.typeId;
297         if (type.version >= 2) // revisions added in version 2
298             d->m_revision = type.revision;
299     }
300
301     d->m_newFunc = 0;
302     d->m_index = index;
303
304     d->m_singletonInstanceInfo = new SingletonInstanceInfo;
305     d->m_singletonInstanceInfo->scriptCallback = type.scriptApi;
306     d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi;
307     d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
308     d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
309 }
310
311 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
312 : d(new QQmlTypePrivate)
313 {
314     d->m_elementName = elementName;
315     d->m_module = moduleFromUtf8(type.uri);
316
317     d->m_version_maj = type.versionMajor;
318     d->m_version_min = type.versionMinor;
319     if (type.version >= 1) // revisions added in version 1
320         d->m_revision = type.revision;
321     d->m_typeId = type.typeId;
322     d->m_listId = type.listId;
323     d->m_allocationSize = type.objectSize;
324     d->m_newFunc = type.create;
325     d->m_noCreationReason = type.noCreationReason;
326     d->m_baseMetaObject = type.metaObject;
327     d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
328     d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
329     if (d->m_attachedPropertiesType) {
330         QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
331         if (iter == d->m_attachedPropertyIds.end())
332             iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
333         d->m_attachedPropertiesId = *iter;
334     } else {
335         d->m_attachedPropertiesId = -1;
336     }
337     d->m_parserStatusCast = type.parserStatusCast;
338     d->m_propertyValueSourceCast = type.valueSourceCast;
339     d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
340     d->m_extFunc = type.extensionObjectCreate;
341     d->m_index = index;
342     d->m_customParser = type.customParser;
343
344     if (type.extensionMetaObject)
345         d->m_extMetaObject = type.extensionMetaObject;
346 }
347
348 QQmlType::~QQmlType()
349 {
350     delete d->m_customParser;
351     delete d;
352 }
353
354 const QHashedString &QQmlType::module() const
355 {
356     return d->m_module;
357 }
358
359 int QQmlType::majorVersion() const
360 {
361     return d->m_version_maj;
362 }
363
364 int QQmlType::minorVersion() const
365 {
366     return d->m_version_min;
367 }
368
369 bool QQmlType::availableInVersion(int vmajor, int vminor) const
370 {
371     Q_ASSERT(vmajor >= 0 && vminor >= 0);
372     return vmajor == d->m_version_maj && vminor >= d->m_version_min;
373 }
374
375 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
376 {
377     Q_ASSERT(vmajor >= 0 && vminor >= 0);
378     return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
379 }
380
381 // returns the nearest _registered_ super class
382 QQmlType *QQmlType::superType() const
383 {
384     if (!d->m_haveSuperType && d->m_baseMetaObject) {
385         const QMetaObject *mo = d->m_baseMetaObject->superClass();
386         while (mo && !d->m_superType) {
387             d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
388             mo = mo->superClass();
389         }
390         d->m_haveSuperType = true;
391     }
392
393     return d->m_superType;
394 }
395
396 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, 
397                   const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
398 {
399     // Set classname
400     builder.setClassName(ignoreEnd->className());
401
402     // Clone Q_CLASSINFO
403     for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
404         QMetaClassInfo info = mo->classInfo(ii);
405
406         int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
407         if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
408             // Skip 
409         } else {
410             builder.addClassInfo(info.name(), info.value());
411         }
412     }
413
414     // Clone Q_PROPERTY
415     for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
416         QMetaProperty property = mo->property(ii);
417
418         int otherIndex = ignoreEnd->indexOfProperty(property.name());
419         if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
420             builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
421             // Skip 
422         } else {
423             builder.addProperty(property);
424         }
425     }
426
427     // Clone Q_METHODS
428     for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
429         QMetaMethod method = mo->method(ii);
430
431         // More complex - need to search name
432         QByteArray name = method.name();
433
434
435         bool found = false;
436
437         for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); 
438              !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
439              ++ii) {
440
441             QMetaMethod other = ignoreEnd->method(ii);
442
443             found = name == other.name();
444         }
445
446         QMetaMethodBuilder m = builder.addMethod(method);
447         if (found) // SKIP
448             m.setAccess(QMetaMethod::Private);
449     }
450
451     // Clone Q_ENUMS
452     for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
453         QMetaEnum enumerator = mo->enumerator(ii);
454
455         int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
456         if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
457             // Skip 
458         } else {
459             builder.addEnumerator(enumerator);
460         }
461     }
462 }
463
464 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
465 {
466     int i = index;
467     i -= mo->propertyOffset();
468     if (i < 0 && mo->d.superdata)
469         return isPropertyRevisioned(mo->d.superdata, index);
470
471     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
472     if (i >= 0 && i < mop->propertyCount) {
473         int handle = mop->propertyData + 3*i;
474         int flags = mo->d.data[handle + 2];
475
476         return (flags & Revisioned);
477     }
478
479     return false;
480 }
481
482 void QQmlTypePrivate::init() const
483 {
484     if (m_isSetup) return;
485
486     QWriteLocker lock(metaTypeDataLock());
487     if (m_isSetup)
488         return;
489
490     const QMetaObject *mo = m_baseMetaObject;
491     if (!mo) {
492         // singleton type without metaobject information
493         return;
494     }
495
496     // Setup extended meta object
497     // XXX - very inefficient
498     if (m_extFunc) {
499         QMetaObjectBuilder builder;
500         clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
501         builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
502         QMetaObject *mmo = builder.toMetaObject();
503         mmo->d.superdata = mo;
504         QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
505         m_metaObjects << data;
506     }
507
508     mo = mo->d.superdata;
509     while(mo) {
510         QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
511         if (t) {
512             if (t->d->m_extFunc) {
513                 QMetaObjectBuilder builder;
514                 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
515                 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
516                 QMetaObject *mmo = builder.toMetaObject();
517                 mmo->d.superdata = m_baseMetaObject;
518                 if (!m_metaObjects.isEmpty())
519                     m_metaObjects.last().metaObject->d.superdata = mmo;
520                 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
521                 m_metaObjects << data;
522             }
523         }
524         mo = mo->d.superdata;
525     }
526
527     for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
528         m_metaObjects[ii].propertyOffset =
529             m_metaObjects.at(ii).metaObject->propertyOffset();
530         m_metaObjects[ii].methodOffset =
531             m_metaObjects.at(ii).metaObject->methodOffset();
532     }
533     
534     // Check for revisioned details
535     {
536         const QMetaObject *mo = 0;
537         if (m_metaObjects.isEmpty())
538             mo = m_baseMetaObject;
539         else
540             mo = m_metaObjects.first().metaObject;
541
542         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
543             if (isPropertyRevisioned(mo, ii))
544                 m_containsRevisionedAttributes = true;
545         }
546
547         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
548             if (mo->method(ii).revision() != 0)
549                 m_containsRevisionedAttributes = true;
550         }
551     }
552
553     m_isSetup = true;
554     lock.unlock();
555 }
556
557 void QQmlTypePrivate::initEnums() const
558 {
559     if (m_isEnumSetup) return;
560
561     init();
562
563     QWriteLocker lock(metaTypeDataLock());
564     if (m_isEnumSetup) return;
565
566     if (m_baseMetaObject) // could be singleton type without metaobject
567         insertEnums(m_baseMetaObject);
568
569     m_isEnumSetup = true;
570 }
571
572 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
573 {
574     // Add any enum values defined by 'related' classes
575     if (metaObject->d.relatedMetaObjects) {
576         const QMetaObject **related = metaObject->d.relatedMetaObjects;
577         if (related) {
578             while (*related)
579                 insertEnums(*related++);
580         }
581     }
582
583     // Add any enum values defined by this class, overwriting any inherited values
584     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
585         QMetaEnum e = metaObject->enumerator(ii);
586         for (int jj = 0; jj < e.keyCount(); ++jj)
587             m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
588     }
589 }
590
591 QByteArray QQmlType::typeName() const
592 {
593     if (d->m_singletonInstanceInfo)
594         return d->m_singletonInstanceInfo->typeName.toUtf8();
595     if (d->m_baseMetaObject)
596         return d->m_baseMetaObject->className();
597     else
598         return QByteArray();
599 }
600
601 const QString &QQmlType::elementName() const
602 {
603     return d->m_elementName;
604 }
605
606 const QString &QQmlType::qmlTypeName() const
607 {
608     if (d->m_name.isEmpty()) {
609         if (!d->m_module.isEmpty())
610             d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
611         else
612             d->m_name = d->m_elementName;
613     }
614
615     return d->m_name;
616 }
617
618 QObject *QQmlType::create() const
619 {
620     d->init();
621
622     QObject *rv = (QObject *)operator new(d->m_allocationSize);
623     d->m_newFunc(rv);
624
625     if (rv && !d->m_metaObjects.isEmpty())
626         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
627
628     return rv;
629 }
630
631 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
632 {
633     d->init();
634
635     QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
636     d->m_newFunc(rv);
637
638     if (rv && !d->m_metaObjects.isEmpty())
639         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
640
641     *out = rv;
642     *memory = ((char *)rv) + d->m_allocationSize;
643 }
644
645 QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
646 {
647     return d->m_singletonInstanceInfo;
648 }
649
650 QQmlCustomParser *QQmlType::customParser() const
651 {
652     return d->m_customParser;
653 }
654
655 QQmlType::CreateFunc QQmlType::createFunction() const
656 {
657     return d->m_newFunc;
658 }
659
660 QString QQmlType::noCreationReason() const
661 {
662     return d->m_noCreationReason;
663 }
664
665 int QQmlType::createSize() const
666 {
667     return d->m_allocationSize;
668 }
669
670 bool QQmlType::isCreatable() const
671 {
672     return d->m_newFunc != 0;
673 }
674
675 bool QQmlType::isExtendedType() const
676 {
677     d->init();
678
679     return !d->m_metaObjects.isEmpty();
680 }
681
682 bool QQmlType::isSingleton() const
683 {
684     return d->m_singletonInstanceInfo != 0;
685 }
686
687 bool QQmlType::isInterface() const
688 {
689     return d->m_isInterface;
690 }
691
692 int QQmlType::typeId() const
693 {
694     return d->m_typeId;
695 }
696
697 int QQmlType::qListTypeId() const
698 {
699     return d->m_listId;
700 }
701
702 const QMetaObject *QQmlType::metaObject() const
703 {
704     d->init();
705
706     if (d->m_metaObjects.isEmpty())
707         return d->m_baseMetaObject;
708     else
709         return d->m_metaObjects.first().metaObject;
710
711 }
712
713 const QMetaObject *QQmlType::baseMetaObject() const
714 {
715     return d->m_baseMetaObject;
716 }
717
718 bool QQmlType::containsRevisionedAttributes() const
719 {
720     d->init();
721
722     return d->m_containsRevisionedAttributes;
723 }
724
725 int QQmlType::metaObjectRevision() const
726 {
727     return d->m_revision;
728 }
729
730 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
731 {
732     return d->m_attachedPropertiesFunc;
733 }
734
735 const QMetaObject *QQmlType::attachedPropertiesType() const
736 {
737     return d->m_attachedPropertiesType;
738 }
739
740 /*
741 This is the id passed to qmlAttachedPropertiesById().  This is different from the index
742 for the case that a single class is registered under two or more names (eg. Item in 
743 Qt 4.7 and QtQuick 1.0).
744 */
745 int QQmlType::attachedPropertiesId() const
746 {
747     return d->m_attachedPropertiesId;
748 }
749
750 int QQmlType::parserStatusCast() const
751 {
752     return d->m_parserStatusCast;
753 }
754
755 int QQmlType::propertyValueSourceCast() const
756 {
757     return d->m_propertyValueSourceCast;
758 }
759
760 int QQmlType::propertyValueInterceptorCast() const
761 {
762     return d->m_propertyValueInterceptorCast;
763 }
764
765 const char *QQmlType::interfaceIId() const
766 {
767     return d->m_iid;
768 }
769
770 int QQmlType::index() const
771 {
772     return d->m_index;
773 }
774
775 int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
776 {
777     Q_ASSERT(ok);
778     *ok = true;
779
780     d->initEnums();
781
782     int *rv = d->m_enums.value(name);
783     if (rv)
784         return *rv;
785
786     *ok = false;
787     return -1;
788 }
789
790 int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
791 {
792     Q_ASSERT(ok);
793     *ok = true;
794
795     d->initEnums();
796
797     int *rv = d->m_enums.value(name);
798     if (rv)
799         return *rv;
800
801     *ok = false;
802     return -1;
803 }
804
805 int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
806 {
807     Q_ASSERT(ok);
808     *ok = true;
809
810     d->initEnums();
811
812     int *rv = d->m_enums.value(name);
813     if (rv)
814         return *rv;
815
816     *ok = false;
817     return -1;
818 }
819
820 QQmlTypeModule::QQmlTypeModule()
821 : d(new QQmlTypeModulePrivate)
822 {
823 }
824
825 QQmlTypeModule::~QQmlTypeModule()
826 {
827     delete d; d = 0;
828 }
829
830 QString QQmlTypeModule::module() const
831 {
832     return d->uri.uri;
833 }
834
835 int QQmlTypeModule::majorVersion() const
836 {
837     return d->uri.majorVersion;
838 }
839
840 int QQmlTypeModule::minimumMinorVersion() const
841 {
842     return d->minMinorVersion;
843 }
844
845 int QQmlTypeModule::maximumMinorVersion() const
846 {
847     return d->maxMinorVersion;
848 }
849
850 void QQmlTypeModulePrivate::add(QQmlType *type)
851 {
852     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
853     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
854
855     QList<QQmlType *> &list = typeHash[type->elementName()];
856     for (int ii = 0; ii < list.count(); ++ii) {
857         if (list.at(ii)->minorVersion() < type->minorVersion()) {
858             list.insert(ii, type);
859             return;
860         }
861     }
862     list.append(type);
863 }
864
865 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
866 {
867     QReadLocker lock(metaTypeDataLock());
868
869     QList<QQmlType *> *types = d->typeHash.value(name);
870     if (!types) return 0;
871
872     for (int ii = 0; ii < types->count(); ++ii)
873         if (types->at(ii)->minorVersion() <= minor)
874             return types->at(ii);
875
876     return 0;
877 }
878
879 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
880 {
881     QReadLocker lock(metaTypeDataLock());
882
883     QList<QQmlType *> *types = d->typeHash.value(name);
884     if (!types) return 0;
885
886     for (int ii = 0; ii < types->count(); ++ii)
887         if (types->at(ii)->minorVersion() <= minor)
888             return types->at(ii);
889
890     return 0;
891 }
892
893 QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
894 {
895     QReadLocker lock(metaTypeDataLock());
896
897     QList<QQmlType *> retn;
898     for (int ii = 0; ii < d->types.count(); ++ii) {
899         QQmlType *curr = d->types.at(ii);
900         if (curr->isSingleton() && curr->minorVersion() <= minor)
901             retn.append(curr);
902     }
903
904     return retn;
905 }
906
907
908 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
909 : m_module(0), m_minor(0)
910 {
911 }
912
913 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
914 : m_module(module), m_minor(minor)
915 {
916     Q_ASSERT(m_module);
917     Q_ASSERT(m_minor >= 0);
918 }
919
920 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
921 : m_module(o.m_module), m_minor(o.m_minor)
922 {
923 }
924
925 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
926 {
927     m_module = o.m_module;
928     m_minor = o.m_minor;
929     return *this;
930 }
931
932 QQmlTypeModule *QQmlTypeModuleVersion::module() const
933 {
934     return m_module;
935 }
936
937 int QQmlTypeModuleVersion::minorVersion() const
938 {
939     return m_minor;
940 }
941
942 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
943 {
944     if (m_module) return m_module->type(name, m_minor);
945     else return 0;
946 }
947
948 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
949 {
950     if (m_module) return m_module->type(name, m_minor);
951     else return 0;
952 }
953
954
955 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
956 {
957     QWriteLocker lock(metaTypeDataLock());
958     QQmlMetaTypeData *data = metaTypeData();
959
960     data->parentFunctions.append(autoparent.function);
961
962     return data->parentFunctions.count() - 1;
963 }
964
965 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
966 {
967     if (interface.version > 0) 
968         qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
969
970     QWriteLocker lock(metaTypeDataLock());
971     QQmlMetaTypeData *data = metaTypeData();
972
973     int index = data->types.count();
974
975     QQmlType *type = new QQmlType(index, interface);
976
977     data->types.append(type);
978     data->idToType.insert(type->typeId(), type);
979     data->idToType.insert(type->qListTypeId(), type);
980     // XXX No insertMulti, so no multi-version interfaces?
981     if (!type->elementName().isEmpty())
982         data->nameToType.insert(type->elementName(), type);
983
984     if (data->interfaces.size() <= interface.typeId)
985         data->interfaces.resize(interface.typeId + 16);
986     if (data->lists.size() <= interface.listId)
987         data->lists.resize(interface.listId + 16);
988     data->interfaces.setBit(interface.typeId, true);
989     data->lists.setBit(interface.listId, true);
990
991     return index;
992 }
993
994 QString registrationTypeString(QQmlType::RegistrationType typeType)
995 {
996     QString typeStr;
997     if (typeType == QQmlType::CppType)
998         typeStr = QStringLiteral("element");
999     else if (typeType == QQmlType::SingletonType)
1000         typeStr = QStringLiteral("singleton type");
1001     return typeStr;
1002 }
1003
1004 // NOTE: caller must hold a QWriteLocker on "data"
1005 bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
1006 {
1007     if (!typeName.isEmpty()) {
1008         int typeNameLen = typeName.length();
1009         for (int ii = 0; ii < typeNameLen; ++ii) {
1010             if (!typeName.at(ii).isLetterOrNumber()) {
1011                 QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
1012                 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
1013                 return false;
1014             }
1015         }
1016     }
1017
1018     if (uri && !typeName.isEmpty()) {
1019         QString nameSpace = moduleFromUtf8(uri);
1020
1021         if (!data->typeRegistrationNamespace.isEmpty()) {
1022             // We can only install types into the registered namespace
1023             if (nameSpace != data->typeRegistrationNamespace) {
1024                 QString failure(QCoreApplication::translate("qmlRegisterType",
1025                                                             "Cannot install %1 '%2' into unregistered namespace '%3'"));
1026                 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
1027                 return false;
1028             }
1029         } else if (data->typeRegistrationNamespace != nameSpace) {
1030             // Is the target namespace protected against further registrations?
1031             if (data->protectedNamespaces.contains(nameSpace)) {
1032                 QString failure(QCoreApplication::translate("qmlRegisterType",
1033                                                             "Cannot install %1 '%2' into protected namespace '%3'"));
1034                 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
1035                 return false;
1036             }
1037         }
1038     }
1039
1040     return true;
1041 }
1042
1043 int registerType(const QQmlPrivate::RegisterType &type)
1044 {
1045     QWriteLocker lock(metaTypeDataLock());
1046     QQmlMetaTypeData *data = metaTypeData();
1047     QString elementName = QString::fromUtf8(type.elementName);
1048     if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
1049         return -1;
1050
1051     int index = data->types.count();
1052
1053     QQmlType *dtype = new QQmlType(index, elementName, type);
1054
1055     data->types.append(dtype);
1056     data->idToType.insert(dtype->typeId(), dtype);
1057     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
1058
1059     if (!dtype->elementName().isEmpty())
1060         data->nameToType.insertMulti(dtype->elementName(), dtype);
1061
1062     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
1063
1064     if (data->objects.size() <= type.typeId)
1065         data->objects.resize(type.typeId + 16);
1066     if (data->lists.size() <= type.listId)
1067         data->lists.resize(type.listId + 16);
1068     data->objects.setBit(type.typeId, true);
1069     if (type.listId) data->lists.setBit(type.listId, true);
1070
1071     if (!dtype->module().isEmpty()) {
1072         const QHashedString &mod = dtype->module();
1073
1074         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
1075         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1076         if (!module) {
1077             module = new QQmlTypeModule;
1078             module->d->uri = versionedUri;
1079             data->uriToModule.insert(versionedUri, module);
1080         }
1081         module->d->add(dtype);
1082     }
1083
1084     return index;
1085 }
1086
1087 int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
1088 {
1089     QWriteLocker lock(metaTypeDataLock());
1090     QQmlMetaTypeData *data = metaTypeData();
1091     QString typeName = QString::fromUtf8(type.typeName);
1092     if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
1093         return -1;
1094
1095     int index = data->types.count();
1096
1097     QQmlType *dtype = new QQmlType(index, typeName, type);
1098
1099     data->types.append(dtype);
1100     data->idToType.insert(dtype->typeId(), dtype);
1101
1102     if (!dtype->elementName().isEmpty())
1103         data->nameToType.insertMulti(dtype->elementName(), dtype);
1104
1105     if (dtype->baseMetaObject())
1106         data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
1107
1108     if (type.typeId) {
1109         if (data->objects.size() <= type.typeId)
1110             data->objects.resize(type.typeId + 16);
1111         data->objects.setBit(type.typeId, true);
1112     }
1113
1114     if (!dtype->module().isEmpty()) {
1115         const QHashedString &mod = dtype->module();
1116
1117         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
1118         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1119         if (!module) {
1120             module = new QQmlTypeModule;
1121             module->d->uri = versionedUri;
1122             data->uriToModule.insert(versionedUri, module);
1123         }
1124         module->d->add(dtype);
1125     }
1126
1127     return index;
1128 }
1129
1130
1131 /*
1132 This method is "over generalized" to allow us to (potentially) register more types of things in
1133 the future without adding exported symbols.
1134 */
1135 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
1136 {
1137     if (type == TypeRegistration) {
1138         return registerType(*reinterpret_cast<RegisterType *>(data));
1139     } else if (type == InterfaceRegistration) {
1140         return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
1141     } else if (type == AutoParentRegistration) {
1142         return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
1143     } else if (type == SingletonRegistration) {
1144         return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
1145     }
1146     return -1;
1147 }
1148
1149 bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
1150 {
1151     QQmlMetaTypeData *data = metaTypeData();
1152
1153     // Has any type previously been installed to this namespace?
1154     QHashedString nameSpace(uri);
1155     foreach (const QQmlType *type, data->types)
1156         if (type->module() == nameSpace)
1157             return true;
1158
1159     return false;
1160 }
1161
1162 void QQmlMetaType::protectNamespace(const QString &uri)
1163 {
1164     QQmlMetaTypeData *data = metaTypeData();
1165
1166     data->protectedNamespaces.insert(uri);
1167 }
1168
1169 void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
1170 {
1171     QQmlMetaTypeData *data = metaTypeData();
1172
1173     data->typeRegistrationNamespace = uri;
1174     data->typeRegistrationFailures.clear();
1175 }
1176
1177 QStringList QQmlMetaType::typeRegistrationFailures()
1178 {
1179     QQmlMetaTypeData *data = metaTypeData();
1180
1181     return data->typeRegistrationFailures;
1182 }
1183
1184 QReadWriteLock *QQmlMetaType::typeRegistrationLock()
1185 {
1186     return metaTypeDataLock();
1187 }
1188
1189 /*
1190     Returns true if a module \a uri of any version is installed.
1191 */
1192 bool QQmlMetaType::isAnyModule(const QString &uri)
1193 {
1194     QReadLocker lock(metaTypeDataLock());
1195     QQmlMetaTypeData *data = metaTypeData();
1196
1197     for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
1198          iter != data->uriToModule.end(); ++iter) {
1199         if ((*iter)->module() == uri)
1200             return true;
1201     }
1202
1203     return false;
1204 }
1205
1206 /*
1207     Returns true if any type or API has been registered for the given \a module with at least
1208     versionMajor.versionMinor, or if types have been registered for \a module with at most
1209     versionMajor.versionMinor.
1210
1211     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.
1212 */
1213 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1214 {
1215     Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1216     QReadLocker lock(metaTypeDataLock());
1217
1218     QQmlMetaTypeData *data = metaTypeData();
1219
1220     // first, check Types
1221     QQmlTypeModule *tm = 
1222         data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1223     if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1224         return true;
1225
1226     return false;
1227 }
1228
1229 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1230 {
1231     QReadLocker lock(metaTypeDataLock());
1232     QQmlMetaTypeData *data = metaTypeData();
1233     return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1234 }
1235
1236 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1237 {
1238     QReadLocker lock(metaTypeDataLock());
1239     QQmlMetaTypeData *data = metaTypeData();
1240     return data->parentFunctions;
1241 }
1242
1243 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1244 {
1245     if (!isQObject(v.userType())) {
1246         if (ok) *ok = false;
1247         return 0;
1248     }
1249
1250     if (ok) *ok = true;
1251
1252     return *(QObject **)v.constData();
1253 }
1254
1255 bool QQmlMetaType::isQObject(int userType)
1256 {
1257     if (userType == QMetaType::QObjectStar)
1258         return true;
1259
1260     QReadLocker lock(metaTypeDataLock());
1261     QQmlMetaTypeData *data = metaTypeData();
1262     return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1263 }
1264
1265 /*
1266     Returns the item type for a list of type \a id.
1267  */
1268 int QQmlMetaType::listType(int id)
1269 {
1270     QReadLocker lock(metaTypeDataLock());
1271     QQmlMetaTypeData *data = metaTypeData();
1272     QQmlType *type = data->idToType.value(id);
1273     if (type && type->qListTypeId() == id)
1274         return type->typeId();
1275     else
1276         return 0;
1277 }
1278
1279 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1280 {
1281     QReadLocker lock(metaTypeDataLock());
1282     QQmlMetaTypeData *data = metaTypeData();
1283
1284     QQmlType *type = data->metaObjectToType.value(mo);
1285     if (type && type->attachedPropertiesFunction())
1286         return type->attachedPropertiesId();
1287     else
1288         return -1;
1289 }
1290
1291 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1292 {
1293     if (id < 0)
1294         return 0;
1295     QReadLocker lock(metaTypeDataLock());
1296     QQmlMetaTypeData *data = metaTypeData();
1297     return data->types.at(id)->attachedPropertiesFunction();
1298 }
1299
1300 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1301 {
1302     int idx = metaObject->indexOfClassInfo("DefaultProperty");
1303     if (-1 == idx)
1304         return QMetaProperty();
1305
1306     QMetaClassInfo info = metaObject->classInfo(idx);
1307     if (!info.value())
1308         return QMetaProperty();
1309
1310     idx = metaObject->indexOfProperty(info.value());
1311     if (-1 == idx)
1312         return QMetaProperty();
1313
1314     return metaObject->property(idx);
1315 }
1316
1317 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1318 {
1319     if (!obj)
1320         return QMetaProperty();
1321
1322     const QMetaObject *metaObject = obj->metaObject();
1323     return defaultProperty(metaObject);
1324 }
1325
1326 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1327 {
1328     int idx = metaObject->indexOfClassInfo("DefaultMethod");
1329     if (-1 == idx)
1330         return QMetaMethod();
1331
1332     QMetaClassInfo info = metaObject->classInfo(idx);
1333     if (!info.value())
1334         return QMetaMethod();
1335
1336     idx = metaObject->indexOfMethod(info.value());
1337     if (-1 == idx)
1338         return QMetaMethod();
1339
1340     return metaObject->method(idx);
1341 }
1342
1343 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1344 {
1345     if (!obj)
1346         return QMetaMethod();
1347
1348     const QMetaObject *metaObject = obj->metaObject();
1349     return defaultMethod(metaObject);
1350 }
1351
1352 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1353 {
1354     if (userType < 0)
1355         return Unknown;
1356     if (userType == QMetaType::QObjectStar)
1357         return Object;
1358
1359     QReadLocker lock(metaTypeDataLock());
1360     QQmlMetaTypeData *data = metaTypeData();
1361     if (userType < data->objects.size() && data->objects.testBit(userType))
1362         return Object;
1363     else if (userType < data->lists.size() && data->lists.testBit(userType))
1364         return List;
1365     else
1366         return Unknown;
1367 }
1368
1369 bool QQmlMetaType::isInterface(int userType)
1370 {
1371     QReadLocker lock(metaTypeDataLock());
1372     QQmlMetaTypeData *data = metaTypeData();
1373     return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1374 }
1375
1376 const char *QQmlMetaType::interfaceIId(int userType)
1377 {
1378     QReadLocker lock(metaTypeDataLock());
1379     QQmlMetaTypeData *data = metaTypeData();
1380     QQmlType *type = data->idToType.value(userType);
1381     lock.unlock();
1382     if (type && type->isInterface() && type->typeId() == userType)
1383         return type->interfaceIId();
1384     else
1385         return 0;
1386 }
1387
1388 bool QQmlMetaType::isList(int userType)
1389 {
1390     QReadLocker lock(metaTypeDataLock());
1391     QQmlMetaTypeData *data = metaTypeData();
1392     return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1393 }
1394
1395 /*!
1396     A custom string convertor allows you to specify a function pointer that
1397     returns a variant of \a type. For example, if you have written your own icon
1398     class that you want to support as an object property assignable in QML:
1399
1400     \code
1401     int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1402     QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1403     \endcode
1404
1405     The function pointer must be of the form:
1406     \code
1407     QVariant (*StringConverter)(const QString &);
1408     \endcode
1409  */
1410 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1411 {
1412     QWriteLocker lock(metaTypeDataLock());
1413
1414     QQmlMetaTypeData *data = metaTypeData();
1415     if (data->stringConverters.contains(type))
1416         return;
1417     data->stringConverters.insert(type, converter);
1418 }
1419
1420 /*!
1421     Return the custom string converter for \a type, previously installed through
1422     registerCustomStringConverter()
1423  */
1424 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1425 {
1426     QReadLocker lock(metaTypeDataLock());
1427
1428     QQmlMetaTypeData *data = metaTypeData();
1429     return data->stringConverters.value(type);
1430 }
1431
1432 /*!
1433     Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1434     by \a version_major and \a version_minor.
1435 */
1436 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1437 {
1438     int slash = qualifiedName.indexOf(QLatin1Char('/'));
1439     if (slash <= 0)
1440         return 0;
1441
1442     QHashedStringRef module(qualifiedName.constData(), slash);
1443     QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1444
1445     return qmlType(name, module, version_major, version_minor);
1446 }
1447
1448 /*!
1449     Returns the type (if any) of \a name in \a module and version specified
1450     by \a version_major and \a version_minor.
1451 */
1452 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1453 {
1454     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1455     QReadLocker lock(metaTypeDataLock());
1456     QQmlMetaTypeData *data = metaTypeData();
1457
1458     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1459     while (it != data->nameToType.end() && it.key() == name) {
1460         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1461         if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1462             return (*it);
1463         ++it;
1464     }
1465
1466     return 0;
1467 }
1468
1469 /*!
1470     Returns the type (if any) that corresponds to the \a metaObject.  Returns null if no
1471     type is registered.
1472 */
1473 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1474 {
1475     QReadLocker lock(metaTypeDataLock());
1476     QQmlMetaTypeData *data = metaTypeData();
1477
1478     return data->metaObjectToType.value(metaObject);
1479 }
1480
1481 /*!
1482     Returns the type (if any) that corresponds to the \a metaObject in version specified
1483     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
1484     type is registered.
1485 */
1486 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1487 {
1488     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1489     QReadLocker lock(metaTypeDataLock());
1490     QQmlMetaTypeData *data = metaTypeData();
1491
1492     QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1493     while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1494         QQmlType *t = *it;
1495         if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1496             return t;
1497         ++it;
1498     }
1499
1500     return 0;
1501 }
1502
1503 /*!
1504     Returns the type (if any) that corresponds to the QVariant::Type \a userType.  
1505     Returns null if no type is registered.
1506 */
1507 QQmlType *QQmlMetaType::qmlType(int userType)
1508 {
1509     QReadLocker lock(metaTypeDataLock());
1510     QQmlMetaTypeData *data = metaTypeData();
1511
1512     QQmlType *type = data->idToType.value(userType);
1513     if (type && type->typeId() == userType)
1514         return type;
1515     else
1516         return 0;
1517 }
1518
1519 /*!
1520     Returns the list of registered QML type names.
1521 */
1522 QList<QString> QQmlMetaType::qmlTypeNames()
1523 {
1524     QReadLocker lock(metaTypeDataLock());
1525     QQmlMetaTypeData *data = metaTypeData();
1526
1527     QList<QString> names;
1528     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1529     while (it != data->nameToType.end()) {
1530         names += (*it)->qmlTypeName();
1531         ++it;
1532     }
1533
1534     return names;
1535 }
1536
1537 /*!
1538     Returns the list of registered QML types.
1539 */
1540 QList<QQmlType*> QQmlMetaType::qmlTypes()
1541 {
1542     QReadLocker lock(metaTypeDataLock());
1543     QQmlMetaTypeData *data = metaTypeData();
1544
1545     return data->nameToType.values();
1546 }
1547
1548 /*!
1549     Returns the list of registered QML singleton types.
1550 */
1551 QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
1552 {
1553     QReadLocker lock(metaTypeDataLock());
1554     QQmlMetaTypeData *data = metaTypeData();
1555
1556     QList<QQmlType*> alltypes = data->nameToType.values();
1557     QList<QQmlType*> retn;
1558     foreach (QQmlType* t, alltypes) {
1559         if (t->isSingleton()) {
1560             retn.append(t);
1561         }
1562     }
1563
1564     return retn;
1565 }
1566
1567 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1568 {
1569     static int id = 0;
1570     if (!id) {
1571         id = QMetaType::type("QQuickAnchorLine");
1572     }
1573     return id;
1574 }
1575
1576 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1577
1578 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1579 {
1580     anchorLineCompareFunction = fun;
1581 }
1582
1583 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1584 {
1585     Q_ASSERT(anchorLineCompareFunction != 0);
1586     return anchorLineCompareFunction(p1, p2);
1587 }
1588
1589 QT_END_NAMESPACE