1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30
31#include <QtGui/QtGui>
32
33#include <algorithm>
34
35Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlag)
36Q_DECLARE_METATYPE(Qt::SortOrder)
37
38class tst_QItemSelectionModel : public QObject
39{
40 Q_OBJECT
41
42public:
43 tst_QItemSelectionModel();
44
45public slots:
46 void initTestCase();
47 void cleanupTestCase();
48 void init();
49private slots:
50 void clear_data();
51 void clear();
52 void clearAndSelect();
53 void toggleSelection();
54 void select_data();
55 void select();
56 void persistentselections_data();
57 void persistentselections();
58 void resetModel();
59 void removeRows_data();
60 void removeRows();
61 void removeColumns_data();
62 void removeColumns();
63 void modelLayoutChanged_data();
64 void modelLayoutChanged();
65 void selectedRows_data();
66 void selectedRows();
67 void selectedColumns_data();
68 void selectedColumns();
69 void setCurrentIndex();
70 void splitOnInsert();
71 void rowIntersectsSelection1();
72 void rowIntersectsSelection2();
73 void rowIntersectsSelection3();
74 void unselectable();
75 void selectedIndexes();
76 void layoutChanged();
77 void merge_data();
78 void merge();
79 void isRowSelected();
80 void childrenDeselectionSignal();
81 void layoutChangedWithAllSelected1();
82 void layoutChangedWithAllSelected2();
83 void layoutChangedTreeSelection();
84 void deselectRemovedMiddleRange();
85#if QT_DEPRECATED_SINCE(5, 15)
86 void rangeOperatorLessThan_data();
87 void rangeOperatorLessThan();
88#endif
89 void setModel();
90
91 void testDifferentModels();
92
93 void testValidRangesInSelectionsAfterReset();
94 void testChainedSelectionClear();
95 void testClearCurrentIndex();
96
97 void QTBUG48402_data();
98 void QTBUG48402();
99
100 void QTBUG58851_data();
101 void QTBUG58851();
102
103 void QTBUG18001_data();
104 void QTBUG18001();
105
106private:
107 QAbstractItemModel *model;
108 QItemSelectionModel *selection;
109};
110
111QDataStream &operator<<(QDataStream &, const QModelIndex &);
112QDataStream &operator>>(QDataStream &, QModelIndex &);
113QDataStream &operator<<(QDataStream &, const QModelIndexList &);
114QDataStream &operator>>(QDataStream &, QModelIndexList &);
115
116typedef QList<int> IntList;
117typedef QPair<int, int> IntPair;
118typedef QList<IntPair> PairList;
119
120class QStreamHelper: public QAbstractItemModel
121{
122public:
123 QStreamHelper() {}
124 static QModelIndex create(int row = -1, int column = -1, void *data = 0)
125 {
126 QStreamHelper helper;
127 return helper.QAbstractItemModel::createIndex(arow: row, acolumn: column, adata: data);
128 }
129
130 QModelIndex index(int, int, const QModelIndex&) const
131 { return QModelIndex(); }
132 QModelIndex parent(const QModelIndex&) const
133 { return QModelIndex(); }
134 int rowCount(const QModelIndex & = QModelIndex()) const
135 { return 0; }
136 int columnCount(const QModelIndex & = QModelIndex()) const
137 { return 0; }
138 QVariant data(const QModelIndex &, int = Qt::DisplayRole) const
139 { return QVariant(); }
140 bool hasChildren(const QModelIndex &) const
141 { return false; }
142};
143
144QDataStream &operator<<(QDataStream &s, const QModelIndex &input)
145{
146 s << input.row()
147 << input.column()
148 << reinterpret_cast<qlonglong>(input.internalPointer());
149 return s;
150}
151
152QDataStream &operator>>(QDataStream &s, QModelIndex &output)
153{
154 int r, c;
155 qlonglong ptr;
156 s >> r;
157 s >> c;
158 s >> ptr;
159 output = QStreamHelper::create(row: r, column: c, data: reinterpret_cast<void *>(ptr));
160 return s;
161}
162
163QDataStream &operator<<(QDataStream &s, const QModelIndexList &input)
164{
165 s << input.count();
166 for (int i=0; i<input.count(); ++i)
167 s << input.at(i);
168 return s;
169}
170
171QDataStream &operator>>(QDataStream &s, QModelIndexList &output)
172{
173 QModelIndex tmpIndex;
174 int count;
175 s >> count;
176 for (int i=0; i<count; ++i) {
177 s >> tmpIndex;
178 output << tmpIndex;
179 }
180 return s;
181}
182
183tst_QItemSelectionModel::tst_QItemSelectionModel()
184 : model(0), selection(0)
185{
186}
187
188/*
189 This test usually uses a model with a 5x5 table
190 -------------------------------------------
191 | 0,0 | 0,1 | 0,2 | 0,3 | 0,4 |
192 -------------------------------------------
193 | 1,0 | 1,1 | 1,2 | 1,3 | 1,4 |
194 -------------------------------------------
195 | 2,0 | 2,1 | 2,2 | 2,3 | 2,4 |
196 -------------------------------------------
197 | 3,0 | 3,1 | 3,2 | 3,3 | 3,4 |
198 -------------------------------------------
199 | 4,0 | 4,1 | 4,2 | 4,3 | 4,4 |
200 -------------------------------------------
201
202 ...that for each row has a children in a new 5x5 table ad infinitum.
203
204*/
205void tst_QItemSelectionModel::initTestCase()
206{
207 qRegisterMetaType<QItemSelection>(typeName: "QItemSelection");
208
209 model = new QStandardItemModel(5, 5);
210 QModelIndex parent = model->index(row: 0, column: 0, parent: QModelIndex());
211 model->insertRows(row: 0, count: 5, parent);
212 model->insertColumns(column: 0, count: 5, parent);
213 selection = new QItemSelectionModel(model);
214}
215
216void tst_QItemSelectionModel::cleanupTestCase()
217{
218 delete selection;
219 delete model;
220}
221
222void tst_QItemSelectionModel::init()
223{
224 selection->clear();
225 while (model->rowCount(parent: QModelIndex()) > 5)
226 model->removeRow(arow: 0, aparent: QModelIndex());
227 while (model->rowCount(parent: QModelIndex()) < 5)
228 model->insertRow(arow: 0, aparent: QModelIndex());
229}
230
231void tst_QItemSelectionModel::clear_data()
232{
233 QTest::addColumn<QModelIndexList>(name: "indexList");
234 QTest::addColumn<IntList>(name: "commandList");
235 {
236 QModelIndexList index;
237 IntList command;
238 index << model->index(row: 0, column: 0, parent: QModelIndex());
239 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
240 index << model->index(row: 1, column: 0, parent: QModelIndex());
241 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
242 QTest::newRow(dataTag: "(0, 0) and (1, 0): Select|Rows")
243 << index
244 << command;
245 }
246 {
247 QModelIndexList index;
248 IntList command;
249 index << model->index(row: 0, column: 0, parent: QModelIndex());
250 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
251 index << model->index(row: 0, column: 1, parent: QModelIndex());
252 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
253 QTest::newRow(dataTag: "(0, 0) and (1, 0): Select|Columns")
254 << index
255 << command;
256 }
257 {
258 QModelIndexList index;
259 IntList command;
260 index << model->index(row: 0, column: 0, parent: QModelIndex());
261 command << QItemSelectionModel::Select;
262 index << model->index(row: 1, column: 1, parent: QModelIndex());
263 command << QItemSelectionModel::Select;
264 index << model->index(row: 2, column: 2, parent: QModelIndex());
265 command << QItemSelectionModel::SelectCurrent;
266 QTest::newRow(dataTag: "(0, 0), (1, 1) and (2, 2): Select, Select, SelectCurrent")
267 << index
268 << command;
269 }
270 {
271 QModelIndexList index;
272 IntList command;
273 index << model->index(row: 0, column: 0, parent: QModelIndex());
274 command << QItemSelectionModel::Select;
275 index << model->index(row: 1, column: 1, parent: QModelIndex());
276 command << QItemSelectionModel::Select;
277 index << model->index(row: 1, column: 1, parent: QModelIndex());
278 command << QItemSelectionModel::Toggle;
279 QTest::newRow(dataTag: "(0, 0), (1, 1) and (1, 1): Select, Select, Toggle")
280 << index
281 << command;
282 }
283 {
284 QModelIndexList index;
285 IntList command;
286 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
287 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
288 QTest::newRow(dataTag: "child (0, 0) of (0, 0): Select|Rows")
289 << index
290 << command;
291 }
292}
293
294void tst_QItemSelectionModel::clear()
295{
296 QFETCH(QModelIndexList, indexList);
297 QFETCH(IntList, commandList);
298
299 // do selections
300 for (int i=0; i<indexList.count(); ++i) {
301 selection->select(index: indexList.at(i), command: (QItemSelectionModel::SelectionFlags)commandList.at(i));
302 }
303 // test that we have selected items
304 QVERIFY(!selection->selectedIndexes().isEmpty());
305 selection->clear();
306 // test that they were all cleared
307 QVERIFY(selection->selectedIndexes().isEmpty());
308}
309
310void tst_QItemSelectionModel::clearAndSelect()
311{
312 // populate selectionmodel
313 selection->select(index: model->index(row: 1, column: 1, parent: QModelIndex()), command: QItemSelectionModel::Select);
314 QCOMPARE(selection->selectedIndexes().count(), 1);
315 QVERIFY(selection->hasSelection());
316
317 // ClearAndSelect with empty selection
318 QItemSelection emptySelection;
319 selection->select(selection: emptySelection, command: QItemSelectionModel::ClearAndSelect);
320
321 // verify the selectionmodel is empty
322 QVERIFY(selection->selectedIndexes().isEmpty());
323 QVERIFY(selection->hasSelection()==false);
324}
325
326void tst_QItemSelectionModel::toggleSelection()
327{
328 //test the toggle selection and checks whether selectedIndex
329 //and hasSelection returns the correct value
330
331 selection->clearSelection();
332 QCOMPARE(selection->selectedIndexes().count(), 0);
333 QVERIFY(selection->hasSelection()==false);
334
335 QModelIndex index=model->index(row: 1, column: 1, parent: QModelIndex());
336 // populate selectionmodel
337 selection->select(index, command: QItemSelectionModel::Toggle);
338 QCOMPARE(selection->selectedIndexes().count(), 1);
339 QVERIFY(selection->hasSelection()==true);
340
341 selection->select(index, command: QItemSelectionModel::Toggle);
342 QCOMPARE(selection->selectedIndexes().count(), 0);
343 QVERIFY(selection->hasSelection()==false);
344
345 // populate selectionmodel with rows
346 selection->select(index, command: QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
347 QCOMPARE(selection->selectedIndexes().count(), model->columnCount());
348 QVERIFY(selection->hasSelection()==true);
349
350 selection->select(index, command: QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
351 QCOMPARE(selection->selectedIndexes().count(), 0);
352 QVERIFY(selection->hasSelection()==false);
353}
354
355void tst_QItemSelectionModel::select_data()
356{
357 QTest::addColumn<QModelIndexList>(name: "indexList");
358 QTest::addColumn<bool>(name: "useRanges");
359 QTest::addColumn<IntList>(name: "commandList");
360 QTest::addColumn<QModelIndexList>(name: "expectedList");
361
362 {
363 QModelIndexList index;
364 QModelIndexList expected;
365 IntList command;
366 index << model->index(row: 0, column: 0, parent: QModelIndex());
367 command << QItemSelectionModel::Select;
368 expected << model->index(row: 0, column: 0, parent: QModelIndex());
369 QTest::newRow(dataTag: "(0, 0): Select")
370 << index
371 << false
372 << command
373 << expected;
374 }
375 {
376 QModelIndexList index;
377 QModelIndexList expected;
378 IntList command;
379 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
380 command << QItemSelectionModel::Select;
381 expected << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
382 QTest::newRow(dataTag: "child (0, 0) of (0, 0): Select")
383 << index
384 << false
385 << command
386 << expected;
387 }
388 {
389 QModelIndexList index;
390 QModelIndexList expected;
391 IntList command;
392 index << model->index(row: 0, column: 0, parent: QModelIndex());
393 command << QItemSelectionModel::Deselect;
394 QTest::newRow(dataTag: "(0, 0): Deselect")
395 << index
396 << false
397 << command
398 << expected;
399 }
400 {
401 QModelIndexList index;
402 QModelIndexList expected;
403 IntList command;
404 index << model->index(row: 0, column: 0, parent: QModelIndex());
405 command << QItemSelectionModel::Toggle;
406 expected << model->index(row: 0, column: 0, parent: QModelIndex());
407 QTest::newRow(dataTag: "(0, 0): Toggle")
408 << index
409 << false
410 << command
411 << expected;
412 }
413 {
414 QModelIndexList index;
415 QModelIndexList expected;
416 IntList command;
417 index << model->index(row: 0, column: 0, parent: QModelIndex());
418 command << QItemSelectionModel::Select;
419 index << model->index(row: 0, column: 0, parent: QModelIndex());
420 command << QItemSelectionModel::Toggle;
421 QTest::newRow(dataTag: "(0, 0) and (0, 0): Select and Toggle")
422 << index
423 << false
424 << command
425 << expected;
426 }
427 {
428 QModelIndexList index;
429 QModelIndexList expected;
430 IntList command;
431 index << model->index(row: 0, column: 0, parent: QModelIndex());
432 command << QItemSelectionModel::Select;
433 index << model->index(row: 0, column: 0, parent: QModelIndex());
434 command << QItemSelectionModel::Deselect;
435 QTest::newRow(dataTag: "(0, 0) and (0, 0): Select and Deselect")
436 << index
437 << false
438 << command
439 << expected;
440 }
441 {
442 QModelIndexList index;
443 QModelIndexList expected;
444 IntList command;
445 index << model->index(row: 0, column: 0, parent: QModelIndex());
446 command << QItemSelectionModel::Select;
447 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
448 command << QItemSelectionModel::ClearAndSelect;
449 expected << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
450 QTest::newRow(dataTag: "(0, 0) and child (0, 0) of (0, 0): Select and ClearAndSelect")
451 << index
452 << false
453 << command
454 << expected;
455 }
456 {
457 QModelIndexList index;
458 QModelIndexList expected;
459 IntList command;
460 index << model->index(row: 0, column: 0, parent: QModelIndex());
461 index << model->index(row: 4, column: 0, parent: QModelIndex());
462 command << QItemSelectionModel::Select;
463 index << model->index(row: 0, column: 1, parent: QModelIndex());
464 index << model->index(row: 4, column: 1, parent: QModelIndex());
465 command << QItemSelectionModel::Select;
466 index << model->index(row: 0, column: 0, parent: QModelIndex());
467 index << model->index(row: 4, column: 1, parent: QModelIndex());
468 command << QItemSelectionModel::Deselect;
469 QTest::newRow(dataTag: "(0, 0 to 4, 0) and (0, 1 to 4, 1) and (0, 0 to 4, 1): Select and Select and Deselect")
470 << index
471 << true
472 << command
473 << expected;
474 }
475 {
476 QModelIndexList index;
477 QModelIndexList expected;
478 IntList command;
479 index << model->index(row: 0, column: 0, parent: QModelIndex());
480 command << QItemSelectionModel::Select;
481 index << model->index(row: 4, column: 4, parent: QModelIndex());
482 command << QItemSelectionModel::Select;
483 expected << model->index(row: 0, column: 0, parent: QModelIndex()) << model->index(row: 4, column: 4, parent: QModelIndex());
484 QTest::newRow(dataTag: "(0, 0) and (4, 4): Select")
485 << index
486 << false
487 << command
488 << expected;
489 }
490 {
491 QModelIndexList index;
492 QModelIndexList expected;
493 IntList command;
494 index << model->index(row: 0, column: 0, parent: QModelIndex());
495 command << QItemSelectionModel::Select;
496 index << model->index(row: 4, column: 4, parent: QModelIndex());
497 command << QItemSelectionModel::ClearAndSelect;
498 expected << model->index(row: 4, column: 4, parent: QModelIndex());
499 QTest::newRow(dataTag: "(0, 0) and (4, 4): Select and ClearAndSelect")
500 << index
501 << false
502 << command
503 << expected;
504 }
505 {
506 QModelIndexList index;
507 QModelIndexList expected;
508 IntList command;
509 index << model->index(row: 0, column: 0, parent: QModelIndex());
510 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
511 index << model->index(row: 4, column: 4, parent: QModelIndex());
512 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
513 expected << model->index(row: 0, column: 0, parent: QModelIndex())
514 << model->index(row: 0, column: 1, parent: QModelIndex())
515 << model->index(row: 0, column: 2, parent: QModelIndex())
516 << model->index(row: 0, column: 3, parent: QModelIndex())
517 << model->index(row: 0, column: 4, parent: QModelIndex())
518 << model->index(row: 4, column: 0, parent: QModelIndex())
519 << model->index(row: 4, column: 1, parent: QModelIndex())
520 << model->index(row: 4, column: 2, parent: QModelIndex())
521 << model->index(row: 4, column: 3, parent: QModelIndex())
522 << model->index(row: 4, column: 4, parent: QModelIndex());
523 QTest::newRow(dataTag: "(0, 0) and (4, 4): Select|Rows")
524 << index
525 << false
526 << command
527 << expected;
528 }
529 {
530 QModelIndexList index;
531 QModelIndexList expected;
532 IntList command;
533 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
534 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
535 index << model->index(row: 4, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
536 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
537 QModelIndex parent = model->index(row: 0, column: 0, parent: QModelIndex());
538 expected << model->index(row: 0, column: 0, parent)
539 << model->index(row: 0, column: 1, parent)
540 << model->index(row: 0, column: 2, parent)
541 << model->index(row: 0, column: 3, parent)
542 << model->index(row: 0, column: 4, parent)
543 << model->index(row: 4, column: 0, parent)
544 << model->index(row: 4, column: 1, parent)
545 << model->index(row: 4, column: 2, parent)
546 << model->index(row: 4, column: 3, parent)
547 << model->index(row: 4, column: 4, parent);
548 QTest::newRow(dataTag: "child (0, 0) and (4, 4) of (0, 0): Select|Rows")
549 << index
550 << false
551 << command
552 << expected;
553 }
554 {
555 QModelIndexList index;
556 QModelIndexList expected;
557 IntList command;
558 index << model->index(row: 0, column: 0, parent: QModelIndex());
559 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
560 index << model->index(row: 4, column: 4, parent: QModelIndex());
561 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
562 expected << model->index(row: 0, column: 0, parent: QModelIndex())
563 << model->index(row: 1, column: 0, parent: QModelIndex())
564 << model->index(row: 2, column: 0, parent: QModelIndex())
565 << model->index(row: 3, column: 0, parent: QModelIndex())
566 << model->index(row: 4, column: 0, parent: QModelIndex())
567 << model->index(row: 0, column: 4, parent: QModelIndex())
568 << model->index(row: 1, column: 4, parent: QModelIndex())
569 << model->index(row: 2, column: 4, parent: QModelIndex())
570 << model->index(row: 3, column: 4, parent: QModelIndex())
571 << model->index(row: 4, column: 4, parent: QModelIndex());
572 QTest::newRow(dataTag: "(0, 0) and (4, 4): Select|Columns")
573 << index
574 << false
575 << command
576 << expected;
577 }
578 {
579 QModelIndexList index;
580 QModelIndexList expected;
581 IntList command;
582 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
583 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
584 index << model->index(row: 4, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
585 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
586 expected << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
587 << model->index(row: 1, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
588 << model->index(row: 2, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
589 << model->index(row: 3, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
590 << model->index(row: 4, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
591 << model->index(row: 0, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
592 << model->index(row: 1, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
593 << model->index(row: 2, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
594 << model->index(row: 3, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()))
595 << model->index(row: 4, column: 4, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
596 QTest::newRow(dataTag: "child (0, 0) and (4, 4) of (0, 0): Select|Columns")
597 << index
598 << false
599 << command
600 << expected;
601 }
602 {
603 QModelIndexList index;
604 QModelIndexList expected;
605 IntList command;
606 index << model->index(row: 0, column: 0, parent: QModelIndex());
607 index << model->index(row: 4, column: 0, parent: QModelIndex());
608 command << QItemSelectionModel::Select;
609 expected << model->index(row: 0, column: 0, parent: QModelIndex())
610 << model->index(row: 1, column: 0, parent: QModelIndex())
611 << model->index(row: 2, column: 0, parent: QModelIndex())
612 << model->index(row: 3, column: 0, parent: QModelIndex())
613 << model->index(row: 4, column: 0, parent: QModelIndex());
614 QTest::newRow(dataTag: "(0, 0 to 4, 0): Select")
615 << index
616 << true
617 << command
618 << expected;
619 }
620 {
621 QModelIndexList index;
622 QModelIndexList expected;
623 IntList command;
624 index << model->index(row: 0, column: 0, parent: QModelIndex());
625 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
626 command << QItemSelectionModel::Select;
627 QTest::newRow(dataTag: "(0, 0 to child 0, 0): Select")
628 << index
629 << true
630 << command
631 << expected;
632 }
633 {
634 QModelIndexList index;
635 QModelIndexList expected;
636 IntList command;
637 index << model->index(row: 0, column: 0, parent: model->index(row: 0, column: 0, parent: QModelIndex()));
638 index << model->index(row: 0, column: 0, parent: model->index(row: 1, column: 0, parent: QModelIndex()));
639 command << QItemSelectionModel::Select;
640 QTest::newRow(dataTag: "child (0, 0) of (0, 0) to child (0, 0) of (1, 0): Select")
641 << index
642 << true
643 << command
644 << expected;
645 }
646 {
647 QModelIndexList index;
648 QModelIndexList expected;
649 IntList command;
650 index << model->index(row: 0, column: 0, parent: QModelIndex());
651 index << model->index(row: 4, column: 4, parent: QModelIndex());
652 command << QItemSelectionModel::Select;
653 expected << model->index(row: 0, column: 0, parent: QModelIndex())
654 << model->index(row: 0, column: 1, parent: QModelIndex())
655 << model->index(row: 0, column: 2, parent: QModelIndex())
656 << model->index(row: 0, column: 3, parent: QModelIndex())
657 << model->index(row: 0, column: 4, parent: QModelIndex())
658 << model->index(row: 1, column: 0, parent: QModelIndex())
659 << model->index(row: 1, column: 1, parent: QModelIndex())
660 << model->index(row: 1, column: 2, parent: QModelIndex())
661 << model->index(row: 1, column: 3, parent: QModelIndex())
662 << model->index(row: 1, column: 4, parent: QModelIndex())
663 << model->index(row: 2, column: 0, parent: QModelIndex())
664 << model->index(row: 2, column: 1, parent: QModelIndex())
665 << model->index(row: 2, column: 2, parent: QModelIndex())
666 << model->index(row: 2, column: 3, parent: QModelIndex())
667 << model->index(row: 2, column: 4, parent: QModelIndex())
668 << model->index(row: 3, column: 0, parent: QModelIndex())
669 << model->index(row: 3, column: 1, parent: QModelIndex())
670 << model->index(row: 3, column: 2, parent: QModelIndex())
671 << model->index(row: 3, column: 3, parent: QModelIndex())
672 << model->index(row: 3, column: 4, parent: QModelIndex())
673 << model->index(row: 4, column: 0, parent: QModelIndex())
674 << model->index(row: 4, column: 1, parent: QModelIndex())
675 << model->index(row: 4, column: 2, parent: QModelIndex())
676 << model->index(row: 4, column: 3, parent: QModelIndex())
677 << model->index(row: 4, column: 4, parent: QModelIndex());
678 QTest::newRow(dataTag: "(0, 0 to 4, 4): Select")
679 << index
680 << true
681 << command
682 << expected;
683 }
684 {
685 QModelIndexList index;
686 QModelIndexList expected;
687 IntList command;
688 index << model->index(row: 0, column: 0, parent: QModelIndex());
689 index << model->index(row: 4, column: 0, parent: QModelIndex());
690 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
691 expected << model->index(row: 0, column: 0, parent: QModelIndex())
692 << model->index(row: 0, column: 1, parent: QModelIndex())
693 << model->index(row: 0, column: 2, parent: QModelIndex())
694 << model->index(row: 0, column: 3, parent: QModelIndex())
695 << model->index(row: 0, column: 4, parent: QModelIndex())
696 << model->index(row: 1, column: 0, parent: QModelIndex())
697 << model->index(row: 1, column: 1, parent: QModelIndex())
698 << model->index(row: 1, column: 2, parent: QModelIndex())
699 << model->index(row: 1, column: 3, parent: QModelIndex())
700 << model->index(row: 1, column: 4, parent: QModelIndex())
701 << model->index(row: 2, column: 0, parent: QModelIndex())
702 << model->index(row: 2, column: 1, parent: QModelIndex())
703 << model->index(row: 2, column: 2, parent: QModelIndex())
704 << model->index(row: 2, column: 3, parent: QModelIndex())
705 << model->index(row: 2, column: 4, parent: QModelIndex())
706 << model->index(row: 3, column: 0, parent: QModelIndex())
707 << model->index(row: 3, column: 1, parent: QModelIndex())
708 << model->index(row: 3, column: 2, parent: QModelIndex())
709 << model->index(row: 3, column: 3, parent: QModelIndex())
710 << model->index(row: 3, column: 4, parent: QModelIndex())
711 << model->index(row: 4, column: 0, parent: QModelIndex())
712 << model->index(row: 4, column: 1, parent: QModelIndex())
713 << model->index(row: 4, column: 2, parent: QModelIndex())
714 << model->index(row: 4, column: 3, parent: QModelIndex())
715 << model->index(row: 4, column: 4, parent: QModelIndex());
716 QTest::newRow(dataTag: "(0, 0 to 4, 0): Select|Rows")
717 << index
718 << true
719 << command
720 << expected;
721 }
722 {
723 QModelIndexList index;
724 QModelIndexList expected;
725 IntList command;
726 index << model->index(row: 0, column: 0, parent: QModelIndex());
727 index << model->index(row: 0, column: 4, parent: QModelIndex());
728 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
729 expected << model->index(row: 0, column: 0, parent: QModelIndex())
730 << model->index(row: 0, column: 1, parent: QModelIndex())
731 << model->index(row: 0, column: 2, parent: QModelIndex())
732 << model->index(row: 0, column: 3, parent: QModelIndex())
733 << model->index(row: 0, column: 4, parent: QModelIndex())
734 << model->index(row: 1, column: 0, parent: QModelIndex())
735 << model->index(row: 1, column: 1, parent: QModelIndex())
736 << model->index(row: 1, column: 2, parent: QModelIndex())
737 << model->index(row: 1, column: 3, parent: QModelIndex())
738 << model->index(row: 1, column: 4, parent: QModelIndex())
739 << model->index(row: 2, column: 0, parent: QModelIndex())
740 << model->index(row: 2, column: 1, parent: QModelIndex())
741 << model->index(row: 2, column: 2, parent: QModelIndex())
742 << model->index(row: 2, column: 3, parent: QModelIndex())
743 << model->index(row: 2, column: 4, parent: QModelIndex())
744 << model->index(row: 3, column: 0, parent: QModelIndex())
745 << model->index(row: 3, column: 1, parent: QModelIndex())
746 << model->index(row: 3, column: 2, parent: QModelIndex())
747 << model->index(row: 3, column: 3, parent: QModelIndex())
748 << model->index(row: 3, column: 4, parent: QModelIndex())
749 << model->index(row: 4, column: 0, parent: QModelIndex())
750 << model->index(row: 4, column: 1, parent: QModelIndex())
751 << model->index(row: 4, column: 2, parent: QModelIndex())
752 << model->index(row: 4, column: 3, parent: QModelIndex())
753 << model->index(row: 4, column: 4, parent: QModelIndex());
754 QTest::newRow(dataTag: "(0, 0 to 0, 4): Select|Columns")
755 << index
756 << true
757 << command
758 << expected;
759 }
760 {
761 QModelIndexList index;
762 QModelIndexList expected;
763 IntList command;
764 index << model->index(row: 0, column: 0, parent: QModelIndex());
765 index << model->index(row: 4, column: 4, parent: QModelIndex());
766 command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
767 expected << model->index(row: 0, column: 0, parent: QModelIndex())
768 << model->index(row: 0, column: 1, parent: QModelIndex())
769 << model->index(row: 0, column: 2, parent: QModelIndex())
770 << model->index(row: 0, column: 3, parent: QModelIndex())
771 << model->index(row: 0, column: 4, parent: QModelIndex())
772 << model->index(row: 1, column: 0, parent: QModelIndex())
773 << model->index(row: 1, column: 1, parent: QModelIndex())
774 << model->index(row: 1, column: 2, parent: QModelIndex())
775 << model->index(row: 1, column: 3, parent: QModelIndex())
776 << model->index(row: 1, column: 4, parent: QModelIndex())
777 << model->index(row: 2, column: 0, parent: QModelIndex())
778 << model->index(row: 2, column: 1, parent: QModelIndex())
779 << model->index(row: 2, column: 2, parent: QModelIndex())
780 << model->index(row: 2, column: 3, parent: QModelIndex())
781 << model->index(row: 2, column: 4, parent: QModelIndex())
782 << model->index(row: 3, column: 0, parent: QModelIndex())
783 << model->index(row: 3, column: 1, parent: QModelIndex())
784 << model->index(row: 3, column: 2, parent: QModelIndex())
785 << model->index(row: 3, column: 3, parent: QModelIndex())
786 << model->index(row: 3, column: 4, parent: QModelIndex())
787 << model->index(row: 4, column: 0, parent: QModelIndex())
788 << model->index(row: 4, column: 1, parent: QModelIndex())
789 << model->index(row: 4, column: 2, parent: QModelIndex())
790 << model->index(row: 4, column: 3, parent: QModelIndex())
791 << model->index(row: 4, column: 4, parent: QModelIndex());
792 QTest::newRow(dataTag: "(0, 0 to 4, 4): Select|Rows")
793 << index
794 << true
795 << command
796 << expected;
797 }
798 {
799 QModelIndexList index;
800 QModelIndexList expected;
801 IntList command;
802 index << model->index(row: 0, column: 0, parent: QModelIndex());
803 index << model->index(row: 4, column: 4, parent: QModelIndex());
804 command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
805 expected << model->index(row: 0, column: 0, parent: QModelIndex())
806 << model->index(row: 0, column: 1, parent: QModelIndex())
807 << model->index(row: 0, column: 2, parent: QModelIndex())
808 << model->index(row: 0, column: 3, parent: QModelIndex())
809 << model->index(row: 0, column: 4, parent: QModelIndex())
810 << model->index(row: 1, column: 0, parent: QModelIndex())
811 << model->index(row: 1, column: 1, parent: QModelIndex())
812 << model->index(row: 1, column: 2, parent: QModelIndex())
813 << model->index(row: 1, column: 3, parent: QModelIndex())
814 << model->index(row: 1, column: 4, parent: QModelIndex())
815 << model->index(row: 2, column: 0, parent: QModelIndex())
816 << model->index(row: 2, column: 1, parent: QModelIndex())
817 << model->index(row: 2, column: 2, parent: QModelIndex())
818 << model->index(row: 2, column: 3, parent: QModelIndex())
819 << model->index(row: 2, column: 4, parent: QModelIndex())
820 << model->index(row: 3, column: 0, parent: QModelIndex())
821 << model->index(row: 3, column: 1, parent: QModelIndex())
822 << model->index(row: 3, column: 2, parent: QModelIndex())
823 << model->index(row: 3, column: 3, parent: QModelIndex())
824 << model->index(row: 3, column: 4, parent: QModelIndex())
825 << model->index(row: 4, column: 0, parent: QModelIndex())
826 << model->index(row: 4, column: 1, parent: QModelIndex())
827 << model->index(row: 4, column: 2, parent: QModelIndex())
828 << model->index(row: 4, column: 3, parent: QModelIndex())
829 << model->index(row: 4, column: 4, parent: QModelIndex());
830 QTest::newRow(dataTag: "(0, 0 to 4, 4): Select|Columns")
831 << index
832 << true
833 << command
834 << expected;
835 }
836 {
837 QModelIndexList index;
838 QModelIndexList expected;
839 IntList command;
840 index << model->index(row: 0, column: 2, parent: QModelIndex());
841 index << model->index(row: 4, column: 2, parent: QModelIndex());
842 command << QItemSelectionModel::Select;
843 index << model->index(row: 2, column: 0, parent: QModelIndex());
844 index << model->index(row: 2, column: 4, parent: QModelIndex());
845 command << QItemSelectionModel::Select;
846 expected << model->index(row: 0, column: 2, parent: QModelIndex())
847 << model->index(row: 1, column: 2, parent: QModelIndex())
848 << model->index(row: 2, column: 2, parent: QModelIndex())
849 << model->index(row: 3, column: 2, parent: QModelIndex())
850 << model->index(row: 4, column: 2, parent: QModelIndex())
851 << model->index(row: 2, column: 0, parent: QModelIndex())
852 << model->index(row: 2, column: 1, parent: QModelIndex())
853 << model->index(row: 2, column: 3, parent: QModelIndex())
854 << model->index(row: 2, column: 4, parent: QModelIndex());
855 QTest::newRow(dataTag: "(0, 2 to 4, 2) and (2, 0 to 2, 4): Select")
856 << index
857 << true
858 << command
859 << expected;
860 }
861 {
862 QModelIndexList index;
863 QModelIndexList expected;
864 IntList command;
865 index << model->index(row: 0, column: 2, parent: QModelIndex());
866 index << model->index(row: 4, column: 2, parent: QModelIndex());
867 command << QItemSelectionModel::Select;
868 index << model->index(row: 2, column: 0, parent: QModelIndex());
869 index << model->index(row: 2, column: 4, parent: QModelIndex());
870 command << QItemSelectionModel::SelectCurrent;
871 expected << model->index(row: 2, column: 0, parent: QModelIndex())
872 << model->index(row: 2, column: 1, parent: QModelIndex())
873 << model->index(row: 2, column: 2, parent: QModelIndex())
874 << model->index(row: 2, column: 3, parent: QModelIndex())
875 << model->index(row: 2, column: 4, parent: QModelIndex());
876 QTest::newRow(dataTag: "(0, 2 to 4, 2) and (2, 0 to 2, 4): Select and SelectCurrent")
877 << index
878 << true
879 << command
880 << expected;
881 }
882 {
883 QModelIndexList index;
884 QModelIndexList expected;
885 IntList command;
886 index << model->index(row: 0, column: 2, parent: QModelIndex());
887 index << model->index(row: 4, column: 2, parent: QModelIndex());
888 command << QItemSelectionModel::Select;
889 index << model->index(row: 2, column: 0, parent: QModelIndex());
890 index << model->index(row: 2, column: 4, parent: QModelIndex());
891 command << QItemSelectionModel::Toggle;
892 expected << model->index(row: 0, column: 2, parent: QModelIndex())
893 << model->index(row: 1, column: 2, parent: QModelIndex())
894 << model->index(row: 3, column: 2, parent: QModelIndex())
895 << model->index(row: 4, column: 2, parent: QModelIndex())
896 << model->index(row: 2, column: 0, parent: QModelIndex())
897 << model->index(row: 2, column: 1, parent: QModelIndex())
898 << model->index(row: 2, column: 3, parent: QModelIndex())
899 << model->index(row: 2, column: 4, parent: QModelIndex());
900 QTest::newRow(dataTag: "(0, 2 to 4, 2) and (2, 0 to 2, 4): Select and Toggle")
901 << index
902 << true
903 << command
904 << expected;
905 }
906 {
907 QModelIndexList index;
908 QModelIndexList expected;
909 IntList command;
910 index << model->index(row: 0, column: 2, parent: QModelIndex());
911 index << model->index(row: 4, column: 2, parent: QModelIndex());
912 command << QItemSelectionModel::Select;
913 index << model->index(row: 2, column: 0, parent: QModelIndex());
914 index << model->index(row: 2, column: 4, parent: QModelIndex());
915 command << QItemSelectionModel::Deselect;
916 expected << model->index(row: 0, column: 2, parent: QModelIndex())
917 << model->index(row: 1, column: 2, parent: QModelIndex())
918 << model->index(row: 3, column: 2, parent: QModelIndex())
919 << model->index(row: 4, column: 2, parent: QModelIndex());
920 QTest::newRow(dataTag: "(0, 2 to 4, 2) and (2, 0 to 2, 4): Select and Deselect")
921 << index
922 << true
923 << command
924 << expected;
925 }
926
927 {
928 QModelIndexList index;
929 QModelIndexList expected;
930 IntList command;
931 index << model->index(row: 0, column: 0, parent: QModelIndex());
932 index << model->index(row: 2, column: 2, parent: QModelIndex());
933 command << QItemSelectionModel::Select;
934
935 index << model->index(row: 0, column: 0, parent: QModelIndex());
936 index << model->index(row: 0, column: 0, parent: QModelIndex());
937 command << QItemSelectionModel::Toggle;
938
939 expected << model->index(row: 0, column: 1, parent: QModelIndex())
940 << model->index(row: 0, column: 2, parent: QModelIndex())
941 << model->index(row: 1, column: 0, parent: QModelIndex())
942 << model->index(row: 1, column: 1, parent: QModelIndex())
943 << model->index(row: 1, column: 2, parent: QModelIndex())
944 << model->index(row: 2, column: 0, parent: QModelIndex())
945 << model->index(row: 2, column: 1, parent: QModelIndex())
946 << model->index(row: 2, column: 2, parent: QModelIndex());
947
948 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (0, 0 to 0, 0): Select and Toggle at selection boundary")
949 << index
950 << true
951 << command
952 << expected;
953 }
954
955 {
956 QModelIndexList index;
957 QModelIndexList expected;
958 IntList command;
959 index << model->index(row: 0, column: 0, parent: QModelIndex());
960 index << model->index(row: 2, column: 2, parent: QModelIndex());
961 command << QItemSelectionModel::Select;
962
963 index << model->index(row: 0, column: 1, parent: QModelIndex());
964 index << model->index(row: 0, column: 1, parent: QModelIndex());
965 command << QItemSelectionModel::Toggle;
966
967 expected << model->index(row: 0, column: 0, parent: QModelIndex())
968 << model->index(row: 0, column: 2, parent: QModelIndex())
969 << model->index(row: 1, column: 0, parent: QModelIndex())
970 << model->index(row: 1, column: 1, parent: QModelIndex())
971 << model->index(row: 1, column: 2, parent: QModelIndex())
972 << model->index(row: 2, column: 0, parent: QModelIndex())
973 << model->index(row: 2, column: 1, parent: QModelIndex())
974 << model->index(row: 2, column: 2, parent: QModelIndex());
975
976 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (0, 1 to 0, 1): Select and Toggle at selection boundary")
977 << index
978 << true
979 << command
980 << expected;
981 }
982
983 {
984 QModelIndexList index;
985 QModelIndexList expected;
986 IntList command;
987 index << model->index(row: 0, column: 0, parent: QModelIndex());
988 index << model->index(row: 2, column: 2, parent: QModelIndex());
989 command << QItemSelectionModel::Select;
990
991 index << model->index(row: 0, column: 2, parent: QModelIndex());
992 index << model->index(row: 0, column: 2, parent: QModelIndex());
993 command << QItemSelectionModel::Toggle;
994
995 expected << model->index(row: 0, column: 0, parent: QModelIndex())
996 << model->index(row: 0, column: 1, parent: QModelIndex())
997 << model->index(row: 1, column: 0, parent: QModelIndex())
998 << model->index(row: 1, column: 1, parent: QModelIndex())
999 << model->index(row: 1, column: 2, parent: QModelIndex())
1000 << model->index(row: 2, column: 0, parent: QModelIndex())
1001 << model->index(row: 2, column: 1, parent: QModelIndex())
1002 << model->index(row: 2, column: 2, parent: QModelIndex());
1003
1004 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (0, 2 to 0, 2): Select and Toggle at selection boundary")
1005 << index
1006 << true
1007 << command
1008 << expected;
1009 }
1010
1011 {
1012 QModelIndexList index;
1013 QModelIndexList expected;
1014 IntList command;
1015 index << model->index(row: 0, column: 0, parent: QModelIndex());
1016 index << model->index(row: 2, column: 2, parent: QModelIndex());
1017 command << QItemSelectionModel::Select;
1018
1019 index << model->index(row: 1, column: 0, parent: QModelIndex());
1020 index << model->index(row: 1, column: 0, parent: QModelIndex());
1021 command << QItemSelectionModel::Toggle;
1022
1023 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1024 << model->index(row: 0, column: 1, parent: QModelIndex())
1025 << model->index(row: 0, column: 2, parent: QModelIndex())
1026 << model->index(row: 1, column: 1, parent: QModelIndex())
1027 << model->index(row: 1, column: 2, parent: QModelIndex())
1028 << model->index(row: 2, column: 0, parent: QModelIndex())
1029 << model->index(row: 2, column: 1, parent: QModelIndex())
1030 << model->index(row: 2, column: 2, parent: QModelIndex());
1031
1032 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (1, 0 to 1, 0): Select and Toggle at selection boundary")
1033 << index
1034 << true
1035 << command
1036 << expected;
1037 }
1038
1039 {
1040 QModelIndexList index;
1041 QModelIndexList expected;
1042 IntList command;
1043 index << model->index(row: 0, column: 0, parent: QModelIndex());
1044 index << model->index(row: 2, column: 2, parent: QModelIndex());
1045 command << QItemSelectionModel::Select;
1046
1047 index << model->index(row: 1, column: 1, parent: QModelIndex());
1048 index << model->index(row: 1, column: 1, parent: QModelIndex());
1049 command << QItemSelectionModel::Toggle;
1050
1051 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1052 << model->index(row: 0, column: 1, parent: QModelIndex())
1053 << model->index(row: 0, column: 2, parent: QModelIndex())
1054 << model->index(row: 1, column: 0, parent: QModelIndex())
1055 << model->index(row: 1, column: 2, parent: QModelIndex())
1056 << model->index(row: 2, column: 0, parent: QModelIndex())
1057 << model->index(row: 2, column: 1, parent: QModelIndex())
1058 << model->index(row: 2, column: 2, parent: QModelIndex());
1059
1060 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (1, 1 to 1, 1): Select and Toggle at selection boundary")
1061 << index
1062 << true
1063 << command
1064 << expected;
1065 }
1066 {
1067 QModelIndexList index;
1068 QModelIndexList expected;
1069 IntList command;
1070 index << model->index(row: 0, column: 0, parent: QModelIndex());
1071 index << model->index(row: 2, column: 2, parent: QModelIndex());
1072 command << QItemSelectionModel::Select;
1073
1074 index << model->index(row: 1, column: 2, parent: QModelIndex());
1075 index << model->index(row: 1, column: 2, parent: QModelIndex());
1076 command << QItemSelectionModel::Toggle;
1077
1078 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1079 << model->index(row: 0, column: 1, parent: QModelIndex())
1080 << model->index(row: 0, column: 2, parent: QModelIndex())
1081 << model->index(row: 1, column: 0, parent: QModelIndex())
1082 << model->index(row: 1, column: 1, parent: QModelIndex())
1083 << model->index(row: 2, column: 0, parent: QModelIndex())
1084 << model->index(row: 2, column: 1, parent: QModelIndex())
1085 << model->index(row: 2, column: 2, parent: QModelIndex());
1086
1087 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (1, 2 to 1, 2): Select and Toggle at selection boundary")
1088 << index
1089 << true
1090 << command
1091 << expected;
1092 }
1093 {
1094 QModelIndexList index;
1095 QModelIndexList expected;
1096 IntList command;
1097 index << model->index(row: 0, column: 0, parent: QModelIndex());
1098 index << model->index(row: 2, column: 2, parent: QModelIndex());
1099 command << QItemSelectionModel::Select;
1100
1101 index << model->index(row: 2, column: 0, parent: QModelIndex());
1102 index << model->index(row: 2, column: 0, parent: QModelIndex());
1103 command << QItemSelectionModel::Toggle;
1104
1105 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1106 << model->index(row: 0, column: 1, parent: QModelIndex())
1107 << model->index(row: 0, column: 2, parent: QModelIndex())
1108 << model->index(row: 1, column: 0, parent: QModelIndex())
1109 << model->index(row: 1, column: 1, parent: QModelIndex())
1110 << model->index(row: 1, column: 2, parent: QModelIndex())
1111 << model->index(row: 2, column: 1, parent: QModelIndex())
1112 << model->index(row: 2, column: 2, parent: QModelIndex());
1113
1114 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (2, 0 to 2, 0): Select and Toggle at selection boundary")
1115 << index
1116 << true
1117 << command
1118 << expected;
1119 }
1120 {
1121 QModelIndexList index;
1122 QModelIndexList expected;
1123 IntList command;
1124 index << model->index(row: 0, column: 0, parent: QModelIndex());
1125 index << model->index(row: 2, column: 2, parent: QModelIndex());
1126 command << QItemSelectionModel::Select;
1127
1128 index << model->index(row: 2, column: 1, parent: QModelIndex());
1129 index << model->index(row: 2, column: 1, parent: QModelIndex());
1130 command << QItemSelectionModel::Toggle;
1131
1132 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1133 << model->index(row: 0, column: 1, parent: QModelIndex())
1134 << model->index(row: 0, column: 2, parent: QModelIndex())
1135 << model->index(row: 1, column: 0, parent: QModelIndex())
1136 << model->index(row: 1, column: 1, parent: QModelIndex())
1137 << model->index(row: 1, column: 2, parent: QModelIndex())
1138 << model->index(row: 2, column: 0, parent: QModelIndex())
1139 << model->index(row: 2, column: 2, parent: QModelIndex());
1140
1141 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (2, 1 to 2, 1): Select and Toggle at selection boundary")
1142 << index
1143 << true
1144 << command
1145 << expected;
1146 }
1147 {
1148 QModelIndexList index;
1149 QModelIndexList expected;
1150 IntList command;
1151
1152 index << model->index(row: 0, column: 0, parent: QModelIndex());
1153 index << model->index(row: 2, column: 2, parent: QModelIndex());
1154 command << QItemSelectionModel::Select;
1155
1156 index << model->index(row: 2, column: 2, parent: QModelIndex());
1157 index << model->index(row: 2, column: 2, parent: QModelIndex());
1158 command << QItemSelectionModel::Toggle;
1159
1160 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1161 << model->index(row: 0, column: 1, parent: QModelIndex())
1162 << model->index(row: 0, column: 2, parent: QModelIndex())
1163 << model->index(row: 1, column: 0, parent: QModelIndex())
1164 << model->index(row: 1, column: 1, parent: QModelIndex())
1165 << model->index(row: 1, column: 2, parent: QModelIndex())
1166 << model->index(row: 2, column: 0, parent: QModelIndex())
1167 << model->index(row: 2, column: 1, parent: QModelIndex());
1168
1169 QTest::newRow(dataTag: "(0, 0 to 2, 2) and (2, 2 to 2, 2): Select and Toggle at selection boundary")
1170 << index
1171 << true
1172 << command
1173 << expected;
1174 }
1175 {
1176 QModelIndexList indexes;
1177 IntList commands;
1178 QModelIndexList expected;
1179
1180 indexes << model->index(row: 0, column: 0, parent: QModelIndex()) << model->index(row: 0, column: 0, parent: QModelIndex()) // press 0
1181 << model->index(row: 0, column: 0, parent: QModelIndex()) << model->index(row: 0, column: 0, parent: QModelIndex()) // release 0
1182 << model->index(row: 1, column: 0, parent: QModelIndex()) << model->index(row: 1, column: 0, parent: QModelIndex()) // press 1
1183 << model->index(row: 1, column: 0, parent: QModelIndex()) << model->index(row: 1, column: 0, parent: QModelIndex()) // release 1
1184 << model->index(row: 2, column: 0, parent: QModelIndex()) << model->index(row: 2, column: 0, parent: QModelIndex()) // press 2
1185 << model->index(row: 2, column: 0, parent: QModelIndex()) << model->index(row: 2, column: 0, parent: QModelIndex()) // release 2
1186 << model->index(row: 3, column: 0, parent: QModelIndex()) << model->index(row: 3, column: 0, parent: QModelIndex()) // press 3
1187 << model->index(row: 3, column: 0, parent: QModelIndex()) << model->index(row: 3, column: 0, parent: QModelIndex()) // release 3
1188 << model->index(row: 2, column: 0, parent: QModelIndex()) << model->index(row: 2, column: 0, parent: QModelIndex()) // press 2 again
1189 << model->index(row: 2, column: 0, parent: QModelIndex()) << model->index(row: 2, column: 0, parent: QModelIndex());// move 2
1190
1191 commands << (QItemSelectionModel::NoUpdate) // press 0
1192 << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 0
1193 << (QItemSelectionModel::NoUpdate) // press 1
1194 << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 1
1195 << (QItemSelectionModel::NoUpdate) // press 2
1196 << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 2
1197 << (QItemSelectionModel::NoUpdate) // press 3
1198 << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 3
1199 << (QItemSelectionModel::NoUpdate) // press 2 again
1200 << (QItemSelectionModel::Toggle/*Current*/|QItemSelectionModel::Rows);// move 2
1201
1202 expected << model->index(row: 0, column: 0, parent: QModelIndex())
1203 << model->index(row: 0, column: 1, parent: QModelIndex())
1204 << model->index(row: 0, column: 2, parent: QModelIndex())
1205 << model->index(row: 0, column: 3, parent: QModelIndex())
1206 << model->index(row: 0, column: 4, parent: QModelIndex())
1207
1208 << model->index(row: 1, column: 0, parent: QModelIndex())
1209 << model->index(row: 1, column: 1, parent: QModelIndex())
1210 << model->index(row: 1, column: 2, parent: QModelIndex())
1211 << model->index(row: 1, column: 3, parent: QModelIndex())
1212 << model->index(row: 1, column: 4, parent: QModelIndex())
1213 /*
1214 << model->index(2, 0, QModelIndex())
1215 << model->index(2, 1, QModelIndex())
1216 << model->index(2, 2, QModelIndex())
1217 << model->index(2, 3, QModelIndex())
1218 << model->index(2, 4, QModelIndex())
1219 */
1220 << model->index(row: 3, column: 0, parent: QModelIndex())
1221 << model->index(row: 3, column: 1, parent: QModelIndex())
1222 << model->index(row: 3, column: 2, parent: QModelIndex())
1223 << model->index(row: 3, column: 3, parent: QModelIndex())
1224 << model->index(row: 3, column: 4, parent: QModelIndex());
1225
1226 QTest::newRow(dataTag: "simulated treeview multiselection behavior")
1227 << indexes
1228 << true
1229 << commands
1230 << expected;
1231 }
1232}
1233
1234void tst_QItemSelectionModel::select()
1235{
1236 QFETCH(QModelIndexList, indexList);
1237 QFETCH(bool, useRanges);
1238 QFETCH(IntList, commandList);
1239 QFETCH(QModelIndexList, expectedList);
1240
1241 int lastCommand = 0;
1242 // do selections
1243 for (int i = 0; i<commandList.count(); ++i) {
1244 if (useRanges) {
1245 selection->select(selection: QItemSelection(indexList.at(i: 2*i), indexList.at(i: 2*i+1)),
1246 command: (QItemSelectionModel::SelectionFlags)commandList.at(i));
1247 } else {
1248 selection->select(index: indexList.at(i),
1249 command: (QItemSelectionModel::SelectionFlags)commandList.at(i));
1250 }
1251 lastCommand = commandList.at(i);
1252 }
1253
1254
1255 QModelIndexList selectedList = selection->selectedIndexes();
1256
1257 QVERIFY(selection->hasSelection()!=selectedList.isEmpty());
1258
1259 // test that the number of indices are as expected
1260 QVERIFY2(selectedList.count() == expectedList.count(),
1261 QString("expected indices: %1 actual indices: %2")
1262 .arg(expectedList.count())
1263 .arg(selectedList.count()).toLatin1());
1264
1265 // test existence of each index
1266 for (int i=0; i<expectedList.count(); ++i) {
1267 QVERIFY2(selectedList.contains(expectedList.at(i)),
1268 QString("expected index(%1, %2) not found in selectedIndexes()")
1269 .arg(expectedList.at(i).row())
1270 .arg(expectedList.at(i).column()).toLatin1());
1271 }
1272
1273 // test that isSelected agrees
1274 for (int i=0; i<indexList.count(); ++i) {
1275 QModelIndex idx = indexList.at(i);
1276 QVERIFY2(selection->isSelected(idx) == selectedList.contains(idx),
1277 QString("isSelected(index: %1, %2) does not match selectedIndexes()")
1278 .arg(idx.row())
1279 .arg(idx.column()).toLatin1());
1280 }
1281
1282 //for now we assume Rows/Columns flag is the same for all commands, therefore we just check lastCommand
1283 // test that isRowSelected agrees
1284 if (lastCommand & QItemSelectionModel::Rows) {
1285 for (int i=0; i<selectedList.count(); ++i)
1286 QVERIFY2(selection->isRowSelected(selectedList.at(i).row(),
1287 model->parent(selectedList.at(i))),
1288 QString("isRowSelected(row: %1) does not match selectedIndexes()")
1289 .arg(selectedList.at(i).row()).toLatin1());
1290 }
1291
1292 // test that isColumnSelected agrees
1293 if (lastCommand & QItemSelectionModel::Columns) {
1294 for (int i=0; i<selectedList.count(); ++i)
1295 QVERIFY2(selection->isColumnSelected(selectedList.at(i).column(),
1296 model->parent(selectedList.at(i))),
1297 QString("isColumnSelected(column: %1) does not match selectedIndexes()")
1298 .arg(selectedList.at(i).column()).toLatin1());
1299 }
1300}
1301
1302void tst_QItemSelectionModel::persistentselections_data()
1303{
1304 QTest::addColumn<PairList>(name: "indexList");
1305 QTest::addColumn<IntList>(name: "commandList");
1306 QTest::addColumn<IntList>(name: "insertRows"); // start, count
1307 QTest::addColumn<IntList>(name: "insertColumns"); // start, count
1308 QTest::addColumn<IntList>(name: "deleteRows"); // start, count
1309 QTest::addColumn<IntList>(name: "deleteColumns"); // start, count
1310 QTest::addColumn<PairList>(name: "expectedList");
1311
1312 PairList index, expected;
1313 IntList command, insertRows, insertColumns, deleteRows, deleteColumns;
1314
1315
1316 index.clear(); expected.clear(); command.clear();
1317 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1318 index << IntPair(0, 0);
1319 command << QItemSelectionModel::ClearAndSelect;
1320 deleteRows << 4 << 1;
1321 expected << IntPair(0, 0);
1322 QTest::newRow(dataTag: "ClearAndSelect (0, 0). Delete last row.")
1323 << index << command
1324 << insertRows << insertColumns << deleteRows << deleteColumns
1325 << expected;
1326
1327 index.clear(); expected.clear(); command.clear();
1328 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1329 index << IntPair(0, 0);
1330 command << QItemSelectionModel::ClearAndSelect;
1331 deleteRows << 0 << 1;
1332 QTest::newRow(dataTag: "ClearAndSelect (0, 0). Delete first row.")
1333 << index << command
1334 << insertRows << insertColumns << deleteRows << deleteColumns
1335 << expected;
1336
1337 index.clear(); expected.clear(); command.clear();
1338 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1339 index << IntPair(1, 0);
1340 command << QItemSelectionModel::ClearAndSelect;
1341 deleteRows << 0 << 1;
1342 expected << IntPair(0, 0);
1343 QTest::newRow(dataTag: "ClearAndSelect (1, 0). Delete first row.")
1344 << index << command
1345 << insertRows << insertColumns << deleteRows << deleteColumns
1346 << expected;
1347
1348 index.clear(); expected.clear(); command.clear();
1349 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1350 index << IntPair(0, 0);
1351 command << QItemSelectionModel::ClearAndSelect;
1352 insertRows << 5 << 1;
1353 expected << IntPair(0, 0);
1354 QTest::newRow(dataTag: "ClearAndSelect (0, 0). Append row.")
1355 << index << command
1356 << insertRows << insertColumns << deleteRows << deleteColumns
1357 << expected;
1358
1359 index.clear(); expected.clear(); command.clear();
1360 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1361 index << IntPair(0, 0);
1362 command << QItemSelectionModel::ClearAndSelect;
1363 insertRows << 0 << 1;
1364 expected << IntPair(1, 0);
1365 QTest::newRow(dataTag: "ClearAndSelect (0, 0). Insert before first row.")
1366 << index << command
1367 << insertRows << insertColumns << deleteRows << deleteColumns
1368 << expected;
1369
1370 index.clear(); expected.clear(); command.clear();
1371 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1372 index << IntPair(0, 0)
1373 << IntPair(4, 0);
1374 command << QItemSelectionModel::ClearAndSelect;
1375 insertRows << 5 << 1;
1376 expected << IntPair(0, 0)
1377 << IntPair(1, 0)
1378 << IntPair(2, 0)
1379 << IntPair(3, 0)
1380 << IntPair(4, 0);
1381 QTest::newRow(dataTag: "ClearAndSelect (0, 0) to (4, 0). Append row.")
1382 << index << command
1383 << insertRows << insertColumns << deleteRows << deleteColumns
1384 << expected;
1385
1386 index.clear(); expected.clear(); command.clear();
1387 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1388 index << IntPair(0, 0)
1389 << IntPair(4, 0);
1390 command << QItemSelectionModel::ClearAndSelect;
1391 insertRows << 0 << 1;
1392 expected << IntPair(1, 0)
1393 << IntPair(2, 0)
1394 << IntPair(3, 0)
1395 << IntPair(4, 0)
1396 << IntPair(5, 0);
1397 QTest::newRow(dataTag: "ClearAndSelect (0, 0) to (4, 0). Insert before first row.")
1398 << index << command
1399 << insertRows << insertColumns << deleteRows << deleteColumns
1400 << expected;
1401
1402 index.clear(); expected.clear(); command.clear();
1403 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1404 index << IntPair(0, 0)
1405 << IntPair(4, 0);
1406 command << QItemSelectionModel::ClearAndSelect;
1407 deleteRows << 0 << 1;
1408 expected << IntPair(0, 0)
1409 << IntPair(1, 0)
1410 << IntPair(2, 0)
1411 << IntPair(3, 0);
1412 QTest::newRow(dataTag: "ClearAndSelect (0, 0) to (4, 0). Delete first row.")
1413 << index << command
1414 << insertRows << insertColumns << deleteRows << deleteColumns
1415 << expected;
1416
1417 index.clear(); expected.clear(); command.clear();
1418 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1419 index << IntPair(0, 0)
1420 << IntPair(4, 0);
1421 command << QItemSelectionModel::ClearAndSelect;
1422 deleteRows << 4 << 1;
1423 expected << IntPair(0, 0)
1424 << IntPair(1, 0)
1425 << IntPair(2, 0)
1426 << IntPair(3, 0);
1427 QTest::newRow(dataTag: "ClearAndSelect (0, 0) to (4, 0). Delete last row.")
1428 << index << command
1429 << insertRows << insertColumns << deleteRows << deleteColumns
1430 << expected;
1431
1432 index.clear(); expected.clear(); command.clear();
1433 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1434 index << IntPair(0, 0)
1435 << IntPair(4, 0);
1436 command << QItemSelectionModel::ClearAndSelect;
1437 deleteRows << 1 << 3;
1438 expected << IntPair(0, 0)
1439 << IntPair(1, 0);
1440 QTest::newRow(dataTag: "ClearAndSelect (0, 0) to (4, 0). Deleting all but first and last row.")
1441 << index << command
1442 << insertRows << insertColumns << deleteRows << deleteColumns
1443 << expected;
1444
1445 index.clear(); expected.clear(); command.clear();
1446 insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
1447 index << IntPair(0, 0)
1448 << IntPair(4, 0);
1449 command << QItemSelectionModel::ClearAndSelect;
1450 insertRows << 1 << 1;
1451 expected << IntPair(0, 0)
1452 // the inserted row should not be selected
1453 << IntPair(2, 0)
1454 << IntPair(3, 0)
1455 << IntPair(4, 0)
1456 << IntPair(5, 0);
1457 QTest::newRow(dataTag: "ClearAndSelect (0, 0) to (4, 0). Insert after first row.")
1458 << index << command
1459 << insertRows << insertColumns << deleteRows << deleteColumns
1460 << expected;
1461}
1462
1463void tst_QItemSelectionModel::persistentselections()
1464{
1465 QFETCH(PairList, indexList);
1466 QFETCH(IntList, commandList);
1467 QFETCH(IntList, insertRows);
1468 QFETCH(IntList, insertColumns);
1469 QFETCH(IntList, deleteRows);
1470 QFETCH(IntList, deleteColumns);
1471 QFETCH(const PairList, expectedList);
1472
1473 // make sure the model is sane (5x5)
1474 QCOMPARE(model->rowCount(QModelIndex()), 5);
1475 QCOMPARE(model->columnCount(QModelIndex()), 5);
1476
1477 // do selections
1478 for (int i=0; i<commandList.count(); ++i) {
1479 if (indexList.count() == commandList.count()) {
1480 QModelIndex index = model->index(row: indexList.at(i).first,
1481 column: indexList.at(i).second,
1482 parent: QModelIndex());
1483 selection->select(index, command: (QItemSelectionModel::SelectionFlags)commandList.at(i));
1484 } else {
1485 QModelIndex tl = model->index(row: indexList.at(i: 2*i).first,
1486 column: indexList.at(i: 2*i).second,
1487 parent: QModelIndex());
1488 QModelIndex br = model->index(row: indexList.at(i: 2*i+1).first,
1489 column: indexList.at(i: 2*i+1).second,
1490 parent: QModelIndex());
1491 selection->select(selection: QItemSelection(tl, br),
1492 command: (QItemSelectionModel::SelectionFlags)commandList.at(i));
1493 }
1494 }
1495 // test that we have selected items
1496 QVERIFY(!selection->selectedIndexes().isEmpty());
1497 QVERIFY(selection->hasSelection());
1498
1499 // insert/delete row and/or columns
1500 if (insertRows.count() > 1)
1501 model->insertRows(row: insertRows.at(i: 0), count: insertRows.at(i: 1), parent: QModelIndex());
1502 if (insertColumns.count() > 1)
1503 model->insertColumns(column: insertColumns.at(i: 0), count: insertColumns.at(i: 1), parent: QModelIndex());
1504 if (deleteRows.count() > 1)
1505 model->removeRows(row: deleteRows.at(i: 0), count: deleteRows.at(i: 1), parent: QModelIndex());
1506 if (deleteColumns.count() > 1)
1507 model->removeColumns(column: deleteColumns.at(i: 0), count: deleteColumns.at(i: 1), parent: QModelIndex());
1508
1509 // check that the selected items are the correct number and indexes
1510 QModelIndexList selectedList = selection->selectedIndexes();
1511 QCOMPARE(selectedList.count(), expectedList.count());
1512 for (const auto &pair : expectedList) {
1513 QModelIndex index = model->index(row: pair.first, column: pair.second, parent: QModelIndex());
1514 QVERIFY(selectedList.contains(index));
1515 }
1516}
1517
1518// "make reset public"-model
1519class MyStandardItemModel: public QStandardItemModel
1520{
1521 Q_OBJECT
1522public:
1523 inline MyStandardItemModel(int i1, int i2): QStandardItemModel(i1, i2) {}
1524 inline void reset() { beginResetModel(); endResetModel(); }
1525};
1526
1527void tst_QItemSelectionModel::resetModel()
1528{
1529 MyStandardItemModel model(20, 20);
1530 QItemSelectionModel *selectionModel = new QItemSelectionModel(&model);
1531
1532 QSignalSpy spy(selectionModel, &QItemSelectionModel::selectionChanged);
1533 QVERIFY(spy.isValid());
1534
1535 selectionModel->select(selection: QItemSelection(model.index(row: 0, column: 0), model.index(row: 5, column: 5)), command: QItemSelectionModel::Select);
1536
1537 QCOMPARE(spy.count(), 1);
1538
1539 model.reset();
1540
1541 QVERIFY(selectionModel->selection().isEmpty());
1542 QVERIFY(!selectionModel->hasSelection());
1543
1544 selectionModel->select(selection: QItemSelection(model.index(row: 0, column: 0), model.index(row: 5, column: 5)), command: QItemSelectionModel::Select);
1545
1546 QCOMPARE(spy.count(), 2);
1547 QCOMPARE(spy.at(1).count(), 2);
1548 // make sure we don't get an "old selection"
1549 QCOMPARE(spy.at(1).at(1).userType(), qMetaTypeId<QItemSelection>());
1550 QVERIFY(qvariant_cast<QItemSelection>(spy.at(1).at(1)).isEmpty());
1551}
1552
1553void tst_QItemSelectionModel::removeRows_data()
1554{
1555 QTest::addColumn<int>(name: "rowCount");
1556 QTest::addColumn<int>(name: "columnCount");
1557
1558 QTest::addColumn<int>(name: "selectTop");
1559 QTest::addColumn<int>(name: "selectLeft");
1560 QTest::addColumn<int>(name: "selectBottom");
1561 QTest::addColumn<int>(name: "selectRight");
1562
1563 QTest::addColumn<int>(name: "removeTop");
1564 QTest::addColumn<int>(name: "removeBottom");
1565
1566 QTest::addColumn<int>(name: "expectedTop");
1567 QTest::addColumn<int>(name: "expectedLeft");
1568 QTest::addColumn<int>(name: "expectedBottom");
1569 QTest::addColumn<int>(name: "expectedRight");
1570
1571 QTest::newRow(dataTag: "4x4 <0,1><1,1>")
1572 << 4 << 4
1573 << 0 << 1 << 1 << 1
1574 << 0 << 0
1575 << 0 << 1 << 0 << 1;
1576}
1577
1578void tst_QItemSelectionModel::removeRows()
1579{
1580 QFETCH(int, rowCount);
1581 QFETCH(int, columnCount);
1582 QFETCH(int, selectTop);
1583 QFETCH(int, selectLeft);
1584 QFETCH(int, selectBottom);
1585 QFETCH(int, selectRight);
1586 QFETCH(int, removeTop);
1587 QFETCH(int, removeBottom);
1588 QFETCH(int, expectedTop);
1589 QFETCH(int, expectedLeft);
1590 QFETCH(int, expectedBottom);
1591 QFETCH(int, expectedRight);
1592
1593 MyStandardItemModel model(rowCount, columnCount);
1594 QItemSelectionModel selections(&model);
1595 QSignalSpy spy(&selections, &QItemSelectionModel::selectionChanged);
1596 QVERIFY(spy.isValid());
1597
1598 QModelIndex tl = model.index(row: selectTop, column: selectLeft);
1599 QModelIndex br = model.index(row: selectBottom, column: selectRight);
1600 selections.select(selection: QItemSelection(tl, br), command: QItemSelectionModel::ClearAndSelect);
1601
1602 QCOMPARE(spy.count(), 1);
1603 QVERIFY(selections.isSelected(tl));
1604 QVERIFY(selections.isSelected(br));
1605 QVERIFY(selections.hasSelection());
1606
1607 model.removeRows(row: removeTop, count: removeBottom - removeTop + 1);
1608
1609 QCOMPARE(spy.count(), 2);
1610 tl = model.index(row: expectedTop, column: expectedLeft);
1611 br = model.index(row: expectedBottom, column: expectedRight);
1612 QVERIFY(selections.isSelected(tl));
1613 QVERIFY(selections.isSelected(br));
1614}
1615
1616void tst_QItemSelectionModel::removeColumns_data()
1617{
1618 QTest::addColumn<int>(name: "rowCount");
1619 QTest::addColumn<int>(name: "columnCount");
1620
1621 QTest::addColumn<int>(name: "selectTop");
1622 QTest::addColumn<int>(name: "selectLeft");
1623 QTest::addColumn<int>(name: "selectBottom");
1624 QTest::addColumn<int>(name: "selectRight");
1625
1626 QTest::addColumn<int>(name: "removeLeft");
1627 QTest::addColumn<int>(name: "removeRight");
1628
1629 QTest::addColumn<int>(name: "expectedTop");
1630 QTest::addColumn<int>(name: "expectedLeft");
1631 QTest::addColumn<int>(name: "expectedBottom");
1632 QTest::addColumn<int>(name: "expectedRight");
1633
1634 QTest::newRow(dataTag: "4x4 <0,1><1,1>")
1635 << 4 << 4
1636 << 1 << 0 << 1 << 1
1637 << 0 << 0
1638 << 1 << 0 << 1 << 0;
1639}
1640
1641void tst_QItemSelectionModel::removeColumns()
1642{
1643 QFETCH(int, rowCount);
1644 QFETCH(int, columnCount);
1645 QFETCH(int, selectTop);
1646 QFETCH(int, selectLeft);
1647 QFETCH(int, selectBottom);
1648 QFETCH(int, selectRight);
1649 QFETCH(int, removeLeft);
1650 QFETCH(int, removeRight);
1651 QFETCH(int, expectedTop);
1652 QFETCH(int, expectedLeft);
1653 QFETCH(int, expectedBottom);
1654 QFETCH(int, expectedRight);
1655
1656 MyStandardItemModel model(rowCount, columnCount);
1657 QItemSelectionModel selections(&model);
1658 QSignalSpy spy(&selections, &QItemSelectionModel::selectionChanged);
1659 QVERIFY(spy.isValid());
1660
1661 QModelIndex tl = model.index(row: selectTop, column: selectLeft);
1662 QModelIndex br = model.index(row: selectBottom, column: selectRight);
1663 selections.select(selection: QItemSelection(tl, br), command: QItemSelectionModel::ClearAndSelect);
1664
1665 QCOMPARE(spy.count(), 1);
1666 QVERIFY(selections.isSelected(tl));
1667 QVERIFY(selections.isSelected(br));
1668 QVERIFY(selections.hasSelection());
1669
1670 model.removeColumns(column: removeLeft, count: removeRight - removeLeft + 1);
1671
1672 QCOMPARE(spy.count(), 2);
1673 tl = model.index(row: expectedTop, column: expectedLeft);
1674 br = model.index(row: expectedBottom, column: expectedRight);
1675 QVERIFY(selections.isSelected(tl));
1676 QVERIFY(selections.isSelected(br));
1677}
1678
1679typedef QList<IntList> IntListList;
1680typedef QPair<IntPair, IntPair> IntPairPair;
1681typedef QList<IntPairPair> IntPairPairList;
1682
1683void tst_QItemSelectionModel::modelLayoutChanged_data()
1684{
1685 QTest::addColumn<IntListList>(name: "items");
1686 QTest::addColumn<IntPairPairList>(name: "initialSelectedRanges");
1687 QTest::addColumn<Qt::SortOrder>(name: "sortOrder");
1688 QTest::addColumn<int>(name: "sortColumn");
1689 QTest::addColumn<IntPairPairList>(name: "expectedSelectedRanges");
1690
1691 QTest::newRow(dataTag: "everything selected, then row order reversed")
1692 << (IntListList()
1693 << (IntList() << 0 << 1 << 2 << 3)
1694 << (IntList() << 3 << 2 << 1 << 0))
1695 << (IntPairPairList()
1696 << IntPairPair(IntPair(0, 0), IntPair(3, 1)))
1697 << Qt::DescendingOrder
1698 << 0
1699 << (IntPairPairList()
1700 << IntPairPair(IntPair(0, 0), IntPair(3, 1)));
1701 QTest::newRow(dataTag: "first two rows selected, then row order reversed")
1702 << (IntListList()
1703 << (IntList() << 0 << 1 << 2 << 3)
1704 << (IntList() << 3 << 2 << 1 << 0))
1705 << (IntPairPairList()
1706 << IntPairPair(IntPair(0, 0), IntPair(1, 1)))
1707 << Qt::DescendingOrder
1708 << 0
1709 << (IntPairPairList()
1710 << IntPairPair(IntPair(2, 0), IntPair(3, 1)));
1711 QTest::newRow(dataTag: "middle two rows selected, then row order reversed")
1712 << (IntListList()
1713 << (IntList() << 0 << 1 << 2 << 3)
1714 << (IntList() << 3 << 2 << 1 << 0))
1715 << (IntPairPairList()
1716 << IntPairPair(IntPair(1, 0), IntPair(2, 1)))
1717 << Qt::DescendingOrder
1718 << 0
1719 << (IntPairPairList()
1720 << IntPairPair(IntPair(1, 0), IntPair(2, 1)));
1721 QTest::newRow(dataTag: "two ranges")
1722 << (IntListList()
1723 << (IntList() << 2 << 0 << 3 << 1)
1724 << (IntList() << 2 << 0 << 3 << 1))
1725 << (IntPairPairList()
1726 << IntPairPair(IntPair(1, 0), IntPair(1, 1))
1727 << IntPairPair(IntPair(3, 0), IntPair(3, 1)))
1728 << Qt::AscendingOrder
1729 << 0
1730 << (IntPairPairList()
1731 << IntPairPair(IntPair(0, 0), IntPair(0, 1))
1732 << IntPairPair(IntPair(1, 0), IntPair(1, 1)));
1733}
1734
1735void tst_QItemSelectionModel::modelLayoutChanged()
1736{
1737 QFETCH(IntListList, items);
1738 QFETCH(const IntPairPairList, initialSelectedRanges);
1739 QFETCH(Qt::SortOrder, sortOrder);
1740 QFETCH(int, sortColumn);
1741 QFETCH(IntPairPairList, expectedSelectedRanges);
1742
1743 MyStandardItemModel model(items.at(i: 0).count(), items.count());
1744 // initialize model data
1745 for (int i = 0; i < model.rowCount(); ++i) {
1746 for (int j = 0; j < model.columnCount(); ++j) {
1747 QModelIndex index = model.index(row: i, column: j);
1748 model.setData(index, value: items.at(i: j).at(i), role: Qt::DisplayRole);
1749 }
1750 }
1751
1752 // select initial ranges
1753 QItemSelectionModel selectionModel(&model);
1754 for (const auto &range : initialSelectedRanges) {
1755 const auto &tl = range.first;
1756 const auto &br = range.second;
1757 QItemSelection selection(
1758 model.index(row: tl.first, column: tl.second),
1759 model.index(row: br.first, column: br.second));
1760 selectionModel.select(selection, command: QItemSelectionModel::Select);
1761 }
1762
1763 // sort the model
1764 model.sort(column: sortColumn, order: sortOrder);
1765
1766 // verify that selection is as expected
1767 QItemSelection selection = selectionModel.selection();
1768 QCOMPARE(selection.count(), expectedSelectedRanges.count());
1769 QCOMPARE(selectionModel.hasSelection(), !expectedSelectedRanges.isEmpty());
1770
1771 for (int i = 0; i < expectedSelectedRanges.count(); ++i) {
1772 IntPairPair expectedRange = expectedSelectedRanges.at(i);
1773 IntPair expectedTl = expectedRange.first;
1774 IntPair expectedBr = expectedRange.second;
1775 QItemSelectionRange actualRange = selection.at(i);
1776 QModelIndex actualTl = actualRange.topLeft();
1777 QModelIndex actualBr = actualRange.bottomRight();
1778 QCOMPARE(actualTl.row(), expectedTl.first);
1779 QCOMPARE(actualTl.column(), expectedTl.second);
1780 QCOMPARE(actualBr.row(), expectedBr.first);
1781 QCOMPARE(actualBr.column(), expectedBr.second);
1782 }
1783}
1784
1785void tst_QItemSelectionModel::selectedRows_data()
1786{
1787 QTest::addColumn<int>(name: "rowCount");
1788 QTest::addColumn<int>(name: "columnCount");
1789 QTest::addColumn<int>(name: "column");
1790 QTest::addColumn<IntList>(name: "selectRows");
1791 QTest::addColumn<IntList>(name: "expectedRows");
1792 QTest::addColumn<IntList>(name: "unexpectedRows");
1793
1794 QTest::newRow(dataTag: "10x10, first row")
1795 << 10 << 10 << 0
1796 << (IntList() << 0)
1797 << (IntList() << 0)
1798 << (IntList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9);
1799
1800 QTest::newRow(dataTag: "10x10, first 4 rows")
1801 << 10 << 10 << 0
1802 << (IntList() << 0 << 1 << 2 << 3)
1803 << (IntList() << 0 << 1 << 2 << 3)
1804 << (IntList() << 4 << 5 << 6 << 7 << 8 << 9);
1805
1806 QTest::newRow(dataTag: "10x10, last 4 rows")
1807 << 10 << 10 << 0
1808 << (IntList() << 6 << 7 << 8 << 9)
1809 << (IntList() << 6 << 7 << 8 << 9)
1810 << (IntList() << 0 << 1 << 2 << 3 << 4 << 6);
1811}
1812
1813void tst_QItemSelectionModel::selectedRows()
1814{
1815 QFETCH(int, rowCount);
1816 QFETCH(int, columnCount);
1817 QFETCH(int, column);
1818 QFETCH(IntList, selectRows);
1819 QFETCH(IntList, expectedRows);
1820 QFETCH(IntList, unexpectedRows);
1821
1822 MyStandardItemModel model(rowCount, columnCount);
1823 QItemSelectionModel selectionModel(&model);
1824
1825 for (int i = 0; i < selectRows.count(); ++i)
1826 selectionModel.select(index: model.index(row: selectRows.at(i), column: 0),
1827 command: QItemSelectionModel::Select
1828 |QItemSelectionModel::Rows);
1829
1830 for (int j = 0; j < selectRows.count(); ++j)
1831 QVERIFY(selectionModel.isRowSelected(expectedRows.at(j), QModelIndex()));
1832
1833 for (int k = 0; k < selectRows.count(); ++k)
1834 QVERIFY(!selectionModel.isRowSelected(unexpectedRows.at(k), QModelIndex()));
1835
1836 QModelIndexList selectedRowIndexes = selectionModel.selectedRows(column);
1837 QCOMPARE(selectedRowIndexes.count(), expectedRows.count());
1838 std::sort(first: selectedRowIndexes.begin(), last: selectedRowIndexes.end());
1839 for (int l = 0; l < selectedRowIndexes.count(); ++l) {
1840 QCOMPARE(selectedRowIndexes.at(l).row(), expectedRows.at(l));
1841 QCOMPARE(selectedRowIndexes.at(l).column(), column);
1842 }
1843}
1844
1845void tst_QItemSelectionModel::selectedColumns_data()
1846{
1847 QTest::addColumn<int>(name: "rowCount");
1848 QTest::addColumn<int>(name: "columnCount");
1849 QTest::addColumn<int>(name: "row");
1850 QTest::addColumn<IntList>(name: "selectColumns");
1851 QTest::addColumn<IntList>(name: "expectedColumns");
1852 QTest::addColumn<IntList>(name: "unexpectedColumns");
1853
1854 QTest::newRow(dataTag: "10x10, first columns")
1855 << 10 << 10 << 0
1856 << (IntList() << 0)
1857 << (IntList() << 0)
1858 << (IntList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9);
1859
1860 QTest::newRow(dataTag: "10x10, first 4 columns")
1861 << 10 << 10 << 0
1862 << (IntList() << 0 << 1 << 2 << 3)
1863 << (IntList() << 0 << 1 << 2 << 3)
1864 << (IntList() << 4 << 5 << 6 << 7 << 8 << 9);
1865
1866 QTest::newRow(dataTag: "10x10, last 4 columns")
1867 << 10 << 10 << 0
1868 << (IntList() << 6 << 7 << 8 << 9)
1869 << (IntList() << 6 << 7 << 8 << 9)
1870 << (IntList() << 0 << 1 << 2 << 3 << 4 << 6);
1871}
1872
1873void tst_QItemSelectionModel::selectedColumns()
1874{
1875 QFETCH(int, rowCount);
1876 QFETCH(int, columnCount);
1877 QFETCH(int, row);
1878 QFETCH(IntList, selectColumns);
1879 QFETCH(IntList, expectedColumns);
1880 QFETCH(IntList, unexpectedColumns);
1881
1882 MyStandardItemModel model(rowCount, columnCount);
1883 QItemSelectionModel selectionModel(&model);
1884
1885 for (int i = 0; i < selectColumns.count(); ++i)
1886 selectionModel.select(index: model.index(row: 0, column: selectColumns.at(i)),
1887 command: QItemSelectionModel::Select
1888 |QItemSelectionModel::Columns);
1889
1890 for (int j = 0; j < selectColumns.count(); ++j)
1891 QVERIFY(selectionModel.isColumnSelected(expectedColumns.at(j), QModelIndex()));
1892
1893 for (int k = 0; k < selectColumns.count(); ++k)
1894 QVERIFY(!selectionModel.isColumnSelected(unexpectedColumns.at(k), QModelIndex()));
1895
1896 QModelIndexList selectedColumnIndexes = selectionModel.selectedColumns(row);
1897 QCOMPARE(selectedColumnIndexes.count(), expectedColumns.count());
1898 std::sort(first: selectedColumnIndexes.begin(), last: selectedColumnIndexes.end());
1899 for (int l = 0; l < selectedColumnIndexes.count(); ++l) {
1900 QCOMPARE(selectedColumnIndexes.at(l).column(), expectedColumns.at(l));
1901 QCOMPARE(selectedColumnIndexes.at(l).row(), row);
1902 }
1903}
1904
1905void tst_QItemSelectionModel::setCurrentIndex()
1906{
1907 // Build up a simple tree
1908 QScopedPointer<QStandardItemModel> treemodel(new QStandardItemModel(0, 1));
1909 treemodel->insertRow(arow: 0, aitem: new QStandardItem(1));
1910 treemodel->insertRow(arow: 1, aitem: new QStandardItem(2));
1911
1912 QItemSelectionModel selectionModel(treemodel.data());
1913 selectionModel.setCurrentIndex(
1914 index: treemodel->index(row: 0, column: 0, parent: treemodel->index(row: 0, column: 0)),
1915 command: QItemSelectionModel::SelectCurrent);
1916
1917 QSignalSpy currentSpy(&selectionModel, &QItemSelectionModel::currentChanged);
1918 QSignalSpy rowSpy(&selectionModel, &QItemSelectionModel::currentRowChanged);
1919 QSignalSpy columnSpy(&selectionModel, &QItemSelectionModel::currentColumnChanged);
1920
1921 QVERIFY(currentSpy.isValid());
1922 QVERIFY(rowSpy.isValid());
1923 QVERIFY(columnSpy.isValid());
1924
1925 // Select the same row and column indexes, but with a different parent
1926 selectionModel.setCurrentIndex(
1927 index: treemodel->index(row: 0, column: 0, parent: treemodel->index(row: 1, column: 0)),
1928 command: QItemSelectionModel::SelectCurrent);
1929
1930 QCOMPARE(currentSpy.count(), 1);
1931 QCOMPARE(rowSpy.count(), 1);
1932 QCOMPARE(columnSpy.count(), 1);
1933
1934 // Select another row in the same parent
1935 selectionModel.setCurrentIndex(
1936 index: treemodel->index(row: 1, column: 0, parent: treemodel->index(row: 1, column: 0)),
1937 command: QItemSelectionModel::SelectCurrent);
1938
1939 QCOMPARE(currentSpy.count(), 2);
1940 QCOMPARE(rowSpy.count(), 2);
1941 QCOMPARE(columnSpy.count(), 1);
1942}
1943
1944void tst_QItemSelectionModel::splitOnInsert()
1945{
1946 QStandardItemModel model(4, 1);
1947 QItemSelectionModel selectionModel(&model);
1948 selectionModel.select(index: model.index(row: 2, column: 0), command: QItemSelectionModel::Select);
1949 model.insertRow(arow: 2);
1950 model.removeRow(arow: 3);
1951 QVERIFY(!selectionModel.isSelected(model.index(1, 0)));
1952}
1953
1954void tst_QItemSelectionModel::rowIntersectsSelection1()
1955{
1956 QStandardItemModel model;
1957 model.setItem(row: 0, column: 0, item: new QStandardItem("foo"));
1958 QItemSelectionModel selectionModel(&model);
1959
1960 QModelIndex index = model.index(row: 0, column: 0, parent: QModelIndex());
1961
1962 selectionModel.select(index, command: QItemSelectionModel::Select);
1963 QVERIFY(selectionModel.rowIntersectsSelection(0, QModelIndex()));
1964 QVERIFY(selectionModel.columnIntersectsSelection(0, QModelIndex()));
1965
1966 selectionModel.select(index, command: QItemSelectionModel::Deselect);
1967 QVERIFY(!selectionModel.rowIntersectsSelection(0, QModelIndex()));
1968 QVERIFY(!selectionModel.columnIntersectsSelection(0, QModelIndex()));
1969
1970 selectionModel.select(index, command: QItemSelectionModel::Toggle);
1971 QVERIFY(selectionModel.rowIntersectsSelection(0, QModelIndex()));
1972 QVERIFY(selectionModel.columnIntersectsSelection(0, QModelIndex()));
1973
1974 selectionModel.select(index, command: QItemSelectionModel::Toggle);
1975 QVERIFY(!selectionModel.rowIntersectsSelection(0, QModelIndex()));
1976 QVERIFY(!selectionModel.columnIntersectsSelection(0, QModelIndex()));
1977}
1978
1979void tst_QItemSelectionModel::rowIntersectsSelection2()
1980{
1981 QStandardItemModel m;
1982 for (int i=0; i<8; ++i) {
1983 const QString text = QLatin1String("Item number ") + QString::number(i);
1984 for (int j=0; j<8; ++j) {
1985 QStandardItem *item = new QStandardItem(text);
1986 if ((i % 2 == 0 && j == 0) ||
1987 (j % 2 == 0 && i == 0) ||
1988 j == 5 || i == 5 ) {
1989 item->setEnabled(false);
1990 //item->setSelectable(false);
1991 }
1992 m.setItem(row: i, column: j, item);
1993 }
1994 }
1995
1996 QItemSelectionModel selected(&m);
1997 //nothing is selected
1998 QVERIFY(!selected.rowIntersectsSelection(0, QModelIndex()));
1999 QVERIFY(!selected.rowIntersectsSelection(2, QModelIndex()));
2000 QVERIFY(!selected.rowIntersectsSelection(3, QModelIndex()));
2001 QVERIFY(!selected.rowIntersectsSelection(5, QModelIndex()));
2002 QVERIFY(!selected.columnIntersectsSelection(0, QModelIndex()));
2003 QVERIFY(!selected.columnIntersectsSelection(2, QModelIndex()));
2004 QVERIFY(!selected.columnIntersectsSelection(3, QModelIndex()));
2005 QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex()));
2006 selected.select(index: m.index(row: 2, column: 0), command: QItemSelectionModel::Select | QItemSelectionModel::Rows);
2007 QVERIFY(!selected.rowIntersectsSelection(0, QModelIndex()));
2008 QVERIFY( selected.rowIntersectsSelection(2, QModelIndex()));
2009 QVERIFY(!selected.rowIntersectsSelection(3, QModelIndex()));
2010 QVERIFY(!selected.rowIntersectsSelection(5, QModelIndex()));
2011 QVERIFY(!selected.columnIntersectsSelection(0, QModelIndex()));
2012 QVERIFY( selected.columnIntersectsSelection(2, QModelIndex()));
2013 QVERIFY( selected.columnIntersectsSelection(3, QModelIndex()));
2014 QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex()));
2015 selected.select(index: m.index(row: 0, column: 5), command: QItemSelectionModel::Select | QItemSelectionModel::Columns);
2016 QVERIFY(!selected.rowIntersectsSelection(0, QModelIndex()));
2017 QVERIFY( selected.rowIntersectsSelection(2, QModelIndex()));
2018 QVERIFY(!selected.rowIntersectsSelection(3, QModelIndex()));
2019 QVERIFY(!selected.rowIntersectsSelection(5, QModelIndex()));
2020 QVERIFY(!selected.columnIntersectsSelection(0, QModelIndex()));
2021 QVERIFY( selected.columnIntersectsSelection(2, QModelIndex()));
2022 QVERIFY( selected.columnIntersectsSelection(3, QModelIndex()));
2023 QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex()));
2024}
2025
2026void tst_QItemSelectionModel::rowIntersectsSelection3()
2027{
2028 QStandardItemModel model;
2029 QStandardItem *parentItem = model.invisibleRootItem();
2030 for (int i = 0; i < 4; ++i) {
2031 QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
2032 parentItem->appendRow(aitem: item);
2033 parentItem = item;
2034 }
2035
2036 QItemSelectionModel selectionModel(&model);
2037
2038 selectionModel.select(index: model.index(row: 0, column: 0, parent: model.index(row: 0, column: 0)), command: QItemSelectionModel::Select);
2039
2040 QModelIndex parent;
2041 QVERIFY(!selectionModel.rowIntersectsSelection(0, parent));
2042 QVERIFY(!selectionModel.columnIntersectsSelection(0, parent));
2043 parent = model.index(row: 0, column: 0, parent);
2044 QVERIFY(selectionModel.rowIntersectsSelection(0, parent));
2045 QVERIFY(selectionModel.columnIntersectsSelection(0, parent));
2046 parent = model.index(row: 0, column: 0, parent);
2047 QVERIFY(!selectionModel.rowIntersectsSelection(0, parent));
2048 QVERIFY(!selectionModel.columnIntersectsSelection(0, parent));
2049 parent = model.index(row: 0, column: 0, parent);
2050 QVERIFY(!selectionModel.rowIntersectsSelection(0, parent));
2051 QVERIFY(!selectionModel.columnIntersectsSelection(0, parent));
2052}
2053
2054void tst_QItemSelectionModel::unselectable()
2055{
2056 QStandardItemModel model;
2057 QStandardItem *parentItem = model.invisibleRootItem();
2058
2059 for (int i = 0; i < 10; ++i) {
2060 QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
2061 parentItem->appendRow(aitem: item);
2062 }
2063 QItemSelectionModel selectionModel(&model);
2064 selectionModel.select(selection: QItemSelection(model.index(row: 0, column: 0), model.index(row: 9, column: 0)), command: QItemSelectionModel::Select);
2065 QCOMPARE(selectionModel.selectedIndexes().count(), 10);
2066 QCOMPARE(selectionModel.selectedRows().count(), 10);
2067 for (int j = 0; j < 10; ++j)
2068 model.item(row: j)->setFlags({ });
2069 QCOMPARE(selectionModel.selectedIndexes().count(), 0);
2070 QCOMPARE(selectionModel.selectedRows().count(), 0);
2071}
2072
2073void tst_QItemSelectionModel::selectedIndexes()
2074{
2075 QStandardItemModel model(2, 2);
2076 QItemSelectionModel selectionModel(&model);
2077 QItemSelection selection;
2078 selection.append(t: QItemSelectionRange(model.index(row: 0,column: 0)));
2079 selection.append(t: QItemSelectionRange(model.index(row: 0,column: 1)));
2080
2081 //we select the 1st row
2082 selectionModel.select(selection, command: QItemSelectionModel::Rows | QItemSelectionModel::Select);
2083
2084 QCOMPARE(selectionModel.selectedRows().count(), 1);
2085 QCOMPARE(selectionModel.selectedIndexes().count(), model.columnCount());
2086}
2087
2088
2089class QtTestTableModel: public QAbstractTableModel
2090{
2091 Q_OBJECT
2092public:
2093 QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = 0)
2094 : QAbstractTableModel(parent)
2095 , row_count(rows)
2096 , column_count(columns)
2097 {
2098 }
2099
2100 int rowCount(const QModelIndex& = QModelIndex()) const { return row_count; }
2101 int columnCount(const QModelIndex& = QModelIndex()) const { return column_count; }
2102 bool isEditable(const QModelIndex &) const { return true; }
2103
2104 QVariant data(const QModelIndex &idx, int role) const
2105 {
2106 if (role == Qt::DisplayRole || role == Qt::EditRole)
2107 return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',')
2108 + QString::number(idx.column()) + QLatin1Char(']');
2109 return QVariant();
2110 }
2111
2112 int row_count;
2113 int column_count;
2114 friend class tst_QItemSelectionModel;
2115};
2116
2117
2118void tst_QItemSelectionModel::layoutChanged()
2119{
2120 QtTestTableModel model(1,1);
2121 QItemSelectionModel selectionModel(&model);
2122 selectionModel.select(index: model.index(row: 0,column: 0), command: QItemSelectionModel::Select);
2123 QCOMPARE(selectionModel.selectedIndexes().count() , 1);
2124
2125 emit model.layoutAboutToBeChanged();
2126 model.row_count = 5;
2127 emit model.layoutChanged();
2128
2129 //The selection should not change.
2130 QCOMPARE(selectionModel.selectedIndexes().count() , 1);
2131 QCOMPARE(selectionModel.selectedIndexes().first() , model.index(0,0));
2132}
2133
2134void tst_QItemSelectionModel::merge_data()
2135{
2136 QTest::addColumn<QItemSelection>(name: "init");
2137 QTest::addColumn<QItemSelection>(name: "other");
2138 QTest::addColumn<QItemSelectionModel::SelectionFlag>(name: "command");
2139 QTest::addColumn<QItemSelection>(name: "result");
2140
2141 QTest::newRow(dataTag: "Simple select")
2142 << QItemSelection()
2143 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2144 << QItemSelectionModel::Select
2145 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4));
2146
2147 QTest::newRow(dataTag: "Simple deselect")
2148 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2149 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2150 << QItemSelectionModel::Deselect
2151 << QItemSelection();
2152
2153 QTest::newRow(dataTag: "Simple Toggle deselect")
2154 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2155 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2156 << QItemSelectionModel::Toggle
2157 << QItemSelection();
2158
2159 QTest::newRow(dataTag: "Simple Toggle select")
2160 << QItemSelection()
2161 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2162 << QItemSelectionModel::Toggle
2163 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4));
2164
2165 QTest::newRow(dataTag: "Add select")
2166 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 3))
2167 << QItemSelection(model->index(row: 2, column: 2) , model->index(row: 3, column: 4))
2168 << QItemSelectionModel::Select
2169 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4));
2170
2171 QTest::newRow(dataTag: "Deselect")
2172 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 4))
2173 << QItemSelection(model->index(row: 2, column: 2) , model->index(row: 3, column: 4))
2174 << QItemSelectionModel::Deselect
2175 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 1));
2176
2177 QItemSelection r1(model->index(row: 2, column: 1) , model->index(row: 3, column: 1));
2178 r1.select(topLeft: model->index(row: 2, column: 4) , bottomRight: model->index(row: 3, column: 4));
2179 QTest::newRow(dataTag: "Toggle")
2180 << QItemSelection(model->index(row: 2, column: 1) , model->index(row: 3, column: 3))
2181 << QItemSelection(model->index(row: 2, column: 2) , model->index(row: 3, column: 4))
2182 << QItemSelectionModel::Toggle
2183 << r1;
2184}
2185
2186void tst_QItemSelectionModel::merge()
2187{
2188 QFETCH(QItemSelection, init);
2189 QFETCH(QItemSelection, other);
2190 QFETCH(QItemSelectionModel::SelectionFlag, command);
2191 QFETCH(QItemSelection, result);
2192
2193 init.merge(other, command);
2194
2195 auto verify = [](const QModelIndexList &a, const QItemSelection &b)
2196 {
2197 for (const QModelIndex &idx : a)
2198 QVERIFY(b.contains(idx));
2199 };
2200 verify(init.indexes(), result);
2201 verify(result.indexes(), init);
2202}
2203
2204void tst_QItemSelectionModel::isRowSelected()
2205{
2206 QStandardItemModel model(2,2);
2207 model.setData(index: model.index(row: 0,column: 0), value: 0, role: Qt::UserRole - 1);
2208 QItemSelectionModel sel(&model);
2209 sel.select( selection: QItemSelection(model.index(row: 0,column: 0), model.index(row: 0, column: 1)), command: QItemSelectionModel::Select);
2210 QCOMPARE(sel.selectedIndexes().count(), 1);
2211 QVERIFY(sel.isRowSelected(0, QModelIndex()));
2212}
2213
2214void tst_QItemSelectionModel::childrenDeselectionSignal()
2215{
2216 QStandardItemModel model;
2217
2218 QStandardItem *parentItem = model.invisibleRootItem();
2219 for (int i = 0; i < 4; ++i) {
2220 QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
2221 parentItem->appendRow(aitem: item);
2222 parentItem = item;
2223 }
2224
2225 QModelIndex root = model.index(row: 0,column: 0);
2226 QModelIndex par = model.index(row: 0, column: 0, parent: root);
2227 QModelIndex sel = model.index(row: 0, column: 0, parent: par);
2228
2229 QItemSelectionModel selectionModel(&model);
2230 selectionModel.select(index: sel, command: QItemSelectionModel::SelectCurrent);
2231
2232 QSignalSpy deselectSpy(&selectionModel, &QItemSelectionModel::selectionChanged);
2233 QVERIFY(deselectSpy.isValid());
2234 model.removeRows(row: 0, count: 1, parent: root);
2235 QCOMPARE(deselectSpy.count(), 1);
2236
2237 // More testing stress for the patch.
2238 model.clear();
2239 selectionModel.clear();
2240
2241 parentItem = model.invisibleRootItem();
2242 for (int i = 0; i < 2; ++i) {
2243 QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
2244 parentItem->appendRow(aitem: item);
2245 }
2246 for (int i = 0; i < 2; ++i) {
2247 parentItem = model.invisibleRootItem()->child(row: i, column: 0);
2248 const QString prefix = QLatin1String("item ") + QString::number(i) + QLatin1Char('.');
2249 for (int j = 0; j < 2; ++j) {
2250 QStandardItem *item = new QStandardItem(prefix + QString::number(j));
2251 parentItem->appendRow(aitem: item);
2252 }
2253 }
2254
2255 sel = model.index(row: 0, column: 0, parent: model.index(row: 0, column: 0));
2256 selectionModel.select(index: sel, command: QItemSelectionModel::Select);
2257 QModelIndex sel2 = model.index(row: 0, column: 0, parent: model.index(row: 1, column: 0));
2258 selectionModel.select(index: sel2, command: QItemSelectionModel::Select);
2259
2260 QVERIFY(selectionModel.selection().contains(sel));
2261 QVERIFY(selectionModel.selection().contains(sel2));
2262 deselectSpy.clear();
2263 model.removeRow(arow: 0, aparent: model.index(row: 0, column: 0));
2264 QCOMPARE(deselectSpy.count(), 1);
2265 QVERIFY(!selectionModel.selection().contains(sel));
2266 QVERIFY(selectionModel.selection().contains(sel2));
2267}
2268
2269void tst_QItemSelectionModel::layoutChangedWithAllSelected1()
2270{
2271 QStringListModel model( QStringList() << "foo" << "bar" << "foo2");
2272 QSortFilterProxyModel proxy;
2273 proxy.setSourceModel(&model);
2274 QItemSelectionModel selection(&proxy);
2275
2276
2277 QCOMPARE(model.rowCount(), 3);
2278 QCOMPARE(proxy.rowCount(), 3);
2279 proxy.setFilterRegularExpression(QRegularExpression("f"));
2280 QCOMPARE(proxy.rowCount(), 2);
2281
2282 const QList<QPersistentModelIndex> indexList({proxy.index(row: 0,column: 0), proxy.index(row: 1,column: 0)});
2283 selection.select(selection: QItemSelection(indexList.first(), indexList.last()), command: QItemSelectionModel::Select);
2284
2285 //let's check the selection hasn't changed
2286 QCOMPARE(selection.selectedIndexes().count(), indexList.count());
2287 for (const auto &index : indexList)
2288 QVERIFY(selection.isSelected(index));
2289
2290 proxy.setFilterRegularExpression(QRegularExpression());
2291 QCOMPARE(proxy.rowCount(), 3);
2292
2293 //let's check the selection hasn't changed
2294 QCOMPARE(selection.selectedIndexes().count(), indexList.count());
2295 for (const auto &index : indexList)
2296 QVERIFY(selection.isSelected(index));
2297}
2298
2299// Same as layoutChangedWithAllSelected1, but with a slightly bigger model.
2300// This test is a regression test for QTBUG-5671.
2301void tst_QItemSelectionModel::layoutChangedWithAllSelected2()
2302{
2303 struct MyFilterModel : public QSortFilterProxyModel
2304 { // Override sort filter proxy to remove even numbered rows.
2305 bool filtering;
2306 virtual bool filterAcceptsRow( int source_row, const QModelIndex& /* source_parent */) const
2307 {
2308 return !filtering || !( source_row & 1 );
2309 }
2310 };
2311
2312 enum { cNumRows=30, cNumCols=20 };
2313
2314 QStandardItemModel model(cNumRows, cNumCols);
2315 MyFilterModel proxy;
2316 proxy.filtering = true;
2317 proxy.setSourceModel(&model);
2318 QItemSelectionModel selection(&proxy);
2319
2320 // Populate the tree view.
2321 for (unsigned int i = 0; i < cNumCols; i++)
2322 model.setHeaderData( section: i, orientation: Qt::Horizontal, value: QLatin1String("Column ") + QString::number(i));
2323
2324 for (unsigned int r = 0; r < cNumRows; r++) {
2325 const QString prefix = QLatin1String("r:") + QString::number(r) + QLatin1String("/c:");
2326 for (unsigned int c = 0; c < cNumCols; c++)
2327 model.setData(index: model.index(row: r, column: c, parent: QModelIndex()), value: prefix + QString::number(c));
2328 }
2329
2330 QCOMPARE(model.rowCount(), int(cNumRows));
2331 QCOMPARE(proxy.rowCount(), int(cNumRows/2));
2332
2333 selection.select( selection: QItemSelection(proxy.index(row: 0,column: 0), proxy.index(row: proxy.rowCount() - 1, column: proxy.columnCount() - 1)), command: QItemSelectionModel::Select);
2334
2335 const auto selIndexes = selection.selectedIndexes();
2336 const QList<QPersistentModelIndex> indexList(selIndexes.begin(), selIndexes.end());
2337
2338 proxy.filtering = false;
2339 proxy.invalidate();
2340 QCOMPARE(proxy.rowCount(), int(cNumRows));
2341
2342 //let's check the selection hasn't changed
2343 QCOMPARE(selection.selectedIndexes().count(), indexList.count());
2344 for (const auto &index : indexList)
2345 QVERIFY(selection.isSelected(index));
2346}
2347
2348// This test is a regression test for QTBUG-2804.
2349void tst_QItemSelectionModel::layoutChangedTreeSelection()
2350{
2351 QStandardItemModel model;
2352 QStandardItem top1("Child1"), top2("Child2"), top3("Child3");
2353 QStandardItem sub11("Alpha"), sub12("Beta"), sub13("Gamma"), sub14("Delta"),
2354 sub21("Alpha"), sub22("Beta"), sub23("Gamma"), sub24("Delta");
2355 top1.appendColumn(aitems: QList<QStandardItem*>() << &sub11 << &sub12 << &sub13 << &sub14);
2356 top2.appendColumn(aitems: QList<QStandardItem*>() << &sub21 << &sub22 << &sub23 << &sub24);
2357 model.appendColumn(items: QList<QStandardItem*>() << &top1 << &top2 << &top3);
2358
2359 QItemSelectionModel selModel(&model);
2360
2361 selModel.select(index: sub11.index(), command: QItemSelectionModel::Select);
2362 selModel.select(index: sub12.index(), command: QItemSelectionModel::Select);
2363 selModel.select(index: sub21.index(), command: QItemSelectionModel::Select);
2364 selModel.select(index: sub23.index(), command: QItemSelectionModel::Select);
2365
2366 QModelIndexList list = selModel.selectedIndexes();
2367 QCOMPARE(list.count(), 4);
2368
2369 model.sort(column: 0); //this will provoke a relayout
2370
2371 QCOMPARE(selModel.selectedIndexes().count(), 4);
2372}
2373
2374class RemovalObserver : public QObject
2375{
2376 Q_OBJECT
2377 QItemSelectionModel *m_itemSelectionModel;
2378public:
2379 RemovalObserver(QItemSelectionModel *selectionModel)
2380 : m_itemSelectionModel(selectionModel)
2381 {
2382 connect(asender: m_itemSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged(QItemSelection,QItemSelection)));
2383 }
2384
2385public slots:
2386 void selectionChanged(const QItemSelection & /* selected */, const QItemSelection &deselected)
2387 {
2388 const auto deselIndexes = deselected.indexes();
2389 for (const auto &index : deselIndexes) {
2390 QVERIFY(!m_itemSelectionModel->selection().contains(index));
2391 }
2392 QCOMPARE(m_itemSelectionModel->selection().size(), 2);
2393 }
2394};
2395
2396void tst_QItemSelectionModel::deselectRemovedMiddleRange()
2397{
2398 QStandardItemModel model(8, 0);
2399
2400 for (int row = 0; row < 8; ++row) {
2401 static const int column = 0;
2402 QStandardItem *item = new QStandardItem(QString::number(row));
2403 model.setItem(row, column, item);
2404 }
2405
2406 QItemSelectionModel selModel(&model);
2407
2408 selModel.select(selection: QItemSelection(model.index(row: 3, column: 0), model.index(row: 6, column: 0)), command: QItemSelectionModel::Select);
2409
2410 QCOMPARE(selModel.selection().size(), 1);
2411
2412 RemovalObserver ro(&selModel);
2413
2414 QSignalSpy spy(&selModel, &QItemSelectionModel::selectionChanged);
2415 QVERIFY(spy.isValid());
2416 bool ok = model.removeRows(row: 4, count: 2);
2417
2418 QVERIFY(ok);
2419 QCOMPARE(spy.size(), 1);
2420}
2421
2422static QStandardItemModel* getModel(QObject *parent)
2423{
2424 QStandardItemModel *model = new QStandardItemModel(parent);
2425
2426 for (int i = 0; i < 4; ++i) {
2427 QStandardItem *parentItem = model->invisibleRootItem();
2428 QList<QStandardItem*> list;
2429 const QString prefix = QLatin1String("item ") + QString::number(i) + QLatin1String(", ");
2430 for (int j = 0; j < 4; ++j) {
2431 list.append(t: new QStandardItem(prefix + QString::number(j)));
2432 }
2433 parentItem->appendRow(aitems: list);
2434 parentItem = list.first();
2435 for (int j = 0; j < 4; ++j) {
2436 QList<QStandardItem*> list;
2437 for (int k = 0; k < 4; ++k) {
2438 list.append(t: new QStandardItem(prefix + QString::number(j)));
2439 }
2440 parentItem->appendRow(aitems: list);
2441 }
2442 }
2443 return model;
2444}
2445
2446#if QT_DEPRECATED_SINCE(5, 15)
2447enum Result {
2448 LessThan,
2449 NotLessThan,
2450 NotEqual
2451};
2452
2453Q_DECLARE_METATYPE(Result);
2454
2455void tst_QItemSelectionModel::rangeOperatorLessThan_data()
2456{
2457 QTest::addColumn<int>(name: "parent1");
2458 QTest::addColumn<int>(name: "top1");
2459 QTest::addColumn<int>(name: "left1");
2460 QTest::addColumn<int>(name: "bottom1");
2461 QTest::addColumn<int>(name: "right1");
2462 QTest::addColumn<int>(name: "parent2");
2463 QTest::addColumn<int>(name: "top2");
2464 QTest::addColumn<int>(name: "left2");
2465 QTest::addColumn<int>(name: "bottom2");
2466 QTest::addColumn<int>(name: "right2");
2467 QTest::addColumn<Result>(name: "result");
2468
2469 QTest::newRow(dataTag: "lt01") << -1 << 0 << 0 << 3 << 3
2470 << -1 << 0 << 0 << 3 << 3 << NotLessThan;
2471
2472 QTest::newRow(dataTag: "lt02") << -1 << 0 << 0 << 2 << 3
2473 << -1 << 0 << 0 << 3 << 3 << LessThan;
2474 QTest::newRow(dataTag: "lt03") << -1 << 0 << 0 << 3 << 2
2475 << -1 << 0 << 0 << 3 << 3 << LessThan;
2476 QTest::newRow(dataTag: "lt04") << -1 << 0 << 0 << 2 << 2
2477 << -1 << 0 << 0 << 3 << 3 << LessThan;
2478
2479 QTest::newRow(dataTag: "lt05") << -1 << 0 << 0 << 3 << 3
2480 << -1 << 0 << 0 << 2 << 3 << NotLessThan;
2481 QTest::newRow(dataTag: "lt06") << -1 << 0 << 0 << 3 << 3
2482 << -1 << 0 << 0 << 3 << 2 << NotLessThan;
2483 QTest::newRow(dataTag: "lt07") << -1 << 0 << 0 << 3 << 3
2484 << -1 << 0 << 0 << 2 << 2 << NotLessThan;
2485
2486 QTest::newRow(dataTag: "lt08") << -1 << 0 << 0 << 3 << 3
2487 << 0 << 0 << 0 << 3 << 3 << NotEqual;
2488 QTest::newRow(dataTag: "lt09") << 1 << 0 << 0 << 3 << 3
2489 << 0 << 0 << 0 << 3 << 3 << NotEqual;
2490 QTest::newRow(dataTag: "lt10") << 1 << 0 << 0 << 1 << 1
2491 << 0 << 2 << 2 << 3 << 3 << NotEqual;
2492 QTest::newRow(dataTag: "lt11") << 1 << 2 << 2 << 3 << 3
2493 << 0 << 0 << 0 << 1 << 1 << NotEqual;
2494
2495 QTest::newRow(dataTag: "lt12") << -1 << 0 << 0 << 1 << 1
2496 << -1 << 2 << 2 << 3 << 3 << LessThan;
2497 QTest::newRow(dataTag: "lt13") << -1 << 2 << 2 << 3 << 3
2498 << -1 << 0 << 0 << 1 << 1 << NotLessThan;
2499 QTest::newRow(dataTag: "lt14") << 1 << 0 << 0 << 1 << 1
2500 << 1 << 2 << 2 << 3 << 3 << LessThan;
2501 QTest::newRow(dataTag: "lt15") << 1 << 2 << 2 << 3 << 3
2502 << 1 << 0 << 0 << 1 << 1 << NotLessThan;
2503
2504 QTest::newRow(dataTag: "lt16") << -1 << 0 << 0 << 2 << 2
2505 << -1 << 1 << 1 << 3 << 3 << LessThan;
2506 QTest::newRow(dataTag: "lt17") << -1 << 1 << 1 << 3 << 3
2507 << -1 << 0 << 0 << 2 << 2 << NotLessThan;
2508 QTest::newRow(dataTag: "lt18") << 1 << 0 << 0 << 2 << 2
2509 << 1 << 1 << 1 << 3 << 3 << LessThan;
2510 QTest::newRow(dataTag: "lt19") << 1 << 1 << 1 << 3 << 3
2511 << 1 << 0 << 0 << 2 << 2 << NotLessThan;
2512}
2513
2514void tst_QItemSelectionModel::rangeOperatorLessThan()
2515{
2516 QStandardItemModel *model1 = getModel(parent: this);
2517 QStandardItemModel *model2 = getModel(parent: this);
2518
2519 QFETCH(int, parent1);
2520 QFETCH(int, top1);
2521 QFETCH(int, left1);
2522 QFETCH(int, bottom1);
2523 QFETCH(int, right1);
2524 QFETCH(int, parent2);
2525 QFETCH(int, top2);
2526 QFETCH(int, left2);
2527 QFETCH(int, bottom2);
2528 QFETCH(int, right2);
2529 QFETCH(Result, result);
2530
2531 QModelIndex p1 = model1->index(row: parent1, column: 0);
2532
2533 QModelIndex tl1 = model1->index(row: top1, column: left1, parent: p1);
2534 QModelIndex br1 = model1->index(row: bottom1, column: right1, parent: p1);
2535
2536 QItemSelectionRange r1(tl1, br1);
2537
2538 QModelIndex p2 = model1->index(row: parent2, column: 0);
2539
2540 QModelIndex tl2 = model1->index(row: top2, column: left2, parent: p2);
2541 QModelIndex br2 = model1->index(row: bottom2, column: right2, parent: p2);
2542
2543 QItemSelectionRange r2(tl2, br2);
2544
2545 if (result == LessThan)
2546 QVERIFY(r1 < r2);
2547 else if (result == NotLessThan)
2548 QVERIFY(!(r1 < r2));
2549 else if (result == NotEqual)
2550 if (!(r1 < r2))
2551 QVERIFY(r2 < r1);
2552
2553 // Ranges in different models are always non-equal
2554
2555 QModelIndex p3 = model2->index(row: parent1, column: 0);
2556
2557 QModelIndex tl3 = model2->index(row: top1, column: left1, parent: p3);
2558 QModelIndex br3 = model2->index(row: bottom1, column: right1, parent: p3);
2559
2560 QItemSelectionRange r3(tl3, br3);
2561
2562 if (!(r1 < r3))
2563 QVERIFY(r3 < r1);
2564
2565 if (!(r2 < r3))
2566 QVERIFY(r3 < r2);
2567
2568 QModelIndex p4 = model2->index(row: parent2, column: 0);
2569
2570 QModelIndex tl4 = model2->index(row: top2, column: left2, parent: p4);
2571 QModelIndex br4 = model2->index(row: bottom2, column: right2, parent: p4);
2572
2573 QItemSelectionRange r4(tl4, br4);
2574
2575 if (!(r1 < r4))
2576 QVERIFY(r4 < r1);
2577
2578 if (!(r2 < r4))
2579 QVERIFY(r4 < r2);
2580}
2581#endif
2582
2583void tst_QItemSelectionModel::setModel()
2584{
2585 QItemSelectionModel sel;
2586 QVERIFY(!sel.model());
2587 QSignalSpy modelChangedSpy(&sel, SIGNAL(modelChanged(QAbstractItemModel*)));
2588 QStringListModel model(QStringList() << "Blah" << "Blah" << "Blah");
2589 sel.setModel(&model);
2590 QCOMPARE(sel.model(), &model);
2591 QCOMPARE(modelChangedSpy.count(), 1);
2592 sel.select(index: model.index(row: 0), command: QItemSelectionModel::Select);
2593 QVERIFY(!sel.selection().isEmpty());
2594 sel.setModel(0);
2595 QVERIFY(sel.selection().isEmpty());
2596}
2597
2598void tst_QItemSelectionModel::testDifferentModels()
2599{
2600 QStandardItemModel model1;
2601 QStandardItemModel model2;
2602 QStandardItem top11("Child1"), top12("Child2"), top13("Child3");
2603 QStandardItem top21("Child1"), top22("Child2"), top23("Child3");
2604
2605 model1.appendColumn(items: QList<QStandardItem*>() << &top11 << &top12 << &top13);
2606 model2.appendColumn(items: QList<QStandardItem*>() << &top21 << &top22 << &top23);
2607
2608 QModelIndex topIndex1 = model1.index(row: 0, column: 0);
2609 QModelIndex bottomIndex1 = model1.index(row: 2, column: 0);
2610 QModelIndex topIndex2 = model2.index(row: 0, column: 0);
2611
2612 QItemSelectionRange range(topIndex1, bottomIndex1);
2613
2614 QVERIFY(range.intersects(QItemSelectionRange(topIndex1, topIndex1)));
2615 QVERIFY(!range.intersects(QItemSelectionRange(topIndex2, topIndex2)));
2616
2617 QItemSelection newSelection;
2618 QItemSelection::split(range, other: QItemSelectionRange(topIndex2, topIndex2), result: &newSelection);
2619
2620 QVERIFY(newSelection.isEmpty());
2621}
2622
2623class SelectionObserver : public QObject
2624{
2625 Q_OBJECT
2626public:
2627 SelectionObserver(QAbstractItemModel *model, QObject *parent = 0)
2628 : QObject(parent), m_model(model), m_selectionModel(0)
2629 {
2630 connect(asender: model, SIGNAL(modelReset()), SLOT(modelReset()));
2631 }
2632
2633 void setSelectionModel(QItemSelectionModel *selectionModel)
2634 {
2635 m_selectionModel = selectionModel;
2636 connect(asender: m_selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged(QItemSelection,QItemSelection)));
2637 }
2638
2639private slots:
2640 void modelReset()
2641 {
2642 const QModelIndex idx = m_model->index(row: 2, column: 0);
2643 QVERIFY(idx.isValid());
2644 m_selectionModel->select(selection: QItemSelection(idx, idx), command: QItemSelectionModel::Clear);
2645 }
2646
2647 void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
2648 {
2649 for (const auto &range : selected)
2650 QVERIFY(range.isValid());
2651 for (const auto &range : deselected)
2652 QVERIFY(range.isValid());
2653 }
2654
2655private:
2656 QAbstractItemModel *m_model;
2657 QItemSelectionModel *m_selectionModel;
2658};
2659
2660void tst_QItemSelectionModel::testValidRangesInSelectionsAfterReset()
2661{
2662 QStringListModel model;
2663
2664 QStringList strings;
2665 strings << "one"
2666 << "two"
2667 << "three"
2668 << "four"
2669 << "five";
2670
2671 model.setStringList(strings);
2672
2673 SelectionObserver observer(&model);
2674
2675 QItemSelectionModel selectionModel(&model);
2676
2677 selectionModel.select(selection: QItemSelection(model.index(row: 1, column: 0), model.index(row: 3, column: 0)), command: QItemSelectionModel::Select);
2678
2679 // Cause d->ranges to contain something.
2680 model.insertRows(row: 2, count: 1);
2681
2682 observer.setSelectionModel(&selectionModel);
2683
2684 model.setStringList(strings);
2685}
2686
2687class DuplicateItemSelectionModel : public QItemSelectionModel
2688{
2689 Q_OBJECT
2690public:
2691 DuplicateItemSelectionModel(QItemSelectionModel *target, QAbstractItemModel *model, QObject *parent = 0)
2692 : QItemSelectionModel(model, parent), m_target(target)
2693 {
2694 }
2695
2696 void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
2697 {
2698 QItemSelectionModel::select(selection, command);
2699 m_target->select(selection, command);
2700 }
2701
2702 using QItemSelectionModel::select;
2703
2704 void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
2705 {
2706 QItemSelectionModel::setCurrentIndex(index, command);
2707 m_target->setCurrentIndex(index, command);
2708 }
2709
2710 void clearCurrentIndex()
2711 {
2712 QItemSelectionModel::clearCurrentIndex();
2713 m_target->clearCurrentIndex();
2714 }
2715
2716private:
2717 QItemSelectionModel *m_target;
2718};
2719
2720void tst_QItemSelectionModel::testChainedSelectionClear()
2721{
2722 QStringListModel model(QStringList() << "Apples" << "Pears");
2723
2724 QItemSelectionModel selectionModel(&model, 0);
2725 DuplicateItemSelectionModel duplicate(&selectionModel, &model, 0);
2726
2727 duplicate.select(index: model.index(row: 0, column: 0), command: QItemSelectionModel::Select);
2728
2729 {
2730 QModelIndexList selectedIndexes = selectionModel.selection().indexes();
2731 QModelIndexList duplicatedIndexes = duplicate.selection().indexes();
2732
2733 QCOMPARE(selectedIndexes.size(), duplicatedIndexes.size());
2734 QCOMPARE(selectedIndexes.size(), 1);
2735 QVERIFY(selectedIndexes.first() == model.index(0, 0));
2736 }
2737
2738 duplicate.clearSelection();
2739
2740 {
2741 QModelIndexList selectedIndexes = selectionModel.selection().indexes();
2742 QModelIndexList duplicatedIndexes = duplicate.selection().indexes();
2743
2744 QCOMPARE(selectedIndexes.size(), duplicatedIndexes.size());
2745 QCOMPARE(selectedIndexes.size(), 0);
2746 }
2747
2748 duplicate.setCurrentIndex(index: model.index(row: 0, column: 0), command: QItemSelectionModel::NoUpdate);
2749
2750 QCOMPARE(selectionModel.currentIndex(), duplicate.currentIndex());
2751
2752 duplicate.clearCurrentIndex();
2753
2754 QVERIFY(!duplicate.currentIndex().isValid());
2755 QCOMPARE(selectionModel.currentIndex(), duplicate.currentIndex());
2756}
2757
2758void tst_QItemSelectionModel::testClearCurrentIndex()
2759{
2760 QStringListModel model(QStringList() << "Apples" << "Pears");
2761
2762 QItemSelectionModel selectionModel(&model, 0);
2763
2764 QSignalSpy currentIndexSpy(&selectionModel, &QItemSelectionModel::currentChanged);
2765 QVERIFY(currentIndexSpy.isValid());
2766
2767 QModelIndex firstIndex = model.index(row: 0, column: 0);
2768 QVERIFY(firstIndex.isValid());
2769 selectionModel.setCurrentIndex(index: firstIndex, command: QItemSelectionModel::NoUpdate);
2770 QCOMPARE(selectionModel.currentIndex(), firstIndex);
2771 QCOMPARE(currentIndexSpy.size(), 1);
2772
2773 selectionModel.clearCurrentIndex();
2774
2775 QCOMPARE(selectionModel.currentIndex(), QModelIndex());
2776 QCOMPARE(currentIndexSpy.size(), 2);
2777}
2778
2779void tst_QItemSelectionModel::QTBUG48402_data()
2780{
2781 QTest::addColumn<int>(name: "rows");
2782 QTest::addColumn<int>(name: "columns");
2783
2784 QTest::addColumn<int>(name: "selectTop");
2785 QTest::addColumn<int>(name: "selectLeft");
2786 QTest::addColumn<int>(name: "selectBottom");
2787 QTest::addColumn<int>(name: "selectRight");
2788
2789 QTest::addColumn<int>(name: "removeTop");
2790 QTest::addColumn<int>(name: "removeBottom");
2791
2792 QTest::addColumn<int>(name: "deselectTop");
2793 QTest::addColumn<int>(name: "deselectLeft");
2794 QTest::addColumn<int>(name: "deselectBottom");
2795 QTest::addColumn<int>(name: "deselectRight");
2796
2797 QTest::newRow(dataTag: "4x4 top intersection")
2798 << 4 << 4
2799 << 0 << 2 << 1 << 3
2800 << 1 << 1
2801 << 1 << 2 << 1 << 3;
2802
2803 QTest::newRow(dataTag: "4x4 bottom intersection")
2804 << 4 << 4
2805 << 0 << 2 << 1 << 3
2806 << 0 << 0
2807 << 0 << 2 << 0 << 3;
2808
2809 QTest::newRow(dataTag: "4x4 middle intersection")
2810 << 4 << 4
2811 << 0 << 2 << 2 << 3
2812 << 1 << 1
2813 << 1 << 2 << 1 << 3;
2814
2815 QTest::newRow(dataTag: "4x4 full inclusion")
2816 << 4 << 4
2817 << 0 << 2 << 1 << 3
2818 << 0 << 1
2819 << 0 << 2 << 1 << 3;
2820}
2821class QTBUG48402_helper : public QObject
2822{
2823 Q_OBJECT
2824public:
2825 QModelIndex tl;
2826 QModelIndex br;
2827public slots:
2828 void changed(const QItemSelection &, const QItemSelection &deselected)
2829 {
2830 tl = deselected.first().topLeft();
2831 br = deselected.first().bottomRight();
2832 }
2833};
2834
2835void tst_QItemSelectionModel::QTBUG48402()
2836{
2837 QFETCH(int, rows);
2838 QFETCH(int, columns);
2839 QFETCH(int, selectTop);
2840 QFETCH(int, selectLeft);
2841 QFETCH(int, selectBottom);
2842 QFETCH(int, selectRight);
2843 QFETCH(int, removeTop);
2844 QFETCH(int, removeBottom);
2845 QFETCH(int, deselectTop);
2846 QFETCH(int, deselectLeft);
2847 QFETCH(int, deselectBottom);
2848 QFETCH(int, deselectRight);
2849
2850 MyStandardItemModel model(rows, columns);
2851 QItemSelectionModel selections(&model);
2852
2853 QModelIndex stl = model.index(row: selectTop, column: selectLeft);
2854 QModelIndex sbr = model.index(row: selectBottom, column: selectRight);
2855 QModelIndex dtl = model.index(row: deselectTop, column: deselectLeft);
2856 QModelIndex dbr = model.index(row: deselectBottom, column: deselectRight);
2857
2858 selections.select(selection: QItemSelection(stl, sbr), command: QItemSelectionModel::ClearAndSelect);
2859 QTBUG48402_helper helper;
2860 helper.connect(sender: &selections, signal: &QItemSelectionModel::selectionChanged, receiver: &helper, slot: &QTBUG48402_helper::changed);
2861 QVERIFY(selections.isSelected(stl));
2862 QVERIFY(selections.isSelected(sbr));
2863 QVERIFY(selections.hasSelection());
2864
2865 model.removeRows(row: removeTop, count: removeBottom - removeTop + 1);
2866
2867 QCOMPARE(QItemSelectionRange(helper.tl, helper.br), QItemSelectionRange(dtl, dbr));
2868}
2869
2870void tst_QItemSelectionModel::QTBUG58851_data()
2871{
2872 using IntPair = std::pair<int, int>;
2873 using IntPairList = QList<IntPair>;
2874 using IntPairPair = std::pair<IntPair, IntPair>;
2875 using IntPairPairList = QList<IntPairPair>;
2876
2877 QTest::addColumn<IntPairPairList>(name: "rangesToSelect");
2878 QTest::addColumn<IntPairList>(name: "expectedSelectedIndexesPairs");
2879 QTest::newRow(dataTag: "Single index in > 0 column")
2880 << (IntPairPairList() << IntPairPair(IntPair(0, 1), IntPair(0, 1)))
2881 << (IntPairList() << IntPair(0, 1));
2882 QTest::newRow(dataTag: "Rectangle in > 0 column")
2883 << (IntPairPairList() << IntPairPair(IntPair(0, 1), IntPair(1, 2)))
2884 << (IntPairList() << IntPair(0, 1) << IntPair(0, 2) << IntPair(1, 1) << IntPair(1, 2));
2885 QTest::newRow(dataTag: "Diagonal in > 0 column")
2886 << (IntPairPairList()
2887 << IntPairPair(IntPair(0, 1), IntPair(0, 1))
2888 << IntPairPair(IntPair(1, 2), IntPair(1, 2))
2889 << IntPairPair(IntPair(2, 3), IntPair(2, 3)))
2890 << (IntPairList()
2891 << IntPair(0, 1)
2892 << IntPair(1, 2)
2893 << IntPair(2, 3));
2894}
2895
2896void tst_QItemSelectionModel::QTBUG58851()
2897{
2898 using IntPair = std::pair<int, int>;
2899 using IntPairList = QList<IntPair>;
2900 using IntPairPair = std::pair<IntPair, IntPair>;
2901 using IntPairPairList = QList<IntPairPair>;
2902
2903 QFETCH(IntPairPairList, rangesToSelect);
2904 QFETCH(IntPairList, expectedSelectedIndexesPairs);
2905
2906 QStandardItemModel model(4, 4);
2907 for (int row = 0; row < model.rowCount(); ++row) {
2908 for (int column = 0; column < model.columnCount(); ++column) {
2909 QStandardItem *item = new QStandardItem(QString("%0%1").arg(a: row).arg(a: column));
2910 model.setItem(row, column, item);
2911 }
2912 }
2913
2914 QSortFilterProxyModel proxy;
2915 proxy.setSourceModel(&model);
2916 proxy.setSortRole(Qt::DisplayRole);
2917
2918 std::vector<QPersistentModelIndex> expectedSelectedIndexes;
2919 for (const IntPair &index : expectedSelectedIndexesPairs)
2920 expectedSelectedIndexes.emplace_back(args: proxy.index(row: index.first, column: index.second));
2921
2922 QItemSelectionModel selections(&proxy);
2923 for (const IntPairPair &range : rangesToSelect) {
2924 const IntPair &tl = range.first;
2925 const IntPair &br = range.second;
2926 selections.select(selection: QItemSelection(proxy.index(row: tl.first, column: tl.second),
2927 proxy.index(row: br.first, column: br.second)),
2928 command: QItemSelectionModel::Select);
2929 }
2930
2931 for (const QPersistentModelIndex &i : expectedSelectedIndexes) {
2932 QVERIFY(selections.isSelected(i));
2933 }
2934 proxy.sort(column: 1, order: Qt::DescendingOrder);
2935 QCOMPARE(selections.selectedIndexes().count(), (int)expectedSelectedIndexes.size());
2936 for (const QPersistentModelIndex &i : expectedSelectedIndexes) {
2937 QVERIFY(selections.isSelected(i));
2938 }
2939}
2940
2941void tst_QItemSelectionModel::QTBUG18001_data()
2942{
2943 using IntPair = std::pair<int, int>;
2944 using IntPairList = QList<IntPair>;
2945 using IntList = QList<int>;
2946 using BoolList = QList<bool>;
2947
2948 QTest::addColumn<IntPairList>(name: "indexesToSelect");
2949 QTest::addColumn<IntList>(name: "selectionCommands");
2950 QTest::addColumn<BoolList>(name: "expectedSelectedRows");
2951 QTest::addColumn<BoolList>(name: "expectedSelectedColums");
2952
2953 int colSelect = QItemSelectionModel::Select | QItemSelectionModel::Columns;
2954 int rowSelect = QItemSelectionModel::Select | QItemSelectionModel::Rows;
2955
2956 QTest::newRow(dataTag: "Select column 1")
2957 << IntPairList { {0, 1} }
2958 << IntList{ colSelect }
2959 << BoolList{ false, false, false, false, false }
2960 << BoolList{ false, true, false, false, false };
2961
2962 QTest::newRow(dataTag: "Select row 1")
2963 << IntPairList { {1, 0} }
2964 << IntList{ rowSelect }
2965 << BoolList{ false, true, false, false, false }
2966 << BoolList{ false, false, false, false, false };
2967
2968 QTest::newRow(dataTag: "Select column 1+2, row 1+2")
2969 << IntPairList { {0, 1}, {0, 2}, {1, 0}, {2, 0} }
2970 << IntList{ colSelect, colSelect, rowSelect, rowSelect }
2971 << BoolList{ false, true, true, false, false }
2972 << BoolList{ false, true, true, false, false };
2973
2974 QTest::newRow(dataTag: "Select row 1+2, col 1+2")
2975 << IntPairList { {1, 0}, {2, 0}, {0, 1}, {0, 2} }
2976 << IntList{ rowSelect, rowSelect, colSelect, colSelect }
2977 << BoolList{ false, true, true, false, false }
2978 << BoolList{ false, true, true, false, false };
2979}
2980
2981void tst_QItemSelectionModel::QTBUG18001()
2982{
2983 using IntPair = std::pair<int, int>;
2984 using IntPairList = QList<IntPair>;
2985 using IntList = QList<int>;
2986 using BoolList = QList<bool>;
2987
2988 QFETCH(IntPairList, indexesToSelect);
2989 QFETCH(IntList, selectionCommands);
2990 QFETCH(BoolList, expectedSelectedRows);
2991 QFETCH(BoolList, expectedSelectedColums);
2992
2993 QStandardItemModel model(5, 5);
2994 for (int row = 0; row < model.rowCount(); ++row) {
2995 for (int column = 0; column < model.columnCount(); ++column) {
2996 QStandardItem *item = new QStandardItem(QString("%0x%1").arg(a: row).arg(a: column));
2997 model.setItem(row, column, item);
2998
2999 const bool oddRow = row % 2;
3000 const bool oddCol = column % 2;
3001
3002 if (oddRow == oddCol)
3003 item->setSelectable(false);
3004 }
3005 }
3006
3007 QItemSelectionModel selectionModel(&model);
3008
3009 for (int i = 0; i < indexesToSelect.count(); ++i) {
3010 QModelIndex idx = model.index( row: indexesToSelect.at(i).first, column: indexesToSelect.at(i).second );
3011 selectionModel.select(index: idx, command: QItemSelectionModel::SelectionFlag(selectionCommands.at(i)));
3012 }
3013
3014 for (int i = 0; i < expectedSelectedRows.count(); ++i) {
3015 const bool expected = expectedSelectedRows.at(i);
3016 const bool actual = selectionModel.isRowSelected(row: i, parent: QModelIndex());
3017 QByteArray description = QByteArray("Row ") + QByteArray::number(i)
3018 + " Expected " + QByteArray::number(expected)
3019 + " Actual " + QByteArray::number(actual);
3020 QVERIFY2(expected == actual, description.data());
3021 }
3022
3023 for (int i = 0; i < expectedSelectedColums.count(); ++i) {
3024 const bool expected = expectedSelectedColums.at(i);
3025 const bool actual = selectionModel.isColumnSelected(column: i, parent: QModelIndex());
3026 QByteArray description = QByteArray("Col ") + QByteArray::number(i)
3027 + " Expected " + QByteArray::number(expected)
3028 + " Actual " + QByteArray::number(actual);
3029 QVERIFY2(expected == actual, description.data());
3030 }
3031
3032}
3033
3034QTEST_MAIN(tst_QItemSelectionModel)
3035#include "tst_qitemselectionmodel.moc"
3036

source code of qtbase/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp