diff options
author | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2024-02-27 15:57:42 +0100 |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2024-02-29 12:08:07 +0100 |
commit | e5c031c1ac542be0d2ac7457e145da011fce0013 (patch) | |
tree | 19e5785d8e122ccc6612db8d41ec0cdca285a20a | |
parent | 779dcf94d05b3daaec5d32db269c95fb5ea409f7 (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.cpp | 8 | ||||
-rw-r--r-- | tests/auto/quick/qquicktableview/data/unloadheader.qml | 43 | ||||
-rw-r--r-- | tests/auto/quick/qquicktableview/tst_qquicktableview.cpp | 16 |
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"); |