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