diff options
Diffstat (limited to 'src/qml/qml/qqmlmetatype.cpp')
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 1359 |
1 files changed, 1359 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp new file mode 100644 index 0000000000..2061530dc5 --- /dev/null +++ b/src/qml/qml/qqmlmetatype.cpp @@ -0,0 +1,1359 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQml/qqmlprivate.h> +#include "qqmlmetatype_p.h" + +#include <private/qqmlproxymetaobject_p.h> +#include <private/qqmlcustomparser_p.h> +#include <private/qqmlguard_p.h> +#include <private/qhashedstring_p.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qbitarray.h> +#include <QtCore/qreadwritelock.h> +#include <QtCore/private/qmetaobject_p.h> + +#include <qmetatype.h> +#include <qobjectdefs.h> +#include <qbytearray.h> +#include <qreadwritelock.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvector.h> + +#include <ctype.h> + +QT_BEGIN_NAMESPACE + +struct QQmlMetaTypeData +{ + QQmlMetaTypeData(); + ~QQmlMetaTypeData(); + QList<QQmlType *> types; + typedef QHash<int, QQmlType *> Ids; + Ids idToType; + typedef QHash<QString, QQmlType *> Names; + Names nameToType; + typedef QHash<const QMetaObject *, QQmlType *> MetaObjects; + MetaObjects metaObjectToType; + typedef QHash<int, QQmlMetaType::StringConverter> StringConverters; + StringConverters stringConverters; + + struct VersionedUri { + VersionedUri() + : majorVersion(0) {} + VersionedUri(const QString &uri, int majorVersion) + : uri(uri), majorVersion(majorVersion) {} + bool operator==(const VersionedUri &other) const { + return other.majorVersion == majorVersion && other.uri == uri; + } + QString uri; + int majorVersion; + }; + typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules; + TypeModules uriToModule; + + struct ModuleApiList { + ModuleApiList() : sorted(true) {} + QList<QQmlMetaType::ModuleApi> moduleApis; + bool sorted; + }; + typedef QHash<QString, ModuleApiList> ModuleApis; + ModuleApis moduleApis; + int moduleApiCount; + + QBitArray objects; + QBitArray interfaces; + QBitArray lists; + + QList<QQmlPrivate::AutoParentFunction> parentFunctions; +}; + +class QQmlTypeModulePrivate +{ +public: + QQmlTypeModulePrivate() + : minMinorVersion(INT_MAX), maxMinorVersion(0) {} + + QQmlMetaTypeData::VersionedUri uri; + + int minMinorVersion; + int maxMinorVersion; + + void add(QQmlType *); + + QStringHash<QList<QQmlType *> > typeHash; + QList<QQmlType *> types; +}; + +Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData) +Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) + +static uint qHash(const QQmlMetaTypeData::VersionedUri &v) +{ + return qHash(v.uri) ^ qHash(v.majorVersion); +} + +QQmlMetaTypeData::QQmlMetaTypeData() +: moduleApiCount(0) +{ +} + +QQmlMetaTypeData::~QQmlMetaTypeData() +{ + for (int i = 0; i < types.count(); ++i) + delete types.at(i); +} + +class QQmlTypePrivate +{ +public: + QQmlTypePrivate(); + + void init() const; + void initEnums() const; + + bool m_isInterface : 1; + const char *m_iid; + QString m_module; + QString m_name; + QString m_elementName; + int m_version_maj; + int m_version_min; + int m_typeId; int m_listId; + int m_revision; + mutable bool m_containsRevisionedAttributes; + mutable QQmlType *m_superType; + + int m_allocationSize; + void (*m_newFunc)(void *); + QString m_noCreationReason; + + const QMetaObject *m_baseMetaObject; + QQmlAttachedPropertiesFunc m_attachedPropertiesFunc; + const QMetaObject *m_attachedPropertiesType; + int m_attachedPropertiesId; + int m_parserStatusCast; + int m_propertyValueSourceCast; + int m_propertyValueInterceptorCast; + QObject *(*m_extFunc)(QObject *); + const QMetaObject *m_extMetaObject; + int m_index; + QQmlCustomParser *m_customParser; + mutable volatile bool m_isSetup:1; + mutable volatile bool m_isEnumSetup:1; + mutable bool m_haveSuperType:1; + mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects; + mutable QStringHash<int> m_enums; + + static QHash<const QMetaObject *, int> m_attachedPropertyIds; +}; + +QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds; + +QQmlTypePrivate::QQmlTypePrivate() +: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false), + m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), + m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), + m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), + m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false) +{ +} + + +QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) +: d(new QQmlTypePrivate) +{ + d->m_isInterface = true; + d->m_iid = interface.iid; + d->m_typeId = interface.typeId; + d->m_listId = interface.listId; + d->m_newFunc = 0; + d->m_index = index; + d->m_isSetup = true; + d->m_version_maj = 0; + d->m_version_min = 0; +} + +QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type) +: d(new QQmlTypePrivate) +{ + QString name = QString::fromUtf8(type.uri); + if (type.uri) name += QLatin1Char('/'); + name += QString::fromUtf8(type.elementName); + + d->m_module = QString::fromUtf8(type.uri); + d->m_name = name; + d->m_version_maj = type.versionMajor; + d->m_version_min = type.versionMinor; + if (type.version >= 1) // revisions added in version 1 + d->m_revision = type.revision; + d->m_typeId = type.typeId; + d->m_listId = type.listId; + d->m_allocationSize = type.objectSize; + d->m_newFunc = type.create; + d->m_noCreationReason = type.noCreationReason; + d->m_baseMetaObject = type.metaObject; + d->m_attachedPropertiesFunc = type.attachedPropertiesFunction; + d->m_attachedPropertiesType = type.attachedPropertiesMetaObject; + if (d->m_attachedPropertiesType) { + QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject); + if (iter == d->m_attachedPropertyIds.end()) + iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index); + d->m_attachedPropertiesId = *iter; + } else { + d->m_attachedPropertiesId = -1; + } + d->m_parserStatusCast = type.parserStatusCast; + d->m_propertyValueSourceCast = type.valueSourceCast; + d->m_propertyValueInterceptorCast = type.valueInterceptorCast; + d->m_extFunc = type.extensionObjectCreate; + d->m_index = index; + d->m_customParser = type.customParser; + + if (type.extensionMetaObject) + d->m_extMetaObject = type.extensionMetaObject; +} + +QQmlType::~QQmlType() +{ + delete d->m_customParser; + delete d; +} + +QString QQmlType::module() const +{ + return d->m_module; +} + +int QQmlType::majorVersion() const +{ + return d->m_version_maj; +} + +int QQmlType::minorVersion() const +{ + return d->m_version_min; +} + +bool QQmlType::availableInVersion(int vmajor, int vminor) const +{ + Q_ASSERT(vmajor >= 0 && vminor >= 0); + return vmajor == d->m_version_maj && vminor >= d->m_version_min; +} + +bool QQmlType::availableInVersion(const QString &module, int vmajor, int vminor) const +{ + Q_ASSERT(vmajor >= 0 && vminor >= 0); + return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min; +} + +// returns the nearest _registered_ super class +QQmlType *QQmlType::superType() const +{ + if (!d->m_haveSuperType) { + const QMetaObject *mo = d->m_baseMetaObject->superClass(); + while (mo && !d->m_superType) { + d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min); + mo = mo->superClass(); + } + d->m_haveSuperType = true; + } + + return d->m_superType; +} + +static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, + const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) +{ + // Set classname + builder.setClassName(ignoreEnd->className()); + + // Clone Q_CLASSINFO + for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) { + QMetaClassInfo info = mo->classInfo(ii); + + int otherIndex = ignoreEnd->indexOfClassInfo(info.name()); + if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) { + // Skip + } else { + builder.addClassInfo(info.name(), info.value()); + } + } + + // Clone Q_PROPERTY + for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) { + QMetaProperty property = mo->property(ii); + + int otherIndex = ignoreEnd->indexOfProperty(property.name()); + if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) { + builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void")); + // Skip + } else { + builder.addProperty(property); + } + } + + // Clone Q_METHODS + for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) { + QMetaMethod method = mo->method(ii); + + // More complex - need to search name + QByteArray name = method.signature(); + int parenIdx = name.indexOf('('); + if (parenIdx != -1) name = name.left(parenIdx); + + + bool found = false; + + for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); + !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); + ++ii) { + + QMetaMethod other = ignoreEnd->method(ii); + QByteArray othername = other.signature(); + int parenIdx = othername.indexOf('('); + if (parenIdx != -1) othername = othername.left(parenIdx); + + found = name == othername; + } + + QMetaMethodBuilder m = builder.addMethod(method); + if (found) // SKIP + m.setAccess(QMetaMethod::Private); + } + + // Clone Q_ENUMS + for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) { + QMetaEnum enumerator = mo->enumerator(ii); + + int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name()); + if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) { + // Skip + } else { + builder.addEnumerator(enumerator); + } + } +} + +static bool isPropertyRevisioned(const QMetaObject *mo, int index) +{ + int i = index; + i -= mo->propertyOffset(); + if (i < 0 && mo->d.superdata) + return isPropertyRevisioned(mo->d.superdata, index); + + const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data); + if (i >= 0 && i < mop->propertyCount) { + int handle = mop->propertyData + 3*i; + int flags = mo->d.data[handle + 2]; + + return (flags & Revisioned); + } + + return false; +} + +void QQmlTypePrivate::init() const +{ + if (m_isSetup) return; + + QWriteLocker lock(metaTypeDataLock()); + if (m_isSetup) + return; + + // Setup extended meta object + // XXX - very inefficient + const QMetaObject *mo = m_baseMetaObject; + if (m_extFunc) { + QMetaObjectBuilder builder; + clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject); + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + QMetaObject *mmo = builder.toMetaObject(); + mmo->d.superdata = mo; + QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 }; + m_metaObjects << data; + } + + mo = mo->d.superdata; + while(mo) { + QQmlType *t = metaTypeData()->metaObjectToType.value(mo); + if (t) { + if (t->d->m_extFunc) { + QMetaObjectBuilder builder; + clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject); + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + QMetaObject *mmo = builder.toMetaObject(); + mmo->d.superdata = m_baseMetaObject; + if (!m_metaObjects.isEmpty()) + m_metaObjects.last().metaObject->d.superdata = mmo; + QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 }; + m_metaObjects << data; + } + } + mo = mo->d.superdata; + } + + for (int ii = 0; ii < m_metaObjects.count(); ++ii) { + m_metaObjects[ii].propertyOffset = + m_metaObjects.at(ii).metaObject->propertyOffset(); + m_metaObjects[ii].methodOffset = + m_metaObjects.at(ii).metaObject->methodOffset(); + } + + // Check for revisioned details + { + const QMetaObject *mo = 0; + if (m_metaObjects.isEmpty()) + mo = m_baseMetaObject; + else + mo = m_metaObjects.first().metaObject; + + for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) { + if (isPropertyRevisioned(mo, ii)) + m_containsRevisionedAttributes = true; + } + + for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) { + if (mo->method(ii).revision() != 0) + m_containsRevisionedAttributes = true; + } + } + + m_isSetup = true; + lock.unlock(); +} + +void QQmlTypePrivate::initEnums() const +{ + if (m_isEnumSetup) return; + + init(); + + QWriteLocker lock(metaTypeDataLock()); + if (m_isEnumSetup) return; + + const QMetaObject *metaObject = m_baseMetaObject; + for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { + + QMetaEnum e = metaObject->enumerator(ii); + + for (int jj = 0; jj < e.keyCount(); ++jj) + m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj)); + } + + m_isEnumSetup = true; +} + +QByteArray QQmlType::typeName() const +{ + if (d->m_baseMetaObject) + return d->m_baseMetaObject->className(); + else + return QByteArray(); +} + +const QString &QQmlType::elementName() const +{ + if (d->m_elementName.isEmpty()) { + QString n = qmlTypeName(); + int idx = n.lastIndexOf(QLatin1Char('/')); + d->m_elementName = n.mid(idx + 1); + } + return d->m_elementName; +} + +const QString &QQmlType::qmlTypeName() const +{ + return d->m_name; +} + +QObject *QQmlType::create() const +{ + d->init(); + + QObject *rv = (QObject *)operator new(d->m_allocationSize); + d->m_newFunc(rv); + + if (rv && !d->m_metaObjects.isEmpty()) + (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects); + + return rv; +} + +void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const +{ + d->init(); + + QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory); + d->m_newFunc(rv); + + if (rv && !d->m_metaObjects.isEmpty()) + (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects); + + *out = rv; + *memory = ((char *)rv) + d->m_allocationSize; +} + +QQmlCustomParser *QQmlType::customParser() const +{ + return d->m_customParser; +} + +QQmlType::CreateFunc QQmlType::createFunction() const +{ + return d->m_newFunc; +} + +QString QQmlType::noCreationReason() const +{ + return d->m_noCreationReason; +} + +int QQmlType::createSize() const +{ + return d->m_allocationSize; +} + +bool QQmlType::isCreatable() const +{ + return d->m_newFunc != 0; +} + +bool QQmlType::isExtendedType() const +{ + d->init(); + + return !d->m_metaObjects.isEmpty(); +} + +bool QQmlType::isInterface() const +{ + return d->m_isInterface; +} + +int QQmlType::typeId() const +{ + return d->m_typeId; +} + +int QQmlType::qListTypeId() const +{ + return d->m_listId; +} + +const QMetaObject *QQmlType::metaObject() const +{ + d->init(); + + if (d->m_metaObjects.isEmpty()) + return d->m_baseMetaObject; + else + return d->m_metaObjects.first().metaObject; + +} + +const QMetaObject *QQmlType::baseMetaObject() const +{ + return d->m_baseMetaObject; +} + +bool QQmlType::containsRevisionedAttributes() const +{ + d->init(); + + return d->m_containsRevisionedAttributes; +} + +int QQmlType::metaObjectRevision() const +{ + return d->m_revision; +} + +QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const +{ + return d->m_attachedPropertiesFunc; +} + +const QMetaObject *QQmlType::attachedPropertiesType() const +{ + return d->m_attachedPropertiesType; +} + +/* +This is the id passed to qmlAttachedPropertiesById(). This is different from the index +for the case that a single class is registered under two or more names (eg. Item in +Qt 4.7 and QtQuick 1.0). +*/ +int QQmlType::attachedPropertiesId() const +{ + return d->m_attachedPropertiesId; +} + +int QQmlType::parserStatusCast() const +{ + return d->m_parserStatusCast; +} + +int QQmlType::propertyValueSourceCast() const +{ + return d->m_propertyValueSourceCast; +} + +int QQmlType::propertyValueInterceptorCast() const +{ + return d->m_propertyValueInterceptorCast; +} + +const char *QQmlType::interfaceIId() const +{ + return d->m_iid; +} + +int QQmlType::index() const +{ + return d->m_index; +} + +int QQmlType::enumValue(const QHashedStringRef &name) const +{ + d->initEnums(); + + int *rv = d->m_enums.value(name); + return rv?*rv:-1; +} + +int QQmlType::enumValue(const QHashedV8String &name) const +{ + d->initEnums(); + + int *rv = d->m_enums.value(name); + return rv?*rv:-1; +} + +QQmlTypeModule::QQmlTypeModule() +: d(new QQmlTypeModulePrivate) +{ +} + +QQmlTypeModule::~QQmlTypeModule() +{ + delete d; d = 0; +} + +QString QQmlTypeModule::module() const +{ + return d->uri.uri; +} + +int QQmlTypeModule::majorVersion() const +{ + return d->uri.majorVersion; +} + +int QQmlTypeModule::minimumMinorVersion() const +{ + return d->minMinorVersion; +} + +int QQmlTypeModule::maximumMinorVersion() const +{ + return d->maxMinorVersion; +} + +void QQmlTypeModulePrivate::add(QQmlType *type) +{ + types << type; + + minMinorVersion = qMin(minMinorVersion, type->minorVersion()); + maxMinorVersion = qMax(maxMinorVersion, type->minorVersion()); + + QList<QQmlType *> &list = typeHash[type->elementName()]; + for (int ii = 0; ii < list.count(); ++ii) { + if (list.at(ii)->minorVersion() < type->minorVersion()) { + list.insert(ii, type); + return; + } + } + list.append(type); +} + +QList<QQmlType *> QQmlTypeModule::types() +{ + QList<QQmlType *> rv; + QReadLocker lock(metaTypeDataLock()); + rv = d->types; + return rv; +} + +QList<QQmlType *> QQmlTypeModule::type(const QString &name) +{ + QReadLocker lock(metaTypeDataLock()); + QList<QQmlType *> rv; + for (int ii = 0; ii < d->types.count(); ++ii) { + if (d->types.at(ii)->elementName() == name) + rv << d->types.at(ii); + } + return rv; +} + +QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor) +{ + QReadLocker lock(metaTypeDataLock()); + + QList<QQmlType *> *types = d->typeHash.value(name); + if (!types) return 0; + + for (int ii = 0; ii < types->count(); ++ii) + if (types->at(ii)->minorVersion() <= minor) + return types->at(ii); + + return 0; +} + +QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor) +{ + QReadLocker lock(metaTypeDataLock()); + + QList<QQmlType *> *types = d->typeHash.value(name); + if (!types) return 0; + + for (int ii = 0; ii < types->count(); ++ii) + if (types->at(ii)->minorVersion() <= minor) + return types->at(ii); + + return 0; +} + + +QQmlTypeModuleVersion::QQmlTypeModuleVersion() +: m_module(0), m_minor(0) +{ +} + +QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor) +: m_module(module), m_minor(minor) +{ + Q_ASSERT(m_module); + Q_ASSERT(m_minor >= 0); +} + +QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o) +: m_module(o.m_module), m_minor(o.m_minor) +{ +} + +QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o) +{ + m_module = o.m_module; + m_minor = o.m_minor; + return *this; +} + +QQmlTypeModule *QQmlTypeModuleVersion::module() const +{ + return m_module; +} + +int QQmlTypeModuleVersion::minorVersion() const +{ + return m_minor; +} + +QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const +{ + if (m_module) return m_module->type(name, m_minor); + else return 0; +} + +QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const +{ + if (m_module) return m_module->type(name, m_minor); + else return 0; +} + + +int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) +{ + QWriteLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + data->parentFunctions.append(autoparent.function); + + return data->parentFunctions.count() - 1; +} + +int registerInterface(const QQmlPrivate::RegisterInterface &interface) +{ + if (interface.version > 0) + qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); + + QWriteLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + int index = data->types.count(); + + QQmlType *type = new QQmlType(index, interface); + + data->types.append(type); + data->idToType.insert(type->typeId(), type); + data->idToType.insert(type->qListTypeId(), type); + // XXX No insertMulti, so no multi-version interfaces? + if (!type->qmlTypeName().isEmpty()) + data->nameToType.insert(type->qmlTypeName(), type); + + if (data->interfaces.size() <= interface.typeId) + data->interfaces.resize(interface.typeId + 16); + if (data->lists.size() <= interface.listId) + data->lists.resize(interface.listId + 16); + data->interfaces.setBit(interface.typeId, true); + data->lists.setBit(interface.listId, true); + + return index; +} + +int registerType(const QQmlPrivate::RegisterType &type) +{ + if (type.elementName) { + for (int ii = 0; type.elementName[ii]; ++ii) { + if (!isalnum(type.elementName[ii])) { + qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName); + return -1; + } + } + } + + QWriteLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + int index = data->types.count(); + + QQmlType *dtype = new QQmlType(index, type); + + data->types.append(dtype); + data->idToType.insert(dtype->typeId(), dtype); + if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype); + + if (!dtype->qmlTypeName().isEmpty()) + data->nameToType.insertMulti(dtype->qmlTypeName(), dtype); + + data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype); + + if (data->objects.size() <= type.typeId) + data->objects.resize(type.typeId + 16); + if (data->lists.size() <= type.listId) + data->lists.resize(type.listId + 16); + data->objects.setBit(type.typeId, true); + if (type.listId) data->lists.setBit(type.listId, true); + + if (type.uri) { + QString mod = QString::fromUtf8(type.uri); + + QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor); + QQmlTypeModule *module = data->uriToModule.value(versionedUri); + if (!module) { + module = new QQmlTypeModule; + module->d->uri = versionedUri; + data->uriToModule.insert(versionedUri, module); + } + module->d->add(dtype); + } + + return index; +} + +int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api) +{ + QWriteLocker lock(metaTypeDataLock()); + + QQmlMetaTypeData *data = metaTypeData(); + QString uri = QString::fromUtf8(api.uri); + QQmlMetaType::ModuleApi import; + import.major = api.versionMajor; + import.minor = api.versionMinor; + import.script = api.scriptApi; + import.qobject = api.qobjectApi; + + int index = data->moduleApiCount++; + + QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri); + if (iter == data->moduleApis.end()) { + QQmlMetaTypeData::ModuleApiList apis; + apis.moduleApis << import; + data->moduleApis.insert(uri, apis); + } else { + iter->moduleApis << import; + iter->sorted = false; + } + + return index; +} + + +/* +This method is "over generalized" to allow us to (potentially) register more types of things in +the future without adding exported symbols. +*/ +int QQmlPrivate::qmlregister(RegistrationType type, void *data) +{ + if (type == TypeRegistration) { + return registerType(*reinterpret_cast<RegisterType *>(data)); + } else if (type == InterfaceRegistration) { + return registerInterface(*reinterpret_cast<RegisterInterface *>(data)); + } else if (type == AutoParentRegistration) { + return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data)); + } else if (type == ModuleApiRegistration) { + return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data)); + } + return -1; +} + +/* + Returns true if a module \a uri of any version is installed. +*/ +bool QQmlMetaType::isAnyModule(const QString &uri) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin(); + iter != data->uriToModule.end(); ++iter) { + if ((*iter)->module() == uri) + return true; + } + + return false; +} + +/* + Returns true if any type or API has been registered for the given \a module with at least + versionMajor.versionMinor, or if types have been registered for \a module with at most + versionMajor.versionMinor. + + 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. +*/ +bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor) +{ + Q_ASSERT(versionMajor >= 0 && versionMinor >= 0); + QReadLocker lock(metaTypeDataLock()); + + QQmlMetaTypeData *data = metaTypeData(); + + // first, check Types + QQmlTypeModule *tm = + data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor)); + if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor) + return true; + + // then, check ModuleApis + foreach (const QQmlMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) { + if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct? + return true; + } + + return false; +} + +QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion)); +} + +QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return data->parentFunctions; +} + +static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs) +{ + return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor); +} + +QQmlMetaType::ModuleApi +QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri); + if (iter == data->moduleApis.end()) + return ModuleApi(); + + if (iter->sorted == false) { + qSort(iter->moduleApis.begin(), iter->moduleApis.end()); + iter->sorted = true; + } + + for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) { + const ModuleApi &import = iter->moduleApis.at(ii); + if (import.major == versionMajor && import.minor <= versionMinor) + return import; + } + + return ModuleApi(); +} + +QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QHash<QString, QList<ModuleApi> > moduleApis; + QHashIterator<QString, QQmlMetaTypeData::ModuleApiList> it(data->moduleApis); + while (it.hasNext()) { + it.next(); + moduleApis[it.key()] = it.value().moduleApis; + } + + return moduleApis; +} + +QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok) +{ + if (!isQObject(v.userType())) { + if (ok) *ok = false; + return 0; + } + + if (ok) *ok = true; + + return *(QObject **)v.constData(); +} + +bool QQmlMetaType::isQObject(int userType) +{ + if (userType == QMetaType::QObjectStar) + return true; + + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); +} + +/* + Returns the item type for a list of type \a id. + */ +int QQmlMetaType::listType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + QQmlType *type = data->idToType.value(id); + if (type && type->qListTypeId() == id) + return type->typeId(); + else + return 0; +} + +int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QQmlType *type = data->metaObjectToType.value(mo); + if (type && type->attachedPropertiesFunction()) + return type->attachedPropertiesId(); + else + return -1; +} + +QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id) +{ + if (id < 0) + return 0; + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return data->types.at(id)->attachedPropertiesFunction(); +} + +QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultProperty"); + if (-1 == idx) + return QMetaProperty(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if (!info.value()) + return QMetaProperty(); + + idx = metaObject->indexOfProperty(info.value()); + if (-1 == idx) + return QMetaProperty(); + + return metaObject->property(idx); +} + +QMetaProperty QQmlMetaType::defaultProperty(QObject *obj) +{ + if (!obj) + return QMetaProperty(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultProperty(metaObject); +} + +QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultMethod"); + if (-1 == idx) + return QMetaMethod(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if (!info.value()) + return QMetaMethod(); + + idx = metaObject->indexOfMethod(info.value()); + if (-1 == idx) + return QMetaMethod(); + + return metaObject->method(idx); +} + +QMetaMethod QQmlMetaType::defaultMethod(QObject *obj) +{ + if (!obj) + return QMetaMethod(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultMethod(metaObject); +} + +QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) +{ + if (userType < 0) + return Unknown; + if (userType == QMetaType::QObjectStar) + return Object; + + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + if (userType < data->objects.size() && data->objects.testBit(userType)) + return Object; + else if (userType < data->lists.size() && data->lists.testBit(userType)) + return List; + else + return Unknown; +} + +bool QQmlMetaType::isInterface(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType); +} + +const char *QQmlMetaType::interfaceIId(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + QQmlType *type = data->idToType.value(userType); + lock.unlock(); + if (type && type->isInterface() && type->typeId() == userType) + return type->interfaceIId(); + else + return 0; +} + +bool QQmlMetaType::isList(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); +} + +/*! + A custom string convertor allows you to specify a function pointer that + returns a variant of \a type. For example, if you have written your own icon + class that you want to support as an object property assignable in QML: + + \code + int type = qRegisterMetaType<SuperIcon>("SuperIcon"); + QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString); + \endcode + + The function pointer must be of the form: + \code + QVariant (*StringConverter)(const QString &); + \endcode + */ +void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter) +{ + QWriteLocker lock(metaTypeDataLock()); + + QQmlMetaTypeData *data = metaTypeData(); + if (data->stringConverters.contains(type)) + return; + data->stringConverters.insert(type, converter); +} + +/*! + Return the custom string converter for \a type, previously installed through + registerCustomStringConverter() + */ +QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type) +{ + QReadLocker lock(metaTypeDataLock()); + + QQmlMetaTypeData *data = metaTypeData(); + return data->stringConverters.value(type); +} + +/*! + Returns the type (if any) of URI-qualified named \a name in version specified + by \a version_major and \a version_minor. +*/ +QQmlType *QQmlMetaType::qmlType(const QString &name, int version_major, int version_minor) +{ + Q_ASSERT(version_major >= 0 && version_minor >= 0); + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name); + while (it != data->nameToType.end()) { + // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty + if (it.key() == name && (version_major<0 || (*it)->availableInVersion(version_major,version_minor))) + return (*it); + ++it; + } + + return 0; +} + +/*! + Returns the type (if any) that corresponds to the \a metaObject. Returns null if no + type is registered. +*/ +QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + return data->metaObjectToType.value(metaObject); +} + +/*! + Returns the type (if any) that corresponds to the \a metaObject in version specified + by \a version_major and \a version_minor in module specified by \a uri. Returns null if no + type is registered. +*/ +QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor) +{ + Q_ASSERT(version_major >= 0 && version_minor >= 0); + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject); + while (it != data->metaObjectToType.end() && it.key() == metaObject) { + QQmlType *t = *it; + if (version_major < 0 || t->availableInVersion(module, version_major,version_minor)) + return t; + ++it; + } + + return 0; +} + +/*! + Returns the type (if any) that corresponds to the QVariant::Type \a userType. + Returns null if no type is registered. +*/ +QQmlType *QQmlMetaType::qmlType(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QQmlType *type = data->idToType.value(userType); + if (type && type->typeId() == userType) + return type; + else + return 0; +} + +/*! + Returns the list of registered QML type names. +*/ +QList<QString> QQmlMetaType::qmlTypeNames() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + return data->nameToType.keys(); +} + +/*! + Returns the list of registered QML types. +*/ +QList<QQmlType*> QQmlMetaType::qmlTypes() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + return data->nameToType.values(); +} + +int QQmlMetaType::QQuickAnchorLineMetaTypeId() +{ + static int id = 0; + if (!id) { + id = QMetaType::type("QQuickAnchorLine"); + } + return id; +} + +QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0; + +void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun) +{ + anchorLineCompareFunction = fun; +} + +bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2) +{ + Q_ASSERT(anchorLineCompareFunction != 0); + return anchorLineCompareFunction(p1, p2); +} + +QT_END_NAMESPACE |