File indexing completed on 2025-03-23 09:56:01
0001 /* 0002 SPDX-FileCopyrightText: 2015 Stephen Kelly <steveire@gmail.com> 0003 SPDX-FileCopyrightText: 2015 David Faure <faure@kde.org> 0004 SPDX-FileCopyrightText: 2016 Ableton AG <info@ableton.com> 0005 SPDX-FileContributor: Stephen Kelly <stephen.kelly@ableton.com> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "dynamictreemodel.h" 0011 #include "modeltest.h" 0012 #include "test_model_helpers.h" 0013 0014 #include <kselectionproxymodel.h> 0015 0016 #include <QIdentityProxyModel> 0017 #include <QSignalSpy> 0018 #include <QStringListModel> 0019 #include <QTest> 0020 0021 using namespace TestModelHelpers; 0022 0023 class KSelectionProxyModelTest : public QObject 0024 { 0025 Q_OBJECT 0026 public: 0027 KSelectionProxyModelTest(QObject *parent = nullptr) 0028 : QObject(parent) 0029 , days({QStringLiteral("Monday"), QStringLiteral("Tuesday"), QStringLiteral("Wednesday"), QStringLiteral("Thursday")}) 0030 { 0031 } 0032 0033 private Q_SLOTS: 0034 void columnCountShouldBeStable(); 0035 void selectOnSourceReset(); 0036 void selectionMapping(); 0037 void removeRows_data(); 0038 void removeRows(); 0039 0040 void selectionModelModelChange(); 0041 void deselection_data(); 0042 void deselection(); 0043 0044 private: 0045 const QStringList days; 0046 }; 0047 0048 void KSelectionProxyModelTest::columnCountShouldBeStable() 0049 { 0050 // Given a KSelectionProxy on top of a stringlist model 0051 QStringListModel strings(days); 0052 QItemSelectionModel selectionModel(&strings); 0053 KSelectionProxyModel proxy(&selectionModel); 0054 proxy.setSourceModel(&strings); 0055 0056 QSignalSpy rowATBISpy(&proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int))); 0057 QSignalSpy rowInsertedSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int))); 0058 0059 // No selection => the proxy should have 0 rows, 1 column 0060 // (if it had 0 columns, it would have to emit column insertions, too much trouble) 0061 QCOMPARE(proxy.rowCount(), 0); 0062 QCOMPARE(proxy.columnCount(), 1); 0063 QCOMPARE(rowATBISpy.count(), 0); 0064 QCOMPARE(rowInsertedSpy.count(), 0); 0065 0066 // Select second entry -> the proxy should have 1 rows, 1 column 0067 selectionModel.select(QItemSelection(strings.index(1, 0), strings.index(1, 0)), QItemSelectionModel::Select); 0068 QCOMPARE(proxy.rowCount(), 1); 0069 QCOMPARE(proxy.columnCount(), 1); 0070 QCOMPARE(rowSpyToText(rowATBISpy), QStringLiteral("0,0")); 0071 QCOMPARE(rowSpyToText(rowInsertedSpy), QStringLiteral("0,0")); 0072 } 0073 0074 void KSelectionProxyModelTest::selectOnSourceReset() 0075 { 0076 QStringListModel strings(days); 0077 QItemSelectionModel selectionModel(&strings); 0078 0079 connect(&strings, &QAbstractItemModel::modelReset, [&] { 0080 selectionModel.select(QItemSelection(strings.index(0, 0), strings.index(2, 0)), QItemSelectionModel::Select); 0081 }); 0082 0083 KSelectionProxyModel proxy(&selectionModel); 0084 proxy.setSourceModel(&strings); 0085 0086 selectionModel.select(QItemSelection(strings.index(0, 0), strings.index(2, 0)), QItemSelectionModel::Select); 0087 0088 QCOMPARE(proxy.rowCount(), 3); 0089 for (int i = 0; i < 3; ++i) { 0090 QCOMPARE(proxy.index(i, 0).data().toString(), days.at(i)); 0091 } 0092 0093 QStringList numbers = {QStringLiteral("One"), QStringLiteral("Two"), QStringLiteral("Three"), QStringLiteral("Four")}; 0094 strings.setStringList(numbers); 0095 0096 QCOMPARE(proxy.rowCount(), 3); 0097 for (int i = 0; i < 3; ++i) { 0098 QCOMPARE(proxy.index(i, 0).data().toString(), numbers.at(i)); 0099 } 0100 0101 QVERIFY(selectionModel.selection().contains(strings.index(0, 0))); 0102 QVERIFY(selectionModel.selection().contains(strings.index(1, 0))); 0103 QVERIFY(selectionModel.selection().contains(strings.index(2, 0))); 0104 } 0105 0106 void KSelectionProxyModelTest::selectionModelModelChange() 0107 { 0108 QStringListModel strings(days); 0109 QItemSelectionModel selectionModel(&strings); 0110 0111 QIdentityProxyModel identity; 0112 identity.setSourceModel(&strings); 0113 0114 KSelectionProxyModel proxy(&selectionModel); 0115 proxy.setSourceModel(&identity); 0116 selectionModel.select(strings.index(0, 0), QItemSelectionModel::Select); 0117 0118 QCOMPARE(proxy.rowCount(), 1); 0119 QCOMPARE(proxy.index(0, 0).data().toString(), QStringLiteral("Monday")); 0120 0121 QStringListModel strings2({QStringLiteral("Today"), QStringLiteral("Tomorrow")}); 0122 0123 QSignalSpy resetSpy(&proxy, &QAbstractItemModel::modelReset); 0124 0125 selectionModel.setModel(&strings2); 0126 0127 QCOMPARE(resetSpy.size(), 1); 0128 QCOMPARE(proxy.rowCount(), 0); 0129 0130 proxy.setSourceModel(&strings2); 0131 selectionModel.select(strings2.index(0, 0), QItemSelectionModel::Select); 0132 0133 QCOMPARE(proxy.rowCount(), 1); 0134 QCOMPARE(proxy.index(0, 0).data().toString(), QStringLiteral("Today")); 0135 0136 QSignalSpy spy(&proxy, SIGNAL(modelReset())); 0137 0138 QStringList numbers = {QStringLiteral("One"), QStringLiteral("Two"), QStringLiteral("Three"), QStringLiteral("Four")}; 0139 strings.setStringList(numbers); 0140 0141 QCOMPARE(spy.count(), 0); 0142 0143 strings2.setStringList(numbers); 0144 0145 QCOMPARE(spy.count(), 1); 0146 0147 QCOMPARE(proxy.rowCount(), 0); 0148 QVERIFY(!selectionModel.hasSelection()); 0149 0150 selectionModel.select(strings2.index(0, 0), QItemSelectionModel::Select); 0151 0152 QCOMPARE(proxy.rowCount(), 1); 0153 QCOMPARE(proxy.index(0, 0).data().toString(), numbers.at(0)); 0154 } 0155 0156 void KSelectionProxyModelTest::deselection_data() 0157 { 0158 QTest::addColumn<int>("kspm_mode"); 0159 QTest::addColumn<QStringList>("selection"); 0160 QTest::addColumn<int>("expectedRowCountBefore"); 0161 QTest::addColumn<int>("spyCount"); 0162 QTest::addColumn<QStringList>("toDeselect"); 0163 QTest::addColumn<int>("expectedRowCountAfter"); 0164 0165 auto testNumber = 1; 0166 0167 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0168 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"2"} << 2 << 1 << QStringList{"2"} << 0; 0169 ++testNumber; 0170 0171 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0172 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9"} << 4 << 1 << QStringList{"3"} << 2; 0173 ++testNumber; 0174 0175 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0176 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9"} << 4 << 1 << QStringList{"3", "9"} << 0; 0177 ++testNumber; 0178 0179 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0180 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9"} << 4 << 1 << QStringList{"9"} << 2; 0181 ++testNumber; 0182 0183 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0184 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9", "11", "15"} << 6 << 1 << QStringList{"9"} << 7; 0185 ++testNumber; 0186 0187 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0188 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9", "11", "15"} << 6 << 1 << QStringList{"9", "15"} << 5; 0189 ++testNumber; 0190 0191 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0192 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9", "11", "15"} << 6 << 1 << QStringList{"3", "9", "15"} << 3; 0193 ++testNumber; 0194 0195 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0196 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9", "11", "15"} << 6 << 1 << QStringList{"3", "9", "11", "15"} 0197 << 0; 0198 ++testNumber; 0199 0200 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0201 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9", "11", "15"} << 6 << 0 << QStringList{"11"} << 6; 0202 ++testNumber; 0203 0204 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0205 << static_cast<int>(KSelectionProxyModel::SubTreesWithoutRoots) << QStringList{"3", "9", "11", "15"} << 6 << 2 << QStringList{"3", "15"} << 2; 0206 ++testNumber; 0207 0208 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0209 << static_cast<int>(KSelectionProxyModel::ExactSelection) << QStringList{"3", "9", "11", "15"} << 4 << 1 << QStringList{"11"} << 3; 0210 ++testNumber; 0211 0212 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0213 << static_cast<int>(KSelectionProxyModel::ExactSelection) << QStringList{"3", "9", "11", "15"} << 4 << 2 << QStringList{"3", "11"} << 2; 0214 ++testNumber; 0215 0216 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0217 << static_cast<int>(KSelectionProxyModel::ExactSelection) << QStringList{"3", "9", "11", "15"} << 4 << 1 << QStringList{"3", "9", "11"} << 1; 0218 ++testNumber; 0219 0220 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0221 << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) << QStringList{"3"} << 2 << 1 << QStringList{"3"} << 0; 0222 ++testNumber; 0223 0224 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0225 << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) << QStringList{"3", "9", "11", "15"} << 9 << 1 << QStringList{"3", "9", "11"} << 2; 0226 ++testNumber; 0227 0228 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0229 << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) << QStringList{"3", "9", "11", "15"} << 9 << 1 << QStringList{"9"} << 7; 0230 ++testNumber; 0231 0232 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0233 << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) << QStringList{"3", "9", "11", "15"} << 9 << 2 << QStringList{"3", "11"} << 4; 0234 ++testNumber; 0235 0236 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0237 << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) << QStringList{"4", "6", "9", "15"} << 7 << 1 << QStringList{"4"} << 5; 0238 ++testNumber; 0239 0240 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0241 << static_cast<int>(KSelectionProxyModel::ChildrenOfExactSelection) << QStringList{"6", "7"} << 1 << 0 << QStringList{"7"} << 1; 0242 ++testNumber; 0243 } 0244 0245 void KSelectionProxyModelTest::deselection() 0246 { 0247 QFETCH(int, kspm_mode); 0248 QFETCH(QStringList, selection); 0249 QFETCH(int, expectedRowCountBefore); 0250 QFETCH(int, spyCount); 0251 QFETCH(QStringList, toDeselect); 0252 QFETCH(int, expectedRowCountAfter); 0253 0254 DynamicTreeModel tree; 0255 new ModelTest(&tree, &tree); 0256 ModelResetCommand resetCommand(&tree); 0257 resetCommand.setInitialTree( 0258 " - 1" 0259 " - - 2" 0260 " - - - 3" 0261 " - - - - 4" 0262 " - - - - - 5" 0263 " - - - - - 6" 0264 " - - - - - - 7" 0265 " - - - - 8" 0266 " - - - 9" 0267 " - - - - 10" 0268 " - - - - 11" 0269 " - - - - - 12" 0270 " - - - - - 13" 0271 " - - - - - 14" 0272 " - - 15" 0273 " - - - 16" 0274 " - - - 17"); 0275 resetCommand.doCommand(); 0276 0277 QItemSelectionModel selectionModel(&tree); 0278 0279 KSelectionProxyModel proxy(&selectionModel); 0280 new ModelTest(&proxy, &proxy); 0281 proxy.setFilterBehavior(static_cast<KSelectionProxyModel::FilterBehavior>(kspm_mode)); 0282 proxy.setSourceModel(&tree); 0283 0284 QSignalSpy beforeSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int))); 0285 QSignalSpy afterSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int))); 0286 0287 QItemSelection sel; 0288 for (auto item : selection) { 0289 QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, item, 1, Qt::MatchRecursive); 0290 QCOMPARE(idxs.size(), 1); 0291 sel << QItemSelectionRange(idxs.at(0), idxs.at(0)); 0292 } 0293 selectionModel.select(sel, QItemSelectionModel::Select); 0294 0295 QCOMPARE(proxy.rowCount(), expectedRowCountBefore); 0296 0297 QItemSelection desel; 0298 for (auto item : toDeselect) { 0299 QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, item, 1, Qt::MatchRecursive); 0300 QCOMPARE(idxs.size(), 1); 0301 desel << QItemSelectionRange(idxs.at(0), idxs.at(0)); 0302 } 0303 selectionModel.select(desel, QItemSelectionModel::Deselect); 0304 0305 QCOMPARE(beforeSpy.count(), spyCount); 0306 QCOMPARE(afterSpy.count(), spyCount); 0307 0308 QCOMPARE(proxy.rowCount(), expectedRowCountAfter); 0309 } 0310 0311 void KSelectionProxyModelTest::removeRows_data() 0312 { 0313 QTest::addColumn<int>("kspm_mode"); 0314 QTest::addColumn<bool>("connectSelectionModelFirst"); 0315 QTest::addColumn<bool>("emulateSingleSelectionMode"); 0316 QTest::addColumn<QStringList>("selection"); 0317 QTest::addColumn<int>("expectedRowCountBefore"); 0318 QTest::addColumn<int>("spyCount"); 0319 QTest::addColumn<QStringList>("toRemove"); 0320 QTest::addColumn<int>("expectedRowCountAfter"); 0321 0322 // Because the KSelectionProxyModel has two dependencies - a QItemSelectionModel 0323 // and a QAbstractItemModel, whichever one signals first determines the internal 0324 // code path is used to perform removal. That order is determined by order 0325 // of signal slot connections, and these tests use connectSelectionModelFirst 0326 // to test both. 0327 0328 // When using a QAbstractItemView, the SelectionMode can determine how the 0329 // selection changes when a selected row is removed. When the row is 0330 // AboutToBeRemoved, the view might change the selection to a row which is 0331 // not to be removed. This means that depending on signal-slot connection 0332 // order, the KSelectionProxyModel::sourceRowsAboutToBeRemoved method 0333 // might be executed, but then the selection can be changed before 0334 // executing the KSelectionProxyModel::sourceRowsRemoved method. These tests 0335 // are run with and without similar emulated behavior. 0336 0337 auto testNumber = 1; 0338 0339 for (auto emulateSingleSelectionMode : {true, false}) { 0340 for (auto kspm_mode : {KSelectionProxyModel::SubTreesWithoutRoots, KSelectionProxyModel::ChildrenOfExactSelection}) { 0341 for (auto connectSelectionModelFirst : {true, false}) { 0342 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0343 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 << 1 0344 << QStringList{"2", "2"} << (emulateSingleSelectionMode ? 2 : 0); 0345 ++testNumber; 0346 0347 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0348 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 0349 << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) << QStringList{"4", "4"} << 2; 0350 ++testNumber; 0351 0352 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0353 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 0354 << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) << QStringList{"5", "5"} << 2; 0355 ++testNumber; 0356 0357 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0358 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 0359 << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) << QStringList{"6", "6"} << 2; 0360 ++testNumber; 0361 0362 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0363 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 0364 << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 0 : 1) << QStringList{"7", "7"} << 2; 0365 ++testNumber; 0366 0367 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0368 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 << 1 0369 << QStringList{"1", "1"} << 0; 0370 ++testNumber; 0371 0372 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0373 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 << 1 0374 << QStringList{"9", "9"} << 1; 0375 ++testNumber; 0376 0377 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0378 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"2"} << 2 << 0 0379 << QStringList{"15", "15"} << 2; 0380 ++testNumber; 0381 0382 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0383 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"5"} << 0 << 0 0384 << QStringList{"5", "5"} << (emulateSingleSelectionMode ? 1 : 0); 0385 ++testNumber; 0386 0387 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0388 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"5"} << 0 << 0 0389 << QStringList{"4", "4"} << 0; 0390 ++testNumber; 0391 0392 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0393 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"5"} << 0 << 0 0394 << QStringList{"3", "3"} << 0; 0395 ++testNumber; 0396 0397 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0398 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"5"} << 0 << 0 0399 << QStringList{"2", "2"} << 0; 0400 ++testNumber; 0401 0402 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0403 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << emulateSingleSelectionMode << QStringList{"6"} << 1 << 1 0404 << QStringList{"4", "4"} << 0; 0405 ++testNumber; 0406 } 0407 } 0408 } 0409 0410 for (auto connectSelectionModelFirst : {true, false}) { 0411 for (auto kspm_mode : {KSelectionProxyModel::SubTreesWithoutRoots, KSelectionProxyModel::ChildrenOfExactSelection}) { 0412 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0413 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"3", "15"} << 4 << 1 << QStringList{"3", "3"} << 2; 0414 ++testNumber; 0415 0416 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0417 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "15"} << 4 << 1 << QStringList{"2", "2"} << 2; 0418 ++testNumber; 0419 0420 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0421 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "11"} << 5 << 1 << QStringList{"2", "2"} << 0; 0422 ++testNumber; 0423 0424 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0425 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "11"} << 5 << 1 << QStringList{"3", "3"} << 3; 0426 ++testNumber; 0427 0428 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0429 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "11"} << 5 << 1 << QStringList{"11", "11"} << 2; 0430 ++testNumber; 0431 0432 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0433 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "11"} << 5 << 1 << QStringList{"3", "9"} << 0; 0434 ++testNumber; 0435 0436 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0437 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "11", "15"} << 7 << 1 << QStringList{"3", "9"} << 2; 0438 ++testNumber; 0439 0440 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0441 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "8", "10", "11", "16"} << 5 << 1 0442 << QStringList{"3", "9"} << 0; 0443 ++testNumber; 0444 0445 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0446 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "8", "10", "11", "16"} << 5 << 1 0447 << QStringList{"3", "3"} << 3; 0448 ++testNumber; 0449 0450 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0451 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "8", "10", "11", "16"} << 5 << 1 0452 << QStringList{"9", "9"} << 2; 0453 ++testNumber; 0454 0455 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0456 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "11"} << 5 << 1 << QStringList{"9", "9"} << 2; 0457 ++testNumber; 0458 0459 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0460 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "6", "11"} 0461 << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 6 : 5) << 1 << QStringList{"9", "9"} 0462 << (kspm_mode == KSelectionProxyModel::ChildrenOfExactSelection ? 3 : 2); 0463 ++testNumber; 0464 0465 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0466 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"4", "8", "11"} << 5 << 1 << QStringList{"9", "9"} << 2; 0467 ++testNumber; 0468 0469 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0470 << static_cast<int>(kspm_mode) << connectSelectionModelFirst << false << QStringList{"6", "8", "11"} << 4 << 0 << QStringList{"8", "8"} << 4; 0471 ++testNumber; 0472 } 0473 } 0474 0475 for (auto connectSelectionModelFirst : {true, false}) { 0476 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0477 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"2"} << 1 << 1 0478 << QStringList{"2", "2"} << 0; 0479 ++testNumber; 0480 0481 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0482 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"2", "3", "4"} << 3 << 1 0483 << QStringList{"2", "2"} << 0; 0484 ++testNumber; 0485 0486 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0487 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"6", "9"} << 2 << 1 0488 << QStringList{"2", "2"} << 0; 0489 ++testNumber; 0490 0491 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0492 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"6", "9"} << 2 << 1 0493 << QStringList{"4", "4"} << 1; 0494 ++testNumber; 0495 0496 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0497 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"4", "10", "11"} << 3 << 1 0498 << QStringList{"3", "9"} << 0; 0499 ++testNumber; 0500 0501 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0502 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"4", "6", "7", "10", "11"} << 5 << 1 0503 << QStringList{"10", "11"} << 3; 0504 ++testNumber; 0505 0506 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0507 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"4", "5", "6", "7", "8"} << 5 << 1 0508 << QStringList{"4", "8"} << 0; 0509 ++testNumber; 0510 0511 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0512 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"4", "5", "6", "7", "8"} << 5 << 1 0513 << QStringList{"4", "4"} << 1; 0514 0515 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0516 << static_cast<int>(KSelectionProxyModel::ExactSelection) << connectSelectionModelFirst << false << QStringList{"4", "5", "6", "7", "8"} << 5 << 1 0517 << QStringList{"6", "6"} << 3; 0518 ++testNumber; 0519 } 0520 0521 for (auto connectSelectionModelFirst : {true, false}) { 0522 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0523 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"2"} << 1 << 1 << QStringList{"2", "2"} 0524 << 0; 0525 ++testNumber; 0526 0527 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0528 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"2"} << 1 << 1 << QStringList{"4", "4"} 0529 << 1; 0530 ++testNumber; 0531 0532 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0533 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"2", "4"} << 1 << 1 0534 << QStringList{"4", "4"} << 1; 0535 ++testNumber; 0536 0537 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0538 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"2", "4"} << 1 << 1 0539 << QStringList{"2", "2"} << 0; 0540 ++testNumber; 0541 0542 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0543 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"4", "9"} << 2 << 1 0544 << QStringList{"2", "2"} << 0; 0545 ++testNumber; 0546 0547 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0548 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"4", "9"} << 2 << 1 0549 << QStringList{"4", "4"} << 1; 0550 ++testNumber; 0551 0552 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0553 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"4", "9"} << 2 << 1 0554 << QStringList{"9", "9"} << 1; 0555 ++testNumber; 0556 0557 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0558 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"4", "9"} << 2 << 1 0559 << QStringList{"5", "6"} << 2; 0560 ++testNumber; 0561 0562 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0563 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"4", "9"} << 2 << 1 0564 << QStringList{"4", "8"} << 1; 0565 ++testNumber; 0566 0567 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0568 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"6", "11", "15"} << 3 << 1 0569 << QStringList{"9", "9"} << 2; 0570 ++testNumber; 0571 0572 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0573 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"6", "11", "15"} << 3 << 1 0574 << QStringList{"11", "11"} << 2; 0575 ++testNumber; 0576 0577 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0578 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"6", "8", "10", "11"} << 4 << 1 0579 << QStringList{"3", "3"} << 2; 0580 ++testNumber; 0581 0582 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0583 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"6", "8", "10", "11"} << 4 << 1 0584 << QStringList{"2", "2"} << 0; 0585 ++testNumber; 0586 0587 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0588 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"6", "8", "10", "11"} << 4 << 1 0589 << QStringList{"9", "9"} << 2; 0590 ++testNumber; 0591 0592 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0593 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"10", "11"} << 2 << 1 0594 << QStringList{"9", "9"} << 0; 0595 ++testNumber; 0596 0597 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0598 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"4", "8"} << 2 << 1 0599 << QStringList{"3", "3"} << 0; 0600 ++testNumber; 0601 0602 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0603 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"12", "13", "14"} << 3 << 1 0604 << QStringList{"11", "11"} << 0; 0605 ++testNumber; 0606 0607 QTest::newRow(QByteArray("test" + QByteArray::number(testNumber)).data()) 0608 << static_cast<int>(KSelectionProxyModel::SubTrees) << connectSelectionModelFirst << false << QStringList{"12", "13", "14"} << 3 << 1 0609 << QStringList{"10", "11"} << 0; 0610 ++testNumber; 0611 } 0612 } 0613 0614 void KSelectionProxyModelTest::removeRows() 0615 { 0616 QFETCH(int, kspm_mode); 0617 QFETCH(bool, connectSelectionModelFirst); 0618 QFETCH(bool, emulateSingleSelectionMode); 0619 QFETCH(QStringList, selection); 0620 QFETCH(int, expectedRowCountBefore); 0621 QFETCH(int, spyCount); 0622 QFETCH(QStringList, toRemove); 0623 QFETCH(int, expectedRowCountAfter); 0624 0625 DynamicTreeModel tree; 0626 new ModelTest(&tree, &tree); 0627 ModelResetCommand resetCommand(&tree); 0628 resetCommand.setInitialTree( 0629 " - 1" 0630 " - - 2" 0631 " - - - 3" 0632 " - - - - 4" 0633 " - - - - - 5" 0634 " - - - - - 6" 0635 " - - - - - - 7" 0636 " - - - - 8" 0637 " - - - 9" 0638 " - - - - 10" 0639 " - - - - 11" 0640 " - - - - - 12" 0641 " - - - - - 13" 0642 " - - - - - 14" 0643 " - - 15" 0644 " - - - 16" 0645 " - - - 17"); 0646 resetCommand.doCommand(); 0647 0648 QItemSelectionModel selectionModel; 0649 0650 if (emulateSingleSelectionMode) { 0651 QObject::connect(&tree, &QAbstractItemModel::rowsAboutToBeRemoved, &tree, [&tree, &selectionModel](QModelIndex const &p, int s, int e) { 0652 auto rmIdx = tree.index(s, 0, p); 0653 if (s == e && selectionModel.selectedIndexes().contains(rmIdx)) { 0654 auto nextIdx = tree.index(e + 1, 0, rmIdx.parent()); 0655 selectionModel.select(nextIdx, QItemSelectionModel::ClearAndSelect); 0656 } 0657 }); 0658 } 0659 0660 KSelectionProxyModel proxy; 0661 new ModelTest(&proxy, &proxy); 0662 proxy.setFilterBehavior(static_cast<KSelectionProxyModel::FilterBehavior>(kspm_mode)); 0663 0664 if (connectSelectionModelFirst) { 0665 selectionModel.setModel(&tree); 0666 proxy.setSourceModel(&tree); 0667 proxy.setSelectionModel(&selectionModel); 0668 } else { 0669 proxy.setSourceModel(&tree); 0670 proxy.setSelectionModel(&selectionModel); 0671 selectionModel.setModel(&tree); 0672 } 0673 0674 QSignalSpy beforeSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int))); 0675 QSignalSpy afterSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int))); 0676 0677 QItemSelection sel; 0678 for (auto item : selection) { 0679 QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, item, 1, Qt::MatchRecursive); 0680 QCOMPARE(idxs.size(), 1); 0681 sel << QItemSelectionRange(idxs.at(0), idxs.at(0)); 0682 } 0683 selectionModel.select(sel, QItemSelectionModel::Select); 0684 0685 QCOMPARE(proxy.rowCount(), expectedRowCountBefore); 0686 0687 for (auto removePairIndex = 0; removePairIndex < toRemove.size(); removePairIndex += 2) { 0688 QModelIndexList idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, toRemove[removePairIndex], 1, Qt::MatchRecursive); 0689 QCOMPARE(idxs.size(), 1); 0690 0691 auto startIdx = idxs.at(0); 0692 0693 idxs = tree.match(tree.index(0, 0), Qt::DisplayRole, toRemove[removePairIndex + 1], 1, Qt::MatchRecursive); 0694 QCOMPARE(idxs.size(), 1); 0695 0696 auto endIdx = idxs.at(0); 0697 0698 ModelRemoveCommand remove(&tree); 0699 remove.setAncestorRowNumbers(tree.indexToPath(startIdx.parent())); 0700 remove.setStartRow(startIdx.row()); 0701 remove.setEndRow(endIdx.row()); 0702 remove.doCommand(); 0703 } 0704 0705 QCOMPARE(beforeSpy.count(), spyCount); 0706 QCOMPARE(afterSpy.count(), spyCount); 0707 0708 QCOMPARE(proxy.rowCount(), expectedRowCountAfter); 0709 } 0710 0711 void KSelectionProxyModelTest::selectionMapping() 0712 { 0713 QStringListModel strings(days); 0714 QItemSelectionModel selectionModel(&strings); 0715 KSelectionProxyModel proxy(&selectionModel); 0716 proxy.setFilterBehavior(KSelectionProxyModel::SubTrees); 0717 proxy.setSourceModel(&strings); 0718 auto idx1 = strings.index(0, 0); 0719 auto idx2 = strings.index(2, 0); 0720 QItemSelection sourceSel; 0721 sourceSel << QItemSelectionRange(idx1, idx2); 0722 selectionModel.select(sourceSel, QItemSelectionModel::Select); 0723 0724 QItemSelection proxySel; 0725 proxySel << QItemSelectionRange(proxy.index(0, 0), proxy.index(2, 0)); 0726 0727 QCOMPARE(proxy.mapSelectionToSource(proxySel), sourceSel); 0728 } 0729 0730 QTEST_MAIN(KSelectionProxyModelTest) 0731 0732 #include "kselectionproxymodeltest.moc"