aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-06-18 09:24:04 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2021-06-23 16:33:47 +0200
commit835955cf8100c7c3381d11b275f62467844d8d7f (patch)
tree3b47476bcbf1ece16b916a1b0ee4b144f3230d61
parent6c56f0eef6a6c54e437d6472eeda25ef4e7b9862 (diff)
Ensure model is in context if required properties are not used
We need to set the set the contextObject already in QQmlDelegateModelPrivate::object, as the context property might be accessed in a child component before we are able to run setRequiredProperties (which would set-up the context in case there are no required properties). Instead of delaying setting the context object, we clear it now in setRequiredProperties. This has the drawback that one might be able to access context properties on initial component setup which should not exist (due to the presence of required properties). This could be avoided by inspecting the Compilation Unit and only setting the context if we do not find required properties, however that needs further work to expose the necessary information. Fixes: QTBUG-94223 Change-Id: I678de81408539417fc650f94da4c9f0d3167653d Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> (cherry picked from commit 58cd06033cacadab541efaa16a3eecec37dab0fa) Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io>
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp13
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/ImageToggle.qml21
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/contextAccessedByHandler.qml31
-rw-r--r--tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp22
4 files changed, 87 insertions, 0 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index dbd73ae667..e256964029 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -968,6 +968,17 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
contextData->extraObject = modelItemToIncubate;
}
+ // If we have required properties, we clear the context object
+ // so that the model role names are not polluting the context
+ if (incubating) {
+ Q_ASSERT(incubating->contextData);
+ incubating->contextData->contextObject = nullptr;
+ }
+
+ if (proxyContext) {
+ proxyContext->contextObject = nullptr;
+ }
+
if (incubatorPriv->requiredProperties().empty())
return;
RequiredProperties &requiredProperties = incubatorPriv->requiredProperties();
@@ -1279,6 +1290,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
QQmlContextData *ctxt = new QQmlContextData;
ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
+ ctxt->contextObject = cacheItem;
cacheItem->contextData = ctxt;
if (m_adaptorModel.hasProxyObject()) {
@@ -1289,6 +1301,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
QObject *proxied = proxy->proxiedObject();
cacheItem->incubationTask->proxiedObject = proxied;
cacheItem->incubationTask->proxyContext = ctxt;
+ ctxt->contextObject = cacheItem;
// We don't own the proxied object. We need to clear it if it goes away.
QObject::connect(proxied, &QObject::destroyed,
cacheItem, &QQmlDelegateModelItem::childContextObjectDestroyed);
diff --git a/tests/auto/qml/qqmldelegatemodel/data/ImageToggle.qml b/tests/auto/qml/qqmldelegatemodel/data/ImageToggle.qml
new file mode 100644
index 0000000000..fa154b25f3
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/data/ImageToggle.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+Item {
+ property var isSelected: null
+ property string source
+ implicitWidth: 16
+ implicitHeight: 16
+
+ onSourceChanged: {
+ updateImageSource()
+ }
+
+ onIsSelectedChanged: {
+ updateImageSource()
+ }
+
+ function updateImageSource() {
+ let result = isSelected ? source + "_selected_dark.png" : source + "_active_dark.png"
+ }
+
+}
diff --git a/tests/auto/qml/qqmldelegatemodel/data/contextAccessedByHandler.qml b/tests/auto/qml/qqmldelegatemodel/data/contextAccessedByHandler.qml
new file mode 100644
index 0000000000..46d7524527
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/data/contextAccessedByHandler.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 640
+ height: 480
+ property bool works: myView.currentItem.okay
+
+ ListView {
+ id: myView
+ model: myModel
+ anchors.fill: parent
+ delegate: Row {
+ property alias okay: image.isSelected
+ ImageToggle {
+ id: image
+ source: "glyph_16_arrow_patch"
+ isSelected: model.age < 6
+ }
+ Text {
+ text: "age:" + model.age + " selected:" + image.isSelected
+ }
+ }
+ }
+
+ ListModel {
+ id: myModel
+ ListElement { type: "Cat"; age: 3; }
+ ListElement { type: "Dog"; age: 2; }
+ }
+}
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
index 9bc359d243..35f1e2c94d 100644
--- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
@@ -46,6 +46,7 @@ private slots:
void valueWithoutCallingObjectFirst();
void filterOnGroup_removeWhenCompleted();
void qtbug_86017();
+ void contextAccessedByHandler();
};
class AbstractItemModel : public QAbstractItemModel
@@ -164,6 +165,27 @@ void tst_QQmlDelegateModel::qtbug_86017()
QCOMPARE(model->filterGroup(), "selected");
}
+void tst_QQmlDelegateModel::filterOnGroup_removeWhenCompleted()
+{
+ QQuickView view(testFileUrl("removeFromGroup.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QQuickItem *root = view.rootObject();
+ QVERIFY(root);
+ QQmlDelegateModel *model = root->findChild<QQmlDelegateModel*>();
+ QVERIFY(model);
+ QVERIFY(QTest::qWaitFor([=]{ return model->count() == 2; }));
+}
+
+void tst_QQmlDelegateModel::contextAccessedByHandler()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextAccessedByHandler.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY2(root, qPrintable(component.errorString()));
+ QVERIFY(root->property("works").toBool());
+}
+
QTEST_MAIN(tst_QQmlDelegateModel)
#include "tst_qqmldelegatemodel.moc"