From 41b8a5fc848fd049813c99373d3131b683367e8c Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 11 Mar 2015 22:26:48 +0100 Subject: [PATCH] KSPM: Fix behavior when a selection is made while resetting. The KSPM should never clear or reset the selection of the QItemSelectionModel it refers to. It should be a read-only view on that selection. If the selection changes while the source is being reset, ignore that selection change. The proxy will clear its own cached data when it processes the modelReset signal from the model, and will populate itself with the selection as it is at that point. --- autotests/CMakeLists.txt | 1 + autotests/kselectionproxymodeltest.cpp | 51 ++++++++++++++++++++++++++ src/kselectionproxymodel.cpp | 14 ++++--- 3 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 autotests/kselectionproxymodeltest.cpp diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 36b1189..5aba1a4 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -18,6 +18,7 @@ ecm_add_tests( kdescendantsproxymodel_smoketest.cpp klinkitemselectionmodeltest.cpp testmodelqueuedconnections.cpp + kselectionproxymodeltest.cpp LINK_LIBRARIES KF5::ItemModels Qt5::Test Qt5::Widgets proxymodeltestsuite ) diff --git a/autotests/kselectionproxymodeltest.cpp b/autotests/kselectionproxymodeltest.cpp new file mode 100644 index 0000000..3464c00 --- /dev/null +++ b/autotests/kselectionproxymodeltest.cpp @@ -0,0 +1,51 @@ + +#include +#include + +#include + +class KSelectionProxyModelTest : public QObject +{ + Q_OBJECT +public: + KSelectionProxyModelTest(QObject* parent = 0) + : QObject(parent) + { + + } + +private Q_SLOTS: + void selectOnSourceReset(); +}; + +void KSelectionProxyModelTest::selectOnSourceReset() +{ + QStringListModel strings({ + "Monday", + "Tuesday", + "Wednesday", + "Thursday" + }); + QItemSelectionModel selectionModel(&strings); + + connect(&strings, &QAbstractItemModel::modelReset, [&] { + selectionModel.select(QItemSelection(strings.index(0, 0), strings.index(2, 0)), + QItemSelectionModel::Select); + }); + + KSelectionProxyModel proxy(&selectionModel); + proxy.setSourceModel(&strings); + + selectionModel.select(QItemSelection(strings.index(0, 0), strings.index(2, 0)), + QItemSelectionModel::Select); + + strings.setStringList({ "One", "Two", "Three", "Four" }); + + QVERIFY(selectionModel.selection().contains(strings.index(0, 0))); + QVERIFY(selectionModel.selection().contains(strings.index(1, 0))); + QVERIFY(selectionModel.selection().contains(strings.index(2, 0))); +} + +QTEST_MAIN(KSelectionProxyModelTest) + +#include "kselectionproxymodeltest.moc" diff --git a/src/kselectionproxymodel.cpp b/src/kselectionproxymodel.cpp index 42e5404..42ba106 100644 --- a/src/kselectionproxymodel.cpp +++ b/src/kselectionproxymodel.cpp @@ -439,6 +439,7 @@ public: m_rowsRemoved(false), m_rowsMoved(false), m_resetting(false), + m_sourceModelResetting(false), m_doubleResetting(false), m_layoutChanging(false), m_ignoreNextLayoutAboutToBeChanged(false), @@ -621,6 +622,7 @@ public: QPair m_proxyRemoveRows; bool m_rowsMoved; bool m_resetting; + bool m_sourceModelResetting; bool m_doubleResetting; bool m_layoutChanging; bool m_ignoreNextLayoutAboutToBeChanged; @@ -863,6 +865,7 @@ void KSelectionProxyModelPrivate::sourceModelDestroyed() // There is very little we can do here. resetInternalData(); m_resetting = false; + m_sourceModelResetting = false; } void KSelectionProxyModelPrivate::sourceModelAboutToBeReset() @@ -887,6 +890,7 @@ void KSelectionProxyModelPrivate::sourceModelAboutToBeReset() q->beginResetModel(); m_resetting = true; + m_sourceModelResetting = true; } void KSelectionProxyModelPrivate::sourceModelReset() @@ -899,11 +903,7 @@ void KSelectionProxyModelPrivate::sourceModelReset() } resetInternalData(); - // No need to try to refill this. When the model is reset it doesn't have a meaningful selection anymore, - // but when it gets one we'll be notified anyway. - if (!m_selectionModel.isNull()) { - m_selectionModel.data()->reset(); - } + m_sourceModelResetting = false; m_resetting = false; q->endResetModel(); } @@ -1860,6 +1860,10 @@ void KSelectionProxyModelPrivate::selectionChanged(const QItemSelection &_select return; } + if (m_sourceModelResetting) { + return; + } + if (m_rowsInserted || m_rowsRemoved) { m_pendingSelectionChanges.append(PendingSelectionChange(_selected, _deselected)); return;