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);
     }
 }
 


Reply via email to