QtQml: Add conversion code for QQmlListProperty to other lists

We have the same conversion code already for lists of value types and
JavaScript arrays. Specialize the common cases of QObjectList and
QQmlListProperty<QObject>.

Pick-to: 6.9 6.8
Fixes: QTBUG-133047
Change-Id: I10826d4a965e18471a486e19befef961ec9a4a6e
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
This commit is contained in:
Ulf Hermann 2025-01-22 10:59:36 +01:00
parent 99052f73d7
commit 3108c58b97
4 changed files with 85 additions and 8 deletions

View File

@ -2728,10 +2728,20 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
} }
const auto wrapperPrivate = wrapper->d(); const auto wrapperPrivate = wrapper->d();
if (wrapperPrivate->propertyType() == metaType) { if (metaType == QMetaType::fromType<QQmlListProperty<QObject> *>()
|| metaType == wrapperPrivate->propertyType()) {
*reinterpret_cast<QQmlListProperty<QObject> *>(data) = *wrapperPrivate->property(); *reinterpret_cast<QQmlListProperty<QObject> *>(data) = *wrapperPrivate->property();
return true; return true;
} }
if (metaType == QMetaType::fromType<QObjectList>()) {
*reinterpret_cast<QObjectList *>(data)
= wrapperPrivate->property()->toList<QObjectList>();
return true;
}
if (convertToIterable(metaType, data, wrapper))
return true;
} }
if (const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>()) { if (const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>()) {

View File

@ -15,6 +15,7 @@ qt_internal_add_test(tst_qmlcppcodegen
LIBRARIES LIBRARIES
Qt::Qml Qt::Qml
Qt::QmlPrivate Qt::QmlPrivate
Qt::QmlMetaPrivate
Qt::GuiPrivate Qt::GuiPrivate
codegen_test_module codegen_test_module
codegen_test_moduleplugin codegen_test_moduleplugin
@ -34,6 +35,7 @@ qt_internal_add_test(tst_qmlcppcodegen_interpreted
LIBRARIES LIBRARIES
Qt::Qml Qt::Qml
Qt::QmlPrivate Qt::QmlPrivate
Qt::QmlMetaPrivate
Qt::GuiPrivate Qt::GuiPrivate
codegen_test_module codegen_test_module
codegen_test_moduleplugin codegen_test_moduleplugin

View File

@ -14,4 +14,23 @@ BirthdayParty {
property list<QtObject> o: self.guests property list<QtObject> o: self.guests
property list<string> s: self.guestNames property list<string> s: self.guestNames
property list<var> v: self.stuffs property list<var> v: self.stuffs
component DataSource : QtObject {
property list<int> numbers: [1, 2]
property list<QtObject> objects: [
QtObject { objectName: "a" },
QtObject { objectName: "b" }
]
property list<Binding> bindings: [
Binding { objectName: "c" },
Binding { objectName: "d" }
]
}
property DataSource src: DataSource {}
property list<int> numbers: src.numbers
property list<QtObject> objects: src.objects
property list<Binding> bindings: src.bindings
property list<QtObject> objectsFromBindings: src.bindings
property list<Binding> nulls: src.objects
} }

View File

@ -15,12 +15,15 @@
#include <data/weathermoduleurl.h> #include <data/weathermoduleurl.h>
#include <data/withlength.h> #include <data/withlength.h>
#include <QtQml/private/qqmlengine_p.h> #include <private/qqmlbind_p.h>
#include <QtQml/private/qqmlpropertycachecreator_p.h> #include <private/qqmlengine_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <QtTest/qsignalspy.h>
#include <QtTest/qtest.h>
#include <QtTest>
#include <QtQml>
#include <QtGui/qcolor.h> #include <QtGui/qcolor.h>
#include <QtGui/qfont.h>
#include <QtGui/qpa/qplatformdialoghelper.h> #include <QtGui/qpa/qplatformdialoghelper.h>
#if QT_CONFIG(process) #if QT_CONFIG(process)
@ -3154,9 +3157,19 @@ void tst_QmlCppCodegen::listAsArgument()
void tst_QmlCppCodegen::listConversion() void tst_QmlCppCodegen::listConversion()
{ {
QQmlEngine e; QQmlEngine e;
QQmlComponent c(&e, QUrl(u"qrc:/qt/qml/TestTypes/listConversion.qml"_s)); QQmlComponent component(&e, QUrl(u"qrc:/qt/qml/TestTypes/listConversion.qml"_s));
QVERIFY2(c.isReady(), qPrintable(c.errorString())); QVERIFY2(component.isReady(), qPrintable(component.errorString()));
QScopedPointer<QObject> o(c.create());
QTest::ignoreMessage(
QtWarningMsg,
QRegularExpression(u"Cannot append QObject\\(0x[0-9a-f]+, name = \"a\"\\) "
"to a QML list of QQmlBind\\*"_s));
QTest::ignoreMessage(
QtWarningMsg,
QRegularExpression(u"Cannot append QObject\\(0x[0-9a-f]+, name = \"b\"\\) "
"to a QML list of QQmlBind\\*"_s));
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull()); QVERIFY(!o.isNull());
QQmlListProperty<QObject> list = o->property("o").value<QQmlListProperty<QObject>>(); QQmlListProperty<QObject> list = o->property("o").value<QQmlListProperty<QObject>>();
@ -3177,6 +3190,39 @@ void tst_QmlCppCodegen::listConversion()
QVariant::fromValue<qsizetype>(3), QVariant::fromValue<qsizetype>(3),
QVariant::fromValue<Person *>(nullptr) QVariant::fromValue<Person *>(nullptr)
})); }));
QCOMPARE(o->property("numbers").value<QList<int>>(), (QList<int>{1, 2}));
auto objects = o->property("objects").value<QQmlListProperty<QObject>>();
QCOMPARE(objects.count(&objects), 2);
const QObject *a = objects.at(&objects, 0);
QVERIFY(a);
QCOMPARE(a->objectName(), u"a"_s);
const QObject *b = objects.at(&objects, 1);
QVERIFY(b);
QCOMPARE(b->objectName(), u"b"_s);
auto bindings = o->property("bindings").value<QQmlListProperty<QQmlBind>>();
QCOMPARE(bindings.count(&bindings), 2);
const QQmlBind *c = bindings.at(&bindings, 0);
QVERIFY(c);
QCOMPARE(c->objectName(), u"c"_s);
const QQmlBind *d = bindings.at(&bindings, 1);
QVERIFY(d);
QCOMPARE(d->objectName(), u"d"_s);
auto objectsFromBindings = o->property("objectsFromBindings").value<QQmlListProperty<QObject>>();
QCOMPARE(objectsFromBindings.count(&objectsFromBindings), 2);
QCOMPARE(objectsFromBindings.at(&objectsFromBindings, 0), c);
QCOMPARE(objectsFromBindings.at(&objectsFromBindings, 1), d);
auto nulls = o->property("nulls").value<QQmlListProperty<QQmlBind>>();
QCOMPARE(nulls.count(&nulls), 2);
QCOMPARE(nulls.at(&nulls, 0), nullptr);
QCOMPARE(nulls.at(&nulls, 1), nullptr);
} }
void tst_QmlCppCodegen::listIndices() void tst_QmlCppCodegen::listIndices()