diff options
Diffstat (limited to 'src/qml/qml/qqml.cpp')
-rw-r--r-- | src/qml/qml/qqml.cpp | 220 |
1 files changed, 210 insertions, 10 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 5b16a3c9e2..fe4e2f4e55 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -46,6 +46,7 @@ #include <private/qqmlmetatypedata_p.h> #include <private/qqmltype_p_p.h> #include <private/qqmltypemodule_p_p.h> +#include <private/qqmltypenotavailable_p.h> #include <QtCore/qmutex.h> @@ -61,7 +62,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h //From qqml.h bool qmlProtectModule(const char *uri, int majVersion) { - return QQmlMetaType::protectModule(uri, majVersion); + return QQmlMetaType::protectModule(QString::fromUtf8(uri), majVersion); } //From qqml.h @@ -103,33 +104,188 @@ QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJS return m_object; }; +static QVector<int> availableRevisions(const QMetaObject *metaObject) +{ + QVector<int> revisions; + if (!metaObject) + return revisions; + const int propertyOffset = metaObject->propertyOffset(); + const int propertyCount = metaObject->propertyCount(); + for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount; + propertyIndex < propertyEnd; ++propertyIndex) { + const QMetaProperty property = metaObject->property(propertyIndex); + if (int revision = property.revision()) + revisions.append(revision); + } + const int methodOffset = metaObject->methodOffset(); + const int methodCount = metaObject->methodCount(); + for (int methodIndex = methodOffset, methodEnd = methodOffset + methodCount; + methodIndex < methodEnd; ++methodIndex) { + const QMetaMethod method = metaObject->method(methodIndex); + if (int revision = method.revision()) + revisions.append(revision); + } + + // Need to also check parent meta objects, as their revisions are inherited. + if (const QMetaObject *superMeta = metaObject->superClass()) + revisions += availableRevisions(superMeta); + + return revisions; +} + /* 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 == AutoParentRegistration) { + QQmlType dtype; + switch (type) { + case AutoParentRegistration: return QQmlMetaType::registerAutoParentFunction( *reinterpret_cast<RegisterAutoParent *>(data)); - } else if (type == QmlUnitCacheHookRegistration) { + case QmlUnitCacheHookRegistration: return QQmlMetaType::registerUnitCacheHook( *reinterpret_cast<RegisterQmlUnitCacheHook *>(data)); + case TypeAndRevisionsRegistration: { + const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data); + const char *elementName = classElementName(type.classInfoMetaObject); + const bool creatable = (elementName != nullptr) + && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true); + + const QString noCreateReason = creatable + ? QString() + : QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason")); + RegisterType revisionRegistration = { + 1, + type.typeId, + type.listId, + creatable ? type.objectSize : 0, + nullptr, + noCreateReason, + type.uri, + type.versionMajor, + -1, + nullptr, + type.metaObject, + type.attachedPropertiesFunction, + type.attachedPropertiesMetaObject, + type.parserStatusCast, + type.valueSourceCast, + type.valueInterceptorCast, + type.extensionObjectCreate, + type.extensionMetaObject, + nullptr, + -1 + }; + + const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0); + const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1); + + auto revisions = availableRevisions(type.metaObject); + revisions.append(qMax(added, 0)); + if (type.attachedPropertiesMetaObject) + revisions += availableRevisions(type.attachedPropertiesMetaObject); + + std::sort(revisions.begin(), revisions.end()); + const auto it = std::unique(revisions.begin(), revisions.end()); + revisions.erase(it, revisions.end()); + + const bool typeWasRemoved = removed >= added; + for (int revision : revisions) { + if (revision < added) + continue; + + // When removed, we still add revisions, but anonymous ones + if (typeWasRemoved && revision >= removed) { + revisionRegistration.elementName = nullptr; + revisionRegistration.create = nullptr; + } else { + revisionRegistration.elementName = elementName; + revisionRegistration.create = creatable ? type.create : nullptr; + } + + // Equivalent of qmlRegisterRevision<T, revision>(...) + revisionRegistration.versionMinor = revision; + revisionRegistration.revision = revision; + revisionRegistration.customParser = type.customParserFactory(); + + qmlregister(TypeRegistration, &revisionRegistration); + } + break; } + case SingletonAndRevisionsRegistration: { + const RegisterSingletonTypeAndRevisions &type + = *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data); + const char *elementName = classElementName(type.classInfoMetaObject); + RegisterSingletonType revisionRegistration = { + QmlCurrentSingletonTypeRegistrationVersion, + type.uri, + type.versionMajor, + -1, + elementName, - QQmlType dtype; - if (type == TypeRegistration) + type.scriptApi, + nullptr, + type.instanceMetaObject, + type.typeId, + -1, + + type.generalizedQobjectApi + }; + + const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0); + const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1); + + auto revisions = availableRevisions(type.instanceMetaObject); + revisions.append(qMax(added, 0)); + + std::sort(revisions.begin(), revisions.end()); + const auto it = std::unique(revisions.begin(), revisions.end()); + revisions.erase(it, revisions.end()); + + const bool typeWasRemoved = removed >= added; + for (int revision : qAsConst(revisions)) { + if (revision < added) + continue; + + // When removed, we still add revisions, but anonymous ones + if (typeWasRemoved && revision >= removed) { + revisionRegistration.typeName = nullptr; + revisionRegistration.scriptApi = nullptr; + revisionRegistration.generalizedQobjectApi = nullptr; + } else { + revisionRegistration.typeName = elementName; + revisionRegistration.scriptApi = type.scriptApi; + revisionRegistration.generalizedQobjectApi = type.generalizedQobjectApi; + } + + // Equivalent of qmlRegisterRevision<T, revision>(...) + revisionRegistration.versionMinor = revision; + revisionRegistration.revision = revision; + + qmlregister(SingletonRegistration, &revisionRegistration); + } + break; + } + case TypeRegistration: dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)); - else if (type == InterfaceRegistration) + break; + case InterfaceRegistration: dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)); - else if (type == SingletonRegistration) + break; + case SingletonRegistration: dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data)); - else if (type == CompositeRegistration) + break; + case CompositeRegistration: dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data)); - else if (type == CompositeSingletonRegistration) + break; + case CompositeSingletonRegistration: dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data)); - else + break; + default: return -1; + } if (!dtype.isValid()) return -1; @@ -155,6 +311,50 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) case CompositeSingletonRegistration: QQmlMetaType::unregisterType(data); break; + case TypeAndRevisionsRegistration: + case SingletonAndRevisionsRegistration: + // Currently unnecessary. We'd need a special data structure to hold + // URI + majorVersion and then we'd iterate the minor versions, look up the + // associated QQmlType objects by uri/elementName/major/minor and qmlunregister + // each of them. + Q_UNREACHABLE(); + break; + } +} + +namespace QQmlPrivate { + template<> + void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>( + const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject) + { + using T = QQmlTypeNotAvailable; + + QML_GETTYPENAMES + + RegisterTypeAndRevisions type = { + 0, + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + 0, + nullptr, + + uri, + versionMajor, + + &QQmlTypeNotAvailable::staticMetaObject, + classInfoMetaObject, + + attachedPropertiesFunc<T>(), + attachedPropertiesMetaObject<T>(), + + StaticCastSelector<T, QQmlParserStatus>::cast(), + StaticCastSelector<T, QQmlPropertyValueSource>::cast(), + StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(), + + nullptr, nullptr, qmlCreateCustomParser<T> + }; + + qmlregister(TypeAndRevisionsRegistration, &type); } } |