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