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 SingletonTypeList {
98 SingletonTypeList() : sorted(true) {}
99 QList<QQmlMetaType::SingletonType> singletonTypes;
102 typedef QStringHash<SingletonTypeList> SingletonTypes;
103 SingletonTypes singletonTypes;
104 int singletonTypeCount;
106 bool singletonTypeExists(const QString &uri, const QString &typeName, int major, int minor)
108 QQmlMetaTypeData::SingletonTypeList *apiList = singletonTypes.value(uri);
110 for (int i=0 ; i < apiList->singletonTypes.size() ; ++i) {
111 const QQmlMetaType::SingletonType &import = apiList->singletonTypes.at(i);
112 if (import.major == major && import.minor == minor && typeName == import.typeName)
120 bool typeExists(const QString &uri, const QString &typeName, int major, int minor)
122 QQmlMetaTypeData::VersionedUri versionedUri(uri, major);
123 QQmlTypeModule *module = uriToModule.value(versionedUri);
124 return module && module->typeNoLock(typeName, minor) != 0;
128 QBitArray interfaces;
131 QList<QQmlPrivate::AutoParentFunction> parentFunctions;
133 QSet<QString> protectedNamespaces;
135 QString typeRegistrationNamespace;
136 QStringList typeRegistrationFailures;
139 class QQmlTypeModulePrivate
142 QQmlTypeModulePrivate()
143 : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
145 QQmlMetaTypeData::VersionedUri uri;
150 void add(QQmlType *);
152 QStringHash<QList<QQmlType *> > typeHash;
153 QList<QQmlType *> types;
156 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
157 Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, metaTypeDataLock, (QReadWriteLock::Recursive))
159 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
161 return v.uri.hash() ^ qHash(v.majorVersion);
164 QQmlMetaTypeData::QQmlMetaTypeData()
165 : singletonTypeCount(0)
169 QQmlMetaTypeData::~QQmlMetaTypeData()
171 for (int i = 0; i < types.count(); ++i)
175 class QQmlTypePrivate
181 void initEnums() const;
182 void insertEnums(const QMetaObject *metaObject) const;
184 bool m_isInterface : 1;
186 QHashedString m_module;
188 QString m_elementName;
191 int m_typeId; int m_listId;
193 mutable bool m_containsRevisionedAttributes;
194 mutable QQmlType *m_superType;
196 int m_allocationSize;
197 void (*m_newFunc)(void *);
198 QString m_noCreationReason;
200 const QMetaObject *m_baseMetaObject;
201 QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
202 const QMetaObject *m_attachedPropertiesType;
203 int m_attachedPropertiesId;
204 int m_parserStatusCast;
205 int m_propertyValueSourceCast;
206 int m_propertyValueInterceptorCast;
207 QObject *(*m_extFunc)(QObject *);
208 const QMetaObject *m_extMetaObject;
210 QQmlCustomParser *m_customParser;
211 mutable volatile bool m_isSetup:1;
212 mutable volatile bool m_isEnumSetup:1;
213 mutable bool m_haveSuperType:1;
214 mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
215 mutable QStringHash<int> m_enums;
217 static QHash<const QMetaObject *, int> m_attachedPropertyIds;
220 // Avoid multiple fromUtf8(), copies and hashing of the module name.
221 // This is only called when metaTypeDataLock is locked.
222 static QHashedString moduleFromUtf8(const char *module)
225 return QHashedString();
227 static const char *lastModule = 0;
228 static QHashedString lastModuleStr;
230 // Separate plugins may have different strings at the same address
231 QHashedCStringRef currentModule(module, ::strlen(module));
232 if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
233 lastModuleStr = QString::fromUtf8(module);
234 lastModuleStr.hash();
238 return lastModuleStr;
241 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
243 QQmlTypePrivate::QQmlTypePrivate()
244 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
245 m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
246 m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
247 m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
248 m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
253 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
254 : d(new QQmlTypePrivate)
256 d->m_isInterface = true;
257 d->m_iid = interface.iid;
258 d->m_typeId = interface.typeId;
259 d->m_listId = interface.listId;
263 d->m_version_maj = 0;
264 d->m_version_min = 0;
267 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
268 : d(new QQmlTypePrivate)
270 d->m_elementName = elementName;
271 d->m_module = moduleFromUtf8(type.uri);
273 d->m_version_maj = type.versionMajor;
274 d->m_version_min = type.versionMinor;
275 if (type.version >= 1) // revisions added in version 1
276 d->m_revision = type.revision;
277 d->m_typeId = type.typeId;
278 d->m_listId = type.listId;
279 d->m_allocationSize = type.objectSize;
280 d->m_newFunc = type.create;
281 d->m_noCreationReason = type.noCreationReason;
282 d->m_baseMetaObject = type.metaObject;
283 d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
284 d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
285 if (d->m_attachedPropertiesType) {
286 QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
287 if (iter == d->m_attachedPropertyIds.end())
288 iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
289 d->m_attachedPropertiesId = *iter;
291 d->m_attachedPropertiesId = -1;
293 d->m_parserStatusCast = type.parserStatusCast;
294 d->m_propertyValueSourceCast = type.valueSourceCast;
295 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
296 d->m_extFunc = type.extensionObjectCreate;
298 d->m_customParser = type.customParser;
300 if (type.extensionMetaObject)
301 d->m_extMetaObject = type.extensionMetaObject;
304 QQmlType::~QQmlType()
306 delete d->m_customParser;
310 const QHashedString &QQmlType::module() const
315 int QQmlType::majorVersion() const
317 return d->m_version_maj;
320 int QQmlType::minorVersion() const
322 return d->m_version_min;
325 bool QQmlType::availableInVersion(int vmajor, int vminor) const
327 Q_ASSERT(vmajor >= 0 && vminor >= 0);
328 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
331 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
333 Q_ASSERT(vmajor >= 0 && vminor >= 0);
334 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
337 // returns the nearest _registered_ super class
338 QQmlType *QQmlType::superType() const
340 if (!d->m_haveSuperType) {
341 const QMetaObject *mo = d->m_baseMetaObject->superClass();
342 while (mo && !d->m_superType) {
343 d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
344 mo = mo->superClass();
346 d->m_haveSuperType = true;
349 return d->m_superType;
352 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
353 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
356 builder.setClassName(ignoreEnd->className());
359 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
360 QMetaClassInfo info = mo->classInfo(ii);
362 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
363 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
366 builder.addClassInfo(info.name(), info.value());
371 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
372 QMetaProperty property = mo->property(ii);
374 int otherIndex = ignoreEnd->indexOfProperty(property.name());
375 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
376 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
379 builder.addProperty(property);
384 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
385 QMetaMethod method = mo->method(ii);
387 // More complex - need to search name
388 QByteArray name = method.name();
393 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
394 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
397 QMetaMethod other = ignoreEnd->method(ii);
399 found = name == other.name();
402 QMetaMethodBuilder m = builder.addMethod(method);
404 m.setAccess(QMetaMethod::Private);
408 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
409 QMetaEnum enumerator = mo->enumerator(ii);
411 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
412 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
415 builder.addEnumerator(enumerator);
420 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
423 i -= mo->propertyOffset();
424 if (i < 0 && mo->d.superdata)
425 return isPropertyRevisioned(mo->d.superdata, index);
427 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
428 if (i >= 0 && i < mop->propertyCount) {
429 int handle = mop->propertyData + 3*i;
430 int flags = mo->d.data[handle + 2];
432 return (flags & Revisioned);
438 void QQmlTypePrivate::init() const
440 if (m_isSetup) return;
442 QWriteLocker lock(metaTypeDataLock());
446 // Setup extended meta object
447 // XXX - very inefficient
448 const QMetaObject *mo = m_baseMetaObject;
450 QMetaObjectBuilder builder;
451 clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
452 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
453 QMetaObject *mmo = builder.toMetaObject();
454 mmo->d.superdata = mo;
455 QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
456 m_metaObjects << data;
459 mo = mo->d.superdata;
461 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
463 if (t->d->m_extFunc) {
464 QMetaObjectBuilder builder;
465 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
466 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
467 QMetaObject *mmo = builder.toMetaObject();
468 mmo->d.superdata = m_baseMetaObject;
469 if (!m_metaObjects.isEmpty())
470 m_metaObjects.last().metaObject->d.superdata = mmo;
471 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
472 m_metaObjects << data;
475 mo = mo->d.superdata;
478 for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
479 m_metaObjects[ii].propertyOffset =
480 m_metaObjects.at(ii).metaObject->propertyOffset();
481 m_metaObjects[ii].methodOffset =
482 m_metaObjects.at(ii).metaObject->methodOffset();
485 // Check for revisioned details
487 const QMetaObject *mo = 0;
488 if (m_metaObjects.isEmpty())
489 mo = m_baseMetaObject;
491 mo = m_metaObjects.first().metaObject;
493 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
494 if (isPropertyRevisioned(mo, ii))
495 m_containsRevisionedAttributes = true;
498 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
499 if (mo->method(ii).revision() != 0)
500 m_containsRevisionedAttributes = true;
508 void QQmlTypePrivate::initEnums() const
510 if (m_isEnumSetup) return;
514 QWriteLocker lock(metaTypeDataLock());
515 if (m_isEnumSetup) return;
517 insertEnums(m_baseMetaObject);
519 m_isEnumSetup = true;
522 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
524 // Add any enum values defined by 'related' classes
525 if (metaObject->d.relatedMetaObjects) {
526 const QMetaObject **related = metaObject->d.relatedMetaObjects;
529 insertEnums(*related++);
533 // Add any enum values defined by this class, overwriting any inherited values
534 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
535 QMetaEnum e = metaObject->enumerator(ii);
536 for (int jj = 0; jj < e.keyCount(); ++jj)
537 m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
541 QByteArray QQmlType::typeName() const
543 if (d->m_baseMetaObject)
544 return d->m_baseMetaObject->className();
549 const QString &QQmlType::elementName() const
551 return d->m_elementName;
554 const QString &QQmlType::qmlTypeName() const
556 if (d->m_name.isEmpty()) {
557 if (!d->m_module.isEmpty())
558 d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
560 d->m_name = d->m_elementName;
566 QObject *QQmlType::create() const
570 QObject *rv = (QObject *)operator new(d->m_allocationSize);
573 if (rv && !d->m_metaObjects.isEmpty())
574 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
579 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
583 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
586 if (rv && !d->m_metaObjects.isEmpty())
587 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
590 *memory = ((char *)rv) + d->m_allocationSize;
593 QQmlCustomParser *QQmlType::customParser() const
595 return d->m_customParser;
598 QQmlType::CreateFunc QQmlType::createFunction() const
603 QString QQmlType::noCreationReason() const
605 return d->m_noCreationReason;
608 int QQmlType::createSize() const
610 return d->m_allocationSize;
613 bool QQmlType::isCreatable() const
615 return d->m_newFunc != 0;
618 bool QQmlType::isExtendedType() const
622 return !d->m_metaObjects.isEmpty();
625 bool QQmlType::isInterface() const
627 return d->m_isInterface;
630 int QQmlType::typeId() const
635 int QQmlType::qListTypeId() const
640 const QMetaObject *QQmlType::metaObject() const
644 if (d->m_metaObjects.isEmpty())
645 return d->m_baseMetaObject;
647 return d->m_metaObjects.first().metaObject;
651 const QMetaObject *QQmlType::baseMetaObject() const
653 return d->m_baseMetaObject;
656 bool QQmlType::containsRevisionedAttributes() const
660 return d->m_containsRevisionedAttributes;
663 int QQmlType::metaObjectRevision() const
665 return d->m_revision;
668 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
670 return d->m_attachedPropertiesFunc;
673 const QMetaObject *QQmlType::attachedPropertiesType() const
675 return d->m_attachedPropertiesType;
679 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
680 for the case that a single class is registered under two or more names (eg. Item in
681 Qt 4.7 and QtQuick 1.0).
683 int QQmlType::attachedPropertiesId() const
685 return d->m_attachedPropertiesId;
688 int QQmlType::parserStatusCast() const
690 return d->m_parserStatusCast;
693 int QQmlType::propertyValueSourceCast() const
695 return d->m_propertyValueSourceCast;
698 int QQmlType::propertyValueInterceptorCast() const
700 return d->m_propertyValueInterceptorCast;
703 const char *QQmlType::interfaceIId() const
708 int QQmlType::index() const
713 int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
720 int *rv = d->m_enums.value(name);
728 int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
735 int *rv = d->m_enums.value(name);
743 int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
750 int *rv = d->m_enums.value(name);
758 QQmlTypeModule::QQmlTypeModule()
759 : d(new QQmlTypeModulePrivate)
763 QQmlTypeModule::~QQmlTypeModule()
768 QString QQmlTypeModule::module() const
773 int QQmlTypeModule::majorVersion() const
775 return d->uri.majorVersion;
778 int QQmlTypeModule::minimumMinorVersion() const
780 return d->minMinorVersion;
783 int QQmlTypeModule::maximumMinorVersion() const
785 return d->maxMinorVersion;
788 void QQmlTypeModulePrivate::add(QQmlType *type)
790 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
791 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
793 QList<QQmlType *> &list = typeHash[type->elementName()];
794 for (int ii = 0; ii < list.count(); ++ii) {
795 if (list.at(ii)->minorVersion() < type->minorVersion()) {
796 list.insert(ii, type);
803 QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor)
805 // Expected that the caller has already handled locking metaTypeDataLock
807 QList<QQmlType *> *types = d->typeHash.value(name);
808 if (!types) return 0;
810 for (int ii = 0; ii < types->count(); ++ii)
811 if (types->at(ii)->minorVersion() <= minor)
812 return types->at(ii);
817 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
819 QReadLocker lock(metaTypeDataLock());
821 QList<QQmlType *> *types = d->typeHash.value(name);
822 if (!types) return 0;
824 for (int ii = 0; ii < types->count(); ++ii)
825 if (types->at(ii)->minorVersion() <= minor)
826 return types->at(ii);
831 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
833 QReadLocker lock(metaTypeDataLock());
835 QList<QQmlType *> *types = d->typeHash.value(name);
836 if (!types) return 0;
838 for (int ii = 0; ii < types->count(); ++ii)
839 if (types->at(ii)->minorVersion() <= minor)
840 return types->at(ii);
846 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
847 : m_module(0), m_minor(0)
851 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
852 : m_module(module), m_minor(minor)
855 Q_ASSERT(m_minor >= 0);
858 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
859 : m_module(o.m_module), m_minor(o.m_minor)
863 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
865 m_module = o.m_module;
870 QQmlTypeModule *QQmlTypeModuleVersion::module() const
875 int QQmlTypeModuleVersion::minorVersion() const
880 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
882 if (m_module) return m_module->type(name, m_minor);
886 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
888 if (m_module) return m_module->type(name, m_minor);
893 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
895 QWriteLocker lock(metaTypeDataLock());
896 QQmlMetaTypeData *data = metaTypeData();
898 data->parentFunctions.append(autoparent.function);
900 return data->parentFunctions.count() - 1;
903 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
905 if (interface.version > 0)
906 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
908 QWriteLocker lock(metaTypeDataLock());
909 QQmlMetaTypeData *data = metaTypeData();
911 int index = data->types.count();
913 QQmlType *type = new QQmlType(index, interface);
915 data->types.append(type);
916 data->idToType.insert(type->typeId(), type);
917 data->idToType.insert(type->qListTypeId(), type);
918 // XXX No insertMulti, so no multi-version interfaces?
919 if (!type->elementName().isEmpty())
920 data->nameToType.insert(type->elementName(), type);
922 if (data->interfaces.size() <= interface.typeId)
923 data->interfaces.resize(interface.typeId + 16);
924 if (data->lists.size() <= interface.listId)
925 data->lists.resize(interface.listId + 16);
926 data->interfaces.setBit(interface.typeId, true);
927 data->lists.setBit(interface.listId, true);
932 int registerType(const QQmlPrivate::RegisterType &type)
934 if (type.elementName) {
935 for (int ii = 0; type.elementName[ii]; ++ii) {
936 if (!isalnum(type.elementName[ii])) {
937 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
943 QWriteLocker lock(metaTypeDataLock());
944 QQmlMetaTypeData *data = metaTypeData();
946 QString elementName = QString::fromUtf8(type.elementName);
948 if (type.uri && type.elementName) {
949 QString nameSpace = moduleFromUtf8(type.uri);
951 if (data->singletonTypeExists(nameSpace, elementName, type.versionMajor, type.versionMinor)) {
952 qWarning("Cannot register type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(elementName), qPrintable(nameSpace), type.versionMajor, type.versionMinor);
956 if (!data->typeRegistrationNamespace.isEmpty()) {
957 // We can only install types into the registered namespace
958 if (nameSpace != data->typeRegistrationNamespace) {
959 QString failure(QCoreApplication::translate("qmlRegisterType",
960 "Cannot install element '%1' into unregistered namespace '%2'"));
961 data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace));
964 } else if (data->typeRegistrationNamespace != nameSpace) {
965 // Is the target namespace protected against further registrations?
966 if (data->protectedNamespaces.contains(nameSpace)) {
967 QString failure(QCoreApplication::translate("qmlRegisterType",
968 "Cannot install element '%1' into protected namespace '%2'"));
969 data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace));
975 int index = data->types.count();
977 QQmlType *dtype = new QQmlType(index, elementName, type);
979 data->types.append(dtype);
980 data->idToType.insert(dtype->typeId(), dtype);
981 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
983 if (!dtype->elementName().isEmpty())
984 data->nameToType.insertMulti(dtype->elementName(), dtype);
986 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
988 if (data->objects.size() <= type.typeId)
989 data->objects.resize(type.typeId + 16);
990 if (data->lists.size() <= type.listId)
991 data->lists.resize(type.listId + 16);
992 data->objects.setBit(type.typeId, true);
993 if (type.listId) data->lists.setBit(type.listId, true);
995 if (!dtype->module().isEmpty()) {
996 const QHashedString &mod = dtype->module();
998 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
999 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1001 module = new QQmlTypeModule;
1002 module->d->uri = versionedUri;
1003 data->uriToModule.insert(versionedUri, module);
1005 module->d->add(dtype);
1011 int registerSingletonType(const QQmlPrivate::RegisterSingletonType &api)
1013 QWriteLocker lock(metaTypeDataLock());
1015 QQmlMetaTypeData *data = metaTypeData();
1016 QString uri = QString::fromUtf8(api.uri);
1017 QQmlMetaType::SingletonType import;
1018 import.major = api.versionMajor;
1019 import.minor = api.versionMinor;
1020 import.script = api.scriptApi;
1021 import.qobject = api.qobjectApi;
1022 Q_ASSERT(api.typeName);
1023 import.typeName = QString::fromUtf8(api.typeName);
1024 import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
1026 if (data->singletonTypeExists(uri, import.typeName, import.major, import.minor)) {
1027 qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor);
1029 } else if (data->typeExists(uri, import.typeName, import.major, import.minor)) {
1030 qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor);
1034 int index = data->singletonTypeCount++;
1036 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
1038 QQmlMetaTypeData::SingletonTypeList apis;
1039 apis.singletonTypes << import;
1040 data->singletonTypes.insert(uri, apis);
1042 apiList->singletonTypes << import;
1043 apiList->sorted = false;
1051 This method is "over generalized" to allow us to (potentially) register more types of things in
1052 the future without adding exported symbols.
1054 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
1056 if (type == TypeRegistration) {
1057 return registerType(*reinterpret_cast<RegisterType *>(data));
1058 } else if (type == InterfaceRegistration) {
1059 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
1060 } else if (type == AutoParentRegistration) {
1061 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
1062 } else if (type == SingletonRegistration) {
1063 return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
1068 bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
1070 QQmlMetaTypeData *data = metaTypeData();
1072 // Has any type previously been installed to this namespace?
1073 QHashedString nameSpace(uri);
1074 foreach (const QQmlType *type, data->types)
1075 if (type->module() == nameSpace)
1081 void QQmlMetaType::protectNamespace(const QString &uri)
1083 QQmlMetaTypeData *data = metaTypeData();
1085 data->protectedNamespaces.insert(uri);
1088 void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
1090 QQmlMetaTypeData *data = metaTypeData();
1092 data->typeRegistrationNamespace = uri;
1093 data->typeRegistrationFailures.clear();
1096 QStringList QQmlMetaType::typeRegistrationFailures()
1098 QQmlMetaTypeData *data = metaTypeData();
1100 return data->typeRegistrationFailures;
1103 QReadWriteLock *QQmlMetaType::typeRegistrationLock()
1105 return metaTypeDataLock();
1109 Returns true if a module \a uri of any version is installed.
1111 bool QQmlMetaType::isAnyModule(const QString &uri)
1113 QReadLocker lock(metaTypeDataLock());
1114 QQmlMetaTypeData *data = metaTypeData();
1116 // first, check Types
1117 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
1118 iter != data->uriToModule.end(); ++iter) {
1119 if ((*iter)->module() == uri)
1123 // then, check SingletonTypes
1124 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
1132 Returns true if any type or API has been registered for the given \a module with at least
1133 versionMajor.versionMinor, or if types have been registered for \a module with at most
1134 versionMajor.versionMinor.
1136 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.
1138 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1140 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1141 QReadLocker lock(metaTypeDataLock());
1143 QQmlMetaTypeData *data = metaTypeData();
1145 // first, check Types
1146 QQmlTypeModule *tm =
1147 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1148 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1151 // then, check SingletonTypes
1152 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(module);
1154 foreach (const QQmlMetaType::SingletonType &mApi, apiList->singletonTypes) {
1155 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
1163 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1165 QReadLocker lock(metaTypeDataLock());
1166 QQmlMetaTypeData *data = metaTypeData();
1167 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1170 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1172 QReadLocker lock(metaTypeDataLock());
1173 QQmlMetaTypeData *data = metaTypeData();
1174 return data->parentFunctions;
1177 static bool operator<(const QQmlMetaType::SingletonType &lhs, const QQmlMetaType::SingletonType &rhs)
1179 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1182 QQmlMetaType::SingletonType
1183 QQmlMetaType::singletonType(const QString &uri, int versionMajor, int versionMinor)
1185 QReadLocker lock(metaTypeDataLock());
1186 QQmlMetaTypeData *data = metaTypeData();
1188 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
1190 return SingletonType();
1192 if (apiList->sorted == false) {
1193 qSort(apiList->singletonTypes.begin(), apiList->singletonTypes.end());
1194 apiList->sorted = true;
1197 for (int ii = apiList->singletonTypes.count() - 1; ii >= 0; --ii) {
1198 const SingletonType &import = apiList->singletonTypes.at(ii);
1199 if (import.major == versionMajor && import.minor <= versionMinor)
1203 return SingletonType();
1206 QHash<QString, QList<QQmlMetaType::SingletonType> > QQmlMetaType::singletonTypes()
1208 QReadLocker lock(metaTypeDataLock());
1209 QQmlMetaTypeData *data = metaTypeData();
1211 QHash<QString, QList<SingletonType> > singletonTypes;
1212 QStringHash<QQmlMetaTypeData::SingletonTypeList>::ConstIterator it = data->singletonTypes.begin();
1213 for (; it != data->singletonTypes.end(); ++it)
1214 singletonTypes[it.key()] = it.value().singletonTypes;
1216 return singletonTypes;
1219 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1221 if (!isQObject(v.userType())) {
1222 if (ok) *ok = false;
1228 return *(QObject **)v.constData();
1231 bool QQmlMetaType::isQObject(int userType)
1233 if (userType == QMetaType::QObjectStar)
1236 QReadLocker lock(metaTypeDataLock());
1237 QQmlMetaTypeData *data = metaTypeData();
1238 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1242 Returns the item type for a list of type \a id.
1244 int QQmlMetaType::listType(int id)
1246 QReadLocker lock(metaTypeDataLock());
1247 QQmlMetaTypeData *data = metaTypeData();
1248 QQmlType *type = data->idToType.value(id);
1249 if (type && type->qListTypeId() == id)
1250 return type->typeId();
1255 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1257 QReadLocker lock(metaTypeDataLock());
1258 QQmlMetaTypeData *data = metaTypeData();
1260 QQmlType *type = data->metaObjectToType.value(mo);
1261 if (type && type->attachedPropertiesFunction())
1262 return type->attachedPropertiesId();
1267 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1271 QReadLocker lock(metaTypeDataLock());
1272 QQmlMetaTypeData *data = metaTypeData();
1273 return data->types.at(id)->attachedPropertiesFunction();
1276 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1278 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1280 return QMetaProperty();
1282 QMetaClassInfo info = metaObject->classInfo(idx);
1284 return QMetaProperty();
1286 idx = metaObject->indexOfProperty(info.value());
1288 return QMetaProperty();
1290 return metaObject->property(idx);
1293 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1296 return QMetaProperty();
1298 const QMetaObject *metaObject = obj->metaObject();
1299 return defaultProperty(metaObject);
1302 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1304 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1306 return QMetaMethod();
1308 QMetaClassInfo info = metaObject->classInfo(idx);
1310 return QMetaMethod();
1312 idx = metaObject->indexOfMethod(info.value());
1314 return QMetaMethod();
1316 return metaObject->method(idx);
1319 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1322 return QMetaMethod();
1324 const QMetaObject *metaObject = obj->metaObject();
1325 return defaultMethod(metaObject);
1328 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1332 if (userType == QMetaType::QObjectStar)
1335 QReadLocker lock(metaTypeDataLock());
1336 QQmlMetaTypeData *data = metaTypeData();
1337 if (userType < data->objects.size() && data->objects.testBit(userType))
1339 else if (userType < data->lists.size() && data->lists.testBit(userType))
1345 bool QQmlMetaType::isInterface(int userType)
1347 QReadLocker lock(metaTypeDataLock());
1348 QQmlMetaTypeData *data = metaTypeData();
1349 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1352 const char *QQmlMetaType::interfaceIId(int userType)
1354 QReadLocker lock(metaTypeDataLock());
1355 QQmlMetaTypeData *data = metaTypeData();
1356 QQmlType *type = data->idToType.value(userType);
1358 if (type && type->isInterface() && type->typeId() == userType)
1359 return type->interfaceIId();
1364 bool QQmlMetaType::isList(int userType)
1366 QReadLocker lock(metaTypeDataLock());
1367 QQmlMetaTypeData *data = metaTypeData();
1368 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1372 A custom string convertor allows you to specify a function pointer that
1373 returns a variant of \a type. For example, if you have written your own icon
1374 class that you want to support as an object property assignable in QML:
1377 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1378 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1381 The function pointer must be of the form:
1383 QVariant (*StringConverter)(const QString &);
1386 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1388 QWriteLocker lock(metaTypeDataLock());
1390 QQmlMetaTypeData *data = metaTypeData();
1391 if (data->stringConverters.contains(type))
1393 data->stringConverters.insert(type, converter);
1397 Return the custom string converter for \a type, previously installed through
1398 registerCustomStringConverter()
1400 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1402 QReadLocker lock(metaTypeDataLock());
1404 QQmlMetaTypeData *data = metaTypeData();
1405 return data->stringConverters.value(type);
1409 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1410 by \a version_major and \a version_minor.
1412 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1414 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1418 QHashedStringRef module(qualifiedName.constData(), slash);
1419 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1421 return qmlType(name, module, version_major, version_minor);
1425 Returns the type (if any) of \a name in \a module and version specified
1426 by \a version_major and \a version_minor.
1428 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1430 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1431 QReadLocker lock(metaTypeDataLock());
1432 QQmlMetaTypeData *data = metaTypeData();
1434 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1435 while (it != data->nameToType.end() && it.key() == name) {
1436 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1437 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1446 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1449 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1451 QReadLocker lock(metaTypeDataLock());
1452 QQmlMetaTypeData *data = metaTypeData();
1454 return data->metaObjectToType.value(metaObject);
1458 Returns the type (if any) that corresponds to the \a metaObject in version specified
1459 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1462 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1464 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1465 QReadLocker lock(metaTypeDataLock());
1466 QQmlMetaTypeData *data = metaTypeData();
1468 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1469 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1471 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1480 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1481 Returns null if no type is registered.
1483 QQmlType *QQmlMetaType::qmlType(int userType)
1485 QReadLocker lock(metaTypeDataLock());
1486 QQmlMetaTypeData *data = metaTypeData();
1488 QQmlType *type = data->idToType.value(userType);
1489 if (type && type->typeId() == userType)
1496 Returns the list of registered QML type names.
1498 QList<QString> QQmlMetaType::qmlTypeNames()
1500 QReadLocker lock(metaTypeDataLock());
1501 QQmlMetaTypeData *data = metaTypeData();
1503 QList<QString> names;
1504 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1505 while (it != data->nameToType.end()) {
1506 names += (*it)->qmlTypeName();
1514 Returns the list of registered QML types.
1516 QList<QQmlType*> QQmlMetaType::qmlTypes()
1518 QReadLocker lock(metaTypeDataLock());
1519 QQmlMetaTypeData *data = metaTypeData();
1521 return data->nameToType.values();
1524 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1528 id = QMetaType::type("QQuickAnchorLine");
1533 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1535 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1537 anchorLineCompareFunction = fun;
1540 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1542 Q_ASSERT(anchorLineCompareFunction != 0);
1543 return anchorLineCompareFunction(p1, p2);