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