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