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