Hello community, here is the log from the commit of package kitemmodels for openSUSE:Factory checked in at 2016-04-12 19:20:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kitemmodels (Old) and /work/SRC/openSUSE:Factory/.kitemmodels.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kitemmodels" Changes: -------- --- /work/SRC/openSUSE:Factory/kitemmodels/kitemmodels.changes 2016-03-16 10:30:13.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.kitemmodels.new/kitemmodels.changes 2016-04-12 19:20:20.000000000 +0200 @@ -1,0 +2,16 @@ +Mon Apr 4 14:21:11 UTC 2016 - [email protected] + +- Update to 5.21.0 (boo#974793) + * KSelectionProxyModel: Simplify row removal handling, + simplify deselection logic + * KSelectionProxyModel: Recreate mapping on removal only if needed + (kde#352369) + * KSelectionProxyModel: Only clear firstChild mappings for top-level + * KSelectionProxyModel: Ensure proper signalling when + removing last selected + * Make DynamicTreeModel searchable by display role + * Upgrade Qt version requirement to 5.4.0 + * For more details please see: + https://www.kde.org/announcements/kde-frameworks-5.21.0.php + +------------------------------------------------------------------- Old: ---- kitemmodels-5.20.0.tar.xz New: ---- kitemmodels-5.21.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kitemmodels.spec ++++++ --- /var/tmp/diff_new_pack.YFEx91/_old 2016-04-12 19:20:21.000000000 +0200 +++ /var/tmp/diff_new_pack.YFEx91/_new 2016-04-12 19:20:21.000000000 +0200 @@ -17,15 +17,15 @@ %define lname libKF5ItemModels5 -%define _tar_path 5.20 +%define _tar_path 5.21 Name: kitemmodels -Version: 5.20.0 +Version: 5.21.0 Release: 0 BuildRequires: cmake >= 2.8.12 BuildRequires: extra-cmake-modules >= %{_tar_path} BuildRequires: fdupes BuildRequires: kf5-filesystem -BuildRequires: cmake(Qt5Core) >= 5.3.0 +BuildRequires: cmake(Qt5Core) >= 5.4.0 Summary: Set of item models extending the Qt model-view framework License: LGPL-2.1+ Group: System/GUI/KDE @@ -50,7 +50,7 @@ Group: Development/Libraries/KDE Requires: %lname = %{version} Requires: extra-cmake-modules -Requires: cmake(Qt5Core) >= 5.3.0 +Requires: cmake(Qt5Core) >= 5.4.0 %description devel KItemModels provides a set of item models extending the Qt model-view framework. ++++++ kitemmodels-5.20.0.tar.xz -> kitemmodels-5.21.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.20.0/CMakeLists.txt new/kitemmodels-5.21.0/CMakeLists.txt --- old/kitemmodels-5.20.0/CMakeLists.txt 2016-03-04 23:18:50.000000000 +0100 +++ new/kitemmodels-5.21.0/CMakeLists.txt 2016-04-03 22:34:03.000000000 +0200 @@ -3,7 +3,7 @@ project(KItemModels) include(FeatureSummary) -find_package(ECM 5.20.0 NO_MODULE) +find_package(ECM 5.21.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) @@ -14,7 +14,7 @@ include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) -set(REQUIRED_QT_VERSION 5.3.0) +set(REQUIRED_QT_VERSION 5.4.0) find_package(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) @@ -23,7 +23,7 @@ include(ECMSetupVersion) include(ECMGenerateHeaders) -set(KF5_VERSION "5.20.0") # handled by release scripts +set(KF5_VERSION "5.21.0") # handled by release scripts ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KITEMMODELS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kitemmodels_version.h" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.20.0/autotests/kselectionproxymodeltest.cpp new/kitemmodels-5.21.0/autotests/kselectionproxymodeltest.cpp --- old/kitemmodels-5.20.0/autotests/kselectionproxymodeltest.cpp 2016-03-04 23:18:50.000000000 +0100 +++ new/kitemmodels-5.21.0/autotests/kselectionproxymodeltest.cpp 2016-04-03 22:34:03.000000000 +0200 @@ -26,6 +26,9 @@ #include <QSignalSpy> #include <kselectionproxymodel.h> +#include "modeltest.h" +#include "dynamictreemodel.h" + #include "test_model_helpers.h" using namespace TestModelHelpers; @@ -48,9 +51,13 @@ void columnCountShouldBeStable(); void selectOnSourceReset(); void selectionMapping(); + void removeRows_data(); + void removeRows(); #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) void selectionModelModelChange(); + void deselection_data(); + void deselection(); #endif private: @@ -169,6 +176,736 @@ QCOMPARE(proxy.rowCount(), 1); QCOMPARE(proxy.index(0, 0).data().toString(), numbers.at(0)); } + +void KSelectionProxyModelTest::deselection_data() +{ + QTest::addColumn<int>("kspm_mode"); + QTest::addColumn<QStringList>("selection"); + QTest::addColumn<int>("expectedRowCountBefore"); + QTest::addColumn<int>("spyCount"); + QTest::addColumn<QStringList>("toDeselect"); + QTest::addColumn<int>("expectedRowCountAfter"); + + auto testNumber = 1; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"2"} << 2 + << 1 + << QStringList{"2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9"} << 4 + << 1 + << QStringList{"3"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9"} << 4 + << 1 + << QStringList{"3", "9"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9"} << 4 + << 1 + << QStringList{"9"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9", "11", "15"} << 6 + << 1 + << QStringList{"9"} << 7; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9", "11", "15"} << 6 + << 1 + << QStringList{"9", "15"} << 5; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9", "11", "15"} << 6 + << 1 + << QStringList{"3", "9", "15"} << 3; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9", "11", "15"} << 6 + << 1 + << QStringList{"3", "9", "11", "15"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9", "11", "15"} << 6 + << 0 + << QStringList{"11"} << 6; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) + << QStringList{"3", "9", "11", "15"} << 6 + << 2 + << QStringList{"3", "15"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) + << QStringList{"3", "9", "11", "15"} << 4 + << 1 + << QStringList{"11"} << 3; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) + << QStringList{"3", "9", "11", "15"} << 4 + << 2 + << QStringList{"3", "11"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) + << QStringList{"3", "9", "11", "15"} << 4 + << 1 + << QStringList{"3", "9", "11"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) + << QStringList{"3"} << 2 + << 1 + << QStringList{"3"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) + << QStringList{"3", "9", "11", "15"} << 9 + << 1 + << QStringList{"3", "9", "11"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) + << QStringList{"3", "9", "11", "15"} << 9 + << 1 + << QStringList{"9"} << 7; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) + << QStringList{"3", "9", "11", "15"} << 9 + << 2 + << QStringList{"3", "11"} << 4; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) + << QStringList{"4", "6", "9", "15"} << 7 + << 1 + << QStringList{"4"} << 5; + ++testNumber; +} + +void KSelectionProxyModelTest::deselection() +{ + QFETCH(int, kspm_mode); + QFETCH(QStringList, selection); + QFETCH(int, expectedRowCountBefore); + QFETCH(int, spyCount); + QFETCH(QStringList, toDeselect); + QFETCH(int, expectedRowCountAfter); + + DynamicTreeModel tree; + new ModelTest(&tree, &tree); + ModelResetCommand resetCommand(&tree); + resetCommand.setInitialTree( + " - 1" + " - - 2" + " - - - 3" + " - - - - 4" + " - - - - - 5" + " - - - - - 6" + " - - - - - - 7" + " - - - - 8" + " - - - 9" + " - - - - 10" + " - - - - 11" + " - - - - - 12" + " - - - - - 13" + " - - - - - 14" + " - - 15" + " - - - 16" + " - - - 17" + ); + resetCommand.doCommand(); + + QItemSelectionModel selectionModel(&tree); + + KSelectionProxyModel proxy(&selectionModel); + new ModelTest(&proxy, &proxy); + proxy.setFilterBehavior(static_cast<KSelectionProxyModel::FilterBehavior>(kspm_mode)); + proxy.setSourceModel(&tree); + + QSignalSpy beforeSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy afterSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); + + QItemSelection sel; + for (auto item : selection) { + QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, item, 1, Qt::MatchRecursive); + QCOMPARE(idxs.size(), 1); + sel << QItemSelectionRange(idxs.at(0), idxs.at(0)); + } + selectionModel.select(sel, QItemSelectionModel::Select); + + QCOMPARE(proxy.rowCount(), expectedRowCountBefore); + + QItemSelection desel; + for (auto item : toDeselect) { + QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, item, 1, Qt::MatchRecursive); + QCOMPARE(idxs.size(), 1); + desel << QItemSelectionRange(idxs.at(0), idxs.at(0)); + } + selectionModel.select(desel, QItemSelectionModel::Deselect); + + QCOMPARE(beforeSpy.count(), spyCount); + QCOMPARE(afterSpy.count(), spyCount); + + QCOMPARE(proxy.rowCount(), expectedRowCountAfter); +} + +void KSelectionProxyModelTest::removeRows_data() +{ + QTest::addColumn<int>("kspm_mode"); + QTest::addColumn<bool>("connectSelectionModelFirst"); + QTest::addColumn<bool>("emulateSingleSelectionMode"); + QTest::addColumn<QStringList>("selection"); + QTest::addColumn<int>("expectedRowCountBefore"); + QTest::addColumn<int>("spyCount"); + QTest::addColumn<QStringList>("toRemove"); + QTest::addColumn<int>("expectedRowCountAfter"); + + // Because the KSelectionProxyModel has two dependencies - a QItemSelectionModel + // and a QAbstractItemModel, whichever one signals first determines the internal + // code path is used to perform removal. That order is determined by order + // of signal slot connections, and these tests use connectSelectionModelFirst + // to test both. + + // When using a QAbstractItemView, the SelectionMode can determine how the + // selection changes when a selected row is removed. When the row is + // AboutToBeRemoved, the view might change the selection to a row which is + // not to be removed. This means that depending on signal-slot connection + // order, the KSelectionProxyModel::sourceRowsAboutToBeRemoved method + // might be executed, but then the selection can be changed before + // executing the KSelectionProxyModel::sourceRowsRemoved method. These tests + // are run with and without similar emulated behavior. + + auto testNumber = 1; + + for (auto emulateSingleSelectionMode: {true, false}) + { + for (auto kspm_mode: {KSelectionProxyModel::SubTreesWithoutRoots, KSelectionProxyModel::ChildrenOfExactSelection}) + { + for (auto connectSelectionModelFirst: {true, false}) + { + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << 1 + << QStringList{"2", "2"} << (emulateSingleSelectionMode ? 2 : 0); + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) + << QStringList{"4", "4"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) + << QStringList{"5", "5"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) + << QStringList{"6", "6"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) + << QStringList{"7", "7"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << 1 + << QStringList{"1", "1"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << 1 + << QStringList{"9", "9"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"2"} << 2 + << 0 + << QStringList{"15", "15"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"5"} << 0 + << 0 + << QStringList{"5", "5"} << (emulateSingleSelectionMode ? 1 : 0); + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"5"} << 0 + << 0 + << QStringList{"4", "4"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"5"} << 0 + << 0 + << QStringList{"3", "3"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"5"} << 0 + << 0 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode + << QStringList{"6"} << 1 + << 1 + << QStringList{"4", "4"} << 0; + ++testNumber; + } + } + } + + for (auto connectSelectionModelFirst: {true, false}) + { + for (auto kspm_mode: {KSelectionProxyModel::SubTreesWithoutRoots, KSelectionProxyModel::ChildrenOfExactSelection}) + { + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"3", "15"} << 4 + << 1 + << QStringList{"3", "3"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "15"} << 4 + << 1 + << QStringList{"2", "2"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "11"} << 5 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "11"} << 5 + << 1 + << QStringList{"3", "3"} << 3; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "11"} << 5 + << 1 + << QStringList{"11", "11"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "11"} << 5 + << 1 + << QStringList{"3", "9"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "11", "15"} << 7 + << 1 + << QStringList{"3", "9"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "8", "10", "11", "16"} << 5 + << 1 + << QStringList{"3", "9"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "8", "10", "11", "16"} << 5 + << 1 + << QStringList{"3", "3"} << 3; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "8", "10", "11", "16"} << 5 + << 1 + << QStringList{"9", "9"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "11"} << 5 + << 1 + << QStringList{"9", "9"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "6", "11"} + << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 6 : 5) + << 1 + << QStringList{"9", "9"} + << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 3 : 2); + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false + << QStringList{"4", "8", "11"} << 5 + << 1 + << QStringList{"9", "9"} << 2; + ++testNumber; + } + } + + for (auto connectSelectionModelFirst: {true, false}) + { + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"2"} << 1 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"2", "3", "4"} << 3 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"6", "9"} << 2 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"6", "9"} << 2 + << 1 + << QStringList{"4", "4"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"4", "10", "11"} << 3 + << 1 + << QStringList{"3", "9"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"4", "6", "7", "10", "11"} << 5 + << 1 + << QStringList{"10", "11"} << 3; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"4", "5", "6", "7", "8"} << 5 + << 1 + << QStringList{"4", "8"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"4", "5", "6", "7", "8"} << 5 + << 1 + << QStringList{"4", "4"} << 1; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false + << QStringList{"4", "5", "6", "7", "8"} << 5 + << 1 + << QStringList{"6", "6"} << 3; + ++testNumber; + } + + for (auto connectSelectionModelFirst: {true, false}) + { + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"2"} << 1 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"2"} << 1 + << 1 + << QStringList{"4", "4"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"2", "4"} << 1 + << 1 + << QStringList{"4", "4"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"2", "4"} << 1 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"4", "9"} << 2 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"4", "9"} << 2 + << 1 + << QStringList{"4", "4"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"4", "9"} << 2 + << 1 + << QStringList{"9", "9"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"4", "9"} << 2 + << 1 + << QStringList{"5", "6"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"4", "9"} << 2 + << 1 + << QStringList{"4", "8"} << 1; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"6", "11", "15"} << 3 + << 1 + << QStringList{"9", "9"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"6", "11", "15"} << 3 + << 1 + << QStringList{"11", "11"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"6", "8", "10", "11"} << 4 + << 1 + << QStringList{"3", "3"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"6", "8", "10", "11"} << 4 + << 1 + << QStringList{"2", "2"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"6", "8", "10", "11"} << 4 + << 1 + << QStringList{"9", "9"} << 2; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"10", "11"} << 2 + << 1 + << QStringList{"9", "9"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"4", "8"} << 2 + << 1 + << QStringList{"3", "3"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"12", "13", "14"} << 3 + << 1 + << QStringList{"11", "11"} << 0; + ++testNumber; + + QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) + << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false + << QStringList{"12", "13", "14"} << 3 + << 1 + << QStringList{"10", "11"} << 0; + ++testNumber; + } +} + +void KSelectionProxyModelTest::removeRows() +{ + QFETCH(int, kspm_mode); + QFETCH(bool, connectSelectionModelFirst); + QFETCH(bool, emulateSingleSelectionMode); + QFETCH(QStringList, selection); + QFETCH(int, expectedRowCountBefore); + QFETCH(int, spyCount); + QFETCH(QStringList, toRemove); + QFETCH(int, expectedRowCountAfter); + + DynamicTreeModel tree; + new ModelTest(&tree, &tree); + ModelResetCommand resetCommand(&tree); + resetCommand.setInitialTree( + " - 1" + " - - 2" + " - - - 3" + " - - - - 4" + " - - - - - 5" + " - - - - - 6" + " - - - - - - 7" + " - - - - 8" + " - - - 9" + " - - - - 10" + " - - - - 11" + " - - - - - 12" + " - - - - - 13" + " - - - - - 14" + " - - 15" + " - - - 16" + " - - - 17" + ); + resetCommand.doCommand(); + + QItemSelectionModel selectionModel; + + if (emulateSingleSelectionMode) + { + QObject::connect(&tree, &QAbstractItemModel::rowsAboutToBeRemoved, &tree, + [&tree, &selectionModel](QModelIndex const& p, int s, int e){ + auto rmIdx = p.child(s, 0); + if (s == e && selectionModel.selectedIndexes().contains(rmIdx)) + { + auto nextIdx = tree.index(e + 1, 0, rmIdx.parent()); + selectionModel.select(nextIdx, QItemSelectionModel::ClearAndSelect); + } + }); + } + + KSelectionProxyModel proxy; + new ModelTest(&proxy, &proxy); + proxy.setFilterBehavior(static_cast<KSelectionProxyModel::FilterBehavior>(kspm_mode)); + + if (connectSelectionModelFirst) { + selectionModel.setModel(&tree); + proxy.setSourceModel(&tree); + proxy.setSelectionModel(&selectionModel); + } else { + proxy.setSourceModel(&tree); + proxy.setSelectionModel(&selectionModel); + selectionModel.setModel(&tree); + } + + QSignalSpy beforeSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy afterSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); + + QItemSelection sel; + for (auto item : selection) { + QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, item, 1, Qt::MatchRecursive); + QCOMPARE(idxs.size(), 1); + sel << QItemSelectionRange(idxs.at(0), idxs.at(0)); + } + selectionModel.select(sel, QItemSelectionModel::Select); + + QCOMPARE(proxy.rowCount(), expectedRowCountBefore); + + for (auto removePairIndex = 0; removePairIndex < toRemove.size(); removePairIndex += 2) { + QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, toRemove[removePairIndex], 1, Qt::MatchRecursive); + QCOMPARE(idxs.size(), 1); + + auto startIdx = idxs.at(0); + + idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, toRemove[removePairIndex + 1], 1, Qt::MatchRecursive); + QCOMPARE(idxs.size(), 1); + + auto endIdx = idxs.at(0); + + ModelRemoveCommand remove(&tree); + remove.setAncestorRowNumbers(tree.indexToPath(startIdx.parent())); + remove.setStartRow(startIdx.row()); + remove.setEndRow(endIdx.row()); + remove.doCommand(); + } + + QCOMPARE(beforeSpy.count(), spyCount); + QCOMPARE(afterSpy.count(), spyCount); + + QCOMPARE(proxy.rowCount(), expectedRowCountAfter); +} + #endif void KSelectionProxyModelTest::selectionMapping() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.20.0/autotests/proxymodeltestsuite/dynamictreemodel.cpp new/kitemmodels-5.21.0/autotests/proxymodeltestsuite/dynamictreemodel.cpp --- old/kitemmodels-5.20.0/autotests/proxymodeltestsuite/dynamictreemodel.cpp 2016-03-04 23:18:50.000000000 +0100 +++ new/kitemmodels-5.21.0/autotests/proxymodeltestsuite/dynamictreemodel.cpp 2016-04-03 22:34:03.000000000 +0200 @@ -351,11 +351,14 @@ QModelIndexList DynamicTreeModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const { - if (role != DynamicTreeModelId) { + if (role != DynamicTreeModelId && role != Qt::DisplayRole) { return QAbstractItemModel::match(start, role, value, hits, flags); } qint64 id = value.toLongLong(); + if (role == Qt::DisplayRole) { + id = m_items.key(value.toString()); + } QHash<qint64, QList<QList<qint64> > >::const_iterator it = m_childItems.constBegin(); const QHash<qint64, QList<QList<qint64> > >::const_iterator end = m_childItems.constEnd(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.20.0/autotests/proxymodeltestsuite/modeltest.h new/kitemmodels-5.21.0/autotests/proxymodeltestsuite/modeltest.h --- old/kitemmodels-5.20.0/autotests/proxymodeltestsuite/modeltest.h 2016-03-04 23:18:50.000000000 +0100 +++ new/kitemmodels-5.21.0/autotests/proxymodeltestsuite/modeltest.h 2016-04-03 22:34:03.000000000 +0200 @@ -24,7 +24,9 @@ #include <QtCore/QAbstractItemModel> #include <QtCore/QStack> -class ModelTest : public QObject +#include "proxymodeltestsuite_export.h" + +class PROXYMODELTESTSUITE_EXPORT ModelTest : public QObject { Q_OBJECT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.20.0/src/kdescendantsproxymodel.cpp new/kitemmodels-5.21.0/src/kdescendantsproxymodel.cpp --- old/kitemmodels-5.20.0/src/kdescendantsproxymodel.cpp 2016-03-04 23:18:50.000000000 +0100 +++ new/kitemmodels-5.21.0/src/kdescendantsproxymodel.cpp 2016-04-03 22:34:03.000000000 +0200 @@ -26,8 +26,6 @@ #include <QtCore/QTimer> #include <QtCore/QDebug> -#define KDO(object) qDebug() << #object << object - #include "kbihash_p.h" typedef KHash2Map<QPersistentModelIndex, int> Mapping; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.20.0/src/kselectionproxymodel.cpp new/kitemmodels-5.21.0/src/kselectionproxymodel.cpp --- old/kitemmodels-5.20.0/src/kselectionproxymodel.cpp 2016-03-04 23:18:50.000000000 +0100 +++ new/kitemmodels-5.21.0/src/kselectionproxymodel.cpp 2016-04-03 22:34:03.000000000 +0200 @@ -61,27 +61,6 @@ return false; } -static bool isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) -{ - if (!descendant.isValid()) { - return false; - } - - if (ancestor == descendant) { - return false; - } - - QModelIndex parent = descendant.parent(); - while (parent.isValid()) { - if (parent == ancestor) { - return true; - } - - parent = parent.parent(); - } - return false; -} - static bool isDescendantOf(const QItemSelection &selection, const QModelIndex &descendant) { if (!descendant.isValid()) { @@ -436,6 +415,7 @@ m_includeAllSelected(false), m_rowsInserted(false), m_rowsRemoved(false), + m_recreateFirstChildMappingOnRemoval(false), m_rowsMoved(false), m_resetting(false), m_sourceModelResetting(false), @@ -583,13 +563,15 @@ void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void removeSelectionFromProxy(const QItemSelection &selection); - void removeRangeFromProxy(const QItemSelectionRange &range); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void sourceModelDestroyed(); void resetInternalData(); + bool rootWillBeRemoved(const QItemSelection &selection, + const QModelIndex &root); + /** When items are inserted or removed in the m_startWithChildTrees configuration, this method helps find the startRow for use emitting the signals from the proxy. @@ -618,6 +600,7 @@ bool m_includeAllSelected; bool m_rowsInserted; bool m_rowsRemoved; + bool m_recreateFirstChildMappingOnRemoval; QPair<int, int> m_proxyRemoveRows; bool m_rowsMoved; bool m_resetting; @@ -1106,93 +1089,96 @@ m_pendingSelectionChanges.clear(); } -QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex &parent, int start, int end) const +static bool rootWillBeRemovedFrom(const QModelIndex &ancestor, int start, int end, + const QModelIndex &root) { - Q_Q(const KSelectionProxyModel); + Q_ASSERT(root.isValid()); - QPair<int, int> pair = qMakePair(start, end); + auto parent = root; + while (parent.isValid()) { + auto prev = parent; + parent = parent.parent(); + if (parent == ancestor) { + return (prev.row() <= end && prev.row() >= start); + } + } + return false; +} - if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) { - // SubTreeRoots - if (m_rootIndexList.contains(parent) || isDescendantOf(m_rootIndexList, parent)) { - return qMakePair(-1, -1); +bool KSelectionProxyModelPrivate::rootWillBeRemoved(const QItemSelection &selection, + const QModelIndex &root) +{ + Q_ASSERT(root.isValid()); + + for (auto r : selection) { + if (m_includeAllSelected) { + if (r.parent() == root.parent() && root.row() <= r.bottom() && root.row() >= r.top()) { + return true; + } + } else { + if (rootWillBeRemovedFrom(r.parent(), r.top(), r.bottom(), root)) { + return true; + } } } + return false; +} - const QModelIndex proxyParent = mapParentFromSource(parent); +QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex &parent, int start, int end) const +{ + Q_Q(const KSelectionProxyModel); if (!m_includeAllSelected && !m_omitChildren) { // SubTrees and SubTreesWithoutRoots + const QModelIndex proxyParent = mapParentFromSource(parent); if (proxyParent.isValid()) { - return pair; - } - if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { - // SubTreesWithoutRoots topLevel - const int proxyStartRow = getProxyInitialRow(parent) + start; - return qMakePair(proxyStartRow, proxyStartRow + (end - start)); + return qMakePair(start, end); } } - if (m_includeAllSelected && m_startWithChildTrees) { - // ChildrenOfExactSelection - int position = m_rootIndexList.indexOf(parent); - if (position != -1) { - const int proxyStartRow = getProxyInitialRow(parent) + start; - int proxyEndRow = proxyStartRow + (end - start); - ++position; - while (m_rootIndexList.size() < position) { - const QModelIndex idx = m_rootIndexList.at(position); - if (isDescendantOf(parent, idx)) { - proxyEndRow += q->sourceModel()->rowCount(idx); - } else { - break; - } - } - return qMakePair(proxyStartRow, proxyEndRow); - } - return qMakePair(-1, -1); + if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { + const int proxyStartRow = getProxyInitialRow(parent) + start; + const int proxyEndRow = proxyStartRow + (end - start); + return qMakePair(proxyStartRow, proxyEndRow); } QList<QPersistentModelIndex>::const_iterator rootIt = m_rootIndexList.constBegin(); const QList<QPersistentModelIndex>::const_iterator rootEnd = m_rootIndexList.constEnd(); - int rootPosition = 0; - int rootStartRemove = -1; - int rootEndRemove = -1; - int siblingCount = 0; - - for (; rootIt != rootEnd; ++rootIt, ++rootPosition) { - if (m_omitChildren && m_includeAllSelected) { - // ExactSelection - if (parent == rootIt->parent() && rootIt->row() <= end && rootIt->row() >= start) { - if (rootStartRemove == -1) { - rootStartRemove = rootPosition; - } - ++rootEndRemove; - } else { - if (rootStartRemove != -1) { - break; - } - } + int proxyStartRemove = 0; + + for (; rootIt != rootEnd; ++rootIt) { + if (rootWillBeRemovedFrom(parent, start, end, *rootIt)) { + break; } else { - if (isDescendantOf(parent, *rootIt)) { - if (rootStartRemove == -1) { - rootStartRemove = rootPosition; - } - ++rootEndRemove; - if (m_startWithChildTrees) { - siblingCount += q->sourceModel()->rowCount(*rootIt); - } + if (m_startWithChildTrees) { + proxyStartRemove += q->sourceModel()->rowCount(*rootIt); } else { - if (rootStartRemove != -1) { - break; - } + ++proxyStartRemove; } } } - if (rootStartRemove != -1) { - return qMakePair(siblingCount + rootStartRemove, siblingCount + rootEndRemove); + + if (rootIt == rootEnd) { + return qMakePair(-1, -1); } + int proxyEndRemove = proxyStartRemove; + + for (; rootIt != rootEnd; ++rootIt) { + if (!rootWillBeRemovedFrom(parent, start, end, *rootIt)) { + break; + } + if (m_startWithChildTrees) { + proxyEndRemove += q->sourceModel()->rowCount(*rootIt); + } else { + ++proxyEndRemove; + } + } + + --proxyEndRemove; + if (proxyEndRemove >= 0) { + return qMakePair(proxyStartRemove, proxyEndRemove); + } return qMakePair(-1, -1); } @@ -1215,6 +1201,7 @@ m_rowsRemoved = true; m_proxyRemoveRows = pair; + m_recreateFirstChildMappingOnRemoval = m_mappedFirstChildren.leftContains(q->sourceModel()->index(start, 0, parent)); q->beginRemoveRows(proxyParent, pair.first, pair.second); } @@ -1265,7 +1252,9 @@ // If D and F are selected, the proxy contains E, F, G, H. If B is then deleted E to H will // be removed, including both first child mappings at E and G. - removeFirstChildMappings(proxyStart, proxyEnd); + if (!proxyParent.isValid()) { + removeFirstChildMappings(proxyStart, proxyEnd); + } } if (proxyParent.isValid()) { @@ -1288,10 +1277,11 @@ { Q_Q(KSelectionProxyModel); Q_UNUSED(end) + Q_UNUSED(start) Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); - if (!m_selectionModel || !m_selectionModel->hasSelection()) { + if (!m_selectionModel) { return; } @@ -1303,12 +1293,13 @@ Q_ASSERT(m_proxyRemoveRows.first >= 0); Q_ASSERT(m_proxyRemoveRows.second >= 0); endRemoveRows(parent, m_proxyRemoveRows.first, m_proxyRemoveRows.second); - if (m_startWithChildTrees && start == 0 && q->sourceModel()->hasChildren(parent)) + if (m_recreateFirstChildMappingOnRemoval && q->sourceModel()->hasChildren(parent)) // The private endRemoveRows call might remove the first child mapping for parent, so // we create it again in that case. { createFirstChildMapping(parent, m_proxyRemoveRows.first); } + m_recreateFirstChildMappingOnRemoval = false; m_proxyRemoveRows = qMakePair(-1, -1); q->endRemoveRows(); @@ -1667,12 +1658,6 @@ SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin(); SourceProxyIndexMapping::right_iterator endIt = m_mappedParents.rightEnd(); - typedef QPair<QModelIndex, QPersistentModelIndex> Pair; - - QList<Pair> pairs; - - QModelIndexList list; - const bool flatList = isFlat(); while (it != endIt) { @@ -1726,131 +1711,62 @@ return; } - q->rootSelectionAboutToBeRemoved(selection); + QList<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin(); + const QList<QPersistentModelIndex>::iterator rootEnd = m_rootIndexList.end(); + int proxyStartRemove = 0; - Q_FOREACH (const QItemSelectionRange &range, selection) { - removeRangeFromProxy(range); + for (; rootIt != rootEnd; ++rootIt) { + if (rootWillBeRemoved(selection, *rootIt)) { + break; + } else { + if (m_startWithChildTrees) { + auto rc = q->sourceModel()->rowCount(*rootIt); + proxyStartRemove += rc; + } else { + ++proxyStartRemove; + } + } } -} -void KSelectionProxyModelPrivate::removeRangeFromProxy(const QItemSelectionRange &range) -{ - Q_Q(KSelectionProxyModel); + if (rootIt == rootEnd) { + return; + } - Q_ASSERT(range.model() == q->sourceModel()); + int proxyEndRemove = proxyStartRemove; - const QModelIndex sourceTopLeft = range.topLeft(); - const QModelIndex proxyTopLeft = mapFromSource(sourceTopLeft); - const QModelIndex sourceBottomLeft = range.bottomRight().sibling(range.bottom(), 0); - const QModelIndex proxyParent = proxyTopLeft.parent(); - const QModelIndex sourceParent = sourceTopLeft.parent(); - - if (m_startWithChildTrees) { - Q_ASSERT(sourceTopLeft.isValid()); - Q_ASSERT(sourceBottomLeft.isValid()); - const int startRootIdx = m_rootIndexList.indexOf(sourceTopLeft); - int endRootIdx = m_rootIndexList.indexOf(sourceBottomLeft); - QItemSelection extraRanges; - if (m_includeAllSelected) { - // It can happen that indexes of descendants get in between indexes which make up a range. - // We handle only the first contiguous block here and handle the rest later. - int idx = startRootIdx; - const int bottomIdx = endRootIdx; - const int rootListSize = m_rootIndexList.size(); - int next = idx + 1; - while (next <= bottomIdx) { - if (next < rootListSize && m_rootIndexList.at(next).parent() == sourceParent) { - idx = next; - ++next; - } else { - break; - } - } - endRootIdx = idx; - ++idx; - while (idx <= bottomIdx) { - const QModelIndex index = m_rootIndexList.at(idx); - if (m_rootIndexList.at(idx).parent() == sourceParent) { - extraRanges << QItemSelectionRange(index, index); - } - ++idx; - } - } - Q_ASSERT(endRootIdx != -1); - int childrenCount = q->sourceModel()->rowCount(sourceTopLeft); - for (int rootIdx = startRootIdx + 1; rootIdx <= endRootIdx; ++rootIdx) { - childrenCount += q->sourceModel()->rowCount(m_rootIndexList.at(rootIdx)); - } - if (childrenCount == 0) { - for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) { - const QModelIndex idx = m_rootIndexList.at(rootIdx); - q->rootIndexAboutToBeRemoved(idx); - m_rootIndexList.removeOne(idx); - } - return; - } - if (!m_includeAllSelected) { - ++endRootIdx; - for (; endRootIdx < m_rootIndexList.size(); ++endRootIdx) { - const QModelIndex idx = m_rootIndexList.at(endRootIdx); - if (isDescendantOf(sourceBottomLeft, idx)) { - childrenCount += q->sourceModel()->rowCount(idx); - } else { - break; - } - } - --endRootIdx; - } - const int proxyStart = getTargetRow(startRootIdx); - int proxyEnd = proxyStart + childrenCount - 1; - q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); - - for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; ++rootIdx) { - q->rootIndexAboutToBeRemoved(m_rootIndexList.at(rootIdx)); - } - - removeParentMappings(QModelIndex(), proxyStart, proxyEnd); - removeFirstChildMappings(proxyStart, proxyEnd); - int numRemovedChildren = 0; - for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) { - const QModelIndex idx = m_rootIndexList.at(rootIdx); - const int childCount = q->sourceModel()->rowCount(idx); - m_rootIndexList.removeAt(rootIdx); - numRemovedChildren += childCount; - } - updateInternalTopIndexes(proxyEnd + 1, -1 * numRemovedChildren); - q->endRemoveRows(); - if (m_includeAllSelected) { - removeSelectionFromProxy(kNormalizeSelection(extraRanges)); + QList<QPersistentModelIndex>::iterator rootRemoveStart = rootIt; + + for (; rootIt != rootEnd; ++rootIt) { + if (!rootWillBeRemoved(selection, *rootIt)) { + break; } - } else { - if (!proxyTopLeft.isValid()) { - return; + q->rootIndexAboutToBeRemoved(*rootIt); + if (m_startWithChildTrees) { + auto rc = q->sourceModel()->rowCount(*rootIt); + proxyEndRemove += rc; + } else { + ++proxyEndRemove; } - const int height = range.height(); - q->beginRemoveRows(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); + } - // TODO: Do this conditionally if the signal is connected to anything. - for (int i = 0; i < height; ++i) { - const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); - q->rootIndexAboutToBeRemoved(idx); - } - - removeParentMappings(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); - updateInternalIndexes(proxyParent, proxyTopLeft.row() + height, -1 * height); - - for (int i = 0; i < height; ++i) { - const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); - Q_ASSERT(idx.isValid()); - const bool b = m_rootIndexList.removeOne(idx); - Q_UNUSED(b) - if (!b) { - qDebug() << idx; - } - Q_ASSERT(b); + --proxyEndRemove; + if (proxyEndRemove >= 0) { + q->beginRemoveRows(QModelIndex(), proxyStartRemove, proxyEndRemove); + + rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt); + + removeParentMappings(QModelIndex(), proxyStartRemove, proxyEndRemove); + if (m_startWithChildTrees) { + removeFirstChildMappings(proxyStartRemove, proxyEndRemove); } + updateInternalTopIndexes(proxyEndRemove + 1, -1 * (proxyEndRemove - proxyStartRemove + 1)); q->endRemoveRows(); + } else { + rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt); + } + if (rootIt != rootEnd) { + removeSelectionFromProxy(selection); } }
