From c07cc979335216a034a3958780150d301e996f67 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 14 Jun 2023 08:32:13 +0200 Subject: QML: Allow creating constructible value types from variant objects VariantObject as source for value type constructions should work the same way as other types. Change-Id: I35770adf0486b404673ee00800fb1d3e429a23cf Reviewed-by: Fabian Kosmale (cherry picked from commit 0bb0eeeb09580de8bccef996f9b4099fb7d1b482) --- src/qml/jsruntime/qv4engine.cpp | 2 + .../data/structuredValueTypes.qml | 4 ++ tests/auto/qml/qqmlvaluetypeproviders/testtypes.h | 15 ++++ .../tst_qqmlvaluetypeproviders.cpp | 84 ++++++++++++++++++++++ 4 files changed, 105 insertions(+) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index dc26d6a93a..8d3d5e6b46 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2685,6 +2685,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi proto = proto->getPrototypeOf(); } } + } else if (QQmlValueTypeProvider::createValueType(var, metaType, data)) { + return true; } } else if (value.isNull() && isPointer) { *reinterpret_cast(data) = nullptr; diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/structuredValueTypes.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/structuredValueTypes.qml index a6f05d7981..b0ae1cda1c 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/data/structuredValueTypes.qml +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/structuredValueTypes.qml @@ -49,4 +49,8 @@ MyTypeObject { property QtObject object: QtObject {} property constructible fromObject: object + property int listResult: acceptConstructibles([Qt.resolvedUrl("foo/bar.baz"), fromObject, 12]) + + property var insanity: ({}) + property structured fromInsanity: acceptStructured(insanity) } diff --git a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h index 7b308ff338..424995b594 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h +++ b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h @@ -34,6 +34,7 @@ public: ConstructibleValueType() = default; Q_INVOKABLE ConstructibleValueType(int foo) : m_foo(foo) {} Q_INVOKABLE ConstructibleValueType(QObject *) : m_foo(67) {} + Q_INVOKABLE ConstructibleValueType(const QUrl &) : m_foo(68) {} int foo() const { return m_foo; } @@ -356,6 +357,20 @@ public: setAVariant(QVariant::fromValue(a)); } + Q_INVOKABLE int acceptConstructibles(const QList &constructibles) + { + int result = 0; + for (const auto &c: constructibles) { + result += c.foo(); + } + return result; + } + + Q_INVOKABLE StructuredValueType acceptStructured(const StructuredValueType &a) + { + return a; + } + signals: void changed(); void runScript(); diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp index 1100827f34..fa4bf6e058 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp +++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp @@ -362,6 +362,90 @@ void tst_qqmlvaluetypeproviders::structured() ConstructibleValueType(nullptr)); QCOMPARE(o->property("aVariant").value(), ConstructibleValueType(nullptr)); + + QCOMPARE(o->property("listResult").toInt(), 12 + 67 + 68); + + + // You can store all kinds of insanity in a VariantObject, but we generally don't. + // Since we cannot rule out the possibility of there being such VariantObjects, we need to test + // their conversions. + + + QCOMPARE(o->property("fromInsanity").value(), StructuredValueType()); + + QV4::Scope scope(e.handle()); + QV4::ScopedString name(scope, scope.engine->newString("insanity")); + + QObject *po = o.data(); + QV4::ScopedObject js( + scope, scope.engine->metaTypeToJS(QMetaType::fromType(), &po)); + + const QVariantHash hash { + {"i", 12}, + {"c", QUrl("http://example.com")}, + {"p", QVariantMap { + {"x", 17}, + {"y", 18} + }} + }; + QV4::ScopedValue hashValue( + scope, e.handle()->newVariantObject(QMetaType::fromType(), &hash)); + + js->put(name, hashValue); + + StructuredValueType fromHash; + fromHash.setI(12); + fromHash.setC(ConstructibleValueType(QUrl())); + fromHash.setP(QPointF(17, 18)); + + QCOMPARE(o->property("fromInsanity").value(), fromHash); + + const QVariantMap map { + {"i", 13}, + {"c", QVariant::fromValue(po) }, + {"p", QVariantMap { + {"x", 19}, + {"y", 20} + }} + }; + QV4::ScopedValue mapValue( + scope, e.handle()->newVariantObject(QMetaType::fromType(), &map)); + js->put(name, mapValue); + + StructuredValueType fromMap; + fromMap.setI(13); + fromMap.setC(ConstructibleValueType(po)); + fromMap.setP(QPointF(19, 20)); + + QCOMPARE(o->property("fromInsanity").value(), fromMap); + + BarrenValueType immediate; + immediate.setI(14); + QV4::ScopedValue immediateValue( + scope, e.handle()->newVariantObject(QMetaType::fromType(), &immediate)); + js->put(name, immediateValue); + + StructuredValueType fromImmediate; + fromImmediate.setI(14); + + QCOMPARE(o->property("fromInsanity").value(), fromImmediate); + + QQmlComponent c2(&e); + c2.setData( + "import QtQml; QtObject { property int i: 99; property point p: ({x: 3, y: 4}) }", QUrl()); + QVERIFY(c2.isReady()); + QScopedPointer o2(c2.create()); + QVERIFY(!o2.isNull()); + QObject *object = o2.data(); + QV4::ScopedValue objectValue( + scope, e.handle()->newVariantObject(QMetaType::fromType(), &object)); + js->put(name, objectValue); + + StructuredValueType fromObject; + fromObject.setI(99); + fromObject.setP(QPointF(3, 4)); + + QCOMPARE(o->property("fromInsanity").value(), fromObject); } void tst_qqmlvaluetypeproviders::recursive() -- cgit v1.2.3