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;
157 bool m_isInterface : 1;
159 QHashedString m_module;
161 QString m_elementName;
164 int m_typeId; int m_listId;
166 mutable bool m_containsRevisionedAttributes;
167 mutable QQmlType *m_superType;
169 int m_allocationSize;
170 void (*m_newFunc)(void *);
171 QString m_noCreationReason;
173 const QMetaObject *m_baseMetaObject;
174 QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
175 const QMetaObject *m_attachedPropertiesType;
176 int m_attachedPropertiesId;
177 int m_parserStatusCast;
178 int m_propertyValueSourceCast;
179 int m_propertyValueInterceptorCast;
180 QObject *(*m_extFunc)(QObject *);
181 const QMetaObject *m_extMetaObject;
183 QQmlCustomParser *m_customParser;
184 mutable volatile bool m_isSetup:1;
185 mutable volatile bool m_isEnumSetup:1;
186 mutable bool m_haveSuperType:1;
187 mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
188 mutable QStringHash<int> m_enums;
190 static QHash<const QMetaObject *, int> m_attachedPropertyIds;
193 // Avoid multiple fromUtf8(), copies and hashing of the module name.
194 // This is only called when metaTypeDataLock is locked.
195 static QHashedString moduletoUtf8(const char *module)
198 return QHashedString();
200 static const char *lastModule = 0;
201 static QHashedString lastModuleStr;
203 if (lastModule != module) {
204 lastModuleStr = QString::fromUtf8(module);
205 lastModuleStr.hash();
209 return lastModuleStr;
212 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
214 QQmlTypePrivate::QQmlTypePrivate()
215 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
216 m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
217 m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
218 m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
219 m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
224 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
225 : d(new QQmlTypePrivate)
227 d->m_isInterface = true;
228 d->m_iid = interface.iid;
229 d->m_typeId = interface.typeId;
230 d->m_listId = interface.listId;
234 d->m_version_maj = 0;
235 d->m_version_min = 0;
238 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
239 : d(new QQmlTypePrivate)
241 d->m_module = moduletoUtf8(type.uri);
242 d->m_elementName = QString::fromUtf8(type.elementName);
244 d->m_version_maj = type.versionMajor;
245 d->m_version_min = type.versionMinor;
246 if (type.version >= 1) // revisions added in version 1
247 d->m_revision = type.revision;
248 d->m_typeId = type.typeId;
249 d->m_listId = type.listId;
250 d->m_allocationSize = type.objectSize;
251 d->m_newFunc = type.create;
252 d->m_noCreationReason = type.noCreationReason;
253 d->m_baseMetaObject = type.metaObject;
254 d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
255 d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
256 if (d->m_attachedPropertiesType) {
257 QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
258 if (iter == d->m_attachedPropertyIds.end())
259 iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
260 d->m_attachedPropertiesId = *iter;
262 d->m_attachedPropertiesId = -1;
264 d->m_parserStatusCast = type.parserStatusCast;
265 d->m_propertyValueSourceCast = type.valueSourceCast;
266 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
267 d->m_extFunc = type.extensionObjectCreate;
269 d->m_customParser = type.customParser;
271 if (type.extensionMetaObject)
272 d->m_extMetaObject = type.extensionMetaObject;
275 QQmlType::~QQmlType()
277 delete d->m_customParser;
281 const QHashedString &QQmlType::module() const
286 int QQmlType::majorVersion() const
288 return d->m_version_maj;
291 int QQmlType::minorVersion() const
293 return d->m_version_min;
296 bool QQmlType::availableInVersion(int vmajor, int vminor) const
298 Q_ASSERT(vmajor >= 0 && vminor >= 0);
299 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
302 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
304 Q_ASSERT(vmajor >= 0 && vminor >= 0);
305 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
308 // returns the nearest _registered_ super class
309 QQmlType *QQmlType::superType() const
311 if (!d->m_haveSuperType) {
312 const QMetaObject *mo = d->m_baseMetaObject->superClass();
313 while (mo && !d->m_superType) {
314 d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
315 mo = mo->superClass();
317 d->m_haveSuperType = true;
320 return d->m_superType;
323 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
324 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
327 builder.setClassName(ignoreEnd->className());
330 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
331 QMetaClassInfo info = mo->classInfo(ii);
333 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
334 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
337 builder.addClassInfo(info.name(), info.value());
342 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
343 QMetaProperty property = mo->property(ii);
345 int otherIndex = ignoreEnd->indexOfProperty(property.name());
346 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
347 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
350 builder.addProperty(property);
355 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
356 QMetaMethod method = mo->method(ii);
358 // More complex - need to search name
359 QByteArray name = method.name();
364 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
365 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
368 QMetaMethod other = ignoreEnd->method(ii);
370 found = name == other.name();
373 QMetaMethodBuilder m = builder.addMethod(method);
375 m.setAccess(QMetaMethod::Private);
379 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
380 QMetaEnum enumerator = mo->enumerator(ii);
382 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
383 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
386 builder.addEnumerator(enumerator);
391 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
394 i -= mo->propertyOffset();
395 if (i < 0 && mo->d.superdata)
396 return isPropertyRevisioned(mo->d.superdata, index);
398 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
399 if (i >= 0 && i < mop->propertyCount) {
400 int handle = mop->propertyData + 3*i;
401 int flags = mo->d.data[handle + 2];
403 return (flags & Revisioned);
409 void QQmlTypePrivate::init() const
411 if (m_isSetup) return;
413 QWriteLocker lock(metaTypeDataLock());
417 // Setup extended meta object
418 // XXX - very inefficient
419 const QMetaObject *mo = m_baseMetaObject;
421 QMetaObjectBuilder builder;
422 clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
423 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
424 QMetaObject *mmo = builder.toMetaObject();
425 mmo->d.superdata = mo;
426 QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
427 m_metaObjects << data;
430 mo = mo->d.superdata;
432 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
434 if (t->d->m_extFunc) {
435 QMetaObjectBuilder builder;
436 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
437 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
438 QMetaObject *mmo = builder.toMetaObject();
439 mmo->d.superdata = m_baseMetaObject;
440 if (!m_metaObjects.isEmpty())
441 m_metaObjects.last().metaObject->d.superdata = mmo;
442 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
443 m_metaObjects << data;
446 mo = mo->d.superdata;
449 for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
450 m_metaObjects[ii].propertyOffset =
451 m_metaObjects.at(ii).metaObject->propertyOffset();
452 m_metaObjects[ii].methodOffset =
453 m_metaObjects.at(ii).metaObject->methodOffset();
456 // Check for revisioned details
458 const QMetaObject *mo = 0;
459 if (m_metaObjects.isEmpty())
460 mo = m_baseMetaObject;
462 mo = m_metaObjects.first().metaObject;
464 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
465 if (isPropertyRevisioned(mo, ii))
466 m_containsRevisionedAttributes = true;
469 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
470 if (mo->method(ii).revision() != 0)
471 m_containsRevisionedAttributes = true;
479 void QQmlTypePrivate::initEnums() const
481 if (m_isEnumSetup) return;
485 QWriteLocker lock(metaTypeDataLock());
486 if (m_isEnumSetup) return;
488 const QMetaObject *metaObject = m_baseMetaObject;
489 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
491 QMetaEnum e = metaObject->enumerator(ii);
493 for (int jj = 0; jj < e.keyCount(); ++jj)
494 m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
497 m_isEnumSetup = true;
500 QByteArray QQmlType::typeName() const
502 if (d->m_baseMetaObject)
503 return d->m_baseMetaObject->className();
508 const QString &QQmlType::elementName() const
510 return d->m_elementName;
513 const QString &QQmlType::qmlTypeName() const
515 if (d->m_name.isEmpty()) {
516 if (!d->m_module.isEmpty())
517 d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
519 d->m_name = d->m_elementName;
525 QObject *QQmlType::create() const
529 QObject *rv = (QObject *)operator new(d->m_allocationSize);
532 if (rv && !d->m_metaObjects.isEmpty())
533 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
538 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
542 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
545 if (rv && !d->m_metaObjects.isEmpty())
546 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
549 *memory = ((char *)rv) + d->m_allocationSize;
552 QQmlCustomParser *QQmlType::customParser() const
554 return d->m_customParser;
557 QQmlType::CreateFunc QQmlType::createFunction() const
562 QString QQmlType::noCreationReason() const
564 return d->m_noCreationReason;
567 int QQmlType::createSize() const
569 return d->m_allocationSize;
572 bool QQmlType::isCreatable() const
574 return d->m_newFunc != 0;
577 bool QQmlType::isExtendedType() const
581 return !d->m_metaObjects.isEmpty();
584 bool QQmlType::isInterface() const
586 return d->m_isInterface;
589 int QQmlType::typeId() const
594 int QQmlType::qListTypeId() const
599 const QMetaObject *QQmlType::metaObject() const
603 if (d->m_metaObjects.isEmpty())
604 return d->m_baseMetaObject;
606 return d->m_metaObjects.first().metaObject;
610 const QMetaObject *QQmlType::baseMetaObject() const
612 return d->m_baseMetaObject;
615 bool QQmlType::containsRevisionedAttributes() const
619 return d->m_containsRevisionedAttributes;
622 int QQmlType::metaObjectRevision() const
624 return d->m_revision;
627 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
629 return d->m_attachedPropertiesFunc;
632 const QMetaObject *QQmlType::attachedPropertiesType() const
634 return d->m_attachedPropertiesType;
638 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
639 for the case that a single class is registered under two or more names (eg. Item in
640 Qt 4.7 and QtQuick 1.0).
642 int QQmlType::attachedPropertiesId() const
644 return d->m_attachedPropertiesId;
647 int QQmlType::parserStatusCast() const
649 return d->m_parserStatusCast;
652 int QQmlType::propertyValueSourceCast() const
654 return d->m_propertyValueSourceCast;
657 int QQmlType::propertyValueInterceptorCast() const
659 return d->m_propertyValueInterceptorCast;
662 const char *QQmlType::interfaceIId() const
667 int QQmlType::index() const
672 int QQmlType::enumValue(const QHashedStringRef &name) const
676 int *rv = d->m_enums.value(name);
680 int QQmlType::enumValue(const QHashedV8String &name) const
684 int *rv = d->m_enums.value(name);
688 QQmlTypeModule::QQmlTypeModule()
689 : d(new QQmlTypeModulePrivate)
693 QQmlTypeModule::~QQmlTypeModule()
698 QString QQmlTypeModule::module() const
703 int QQmlTypeModule::majorVersion() const
705 return d->uri.majorVersion;
708 int QQmlTypeModule::minimumMinorVersion() const
710 return d->minMinorVersion;
713 int QQmlTypeModule::maximumMinorVersion() const
715 return d->maxMinorVersion;
718 void QQmlTypeModulePrivate::add(QQmlType *type)
720 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
721 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
723 QList<QQmlType *> &list = typeHash[type->elementName()];
724 for (int ii = 0; ii < list.count(); ++ii) {
725 if (list.at(ii)->minorVersion() < type->minorVersion()) {
726 list.insert(ii, type);
733 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
735 QReadLocker lock(metaTypeDataLock());
737 QList<QQmlType *> *types = d->typeHash.value(name);
738 if (!types) return 0;
740 for (int ii = 0; ii < types->count(); ++ii)
741 if (types->at(ii)->minorVersion() <= minor)
742 return types->at(ii);
747 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
749 QReadLocker lock(metaTypeDataLock());
751 QList<QQmlType *> *types = d->typeHash.value(name);
752 if (!types) return 0;
754 for (int ii = 0; ii < types->count(); ++ii)
755 if (types->at(ii)->minorVersion() <= minor)
756 return types->at(ii);
762 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
763 : m_module(0), m_minor(0)
767 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
768 : m_module(module), m_minor(minor)
771 Q_ASSERT(m_minor >= 0);
774 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
775 : m_module(o.m_module), m_minor(o.m_minor)
779 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
781 m_module = o.m_module;
786 QQmlTypeModule *QQmlTypeModuleVersion::module() const
791 int QQmlTypeModuleVersion::minorVersion() const
796 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
798 if (m_module) return m_module->type(name, m_minor);
802 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
804 if (m_module) return m_module->type(name, m_minor);
809 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
811 QWriteLocker lock(metaTypeDataLock());
812 QQmlMetaTypeData *data = metaTypeData();
814 data->parentFunctions.append(autoparent.function);
816 return data->parentFunctions.count() - 1;
819 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
821 if (interface.version > 0)
822 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
824 QWriteLocker lock(metaTypeDataLock());
825 QQmlMetaTypeData *data = metaTypeData();
827 int index = data->types.count();
829 QQmlType *type = new QQmlType(index, interface);
831 data->types.append(type);
832 data->idToType.insert(type->typeId(), type);
833 data->idToType.insert(type->qListTypeId(), type);
834 // XXX No insertMulti, so no multi-version interfaces?
835 if (!type->elementName().isEmpty())
836 data->nameToType.insert(type->elementName(), type);
838 if (data->interfaces.size() <= interface.typeId)
839 data->interfaces.resize(interface.typeId + 16);
840 if (data->lists.size() <= interface.listId)
841 data->lists.resize(interface.listId + 16);
842 data->interfaces.setBit(interface.typeId, true);
843 data->lists.setBit(interface.listId, true);
848 int registerType(const QQmlPrivate::RegisterType &type)
850 if (type.elementName) {
851 for (int ii = 0; type.elementName[ii]; ++ii) {
852 if (!isalnum(type.elementName[ii])) {
853 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
859 QWriteLocker lock(metaTypeDataLock());
860 QQmlMetaTypeData *data = metaTypeData();
861 int index = data->types.count();
863 QQmlType *dtype = new QQmlType(index, type);
865 data->types.append(dtype);
866 data->idToType.insert(dtype->typeId(), dtype);
867 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
869 if (!dtype->elementName().isEmpty())
870 data->nameToType.insertMulti(dtype->elementName(), dtype);
872 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
874 if (data->objects.size() <= type.typeId)
875 data->objects.resize(type.typeId + 16);
876 if (data->lists.size() <= type.listId)
877 data->lists.resize(type.listId + 16);
878 data->objects.setBit(type.typeId, true);
879 if (type.listId) data->lists.setBit(type.listId, true);
881 if (!dtype->module().isEmpty()) {
882 const QHashedString &mod = dtype->module();
884 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
885 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
887 module = new QQmlTypeModule;
888 module->d->uri = versionedUri;
889 data->uriToModule.insert(versionedUri, module);
891 module->d->add(dtype);
897 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
899 QWriteLocker lock(metaTypeDataLock());
901 QQmlMetaTypeData *data = metaTypeData();
902 QString uri = QString::fromUtf8(api.uri);
903 QQmlMetaType::ModuleApi import;
904 import.major = api.versionMajor;
905 import.minor = api.versionMinor;
906 import.script = api.scriptApi;
907 import.qobject = api.qobjectApi;
908 import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
910 if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO.
911 qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!";
913 int index = data->moduleApiCount++;
915 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
917 QQmlMetaTypeData::ModuleApiList apis;
918 apis.moduleApis << import;
919 data->moduleApis.insert(uri, apis);
921 apiList->moduleApis << import;
922 apiList->sorted = false;
930 This method is "over generalized" to allow us to (potentially) register more types of things in
931 the future without adding exported symbols.
933 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
935 if (type == TypeRegistration) {
936 return registerType(*reinterpret_cast<RegisterType *>(data));
937 } else if (type == InterfaceRegistration) {
938 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
939 } else if (type == AutoParentRegistration) {
940 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
941 } else if (type == ModuleApiRegistration) {
942 return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
948 Returns true if a module \a uri of any version is installed.
950 bool QQmlMetaType::isAnyModule(const QString &uri)
952 QReadLocker lock(metaTypeDataLock());
953 QQmlMetaTypeData *data = metaTypeData();
955 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
956 iter != data->uriToModule.end(); ++iter) {
957 if ((*iter)->module() == uri)
965 Returns true if any type or API has been registered for the given \a module with at least
966 versionMajor.versionMinor, or if types have been registered for \a module with at most
967 versionMajor.versionMinor.
969 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.
971 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
973 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
974 QReadLocker lock(metaTypeDataLock());
976 QQmlMetaTypeData *data = metaTypeData();
978 // first, check Types
980 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
981 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
984 // then, check ModuleApis
985 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
987 foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
988 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
996 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
998 QReadLocker lock(metaTypeDataLock());
999 QQmlMetaTypeData *data = metaTypeData();
1000 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1003 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1005 QReadLocker lock(metaTypeDataLock());
1006 QQmlMetaTypeData *data = metaTypeData();
1007 return data->parentFunctions;
1010 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1012 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1015 QQmlMetaType::ModuleApi
1016 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1018 QReadLocker lock(metaTypeDataLock());
1019 QQmlMetaTypeData *data = metaTypeData();
1021 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1025 if (apiList->sorted == false) {
1026 qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1027 apiList->sorted = true;
1030 for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1031 const ModuleApi &import = apiList->moduleApis.at(ii);
1032 if (import.major == versionMajor && import.minor <= versionMinor)
1039 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1041 QReadLocker lock(metaTypeDataLock());
1042 QQmlMetaTypeData *data = metaTypeData();
1044 QHash<QString, QList<ModuleApi> > moduleApis;
1045 QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1046 for (; it != data->moduleApis.end(); ++it)
1047 moduleApis[it.key()] = it.value().moduleApis;
1052 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1054 if (!isQObject(v.userType())) {
1055 if (ok) *ok = false;
1061 return *(QObject **)v.constData();
1064 bool QQmlMetaType::isQObject(int userType)
1066 if (userType == QMetaType::QObjectStar)
1069 QReadLocker lock(metaTypeDataLock());
1070 QQmlMetaTypeData *data = metaTypeData();
1071 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1075 Returns the item type for a list of type \a id.
1077 int QQmlMetaType::listType(int id)
1079 QReadLocker lock(metaTypeDataLock());
1080 QQmlMetaTypeData *data = metaTypeData();
1081 QQmlType *type = data->idToType.value(id);
1082 if (type && type->qListTypeId() == id)
1083 return type->typeId();
1088 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1090 QReadLocker lock(metaTypeDataLock());
1091 QQmlMetaTypeData *data = metaTypeData();
1093 QQmlType *type = data->metaObjectToType.value(mo);
1094 if (type && type->attachedPropertiesFunction())
1095 return type->attachedPropertiesId();
1100 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1104 QReadLocker lock(metaTypeDataLock());
1105 QQmlMetaTypeData *data = metaTypeData();
1106 return data->types.at(id)->attachedPropertiesFunction();
1109 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1111 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1113 return QMetaProperty();
1115 QMetaClassInfo info = metaObject->classInfo(idx);
1117 return QMetaProperty();
1119 idx = metaObject->indexOfProperty(info.value());
1121 return QMetaProperty();
1123 return metaObject->property(idx);
1126 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1129 return QMetaProperty();
1131 const QMetaObject *metaObject = obj->metaObject();
1132 return defaultProperty(metaObject);
1135 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1137 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1139 return QMetaMethod();
1141 QMetaClassInfo info = metaObject->classInfo(idx);
1143 return QMetaMethod();
1145 idx = metaObject->indexOfMethod(info.value());
1147 return QMetaMethod();
1149 return metaObject->method(idx);
1152 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1155 return QMetaMethod();
1157 const QMetaObject *metaObject = obj->metaObject();
1158 return defaultMethod(metaObject);
1161 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1165 if (userType == QMetaType::QObjectStar)
1168 QReadLocker lock(metaTypeDataLock());
1169 QQmlMetaTypeData *data = metaTypeData();
1170 if (userType < data->objects.size() && data->objects.testBit(userType))
1172 else if (userType < data->lists.size() && data->lists.testBit(userType))
1178 bool QQmlMetaType::isInterface(int userType)
1180 QReadLocker lock(metaTypeDataLock());
1181 QQmlMetaTypeData *data = metaTypeData();
1182 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1185 const char *QQmlMetaType::interfaceIId(int userType)
1187 QReadLocker lock(metaTypeDataLock());
1188 QQmlMetaTypeData *data = metaTypeData();
1189 QQmlType *type = data->idToType.value(userType);
1191 if (type && type->isInterface() && type->typeId() == userType)
1192 return type->interfaceIId();
1197 bool QQmlMetaType::isList(int userType)
1199 QReadLocker lock(metaTypeDataLock());
1200 QQmlMetaTypeData *data = metaTypeData();
1201 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1205 A custom string convertor allows you to specify a function pointer that
1206 returns a variant of \a type. For example, if you have written your own icon
1207 class that you want to support as an object property assignable in QML:
1210 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1211 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1214 The function pointer must be of the form:
1216 QVariant (*StringConverter)(const QString &);
1219 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1221 QWriteLocker lock(metaTypeDataLock());
1223 QQmlMetaTypeData *data = metaTypeData();
1224 if (data->stringConverters.contains(type))
1226 data->stringConverters.insert(type, converter);
1230 Return the custom string converter for \a type, previously installed through
1231 registerCustomStringConverter()
1233 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1235 QReadLocker lock(metaTypeDataLock());
1237 QQmlMetaTypeData *data = metaTypeData();
1238 return data->stringConverters.value(type);
1242 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1243 by \a version_major and \a version_minor.
1245 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1247 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1251 QHashedStringRef module(qualifiedName.constData(), slash);
1252 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1254 return qmlType(name, module, version_major, version_minor);
1258 Returns the type (if any) of \a name in \a module and version specified
1259 by \a version_major and \a version_minor.
1261 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1263 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1264 QReadLocker lock(metaTypeDataLock());
1265 QQmlMetaTypeData *data = metaTypeData();
1267 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1268 while (it != data->nameToType.end() && it.key() == name) {
1269 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1270 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1279 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1282 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1284 QReadLocker lock(metaTypeDataLock());
1285 QQmlMetaTypeData *data = metaTypeData();
1287 return data->metaObjectToType.value(metaObject);
1291 Returns the type (if any) that corresponds to the \a metaObject in version specified
1292 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1295 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1297 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1298 QReadLocker lock(metaTypeDataLock());
1299 QQmlMetaTypeData *data = metaTypeData();
1301 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1302 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1304 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1313 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1314 Returns null if no type is registered.
1316 QQmlType *QQmlMetaType::qmlType(int userType)
1318 QReadLocker lock(metaTypeDataLock());
1319 QQmlMetaTypeData *data = metaTypeData();
1321 QQmlType *type = data->idToType.value(userType);
1322 if (type && type->typeId() == userType)
1329 Returns the list of registered QML type names.
1331 QList<QString> QQmlMetaType::qmlTypeNames()
1333 QReadLocker lock(metaTypeDataLock());
1334 QQmlMetaTypeData *data = metaTypeData();
1336 QList<QString> names;
1337 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1338 while (it != data->nameToType.end()) {
1339 names += (*it)->qmlTypeName();
1347 Returns the list of registered QML types.
1349 QList<QQmlType*> QQmlMetaType::qmlTypes()
1351 QReadLocker lock(metaTypeDataLock());
1352 QQmlMetaTypeData *data = metaTypeData();
1354 return data->nameToType.values();
1357 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1361 id = QMetaType::type("QQuickAnchorLine");
1366 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1368 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1370 anchorLineCompareFunction = fun;
1373 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1375 Q_ASSERT(anchorLineCompareFunction != 0);
1376 return anchorLineCompareFunction(p1, p2);