1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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;
101 QList<QQmlPrivate::AutoParentFunction> parentFunctions;
103 QSet<QString> protectedNamespaces;
105 QString typeRegistrationNamespace;
106 QStringList typeRegistrationFailures;
109 class QQmlTypeModulePrivate
112 QQmlTypeModulePrivate()
113 : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
115 QQmlMetaTypeData::VersionedUri uri;
120 void add(QQmlType *);
122 QStringHash<QList<QQmlType *> > typeHash;
123 QList<QQmlType *> types;
126 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
127 Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, metaTypeDataLock, (QReadWriteLock::Recursive))
129 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
131 return v.uri.hash() ^ qHash(v.majorVersion);
134 QQmlMetaTypeData::QQmlMetaTypeData()
138 QQmlMetaTypeData::~QQmlMetaTypeData()
140 for (int i = 0; i < types.count(); ++i)
143 TypeModules::const_iterator i = uriToModule.constBegin();
144 for (; i != uriToModule.constEnd(); ++i)
148 class QQmlTypePrivate
155 void initEnums() const;
156 void insertEnums(const QMetaObject *metaObject) const;
158 bool m_isInterface : 1;
160 QHashedString m_module;
162 QString m_elementName;
165 int m_typeId; int m_listId;
167 mutable bool m_containsRevisionedAttributes;
168 mutable QQmlType *m_superType;
170 int m_allocationSize;
171 void (*m_newFunc)(void *);
172 QString m_noCreationReason;
174 const QMetaObject *m_baseMetaObject;
175 QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
176 const QMetaObject *m_attachedPropertiesType;
177 int m_attachedPropertiesId;
178 int m_parserStatusCast;
179 int m_propertyValueSourceCast;
180 int m_propertyValueInterceptorCast;
181 QObject *(*m_extFunc)(QObject *);
182 const QMetaObject *m_extMetaObject;
184 QQmlCustomParser *m_customParser;
185 mutable volatile bool m_isSetup:1;
186 mutable volatile bool m_isEnumSetup:1;
187 mutable bool m_haveSuperType:1;
188 mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
189 mutable QStringHash<int> m_enums;
190 QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo;
192 static QHash<const QMetaObject *, int> m_attachedPropertyIds;
195 // Avoid multiple fromUtf8(), copies and hashing of the module name.
196 // This is only called when metaTypeDataLock is locked.
197 static QHashedString moduleFromUtf8(const char *module)
200 return QHashedString();
202 static const char *lastModule = 0;
203 static QHashedString lastModuleStr;
205 // Separate plugins may have different strings at the same address
206 QHashedCStringRef currentModule(module, ::strlen(module));
207 if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
208 lastModuleStr = QString::fromUtf8(module);
209 lastModuleStr.hash();
213 return lastModuleStr;
216 void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
218 if (scriptCallback && scriptApi(e).isUndefined()) {
219 setScriptApi(e, scriptCallback(e, e));
220 } else if (qobjectCallback && !qobjectApi(e)) {
221 setQObjectApi(e, qobjectCallback(e, e));
225 void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
227 // cleans up the engine-specific singleton instances if they exist.
228 scriptApis.remove(e);
229 QObject *o = qobjectApis.take(e);
233 void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
235 qobjectApis.insert(e, o);
238 QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
240 return qobjectApis.value(e);
243 void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v)
245 scriptApis.insert(e, v);
248 QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
250 return scriptApis.value(e);
253 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
255 QQmlTypePrivate::QQmlTypePrivate()
256 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
257 m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
258 m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
259 m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
260 m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0)
264 QQmlTypePrivate::~QQmlTypePrivate()
266 delete m_singletonInstanceInfo;
269 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
270 : d(new QQmlTypePrivate)
272 d->m_isInterface = true;
273 d->m_iid = interface.iid;
274 d->m_typeId = interface.typeId;
275 d->m_listId = interface.listId;
279 d->m_version_maj = 0;
280 d->m_version_min = 0;
283 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
284 : d(new QQmlTypePrivate)
286 d->m_elementName = elementName;
287 d->m_module = moduleFromUtf8(type.uri);
289 d->m_version_maj = type.versionMajor;
290 d->m_version_min = type.versionMinor;
292 if (type.qobjectApi) {
293 if (type.version >= 1) // static metaobject added in version 1
294 d->m_baseMetaObject = type.instanceMetaObject;
295 if (type.version >= 2) // typeId added in version 2
296 d->m_typeId = type.typeId;
297 if (type.version >= 2) // revisions added in version 2
298 d->m_revision = type.revision;
304 d->m_singletonInstanceInfo = new SingletonInstanceInfo;
305 d->m_singletonInstanceInfo->scriptCallback = type.scriptApi;
306 d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi;
307 d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
308 d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
311 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
312 : d(new QQmlTypePrivate)
314 d->m_elementName = elementName;
315 d->m_module = moduleFromUtf8(type.uri);
317 d->m_version_maj = type.versionMajor;
318 d->m_version_min = type.versionMinor;
319 if (type.version >= 1) // revisions added in version 1
320 d->m_revision = type.revision;
321 d->m_typeId = type.typeId;
322 d->m_listId = type.listId;
323 d->m_allocationSize = type.objectSize;
324 d->m_newFunc = type.create;
325 d->m_noCreationReason = type.noCreationReason;
326 d->m_baseMetaObject = type.metaObject;
327 d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
328 d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
329 if (d->m_attachedPropertiesType) {
330 QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
331 if (iter == d->m_attachedPropertyIds.end())
332 iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
333 d->m_attachedPropertiesId = *iter;
335 d->m_attachedPropertiesId = -1;
337 d->m_parserStatusCast = type.parserStatusCast;
338 d->m_propertyValueSourceCast = type.valueSourceCast;
339 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
340 d->m_extFunc = type.extensionObjectCreate;
342 d->m_customParser = type.customParser;
344 if (type.extensionMetaObject)
345 d->m_extMetaObject = type.extensionMetaObject;
348 QQmlType::~QQmlType()
350 delete d->m_customParser;
354 const QHashedString &QQmlType::module() const
359 int QQmlType::majorVersion() const
361 return d->m_version_maj;
364 int QQmlType::minorVersion() const
366 return d->m_version_min;
369 bool QQmlType::availableInVersion(int vmajor, int vminor) const
371 Q_ASSERT(vmajor >= 0 && vminor >= 0);
372 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
375 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
377 Q_ASSERT(vmajor >= 0 && vminor >= 0);
378 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
381 // returns the nearest _registered_ super class
382 QQmlType *QQmlType::superType() const
384 if (!d->m_haveSuperType && d->m_baseMetaObject) {
385 const QMetaObject *mo = d->m_baseMetaObject->superClass();
386 while (mo && !d->m_superType) {
387 d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
388 mo = mo->superClass();
390 d->m_haveSuperType = true;
393 return d->m_superType;
396 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
397 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
400 builder.setClassName(ignoreEnd->className());
403 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
404 QMetaClassInfo info = mo->classInfo(ii);
406 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
407 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
410 builder.addClassInfo(info.name(), info.value());
415 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
416 QMetaProperty property = mo->property(ii);
418 int otherIndex = ignoreEnd->indexOfProperty(property.name());
419 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
420 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
423 builder.addProperty(property);
428 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
429 QMetaMethod method = mo->method(ii);
431 // More complex - need to search name
432 QByteArray name = method.name();
437 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
438 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
441 QMetaMethod other = ignoreEnd->method(ii);
443 found = name == other.name();
446 QMetaMethodBuilder m = builder.addMethod(method);
448 m.setAccess(QMetaMethod::Private);
452 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
453 QMetaEnum enumerator = mo->enumerator(ii);
455 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
456 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
459 builder.addEnumerator(enumerator);
464 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
467 i -= mo->propertyOffset();
468 if (i < 0 && mo->d.superdata)
469 return isPropertyRevisioned(mo->d.superdata, index);
471 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
472 if (i >= 0 && i < mop->propertyCount) {
473 int handle = mop->propertyData + 3*i;
474 int flags = mo->d.data[handle + 2];
476 return (flags & Revisioned);
482 void QQmlTypePrivate::init() const
484 if (m_isSetup) return;
486 QWriteLocker lock(metaTypeDataLock());
490 const QMetaObject *mo = m_baseMetaObject;
492 // singleton type without metaobject information
496 // Setup extended meta object
497 // XXX - very inefficient
499 QMetaObjectBuilder builder;
500 clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
501 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
502 QMetaObject *mmo = builder.toMetaObject();
503 mmo->d.superdata = mo;
504 QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
505 m_metaObjects << data;
508 mo = mo->d.superdata;
510 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
512 if (t->d->m_extFunc) {
513 QMetaObjectBuilder builder;
514 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
515 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
516 QMetaObject *mmo = builder.toMetaObject();
517 mmo->d.superdata = m_baseMetaObject;
518 if (!m_metaObjects.isEmpty())
519 m_metaObjects.last().metaObject->d.superdata = mmo;
520 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
521 m_metaObjects << data;
524 mo = mo->d.superdata;
527 for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
528 m_metaObjects[ii].propertyOffset =
529 m_metaObjects.at(ii).metaObject->propertyOffset();
530 m_metaObjects[ii].methodOffset =
531 m_metaObjects.at(ii).metaObject->methodOffset();
534 // Check for revisioned details
536 const QMetaObject *mo = 0;
537 if (m_metaObjects.isEmpty())
538 mo = m_baseMetaObject;
540 mo = m_metaObjects.first().metaObject;
542 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
543 if (isPropertyRevisioned(mo, ii))
544 m_containsRevisionedAttributes = true;
547 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
548 if (mo->method(ii).revision() != 0)
549 m_containsRevisionedAttributes = true;
557 void QQmlTypePrivate::initEnums() const
559 if (m_isEnumSetup) return;
563 QWriteLocker lock(metaTypeDataLock());
564 if (m_isEnumSetup) return;
566 if (m_baseMetaObject) // could be singleton type without metaobject
567 insertEnums(m_baseMetaObject);
569 m_isEnumSetup = true;
572 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
574 // Add any enum values defined by 'related' classes
575 if (metaObject->d.relatedMetaObjects) {
576 const QMetaObject **related = metaObject->d.relatedMetaObjects;
579 insertEnums(*related++);
583 // Add any enum values defined by this class, overwriting any inherited values
584 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
585 QMetaEnum e = metaObject->enumerator(ii);
586 for (int jj = 0; jj < e.keyCount(); ++jj)
587 m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
591 QByteArray QQmlType::typeName() const
593 if (d->m_singletonInstanceInfo)
594 return d->m_singletonInstanceInfo->typeName.toUtf8();
595 if (d->m_baseMetaObject)
596 return d->m_baseMetaObject->className();
601 const QString &QQmlType::elementName() const
603 return d->m_elementName;
606 const QString &QQmlType::qmlTypeName() const
608 if (d->m_name.isEmpty()) {
609 if (!d->m_module.isEmpty())
610 d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
612 d->m_name = d->m_elementName;
618 QObject *QQmlType::create() const
622 QObject *rv = (QObject *)operator new(d->m_allocationSize);
625 if (rv && !d->m_metaObjects.isEmpty())
626 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
631 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
635 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
638 if (rv && !d->m_metaObjects.isEmpty())
639 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
642 *memory = ((char *)rv) + d->m_allocationSize;
645 QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
647 return d->m_singletonInstanceInfo;
650 QQmlCustomParser *QQmlType::customParser() const
652 return d->m_customParser;
655 QQmlType::CreateFunc QQmlType::createFunction() const
660 QString QQmlType::noCreationReason() const
662 return d->m_noCreationReason;
665 int QQmlType::createSize() const
667 return d->m_allocationSize;
670 bool QQmlType::isCreatable() const
672 return d->m_newFunc != 0;
675 bool QQmlType::isExtendedType() const
679 return !d->m_metaObjects.isEmpty();
682 bool QQmlType::isSingleton() const
684 return d->m_singletonInstanceInfo != 0;
687 bool QQmlType::isInterface() const
689 return d->m_isInterface;
692 int QQmlType::typeId() const
697 int QQmlType::qListTypeId() const
702 const QMetaObject *QQmlType::metaObject() const
706 if (d->m_metaObjects.isEmpty())
707 return d->m_baseMetaObject;
709 return d->m_metaObjects.first().metaObject;
713 const QMetaObject *QQmlType::baseMetaObject() const
715 return d->m_baseMetaObject;
718 bool QQmlType::containsRevisionedAttributes() const
722 return d->m_containsRevisionedAttributes;
725 int QQmlType::metaObjectRevision() const
727 return d->m_revision;
730 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
732 return d->m_attachedPropertiesFunc;
735 const QMetaObject *QQmlType::attachedPropertiesType() const
737 return d->m_attachedPropertiesType;
741 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
742 for the case that a single class is registered under two or more names (eg. Item in
743 Qt 4.7 and QtQuick 1.0).
745 int QQmlType::attachedPropertiesId() const
747 return d->m_attachedPropertiesId;
750 int QQmlType::parserStatusCast() const
752 return d->m_parserStatusCast;
755 int QQmlType::propertyValueSourceCast() const
757 return d->m_propertyValueSourceCast;
760 int QQmlType::propertyValueInterceptorCast() const
762 return d->m_propertyValueInterceptorCast;
765 const char *QQmlType::interfaceIId() const
770 int QQmlType::index() const
775 int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
782 int *rv = d->m_enums.value(name);
790 int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
797 int *rv = d->m_enums.value(name);
805 int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
812 int *rv = d->m_enums.value(name);
820 QQmlTypeModule::QQmlTypeModule()
821 : d(new QQmlTypeModulePrivate)
825 QQmlTypeModule::~QQmlTypeModule()
830 QString QQmlTypeModule::module() const
835 int QQmlTypeModule::majorVersion() const
837 return d->uri.majorVersion;
840 int QQmlTypeModule::minimumMinorVersion() const
842 return d->minMinorVersion;
845 int QQmlTypeModule::maximumMinorVersion() const
847 return d->maxMinorVersion;
850 void QQmlTypeModulePrivate::add(QQmlType *type)
852 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
853 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
855 QList<QQmlType *> &list = typeHash[type->elementName()];
856 for (int ii = 0; ii < list.count(); ++ii) {
857 if (list.at(ii)->minorVersion() < type->minorVersion()) {
858 list.insert(ii, type);
865 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
867 QReadLocker lock(metaTypeDataLock());
869 QList<QQmlType *> *types = d->typeHash.value(name);
870 if (!types) return 0;
872 for (int ii = 0; ii < types->count(); ++ii)
873 if (types->at(ii)->minorVersion() <= minor)
874 return types->at(ii);
879 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
881 QReadLocker lock(metaTypeDataLock());
883 QList<QQmlType *> *types = d->typeHash.value(name);
884 if (!types) return 0;
886 for (int ii = 0; ii < types->count(); ++ii)
887 if (types->at(ii)->minorVersion() <= minor)
888 return types->at(ii);
893 QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
895 QReadLocker lock(metaTypeDataLock());
897 QList<QQmlType *> retn;
898 for (int ii = 0; ii < d->types.count(); ++ii) {
899 QQmlType *curr = d->types.at(ii);
900 if (curr->isSingleton() && curr->minorVersion() <= minor)
908 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
909 : m_module(0), m_minor(0)
913 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
914 : m_module(module), m_minor(minor)
917 Q_ASSERT(m_minor >= 0);
920 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
921 : m_module(o.m_module), m_minor(o.m_minor)
925 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
927 m_module = o.m_module;
932 QQmlTypeModule *QQmlTypeModuleVersion::module() const
937 int QQmlTypeModuleVersion::minorVersion() const
942 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
944 if (m_module) return m_module->type(name, m_minor);
948 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
950 if (m_module) return m_module->type(name, m_minor);
955 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
957 QWriteLocker lock(metaTypeDataLock());
958 QQmlMetaTypeData *data = metaTypeData();
960 data->parentFunctions.append(autoparent.function);
962 return data->parentFunctions.count() - 1;
965 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
967 if (interface.version > 0)
968 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
970 QWriteLocker lock(metaTypeDataLock());
971 QQmlMetaTypeData *data = metaTypeData();
973 int index = data->types.count();
975 QQmlType *type = new QQmlType(index, interface);
977 data->types.append(type);
978 data->idToType.insert(type->typeId(), type);
979 data->idToType.insert(type->qListTypeId(), type);
980 // XXX No insertMulti, so no multi-version interfaces?
981 if (!type->elementName().isEmpty())
982 data->nameToType.insert(type->elementName(), type);
984 if (data->interfaces.size() <= interface.typeId)
985 data->interfaces.resize(interface.typeId + 16);
986 if (data->lists.size() <= interface.listId)
987 data->lists.resize(interface.listId + 16);
988 data->interfaces.setBit(interface.typeId, true);
989 data->lists.setBit(interface.listId, true);
994 QString registrationTypeString(QQmlType::RegistrationType typeType)
997 if (typeType == QQmlType::CppType)
998 typeStr = QStringLiteral("element");
999 else if (typeType == QQmlType::SingletonType)
1000 typeStr = QStringLiteral("singleton type");
1004 // NOTE: caller must hold a QWriteLocker on "data"
1005 bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
1007 if (!typeName.isEmpty()) {
1008 int typeNameLen = typeName.length();
1009 for (int ii = 0; ii < typeNameLen; ++ii) {
1010 if (!typeName.at(ii).isLetterOrNumber()) {
1011 QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
1012 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
1018 if (uri && !typeName.isEmpty()) {
1019 QString nameSpace = moduleFromUtf8(uri);
1021 if (!data->typeRegistrationNamespace.isEmpty()) {
1022 // We can only install types into the registered namespace
1023 if (nameSpace != data->typeRegistrationNamespace) {
1024 QString failure(QCoreApplication::translate("qmlRegisterType",
1025 "Cannot install %1 '%2' into unregistered namespace '%3'"));
1026 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
1029 } else if (data->typeRegistrationNamespace != nameSpace) {
1030 // Is the target namespace protected against further registrations?
1031 if (data->protectedNamespaces.contains(nameSpace)) {
1032 QString failure(QCoreApplication::translate("qmlRegisterType",
1033 "Cannot install %1 '%2' into protected namespace '%3'"));
1034 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
1043 int registerType(const QQmlPrivate::RegisterType &type)
1045 QWriteLocker lock(metaTypeDataLock());
1046 QQmlMetaTypeData *data = metaTypeData();
1047 QString elementName = QString::fromUtf8(type.elementName);
1048 if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
1051 int index = data->types.count();
1053 QQmlType *dtype = new QQmlType(index, elementName, type);
1055 data->types.append(dtype);
1056 data->idToType.insert(dtype->typeId(), dtype);
1057 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
1059 if (!dtype->elementName().isEmpty())
1060 data->nameToType.insertMulti(dtype->elementName(), dtype);
1062 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
1064 if (data->objects.size() <= type.typeId)
1065 data->objects.resize(type.typeId + 16);
1066 if (data->lists.size() <= type.listId)
1067 data->lists.resize(type.listId + 16);
1068 data->objects.setBit(type.typeId, true);
1069 if (type.listId) data->lists.setBit(type.listId, true);
1071 if (!dtype->module().isEmpty()) {
1072 const QHashedString &mod = dtype->module();
1074 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
1075 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1077 module = new QQmlTypeModule;
1078 module->d->uri = versionedUri;
1079 data->uriToModule.insert(versionedUri, module);
1081 module->d->add(dtype);
1087 int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
1089 QWriteLocker lock(metaTypeDataLock());
1090 QQmlMetaTypeData *data = metaTypeData();
1091 QString typeName = QString::fromUtf8(type.typeName);
1092 if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
1095 int index = data->types.count();
1097 QQmlType *dtype = new QQmlType(index, typeName, type);
1099 data->types.append(dtype);
1100 data->idToType.insert(dtype->typeId(), dtype);
1102 if (!dtype->elementName().isEmpty())
1103 data->nameToType.insertMulti(dtype->elementName(), dtype);
1105 if (dtype->baseMetaObject())
1106 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
1109 if (data->objects.size() <= type.typeId)
1110 data->objects.resize(type.typeId + 16);
1111 data->objects.setBit(type.typeId, true);
1114 if (!dtype->module().isEmpty()) {
1115 const QHashedString &mod = dtype->module();
1117 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
1118 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1120 module = new QQmlTypeModule;
1121 module->d->uri = versionedUri;
1122 data->uriToModule.insert(versionedUri, module);
1124 module->d->add(dtype);
1132 This method is "over generalized" to allow us to (potentially) register more types of things in
1133 the future without adding exported symbols.
1135 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
1137 if (type == TypeRegistration) {
1138 return registerType(*reinterpret_cast<RegisterType *>(data));
1139 } else if (type == InterfaceRegistration) {
1140 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
1141 } else if (type == AutoParentRegistration) {
1142 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
1143 } else if (type == SingletonRegistration) {
1144 return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
1149 bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
1151 QQmlMetaTypeData *data = metaTypeData();
1153 // Has any type previously been installed to this namespace?
1154 QHashedString nameSpace(uri);
1155 foreach (const QQmlType *type, data->types)
1156 if (type->module() == nameSpace)
1162 void QQmlMetaType::protectNamespace(const QString &uri)
1164 QQmlMetaTypeData *data = metaTypeData();
1166 data->protectedNamespaces.insert(uri);
1169 void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
1171 QQmlMetaTypeData *data = metaTypeData();
1173 data->typeRegistrationNamespace = uri;
1174 data->typeRegistrationFailures.clear();
1177 QStringList QQmlMetaType::typeRegistrationFailures()
1179 QQmlMetaTypeData *data = metaTypeData();
1181 return data->typeRegistrationFailures;
1184 QReadWriteLock *QQmlMetaType::typeRegistrationLock()
1186 return metaTypeDataLock();
1190 Returns true if a module \a uri of any version is installed.
1192 bool QQmlMetaType::isAnyModule(const QString &uri)
1194 QReadLocker lock(metaTypeDataLock());
1195 QQmlMetaTypeData *data = metaTypeData();
1197 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
1198 iter != data->uriToModule.end(); ++iter) {
1199 if ((*iter)->module() == uri)
1207 Returns true if any type or API has been registered for the given \a module with at least
1208 versionMajor.versionMinor, or if types have been registered for \a module with at most
1209 versionMajor.versionMinor.
1211 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.
1213 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1215 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1216 QReadLocker lock(metaTypeDataLock());
1218 QQmlMetaTypeData *data = metaTypeData();
1220 // first, check Types
1221 QQmlTypeModule *tm =
1222 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1223 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1229 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1231 QReadLocker lock(metaTypeDataLock());
1232 QQmlMetaTypeData *data = metaTypeData();
1233 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1236 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1238 QReadLocker lock(metaTypeDataLock());
1239 QQmlMetaTypeData *data = metaTypeData();
1240 return data->parentFunctions;
1243 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1245 if (!isQObject(v.userType())) {
1246 if (ok) *ok = false;
1252 return *(QObject **)v.constData();
1255 bool QQmlMetaType::isQObject(int userType)
1257 if (userType == QMetaType::QObjectStar)
1260 QReadLocker lock(metaTypeDataLock());
1261 QQmlMetaTypeData *data = metaTypeData();
1262 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1266 Returns the item type for a list of type \a id.
1268 int QQmlMetaType::listType(int id)
1270 QReadLocker lock(metaTypeDataLock());
1271 QQmlMetaTypeData *data = metaTypeData();
1272 QQmlType *type = data->idToType.value(id);
1273 if (type && type->qListTypeId() == id)
1274 return type->typeId();
1279 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1281 QReadLocker lock(metaTypeDataLock());
1282 QQmlMetaTypeData *data = metaTypeData();
1284 QQmlType *type = data->metaObjectToType.value(mo);
1285 if (type && type->attachedPropertiesFunction())
1286 return type->attachedPropertiesId();
1291 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1295 QReadLocker lock(metaTypeDataLock());
1296 QQmlMetaTypeData *data = metaTypeData();
1297 return data->types.at(id)->attachedPropertiesFunction();
1300 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1302 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1304 return QMetaProperty();
1306 QMetaClassInfo info = metaObject->classInfo(idx);
1308 return QMetaProperty();
1310 idx = metaObject->indexOfProperty(info.value());
1312 return QMetaProperty();
1314 return metaObject->property(idx);
1317 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1320 return QMetaProperty();
1322 const QMetaObject *metaObject = obj->metaObject();
1323 return defaultProperty(metaObject);
1326 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1328 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1330 return QMetaMethod();
1332 QMetaClassInfo info = metaObject->classInfo(idx);
1334 return QMetaMethod();
1336 idx = metaObject->indexOfMethod(info.value());
1338 return QMetaMethod();
1340 return metaObject->method(idx);
1343 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1346 return QMetaMethod();
1348 const QMetaObject *metaObject = obj->metaObject();
1349 return defaultMethod(metaObject);
1352 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1356 if (userType == QMetaType::QObjectStar)
1359 QReadLocker lock(metaTypeDataLock());
1360 QQmlMetaTypeData *data = metaTypeData();
1361 if (userType < data->objects.size() && data->objects.testBit(userType))
1363 else if (userType < data->lists.size() && data->lists.testBit(userType))
1369 bool QQmlMetaType::isInterface(int userType)
1371 QReadLocker lock(metaTypeDataLock());
1372 QQmlMetaTypeData *data = metaTypeData();
1373 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1376 const char *QQmlMetaType::interfaceIId(int userType)
1378 QReadLocker lock(metaTypeDataLock());
1379 QQmlMetaTypeData *data = metaTypeData();
1380 QQmlType *type = data->idToType.value(userType);
1382 if (type && type->isInterface() && type->typeId() == userType)
1383 return type->interfaceIId();
1388 bool QQmlMetaType::isList(int userType)
1390 QReadLocker lock(metaTypeDataLock());
1391 QQmlMetaTypeData *data = metaTypeData();
1392 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1396 A custom string convertor allows you to specify a function pointer that
1397 returns a variant of \a type. For example, if you have written your own icon
1398 class that you want to support as an object property assignable in QML:
1401 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1402 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1405 The function pointer must be of the form:
1407 QVariant (*StringConverter)(const QString &);
1410 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1412 QWriteLocker lock(metaTypeDataLock());
1414 QQmlMetaTypeData *data = metaTypeData();
1415 if (data->stringConverters.contains(type))
1417 data->stringConverters.insert(type, converter);
1421 Return the custom string converter for \a type, previously installed through
1422 registerCustomStringConverter()
1424 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1426 QReadLocker lock(metaTypeDataLock());
1428 QQmlMetaTypeData *data = metaTypeData();
1429 return data->stringConverters.value(type);
1433 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1434 by \a version_major and \a version_minor.
1436 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1438 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1442 QHashedStringRef module(qualifiedName.constData(), slash);
1443 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1445 return qmlType(name, module, version_major, version_minor);
1449 Returns the type (if any) of \a name in \a module and version specified
1450 by \a version_major and \a version_minor.
1452 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1454 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1455 QReadLocker lock(metaTypeDataLock());
1456 QQmlMetaTypeData *data = metaTypeData();
1458 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1459 while (it != data->nameToType.end() && it.key() == name) {
1460 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1461 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1470 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1473 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1475 QReadLocker lock(metaTypeDataLock());
1476 QQmlMetaTypeData *data = metaTypeData();
1478 return data->metaObjectToType.value(metaObject);
1482 Returns the type (if any) that corresponds to the \a metaObject in version specified
1483 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1486 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1488 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1489 QReadLocker lock(metaTypeDataLock());
1490 QQmlMetaTypeData *data = metaTypeData();
1492 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1493 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1495 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1504 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1505 Returns null if no type is registered.
1507 QQmlType *QQmlMetaType::qmlType(int userType)
1509 QReadLocker lock(metaTypeDataLock());
1510 QQmlMetaTypeData *data = metaTypeData();
1512 QQmlType *type = data->idToType.value(userType);
1513 if (type && type->typeId() == userType)
1520 Returns the list of registered QML type names.
1522 QList<QString> QQmlMetaType::qmlTypeNames()
1524 QReadLocker lock(metaTypeDataLock());
1525 QQmlMetaTypeData *data = metaTypeData();
1527 QList<QString> names;
1528 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1529 while (it != data->nameToType.end()) {
1530 names += (*it)->qmlTypeName();
1538 Returns the list of registered QML types.
1540 QList<QQmlType*> QQmlMetaType::qmlTypes()
1542 QReadLocker lock(metaTypeDataLock());
1543 QQmlMetaTypeData *data = metaTypeData();
1545 return data->nameToType.values();
1549 Returns the list of registered QML singleton types.
1551 QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
1553 QReadLocker lock(metaTypeDataLock());
1554 QQmlMetaTypeData *data = metaTypeData();
1556 QList<QQmlType*> alltypes = data->nameToType.values();
1557 QList<QQmlType*> retn;
1558 foreach (QQmlType* t, alltypes) {
1559 if (t->isSingleton()) {
1567 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1571 id = QMetaType::type("QQuickAnchorLine");
1576 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1578 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1580 anchorLineCompareFunction = fun;
1583 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1585 Q_ASSERT(anchorLineCompareFunction != 0);
1586 return anchorLineCompareFunction(p1, p2);