aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-11-06 15:13:27 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-11-11 11:37:49 +0100
commitf0908255c9921371d886eff0b8ce245929b50d88 (patch)
treeb246bca2fcdae9ee906acc6e2b54a874b36734ea /src/qml/qml
parent40c0cbda771e9888999d8b78179e9600de4e7795 (diff)
QtQml: Integrate sequences with registration macros
You get to write QML_SEQUENTIAL_CONTAINER(value_type) now, and qmltyperegistrar will generate a sensible registration call from that. A registration might look like this: struct MyStringListForeign { Q_GADGET QML_ANONYMOUS QML_SEQUENTIAL_CONTAINER(QString) QML_FOREIGN(MyStringList) QML_ADDED_IN_VERSION(3, 1) }; It's unfortunate that we need to use a metaobject to transfer all of this information, but there is no other sensible way. Transform the containers defined in qv4sequenceobject.cpp to use the new style, and move them out of the builtins, into QtQml. Recognize that only one of them was ever tested, and add tests for the rest. Task-number: QTBUG-82443 Change-Id: I3a30f9e27266bb575eea26c5daf5dad1ec461cc5 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqml.cpp43
-rw-r--r--src/qml/qml/qqml.h33
-rw-r--r--src/qml/qml/qqmlmetatype.cpp6
-rw-r--r--src/qml/qml/qqmlprivate.h46
4 files changed, 120 insertions, 8 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 20608a60e4..40e629284b 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -421,6 +421,48 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
}
break;
}
+ case SequentialContainerAndRevisionsRegistration: {
+ const RegisterSequentialContainerAndRevisions &type
+ = *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
+ const char *elementName = classElementName(type.classInfoMetaObject);
+ RegisterSequentialContainer revisionRegistration = {
+ 0,
+ type.uri,
+ type.version,
+ elementName,
+ type.typeId,
+ type.metaSequence,
+ QTypeRevision()
+ };
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromMinorVersion(0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+
+ QVector<QTypeRevision> revisions = { added };
+ uniqueRevisions(&revisions, type.version, added);
+
+ for (QTypeRevision revision : qAsConst(revisions)) {
+ if (revision < added)
+ continue;
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ // When removed, we still add revisions, but anonymous ones
+ if (removed.isValid() && !(revision < removed))
+ revisionRegistration.typeName = nullptr;
+ else
+ revisionRegistration.typeName = elementName;
+
+ assignVersions(&revisionRegistration, revision, type.version);
+ const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+ }
+ break;
+ }
case TypeRegistration:
dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data));
break;
@@ -472,6 +514,7 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
break;
case TypeAndRevisionsRegistration:
case SingletonAndRevisionsRegistration:
+ case SequentialContainerAndRevisionsRegistration:
// 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
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 75f7ae5f06..7f0c81c514 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -94,6 +94,14 @@
template<typename T, typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
+#define QML_SEQUENTIAL_CONTAINER(VALUE_TYPE) \
+ Q_CLASSINFO("QML.Sequence", #VALUE_TYPE) \
+ using QmlSequenceValueType = VALUE_TYPE; \
+ enum class QmlIsSequence {yes = true}; \
+ template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSequence; \
+ template<typename T, typename... Args> \
+ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
+
#define QML_ADDED_IN_MINOR_VERSION(VERSION) \
Q_CLASSINFO("QML.AddedInVersion", Q_REVISION(VERSION))
@@ -792,17 +800,18 @@ inline int qmlRegisterAnonymousSequentialContainer(const char *uri, int versionM
QTypeRevision::fromMajorVersion(versionMajor),
nullptr,
QMetaType::fromType<Container>(),
- QMetaSequence::fromContainer<Container>()
+ QMetaSequence::fromContainer<Container>(),
+ QTypeRevision::zero()
};
return QQmlPrivate::qmlregister(QQmlPrivate::SequentialContainerRegistration, &type);
}
-template<class T, class Resolved, class Extended, bool Singleton, bool Interface>
+template<class T, class Resolved, class Extended, bool Singleton, bool Interface, bool Sequence>
struct QmlTypeAndRevisionsRegistration;
template<class T, class Resolved, class Extended>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *extension)
{
@@ -812,8 +821,19 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false> {
}
};
+template<class T, class Resolved>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *)
+ {
+ QQmlPrivate::qmlRegisterSequenceAndRevisions<Resolved>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds);
+ }
+};
+
template<class T, class Resolved, class Extended>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *extension)
{
@@ -824,7 +844,7 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false> {
};
template<class T, class Resolved>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *)
{
@@ -845,7 +865,8 @@ void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor, QList<int>
T, typename QQmlPrivate::QmlResolved<T>::Type,
typename QQmlPrivate::QmlExtended<T>::Type,
QQmlPrivate::QmlSingleton<T>::Value,
- QQmlPrivate::QmlInterface<T>::Value>
+ QQmlPrivate::QmlInterface<T>::Value,
+ QQmlPrivate::QmlSequence<T>::Value>
::registerTypeAndRevisions(uri, versionMajor, qmlTypeIds,
QQmlPrivate::QmlExtendedNamespace<T>::metaObject());
qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor, qmlTypeIds);
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index e59ebc97eb..9dea173127 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -667,7 +667,8 @@ QQmlType QQmlMetaType::registerSequentialContainer(
QQmlMetaTypeDataPtr data;
- if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, QString(),
+ const QString typeName = QString::fromUtf8(container.typeName);
+ if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, typeName,
container.version, {})) {
return QQmlType();
}
@@ -675,8 +676,9 @@ QQmlType QQmlMetaType::registerSequentialContainer(
QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::SequentialContainerType);
data->registerType(priv);
- priv->setName(QString::fromUtf8(container.uri), QString());
+ priv->setName(QString::fromUtf8(container.uri), typeName);
priv->version = container.version;
+ priv->revision = container.revision;
priv->typeId = container.typeId;
*priv->extraData.ld = container.metaSequence;
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 19072f0751..feee3f8686 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -574,6 +574,19 @@ namespace QQmlPrivate
const char *typeName;
QMetaType typeId;
QMetaSequence metaSequence;
+ QTypeRevision revision;
+ };
+
+ struct RegisterSequentialContainerAndRevisions {
+ int structVersion;
+ const char *uri;
+ QTypeRevision version;
+
+ const QMetaObject *classInfoMetaObject;
+ QMetaType typeId;
+ QMetaSequence metaSequence;
+
+ QVector<int> *qmlTypeIds;
};
struct AOTCompiledFunction {
@@ -605,6 +618,7 @@ namespace QQmlPrivate
TypeAndRevisionsRegistration = 7,
SingletonAndRevisionsRegistration = 8,
SequentialContainerRegistration = 9,
+ SequentialContainerAndRevisionsRegistration = 10,
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
@@ -717,6 +731,20 @@ namespace QQmlPrivate
};
template<class T, class = std::void_t<>>
+ struct QmlSequence
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlSequence<T, std::void_t<typename T::QmlIsSequence>>
+ {
+ Q_STATIC_ASSERT((std::is_same_v<typename T::QmlSequenceValueType,
+ typename QmlResolved<T>::Type::value_type>));
+ static constexpr bool Value = bool(T::QmlIsSequence::yes);
+ };
+
+ template<class T, class = std::void_t<>>
struct QmlInterface
{
static constexpr bool Value = false;
@@ -823,6 +851,24 @@ namespace QQmlPrivate
qmlregister(TypeAndRevisionsRegistration, &type);
}
+ template<typename T>
+ void qmlRegisterSequenceAndRevisions(const char *uri, int versionMajor,
+ const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds)
+ {
+ RegisterSequentialContainerAndRevisions type = {
+ 0,
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+ classInfoMetaObject,
+ QMetaType::fromType<T>(),
+ QMetaSequence::fromContainer<T>(),
+ qmlTypeIds
+ };
+
+ qmlregister(SequentialContainerAndRevisionsRegistration, &type);
+ }
+
template<>
void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,