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;
112 QSet<QString> protectedNamespaces;
114 QString typeRegistrationNamespace;
115 QStringList typeRegistrationFailures;
118 class QQmlTypeModulePrivate
121 QQmlTypeModulePrivate()
122 : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
124 QQmlMetaTypeData::VersionedUri uri;
129 void add(QQmlType *);
131 QStringHash<QList<QQmlType *> > typeHash;
132 QList<QQmlType *> types;
135 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
136 Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, metaTypeDataLock, (QReadWriteLock::Recursive))
138 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
140 return v.uri.hash() ^ qHash(v.majorVersion);
143 QQmlMetaTypeData::QQmlMetaTypeData()
148 QQmlMetaTypeData::~QQmlMetaTypeData()
150 for (int i = 0; i < types.count(); ++i)
154 class QQmlTypePrivate
160 void initEnums() const;
161 void insertEnums(const QMetaObject *metaObject) const;
163 bool m_isInterface : 1;
165 QHashedString m_module;
167 QString m_elementName;
170 int m_typeId; int m_listId;
172 mutable bool m_containsRevisionedAttributes;
173 mutable QQmlType *m_superType;
175 int m_allocationSize;
176 void (*m_newFunc)(void *);
177 QString m_noCreationReason;
179 const QMetaObject *m_baseMetaObject;
180 QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
181 const QMetaObject *m_attachedPropertiesType;
182 int m_attachedPropertiesId;
183 int m_parserStatusCast;
184 int m_propertyValueSourceCast;
185 int m_propertyValueInterceptorCast;
186 QObject *(*m_extFunc)(QObject *);
187 const QMetaObject *m_extMetaObject;
189 QQmlCustomParser *m_customParser;
190 mutable volatile bool m_isSetup:1;
191 mutable volatile bool m_isEnumSetup:1;
192 mutable bool m_haveSuperType:1;
193 mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
194 mutable QStringHash<int> m_enums;
196 static QHash<const QMetaObject *, int> m_attachedPropertyIds;
199 // Avoid multiple fromUtf8(), copies and hashing of the module name.
200 // This is only called when metaTypeDataLock is locked.
201 static QHashedString moduleFromUtf8(const char *module)
204 return QHashedString();
206 static const char *lastModule = 0;
207 static QHashedString lastModuleStr;
209 // Separate plugins may have different strings at the same address
210 QHashedCStringRef currentModule(module, ::strlen(module));
211 if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
212 lastModuleStr = QString::fromUtf8(module);
213 lastModuleStr.hash();
217 return lastModuleStr;
220 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
222 QQmlTypePrivate::QQmlTypePrivate()
223 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
224 m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
225 m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
226 m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
227 m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
232 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
233 : d(new QQmlTypePrivate)
235 d->m_isInterface = true;
236 d->m_iid = interface.iid;
237 d->m_typeId = interface.typeId;
238 d->m_listId = interface.listId;
242 d->m_version_maj = 0;
243 d->m_version_min = 0;
246 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
247 : d(new QQmlTypePrivate)
249 d->m_module = moduleFromUtf8(type.uri);
250 d->m_elementName = QString::fromUtf8(type.elementName);
252 d->m_version_maj = type.versionMajor;
253 d->m_version_min = type.versionMinor;
254 if (type.version >= 1) // revisions added in version 1
255 d->m_revision = type.revision;
256 d->m_typeId = type.typeId;
257 d->m_listId = type.listId;
258 d->m_allocationSize = type.objectSize;
259 d->m_newFunc = type.create;
260 d->m_noCreationReason = type.noCreationReason;
261 d->m_baseMetaObject = type.metaObject;
262 d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
263 d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
264 if (d->m_attachedPropertiesType) {
265 QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
266 if (iter == d->m_attachedPropertyIds.end())
267 iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
268 d->m_attachedPropertiesId = *iter;
270 d->m_attachedPropertiesId = -1;
272 d->m_parserStatusCast = type.parserStatusCast;
273 d->m_propertyValueSourceCast = type.valueSourceCast;
274 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
275 d->m_extFunc = type.extensionObjectCreate;
277 d->m_customParser = type.customParser;
279 if (type.extensionMetaObject)
280 d->m_extMetaObject = type.extensionMetaObject;
283 QQmlType::~QQmlType()
285 delete d->m_customParser;
289 const QHashedString &QQmlType::module() const
294 int QQmlType::majorVersion() const
296 return d->m_version_maj;
299 int QQmlType::minorVersion() const
301 return d->m_version_min;
304 bool QQmlType::availableInVersion(int vmajor, int vminor) const
306 Q_ASSERT(vmajor >= 0 && vminor >= 0);
307 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
310 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
312 Q_ASSERT(vmajor >= 0 && vminor >= 0);
313 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
316 // returns the nearest _registered_ super class
317 QQmlType *QQmlType::superType() const
319 if (!d->m_haveSuperType) {
320 const QMetaObject *mo = d->m_baseMetaObject->superClass();
321 while (mo && !d->m_superType) {
322 d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
323 mo = mo->superClass();
325 d->m_haveSuperType = true;
328 return d->m_superType;
331 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
332 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
335 builder.setClassName(ignoreEnd->className());
338 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
339 QMetaClassInfo info = mo->classInfo(ii);
341 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
342 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
345 builder.addClassInfo(info.name(), info.value());
350 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
351 QMetaProperty property = mo->property(ii);
353 int otherIndex = ignoreEnd->indexOfProperty(property.name());
354 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
355 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
358 builder.addProperty(property);
363 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
364 QMetaMethod method = mo->method(ii);
366 // More complex - need to search name
367 QByteArray name = method.name();
372 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
373 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
376 QMetaMethod other = ignoreEnd->method(ii);
378 found = name == other.name();
381 QMetaMethodBuilder m = builder.addMethod(method);
383 m.setAccess(QMetaMethod::Private);
387 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
388 QMetaEnum enumerator = mo->enumerator(ii);
390 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
391 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
394 builder.addEnumerator(enumerator);
399 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
402 i -= mo->propertyOffset();
403 if (i < 0 && mo->d.superdata)
404 return isPropertyRevisioned(mo->d.superdata, index);
406 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
407 if (i >= 0 && i < mop->propertyCount) {
408 int handle = mop->propertyData + 3*i;
409 int flags = mo->d.data[handle + 2];
411 return (flags & Revisioned);
417 void QQmlTypePrivate::init() const
419 if (m_isSetup) return;
421 QWriteLocker lock(metaTypeDataLock());
425 // Setup extended meta object
426 // XXX - very inefficient
427 const QMetaObject *mo = m_baseMetaObject;
429 QMetaObjectBuilder builder;
430 clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
431 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
432 QMetaObject *mmo = builder.toMetaObject();
433 mmo->d.superdata = mo;
434 QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
435 m_metaObjects << data;
438 mo = mo->d.superdata;
440 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
442 if (t->d->m_extFunc) {
443 QMetaObjectBuilder builder;
444 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
445 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
446 QMetaObject *mmo = builder.toMetaObject();
447 mmo->d.superdata = m_baseMetaObject;
448 if (!m_metaObjects.isEmpty())
449 m_metaObjects.last().metaObject->d.superdata = mmo;
450 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
451 m_metaObjects << data;
454 mo = mo->d.superdata;
457 for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
458 m_metaObjects[ii].propertyOffset =
459 m_metaObjects.at(ii).metaObject->propertyOffset();
460 m_metaObjects[ii].methodOffset =
461 m_metaObjects.at(ii).metaObject->methodOffset();
464 // Check for revisioned details
466 const QMetaObject *mo = 0;
467 if (m_metaObjects.isEmpty())
468 mo = m_baseMetaObject;
470 mo = m_metaObjects.first().metaObject;
472 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
473 if (isPropertyRevisioned(mo, ii))
474 m_containsRevisionedAttributes = true;
477 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
478 if (mo->method(ii).revision() != 0)
479 m_containsRevisionedAttributes = true;
487 void QQmlTypePrivate::initEnums() const
489 if (m_isEnumSetup) return;
493 QWriteLocker lock(metaTypeDataLock());
494 if (m_isEnumSetup) return;
496 insertEnums(m_baseMetaObject);
498 m_isEnumSetup = true;
501 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
503 // Add any enum values defined by 'related' classes
504 if (metaObject->d.relatedMetaObjects) {
505 const QMetaObject **related = metaObject->d.relatedMetaObjects;
508 insertEnums(*related++);
512 // Add any enum values defined by this class, overwriting any inherited values
513 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
514 QMetaEnum e = metaObject->enumerator(ii);
515 for (int jj = 0; jj < e.keyCount(); ++jj)
516 m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
520 QByteArray QQmlType::typeName() const
522 if (d->m_baseMetaObject)
523 return d->m_baseMetaObject->className();
528 const QString &QQmlType::elementName() const
530 return d->m_elementName;
533 const QString &QQmlType::qmlTypeName() const
535 if (d->m_name.isEmpty()) {
536 if (!d->m_module.isEmpty())
537 d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
539 d->m_name = d->m_elementName;
545 QObject *QQmlType::create() const
549 QObject *rv = (QObject *)operator new(d->m_allocationSize);
552 if (rv && !d->m_metaObjects.isEmpty())
553 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
558 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
562 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
565 if (rv && !d->m_metaObjects.isEmpty())
566 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
569 *memory = ((char *)rv) + d->m_allocationSize;
572 QQmlCustomParser *QQmlType::customParser() const
574 return d->m_customParser;
577 QQmlType::CreateFunc QQmlType::createFunction() const
582 QString QQmlType::noCreationReason() const
584 return d->m_noCreationReason;
587 int QQmlType::createSize() const
589 return d->m_allocationSize;
592 bool QQmlType::isCreatable() const
594 return d->m_newFunc != 0;
597 bool QQmlType::isExtendedType() const
601 return !d->m_metaObjects.isEmpty();
604 bool QQmlType::isInterface() const
606 return d->m_isInterface;
609 int QQmlType::typeId() const
614 int QQmlType::qListTypeId() const
619 const QMetaObject *QQmlType::metaObject() const
623 if (d->m_metaObjects.isEmpty())
624 return d->m_baseMetaObject;
626 return d->m_metaObjects.first().metaObject;
630 const QMetaObject *QQmlType::baseMetaObject() const
632 return d->m_baseMetaObject;
635 bool QQmlType::containsRevisionedAttributes() const
639 return d->m_containsRevisionedAttributes;
642 int QQmlType::metaObjectRevision() const
644 return d->m_revision;
647 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
649 return d->m_attachedPropertiesFunc;
652 const QMetaObject *QQmlType::attachedPropertiesType() const
654 return d->m_attachedPropertiesType;
658 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
659 for the case that a single class is registered under two or more names (eg. Item in
660 Qt 4.7 and QtQuick 1.0).
662 int QQmlType::attachedPropertiesId() const
664 return d->m_attachedPropertiesId;
667 int QQmlType::parserStatusCast() const
669 return d->m_parserStatusCast;
672 int QQmlType::propertyValueSourceCast() const
674 return d->m_propertyValueSourceCast;
677 int QQmlType::propertyValueInterceptorCast() const
679 return d->m_propertyValueInterceptorCast;
682 const char *QQmlType::interfaceIId() const
687 int QQmlType::index() const
692 int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
699 int *rv = d->m_enums.value(name);
707 int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
714 int *rv = d->m_enums.value(name);
722 int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
729 int *rv = d->m_enums.value(name);
737 QQmlTypeModule::QQmlTypeModule()
738 : d(new QQmlTypeModulePrivate)
742 QQmlTypeModule::~QQmlTypeModule()
747 QString QQmlTypeModule::module() const
752 int QQmlTypeModule::majorVersion() const
754 return d->uri.majorVersion;
757 int QQmlTypeModule::minimumMinorVersion() const
759 return d->minMinorVersion;
762 int QQmlTypeModule::maximumMinorVersion() const
764 return d->maxMinorVersion;
767 void QQmlTypeModulePrivate::add(QQmlType *type)
769 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
770 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
772 QList<QQmlType *> &list = typeHash[type->elementName()];
773 for (int ii = 0; ii < list.count(); ++ii) {
774 if (list.at(ii)->minorVersion() < type->minorVersion()) {
775 list.insert(ii, type);
782 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
784 QReadLocker lock(metaTypeDataLock());
786 QList<QQmlType *> *types = d->typeHash.value(name);
787 if (!types) return 0;
789 for (int ii = 0; ii < types->count(); ++ii)
790 if (types->at(ii)->minorVersion() <= minor)
791 return types->at(ii);
796 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
798 QReadLocker lock(metaTypeDataLock());
800 QList<QQmlType *> *types = d->typeHash.value(name);
801 if (!types) return 0;
803 for (int ii = 0; ii < types->count(); ++ii)
804 if (types->at(ii)->minorVersion() <= minor)
805 return types->at(ii);
811 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
812 : m_module(0), m_minor(0)
816 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
817 : m_module(module), m_minor(minor)
820 Q_ASSERT(m_minor >= 0);
823 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
824 : m_module(o.m_module), m_minor(o.m_minor)
828 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
830 m_module = o.m_module;
835 QQmlTypeModule *QQmlTypeModuleVersion::module() const
840 int QQmlTypeModuleVersion::minorVersion() const
845 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
847 if (m_module) return m_module->type(name, m_minor);
851 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
853 if (m_module) return m_module->type(name, m_minor);
858 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
860 QWriteLocker lock(metaTypeDataLock());
861 QQmlMetaTypeData *data = metaTypeData();
863 data->parentFunctions.append(autoparent.function);
865 return data->parentFunctions.count() - 1;
868 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
870 if (interface.version > 0)
871 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
873 QWriteLocker lock(metaTypeDataLock());
874 QQmlMetaTypeData *data = metaTypeData();
876 int index = data->types.count();
878 QQmlType *type = new QQmlType(index, interface);
880 data->types.append(type);
881 data->idToType.insert(type->typeId(), type);
882 data->idToType.insert(type->qListTypeId(), type);
883 // XXX No insertMulti, so no multi-version interfaces?
884 if (!type->elementName().isEmpty())
885 data->nameToType.insert(type->elementName(), type);
887 if (data->interfaces.size() <= interface.typeId)
888 data->interfaces.resize(interface.typeId + 16);
889 if (data->lists.size() <= interface.listId)
890 data->lists.resize(interface.listId + 16);
891 data->interfaces.setBit(interface.typeId, true);
892 data->lists.setBit(interface.listId, true);
897 int registerType(const QQmlPrivate::RegisterType &type)
899 if (type.elementName) {
900 for (int ii = 0; type.elementName[ii]; ++ii) {
901 if (!isalnum(type.elementName[ii])) {
902 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
908 QWriteLocker lock(metaTypeDataLock());
909 QQmlMetaTypeData *data = metaTypeData();
911 if (type.uri && type.elementName) {
912 QString nameSpace = moduleFromUtf8(type.uri);
914 if (!data->typeRegistrationNamespace.isEmpty()) {
915 // We can only install types into the registered namespace
916 if (nameSpace != data->typeRegistrationNamespace) {
917 QString failure(QCoreApplication::translate("qmlRegisterType",
918 "Cannot install element '%1' into unregistered namespace '%2'"));
919 data->typeRegistrationFailures.append(failure.arg(QString::fromUtf8(type.elementName)).arg(nameSpace));
922 } else if (data->typeRegistrationNamespace != nameSpace) {
923 // Is the target namespace protected against further registrations?
924 if (data->protectedNamespaces.contains(nameSpace)) {
925 QString failure(QCoreApplication::translate("qmlRegisterType",
926 "Cannot install element '%1' into protected namespace '%2'"));
927 data->typeRegistrationFailures.append(failure.arg(QString::fromUtf8(type.elementName)).arg(nameSpace));
933 int index = data->types.count();
935 QQmlType *dtype = new QQmlType(index, type);
937 data->types.append(dtype);
938 data->idToType.insert(dtype->typeId(), dtype);
939 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
941 if (!dtype->elementName().isEmpty())
942 data->nameToType.insertMulti(dtype->elementName(), dtype);
944 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
946 if (data->objects.size() <= type.typeId)
947 data->objects.resize(type.typeId + 16);
948 if (data->lists.size() <= type.listId)
949 data->lists.resize(type.listId + 16);
950 data->objects.setBit(type.typeId, true);
951 if (type.listId) data->lists.setBit(type.listId, true);
953 if (!dtype->module().isEmpty()) {
954 const QHashedString &mod = dtype->module();
956 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
957 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
959 module = new QQmlTypeModule;
960 module->d->uri = versionedUri;
961 data->uriToModule.insert(versionedUri, module);
963 module->d->add(dtype);
969 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
971 QWriteLocker lock(metaTypeDataLock());
973 QQmlMetaTypeData *data = metaTypeData();
974 QString uri = QString::fromUtf8(api.uri);
975 QQmlMetaType::ModuleApi import;
976 import.major = api.versionMajor;
977 import.minor = api.versionMinor;
978 import.script = api.scriptApi;
979 import.qobject = api.qobjectApi;
980 import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
982 int index = data->moduleApiCount++;
984 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
986 QQmlMetaTypeData::ModuleApiList apis;
987 apis.moduleApis << import;
988 data->moduleApis.insert(uri, apis);
990 apiList->moduleApis << import;
991 apiList->sorted = false;
999 This method is "over generalized" to allow us to (potentially) register more types of things in
1000 the future without adding exported symbols.
1002 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
1004 if (type == TypeRegistration) {
1005 return registerType(*reinterpret_cast<RegisterType *>(data));
1006 } else if (type == InterfaceRegistration) {
1007 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
1008 } else if (type == AutoParentRegistration) {
1009 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
1010 } else if (type == ModuleApiRegistration) {
1011 return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
1016 bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
1018 QQmlMetaTypeData *data = metaTypeData();
1020 // Has any type previously been installed to this namespace?
1021 QHashedString nameSpace(uri);
1022 foreach (const QQmlType *type, data->types)
1023 if (type->module() == nameSpace)
1029 void QQmlMetaType::protectNamespace(const QString &uri)
1031 QQmlMetaTypeData *data = metaTypeData();
1033 data->protectedNamespaces.insert(uri);
1036 void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
1038 QQmlMetaTypeData *data = metaTypeData();
1040 data->typeRegistrationNamespace = uri;
1041 data->typeRegistrationFailures.clear();
1044 QStringList QQmlMetaType::typeRegistrationFailures()
1046 QQmlMetaTypeData *data = metaTypeData();
1048 return data->typeRegistrationFailures;
1051 QReadWriteLock *QQmlMetaType::typeRegistrationLock()
1053 return metaTypeDataLock();
1057 Returns true if a module \a uri of any version is installed.
1059 bool QQmlMetaType::isAnyModule(const QString &uri)
1061 QReadLocker lock(metaTypeDataLock());
1062 QQmlMetaTypeData *data = metaTypeData();
1064 // first, check Types
1065 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
1066 iter != data->uriToModule.end(); ++iter) {
1067 if ((*iter)->module() == uri)
1071 // then, check ModuleApis
1072 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1080 Returns true if any type or API has been registered for the given \a module with at least
1081 versionMajor.versionMinor, or if types have been registered for \a module with at most
1082 versionMajor.versionMinor.
1084 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.
1086 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1088 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1089 QReadLocker lock(metaTypeDataLock());
1091 QQmlMetaTypeData *data = metaTypeData();
1093 // first, check Types
1094 QQmlTypeModule *tm =
1095 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1096 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1099 // then, check ModuleApis
1100 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
1102 foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
1103 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
1111 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1113 QReadLocker lock(metaTypeDataLock());
1114 QQmlMetaTypeData *data = metaTypeData();
1115 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1118 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1120 QReadLocker lock(metaTypeDataLock());
1121 QQmlMetaTypeData *data = metaTypeData();
1122 return data->parentFunctions;
1125 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1127 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1130 QQmlMetaType::ModuleApi
1131 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1133 QReadLocker lock(metaTypeDataLock());
1134 QQmlMetaTypeData *data = metaTypeData();
1136 QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1140 if (apiList->sorted == false) {
1141 qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1142 apiList->sorted = true;
1145 for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1146 const ModuleApi &import = apiList->moduleApis.at(ii);
1147 if (import.major == versionMajor && import.minor <= versionMinor)
1154 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1156 QReadLocker lock(metaTypeDataLock());
1157 QQmlMetaTypeData *data = metaTypeData();
1159 QHash<QString, QList<ModuleApi> > moduleApis;
1160 QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1161 for (; it != data->moduleApis.end(); ++it)
1162 moduleApis[it.key()] = it.value().moduleApis;
1167 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1169 if (!isQObject(v.userType())) {
1170 if (ok) *ok = false;
1176 return *(QObject **)v.constData();
1179 bool QQmlMetaType::isQObject(int userType)
1181 if (userType == QMetaType::QObjectStar)
1184 QReadLocker lock(metaTypeDataLock());
1185 QQmlMetaTypeData *data = metaTypeData();
1186 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1190 Returns the item type for a list of type \a id.
1192 int QQmlMetaType::listType(int id)
1194 QReadLocker lock(metaTypeDataLock());
1195 QQmlMetaTypeData *data = metaTypeData();
1196 QQmlType *type = data->idToType.value(id);
1197 if (type && type->qListTypeId() == id)
1198 return type->typeId();
1203 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1205 QReadLocker lock(metaTypeDataLock());
1206 QQmlMetaTypeData *data = metaTypeData();
1208 QQmlType *type = data->metaObjectToType.value(mo);
1209 if (type && type->attachedPropertiesFunction())
1210 return type->attachedPropertiesId();
1215 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1219 QReadLocker lock(metaTypeDataLock());
1220 QQmlMetaTypeData *data = metaTypeData();
1221 return data->types.at(id)->attachedPropertiesFunction();
1224 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1226 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1228 return QMetaProperty();
1230 QMetaClassInfo info = metaObject->classInfo(idx);
1232 return QMetaProperty();
1234 idx = metaObject->indexOfProperty(info.value());
1236 return QMetaProperty();
1238 return metaObject->property(idx);
1241 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1244 return QMetaProperty();
1246 const QMetaObject *metaObject = obj->metaObject();
1247 return defaultProperty(metaObject);
1250 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1252 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1254 return QMetaMethod();
1256 QMetaClassInfo info = metaObject->classInfo(idx);
1258 return QMetaMethod();
1260 idx = metaObject->indexOfMethod(info.value());
1262 return QMetaMethod();
1264 return metaObject->method(idx);
1267 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1270 return QMetaMethod();
1272 const QMetaObject *metaObject = obj->metaObject();
1273 return defaultMethod(metaObject);
1276 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1280 if (userType == QMetaType::QObjectStar)
1283 QReadLocker lock(metaTypeDataLock());
1284 QQmlMetaTypeData *data = metaTypeData();
1285 if (userType < data->objects.size() && data->objects.testBit(userType))
1287 else if (userType < data->lists.size() && data->lists.testBit(userType))
1293 bool QQmlMetaType::isInterface(int userType)
1295 QReadLocker lock(metaTypeDataLock());
1296 QQmlMetaTypeData *data = metaTypeData();
1297 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1300 const char *QQmlMetaType::interfaceIId(int userType)
1302 QReadLocker lock(metaTypeDataLock());
1303 QQmlMetaTypeData *data = metaTypeData();
1304 QQmlType *type = data->idToType.value(userType);
1306 if (type && type->isInterface() && type->typeId() == userType)
1307 return type->interfaceIId();
1312 bool QQmlMetaType::isList(int userType)
1314 QReadLocker lock(metaTypeDataLock());
1315 QQmlMetaTypeData *data = metaTypeData();
1316 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1320 A custom string convertor allows you to specify a function pointer that
1321 returns a variant of \a type. For example, if you have written your own icon
1322 class that you want to support as an object property assignable in QML:
1325 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1326 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1329 The function pointer must be of the form:
1331 QVariant (*StringConverter)(const QString &);
1334 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1336 QWriteLocker lock(metaTypeDataLock());
1338 QQmlMetaTypeData *data = metaTypeData();
1339 if (data->stringConverters.contains(type))
1341 data->stringConverters.insert(type, converter);
1345 Return the custom string converter for \a type, previously installed through
1346 registerCustomStringConverter()
1348 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1350 QReadLocker lock(metaTypeDataLock());
1352 QQmlMetaTypeData *data = metaTypeData();
1353 return data->stringConverters.value(type);
1357 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1358 by \a version_major and \a version_minor.
1360 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1362 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1366 QHashedStringRef module(qualifiedName.constData(), slash);
1367 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1369 return qmlType(name, module, version_major, version_minor);
1373 Returns the type (if any) of \a name in \a module and version specified
1374 by \a version_major and \a version_minor.
1376 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1378 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1379 QReadLocker lock(metaTypeDataLock());
1380 QQmlMetaTypeData *data = metaTypeData();
1382 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1383 while (it != data->nameToType.end() && it.key() == name) {
1384 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1385 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1394 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1397 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1399 QReadLocker lock(metaTypeDataLock());
1400 QQmlMetaTypeData *data = metaTypeData();
1402 return data->metaObjectToType.value(metaObject);
1406 Returns the type (if any) that corresponds to the \a metaObject in version specified
1407 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1410 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1412 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1413 QReadLocker lock(metaTypeDataLock());
1414 QQmlMetaTypeData *data = metaTypeData();
1416 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1417 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1419 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1428 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1429 Returns null if no type is registered.
1431 QQmlType *QQmlMetaType::qmlType(int userType)
1433 QReadLocker lock(metaTypeDataLock());
1434 QQmlMetaTypeData *data = metaTypeData();
1436 QQmlType *type = data->idToType.value(userType);
1437 if (type && type->typeId() == userType)
1444 Returns the list of registered QML type names.
1446 QList<QString> QQmlMetaType::qmlTypeNames()
1448 QReadLocker lock(metaTypeDataLock());
1449 QQmlMetaTypeData *data = metaTypeData();
1451 QList<QString> names;
1452 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1453 while (it != data->nameToType.end()) {
1454 names += (*it)->qmlTypeName();
1462 Returns the list of registered QML types.
1464 QList<QQmlType*> QQmlMetaType::qmlTypes()
1466 QReadLocker lock(metaTypeDataLock());
1467 QQmlMetaTypeData *data = metaTypeData();
1469 return data->nameToType.values();
1472 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1476 id = QMetaType::type("QQuickAnchorLine");
1481 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1483 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1485 anchorLineCompareFunction = fun;
1488 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1490 Q_ASSERT(anchorLineCompareFunction != 0);
1491 return anchorLineCompareFunction(p1, p2);