diff options
Diffstat (limited to 'src/qml/qml/qqmlmetatype.cpp')
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 345 |
1 files changed, 192 insertions, 153 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 1b94365d03..284269bf63 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -94,36 +94,6 @@ struct QQmlMetaTypeData typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules; TypeModules uriToModule; - struct SingletonTypeList { - SingletonTypeList() : sorted(true) {} - QList<QQmlMetaType::SingletonType> singletonTypes; - bool sorted; - }; - typedef QStringHash<SingletonTypeList> SingletonTypes; - SingletonTypes singletonTypes; - int singletonTypeCount; - - bool singletonTypeExists(const QString &uri, const QString &typeName, int major, int minor) - { - QQmlMetaTypeData::SingletonTypeList *apiList = singletonTypes.value(uri); - if (apiList) { - for (int i=0 ; i < apiList->singletonTypes.size() ; ++i) { - const QQmlMetaType::SingletonType &import = apiList->singletonTypes.at(i); - if (import.major == major && import.minor == minor && typeName == import.typeName) - return true; - } - } - - return false; - } - - bool typeExists(const QString &uri, const QString &typeName, int major, int minor) - { - QQmlMetaTypeData::VersionedUri versionedUri(uri, major); - QQmlTypeModule *module = uriToModule.value(versionedUri); - return module && module->typeNoLock(typeName, minor) != 0; - } - QBitArray objects; QBitArray interfaces; QBitArray lists; @@ -162,7 +132,6 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v) } QQmlMetaTypeData::QQmlMetaTypeData() -: singletonTypeCount(0) { } @@ -176,6 +145,7 @@ class QQmlTypePrivate { public: QQmlTypePrivate(); + ~QQmlTypePrivate(); void init() const; void initEnums() const; @@ -213,6 +183,7 @@ public: mutable bool m_haveSuperType:1; mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects; mutable QStringHash<int> m_enums; + QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo; static QHash<const QMetaObject *, int> m_attachedPropertyIds; }; @@ -238,6 +209,43 @@ static QHashedString moduleFromUtf8(const char *module) return lastModuleStr; } +void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) +{ + if (scriptCallback && scriptApi(e).isUndefined()) { + setScriptApi(e, scriptCallback(e, e)); + } else if (qobjectCallback && !qobjectApi(e)) { + setQObjectApi(e, qobjectCallback(e, e)); + } +} + +void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e) +{ + // cleans up the engine-specific singleton instances if they exist. + scriptApis.remove(e); + QObject *o = qobjectApis.take(e); + delete o; +} + +void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o) +{ + qobjectApis.insert(e, o); +} + +QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const +{ + return qobjectApis.value(e); +} + +void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v) +{ + scriptApis.insert(e, v); +} + +QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const +{ + return scriptApis.value(e); +} + QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds; QQmlTypePrivate::QQmlTypePrivate() @@ -245,10 +253,14 @@ QQmlTypePrivate::QQmlTypePrivate() 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) + m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0) { } +QQmlTypePrivate::~QQmlTypePrivate() +{ + delete m_singletonInstanceInfo; +} QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) : d(new QQmlTypePrivate) @@ -264,6 +276,34 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) d->m_version_min = 0; } +QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) +: d(new QQmlTypePrivate) +{ + d->m_elementName = elementName; + d->m_module = moduleFromUtf8(type.uri); + + d->m_version_maj = type.versionMajor; + d->m_version_min = type.versionMinor; + + if (type.qobjectApi) { + if (type.version >= 1) // static metaobject added in version 1 + d->m_baseMetaObject = type.instanceMetaObject; + if (type.version >= 2) // typeId added in version 2 + d->m_typeId = type.typeId; + if (type.version >= 2) // revisions added in version 2 + d->m_revision = type.revision; + } + + d->m_newFunc = 0; + d->m_index = index; + + d->m_singletonInstanceInfo = new SingletonInstanceInfo; + d->m_singletonInstanceInfo->scriptCallback = type.scriptApi; + d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi; + d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); + d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0; +} + QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type) : d(new QQmlTypePrivate) { @@ -337,7 +377,7 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in // returns the nearest _registered_ super class QQmlType *QQmlType::superType() const { - if (!d->m_haveSuperType) { + if (!d->m_haveSuperType && d->m_baseMetaObject) { 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); @@ -443,9 +483,14 @@ void QQmlTypePrivate::init() const if (m_isSetup) return; + const QMetaObject *mo = m_baseMetaObject; + if (!mo) { + // singleton type without metaobject information + 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); @@ -514,7 +559,8 @@ void QQmlTypePrivate::initEnums() const QWriteLocker lock(metaTypeDataLock()); if (m_isEnumSetup) return; - insertEnums(m_baseMetaObject); + if (m_baseMetaObject) // could be singleton type without metaobject + insertEnums(m_baseMetaObject); m_isEnumSetup = true; } @@ -540,6 +586,8 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const QByteArray QQmlType::typeName() const { + if (d->m_singletonInstanceInfo) + return d->m_singletonInstanceInfo->typeName.toUtf8(); if (d->m_baseMetaObject) return d->m_baseMetaObject->className(); else @@ -590,6 +638,11 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con *memory = ((char *)rv) + d->m_allocationSize; } +QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const +{ + return d->m_singletonInstanceInfo; +} + QQmlCustomParser *QQmlType::customParser() const { return d->m_customParser; @@ -622,6 +675,11 @@ bool QQmlType::isExtendedType() const return !d->m_metaObjects.isEmpty(); } +bool QQmlType::isSingleton() const +{ + return d->m_singletonInstanceInfo != 0; +} + bool QQmlType::isInterface() const { return d->m_isInterface; @@ -800,9 +858,9 @@ void QQmlTypeModulePrivate::add(QQmlType *type) list.append(type); } -QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor) +QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor) { - // Expected that the caller has already handled locking metaTypeDataLock + QReadLocker lock(metaTypeDataLock()); QList<QQmlType *> *types = d->typeHash.value(name); if (!types) return 0; @@ -814,7 +872,7 @@ QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor) return 0; } -QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor) +QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor) { QReadLocker lock(metaTypeDataLock()); @@ -828,18 +886,18 @@ QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor) return 0; } -QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor) +QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const { 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); + QList<QQmlType *> retn; + for (int ii = 0; ii < d->types.count(); ++ii) { + QQmlType *curr = d->types.at(ii); + if (curr->isSingleton() && curr->minorVersion() <= minor) + retn.append(curr); + } - return 0; + return retn; } @@ -929,49 +987,63 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface) return index; } -int registerType(const QQmlPrivate::RegisterType &type) +QString registrationTypeString(QQmlType::RegistrationType typeType) { - 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; + QString typeStr; + if (typeType == QQmlType::CppType) + typeStr = QStringLiteral("element"); + else if (typeType == QQmlType::SingletonType) + typeStr = QStringLiteral("singleton type"); + return typeStr; +} + +// NOTE: caller must hold a QWriteLocker on "data" +bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName) +{ + if (!typeName.isEmpty()) { + int typeNameLen = typeName.length(); + for (int ii = 0; ii < typeNameLen; ++ii) { + if (!typeName.at(ii).isLetterOrNumber()) { + QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"")); + data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName)); + return false; } } } - QWriteLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - - QString elementName = QString::fromUtf8(type.elementName); - - if (type.uri && type.elementName) { - QString nameSpace = moduleFromUtf8(type.uri); - - if (data->singletonTypeExists(nameSpace, elementName, type.versionMajor, type.versionMinor)) { - qWarning("Cannot register type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(elementName), qPrintable(nameSpace), type.versionMajor, type.versionMinor); - return -1; - } + if (uri && !typeName.isEmpty()) { + QString nameSpace = moduleFromUtf8(uri); if (!data->typeRegistrationNamespace.isEmpty()) { // We can only install types into the registered namespace if (nameSpace != data->typeRegistrationNamespace) { QString failure(QCoreApplication::translate("qmlRegisterType", - "Cannot install element '%1' into unregistered namespace '%2'")); - data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace)); - return -1; + "Cannot install %1 '%2' into unregistered namespace '%3'")); + data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace)); + return false; } } else if (data->typeRegistrationNamespace != nameSpace) { // Is the target namespace protected against further registrations? if (data->protectedNamespaces.contains(nameSpace)) { QString failure(QCoreApplication::translate("qmlRegisterType", - "Cannot install element '%1' into protected namespace '%2'")); - data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace)); - return -1; + "Cannot install %1 '%2' into protected namespace '%3'")); + data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace)); + return false; } } } + return true; +} + +int registerType(const QQmlPrivate::RegisterType &type) +{ + QWriteLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + QString elementName = QString::fromUtf8(type.elementName); + if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName)) + return -1; + int index = data->types.count(); QQmlType *dtype = new QQmlType(index, elementName, type); @@ -1008,39 +1080,44 @@ int registerType(const QQmlPrivate::RegisterType &type) return index; } -int registerSingletonType(const QQmlPrivate::RegisterSingletonType &api) +int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) { QWriteLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - QString uri = QString::fromUtf8(api.uri); - QQmlMetaType::SingletonType import; - import.major = api.versionMajor; - import.minor = api.versionMinor; - import.script = api.scriptApi; - import.qobject = api.qobjectApi; - Q_ASSERT(api.typeName); - import.typeName = QString::fromUtf8(api.typeName); - import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0. - - if (data->singletonTypeExists(uri, import.typeName, import.major, import.minor)) { - qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor); - return -1; - } else if (data->typeExists(uri, import.typeName, import.major, import.minor)) { - qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor); + QString typeName = QString::fromUtf8(type.typeName); + if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName)) return -1; + + int index = data->types.count(); + + QQmlType *dtype = new QQmlType(index, typeName, type); + + data->types.append(dtype); + data->idToType.insert(dtype->typeId(), dtype); + + if (!dtype->elementName().isEmpty()) + data->nameToType.insertMulti(dtype->elementName(), dtype); + + if (dtype->baseMetaObject()) + data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype); + + if (type.typeId) { + if (data->objects.size() <= type.typeId) + data->objects.resize(type.typeId + 16); + data->objects.setBit(type.typeId, true); } - int index = data->singletonTypeCount++; + if (!dtype->module().isEmpty()) { + const QHashedString &mod = dtype->module(); - QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri); - if (!apiList) { - QQmlMetaTypeData::SingletonTypeList apis; - apis.singletonTypes << import; - data->singletonTypes.insert(uri, apis); - } else { - apiList->singletonTypes << import; - apiList->sorted = false; + 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; @@ -1113,18 +1190,12 @@ bool QQmlMetaType::isAnyModule(const QString &uri) QReadLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - // first, check Types for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin(); iter != data->uriToModule.end(); ++iter) { if ((*iter)->module() == uri) return true; } - // then, check SingletonTypes - QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri); - if (apiList) - return true; - return false; } @@ -1148,15 +1219,6 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor) return true; - // then, check SingletonTypes - QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(module); - if (apiList) { - foreach (const QQmlMetaType::SingletonType &mApi, apiList->singletonTypes) { - if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct? - return true; - } - } - return false; } @@ -1174,48 +1236,6 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions() return data->parentFunctions; } -static bool operator<(const QQmlMetaType::SingletonType &lhs, const QQmlMetaType::SingletonType &rhs) -{ - return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor); -} - -QQmlMetaType::SingletonType -QQmlMetaType::singletonType(const QString &uri, int versionMajor, int versionMinor) -{ - QReadLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - - QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri); - if (!apiList) - return SingletonType(); - - if (apiList->sorted == false) { - qSort(apiList->singletonTypes.begin(), apiList->singletonTypes.end()); - apiList->sorted = true; - } - - for (int ii = apiList->singletonTypes.count() - 1; ii >= 0; --ii) { - const SingletonType &import = apiList->singletonTypes.at(ii); - if (import.major == versionMajor && import.minor <= versionMinor) - return import; - } - - return SingletonType(); -} - -QHash<QString, QList<QQmlMetaType::SingletonType> > QQmlMetaType::singletonTypes() -{ - QReadLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - - QHash<QString, QList<SingletonType> > singletonTypes; - QStringHash<QQmlMetaTypeData::SingletonTypeList>::ConstIterator it = data->singletonTypes.begin(); - for (; it != data->singletonTypes.end(); ++it) - singletonTypes[it.key()] = it.value().singletonTypes; - - return singletonTypes; -} - QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok) { if (!isQObject(v.userType())) { @@ -1521,6 +1541,25 @@ QList<QQmlType*> QQmlMetaType::qmlTypes() return data->nameToType.values(); } +/*! + Returns the list of registered QML singleton types. +*/ +QList<QQmlType*> QQmlMetaType::qmlSingletonTypes() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QList<QQmlType*> alltypes = data->nameToType.values(); + QList<QQmlType*> retn; + foreach (QQmlType* t, alltypes) { + if (t->isSingleton()) { + retn.append(t); + } + } + + return retn; +} + int QQmlMetaType::QQuickAnchorLineMetaTypeId() { static int id = 0; |