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