Remove non-templated qobject module api registration function
[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     int index = data->moduleApiCount++;
913
914     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
915     if (!apiList) {
916         QQmlMetaTypeData::ModuleApiList apis;
917         apis.moduleApis << import;
918         data->moduleApis.insert(uri, apis);
919     } else {
920         apiList->moduleApis << import;
921         apiList->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     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
985     if (apiList) {
986         foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
987             if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
988                 return true;
989         }
990     }
991
992     return false;
993 }
994
995 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
996 {
997     QReadLocker lock(metaTypeDataLock());
998     QQmlMetaTypeData *data = metaTypeData();
999     return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1000 }
1001
1002 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1003 {
1004     QReadLocker lock(metaTypeDataLock());
1005     QQmlMetaTypeData *data = metaTypeData();
1006     return data->parentFunctions;
1007 }
1008
1009 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1010 {
1011     return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1012 }
1013
1014 QQmlMetaType::ModuleApi
1015 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1016 {
1017     QReadLocker lock(metaTypeDataLock());
1018     QQmlMetaTypeData *data = metaTypeData();
1019
1020     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1021     if (!apiList)
1022         return ModuleApi();
1023
1024     if (apiList->sorted == false) {
1025         qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1026         apiList->sorted = true;
1027     }
1028
1029     for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1030         const ModuleApi &import = apiList->moduleApis.at(ii);
1031         if (import.major == versionMajor && import.minor <= versionMinor)
1032             return import;
1033     }
1034
1035     return ModuleApi();
1036 }
1037
1038 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1039 {
1040     QReadLocker lock(metaTypeDataLock());
1041     QQmlMetaTypeData *data = metaTypeData();
1042
1043     QHash<QString, QList<ModuleApi> > moduleApis;
1044     QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1045     for (; it != data->moduleApis.end(); ++it)
1046         moduleApis[it.key()] = it.value().moduleApis;
1047
1048     return moduleApis;
1049 }
1050
1051 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1052 {
1053     if (!isQObject(v.userType())) {
1054         if (ok) *ok = false;
1055         return 0;
1056     }
1057
1058     if (ok) *ok = true;
1059
1060     return *(QObject **)v.constData();
1061 }
1062
1063 bool QQmlMetaType::isQObject(int userType)
1064 {
1065     if (userType == QMetaType::QObjectStar)
1066         return true;
1067
1068     QReadLocker lock(metaTypeDataLock());
1069     QQmlMetaTypeData *data = metaTypeData();
1070     return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1071 }
1072
1073 /*
1074     Returns the item type for a list of type \a id.
1075  */
1076 int QQmlMetaType::listType(int id)
1077 {
1078     QReadLocker lock(metaTypeDataLock());
1079     QQmlMetaTypeData *data = metaTypeData();
1080     QQmlType *type = data->idToType.value(id);
1081     if (type && type->qListTypeId() == id)
1082         return type->typeId();
1083     else
1084         return 0;
1085 }
1086
1087 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1088 {
1089     QReadLocker lock(metaTypeDataLock());
1090     QQmlMetaTypeData *data = metaTypeData();
1091
1092     QQmlType *type = data->metaObjectToType.value(mo);
1093     if (type && type->attachedPropertiesFunction())
1094         return type->attachedPropertiesId();
1095     else
1096         return -1;
1097 }
1098
1099 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1100 {
1101     if (id < 0)
1102         return 0;
1103     QReadLocker lock(metaTypeDataLock());
1104     QQmlMetaTypeData *data = metaTypeData();
1105     return data->types.at(id)->attachedPropertiesFunction();
1106 }
1107
1108 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1109 {
1110     int idx = metaObject->indexOfClassInfo("DefaultProperty");
1111     if (-1 == idx)
1112         return QMetaProperty();
1113
1114     QMetaClassInfo info = metaObject->classInfo(idx);
1115     if (!info.value())
1116         return QMetaProperty();
1117
1118     idx = metaObject->indexOfProperty(info.value());
1119     if (-1 == idx)
1120         return QMetaProperty();
1121
1122     return metaObject->property(idx);
1123 }
1124
1125 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1126 {
1127     if (!obj)
1128         return QMetaProperty();
1129
1130     const QMetaObject *metaObject = obj->metaObject();
1131     return defaultProperty(metaObject);
1132 }
1133
1134 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1135 {
1136     int idx = metaObject->indexOfClassInfo("DefaultMethod");
1137     if (-1 == idx)
1138         return QMetaMethod();
1139
1140     QMetaClassInfo info = metaObject->classInfo(idx);
1141     if (!info.value())
1142         return QMetaMethod();
1143
1144     idx = metaObject->indexOfMethod(info.value());
1145     if (-1 == idx)
1146         return QMetaMethod();
1147
1148     return metaObject->method(idx);
1149 }
1150
1151 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1152 {
1153     if (!obj)
1154         return QMetaMethod();
1155
1156     const QMetaObject *metaObject = obj->metaObject();
1157     return defaultMethod(metaObject);
1158 }
1159
1160 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1161 {
1162     if (userType < 0)
1163         return Unknown;
1164     if (userType == QMetaType::QObjectStar)
1165         return Object;
1166
1167     QReadLocker lock(metaTypeDataLock());
1168     QQmlMetaTypeData *data = metaTypeData();
1169     if (userType < data->objects.size() && data->objects.testBit(userType))
1170         return Object;
1171     else if (userType < data->lists.size() && data->lists.testBit(userType))
1172         return List;
1173     else
1174         return Unknown;
1175 }
1176
1177 bool QQmlMetaType::isInterface(int userType)
1178 {
1179     QReadLocker lock(metaTypeDataLock());
1180     QQmlMetaTypeData *data = metaTypeData();
1181     return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1182 }
1183
1184 const char *QQmlMetaType::interfaceIId(int userType)
1185 {
1186     QReadLocker lock(metaTypeDataLock());
1187     QQmlMetaTypeData *data = metaTypeData();
1188     QQmlType *type = data->idToType.value(userType);
1189     lock.unlock();
1190     if (type && type->isInterface() && type->typeId() == userType)
1191         return type->interfaceIId();
1192     else
1193         return 0;
1194 }
1195
1196 bool QQmlMetaType::isList(int userType)
1197 {
1198     QReadLocker lock(metaTypeDataLock());
1199     QQmlMetaTypeData *data = metaTypeData();
1200     return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1201 }
1202
1203 /*!
1204     A custom string convertor allows you to specify a function pointer that
1205     returns a variant of \a type. For example, if you have written your own icon
1206     class that you want to support as an object property assignable in QML:
1207
1208     \code
1209     int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1210     QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1211     \endcode
1212
1213     The function pointer must be of the form:
1214     \code
1215     QVariant (*StringConverter)(const QString &);
1216     \endcode
1217  */
1218 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1219 {
1220     QWriteLocker lock(metaTypeDataLock());
1221
1222     QQmlMetaTypeData *data = metaTypeData();
1223     if (data->stringConverters.contains(type))
1224         return;
1225     data->stringConverters.insert(type, converter);
1226 }
1227
1228 /*!
1229     Return the custom string converter for \a type, previously installed through
1230     registerCustomStringConverter()
1231  */
1232 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1233 {
1234     QReadLocker lock(metaTypeDataLock());
1235
1236     QQmlMetaTypeData *data = metaTypeData();
1237     return data->stringConverters.value(type);
1238 }
1239
1240 /*!
1241     Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1242     by \a version_major and \a version_minor.
1243 */
1244 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1245 {
1246     int slash = qualifiedName.indexOf(QLatin1Char('/'));
1247     if (slash <= 0)
1248         return 0;
1249
1250     QHashedStringRef module(qualifiedName.constData(), slash);
1251     QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1252
1253     return qmlType(name, module, version_major, version_minor);
1254 }
1255
1256 /*!
1257     Returns the type (if any) of \a name in \a module and version specified
1258     by \a version_major and \a version_minor.
1259 */
1260 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1261 {
1262     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1263     QReadLocker lock(metaTypeDataLock());
1264     QQmlMetaTypeData *data = metaTypeData();
1265
1266     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1267     while (it != data->nameToType.end() && it.key() == name) {
1268         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1269         if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1270             return (*it);
1271         ++it;
1272     }
1273
1274     return 0;
1275 }
1276
1277 /*!
1278     Returns the type (if any) that corresponds to the \a metaObject.  Returns null if no
1279     type is registered.
1280 */
1281 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1282 {
1283     QReadLocker lock(metaTypeDataLock());
1284     QQmlMetaTypeData *data = metaTypeData();
1285
1286     return data->metaObjectToType.value(metaObject);
1287 }
1288
1289 /*!
1290     Returns the type (if any) that corresponds to the \a metaObject in version specified
1291     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
1292     type is registered.
1293 */
1294 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1295 {
1296     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1297     QReadLocker lock(metaTypeDataLock());
1298     QQmlMetaTypeData *data = metaTypeData();
1299
1300     QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1301     while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1302         QQmlType *t = *it;
1303         if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1304             return t;
1305         ++it;
1306     }
1307
1308     return 0;
1309 }
1310
1311 /*!
1312     Returns the type (if any) that corresponds to the QVariant::Type \a userType.  
1313     Returns null if no type is registered.
1314 */
1315 QQmlType *QQmlMetaType::qmlType(int userType)
1316 {
1317     QReadLocker lock(metaTypeDataLock());
1318     QQmlMetaTypeData *data = metaTypeData();
1319
1320     QQmlType *type = data->idToType.value(userType);
1321     if (type && type->typeId() == userType)
1322         return type;
1323     else
1324         return 0;
1325 }
1326
1327 /*!
1328     Returns the list of registered QML type names.
1329 */
1330 QList<QString> QQmlMetaType::qmlTypeNames()
1331 {
1332     QReadLocker lock(metaTypeDataLock());
1333     QQmlMetaTypeData *data = metaTypeData();
1334
1335     QList<QString> names;
1336     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1337     while (it != data->nameToType.end()) {
1338         names += (*it)->qmlTypeName();
1339         ++it;
1340     }
1341
1342     return names;
1343 }
1344
1345 /*!
1346     Returns the list of registered QML types.
1347 */
1348 QList<QQmlType*> QQmlMetaType::qmlTypes()
1349 {
1350     QReadLocker lock(metaTypeDataLock());
1351     QQmlMetaTypeData *data = metaTypeData();
1352
1353     return data->nameToType.values();
1354 }
1355
1356 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1357 {
1358     static int id = 0;
1359     if (!id) {
1360         id = QMetaType::type("QQuickAnchorLine");
1361     }
1362     return id;
1363 }
1364
1365 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1366
1367 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1368 {
1369     anchorLineCompareFunction = fun;
1370 }
1371
1372 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1373 {
1374     Q_ASSERT(anchorLineCompareFunction != 0);
1375     return anchorLineCompareFunction(p1, p2);
1376 }
1377
1378 QT_END_NAMESPACE