mirror of
git://slackware.nl/current.git
synced 2025-01-14 08:01:11 +01:00
131 lines
4.9 KiB
Diff
131 lines
4.9 KiB
Diff
|
From 861a7921ed7833a90f77b5fca436c789a4f9517c Mon Sep 17 00:00:00 2001
|
||
|
From: Mitch Curtis <mitch.curtis@qt.io>
|
||
|
Date: Tue, 22 Oct 2024 13:26:08 +0800
|
||
|
Subject: [PATCH] QQuickItemView: fix crash with zero-size SwipeView that uses
|
||
|
Repeater
|
||
|
|
||
|
When running the minimal example from the bug report, the order of
|
||
|
events is:
|
||
|
|
||
|
1. deletables are iterated in QQuickRepeater::clear(), and deleteLater
|
||
|
is called on the delegate item.
|
||
|
2. deletables are unparented. This causes Container (SwipeView) to be
|
||
|
notified of the parent change and it removes the item. Part of this
|
||
|
involves changing the currentIndex, since the removed item was current.
|
||
|
3. SwipeView's contentItem (ListView) has its currentIndex bound to the
|
||
|
container's, so QQuickItemView::setCurrentIndex is called.
|
||
|
4. setCurrentIndex calls updateCurrent, which detects that the
|
||
|
currentIndex (which is -1, because there was only one item) is out of
|
||
|
range and so releases the item. This causes it to be added to
|
||
|
unrequestedItems, even though it has been scheduled for deletion.
|
||
|
|
||
|
This patch makes QQuickItemView detect that the item is going to be
|
||
|
deleted and not add it to the list of deletables.
|
||
|
|
||
|
Fixes: QTBUG-129622
|
||
|
Pick-to: 6.5
|
||
|
Change-Id: I999aedbdfafc61ff6d33eb6579331f470e9c1454
|
||
|
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
|
||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||
|
(cherry picked from commit 18a6a658aaf25fa8c380daef8a72dee4c1661164)
|
||
|
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
|
||
|
---
|
||
|
src/quick/items/qquickitemview.cpp | 4 +-
|
||
|
.../quickcontrols/controls/data/tst_swipeview.qml | 59 ++++++++++++++++++++++
|
||
|
2 files changed, 62 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
|
||
|
index 19e5b7f4029..dabd5630dbc 100644
|
||
|
--- a/src/quick/items/qquickitemview.cpp
|
||
|
+++ b/src/quick/items/qquickitemview.cpp
|
||
|
@@ -2499,7 +2499,9 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::Reu
|
||
|
// One case where this can happen is moving an item out of one ObjectModel and into another.
|
||
|
QQuickItemPrivate::get(item->item)->setCulled(true);
|
||
|
}
|
||
|
- if (!isClearing)
|
||
|
+ // If deleteLater was called, the item isn't long for this world and so we shouldn't store references to it.
|
||
|
+ // This can happen when a Repeater is used to populate items in SwipeView's ListView contentItem.
|
||
|
+ if (!isClearing && !QObjectPrivate::get(item->item)->deleteLaterCalled)
|
||
|
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
|
||
|
} else if (flags & QQmlInstanceModel::Destroyed) {
|
||
|
item->item->setParentItem(nullptr);
|
||
|
diff --git a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
|
||
|
index 3a7558c0e4d..a3dd16c3044 100644
|
||
|
--- a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
|
||
|
+++ b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
|
||
|
@@ -4,6 +4,7 @@
|
||
|
import QtQuick
|
||
|
import QtTest
|
||
|
import QtQuick.Controls
|
||
|
+import QtQuick.Layouts
|
||
|
|
||
|
TestCase {
|
||
|
id: testCase
|
||
|
@@ -760,4 +761,62 @@ TestCase {
|
||
|
tryCompare(swipeListView, "contentX", swipeListView.width, 1000)
|
||
|
compare(item2.x, swipeListView.width)
|
||
|
}
|
||
|
+
|
||
|
+ Component {
|
||
|
+ id: zeroSizeSwipeViewWithRepeatersComponent
|
||
|
+
|
||
|
+ Item {
|
||
|
+ objectName: "rootItem"
|
||
|
+ anchors.fill: parent
|
||
|
+
|
||
|
+ property alias swipeView: swipeView
|
||
|
+ property int d
|
||
|
+
|
||
|
+ Timer {
|
||
|
+ interval: 2
|
||
|
+ running: true
|
||
|
+ repeat: false
|
||
|
+ onTriggered: d = 2
|
||
|
+ }
|
||
|
+
|
||
|
+ SwipeView {
|
||
|
+ id: swipeView
|
||
|
+ contentItem.objectName: "swipeViewListView"
|
||
|
+
|
||
|
+ Repeater {
|
||
|
+ objectName: "swipeViewContentItemRepeater"
|
||
|
+ model: [
|
||
|
+ {
|
||
|
+ title: d
|
||
|
+ }
|
||
|
+ ]
|
||
|
+
|
||
|
+ delegate: GridLayout {
|
||
|
+ objectName: "gridLayoutDelegate"
|
||
|
+
|
||
|
+ Repeater {
|
||
|
+ id: repeater
|
||
|
+ objectName: "delegateRepeater"
|
||
|
+ model: d
|
||
|
+ delegate: Item {
|
||
|
+ objectName: "delegate" + index
|
||
|
+
|
||
|
+ required property int index
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ // QTBUG-129622
|
||
|
+ function test_zeroSizeSwipeViewWithRepeaters() {
|
||
|
+ let root = createTemporaryObject(zeroSizeSwipeViewWithRepeatersComponent, testCase)
|
||
|
+ verify(root)
|
||
|
+
|
||
|
+ let swipeView = root.swipeView
|
||
|
+ tryCompare(root, "d", 2)
|
||
|
+ // Shouldn't crash when the model is changed.
|
||
|
+ }
|
||
|
}
|
||
|
--
|
||
|
2.16.3
|
||
|
|
||
|
|