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 // Separate plugins may have different strings at the same address
204 QHashedCStringRef currentModule(module, ::strlen(module));
205 if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
206 lastModuleStr = QString::fromUtf8(module);
207 lastModuleStr.hash();
211 return lastModuleStr;
214 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
216 QQmlTypePrivate::QQmlTypePrivate()
217 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
218 m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
219 m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
220 m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
221 m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
226 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
227 : d(new QQmlTypePrivate)
229 d->m_isInterface = true;
230 d->m_iid = interface.iid;
231 d->m_typeId = interface.typeId;
232 d->m_listId = interface.listId;
236 d->m_version_maj = 0;
237 d->m_version_min = 0;
240 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
241 : d(new QQmlTypePrivate)
243 d->m_module = moduletoUtf8(type.uri);
244 d->m_elementName = QString::fromUtf8(type.elementName);
246 d->m_version_maj = type.versionMajor;
247 d->m_version_min = type.versionMinor;
248 if (type.version >= 1) // revisions added in version 1
249 d->m_revision = type.revision;
250 d->m_typeId = type.typeId;
251 d->m_listId = type.listId;
252 d->m_allocationSize = type.objectSize;
253 d->m_newFunc = type.create;
254 d->m_noCreationReason = type.noCreationReason;
255 d->m_baseMetaObject = type.metaObject;
256 d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
257 d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
258 if (d->m_attachedPropertiesType) {
259 QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
260 if (iter == d->m_attachedPropertyIds.end())
261 iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
262 d->m_attachedPropertiesId = *iter;
264 d->m_attachedPropertiesId = -1;
266 d->m_parserStatusCast = type.parserStatusCast;
267 d->m_propertyValueSourceCast = type.valueSourceCast;
268 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
269 d->m_extFunc = type.extensionObjectCreate;
271 d->m_customParser = type.customParser;
273 if (type.extensionMetaObject)
274 d->m_extMetaObject = type.extensionMetaObject;
277 QQmlType::~QQmlType()
279 delete d->m_customParser;
283 const QHashedString &QQmlType::module() const
288 int QQmlType::majorVersion() const
290 return d->m_version_maj;
293 int QQmlType::minorVersion() const
295 return d->m_version_min;
298 bool QQmlType::availableInVersion(int vmajor, int vminor) const
300 Q_ASSERT(vmajor >= 0 && vminor >= 0);
301 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
304 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
306 Q_ASSERT(vmajor >= 0 && vminor >= 0);
307 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
310 // returns the nearest _registered_ super class
311 QQmlType *QQmlType::superType() const
313 if (!d->m_haveSuperType) {
314 const QMetaObject *mo = d->m_baseMetaObject->superClass();
315 while (mo && !d->m_superType) {
316 d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
317 mo = mo->superClass();
319 d->m_haveSuperType = true;
322 return d->m_superType;
325 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
326 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
329 builder.setClassName(ignoreEnd->className());
332 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
333 QMetaClassInfo info = mo->classInfo(ii);
335 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
336 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
339 builder.addClassInfo(info.name(), info.value());
344 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
345 QMetaProperty property = mo->property(ii);
347 int otherIndex = ignoreEnd->indexOfProperty(property.name());
348 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
349 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
352 builder.addProperty(property);
357 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
358 QMetaMethod method = mo->method(ii);
360 // More complex - need to search name
361 QByteArray name = method.name();
366 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
367 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
370 QMetaMethod other = ignoreEnd->method(ii);
372 found = name == other.name();
375 QMetaMethodBuilder m = builder.addMethod(method);
377 m.setAccess(QMetaMethod::Private);
381 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
382 QMetaEnum enumerator = mo->enumerator(ii);
384 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
385 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
388 builder.addEnumerator(enumerator);
393 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
396 i -= mo->propertyOffset();
397 if (i < 0 && mo->d.superdata)
398 return isPropertyRevisioned(mo->d.superdata, index);
400 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
401 if (i >= 0 && i < mop->propertyCount) {
402 int handle = mop->propertyData + 3*i;
403 int flags = mo->d.data[handle + 2];
405 return (flags & Revisioned);
411 void QQmlTypePrivate::init() const
413 if (m_isSetup) return;
415 QWriteLocker lock(metaTypeDataLock());
419 // Setup extended meta object
420 // XXX - very inefficient
421 const QMetaObject *mo = m_baseMetaObject;
423 QMetaObjectBuilder builder;
424 clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
425 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
426 QMetaObject *mmo = builder.toMetaObject();
427 mmo->d.superdata = mo;
428 QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
429 m_metaObjects << data;
432 mo = mo->d.superdata;
434 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
436 if (t->d->m_extFunc) {
437 QMetaObjectBuilder builder;
438 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
439 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
440 QMetaObject *mmo = builder.toMetaObject();
441 mmo->d.superdata = m_baseMetaObject;
442 if (!m_metaObjects.isEmpty())
443 m_metaObjects.last().metaObject->d.superdata = mmo;
444 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
445 m_metaObjects << data;
448 mo = mo->d.superdata;
451 for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
452 m_metaObjects[ii].propertyOffset =
453 m_metaObjects.at(ii).metaObject->propertyOffset();
454 m_metaObjects[ii].methodOffset =
455 m_metaObjects.at(ii).metaObject->methodOffset();
458 // Check for revisioned details
460 const QMetaObject *mo = 0;
461 if (m_metaObjects.isEmpty())
462 mo = m_baseMetaObject;
464 mo = m_metaObjects.first().metaObject;
466 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
467 if (isPropertyRevisioned(mo, ii))
468 m_containsRevisionedAttributes = true;
471 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
472 if (mo->method(ii).revision() != 0)
473 m_containsRevisionedAttributes = true;
481 void QQmlTypePrivate::initEnums() const
483 if (m_isEnumSetup) return;
487 QWriteLocker lock(metaTypeDataLock());
488 if (m_isEnumSetup) return;
490 const QMetaObject *metaObject = m_baseMetaObject;
491 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
493 QMetaEnum e = metaObject->enumerator(ii);
495 for (int jj = 0; jj < e.keyCount(); ++jj)
496 m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
499 m_isEnumSetup = true;
502 QByteArray QQmlType::typeName() const
504 if (d->m_baseMetaObject)
505 return d->m_baseMetaObject->className();
510 const QString &QQmlType::elementName() const
512 return d->m_elementName;
515 const QString &QQmlType::qmlTypeName() const
517 if (d->m_name.isEmpty()) {
518 if (!d->m_module.isEmpty())
519 d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
521 d->m_name = d->m_elementName;
527 QObject *QQmlType::create() const
531 QObject *rv = (QObject *)operator new(d->m_allocationSize);
534 if (rv && !d->m_metaObjects.isEmpty())
535 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
540 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
544 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
547 if (rv && !d->m_metaObjects.isEmpty())
548 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
551 *memory = ((char *)rv) + d->m_allocationSize;
554 QQmlCustomParser *QQmlType::customParser() const
556 return d->m_customParser;
559 QQmlType::CreateFunc QQmlType::createFunction() const
564 QString QQmlType::noCreationReason() const
566 return d->m_noCreationReason;
569 int QQmlType::createSize() const
571 return d->m_allocationSize;
574 bool QQmlType::isCreatable() const
576 return d->m_newFunc != 0;
579 bool QQmlType::isExtendedType() const
583 return !d->m_metaObjects.isEmpty();
586 bool QQmlType::isInterface() const
588 return d->m_isInterface;
591 int QQmlType::typeId() const
596 int QQmlType::qListTypeId() const
601 const QMetaObject *QQmlType::metaObject() const
605 if (d->m_metaObjects.isEmpty())
606 return d->m_baseMetaObject;
608 return d->m_metaObjects.first().metaObject;
612 const QMetaObject *QQmlType::baseMetaObject() const
614 return d->m_baseMetaObject;
617 bool QQmlType::containsRevisionedAttributes() const
621 return d->m_containsRevisionedAttributes;
624 int QQmlType::metaObjectRevision() const
626 return d->m_revision;
629 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
631 return d->m_attachedPropertiesFunc;
634 const QMetaObject *QQmlType::attachedPropertiesType() const
636 return d->m_attachedPropertiesType;
640 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
641 for the case that a single class is registered under two or more names (eg. Item in
642 Qt 4.7 and QtQuick 1.0).
644 int QQmlType::attachedPropertiesId() const
646 return d->m_attachedPropertiesId;
649 int QQmlType::parserStatusCast() const
651 return d->m_parserStatusCast;
654 int QQmlType::propertyValueSourceCast() const
656 return d->m_propertyValueSourceCast;
659 int QQmlType::propertyValueInterceptorCast() const
661 return d->m_propertyValueInterceptorCast;
664 const char *QQmlType::interfaceIId() const
669 int QQmlType::index() const
674 int QQmlType::enumValue(const QHashedStringRef &name) const
678 int *rv = d->m_enums.value(name);
682 int QQmlType::enumValue(const QHashedV8String &name) const
686 int *rv = d->m_enums.value(name);
690 QQmlTypeModule::QQmlTypeModule()
691 : d(new QQmlTypeModulePrivate)
695 QQmlTypeModule::~QQmlTypeModule()
700 QString QQmlTypeModule::module() const
705 int QQmlTypeModule::majorVersion() const
707 return d->uri.majorVersion;
710 int QQmlTypeModule::minimumMinorVersion() const
712 return d->minMinorVersion;
715 int QQmlTypeModule::maximumMinorVersion() const
717 return d->maxMinorVersion;
720 void QQmlTypeModulePrivate::add(QQmlType *type)
722 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
723 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
725 QList<QQmlType *> &list = typeHash[type->elementName()];
726 for (int ii = 0; ii < list.count(); ++ii) {
727 if (list.at(ii)->minorVersion() < type->minorVersion()) {
728 list.insert(ii, type);
735 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
737 QReadLocker lock(metaTypeDataLock());
739 QList<QQmlType *> *types = d->typeHash.value(name);
740 if (!types) return 0;
742 for (int ii = 0; ii < types->count(); ++ii)
743 if (types->at(ii)->minorVersion() <= minor)
744 return types->at(ii);
749 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
751 QReadLocker lock(metaTypeDataLock());
753 QList<QQmlType *> *types = d->typeHash.value(name);
754 if (!types) return 0;
756 for (int ii = 0; ii < types->count(); ++ii)
757 if (types->at(ii)->minorVersion() <= minor)
758 return types->at(ii);
764 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
765 : m_module(0), m_minor(0)
769 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
770 : m_module(module), m_minor(minor)
773 Q_ASSERT(m_minor >= 0);
776 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
777 : m_module(o.m_module), m_minor(o.m_minor)
781 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
783 m_module = o.m_module;
788 QQmlTypeModule *QQmlTypeModuleVersion::module() const
793 int QQmlTypeModuleVersion::minorVersion() const
798 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
800 if (m_module) return m_module->type(name, m_minor);
804 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
806 if (m_module) return m_module->type(name, m_minor);
811 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
813 QWriteLocker lock(metaTypeDataLock());
814 QQmlMetaTypeData *data = metaTypeData();
816 data->parentFunctions.append(autoparent.function);
818 return data->parentFunctions.count() - 1;
821 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
823 if (interface.version > 0)
824 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
826 QWriteLocker lock(metaTypeDataLock());
827 QQmlMetaTypeData *data = metaTypeData();
829 int index = data->types.count();
831 QQmlType *type = new QQmlType(index, interface);
833 data->types.append(type);
834 data->idToType.insert(type->typeId(), type);
835 data->idToType.insert(type->qListTypeId(), type);
836 // XXX No insertMulti, so no multi-version interfaces?
837 if (!type->elementName().isEmpty())
838 data->nameToType.insert(type->elementName(), type);
840 if (data->interfaces.size() <= interface.typeId)
841 data->interfaces.resize(interface.typeId + 16);
842 if (data->lists.size() <= interface.listId)
843 data->lists.resize(interface.listId + 16);
844 data->interfaces.setBit(interface.typeId, true);
845 data->lists.setBit(interface.listId, true);
850 int registerType(const QQmlPrivate::RegisterType &type)
852 if (type.elementName) {
853 for (int ii = 0; type.elementName[ii]; ++ii) {
854 if (!isalnum(type.elementName[ii])) {
855 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
861 QWriteLocker lock(metaTypeDataLock());
862 QQmlMetaTypeData *data = metaTypeData();
863 int index = data->types.count();
865 QQmlType *dtype = new QQmlType(index, type);
867 data->types.append(dtype);
868 data->idToType.insert(dtype->typeId(), dtype);
869 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
871 if (!dtype->elementName().isEmpty())
872 data->nameToType.insertMulti(dtype->elementName(), dtype);
874 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
876 if (data->objects.size() <= type.typeId)
877 data->objects.resize(type.typeId + 16);
878 if (data->lists.size() <= type.listId)
879 data->lists.resize(type.listId + 16);
880 data->objects.setBit(type.typeId, true);
881 if (type.listId) data->lists.setBit(type.listId, true);
883 if (!dtype->module().isEmpty()) {
884 const QHashedString &mod = dtype->module();
886 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
887 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
889 module = new QQmlTypeModule;
890 module->d->uri = versionedUri;
891 data->uriToModule.insert(versionedUri, module);
893 module->d->add(dtype);
899 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
901 QWriteLocker lock(metaTypeDataLock());
903 QQmlMetaTypeData *data = metaTypeData();
904 QString uri = QString::fromUtf8(api.uri);
905 QQmlMetaType::ModuleApi import;
906 import.major = api.versionMajor;
907 import.minor = api.versionMinor;
908 import.script = api.scriptApi;
909 import.qobject = api.qobjectApi;
910 import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
912 int index = data->moduleApiCount++;
914 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
916 QQmlMetaTypeData::ModuleApiList apis;
917 apis.moduleApis << import;
918 data->moduleApis.insert(uri, apis);
920 apiList->moduleApis << import;
921 apiList->sorted = false;
929 This method is "over generalized" to allow us to (potentially) register more types of things in
930 the future without adding exported symbols.
932 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
934 if (type == TypeRegistration) {
935 return registerType(*reinterpret_cast<RegisterType *>(data));
936 } else if (type == InterfaceRegistration) {
937 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
938 } else if (type == AutoParentRegistration) {
939 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
940 } else if (type == ModuleApiRegistration) {
941 return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
947 Returns true if a module \a uri of any version is installed.
949 bool QQmlMetaType::isAnyModule(const QString &uri)
951 QReadLocker lock(metaTypeDataLock());
952 QQmlMetaTypeData *data = metaTypeData();
954 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
955 iter != data->uriToModule.end(); ++iter) {
956 if ((*iter)->module() == uri)
964 Returns true if any type or API has been registered for the given \a module with at least
965 versionMajor.versionMinor, or if types have been registered for \a module with at most
966 versionMajor.versionMinor.
968 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.
970 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
972 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
973 QReadLocker lock(metaTypeDataLock());
975 QQmlMetaTypeData *data = metaTypeData();
977 // first, check Types
979 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
980 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
983 // then, check ModuleApis
984 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
986 foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
987 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
995 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
997 QReadLocker lock(metaTypeDataLock());
998 QQmlMetaTypeData *data = metaTypeData();
999 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1002 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1004 QReadLocker lock(metaTypeDataLock());
1005 QQmlMetaTypeData *data = metaTypeData();
1006 return data->parentFunctions;
1009 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1011 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1014 QQmlMetaType::ModuleApi
1015 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1017 QReadLocker lock(metaTypeDataLock());
1018 QQmlMetaTypeData *data = metaTypeData();
1020 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1024 if (apiList->sorted == false) {
1025 qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1026 apiList->sorted = true;
1029 for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1030 const ModuleApi &import = apiList->moduleApis.at(ii);
1031 if (import.major == versionMajor && import.minor <= versionMinor)
1038 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1040 QReadLocker lock(metaTypeDataLock());
1041 QQmlMetaTypeData *data = metaTypeData();
1043 QHash<QString, QList<ModuleApi> > moduleApis;
1044 QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1045 for (; it != data->moduleApis.end(); ++it)
1046 moduleApis[it.key()] = it.value().moduleApis;
1051 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1053 if (!isQObject(v.userType())) {
1054 if (ok) *ok = false;
1060 return *(QObject **)v.constData();
1063 bool QQmlMetaType::isQObject(int userType)
1065 if (userType == QMetaType::QObjectStar)
1068 QReadLocker lock(metaTypeDataLock());
1069 QQmlMetaTypeData *data = metaTypeData();
1070 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1074 Returns the item type for a list of type \a id.
1076 int QQmlMetaType::listType(int id)
1078 QReadLocker lock(metaTypeDataLock());
1079 QQmlMetaTypeData *data = metaTypeData();
1080 QQmlType *type = data->idToType.value(id);
1081 if (type && type->qListTypeId() == id)
1082 return type->typeId();
1087 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1089 QReadLocker lock(metaTypeDataLock());
1090 QQmlMetaTypeData *data = metaTypeData();
1092 QQmlType *type = data->metaObjectToType.value(mo);
1093 if (type && type->attachedPropertiesFunction())
1094 return type->attachedPropertiesId();
1099 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1103 QReadLocker lock(metaTypeDataLock());
1104 QQmlMetaTypeData *data = metaTypeData();
1105 return data->types.at(id)->attachedPropertiesFunction();
1108 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1110 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1112 return QMetaProperty();
1114 QMetaClassInfo info = metaObject->classInfo(idx);
1116 return QMetaProperty();
1118 idx = metaObject->indexOfProperty(info.value());
1120 return QMetaProperty();
1122 return metaObject->property(idx);
1125 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1128 return QMetaProperty();
1130 const QMetaObject *metaObject = obj->metaObject();
1131 return defaultProperty(metaObject);
1134 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1136 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1138 return QMetaMethod();
1140 QMetaClassInfo info = metaObject->classInfo(idx);
1142 return QMetaMethod();
1144 idx = metaObject->indexOfMethod(info.value());
1146 return QMetaMethod();
1148 return metaObject->method(idx);
1151 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1154 return QMetaMethod();
1156 const QMetaObject *metaObject = obj->metaObject();
1157 return defaultMethod(metaObject);
1160 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1164 if (userType == QMetaType::QObjectStar)
1167 QReadLocker lock(metaTypeDataLock());
1168 QQmlMetaTypeData *data = metaTypeData();
1169 if (userType < data->objects.size() && data->objects.testBit(userType))
1171 else if (userType < data->lists.size() && data->lists.testBit(userType))
1177 bool QQmlMetaType::isInterface(int userType)
1179 QReadLocker lock(metaTypeDataLock());
1180 QQmlMetaTypeData *data = metaTypeData();
1181 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1184 const char *QQmlMetaType::interfaceIId(int userType)
1186 QReadLocker lock(metaTypeDataLock());
1187 QQmlMetaTypeData *data = metaTypeData();
1188 QQmlType *type = data->idToType.value(userType);
1190 if (type && type->isInterface() && type->typeId() == userType)
1191 return type->interfaceIId();
1196 bool QQmlMetaType::isList(int userType)
1198 QReadLocker lock(metaTypeDataLock());
1199 QQmlMetaTypeData *data = metaTypeData();
1200 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1204 A custom string convertor allows you to specify a function pointer that
1205 returns a variant of \a type. For example, if you have written your own icon
1206 class that you want to support as an object property assignable in QML:
1209 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1210 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1213 The function pointer must be of the form:
1215 QVariant (*StringConverter)(const QString &);
1218 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1220 QWriteLocker lock(metaTypeDataLock());
1222 QQmlMetaTypeData *data = metaTypeData();
1223 if (data->stringConverters.contains(type))
1225 data->stringConverters.insert(type, converter);
1229 Return the custom string converter for \a type, previously installed through
1230 registerCustomStringConverter()
1232 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1234 QReadLocker lock(metaTypeDataLock());
1236 QQmlMetaTypeData *data = metaTypeData();
1237 return data->stringConverters.value(type);
1241 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1242 by \a version_major and \a version_minor.
1244 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1246 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1250 QHashedStringRef module(qualifiedName.constData(), slash);
1251 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1253 return qmlType(name, module, version_major, version_minor);
1257 Returns the type (if any) of \a name in \a module and version specified
1258 by \a version_major and \a version_minor.
1260 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1262 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1263 QReadLocker lock(metaTypeDataLock());
1264 QQmlMetaTypeData *data = metaTypeData();
1266 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1267 while (it != data->nameToType.end() && it.key() == name) {
1268 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1269 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1278 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1281 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1283 QReadLocker lock(metaTypeDataLock());
1284 QQmlMetaTypeData *data = metaTypeData();
1286 return data->metaObjectToType.value(metaObject);
1290 Returns the type (if any) that corresponds to the \a metaObject in version specified
1291 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1294 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1296 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1297 QReadLocker lock(metaTypeDataLock());
1298 QQmlMetaTypeData *data = metaTypeData();
1300 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1301 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1303 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1312 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1313 Returns null if no type is registered.
1315 QQmlType *QQmlMetaType::qmlType(int userType)
1317 QReadLocker lock(metaTypeDataLock());
1318 QQmlMetaTypeData *data = metaTypeData();
1320 QQmlType *type = data->idToType.value(userType);
1321 if (type && type->typeId() == userType)
1328 Returns the list of registered QML type names.
1330 QList<QString> QQmlMetaType::qmlTypeNames()
1332 QReadLocker lock(metaTypeDataLock());
1333 QQmlMetaTypeData *data = metaTypeData();
1335 QList<QString> names;
1336 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1337 while (it != data->nameToType.end()) {
1338 names += (*it)->qmlTypeName();
1346 Returns the list of registered QML types.
1348 QList<QQmlType*> QQmlMetaType::qmlTypes()
1350 QReadLocker lock(metaTypeDataLock());
1351 QQmlMetaTypeData *data = metaTypeData();
1353 return data->nameToType.values();
1356 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1360 id = QMetaType::type("QQuickAnchorLine");
1365 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1367 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1369 anchorLineCompareFunction = fun;
1372 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1374 Q_ASSERT(anchorLineCompareFunction != 0);
1375 return anchorLineCompareFunction(p1, p2);