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 QQmlPrivate::RegisterType &type)
268 : d(new QQmlTypePrivate)
270 d->m_module = moduleFromUtf8(type.uri);
271 d->m_elementName = QString::fromUtf8(type.elementName);
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 if (type.uri && type.elementName) {
947 QString nameSpace = moduleFromUtf8(type.uri);
949 if (data->singletonTypeExists(nameSpace, type.elementName, type.versionMajor, type.versionMinor)) {
950 qWarning("Cannot register type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(type.elementName), qPrintable(nameSpace), type.versionMajor, type.versionMinor);
954 if (!data->typeRegistrationNamespace.isEmpty()) {
955 // We can only install types into the registered namespace
956 if (nameSpace != data->typeRegistrationNamespace) {
957 QString failure(QCoreApplication::translate("qmlRegisterType",
958 "Cannot install element '%1' into unregistered namespace '%2'"));
959 data->typeRegistrationFailures.append(failure.arg(QString::fromUtf8(type.elementName)).arg(nameSpace));
962 } else if (data->typeRegistrationNamespace != nameSpace) {
963 // Is the target namespace protected against further registrations?
964 if (data->protectedNamespaces.contains(nameSpace)) {
965 QString failure(QCoreApplication::translate("qmlRegisterType",
966 "Cannot install element '%1' into protected namespace '%2'"));
967 data->typeRegistrationFailures.append(failure.arg(QString::fromUtf8(type.elementName)).arg(nameSpace));
973 int index = data->types.count();
975 QQmlType *dtype = new QQmlType(index, type);
977 data->types.append(dtype);
978 data->idToType.insert(dtype->typeId(), dtype);
979 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
981 if (!dtype->elementName().isEmpty())
982 data->nameToType.insertMulti(dtype->elementName(), dtype);
984 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
986 if (data->objects.size() <= type.typeId)
987 data->objects.resize(type.typeId + 16);
988 if (data->lists.size() <= type.listId)
989 data->lists.resize(type.listId + 16);
990 data->objects.setBit(type.typeId, true);
991 if (type.listId) data->lists.setBit(type.listId, true);
993 if (!dtype->module().isEmpty()) {
994 const QHashedString &mod = dtype->module();
996 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
997 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
999 module = new QQmlTypeModule;
1000 module->d->uri = versionedUri;
1001 data->uriToModule.insert(versionedUri, module);
1003 module->d->add(dtype);
1009 int registerSingletonType(const QQmlPrivate::RegisterSingletonType &api)
1011 QWriteLocker lock(metaTypeDataLock());
1013 QQmlMetaTypeData *data = metaTypeData();
1014 QString uri = QString::fromUtf8(api.uri);
1015 QQmlMetaType::SingletonType import;
1016 import.major = api.versionMajor;
1017 import.minor = api.versionMinor;
1018 import.script = api.scriptApi;
1019 import.qobject = api.qobjectApi;
1020 Q_ASSERT(api.typeName);
1021 import.typeName = QString::fromUtf8(api.typeName);
1022 import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
1024 if (data->singletonTypeExists(uri, import.typeName, import.major, import.minor)) {
1025 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);
1027 } else if (data->typeExists(uri, import.typeName, import.major, import.minor)) {
1028 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);
1032 int index = data->singletonTypeCount++;
1034 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
1036 QQmlMetaTypeData::SingletonTypeList apis;
1037 apis.singletonTypes << import;
1038 data->singletonTypes.insert(uri, apis);
1040 apiList->singletonTypes << import;
1041 apiList->sorted = false;
1049 This method is "over generalized" to allow us to (potentially) register more types of things in
1050 the future without adding exported symbols.
1052 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
1054 if (type == TypeRegistration) {
1055 return registerType(*reinterpret_cast<RegisterType *>(data));
1056 } else if (type == InterfaceRegistration) {
1057 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
1058 } else if (type == AutoParentRegistration) {
1059 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
1060 } else if (type == SingletonRegistration) {
1061 return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
1066 bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
1068 QQmlMetaTypeData *data = metaTypeData();
1070 // Has any type previously been installed to this namespace?
1071 QHashedString nameSpace(uri);
1072 foreach (const QQmlType *type, data->types)
1073 if (type->module() == nameSpace)
1079 void QQmlMetaType::protectNamespace(const QString &uri)
1081 QQmlMetaTypeData *data = metaTypeData();
1083 data->protectedNamespaces.insert(uri);
1086 void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
1088 QQmlMetaTypeData *data = metaTypeData();
1090 data->typeRegistrationNamespace = uri;
1091 data->typeRegistrationFailures.clear();
1094 QStringList QQmlMetaType::typeRegistrationFailures()
1096 QQmlMetaTypeData *data = metaTypeData();
1098 return data->typeRegistrationFailures;
1101 QReadWriteLock *QQmlMetaType::typeRegistrationLock()
1103 return metaTypeDataLock();
1107 Returns true if a module \a uri of any version is installed.
1109 bool QQmlMetaType::isAnyModule(const QString &uri)
1111 QReadLocker lock(metaTypeDataLock());
1112 QQmlMetaTypeData *data = metaTypeData();
1114 // first, check Types
1115 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
1116 iter != data->uriToModule.end(); ++iter) {
1117 if ((*iter)->module() == uri)
1121 // then, check SingletonTypes
1122 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
1130 Returns true if any type or API has been registered for the given \a module with at least
1131 versionMajor.versionMinor, or if types have been registered for \a module with at most
1132 versionMajor.versionMinor.
1134 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.
1136 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1138 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1139 QReadLocker lock(metaTypeDataLock());
1141 QQmlMetaTypeData *data = metaTypeData();
1143 // first, check Types
1144 QQmlTypeModule *tm =
1145 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1146 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1149 // then, check SingletonTypes
1150 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(module);
1152 foreach (const QQmlMetaType::SingletonType &mApi, apiList->singletonTypes) {
1153 if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
1161 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1163 QReadLocker lock(metaTypeDataLock());
1164 QQmlMetaTypeData *data = metaTypeData();
1165 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1168 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1170 QReadLocker lock(metaTypeDataLock());
1171 QQmlMetaTypeData *data = metaTypeData();
1172 return data->parentFunctions;
1175 static bool operator<(const QQmlMetaType::SingletonType &lhs, const QQmlMetaType::SingletonType &rhs)
1177 return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1180 QQmlMetaType::SingletonType
1181 QQmlMetaType::singletonType(const QString &uri, int versionMajor, int versionMinor)
1183 QReadLocker lock(metaTypeDataLock());
1184 QQmlMetaTypeData *data = metaTypeData();
1186 QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
1188 return SingletonType();
1190 if (apiList->sorted == false) {
1191 qSort(apiList->singletonTypes.begin(), apiList->singletonTypes.end());
1192 apiList->sorted = true;
1195 for (int ii = apiList->singletonTypes.count() - 1; ii >= 0; --ii) {
1196 const SingletonType &import = apiList->singletonTypes.at(ii);
1197 if (import.major == versionMajor && import.minor <= versionMinor)
1201 return SingletonType();
1204 QHash<QString, QList<QQmlMetaType::SingletonType> > QQmlMetaType::singletonTypes()
1206 QReadLocker lock(metaTypeDataLock());
1207 QQmlMetaTypeData *data = metaTypeData();
1209 QHash<QString, QList<SingletonType> > singletonTypes;
1210 QStringHash<QQmlMetaTypeData::SingletonTypeList>::ConstIterator it = data->singletonTypes.begin();
1211 for (; it != data->singletonTypes.end(); ++it)
1212 singletonTypes[it.key()] = it.value().singletonTypes;
1214 return singletonTypes;
1217 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1219 if (!isQObject(v.userType())) {
1220 if (ok) *ok = false;
1226 return *(QObject **)v.constData();
1229 bool QQmlMetaType::isQObject(int userType)
1231 if (userType == QMetaType::QObjectStar)
1234 QReadLocker lock(metaTypeDataLock());
1235 QQmlMetaTypeData *data = metaTypeData();
1236 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1240 Returns the item type for a list of type \a id.
1242 int QQmlMetaType::listType(int id)
1244 QReadLocker lock(metaTypeDataLock());
1245 QQmlMetaTypeData *data = metaTypeData();
1246 QQmlType *type = data->idToType.value(id);
1247 if (type && type->qListTypeId() == id)
1248 return type->typeId();
1253 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1255 QReadLocker lock(metaTypeDataLock());
1256 QQmlMetaTypeData *data = metaTypeData();
1258 QQmlType *type = data->metaObjectToType.value(mo);
1259 if (type && type->attachedPropertiesFunction())
1260 return type->attachedPropertiesId();
1265 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1269 QReadLocker lock(metaTypeDataLock());
1270 QQmlMetaTypeData *data = metaTypeData();
1271 return data->types.at(id)->attachedPropertiesFunction();
1274 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1276 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1278 return QMetaProperty();
1280 QMetaClassInfo info = metaObject->classInfo(idx);
1282 return QMetaProperty();
1284 idx = metaObject->indexOfProperty(info.value());
1286 return QMetaProperty();
1288 return metaObject->property(idx);
1291 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1294 return QMetaProperty();
1296 const QMetaObject *metaObject = obj->metaObject();
1297 return defaultProperty(metaObject);
1300 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1302 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1304 return QMetaMethod();
1306 QMetaClassInfo info = metaObject->classInfo(idx);
1308 return QMetaMethod();
1310 idx = metaObject->indexOfMethod(info.value());
1312 return QMetaMethod();
1314 return metaObject->method(idx);
1317 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1320 return QMetaMethod();
1322 const QMetaObject *metaObject = obj->metaObject();
1323 return defaultMethod(metaObject);
1326 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1330 if (userType == QMetaType::QObjectStar)
1333 QReadLocker lock(metaTypeDataLock());
1334 QQmlMetaTypeData *data = metaTypeData();
1335 if (userType < data->objects.size() && data->objects.testBit(userType))
1337 else if (userType < data->lists.size() && data->lists.testBit(userType))
1343 bool QQmlMetaType::isInterface(int userType)
1345 QReadLocker lock(metaTypeDataLock());
1346 QQmlMetaTypeData *data = metaTypeData();
1347 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1350 const char *QQmlMetaType::interfaceIId(int userType)
1352 QReadLocker lock(metaTypeDataLock());
1353 QQmlMetaTypeData *data = metaTypeData();
1354 QQmlType *type = data->idToType.value(userType);
1356 if (type && type->isInterface() && type->typeId() == userType)
1357 return type->interfaceIId();
1362 bool QQmlMetaType::isList(int userType)
1364 QReadLocker lock(metaTypeDataLock());
1365 QQmlMetaTypeData *data = metaTypeData();
1366 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1370 A custom string convertor allows you to specify a function pointer that
1371 returns a variant of \a type. For example, if you have written your own icon
1372 class that you want to support as an object property assignable in QML:
1375 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1376 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1379 The function pointer must be of the form:
1381 QVariant (*StringConverter)(const QString &);
1384 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1386 QWriteLocker lock(metaTypeDataLock());
1388 QQmlMetaTypeData *data = metaTypeData();
1389 if (data->stringConverters.contains(type))
1391 data->stringConverters.insert(type, converter);
1395 Return the custom string converter for \a type, previously installed through
1396 registerCustomStringConverter()
1398 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1400 QReadLocker lock(metaTypeDataLock());
1402 QQmlMetaTypeData *data = metaTypeData();
1403 return data->stringConverters.value(type);
1407 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1408 by \a version_major and \a version_minor.
1410 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1412 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1416 QHashedStringRef module(qualifiedName.constData(), slash);
1417 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1419 return qmlType(name, module, version_major, version_minor);
1423 Returns the type (if any) of \a name in \a module and version specified
1424 by \a version_major and \a version_minor.
1426 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1428 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1429 QReadLocker lock(metaTypeDataLock());
1430 QQmlMetaTypeData *data = metaTypeData();
1432 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1433 while (it != data->nameToType.end() && it.key() == name) {
1434 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1435 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1444 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1447 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1449 QReadLocker lock(metaTypeDataLock());
1450 QQmlMetaTypeData *data = metaTypeData();
1452 return data->metaObjectToType.value(metaObject);
1456 Returns the type (if any) that corresponds to the \a metaObject in version specified
1457 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1460 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1462 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1463 QReadLocker lock(metaTypeDataLock());
1464 QQmlMetaTypeData *data = metaTypeData();
1466 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1467 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1469 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1478 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1479 Returns null if no type is registered.
1481 QQmlType *QQmlMetaType::qmlType(int userType)
1483 QReadLocker lock(metaTypeDataLock());
1484 QQmlMetaTypeData *data = metaTypeData();
1486 QQmlType *type = data->idToType.value(userType);
1487 if (type && type->typeId() == userType)
1494 Returns the list of registered QML type names.
1496 QList<QString> QQmlMetaType::qmlTypeNames()
1498 QReadLocker lock(metaTypeDataLock());
1499 QQmlMetaTypeData *data = metaTypeData();
1501 QList<QString> names;
1502 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1503 while (it != data->nameToType.end()) {
1504 names += (*it)->qmlTypeName();
1512 Returns the list of registered QML types.
1514 QList<QQmlType*> QQmlMetaType::qmlTypes()
1516 QReadLocker lock(metaTypeDataLock());
1517 QQmlMetaTypeData *data = metaTypeData();
1519 return data->nameToType.values();
1522 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1526 id = QMetaType::type("QQuickAnchorLine");
1531 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1533 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1535 anchorLineCompareFunction = fun;
1538 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1540 Q_ASSERT(anchorLineCompareFunction != 0);
1541 return anchorLineCompareFunction(p1, p2);