1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include <QtQml/qqmlprivate.h>
43 #include "qqmlmetatype_p.h"
45 #include <private/qqmlproxymetaobject_p.h>
46 #include <private/qqmlcustomparser_p.h>
47 #include <private/qqmlguard_p.h>
48 #include <private/qhashedstring_p.h>
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>
57 #include <qmetatype.h>
58 #include <qobjectdefs.h>
59 #include <qbytearray.h>
60 #include <qreadwritelock.h>
62 #include <qstringlist.h>
69 struct QQmlMetaTypeData
73 QList<QQmlType *> types;
74 typedef QHash<int, QQmlType *> Ids;
76 typedef QHash<QHashedStringRef,QQmlType *> Names;
78 typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
79 MetaObjects metaObjectToType;
80 typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
81 StringConverters stringConverters;
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;
94 typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
95 TypeModules uriToModule;
97 struct ModuleApiList {
98 ModuleApiList() : sorted(true) {}
99 QList<QQmlMetaType::ModuleApi> moduleApis;
102 typedef QStringHash<ModuleApiList> ModuleApis;
103 ModuleApis moduleApis;
107 QBitArray interfaces;
110 QList<QQmlPrivate::AutoParentFunction> parentFunctions;
113 class QQmlTypeModulePrivate
116 QQmlTypeModulePrivate()
117 : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
119 QQmlMetaTypeData::VersionedUri uri;
124 void add(QQmlType *);
126 QStringHash<QList<QQmlType *> > typeHash;
127 QList<QQmlType *> types;
130 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
131 Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
133 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
135 return v.uri.hash() ^ qHash(v.majorVersion);
138 QQmlMetaTypeData::QQmlMetaTypeData()
143 QQmlMetaTypeData::~QQmlMetaTypeData()
145 for (int i = 0; i < types.count(); ++i)
149 class QQmlTypePrivate
155 void initEnums() const;
156 void insertEnums(const QMetaObject *metaObject) const;
158 bool m_isInterface : 1;
160 QHashedString m_module;
162 QString m_elementName;
165 int m_typeId; int m_listId;
167 mutable bool m_containsRevisionedAttributes;
168 mutable QQmlType *m_superType;
170 int m_allocationSize;
171 void (*m_newFunc)(void *);
172 QString m_noCreationReason;
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;
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;
191 static QHash<const QMetaObject *, int> m_attachedPropertyIds;
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)
199 return QHashedString();
201 static const char *lastModule = 0;
202 static QHashedString lastModuleStr;
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();
212 return lastModuleStr;
215 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
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)
227 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
228 : d(new QQmlTypePrivate)
230 d->m_isInterface = true;
231 d->m_iid = interface.iid;
232 d->m_typeId = interface.typeId;
233 d->m_listId = interface.listId;
237 d->m_version_maj = 0;
238 d->m_version_min = 0;
241 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
242 : d(new QQmlTypePrivate)
244 d->m_module = moduletoUtf8(type.uri);
245 d->m_elementName = QString::fromUtf8(type.elementName);
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;
265 d->m_attachedPropertiesId = -1;
267 d->m_parserStatusCast = type.parserStatusCast;
268 d->m_propertyValueSourceCast = type.valueSourceCast;
269 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
270 d->m_extFunc = type.extensionObjectCreate;
272 d->m_customParser = type.customParser;
274 if (type.extensionMetaObject)
275 d->m_extMetaObject = type.extensionMetaObject;
278 QQmlType::~QQmlType()
280 delete d->m_customParser;
284 const QHashedString &QQmlType::module() const
289 int QQmlType::majorVersion() const
291 return d->m_version_maj;
294 int QQmlType::minorVersion() const
296 return d->m_version_min;
299 bool QQmlType::availableInVersion(int vmajor, int vminor) const
301 Q_ASSERT(vmajor >= 0 && vminor >= 0);
302 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
305 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
307 Q_ASSERT(vmajor >= 0 && vminor >= 0);
308 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
311 // returns the nearest _registered_ super class
312 QQmlType *QQmlType::superType() const
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();
320 d->m_haveSuperType = true;
323 return d->m_superType;
326 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
327 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
330 builder.setClassName(ignoreEnd->className());
333 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
334 QMetaClassInfo info = mo->classInfo(ii);
336 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
337 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
340 builder.addClassInfo(info.name(), info.value());
345 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
346 QMetaProperty property = mo->property(ii);
348 int otherIndex = ignoreEnd->indexOfProperty(property.name());
349 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
350 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
353 builder.addProperty(property);
358 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
359 QMetaMethod method = mo->method(ii);
361 // More complex - need to search name
362 QByteArray name = method.name();
367 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
368 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
371 QMetaMethod other = ignoreEnd->method(ii);
373 found = name == other.name();
376 QMetaMethodBuilder m = builder.addMethod(method);
378 m.setAccess(QMetaMethod::Private);
382 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
383 QMetaEnum enumerator = mo->enumerator(ii);
385 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
386 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
389 builder.addEnumerator(enumerator);
394 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
397 i -= mo->propertyOffset();
398 if (i < 0 && mo->d.superdata)
399 return isPropertyRevisioned(mo->d.superdata, index);
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];
406 return (flags & Revisioned);
412 void QQmlTypePrivate::init() const
414 if (m_isSetup) return;
416 QWriteLocker lock(metaTypeDataLock());
420 // Setup extended meta object
421 // XXX - very inefficient
422 const QMetaObject *mo = m_baseMetaObject;
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;
433 mo = mo->d.superdata;
435 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
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;
449 mo = mo->d.superdata;
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();
459 // Check for revisioned details
461 const QMetaObject *mo = 0;
462 if (m_metaObjects.isEmpty())
463 mo = m_baseMetaObject;
465 mo = m_metaObjects.first().metaObject;
467 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
468 if (isPropertyRevisioned(mo, ii))
469 m_containsRevisionedAttributes = true;
472 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
473 if (mo->method(ii).revision() != 0)
474 m_containsRevisionedAttributes = true;
482 void QQmlTypePrivate::initEnums() const
484 if (m_isEnumSetup) return;
488 QWriteLocker lock(metaTypeDataLock());
489 if (m_isEnumSetup) return;
491 insertEnums(m_baseMetaObject);
493 m_isEnumSetup = true;
496 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
498 // Add any enum values defined by 'related' classes
499 if (metaObject->d.relatedMetaObjects) {
500 const QMetaObject **related = metaObject->d.relatedMetaObjects;
503 insertEnums(*related++);
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));
515 QByteArray QQmlType::typeName() const
517 if (d->m_baseMetaObject)
518 return d->m_baseMetaObject->className();
523 const QString &QQmlType::elementName() const
525 return d->m_elementName;
528 const QString &QQmlType::qmlTypeName() const
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;
534 d->m_name = d->m_elementName;
540 QObject *QQmlType::create() const
544 QObject *rv = (QObject *)operator new(d->m_allocationSize);
547 if (rv && !d->m_metaObjects.isEmpty())
548 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
553 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
557 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
560 if (rv && !d->m_metaObjects.isEmpty())
561 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
564 *memory = ((char *)rv) + d->m_allocationSize;
567 QQmlCustomParser *QQmlType::customParser() const
569 return d->m_customParser;
572 QQmlType::CreateFunc QQmlType::createFunction() const
577 QString QQmlType::noCreationReason() const
579 return d->m_noCreationReason;
582 int QQmlType::createSize() const
584 return d->m_allocationSize;
587 bool QQmlType::isCreatable() const
589 return d->m_newFunc != 0;
592 bool QQmlType::isExtendedType() const
596 return !d->m_metaObjects.isEmpty();
599 bool QQmlType::isInterface() const
601 return d->m_isInterface;
604 int QQmlType::typeId() const
609 int QQmlType::qListTypeId() const
614 const QMetaObject *QQmlType::metaObject() const
618 if (d->m_metaObjects.isEmpty())
619 return d->m_baseMetaObject;
621 return d->m_metaObjects.first().metaObject;
625 const QMetaObject *QQmlType::baseMetaObject() const
627 return d->m_baseMetaObject;
630 bool QQmlType::containsRevisionedAttributes() const
634 return d->m_containsRevisionedAttributes;
637 int QQmlType::metaObjectRevision() const
639 return d->m_revision;
642 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
644 return d->m_attachedPropertiesFunc;
647 const QMetaObject *QQmlType::attachedPropertiesType() const
649 return d->m_attachedPropertiesType;
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).
657 int QQmlType::attachedPropertiesId() const
659 return d->m_attachedPropertiesId;
662 int QQmlType::parserStatusCast() const
664 return d->m_parserStatusCast;
667 int QQmlType::propertyValueSourceCast() const
669 return d->m_propertyValueSourceCast;
672 int QQmlType::propertyValueInterceptorCast() const
674 return d->m_propertyValueInterceptorCast;
677 const char *QQmlType::interfaceIId() const
682 int QQmlType::index() const
687 int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
694 int *rv = d->m_enums.value(name);
702 int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
709 int *rv = d->m_enums.value(name);
717 int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
724 int *rv = d->m_enums.value(name);
732 QQmlTypeModule::QQmlTypeModule()
733 : d(new QQmlTypeModulePrivate)
737 QQmlTypeModule::~QQmlTypeModule()
742 QString QQmlTypeModule::module() const
747 int QQmlTypeModule::majorVersion() const
749 return d->uri.majorVersion;
752 int QQmlTypeModule::minimumMinorVersion() const
754 return d->minMinorVersion;
757 int QQmlTypeModule::maximumMinorVersion() const
759 return d->maxMinorVersion;
762 void QQmlTypeModulePrivate::add(QQmlType *type)
764 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
765 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
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);
777 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
779 QReadLocker lock(metaTypeDataLock());
781 QList<QQmlType *> *types = d->typeHash.value(name);
782 if (!types) return 0;
784 for (int ii = 0; ii < types->count(); ++ii)
785 if (types->at(ii)->minorVersion() <= minor)
786 return types->at(ii);
791 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
793 QReadLocker lock(metaTypeDataLock());
795 QList<QQmlType *> *types = d->typeHash.value(name);
796 if (!types) return 0;
798 for (int ii = 0; ii < types->count(); ++ii)
799 if (types->at(ii)->minorVersion() <= minor)
800 return types->at(ii);
806 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
807 : m_module(0), m_minor(0)
811 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
812 : m_module(module), m_minor(minor)
815 Q_ASSERT(m_minor >= 0);
818 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
819 : m_module(o.m_module), m_minor(o.m_minor)
823 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
825 m_module = o.m_module;
830 QQmlTypeModule *QQmlTypeModuleVersion::module() const
835 int QQmlTypeModuleVersion::minorVersion() const
840 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
842 if (m_module) return m_module->type(name, m_minor);
846 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
848 if (m_module) return m_module->type(name, m_minor);
853 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
855 QWriteLocker lock(metaTypeDataLock());
856 QQmlMetaTypeData *data = metaTypeData();
858 data->parentFunctions.append(autoparent.function);
860 return data->parentFunctions.count() - 1;
863 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
865 if (interface.version > 0)
866 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
868 QWriteLocker lock(metaTypeDataLock());
869 QQmlMetaTypeData *data = metaTypeData();
871 int index = data->types.count();
873 QQmlType *type = new QQmlType(index, interface);
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);
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);
892 int registerType(const QQmlPrivate::RegisterType &type)
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);
903 QWriteLocker lock(metaTypeDataLock());
904 QQmlMetaTypeData *data = metaTypeData();
905 int index = data->types.count();
907 QQmlType *dtype = new QQmlType(index, type);
909 data->types.append(dtype);
910 data->idToType.insert(dtype->typeId(), dtype);
911 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
913 if (!dtype->elementName().isEmpty())
914 data->nameToType.insertMulti(dtype->elementName(), dtype);
916 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
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);
925 if (!dtype->module().isEmpty()) {
926 const QHashedString &mod = dtype->module();
928 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
929 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
931 module = new QQmlTypeModule;
932 module->d->uri = versionedUri;
933 data->uriToModule.insert(versionedUri, module);
935 module->d->add(dtype);
941 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
943 QWriteLocker lock(metaTypeDataLock());
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.
954 int index = data->moduleApiCount++;
956 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
958 QQmlMetaTypeData::ModuleApiList apis;
959 apis.moduleApis << import;
960 data->moduleApis.insert(uri, apis);
962 apiList->moduleApis << import;
963 apiList->sorted = false;
971 This method is "over generalized" to allow us to (potentially) register more types of things in
972 the future without adding exported symbols.
974 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
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));
989 Returns true if a module \a uri of any version is installed.
991 bool QQmlMetaType::isAnyModule(const QString &uri)
993 QReadLocker lock(metaTypeDataLock());
994 QQmlMetaTypeData *data = metaTypeData();
996 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
997 iter != data->uriToModule.end(); ++iter) {
998 if ((*iter)->module() == uri)
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.
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.
1012 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1014 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1015 QReadLocker lock(metaTypeDataLock());
1017 QQmlMetaTypeData *data = metaTypeData();
1019 // first, check Types
1020 QQmlTypeModule *tm =
1021 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1022 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1025 // then, check ModuleApis
1026 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
1028 foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
1029 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
1037 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1039 QReadLocker lock(metaTypeDataLock());
1040 QQmlMetaTypeData *data = metaTypeData();
1041 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1044 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1046 QReadLocker lock(metaTypeDataLock());
1047 QQmlMetaTypeData *data = metaTypeData();
1048 return data->parentFunctions;
1051 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1053 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1056 QQmlMetaType::ModuleApi
1057 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1059 QReadLocker lock(metaTypeDataLock());
1060 QQmlMetaTypeData *data = metaTypeData();
1062 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1066 if (apiList->sorted == false) {
1067 qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1068 apiList->sorted = true;
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)
1080 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1082 QReadLocker lock(metaTypeDataLock());
1083 QQmlMetaTypeData *data = metaTypeData();
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;
1093 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1095 if (!isQObject(v.userType())) {
1096 if (ok) *ok = false;
1102 return *(QObject **)v.constData();
1105 bool QQmlMetaType::isQObject(int userType)
1107 if (userType == QMetaType::QObjectStar)
1110 QReadLocker lock(metaTypeDataLock());
1111 QQmlMetaTypeData *data = metaTypeData();
1112 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1116 Returns the item type for a list of type \a id.
1118 int QQmlMetaType::listType(int id)
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();
1129 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1131 QReadLocker lock(metaTypeDataLock());
1132 QQmlMetaTypeData *data = metaTypeData();
1134 QQmlType *type = data->metaObjectToType.value(mo);
1135 if (type && type->attachedPropertiesFunction())
1136 return type->attachedPropertiesId();
1141 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1145 QReadLocker lock(metaTypeDataLock());
1146 QQmlMetaTypeData *data = metaTypeData();
1147 return data->types.at(id)->attachedPropertiesFunction();
1150 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1152 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1154 return QMetaProperty();
1156 QMetaClassInfo info = metaObject->classInfo(idx);
1158 return QMetaProperty();
1160 idx = metaObject->indexOfProperty(info.value());
1162 return QMetaProperty();
1164 return metaObject->property(idx);
1167 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1170 return QMetaProperty();
1172 const QMetaObject *metaObject = obj->metaObject();
1173 return defaultProperty(metaObject);
1176 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1178 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1180 return QMetaMethod();
1182 QMetaClassInfo info = metaObject->classInfo(idx);
1184 return QMetaMethod();
1186 idx = metaObject->indexOfMethod(info.value());
1188 return QMetaMethod();
1190 return metaObject->method(idx);
1193 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1196 return QMetaMethod();
1198 const QMetaObject *metaObject = obj->metaObject();
1199 return defaultMethod(metaObject);
1202 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1206 if (userType == QMetaType::QObjectStar)
1209 QReadLocker lock(metaTypeDataLock());
1210 QQmlMetaTypeData *data = metaTypeData();
1211 if (userType < data->objects.size() && data->objects.testBit(userType))
1213 else if (userType < data->lists.size() && data->lists.testBit(userType))
1219 bool QQmlMetaType::isInterface(int userType)
1221 QReadLocker lock(metaTypeDataLock());
1222 QQmlMetaTypeData *data = metaTypeData();
1223 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1226 const char *QQmlMetaType::interfaceIId(int userType)
1228 QReadLocker lock(metaTypeDataLock());
1229 QQmlMetaTypeData *data = metaTypeData();
1230 QQmlType *type = data->idToType.value(userType);
1232 if (type && type->isInterface() && type->typeId() == userType)
1233 return type->interfaceIId();
1238 bool QQmlMetaType::isList(int userType)
1240 QReadLocker lock(metaTypeDataLock());
1241 QQmlMetaTypeData *data = metaTypeData();
1242 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
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:
1251 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1252 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1255 The function pointer must be of the form:
1257 QVariant (*StringConverter)(const QString &);
1260 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1262 QWriteLocker lock(metaTypeDataLock());
1264 QQmlMetaTypeData *data = metaTypeData();
1265 if (data->stringConverters.contains(type))
1267 data->stringConverters.insert(type, converter);
1271 Return the custom string converter for \a type, previously installed through
1272 registerCustomStringConverter()
1274 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1276 QReadLocker lock(metaTypeDataLock());
1278 QQmlMetaTypeData *data = metaTypeData();
1279 return data->stringConverters.value(type);
1283 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1284 by \a version_major and \a version_minor.
1286 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1288 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1292 QHashedStringRef module(qualifiedName.constData(), slash);
1293 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1295 return qmlType(name, module, version_major, version_minor);
1299 Returns the type (if any) of \a name in \a module and version specified
1300 by \a version_major and \a version_minor.
1302 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1304 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1305 QReadLocker lock(metaTypeDataLock());
1306 QQmlMetaTypeData *data = metaTypeData();
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))
1320 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1323 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1325 QReadLocker lock(metaTypeDataLock());
1326 QQmlMetaTypeData *data = metaTypeData();
1328 return data->metaObjectToType.value(metaObject);
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
1336 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1338 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1339 QReadLocker lock(metaTypeDataLock());
1340 QQmlMetaTypeData *data = metaTypeData();
1342 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1343 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1345 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1354 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1355 Returns null if no type is registered.
1357 QQmlType *QQmlMetaType::qmlType(int userType)
1359 QReadLocker lock(metaTypeDataLock());
1360 QQmlMetaTypeData *data = metaTypeData();
1362 QQmlType *type = data->idToType.value(userType);
1363 if (type && type->typeId() == userType)
1370 Returns the list of registered QML type names.
1372 QList<QString> QQmlMetaType::qmlTypeNames()
1374 QReadLocker lock(metaTypeDataLock());
1375 QQmlMetaTypeData *data = metaTypeData();
1377 QList<QString> names;
1378 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1379 while (it != data->nameToType.end()) {
1380 names += (*it)->qmlTypeName();
1388 Returns the list of registered QML types.
1390 QList<QQmlType*> QQmlMetaType::qmlTypes()
1392 QReadLocker lock(metaTypeDataLock());
1393 QQmlMetaTypeData *data = metaTypeData();
1395 return data->nameToType.values();
1398 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1402 id = QMetaType::type("QQuickAnchorLine");
1407 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1409 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1411 anchorLineCompareFunction = fun;
1414 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1416 Q_ASSERT(anchorLineCompareFunction != 0);
1417 return anchorLineCompareFunction(p1, p2);