Fix crash due to QTreeView accessing deleted model indexes.
QTreeViewPrivate::updateScrollBars depends on a correctly set up viewItems vector. If a delayed layout is pending, we must call QTreeViewPrivate::executePostedLayout before accessing any stored model indices. Task-number: QTBUG-45697 Change-Id: I55fcbaf81f225b26181c2cf739283740b85dd16a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com> Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
parent
310b7ef010
commit
42b7a7c609
@ -3658,6 +3658,7 @@ void QTreeViewPrivate::updateScrollBars()
|
||||
if (!viewportSize.isValid())
|
||||
viewportSize = QSize(0, 0);
|
||||
|
||||
executePostedLayout();
|
||||
if (viewItems.isEmpty()) {
|
||||
q->doItemsLayout();
|
||||
}
|
||||
|
@ -255,6 +255,7 @@ private slots:
|
||||
void taskQTBUG_8176_emitOnExpandAll();
|
||||
void taskQTBUG_34717_collapseAtBottom();
|
||||
void taskQTBUG_37813_crash();
|
||||
void taskQTBUG_45697_crash();
|
||||
void testInitialFocus();
|
||||
};
|
||||
|
||||
@ -4385,5 +4386,82 @@ void tst_QTreeView::taskQTBUG_37813_crash()
|
||||
#endif // QT_BUILD_INTERNAL
|
||||
}
|
||||
|
||||
// QTBUG-45697: Using a QTreeView with a multi-column model filtered by QSortFilterProxyModel,
|
||||
// when sorting the source model while the widget is not yet visible and showing the widget
|
||||
// later on, corruption occurs in QTreeView.
|
||||
class Qtbug45697TestWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const int columnCount = 3;
|
||||
|
||||
explicit Qtbug45697TestWidget();
|
||||
int timerTick() const { return m_timerTick; }
|
||||
|
||||
public slots:
|
||||
void slotTimer();
|
||||
|
||||
private:
|
||||
QTreeView *m_treeView;
|
||||
QStandardItemModel *m_model;
|
||||
QSortFilterProxyModel *m_sortFilterProxyModel;
|
||||
int m_timerTick;
|
||||
};
|
||||
|
||||
Qtbug45697TestWidget::Qtbug45697TestWidget()
|
||||
: m_treeView(new QTreeView(this))
|
||||
, m_model(new QStandardItemModel(0, Qtbug45697TestWidget::columnCount, this))
|
||||
, m_sortFilterProxyModel(new QSortFilterProxyModel(this))
|
||||
, m_timerTick(0)
|
||||
{
|
||||
QVBoxLayout *vBoxLayout = new QVBoxLayout(this);
|
||||
vBoxLayout->addWidget(m_treeView);
|
||||
|
||||
for (char sortChar = 'z'; sortChar >= 'a' ; --sortChar) {
|
||||
QList<QStandardItem *> items;
|
||||
for (int column = 0; column < Qtbug45697TestWidget::columnCount; ++column) {
|
||||
const QString text = QLatin1Char(sortChar) + QLatin1String(" ") + QString::number(column);
|
||||
items.append(new QStandardItem(text));
|
||||
}
|
||||
m_model->appendRow(items);
|
||||
}
|
||||
|
||||
m_sortFilterProxyModel->setSourceModel(m_model);
|
||||
m_treeView->setModel(m_sortFilterProxyModel);
|
||||
|
||||
QHeaderView *headerView = m_treeView->header();
|
||||
for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s )
|
||||
headerView->setSectionResizeMode(s, QHeaderView::ResizeToContents);
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
timer->setInterval(50);
|
||||
connect(timer, &QTimer::timeout, this, &Qtbug45697TestWidget::slotTimer);
|
||||
timer->start();
|
||||
}
|
||||
|
||||
void Qtbug45697TestWidget::slotTimer()
|
||||
{
|
||||
switch (m_timerTick++) {
|
||||
case 0:
|
||||
m_model->sort(0);
|
||||
break;
|
||||
case 1:
|
||||
show();
|
||||
break;
|
||||
default:
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QTreeView::taskQTBUG_45697_crash()
|
||||
{
|
||||
Qtbug45697TestWidget testWidget;
|
||||
testWidget.setWindowTitle(QTest::currentTestFunction());
|
||||
testWidget.resize(400, 400);
|
||||
testWidget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(100, 100));
|
||||
QTRY_VERIFY(testWidget.timerTick() >= 2);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QTreeView)
|
||||
#include "tst_qtreeview.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user