Adapt to Qt5 meta-object 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.name();
344
345
346         bool found = false;
347
348         for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); 
349              !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
350              ++ii) {
351
352             QMetaMethod other = ignoreEnd->method(ii);
353
354             found = name == other.name();
355         }
356
357         QMetaMethodBuilder m = builder.addMethod(method);
358         if (found) // SKIP
359             m.setAccess(QMetaMethod::Private);
360     }
361
362     // Clone Q_ENUMS
363     for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
364         QMetaEnum enumerator = mo->enumerator(ii);
365
366         int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
367         if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
368             // Skip 
369         } else {
370             builder.addEnumerator(enumerator);
371         }
372     }
373 }
374
375 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
376 {
377     int i = index;
378     i -= mo->propertyOffset();
379     if (i < 0 && mo->d.superdata)
380         return isPropertyRevisioned(mo->d.superdata, index);
381
382     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
383     if (i >= 0 && i < mop->propertyCount) {
384         int handle = mop->propertyData + 3*i;
385         int flags = mo->d.data[handle + 2];
386
387         return (flags & Revisioned);
388     }
389
390     return false;
391 }
392
393 void QQmlTypePrivate::init() const
394 {
395     if (m_isSetup) return;
396
397     QWriteLocker lock(metaTypeDataLock());
398     if (m_isSetup)
399         return;
400
401     // Setup extended meta object
402     // XXX - very inefficient
403     const QMetaObject *mo = m_baseMetaObject;
404     if (m_extFunc) {
405         QMetaObjectBuilder builder;
406         clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
407         builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
408         QMetaObject *mmo = builder.toMetaObject();
409         mmo->d.superdata = mo;
410         QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
411         m_metaObjects << data;
412     }
413
414     mo = mo->d.superdata;
415     while(mo) {
416         QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
417         if (t) {
418             if (t->d->m_extFunc) {
419                 QMetaObjectBuilder builder;
420                 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
421                 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
422                 QMetaObject *mmo = builder.toMetaObject();
423                 mmo->d.superdata = m_baseMetaObject;
424                 if (!m_metaObjects.isEmpty())
425                     m_metaObjects.last().metaObject->d.superdata = mmo;
426                 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
427                 m_metaObjects << data;
428             }
429         }
430         mo = mo->d.superdata;
431     }
432
433     for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
434         m_metaObjects[ii].propertyOffset =
435             m_metaObjects.at(ii).metaObject->propertyOffset();
436         m_metaObjects[ii].methodOffset =
437             m_metaObjects.at(ii).metaObject->methodOffset();
438     }
439     
440     // Check for revisioned details
441     {
442         const QMetaObject *mo = 0;
443         if (m_metaObjects.isEmpty())
444             mo = m_baseMetaObject;
445         else
446             mo = m_metaObjects.first().metaObject;
447
448         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
449             if (isPropertyRevisioned(mo, ii))
450                 m_containsRevisionedAttributes = true;
451         }
452
453         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
454             if (mo->method(ii).revision() != 0)
455                 m_containsRevisionedAttributes = true;
456         }
457     }
458
459     m_isSetup = true;
460     lock.unlock();
461 }
462
463 void QQmlTypePrivate::initEnums() const
464 {
465     if (m_isEnumSetup) return;
466
467     init();
468
469     QWriteLocker lock(metaTypeDataLock());
470     if (m_isEnumSetup) return;
471
472     const QMetaObject *metaObject = m_baseMetaObject;
473     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
474
475         QMetaEnum e = metaObject->enumerator(ii);
476
477         for (int jj = 0; jj < e.keyCount(); ++jj) 
478             m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
479     }
480
481     m_isEnumSetup = true;
482 }
483
484 QByteArray QQmlType::typeName() const
485 {
486     if (d->m_baseMetaObject)
487         return d->m_baseMetaObject->className();
488     else
489         return QByteArray();
490 }
491
492 const QString &QQmlType::elementName() const
493 {
494     if (d->m_elementName.isEmpty()) {
495         QString n = qmlTypeName();
496         int idx = n.lastIndexOf(QLatin1Char('/'));
497         d->m_elementName = n.mid(idx + 1);
498     }
499     return d->m_elementName;
500 }
501
502 const QString &QQmlType::qmlTypeName() const
503 {
504     return d->m_name;
505 }
506
507 QObject *QQmlType::create() const
508 {
509     d->init();
510
511     QObject *rv = (QObject *)operator new(d->m_allocationSize);
512     d->m_newFunc(rv);
513
514     if (rv && !d->m_metaObjects.isEmpty())
515         (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
516
517     return rv;
518 }
519
520 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
521 {
522     d->init();
523
524     QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
525     d->m_newFunc(rv);
526
527     if (rv && !d->m_metaObjects.isEmpty())
528         (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
529
530     *out = rv;
531     *memory = ((char *)rv) + d->m_allocationSize;
532 }
533
534 QQmlCustomParser *QQmlType::customParser() const
535 {
536     return d->m_customParser;
537 }
538
539 QQmlType::CreateFunc QQmlType::createFunction() const
540 {
541     return d->m_newFunc;
542 }
543
544 QString QQmlType::noCreationReason() const
545 {
546     return d->m_noCreationReason;
547 }
548
549 int QQmlType::createSize() const
550 {
551     return d->m_allocationSize;
552 }
553
554 bool QQmlType::isCreatable() const
555 {
556     return d->m_newFunc != 0;
557 }
558
559 bool QQmlType::isExtendedType() const
560 {
561     d->init();
562
563     return !d->m_metaObjects.isEmpty();
564 }
565
566 bool QQmlType::isInterface() const
567 {
568     return d->m_isInterface;
569 }
570
571 int QQmlType::typeId() const
572 {
573     return d->m_typeId;
574 }
575
576 int QQmlType::qListTypeId() const
577 {
578     return d->m_listId;
579 }
580
581 const QMetaObject *QQmlType::metaObject() const
582 {
583     d->init();
584
585     if (d->m_metaObjects.isEmpty())
586         return d->m_baseMetaObject;
587     else
588         return d->m_metaObjects.first().metaObject;
589
590 }
591
592 const QMetaObject *QQmlType::baseMetaObject() const
593 {
594     return d->m_baseMetaObject;
595 }
596
597 bool QQmlType::containsRevisionedAttributes() const
598 {
599     d->init();
600
601     return d->m_containsRevisionedAttributes;
602 }
603
604 int QQmlType::metaObjectRevision() const
605 {
606     return d->m_revision;
607 }
608
609 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
610 {
611     return d->m_attachedPropertiesFunc;
612 }
613
614 const QMetaObject *QQmlType::attachedPropertiesType() const
615 {
616     return d->m_attachedPropertiesType;
617 }
618
619 /*
620 This is the id passed to qmlAttachedPropertiesById().  This is different from the index
621 for the case that a single class is registered under two or more names (eg. Item in 
622 Qt 4.7 and QtQuick 1.0).
623 */
624 int QQmlType::attachedPropertiesId() const
625 {
626     return d->m_attachedPropertiesId;
627 }
628
629 int QQmlType::parserStatusCast() const
630 {
631     return d->m_parserStatusCast;
632 }
633
634 int QQmlType::propertyValueSourceCast() const
635 {
636     return d->m_propertyValueSourceCast;
637 }
638
639 int QQmlType::propertyValueInterceptorCast() const
640 {
641     return d->m_propertyValueInterceptorCast;
642 }
643
644 const char *QQmlType::interfaceIId() const
645 {
646     return d->m_iid;
647 }
648
649 int QQmlType::index() const
650 {
651     return d->m_index;
652 }
653
654 int QQmlType::enumValue(const QHashedStringRef &name) const
655 {
656     d->initEnums();
657
658     int *rv = d->m_enums.value(name);
659     return rv?*rv:-1;
660 }
661
662 int QQmlType::enumValue(const QHashedV8String &name) const
663 {
664     d->initEnums();
665
666     int *rv = d->m_enums.value(name);
667     return rv?*rv:-1;
668 }
669
670 QQmlTypeModule::QQmlTypeModule()
671 : d(new QQmlTypeModulePrivate)
672 {
673 }
674
675 QQmlTypeModule::~QQmlTypeModule()
676 {
677     delete d; d = 0;
678 }
679
680 QString QQmlTypeModule::module() const
681 {
682     return d->uri.uri;
683 }
684
685 int QQmlTypeModule::majorVersion() const
686 {
687     return d->uri.majorVersion;
688 }
689
690 int QQmlTypeModule::minimumMinorVersion() const
691 {
692     return d->minMinorVersion;
693 }
694
695 int QQmlTypeModule::maximumMinorVersion() const
696 {
697     return d->maxMinorVersion;
698 }
699
700 void QQmlTypeModulePrivate::add(QQmlType *type)
701 {
702     types << type;
703
704     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
705     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
706
707     QList<QQmlType *> &list = typeHash[type->elementName()];
708     for (int ii = 0; ii < list.count(); ++ii) {
709         if (list.at(ii)->minorVersion() < type->minorVersion()) {
710             list.insert(ii, type);
711             return;
712         }
713     }
714     list.append(type);
715 }
716
717 QList<QQmlType *> QQmlTypeModule::types()
718 {
719     QList<QQmlType *> rv;
720     QReadLocker lock(metaTypeDataLock());
721     rv = d->types;
722     return rv;
723 }
724
725 QList<QQmlType *> QQmlTypeModule::type(const QString &name)
726 {
727     QReadLocker lock(metaTypeDataLock());
728     QList<QQmlType *> rv;
729     for (int ii = 0; ii < d->types.count(); ++ii) {
730         if (d->types.at(ii)->elementName() == name)
731             rv << d->types.at(ii);
732     }
733     return rv;
734 }
735
736 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
737 {
738     QReadLocker lock(metaTypeDataLock());
739
740     QList<QQmlType *> *types = d->typeHash.value(name);
741     if (!types) return 0;
742
743     for (int ii = 0; ii < types->count(); ++ii)
744         if (types->at(ii)->minorVersion() <= minor)
745             return types->at(ii);
746
747     return 0;
748 }
749
750 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
751 {
752     QReadLocker lock(metaTypeDataLock());
753
754     QList<QQmlType *> *types = d->typeHash.value(name);
755     if (!types) return 0;
756
757     for (int ii = 0; ii < types->count(); ++ii)
758         if (types->at(ii)->minorVersion() <= minor)
759             return types->at(ii);
760
761     return 0;
762 }
763
764
765 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
766 : m_module(0), m_minor(0)
767 {
768 }
769
770 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
771 : m_module(module), m_minor(minor)
772 {
773     Q_ASSERT(m_module);
774     Q_ASSERT(m_minor >= 0);
775 }
776
777 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
778 : m_module(o.m_module), m_minor(o.m_minor)
779 {
780 }
781
782 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
783 {
784     m_module = o.m_module;
785     m_minor = o.m_minor;
786     return *this;
787 }
788
789 QQmlTypeModule *QQmlTypeModuleVersion::module() const
790 {
791     return m_module;
792 }
793
794 int QQmlTypeModuleVersion::minorVersion() const
795 {
796     return m_minor;
797 }
798
799 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
800 {
801     if (m_module) return m_module->type(name, m_minor);
802     else return 0;
803 }
804
805 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
806 {
807     if (m_module) return m_module->type(name, m_minor);
808     else return 0;
809 }
810
811
812 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
813 {
814     QWriteLocker lock(metaTypeDataLock());
815     QQmlMetaTypeData *data = metaTypeData();
816
817     data->parentFunctions.append(autoparent.function);
818
819     return data->parentFunctions.count() - 1;
820 }
821
822 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
823 {
824     if (interface.version > 0) 
825         qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
826
827     QWriteLocker lock(metaTypeDataLock());
828     QQmlMetaTypeData *data = metaTypeData();
829
830     int index = data->types.count();
831
832     QQmlType *type = new QQmlType(index, interface);
833
834     data->types.append(type);
835     data->idToType.insert(type->typeId(), type);
836     data->idToType.insert(type->qListTypeId(), type);
837     // XXX No insertMulti, so no multi-version interfaces?
838     if (!type->qmlTypeName().isEmpty())
839         data->nameToType.insert(type->qmlTypeName(), type);
840
841     if (data->interfaces.size() <= interface.typeId)
842         data->interfaces.resize(interface.typeId + 16);
843     if (data->lists.size() <= interface.listId)
844         data->lists.resize(interface.listId + 16);
845     data->interfaces.setBit(interface.typeId, true);
846     data->lists.setBit(interface.listId, true);
847
848     return index;
849 }
850
851 int registerType(const QQmlPrivate::RegisterType &type)
852 {
853     if (type.elementName) {
854         for (int ii = 0; type.elementName[ii]; ++ii) {
855             if (!isalnum(type.elementName[ii])) {
856                 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
857                 return -1;
858             }
859         }
860     }
861
862     QWriteLocker lock(metaTypeDataLock());
863     QQmlMetaTypeData *data = metaTypeData();
864     int index = data->types.count();
865
866     QQmlType *dtype = new QQmlType(index, type);
867
868     data->types.append(dtype);
869     data->idToType.insert(dtype->typeId(), dtype);
870     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
871
872     if (!dtype->qmlTypeName().isEmpty())
873         data->nameToType.insertMulti(dtype->qmlTypeName(), dtype);
874
875     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
876
877     if (data->objects.size() <= type.typeId)
878         data->objects.resize(type.typeId + 16);
879     if (data->lists.size() <= type.listId)
880         data->lists.resize(type.listId + 16);
881     data->objects.setBit(type.typeId, true);
882     if (type.listId) data->lists.setBit(type.listId, true);
883
884     if (type.uri) {
885         QString mod = QString::fromUtf8(type.uri);
886
887         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
888         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
889         if (!module) {
890             module = new QQmlTypeModule;
891             module->d->uri = versionedUri;
892             data->uriToModule.insert(versionedUri, module);
893         }
894         module->d->add(dtype);
895     }
896
897     return index;
898 }
899
900 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
901 {
902     QWriteLocker lock(metaTypeDataLock());
903
904     QQmlMetaTypeData *data = metaTypeData();
905     QString uri = QString::fromUtf8(api.uri);
906     QQmlMetaType::ModuleApi import;
907     import.major = api.versionMajor;
908     import.minor = api.versionMinor;
909     import.script = api.scriptApi;
910     import.qobject = api.qobjectApi;
911
912     int index = data->moduleApiCount++;
913
914     QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
915     if (iter == data->moduleApis.end()) {
916         QQmlMetaTypeData::ModuleApiList apis;
917         apis.moduleApis << import;
918         data->moduleApis.insert(uri, apis);
919     } else {
920         iter->moduleApis << import;
921         iter->sorted = false;
922     }
923
924     return index;
925 }
926
927
928 /*
929 This method is "over generalized" to allow us to (potentially) register more types of things in
930 the future without adding exported symbols.
931 */
932 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
933 {
934     if (type == TypeRegistration) {
935         return registerType(*reinterpret_cast<RegisterType *>(data));
936     } else if (type == InterfaceRegistration) {
937         return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
938     } else if (type == AutoParentRegistration) {
939         return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
940     } else if (type == ModuleApiRegistration) {
941         return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
942     }
943     return -1;
944 }
945
946 /*
947     Returns true if a module \a uri of any version is installed.
948 */
949 bool QQmlMetaType::isAnyModule(const QString &uri)
950 {
951     QReadLocker lock(metaTypeDataLock());
952     QQmlMetaTypeData *data = metaTypeData();
953
954     for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
955          iter != data->uriToModule.end(); ++iter) {
956         if ((*iter)->module() == uri)
957             return true;
958     }
959
960     return false;
961 }
962
963 /*
964     Returns true if any type or API has been registered for the given \a module with at least
965     versionMajor.versionMinor, or if types have been registered for \a module with at most
966     versionMajor.versionMinor.
967
968     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.
969 */
970 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
971 {
972     Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
973     QReadLocker lock(metaTypeDataLock());
974
975     QQmlMetaTypeData *data = metaTypeData();
976
977     // first, check Types
978     QQmlTypeModule *tm = 
979         data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
980     if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
981         return true;
982
983     // then, check ModuleApis
984     foreach (const QQmlMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
985         if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
986             return true;
987     }
988
989     return false;
990 }
991
992 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
993 {
994     QReadLocker lock(metaTypeDataLock());
995     QQmlMetaTypeData *data = metaTypeData();
996     return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
997 }
998
999 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1000 {
1001     QReadLocker lock(metaTypeDataLock());
1002     QQmlMetaTypeData *data = metaTypeData();
1003     return data->parentFunctions;
1004 }
1005
1006 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1007 {
1008     return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1009 }
1010
1011 QQmlMetaType::ModuleApi
1012 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1013 {
1014     QReadLocker lock(metaTypeDataLock());
1015     QQmlMetaTypeData *data = metaTypeData();
1016
1017     QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
1018     if (iter == data->moduleApis.end())
1019         return ModuleApi();
1020
1021     if (iter->sorted == false) {
1022         qSort(iter->moduleApis.begin(), iter->moduleApis.end());
1023         iter->sorted = true;
1024     }
1025
1026     for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
1027         const ModuleApi &import = iter->moduleApis.at(ii);
1028         if (import.major == versionMajor && import.minor <= versionMinor)
1029             return import;
1030     }
1031
1032     return ModuleApi();
1033 }
1034
1035 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1036 {
1037     QReadLocker lock(metaTypeDataLock());
1038     QQmlMetaTypeData *data = metaTypeData();
1039
1040     QHash<QString, QList<ModuleApi> > moduleApis;
1041     QHashIterator<QString, QQmlMetaTypeData::ModuleApiList> it(data->moduleApis);
1042     while (it.hasNext()) {
1043         it.next();
1044         moduleApis[it.key()] = it.value().moduleApis;
1045     }
1046
1047     return moduleApis;
1048 }
1049
1050 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1051 {
1052     if (!isQObject(v.userType())) {
1053         if (ok) *ok = false;
1054         return 0;
1055     }
1056
1057     if (ok) *ok = true;
1058
1059     return *(QObject **)v.constData();
1060 }
1061
1062 bool QQmlMetaType::isQObject(int userType)
1063 {
1064     if (userType == QMetaType::QObjectStar)
1065         return true;
1066
1067     QReadLocker lock(metaTypeDataLock());
1068     QQmlMetaTypeData *data = metaTypeData();
1069     return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1070 }
1071
1072 /*
1073     Returns the item type for a list of type \a id.
1074  */
1075 int QQmlMetaType::listType(int id)
1076 {
1077     QReadLocker lock(metaTypeDataLock());
1078     QQmlMetaTypeData *data = metaTypeData();
1079     QQmlType *type = data->idToType.value(id);
1080     if (type && type->qListTypeId() == id)
1081         return type->typeId();
1082     else
1083         return 0;
1084 }
1085
1086 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1087 {
1088     QReadLocker lock(metaTypeDataLock());
1089     QQmlMetaTypeData *data = metaTypeData();
1090
1091     QQmlType *type = data->metaObjectToType.value(mo);
1092     if (type && type->attachedPropertiesFunction())
1093         return type->attachedPropertiesId();
1094     else
1095         return -1;
1096 }
1097
1098 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1099 {
1100     if (id < 0)
1101         return 0;
1102     QReadLocker lock(metaTypeDataLock());
1103     QQmlMetaTypeData *data = metaTypeData();
1104     return data->types.at(id)->attachedPropertiesFunction();
1105 }
1106
1107 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1108 {
1109     int idx = metaObject->indexOfClassInfo("DefaultProperty");
1110     if (-1 == idx)
1111         return QMetaProperty();
1112
1113     QMetaClassInfo info = metaObject->classInfo(idx);
1114     if (!info.value())
1115         return QMetaProperty();
1116
1117     idx = metaObject->indexOfProperty(info.value());
1118     if (-1 == idx)
1119         return QMetaProperty();
1120
1121     return metaObject->property(idx);
1122 }
1123
1124 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1125 {
1126     if (!obj)
1127         return QMetaProperty();
1128
1129     const QMetaObject *metaObject = obj->metaObject();
1130     return defaultProperty(metaObject);
1131 }
1132
1133 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1134 {
1135     int idx = metaObject->indexOfClassInfo("DefaultMethod");
1136     if (-1 == idx)
1137         return QMetaMethod();
1138
1139     QMetaClassInfo info = metaObject->classInfo(idx);
1140     if (!info.value())
1141         return QMetaMethod();
1142
1143     idx = metaObject->indexOfMethod(info.value());
1144     if (-1 == idx)
1145         return QMetaMethod();
1146
1147     return metaObject->method(idx);
1148 }
1149
1150 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1151 {
1152     if (!obj)
1153         return QMetaMethod();
1154
1155     const QMetaObject *metaObject = obj->metaObject();
1156     return defaultMethod(metaObject);
1157 }
1158
1159 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1160 {
1161     if (userType < 0)
1162         return Unknown;
1163     if (userType == QMetaType::QObjectStar)
1164         return Object;
1165
1166     QReadLocker lock(metaTypeDataLock());
1167     QQmlMetaTypeData *data = metaTypeData();
1168     if (userType < data->objects.size() && data->objects.testBit(userType))
1169         return Object;
1170     else if (userType < data->lists.size() && data->lists.testBit(userType))
1171         return List;
1172     else
1173         return Unknown;
1174 }
1175
1176 bool QQmlMetaType::isInterface(int userType)
1177 {
1178     QReadLocker lock(metaTypeDataLock());
1179     QQmlMetaTypeData *data = metaTypeData();
1180     return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1181 }
1182
1183 const char *QQmlMetaType::interfaceIId(int userType)
1184 {
1185     QReadLocker lock(metaTypeDataLock());
1186     QQmlMetaTypeData *data = metaTypeData();
1187     QQmlType *type = data->idToType.value(userType);
1188     lock.unlock();
1189     if (type && type->isInterface() && type->typeId() == userType)
1190         return type->interfaceIId();
1191     else
1192         return 0;
1193 }
1194
1195 bool QQmlMetaType::isList(int userType)
1196 {
1197     QReadLocker lock(metaTypeDataLock());
1198     QQmlMetaTypeData *data = metaTypeData();
1199     return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1200 }
1201
1202 /*!
1203     A custom string convertor allows you to specify a function pointer that
1204     returns a variant of \a type. For example, if you have written your own icon
1205     class that you want to support as an object property assignable in QML:
1206
1207     \code
1208     int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1209     QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1210     \endcode
1211
1212     The function pointer must be of the form:
1213     \code
1214     QVariant (*StringConverter)(const QString &);
1215     \endcode
1216  */
1217 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1218 {
1219     QWriteLocker lock(metaTypeDataLock());
1220
1221     QQmlMetaTypeData *data = metaTypeData();
1222     if (data->stringConverters.contains(type))
1223         return;
1224     data->stringConverters.insert(type, converter);
1225 }
1226
1227 /*!
1228     Return the custom string converter for \a type, previously installed through
1229     registerCustomStringConverter()
1230  */
1231 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1232 {
1233     QReadLocker lock(metaTypeDataLock());
1234
1235     QQmlMetaTypeData *data = metaTypeData();
1236     return data->stringConverters.value(type);
1237 }
1238
1239 /*!
1240     Returns the type (if any) of URI-qualified named \a name in version specified
1241     by \a version_major and \a version_minor.
1242 */
1243 QQmlType *QQmlMetaType::qmlType(const QString &name, int version_major, int version_minor)
1244 {
1245     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1246     QReadLocker lock(metaTypeDataLock());
1247     QQmlMetaTypeData *data = metaTypeData();
1248
1249     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1250     while (it != data->nameToType.end()) {
1251         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1252         if (it.key() == name && (version_major<0 || (*it)->availableInVersion(version_major,version_minor)))
1253             return (*it);
1254         ++it;
1255     }
1256
1257     return 0;
1258 }
1259
1260 /*!
1261     Returns the type (if any) that corresponds to the \a metaObject.  Returns null if no
1262     type is registered.
1263 */
1264 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1265 {
1266     QReadLocker lock(metaTypeDataLock());
1267     QQmlMetaTypeData *data = metaTypeData();
1268
1269     return data->metaObjectToType.value(metaObject);
1270 }
1271
1272 /*!
1273     Returns the type (if any) that corresponds to the \a metaObject in version specified
1274     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
1275     type is registered.
1276 */
1277 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor)
1278 {
1279     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1280     QReadLocker lock(metaTypeDataLock());
1281     QQmlMetaTypeData *data = metaTypeData();
1282
1283     QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1284     while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1285         QQmlType *t = *it;
1286         if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1287             return t;
1288         ++it;
1289     }
1290
1291     return 0;
1292 }
1293
1294 /*!
1295     Returns the type (if any) that corresponds to the QVariant::Type \a userType.  
1296     Returns null if no type is registered.
1297 */
1298 QQmlType *QQmlMetaType::qmlType(int userType)
1299 {
1300     QReadLocker lock(metaTypeDataLock());
1301     QQmlMetaTypeData *data = metaTypeData();
1302
1303     QQmlType *type = data->idToType.value(userType);
1304     if (type && type->typeId() == userType)
1305         return type;
1306     else
1307         return 0;
1308 }
1309
1310 /*!
1311     Returns the list of registered QML type names.
1312 */
1313 QList<QString> QQmlMetaType::qmlTypeNames()
1314 {
1315     QReadLocker lock(metaTypeDataLock());
1316     QQmlMetaTypeData *data = metaTypeData();
1317
1318     return data->nameToType.keys();
1319 }
1320
1321 /*!
1322     Returns the list of registered QML types.
1323 */
1324 QList<QQmlType*> QQmlMetaType::qmlTypes()
1325 {
1326     QReadLocker lock(metaTypeDataLock());
1327     QQmlMetaTypeData *data = metaTypeData();
1328
1329     return data->nameToType.values();
1330 }
1331
1332 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1333 {
1334     static int id = 0;
1335     if (!id) {
1336         id = QMetaType::type("QQuickAnchorLine");
1337     }
1338     return id;
1339 }
1340
1341 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1342
1343 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1344 {
1345     anchorLineCompareFunction = fun;
1346 }
1347
1348 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1349 {
1350     Q_ASSERT(anchorLineCompareFunction != 0);
1351     return anchorLineCompareFunction(p1, p2);
1352 }
1353
1354 QT_END_NAMESPACE