qmltc: stop using QQmlListReference to append
Instead of using a QQmlListReference to append into lists, use directly the underlying QList<T*> for types compiled with qmltc and QQmlListProperty<T> for types not compiled with qmltc (e.g. types defined in c++). Add a test that tests the private c++ backed "data" property of QQuickItem and different kind of lists (QtObjects and HelloWorlds). Also, append multiple objects to QLists in one go. Fixes: QTBUG-104664 Change-Id: Id5ce6307a241c4c8a167feca677ba5e9b492bc07 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
4b7bd4dae3
commit
60ca8dae85
|
@ -98,6 +98,7 @@ set(qml_sources
|
|||
translations.qml
|
||||
translationsById.qml
|
||||
generalizedGroupedProperty.qml
|
||||
appendToQQmlListProperty.qml
|
||||
|
||||
# support types:
|
||||
DefaultPropertySingleChild.qml
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick
|
||||
import QmltcTests
|
||||
|
||||
Item {
|
||||
|
||||
property var myComponentList
|
||||
property list<int> myValueTypeList
|
||||
property list<QtObject> myQtObjectList
|
||||
property list<HelloWorld> myHelloWorldList
|
||||
|
||||
property Item myItem: Item {
|
||||
// test qquickitems default data list (appending to private property of qquickitem)
|
||||
HelloWorld {
|
||||
hello: "hello1"
|
||||
}
|
||||
HelloWorld {
|
||||
hello: "hello2"
|
||||
}
|
||||
Rectangle {
|
||||
property string hello: "I am a Rectangle."
|
||||
}
|
||||
}
|
||||
|
||||
myComponentList: [
|
||||
"Hello",
|
||||
42,
|
||||
4.0,
|
||||
]
|
||||
|
||||
myValueTypeList: [
|
||||
12489,
|
||||
10,
|
||||
42
|
||||
]
|
||||
|
||||
myQtObjectList: [
|
||||
HelloWorld {
|
||||
hello: "Guten Morgen!"
|
||||
},
|
||||
Rectangle {
|
||||
property string hello: "I am a Rectangle."
|
||||
},
|
||||
HelloWorld {
|
||||
hello: "Moin!"
|
||||
}
|
||||
]
|
||||
|
||||
myHelloWorldList: [
|
||||
HelloWorld{
|
||||
hello: "Good morning1"
|
||||
},
|
||||
HelloWorld {
|
||||
hello: "Good morning2"
|
||||
},
|
||||
HelloWorld {
|
||||
hello: "Good morning3"
|
||||
}
|
||||
]
|
||||
|
||||
property var extended: TypeWithExtension {
|
||||
myList: [
|
||||
HelloWorld {},
|
||||
Rectangle {},
|
||||
QtObject {}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -100,3 +100,8 @@ QBindable<int> TypeWithExtensionNamespace::bindableCount()
|
|||
{
|
||||
return QBindable<int>(&m_count);
|
||||
}
|
||||
|
||||
QQmlListProperty<QObject> Extension::getMyList()
|
||||
{
|
||||
return QQmlListProperty<QObject>(this, &m_myList);
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ class Extension : public QObject
|
|||
QML_ANONYMOUS
|
||||
Q_PROPERTY(int count READ getCount WRITE setCount BINDABLE bindableCount)
|
||||
Q_PROPERTY(double foo READ getFoo WRITE setFoo BINDABLE bindableFoo)
|
||||
Q_PROPERTY(QQmlListProperty<QObject> myList READ getMyList)
|
||||
|
||||
QProperty<int> m_extCount { 0 };
|
||||
QProperty<double> m_foo { 0 };
|
||||
QList<QObject *> m_myList;
|
||||
|
||||
public:
|
||||
Extension(QObject *parent = nullptr);
|
||||
|
@ -27,6 +29,8 @@ public:
|
|||
double getFoo() const;
|
||||
void setFoo(double v);
|
||||
QBindable<double> bindableFoo();
|
||||
|
||||
QQmlListProperty<QObject> getMyList();
|
||||
};
|
||||
|
||||
class IndirectExtension : public Extension
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include "translationsbyid.h"
|
||||
#include "defaultalias.h"
|
||||
#include "generalizedgroupedproperty.h"
|
||||
#include "appendtoqqmllistproperty.h"
|
||||
|
||||
#include "testprivateproperty.h"
|
||||
|
||||
|
@ -183,6 +184,7 @@ void tst_qmltc::initTestCase()
|
|||
QUrl("qrc:/qt/qml/QmltcTests/privatePropertySubclass.qml"),
|
||||
QUrl("qrc:/qt/qml/QmltcTests/calqlatrBits.qml"),
|
||||
QUrl("qrc:/qt/qml/QmltcTests/valueTypeListProperty.qml"),
|
||||
QUrl("qrc:/qt/qml/QmltcTests/appendToQQmlListProperty.qml"),
|
||||
};
|
||||
|
||||
QQmlEngine e;
|
||||
|
@ -2506,4 +2508,76 @@ void tst_qmltc::generalizedGroupedProperty()
|
|||
}
|
||||
}
|
||||
|
||||
void tst_qmltc::appendToQQmlListProperty()
|
||||
{
|
||||
QQmlEngine e;
|
||||
PREPEND_NAMESPACE(appendToQQmlListProperty) fromQmltc(&e);
|
||||
QQmlComponent component(&e, "qrc:/qt/qml/QmltcTests/appendToQQmlListProperty.qml");
|
||||
QVERIFY2(component.isReady(), qPrintable(component.errorString()));
|
||||
QScopedPointer<QObject> fromEngine(component.create());
|
||||
|
||||
auto itemFromEngine = fromEngine->property("myItem").value<QQuickItem *>();
|
||||
auto itemFromQmltc = fromQmltc.myItem();
|
||||
|
||||
QCOMPARE(itemFromEngine->children().size(), 3);
|
||||
QCOMPARE(itemFromQmltc->children().size(), 3);
|
||||
|
||||
QCOMPARE(itemFromEngine->children().at(0)->property("hello"), u"hello1"_s);
|
||||
QCOMPARE(itemFromEngine->children().at(1)->property("hello"), u"hello2"_s);
|
||||
QCOMPARE(itemFromEngine->children().at(2)->property("hello"), u"I am a Rectangle."_s);
|
||||
|
||||
QCOMPARE(itemFromQmltc->children().at(0)->property("hello"), u"hello1"_s);
|
||||
QCOMPARE(itemFromQmltc->children().at(1)->property("hello"), u"hello2"_s);
|
||||
QCOMPARE(itemFromQmltc->children().at(2)->property("hello"), u"I am a Rectangle."_s);
|
||||
|
||||
QVariantList referenceComponentList = { QVariant(u"Hello"_s), QVariant(42), QVariant(4.0) };
|
||||
QCOMPARE(fromQmltc.myComponentList().toList(), referenceComponentList);
|
||||
QCOMPARE(fromEngine->property("myComponentList").toList(), referenceComponentList);
|
||||
|
||||
QList<int> referenceValueTypeList = { 12489, 10, 42 };
|
||||
QVariantList referenceValueTypeList2 = { 12489, 10, 42 };
|
||||
QCOMPARE(fromQmltc.myValueTypeList().toList(), referenceValueTypeList);
|
||||
QCOMPARE(fromEngine->property("myValueTypeList").toList(), referenceValueTypeList2);
|
||||
|
||||
QQmlListReference qtObjectsFromQmltc(&fromQmltc, "myQtObjectList");
|
||||
QVERIFY(qtObjectsFromQmltc.isValid());
|
||||
QQmlListReference qtObjectsFromEngine(fromEngine.data(), "myQtObjectList");
|
||||
QVERIFY(qtObjectsFromEngine.isValid());
|
||||
|
||||
QCOMPARE(qtObjectsFromQmltc.size(), 3);
|
||||
QCOMPARE(qtObjectsFromEngine.size(), 3);
|
||||
|
||||
QCOMPARE(qtObjectsFromQmltc.at(0)->property("hello"), u"Guten Morgen!"_s);
|
||||
QCOMPARE(qtObjectsFromQmltc.at(1)->property("hello"), u"I am a Rectangle."_s);
|
||||
QCOMPARE(qtObjectsFromQmltc.at(2)->property("hello"), u"Moin!"_s);
|
||||
|
||||
QCOMPARE(qtObjectsFromEngine.at(0)->property("hello"), u"Guten Morgen!"_s);
|
||||
QCOMPARE(qtObjectsFromEngine.at(1)->property("hello"), u"I am a Rectangle."_s);
|
||||
QCOMPARE(qtObjectsFromEngine.at(2)->property("hello"), u"Moin!"_s);
|
||||
|
||||
QQmlListReference qtHWFromQmltc(&fromQmltc, "myHelloWorldList");
|
||||
QQmlListReference qtHWFromEngine(fromEngine.data(), "myHelloWorldList");
|
||||
|
||||
QCOMPARE(qtHWFromQmltc.size(), 3);
|
||||
QCOMPARE(qtHWFromEngine.size(), 3);
|
||||
|
||||
QCOMPARE(qtHWFromQmltc.at(0)->property("hello"), u"Good morning1"_s);
|
||||
QCOMPARE(qtHWFromQmltc.at(1)->property("hello"), u"Good morning2"_s);
|
||||
QCOMPARE(qtHWFromQmltc.at(2)->property("hello"), u"Good morning3"_s);
|
||||
|
||||
QCOMPARE(qtHWFromEngine.at(0)->property("hello"), u"Good morning1"_s);
|
||||
QCOMPARE(qtHWFromEngine.at(1)->property("hello"), u"Good morning2"_s);
|
||||
QCOMPARE(qtHWFromEngine.at(2)->property("hello"), u"Good morning3"_s);
|
||||
|
||||
// make sure that extensions are handled correctly, as they require a slightly different code
|
||||
// path to be generated
|
||||
QQmlListReference extendedFromQmltc(fromQmltc.extended().value<QObject *>(), "myList");
|
||||
QVERIFY(extendedFromQmltc.isValid());
|
||||
QQmlListReference extendedFromEngine(fromEngine->property("extended").value<QObject *>(),
|
||||
"myList");
|
||||
QVERIFY(extendedFromEngine.isValid());
|
||||
QCOMPARE(extendedFromQmltc.size(), 3);
|
||||
QCOMPARE(extendedFromEngine.size(), 3);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qmltc)
|
||||
|
|
|
@ -85,4 +85,5 @@ private slots:
|
|||
void valueTypeListProperty();
|
||||
void translations();
|
||||
void generalizedGroupedProperty();
|
||||
void appendToQQmlListProperty();
|
||||
};
|
||||
|
|
|
@ -92,17 +92,21 @@ void QmltcCodeGenerator::generate_assignToListProperty(
|
|||
const bool populateLocalListProperty = qmlListVarName.isEmpty();
|
||||
|
||||
if (populateLocalListProperty) {
|
||||
qmlListVarName = u"listref_%1"_s.arg(p.propertyName());
|
||||
*block << u"QQmlListReference %1(%2, %3);"_s.arg(
|
||||
qmlListVarName, accessor,
|
||||
QQmlJSUtils::toLiteral(p.propertyName(), u"QByteArrayLiteral"));
|
||||
*block << QStringLiteral("Q_ASSERT(%1.canAppend());").arg(qmlListVarName);
|
||||
auto [extensionPrologue, extensionAccessor, extensionEpilogue] =
|
||||
QmltcCodeGenerator::wrap_extensionType(
|
||||
type, p, QmltcCodeGenerator::wrap_privateClass(accessor, p));
|
||||
|
||||
qmlListVarName = u"listprop_%1"_s.arg(p.propertyName());
|
||||
*block << u"QQmlListProperty<%1> %2;"_s.arg(p.type()->internalName(), qmlListVarName);
|
||||
*block << extensionPrologue;
|
||||
*block << u"%1 = %2->%3();"_s.arg(qmlListVarName, extensionAccessor, p.read());
|
||||
*block << extensionEpilogue;
|
||||
}
|
||||
for (const QString &value : values) {
|
||||
auto [prologue, wrappedValue, epilogue] =
|
||||
QmltcCodeGenerator::wrap_mismatchingTypeConversion(p, value);
|
||||
*block << prologue;
|
||||
*block << u"%1.append(%2);"_s.arg(qmlListVarName, wrappedValue);
|
||||
*block << u"%1.append(std::addressof(%1), %2);"_s.arg(qmlListVarName, wrappedValue);
|
||||
*block << epilogue;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue