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 if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO.
913 qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!";
915 int index = data->moduleApiCount++;
917 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
919 QQmlMetaTypeData::ModuleApiList apis;
920 apis.moduleApis << import;
921 data->moduleApis.insert(uri, apis);
923 apiList->moduleApis << import;
924 apiList->sorted = false;
932 This method is "over generalized" to allow us to (potentially) register more types of things in
933 the future without adding exported symbols.
935 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
937 if (type == TypeRegistration) {
938 return registerType(*reinterpret_cast<RegisterType *>(data));
939 } else if (type == InterfaceRegistration) {
940 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
941 } else if (type == AutoParentRegistration) {
942 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
943 } else if (type == ModuleApiRegistration) {
944 return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
950 Returns true if a module \a uri of any version is installed.
952 bool QQmlMetaType::isAnyModule(const QString &uri)
954 QReadLocker lock(metaTypeDataLock());
955 QQmlMetaTypeData *data = metaTypeData();
957 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
958 iter != data->uriToModule.end(); ++iter) {
959 if ((*iter)->module() == uri)
967 Returns true if any type or API has been registered for the given \a module with at least
968 versionMajor.versionMinor, or if types have been registered for \a module with at most
969 versionMajor.versionMinor.
971 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.
973 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
975 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
976 QReadLocker lock(metaTypeDataLock());
978 QQmlMetaTypeData *data = metaTypeData();
980 // first, check Types
982 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
983 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
986 // then, check ModuleApis
987 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
989 foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
990 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
998 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1000 QReadLocker lock(metaTypeDataLock());
1001 QQmlMetaTypeData *data = metaTypeData();
1002 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1005 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1007 QReadLocker lock(metaTypeDataLock());
1008 QQmlMetaTypeData *data = metaTypeData();
1009 return data->parentFunctions;
1012 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1014 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1017 QQmlMetaType::ModuleApi
1018 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1020 QReadLocker lock(metaTypeDataLock());
1021 QQmlMetaTypeData *data = metaTypeData();
1023 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1027 if (apiList->sorted == false) {
1028 qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1029 apiList->sorted = true;
1032 for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1033 const ModuleApi &import = apiList->moduleApis.at(ii);
1034 if (import.major == versionMajor && import.minor <= versionMinor)
1041 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1043 QReadLocker lock(metaTypeDataLock());
1044 QQmlMetaTypeData *data = metaTypeData();
1046 QHash<QString, QList<ModuleApi> > moduleApis;
1047 QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1048 for (; it != data->moduleApis.end(); ++it)
1049 moduleApis[it.key()] = it.value().moduleApis;
1054 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1056 if (!isQObject(v.userType())) {
1057 if (ok) *ok = false;
1063 return *(QObject **)v.constData();
1066 bool QQmlMetaType::isQObject(int userType)
1068 if (userType == QMetaType::QObjectStar)
1071 QReadLocker lock(metaTypeDataLock());
1072 QQmlMetaTypeData *data = metaTypeData();
1073 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1077 Returns the item type for a list of type \a id.
1079 int QQmlMetaType::listType(int id)
1081 QReadLocker lock(metaTypeDataLock());
1082 QQmlMetaTypeData *data = metaTypeData();
1083 QQmlType *type = data->idToType.value(id);
1084 if (type && type->qListTypeId() == id)
1085 return type->typeId();
1090 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1092 QReadLocker lock(metaTypeDataLock());
1093 QQmlMetaTypeData *data = metaTypeData();
1095 QQmlType *type = data->metaObjectToType.value(mo);
1096 if (type && type->attachedPropertiesFunction())
1097 return type->attachedPropertiesId();
1102 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1106 QReadLocker lock(metaTypeDataLock());
1107 QQmlMetaTypeData *data = metaTypeData();
1108 return data->types.at(id)->attachedPropertiesFunction();
1111 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1113 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1115 return QMetaProperty();
1117 QMetaClassInfo info = metaObject->classInfo(idx);
1119 return QMetaProperty();
1121 idx = metaObject->indexOfProperty(info.value());
1123 return QMetaProperty();
1125 return metaObject->property(idx);
1128 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1131 return QMetaProperty();
1133 const QMetaObject *metaObject = obj->metaObject();
1134 return defaultProperty(metaObject);
1137 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1139 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1141 return QMetaMethod();
1143 QMetaClassInfo info = metaObject->classInfo(idx);
1145 return QMetaMethod();
1147 idx = metaObject->indexOfMethod(info.value());
1149 return QMetaMethod();
1151 return metaObject->method(idx);
1154 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1157 return QMetaMethod();
1159 const QMetaObject *metaObject = obj->metaObject();
1160 return defaultMethod(metaObject);
1163 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1167 if (userType == QMetaType::QObjectStar)
1170 QReadLocker lock(metaTypeDataLock());
1171 QQmlMetaTypeData *data = metaTypeData();
1172 if (userType < data->objects.size() && data->objects.testBit(userType))
1174 else if (userType < data->lists.size() && data->lists.testBit(userType))
1180 bool QQmlMetaType::isInterface(int userType)
1182 QReadLocker lock(metaTypeDataLock());
1183 QQmlMetaTypeData *data = metaTypeData();
1184 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1187 const char *QQmlMetaType::interfaceIId(int userType)
1189 QReadLocker lock(metaTypeDataLock());
1190 QQmlMetaTypeData *data = metaTypeData();
1191 QQmlType *type = data->idToType.value(userType);
1193 if (type && type->isInterface() && type->typeId() == userType)
1194 return type->interfaceIId();
1199 bool QQmlMetaType::isList(int userType)
1201 QReadLocker lock(metaTypeDataLock());
1202 QQmlMetaTypeData *data = metaTypeData();
1203 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1207 A custom string convertor allows you to specify a function pointer that
1208 returns a variant of \a type. For example, if you have written your own icon
1209 class that you want to support as an object property assignable in QML:
1212 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1213 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1216 The function pointer must be of the form:
1218 QVariant (*StringConverter)(const QString &);
1221 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1223 QWriteLocker lock(metaTypeDataLock());
1225 QQmlMetaTypeData *data = metaTypeData();
1226 if (data->stringConverters.contains(type))
1228 data->stringConverters.insert(type, converter);
1232 Return the custom string converter for \a type, previously installed through
1233 registerCustomStringConverter()
1235 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1237 QReadLocker lock(metaTypeDataLock());
1239 QQmlMetaTypeData *data = metaTypeData();
1240 return data->stringConverters.value(type);
1244 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1245 by \a version_major and \a version_minor.
1247 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1249 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1253 QHashedStringRef module(qualifiedName.constData(), slash);
1254 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1256 return qmlType(name, module, version_major, version_minor);
1260 Returns the type (if any) of \a name in \a module and version specified
1261 by \a version_major and \a version_minor.
1263 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1265 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1266 QReadLocker lock(metaTypeDataLock());
1267 QQmlMetaTypeData *data = metaTypeData();
1269 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1270 while (it != data->nameToType.end() && it.key() == name) {
1271 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1272 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1281 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1284 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1286 QReadLocker lock(metaTypeDataLock());
1287 QQmlMetaTypeData *data = metaTypeData();
1289 return data->metaObjectToType.value(metaObject);
1293 Returns the type (if any) that corresponds to the \a metaObject in version specified
1294 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1297 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1299 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1300 QReadLocker lock(metaTypeDataLock());
1301 QQmlMetaTypeData *data = metaTypeData();
1303 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1304 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1306 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1315 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1316 Returns null if no type is registered.
1318 QQmlType *QQmlMetaType::qmlType(int userType)
1320 QReadLocker lock(metaTypeDataLock());
1321 QQmlMetaTypeData *data = metaTypeData();
1323 QQmlType *type = data->idToType.value(userType);
1324 if (type && type->typeId() == userType)
1331 Returns the list of registered QML type names.
1333 QList<QString> QQmlMetaType::qmlTypeNames()
1335 QReadLocker lock(metaTypeDataLock());
1336 QQmlMetaTypeData *data = metaTypeData();
1338 QList<QString> names;
1339 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1340 while (it != data->nameToType.end()) {
1341 names += (*it)->qmlTypeName();
1349 Returns the list of registered QML types.
1351 QList<QQmlType*> QQmlMetaType::qmlTypes()
1353 QReadLocker lock(metaTypeDataLock());
1354 QQmlMetaTypeData *data = metaTypeData();
1356 return data->nameToType.values();
1359 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1363 id = QMetaType::type("QQuickAnchorLine");
1368 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1370 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1372 anchorLineCompareFunction = fun;
1375 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1377 Q_ASSERT(anchorLineCompareFunction != 0);
1378 return anchorLineCompareFunction(p1, p2);