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