From 228efa08af2590081c163dc9617f785d88850cf3 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Tue, 20 Jun 2023 14:21:18 +0200 Subject: [PATCH] QQmlDelegateModelPrivate::itemsRemoved - keep persisted items in cache QQmlDelegateModelPrivate::itemsRemoved removes unreferenced items from the cache. If an item is persisted and unreferenced, it's disappearance from the cache will prevent display models (e.g. qqmllistmodel) from looping over all delegates. This can lead incomplete clear operations and dangling screen artifacts. This patch adds a condition to prevent persited items from being removed from the cache. It adds a test function in tst_QQmlDelegateModel. Fixes: QTBUG-98365 Change-Id: I52e6344be85ca64eadbf44378de32cde126ff07a Reviewed-by: Richard Moe Gustavsen (cherry picked from commit da38eaf433ac1c241a29766ea8a82237caa497b5) Reviewed-by: Qt Cherry-pick Bot --- src/qmlmodels/qqmldelegatemodel.cpp | 2 +- .../data/persistedItemsCache.qml | 62 +++++++++++++++++++ .../tst_qqmldelegatemodel.cpp | 17 +++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmldelegatemodel/data/persistedItemsCache.qml diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index 444379818a..c6e06ac6f4 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -1617,7 +1617,7 @@ void QQmlDelegateModelPrivate::itemsRemoved( emitDestroyingItem(object); cacheItem->scriptRef -= 1; } - if (!cacheItem->isReferenced()) { + if (!cacheItem->isReferenced() && !remove.inGroup(Compositor::Persisted)) { m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag); m_cache.removeAt(cacheIndex); delete cacheItem; diff --git a/tests/auto/qml/qqmldelegatemodel/data/persistedItemsCache.qml b/tests/auto/qml/qqmldelegatemodel/data/persistedItemsCache.qml new file mode 100644 index 0000000000..5ae2038e1f --- /dev/null +++ b/tests/auto/qml/qqmldelegatemodel/data/persistedItemsCache.qml @@ -0,0 +1,62 @@ +import QtQuick +import QtQuick.Window +import QtQml.Models + +Window { + id: win + visible: true + width: 640 + height: 480 + property int destroyCount : 0; + property int createCount : 0; + property alias testListModel: mdl + + DelegateModel { + id: visualModel + model: ListModel { + id: mdl + ListElement { + name: "a" + hidden: false + } + ListElement { + name: "b" + hidden: true + } + ListElement { + name: "c" + hidden: false + } + } + + filterOnGroup: "selected" + + groups: [ + DelegateModelGroup { + name: "selected" + includeByDefault: true + } + ] + + delegate: Text { + visible: DelegateModel.inSelected + property var idx + Component.onCompleted: { + ++createCount + idx = index + DelegateModel.inPersistedItems = true + DelegateModel.inSelected = !model.hidden + } + Component.onDestruction: ++destroyCount + text: model.name + } + } + + ListView { + id: listView + model: visualModel + anchors.fill: parent + focus: true + } + +} diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp index 8b433d346c..4169690ed0 100644 --- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp +++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ private slots: void nestedDelegates(); void typedModelData(); void deleteRace(); + void persistedItemsStayInCache(); }; class AbstractItemModel : public QAbstractItemModel @@ -289,6 +291,21 @@ void tst_QQmlDelegateModel::deleteRace() QTRY_COMPARE(o->property("count").toInt(), 0); } +void tst_QQmlDelegateModel::persistedItemsStayInCache() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("persistedItemsCache.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + std::unique_ptr object(component.create()); + QVERIFY(object); + const QVariant properyListModel = object->property("testListModel"); + QQmlListModel *listModel = qvariant_cast(properyListModel); + QVERIFY(listModel); + QTRY_COMPARE(object->property("createCount").toInt(), 3); + listModel->clear(); + QTRY_COMPARE(object->property("destroyCount").toInt(), 3); +} + QTEST_MAIN(tst_QQmlDelegateModel) #include "tst_qqmldelegatemodel.moc"