aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2024-02-27 15:57:42 +0100
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2024-02-29 12:08:07 +0100
commite5c031c1ac542be0d2ac7457e145da011fce0013 (patch)
tree19e5785d8e122ccc6612db8d41ec0cdca285a20a
parent779dcf94d05b3daaec5d32db269c95fb5ea409f7 (diff)
QQuickTableView: remove syncView from destructor
If a TableView has a syncView, we need to ensure that it detaches itself from the syncView when it's destroyed. Otherwise the syncView will have a dangling pointer to the deleted TableView afterwards, which can cause a crash. Fixes: QTBUG-120760 Pick-to: 6.7 6.6 6.5 Change-Id: I4c6acfaa0c623ea43ba8b938585fcd9c9247f66c Reviewed-by: Santhosh Kumar <santhosh.kumar.selvaraj@qt.io>
-rw-r--r--src/quick/items/qquicktableview.cpp8
-rw-r--r--tests/auto/quick/qquicktableview/data/unloadheader.qml43
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp16
3 files changed, 67 insertions, 0 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 92ebe817b6..13b6de40fc 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -5365,6 +5365,14 @@ QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
QQuickTableView::~QQuickTableView()
{
+ Q_D(QQuickTableView);
+
+ if (d->syncView) {
+ // Remove this TableView as a sync child from the syncView
+ auto syncView_d = d->syncView->d_func();
+ syncView_d->syncChildren.removeOne(this);
+ syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+ }
}
void QQuickTableView::componentFinalized()
diff --git a/tests/auto/quick/qquicktableview/data/unloadheader.qml b/tests/auto/quick/qquicktableview/data/unloadheader.qml
new file mode 100644
index 0000000000..35e58d56c3
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/unloadheader.qml
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import Qt.labs.qmlmodels
+
+Item {
+ width: 640
+ height: 480
+
+ property alias tableView: tableView
+ property alias loader: verticalHeaderLoader
+
+ Loader {
+ id: verticalHeaderLoader
+ x: 0
+ width: item ? item.contentWidth : 0
+ height: parent.height
+ sourceComponent: TableView {
+ model: 5
+ syncView: tableView
+ syncDirection: Qt.Vertical
+ delegate: Text {
+ text: index
+ }
+ }
+ }
+
+ TableView {
+ id: tableView
+ anchors {
+ left: verticalHeaderLoader.right
+ right: parent.right
+ top: parent.top
+ bottom: parent.bottom
+ }
+
+ model: 5
+ delegate: Text {
+ text: index
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 090d546200..7fb5cc21e5 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -168,6 +168,7 @@ private slots:
void checkSyncView_pageFlicking();
void checkSyncView_emptyModel();
void checkSyncView_topLeftChanged();
+ void checkSyncView_unloadHeader();
void delegateWithRequiredProperties();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
void replaceModel();
@@ -3292,6 +3293,21 @@ void tst_QQuickTableView::checkSyncView_emptyModel()
QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0);
}
+void tst_QQuickTableView::checkSyncView_unloadHeader()
+{
+ // Check that we don't get a crash in TableView if one
+ // of the sync children is suddenly deleted (from e.g a Loader).
+ LOAD_TABLEVIEW("unloadheader.qml");
+
+ const auto loader = view->rootObject()->property("loader").value<QQuickLoader *>();
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ loader->setActive(false);
+ QVERIFY(!loader->item());
+ gc(*qmlEngine(tableView));
+ tableView->forceLayout();
+}
+
void tst_QQuickTableView::checkSyncView_topLeftChanged()
{
LOAD_TABLEVIEW("syncviewsimple.qml");