summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQiang Li <liqianga@uniontech.com>2021-03-03 19:26:27 +0800
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-05-31 20:32:35 +0200
commitc6803b0ef71278e68c371158db368d59ab198bc1 (patch)
treed26ac9c3470522e8670c74beba759a5c7b3d0d0e
parentd6181cc7044f0d198bbd2a5c3aec3d162006da91 (diff)
Fix the crashes when animated QTreeWidgetItems are hidden
QTreeView's drawTree implementation performs lazy layouting when calling itemDecorationAt. If animations are enabled, this can change the list of items, and invalidate the copy made earlier. Don't copy the list of items, use a reference instead so that code iterating over the items later operates on valid data. Add an assert in the private itemHeight method, it must not be called with an index that is out of bounds. Fixes: QTBUG-42469 Change-Id: Ifdb782881447912e00baffd1c407de10a1d8d0d4 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit f140ef04a0c54c2c8a699db33433b8d7235d137c)
-rw-r--r--src/widgets/itemviews/qtreeview.cpp4
-rw-r--r--tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp24
2 files changed, 27 insertions, 1 deletions
diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp
index 4a90a95361..3ceafaed62 100644
--- a/src/widgets/itemviews/qtreeview.cpp
+++ b/src/widgets/itemviews/qtreeview.cpp
@@ -1448,7 +1448,8 @@ void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItem *option, c
void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
{
Q_D(const QTreeView);
- const QVector<QTreeViewItem> viewItems = d->viewItems;
+ // d->viewItems changes when posted layouts are executed in itemDecorationAt, so don't copy
+ const QVector<QTreeViewItem> &viewItems = d->viewItems;
QStyleOptionViewItem option = d->viewOptionsV1();
const QStyle::State state = option.state;
@@ -3459,6 +3460,7 @@ int QTreeViewPrivate::indentationForItem(int item) const
int QTreeViewPrivate::itemHeight(int item) const
{
+ Q_ASSERT(item < viewItems.count());
if (uniformRowHeights)
return defaultItemHeight;
if (viewItems.isEmpty())
diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
index 52fac891c0..b75defe168 100644
--- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
+++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
@@ -241,6 +241,7 @@ private slots:
void taskQTBUG_7232_AllowUserToControlSingleStep();
void taskQTBUG_8376();
void taskQTBUG_61476();
+ void taskQTBUG_42469_crash();
void testInitialFocus();
void fetchUntilScreenFull();
};
@@ -4966,6 +4967,29 @@ void tst_QTreeView::taskQTBUG_61476()
QCOMPARE(lastTopLevel->checkState(), Qt::Checked);
}
+void tst_QTreeView::taskQTBUG_42469_crash()
+{
+ QTreeWidget treeWidget;
+ QTreeWidgetItem *itemOne = new QTreeWidgetItem(QStringList("item1"));
+ QTreeWidgetItem *itemTwo = new QTreeWidgetItem(QStringList("item2"));
+ treeWidget.addTopLevelItem(itemOne);
+ treeWidget.addTopLevelItem(itemTwo);
+ treeWidget.topLevelItem(1)->addChild(new QTreeWidgetItem(QStringList("child1")));
+
+ treeWidget.setAnimated(true);
+ QObject::connect(&treeWidget, &QTreeWidget::itemExpanded, [&](QTreeWidgetItem* p_item) {
+ auto tempCount = treeWidget.topLevelItemCount();
+ for (int j = 0; j < tempCount; ++j)
+ if (treeWidget.topLevelItem(j) != p_item) {
+ auto temp = treeWidget.topLevelItem(j);
+ temp->setHidden(true);
+ }
+ });
+
+ treeWidget.show();
+ itemTwo->setExpanded(true);
+}
+
void tst_QTreeView::fetchUntilScreenFull()
{
class TreeModel : public QAbstractItemModel