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;
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)
144 class QQmlTypePrivate
151 void initEnums() const;
152 void insertEnums(const QMetaObject *metaObject) const;
154 bool m_isInterface : 1;
156 QHashedString m_module;
158 QString m_elementName;
161 int m_typeId; int m_listId;
163 mutable bool m_containsRevisionedAttributes;
164 mutable QQmlType *m_superType;
166 int m_allocationSize;
167 void (*m_newFunc)(void *);
168 QString m_noCreationReason;
170 const QMetaObject *m_baseMetaObject;
171 QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
172 const QMetaObject *m_attachedPropertiesType;
173 int m_attachedPropertiesId;
174 int m_parserStatusCast;
175 int m_propertyValueSourceCast;
176 int m_propertyValueInterceptorCast;
177 QObject *(*m_extFunc)(QObject *);
178 const QMetaObject *m_extMetaObject;
180 QQmlCustomParser *m_customParser;
181 mutable volatile bool m_isSetup:1;
182 mutable volatile bool m_isEnumSetup:1;
183 mutable bool m_haveSuperType:1;
184 mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
185 mutable QStringHash<int> m_enums;
186 QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo;
188 static QHash<const QMetaObject *, int> m_attachedPropertyIds;
191 // Avoid multiple fromUtf8(), copies and hashing of the module name.
192 // This is only called when metaTypeDataLock is locked.
193 static QHashedString moduleFromUtf8(const char *module)
196 return QHashedString();
198 static const char *lastModule = 0;
199 static QHashedString lastModuleStr;
201 // Separate plugins may have different strings at the same address
202 QHashedCStringRef currentModule(module, ::strlen(module));
203 if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
204 lastModuleStr = QString::fromUtf8(module);
205 lastModuleStr.hash();
209 return lastModuleStr;
212 void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
214 if (scriptCallback && scriptApi(e).isUndefined()) {
215 setScriptApi(e, scriptCallback(e, e));
216 } else if (qobjectCallback && !qobjectApi(e)) {
217 setQObjectApi(e, qobjectCallback(e, e));
221 void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
223 // cleans up the engine-specific singleton instances if they exist.
224 scriptApis.remove(e);
225 QObject *o = qobjectApis.take(e);
229 void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
231 qobjectApis.insert(e, o);
234 QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
236 return qobjectApis.value(e);
239 void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v)
241 scriptApis.insert(e, v);
244 QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
246 return scriptApis.value(e);
249 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
251 QQmlTypePrivate::QQmlTypePrivate()
252 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
253 m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
254 m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
255 m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
256 m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0)
260 QQmlTypePrivate::~QQmlTypePrivate()
262 delete m_singletonInstanceInfo;
265 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
266 : d(new QQmlTypePrivate)
268 d->m_isInterface = true;
269 d->m_iid = interface.iid;
270 d->m_typeId = interface.typeId;
271 d->m_listId = interface.listId;
275 d->m_version_maj = 0;
276 d->m_version_min = 0;
279 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
280 : d(new QQmlTypePrivate)
282 d->m_elementName = elementName;
283 d->m_module = moduleFromUtf8(type.uri);
285 d->m_version_maj = type.versionMajor;
286 d->m_version_min = type.versionMinor;
288 if (type.qobjectApi) {
289 if (type.version >= 1) // static metaobject added in version 1
290 d->m_baseMetaObject = type.instanceMetaObject;
291 if (type.version >= 2) // typeId added in version 2
292 d->m_typeId = type.typeId;
293 if (type.version >= 2) // revisions added in version 2
294 d->m_revision = type.revision;
300 d->m_singletonInstanceInfo = new SingletonInstanceInfo;
301 d->m_singletonInstanceInfo->scriptCallback = type.scriptApi;
302 d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi;
303 d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
304 d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
307 QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
308 : d(new QQmlTypePrivate)
310 d->m_elementName = elementName;
311 d->m_module = moduleFromUtf8(type.uri);
313 d->m_version_maj = type.versionMajor;
314 d->m_version_min = type.versionMinor;
315 if (type.version >= 1) // revisions added in version 1
316 d->m_revision = type.revision;
317 d->m_typeId = type.typeId;
318 d->m_listId = type.listId;
319 d->m_allocationSize = type.objectSize;
320 d->m_newFunc = type.create;
321 d->m_noCreationReason = type.noCreationReason;
322 d->m_baseMetaObject = type.metaObject;
323 d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
324 d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
325 if (d->m_attachedPropertiesType) {
326 QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
327 if (iter == d->m_attachedPropertyIds.end())
328 iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
329 d->m_attachedPropertiesId = *iter;
331 d->m_attachedPropertiesId = -1;
333 d->m_parserStatusCast = type.parserStatusCast;
334 d->m_propertyValueSourceCast = type.valueSourceCast;
335 d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
336 d->m_extFunc = type.extensionObjectCreate;
338 d->m_customParser = type.customParser;
340 if (type.extensionMetaObject)
341 d->m_extMetaObject = type.extensionMetaObject;
344 QQmlType::~QQmlType()
346 delete d->m_customParser;
350 const QHashedString &QQmlType::module() const
355 int QQmlType::majorVersion() const
357 return d->m_version_maj;
360 int QQmlType::minorVersion() const
362 return d->m_version_min;
365 bool QQmlType::availableInVersion(int vmajor, int vminor) const
367 Q_ASSERT(vmajor >= 0 && vminor >= 0);
368 return vmajor == d->m_version_maj && vminor >= d->m_version_min;
371 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
373 Q_ASSERT(vmajor >= 0 && vminor >= 0);
374 return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
377 // returns the nearest _registered_ super class
378 QQmlType *QQmlType::superType() const
380 if (!d->m_haveSuperType && d->m_baseMetaObject) {
381 const QMetaObject *mo = d->m_baseMetaObject->superClass();
382 while (mo && !d->m_superType) {
383 d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
384 mo = mo->superClass();
386 d->m_haveSuperType = true;
389 return d->m_superType;
392 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
393 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
396 builder.setClassName(ignoreEnd->className());
399 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
400 QMetaClassInfo info = mo->classInfo(ii);
402 int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
403 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
406 builder.addClassInfo(info.name(), info.value());
411 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
412 QMetaProperty property = mo->property(ii);
414 int otherIndex = ignoreEnd->indexOfProperty(property.name());
415 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
416 builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
419 builder.addProperty(property);
424 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
425 QMetaMethod method = mo->method(ii);
427 // More complex - need to search name
428 QByteArray name = method.name();
433 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
434 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
437 QMetaMethod other = ignoreEnd->method(ii);
439 found = name == other.name();
442 QMetaMethodBuilder m = builder.addMethod(method);
444 m.setAccess(QMetaMethod::Private);
448 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
449 QMetaEnum enumerator = mo->enumerator(ii);
451 int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
452 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
455 builder.addEnumerator(enumerator);
460 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
463 i -= mo->propertyOffset();
464 if (i < 0 && mo->d.superdata)
465 return isPropertyRevisioned(mo->d.superdata, index);
467 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
468 if (i >= 0 && i < mop->propertyCount) {
469 int handle = mop->propertyData + 3*i;
470 int flags = mo->d.data[handle + 2];
472 return (flags & Revisioned);
478 void QQmlTypePrivate::init() const
480 if (m_isSetup) return;
482 QWriteLocker lock(metaTypeDataLock());
486 const QMetaObject *mo = m_baseMetaObject;
488 // singleton type without metaobject information
492 // Setup extended meta object
493 // XXX - very inefficient
495 QMetaObjectBuilder builder;
496 clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
497 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
498 QMetaObject *mmo = builder.toMetaObject();
499 mmo->d.superdata = mo;
500 QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
501 m_metaObjects << data;
504 mo = mo->d.superdata;
506 QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
508 if (t->d->m_extFunc) {
509 QMetaObjectBuilder builder;
510 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
511 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
512 QMetaObject *mmo = builder.toMetaObject();
513 mmo->d.superdata = m_baseMetaObject;
514 if (!m_metaObjects.isEmpty())
515 m_metaObjects.last().metaObject->d.superdata = mmo;
516 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
517 m_metaObjects << data;
520 mo = mo->d.superdata;
523 for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
524 m_metaObjects[ii].propertyOffset =
525 m_metaObjects.at(ii).metaObject->propertyOffset();
526 m_metaObjects[ii].methodOffset =
527 m_metaObjects.at(ii).metaObject->methodOffset();
530 // Check for revisioned details
532 const QMetaObject *mo = 0;
533 if (m_metaObjects.isEmpty())
534 mo = m_baseMetaObject;
536 mo = m_metaObjects.first().metaObject;
538 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
539 if (isPropertyRevisioned(mo, ii))
540 m_containsRevisionedAttributes = true;
543 for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
544 if (mo->method(ii).revision() != 0)
545 m_containsRevisionedAttributes = true;
553 void QQmlTypePrivate::initEnums() const
555 if (m_isEnumSetup) return;
559 QWriteLocker lock(metaTypeDataLock());
560 if (m_isEnumSetup) return;
562 if (m_baseMetaObject) // could be singleton type without metaobject
563 insertEnums(m_baseMetaObject);
565 m_isEnumSetup = true;
568 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
570 // Add any enum values defined by 'related' classes
571 if (metaObject->d.relatedMetaObjects) {
572 const QMetaObject **related = metaObject->d.relatedMetaObjects;
575 insertEnums(*related++);
579 // Add any enum values defined by this class, overwriting any inherited values
580 for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
581 QMetaEnum e = metaObject->enumerator(ii);
582 for (int jj = 0; jj < e.keyCount(); ++jj)
583 m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
587 QByteArray QQmlType::typeName() const
589 if (d->m_singletonInstanceInfo)
590 return d->m_singletonInstanceInfo->typeName.toUtf8();
591 if (d->m_baseMetaObject)
592 return d->m_baseMetaObject->className();
597 const QString &QQmlType::elementName() const
599 return d->m_elementName;
602 const QString &QQmlType::qmlTypeName() const
604 if (d->m_name.isEmpty()) {
605 if (!d->m_module.isEmpty())
606 d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
608 d->m_name = d->m_elementName;
614 QObject *QQmlType::create() const
618 QObject *rv = (QObject *)operator new(d->m_allocationSize);
621 if (rv && !d->m_metaObjects.isEmpty())
622 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
627 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
631 QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
634 if (rv && !d->m_metaObjects.isEmpty())
635 (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
638 *memory = ((char *)rv) + d->m_allocationSize;
641 QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
643 return d->m_singletonInstanceInfo;
646 QQmlCustomParser *QQmlType::customParser() const
648 return d->m_customParser;
651 QQmlType::CreateFunc QQmlType::createFunction() const
656 QString QQmlType::noCreationReason() const
658 return d->m_noCreationReason;
661 int QQmlType::createSize() const
663 return d->m_allocationSize;
666 bool QQmlType::isCreatable() const
668 return d->m_newFunc != 0;
671 bool QQmlType::isExtendedType() const
675 return !d->m_metaObjects.isEmpty();
678 bool QQmlType::isSingleton() const
680 return d->m_singletonInstanceInfo != 0;
683 bool QQmlType::isInterface() const
685 return d->m_isInterface;
688 int QQmlType::typeId() const
693 int QQmlType::qListTypeId() const
698 const QMetaObject *QQmlType::metaObject() const
702 if (d->m_metaObjects.isEmpty())
703 return d->m_baseMetaObject;
705 return d->m_metaObjects.first().metaObject;
709 const QMetaObject *QQmlType::baseMetaObject() const
711 return d->m_baseMetaObject;
714 bool QQmlType::containsRevisionedAttributes() const
718 return d->m_containsRevisionedAttributes;
721 int QQmlType::metaObjectRevision() const
723 return d->m_revision;
726 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
728 return d->m_attachedPropertiesFunc;
731 const QMetaObject *QQmlType::attachedPropertiesType() const
733 return d->m_attachedPropertiesType;
737 This is the id passed to qmlAttachedPropertiesById(). This is different from the index
738 for the case that a single class is registered under two or more names (eg. Item in
739 Qt 4.7 and QtQuick 1.0).
741 int QQmlType::attachedPropertiesId() const
743 return d->m_attachedPropertiesId;
746 int QQmlType::parserStatusCast() const
748 return d->m_parserStatusCast;
751 int QQmlType::propertyValueSourceCast() const
753 return d->m_propertyValueSourceCast;
756 int QQmlType::propertyValueInterceptorCast() const
758 return d->m_propertyValueInterceptorCast;
761 const char *QQmlType::interfaceIId() const
766 int QQmlType::index() const
771 int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
778 int *rv = d->m_enums.value(name);
786 int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
793 int *rv = d->m_enums.value(name);
801 int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
808 int *rv = d->m_enums.value(name);
816 QQmlTypeModule::QQmlTypeModule()
817 : d(new QQmlTypeModulePrivate)
821 QQmlTypeModule::~QQmlTypeModule()
826 QString QQmlTypeModule::module() const
831 int QQmlTypeModule::majorVersion() const
833 return d->uri.majorVersion;
836 int QQmlTypeModule::minimumMinorVersion() const
838 return d->minMinorVersion;
841 int QQmlTypeModule::maximumMinorVersion() const
843 return d->maxMinorVersion;
846 void QQmlTypeModulePrivate::add(QQmlType *type)
848 minMinorVersion = qMin(minMinorVersion, type->minorVersion());
849 maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
851 QList<QQmlType *> &list = typeHash[type->elementName()];
852 for (int ii = 0; ii < list.count(); ++ii) {
853 if (list.at(ii)->minorVersion() < type->minorVersion()) {
854 list.insert(ii, type);
861 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
863 QReadLocker lock(metaTypeDataLock());
865 QList<QQmlType *> *types = d->typeHash.value(name);
866 if (!types) return 0;
868 for (int ii = 0; ii < types->count(); ++ii)
869 if (types->at(ii)->minorVersion() <= minor)
870 return types->at(ii);
875 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
877 QReadLocker lock(metaTypeDataLock());
879 QList<QQmlType *> *types = d->typeHash.value(name);
880 if (!types) return 0;
882 for (int ii = 0; ii < types->count(); ++ii)
883 if (types->at(ii)->minorVersion() <= minor)
884 return types->at(ii);
889 QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
891 QReadLocker lock(metaTypeDataLock());
893 QList<QQmlType *> retn;
894 for (int ii = 0; ii < d->types.count(); ++ii) {
895 QQmlType *curr = d->types.at(ii);
896 if (curr->isSingleton() && curr->minorVersion() <= minor)
904 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
905 : m_module(0), m_minor(0)
909 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
910 : m_module(module), m_minor(minor)
913 Q_ASSERT(m_minor >= 0);
916 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
917 : m_module(o.m_module), m_minor(o.m_minor)
921 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
923 m_module = o.m_module;
928 QQmlTypeModule *QQmlTypeModuleVersion::module() const
933 int QQmlTypeModuleVersion::minorVersion() const
938 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
940 if (m_module) return m_module->type(name, m_minor);
944 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
946 if (m_module) return m_module->type(name, m_minor);
951 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
953 QWriteLocker lock(metaTypeDataLock());
954 QQmlMetaTypeData *data = metaTypeData();
956 data->parentFunctions.append(autoparent.function);
958 return data->parentFunctions.count() - 1;
961 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
963 if (interface.version > 0)
964 qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
966 QWriteLocker lock(metaTypeDataLock());
967 QQmlMetaTypeData *data = metaTypeData();
969 int index = data->types.count();
971 QQmlType *type = new QQmlType(index, interface);
973 data->types.append(type);
974 data->idToType.insert(type->typeId(), type);
975 data->idToType.insert(type->qListTypeId(), type);
976 // XXX No insertMulti, so no multi-version interfaces?
977 if (!type->elementName().isEmpty())
978 data->nameToType.insert(type->elementName(), type);
980 if (data->interfaces.size() <= interface.typeId)
981 data->interfaces.resize(interface.typeId + 16);
982 if (data->lists.size() <= interface.listId)
983 data->lists.resize(interface.listId + 16);
984 data->interfaces.setBit(interface.typeId, true);
985 data->lists.setBit(interface.listId, true);
990 QString registrationTypeString(QQmlType::RegistrationType typeType)
993 if (typeType == QQmlType::CppType)
994 typeStr = QStringLiteral("element");
995 else if (typeType == QQmlType::SingletonType)
996 typeStr = QStringLiteral("singleton type");
1000 // NOTE: caller must hold a QWriteLocker on "data"
1001 bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
1003 if (!typeName.isEmpty()) {
1004 int typeNameLen = typeName.length();
1005 for (int ii = 0; ii < typeNameLen; ++ii) {
1006 if (!typeName.at(ii).isLetterOrNumber()) {
1007 QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
1008 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
1014 if (uri && !typeName.isEmpty()) {
1015 QString nameSpace = moduleFromUtf8(uri);
1017 if (!data->typeRegistrationNamespace.isEmpty()) {
1018 // We can only install types into the registered namespace
1019 if (nameSpace != data->typeRegistrationNamespace) {
1020 QString failure(QCoreApplication::translate("qmlRegisterType",
1021 "Cannot install %1 '%2' into unregistered namespace '%3'"));
1022 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
1025 } else if (data->typeRegistrationNamespace != nameSpace) {
1026 // Is the target namespace protected against further registrations?
1027 if (data->protectedNamespaces.contains(nameSpace)) {
1028 QString failure(QCoreApplication::translate("qmlRegisterType",
1029 "Cannot install %1 '%2' into protected namespace '%3'"));
1030 data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
1039 int registerType(const QQmlPrivate::RegisterType &type)
1041 QWriteLocker lock(metaTypeDataLock());
1042 QQmlMetaTypeData *data = metaTypeData();
1043 QString elementName = QString::fromUtf8(type.elementName);
1044 if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
1047 int index = data->types.count();
1049 QQmlType *dtype = new QQmlType(index, elementName, type);
1051 data->types.append(dtype);
1052 data->idToType.insert(dtype->typeId(), dtype);
1053 if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
1055 if (!dtype->elementName().isEmpty())
1056 data->nameToType.insertMulti(dtype->elementName(), dtype);
1058 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
1060 if (data->objects.size() <= type.typeId)
1061 data->objects.resize(type.typeId + 16);
1062 if (data->lists.size() <= type.listId)
1063 data->lists.resize(type.listId + 16);
1064 data->objects.setBit(type.typeId, true);
1065 if (type.listId) data->lists.setBit(type.listId, true);
1067 if (!dtype->module().isEmpty()) {
1068 const QHashedString &mod = dtype->module();
1070 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
1071 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1073 module = new QQmlTypeModule;
1074 module->d->uri = versionedUri;
1075 data->uriToModule.insert(versionedUri, module);
1077 module->d->add(dtype);
1083 int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
1085 QWriteLocker lock(metaTypeDataLock());
1086 QQmlMetaTypeData *data = metaTypeData();
1087 QString typeName = QString::fromUtf8(type.typeName);
1088 if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
1091 int index = data->types.count();
1093 QQmlType *dtype = new QQmlType(index, typeName, type);
1095 data->types.append(dtype);
1096 data->idToType.insert(dtype->typeId(), dtype);
1098 if (!dtype->elementName().isEmpty())
1099 data->nameToType.insertMulti(dtype->elementName(), dtype);
1101 if (dtype->baseMetaObject())
1102 data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
1105 if (data->objects.size() <= type.typeId)
1106 data->objects.resize(type.typeId + 16);
1107 data->objects.setBit(type.typeId, true);
1110 if (!dtype->module().isEmpty()) {
1111 const QHashedString &mod = dtype->module();
1113 QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
1114 QQmlTypeModule *module = data->uriToModule.value(versionedUri);
1116 module = new QQmlTypeModule;
1117 module->d->uri = versionedUri;
1118 data->uriToModule.insert(versionedUri, module);
1120 module->d->add(dtype);
1128 This method is "over generalized" to allow us to (potentially) register more types of things in
1129 the future without adding exported symbols.
1131 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
1133 if (type == TypeRegistration) {
1134 return registerType(*reinterpret_cast<RegisterType *>(data));
1135 } else if (type == InterfaceRegistration) {
1136 return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
1137 } else if (type == AutoParentRegistration) {
1138 return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
1139 } else if (type == SingletonRegistration) {
1140 return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
1145 bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
1147 QQmlMetaTypeData *data = metaTypeData();
1149 // Has any type previously been installed to this namespace?
1150 QHashedString nameSpace(uri);
1151 foreach (const QQmlType *type, data->types)
1152 if (type->module() == nameSpace)
1158 void QQmlMetaType::protectNamespace(const QString &uri)
1160 QQmlMetaTypeData *data = metaTypeData();
1162 data->protectedNamespaces.insert(uri);
1165 void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
1167 QQmlMetaTypeData *data = metaTypeData();
1169 data->typeRegistrationNamespace = uri;
1170 data->typeRegistrationFailures.clear();
1173 QStringList QQmlMetaType::typeRegistrationFailures()
1175 QQmlMetaTypeData *data = metaTypeData();
1177 return data->typeRegistrationFailures;
1180 QReadWriteLock *QQmlMetaType::typeRegistrationLock()
1182 return metaTypeDataLock();
1186 Returns true if a module \a uri of any version is installed.
1188 bool QQmlMetaType::isAnyModule(const QString &uri)
1190 QReadLocker lock(metaTypeDataLock());
1191 QQmlMetaTypeData *data = metaTypeData();
1193 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
1194 iter != data->uriToModule.end(); ++iter) {
1195 if ((*iter)->module() == uri)
1203 Returns true if any type or API has been registered for the given \a module with at least
1204 versionMajor.versionMinor, or if types have been registered for \a module with at most
1205 versionMajor.versionMinor.
1207 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.
1209 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
1211 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
1212 QReadLocker lock(metaTypeDataLock());
1214 QQmlMetaTypeData *data = metaTypeData();
1216 // first, check Types
1217 QQmlTypeModule *tm =
1218 data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
1219 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
1225 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
1227 QReadLocker lock(metaTypeDataLock());
1228 QQmlMetaTypeData *data = metaTypeData();
1229 return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1232 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1234 QReadLocker lock(metaTypeDataLock());
1235 QQmlMetaTypeData *data = metaTypeData();
1236 return data->parentFunctions;
1239 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1241 if (!isQObject(v.userType())) {
1242 if (ok) *ok = false;
1248 return *(QObject **)v.constData();
1251 bool QQmlMetaType::isQObject(int userType)
1253 if (userType == QMetaType::QObjectStar)
1256 QReadLocker lock(metaTypeDataLock());
1257 QQmlMetaTypeData *data = metaTypeData();
1258 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1262 Returns the item type for a list of type \a id.
1264 int QQmlMetaType::listType(int id)
1266 QReadLocker lock(metaTypeDataLock());
1267 QQmlMetaTypeData *data = metaTypeData();
1268 QQmlType *type = data->idToType.value(id);
1269 if (type && type->qListTypeId() == id)
1270 return type->typeId();
1275 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1277 QReadLocker lock(metaTypeDataLock());
1278 QQmlMetaTypeData *data = metaTypeData();
1280 QQmlType *type = data->metaObjectToType.value(mo);
1281 if (type && type->attachedPropertiesFunction())
1282 return type->attachedPropertiesId();
1287 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1291 QReadLocker lock(metaTypeDataLock());
1292 QQmlMetaTypeData *data = metaTypeData();
1293 return data->types.at(id)->attachedPropertiesFunction();
1296 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1298 int idx = metaObject->indexOfClassInfo("DefaultProperty");
1300 return QMetaProperty();
1302 QMetaClassInfo info = metaObject->classInfo(idx);
1304 return QMetaProperty();
1306 idx = metaObject->indexOfProperty(info.value());
1308 return QMetaProperty();
1310 return metaObject->property(idx);
1313 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1316 return QMetaProperty();
1318 const QMetaObject *metaObject = obj->metaObject();
1319 return defaultProperty(metaObject);
1322 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1324 int idx = metaObject->indexOfClassInfo("DefaultMethod");
1326 return QMetaMethod();
1328 QMetaClassInfo info = metaObject->classInfo(idx);
1330 return QMetaMethod();
1332 idx = metaObject->indexOfMethod(info.value());
1334 return QMetaMethod();
1336 return metaObject->method(idx);
1339 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1342 return QMetaMethod();
1344 const QMetaObject *metaObject = obj->metaObject();
1345 return defaultMethod(metaObject);
1348 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1352 if (userType == QMetaType::QObjectStar)
1355 QReadLocker lock(metaTypeDataLock());
1356 QQmlMetaTypeData *data = metaTypeData();
1357 if (userType < data->objects.size() && data->objects.testBit(userType))
1359 else if (userType < data->lists.size() && data->lists.testBit(userType))
1365 bool QQmlMetaType::isInterface(int userType)
1367 QReadLocker lock(metaTypeDataLock());
1368 QQmlMetaTypeData *data = metaTypeData();
1369 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1372 const char *QQmlMetaType::interfaceIId(int userType)
1374 QReadLocker lock(metaTypeDataLock());
1375 QQmlMetaTypeData *data = metaTypeData();
1376 QQmlType *type = data->idToType.value(userType);
1378 if (type && type->isInterface() && type->typeId() == userType)
1379 return type->interfaceIId();
1384 bool QQmlMetaType::isList(int userType)
1386 QReadLocker lock(metaTypeDataLock());
1387 QQmlMetaTypeData *data = metaTypeData();
1388 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1392 A custom string convertor allows you to specify a function pointer that
1393 returns a variant of \a type. For example, if you have written your own icon
1394 class that you want to support as an object property assignable in QML:
1397 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1398 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1401 The function pointer must be of the form:
1403 QVariant (*StringConverter)(const QString &);
1406 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1408 QWriteLocker lock(metaTypeDataLock());
1410 QQmlMetaTypeData *data = metaTypeData();
1411 if (data->stringConverters.contains(type))
1413 data->stringConverters.insert(type, converter);
1417 Return the custom string converter for \a type, previously installed through
1418 registerCustomStringConverter()
1420 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1422 QReadLocker lock(metaTypeDataLock());
1424 QQmlMetaTypeData *data = metaTypeData();
1425 return data->stringConverters.value(type);
1429 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1430 by \a version_major and \a version_minor.
1432 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1434 int slash = qualifiedName.indexOf(QLatin1Char('/'));
1438 QHashedStringRef module(qualifiedName.constData(), slash);
1439 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1441 return qmlType(name, module, version_major, version_minor);
1445 Returns the type (if any) of \a name in \a module and version specified
1446 by \a version_major and \a version_minor.
1448 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1450 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1451 QReadLocker lock(metaTypeDataLock());
1452 QQmlMetaTypeData *data = metaTypeData();
1454 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1455 while (it != data->nameToType.end() && it.key() == name) {
1456 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1457 if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1466 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1469 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1471 QReadLocker lock(metaTypeDataLock());
1472 QQmlMetaTypeData *data = metaTypeData();
1474 return data->metaObjectToType.value(metaObject);
1478 Returns the type (if any) that corresponds to the \a metaObject in version specified
1479 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1482 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1484 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1485 QReadLocker lock(metaTypeDataLock());
1486 QQmlMetaTypeData *data = metaTypeData();
1488 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1489 while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1491 if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1500 Returns the type (if any) that corresponds to the QVariant::Type \a userType.
1501 Returns null if no type is registered.
1503 QQmlType *QQmlMetaType::qmlType(int userType)
1505 QReadLocker lock(metaTypeDataLock());
1506 QQmlMetaTypeData *data = metaTypeData();
1508 QQmlType *type = data->idToType.value(userType);
1509 if (type && type->typeId() == userType)
1516 Returns the list of registered QML type names.
1518 QList<QString> QQmlMetaType::qmlTypeNames()
1520 QReadLocker lock(metaTypeDataLock());
1521 QQmlMetaTypeData *data = metaTypeData();
1523 QList<QString> names;
1524 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1525 while (it != data->nameToType.end()) {
1526 names += (*it)->qmlTypeName();
1534 Returns the list of registered QML types.
1536 QList<QQmlType*> QQmlMetaType::qmlTypes()
1538 QReadLocker lock(metaTypeDataLock());
1539 QQmlMetaTypeData *data = metaTypeData();
1541 return data->nameToType.values();
1545 Returns the list of registered QML singleton types.
1547 QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
1549 QReadLocker lock(metaTypeDataLock());
1550 QQmlMetaTypeData *data = metaTypeData();
1552 QList<QQmlType*> alltypes = data->nameToType.values();
1553 QList<QQmlType*> retn;
1554 foreach (QQmlType* t, alltypes) {
1555 if (t->isSingleton()) {
1563 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1567 id = QMetaType::type("QQuickAnchorLine");
1572 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1574 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1576 anchorLineCompareFunction = fun;
1579 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1581 Q_ASSERT(anchorLineCompareFunction != 0);
1582 return anchorLineCompareFunction(p1, p2);