Fix crash when invalidating a QSortFilterProxyModel
[profile/ivi/qtbase.git] / tests / auto / corelib / itemmodels / qsortfilterproxymodel / tst_qsortfilterproxymodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include "dynamictreemodel.h"
44 #include "modeltest.h"
45
46 #include <QtCore/QCoreApplication>
47 #include <QtGui/QStandardItem>
48 #include <QtWidgets/QTreeView>
49 #include <QtWidgets/QTableView>
50
51 #include <qdebug.h>
52
53 typedef QList<int> IntList;
54 typedef QPair<int, int> IntPair;
55 typedef QList<IntPair> IntPairList;
56
57 Q_DECLARE_METATYPE(IntList)
58 Q_DECLARE_METATYPE(IntPair)
59 Q_DECLARE_METATYPE(IntPairList)
60 Q_DECLARE_METATYPE(QModelIndex)
61
62 class tst_QSortFilterProxyModel : public QObject
63 {
64     Q_OBJECT
65 public:
66     tst_QSortFilterProxyModel();
67
68 public slots:
69     void initTestCase();
70     void cleanupTestCase();
71     void cleanup();
72
73 private slots:
74     void getSetCheck();
75     void sort_data();
76     void sort();
77     void sortHierarchy_data();
78     void sortHierarchy();
79
80     void insertRows_data();
81     void insertRows();
82     void prependRow();
83     void removeRows_data();
84     void removeRows();
85     void removeColumns_data();
86     void removeColumns();
87     void insertAfterSelect();
88     void removeAfterSelect();
89     void filter_data();
90     void filter();
91     void filterHierarchy_data();
92     void filterHierarchy();
93     void filterColumns_data();
94     void filterColumns();
95
96     void filterTable();
97     void filterCurrent();
98
99     void changeSourceLayout();
100     void removeSourceRows_data();
101     void removeSourceRows();
102     void insertSourceRows_data();
103     void insertSourceRows();
104     void changeFilter_data();
105     void changeFilter();
106     void changeSourceData_data();
107     void changeSourceData();
108     void sortFilterRole();
109     void selectionFilteredOut();
110     void match_data();
111     void match();
112     void insertIntoChildrenlessItem();
113     void invalidateMappedChildren();
114     void insertRowIntoFilteredParent();
115     void filterOutParentAndFilterInChild();
116
117     void sourceInsertRows();
118     void sourceModelDeletion();
119
120     void sortColumnTracking1();
121     void sortColumnTracking2();
122
123     void sortStable();
124
125     void hiddenColumns();
126     void insertRowsSort();
127     void staticSorting();
128     void dynamicSorting();
129     void fetchMore();
130     void hiddenChildren();
131     void mapFromToSource();
132     void removeRowsRecursive();
133     void doubleProxySelectionSetSourceModel();
134     void appearsAndSort();
135     void unnecessaryDynamicSorting();
136     void unnecessaryMapCreation();
137     void resetInvalidate_data();
138     void resetInvalidate();
139
140     void testMultipleProxiesWithSelection();
141     void mapSelectionFromSource();
142     void filteredColumns();
143     void headerDataChanged();
144
145     void testParentLayoutChanged();
146     void moveSourceRows();
147
148     void hierarchyFilterInvalidation();
149     void simpleFilterInvalidation();
150
151 protected:
152     void buildHierarchy(const QStringList &data, QAbstractItemModel *model);
153     void checkHierarchy(const QStringList &data, const QAbstractItemModel *model);
154
155 private:
156     QStandardItemModel *m_model;
157     QSortFilterProxyModel *m_proxy;
158 };
159
160 // Testing get/set functions
161 void tst_QSortFilterProxyModel::getSetCheck()
162 {
163     QSortFilterProxyModel obj1;
164     QCOMPARE(obj1.sourceModel(), (QAbstractItemModel *)0);
165     // int QSortFilterProxyModel::filterKeyColumn()
166     // void QSortFilterProxyModel::setFilterKeyColumn(int)
167     obj1.setFilterKeyColumn(0);
168     QCOMPARE(0, obj1.filterKeyColumn());
169     obj1.setFilterKeyColumn(INT_MIN);
170     QCOMPARE(INT_MIN, obj1.filterKeyColumn());
171     obj1.setFilterKeyColumn(INT_MAX);
172     QCOMPARE(INT_MAX, obj1.filterKeyColumn());
173 }
174
175 tst_QSortFilterProxyModel::tst_QSortFilterProxyModel()
176     : m_model(0), m_proxy(0)
177 {
178 }
179
180 void tst_QSortFilterProxyModel::initTestCase()
181 {
182     qRegisterMetaType<QModelIndex>("QModelIndex");
183     qRegisterMetaType<IntList>("IntList");
184     qRegisterMetaType<IntPair>("IntPair");
185     qRegisterMetaType<IntPairList>("IntPairList");
186     m_model = new QStandardItemModel(0, 1);
187     m_proxy = new QSortFilterProxyModel();
188     m_proxy->setSourceModel(m_model);
189 }
190
191 void tst_QSortFilterProxyModel::cleanupTestCase()
192 {
193     delete m_proxy;
194     delete m_model;
195 }
196
197 void tst_QSortFilterProxyModel::cleanup()
198 {
199     m_proxy->setFilterRegExp(QRegExp());
200     m_proxy->sort(-1, Qt::AscendingOrder);
201     m_model->clear();
202     m_model->insertColumns(0, 1);
203 }
204
205 /*
206   tests
207 */
208
209 void tst_QSortFilterProxyModel::sort_data()
210 {
211     QTest::addColumn<int>("sortOrder");
212     QTest::addColumn<int>("sortCaseSensitivity");
213     QTest::addColumn<QStringList>("initial");
214     QTest::addColumn<QStringList>("expected");
215
216     QTest::newRow("flat descending") << static_cast<int>(Qt::DescendingOrder)
217                                   << int(Qt::CaseSensitive)
218                                   << (QStringList()
219                                       << "delta"
220                                       << "yankee"
221                                       << "bravo"
222                                       << "lima"
223                                       << "charlie"
224                                       << "juliet"
225                                       << "tango"
226                                       << "hotel"
227                                       << "uniform"
228                                       << "alpha"
229                                       << "echo"
230                                       << "golf"
231                                       << "quebec"
232                                       << "foxtrot"
233                                       << "india"
234                                       << "romeo"
235                                       << "november"
236                                       << "oskar"
237                                       << "zulu"
238                                       << "kilo"
239                                       << "whiskey"
240                                       << "mike"
241                                       << "papa"
242                                       << "sierra"
243                                       << "xray"
244                                       << "viktor")
245                                   << (QStringList()
246                                       << "zulu"
247                                       << "yankee"
248                                       << "xray"
249                                       << "whiskey"
250                                       << "viktor"
251                                       << "uniform"
252                                       << "tango"
253                                       << "sierra"
254                                       << "romeo"
255                                       << "quebec"
256                                       << "papa"
257                                       << "oskar"
258                                       << "november"
259                                       << "mike"
260                                       << "lima"
261                                       << "kilo"
262                                       << "juliet"
263                                       << "india"
264                                       << "hotel"
265                                       << "golf"
266                                       << "foxtrot"
267                                       << "echo"
268                                       << "delta"
269                                       << "charlie"
270                                       << "bravo"
271                                       << "alpha");
272     QTest::newRow("flat ascending") <<  static_cast<int>(Qt::AscendingOrder)
273                                  << int(Qt::CaseSensitive)
274                                  << (QStringList()
275                                      << "delta"
276                                      << "yankee"
277                                      << "bravo"
278                                      << "lima"
279                                      << "charlie"
280                                      << "juliet"
281                                      << "tango"
282                                      << "hotel"
283                                      << "uniform"
284                                      << "alpha"
285                                      << "echo"
286                                      << "golf"
287                                      << "quebec"
288                                      << "foxtrot"
289                                      << "india"
290                                      << "romeo"
291                                      << "november"
292                                      << "oskar"
293                                      << "zulu"
294                                      << "kilo"
295                                      << "whiskey"
296                                      << "mike"
297                                      << "papa"
298                                      << "sierra"
299                                      << "xray"
300                                      << "viktor")
301                                  << (QStringList()
302                                      << "alpha"
303                                      << "bravo"
304                                      << "charlie"
305                                      << "delta"
306                                      << "echo"
307                                      << "foxtrot"
308                                      << "golf"
309                                      << "hotel"
310                                      << "india"
311                                      << "juliet"
312                                      << "kilo"
313                                      << "lima"
314                                      << "mike"
315                                      << "november"
316                                      << "oskar"
317                                      << "papa"
318                                      << "quebec"
319                                      << "romeo"
320                                      << "sierra"
321                                      << "tango"
322                                      << "uniform"
323                                      << "viktor"
324                                      << "whiskey"
325                                      << "xray"
326                                      << "yankee"
327                                      << "zulu");
328     QTest::newRow("case insensitive") <<  static_cast<int>(Qt::AscendingOrder)
329                                  << int(Qt::CaseInsensitive)
330                                  << (QStringList()
331                                      << "alpha" << "BETA" << "Gamma" << "delta")
332                                  << (QStringList()
333                                      << "alpha" << "BETA" << "delta" << "Gamma");
334     QTest::newRow("case sensitive") <<  static_cast<int>(Qt::AscendingOrder)
335                                  << int(Qt::CaseSensitive)
336                                  << (QStringList()
337                                      << "alpha" << "BETA" << "Gamma" << "delta")
338                                  << (QStringList()
339                                      << "BETA" << "Gamma" << "alpha" << "delta");
340
341     QStringList list;
342     for (int i = 10000; i < 20000; ++i)
343         list.append(QString("Number: %1").arg(i));
344     QTest::newRow("large set ascending") <<  static_cast<int>(Qt::AscendingOrder) << int(Qt::CaseSensitive) << list << list;
345 }
346
347 void tst_QSortFilterProxyModel::sort()
348 {
349     QFETCH(int, sortOrder);
350     QFETCH(int, sortCaseSensitivity);
351     QFETCH(QStringList, initial);
352     QFETCH(QStringList, expected);
353
354     // prepare model
355     QStandardItem *root = m_model->invisibleRootItem ();
356     QList<QStandardItem *> items;
357     for (int i = 0; i < initial.count(); ++i) {
358         items.append(new QStandardItem(initial.at(i)));
359     }
360     root->insertRows(0, items);
361     QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
362     QCOMPARE(m_model->columnCount(QModelIndex()), 1);
363
364     // make sure the proxy is unsorted
365     QCOMPARE(m_proxy->columnCount(QModelIndex()), 1);
366     QCOMPARE(m_proxy->rowCount(QModelIndex()), initial.count());
367     for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
368         QModelIndex index = m_proxy->index(row, 0, QModelIndex());
369         QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
370     }
371
372     // sort
373     m_proxy->sort(0, static_cast<Qt::SortOrder>(sortOrder));
374     m_proxy->setSortCaseSensitivity(static_cast<Qt::CaseSensitivity>(sortCaseSensitivity));
375
376     // make sure the model is unchanged
377     for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
378         QModelIndex index = m_model->index(row, 0, QModelIndex());
379         QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
380     }
381     // make sure the proxy is sorted
382     for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
383         QModelIndex index = m_proxy->index(row, 0, QModelIndex());
384         QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
385     }
386
387     // restore the unsorted order
388     m_proxy->sort(-1);
389
390     // make sure the proxy is unsorted again
391     for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
392         QModelIndex index = m_proxy->index(row, 0, QModelIndex());
393         QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
394     }
395 }
396
397 void tst_QSortFilterProxyModel::sortHierarchy_data()
398 {
399     QTest::addColumn<int>("sortOrder");
400     QTest::addColumn<QStringList>("initial");
401     QTest::addColumn<QStringList>("expected");
402
403     QTest::newRow("flat ascending")
404         << static_cast<int>(Qt::AscendingOrder)
405         << (QStringList()
406             << "c" << "f" << "d" << "e" << "a" << "b")
407         << (QStringList()
408             << "a" << "b" << "c" << "d" << "e" << "f");
409
410     QTest::newRow("simple hierarchy")
411         << static_cast<int>(Qt::AscendingOrder)
412         << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">")
413         << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">");
414
415     QTest::newRow("hierarchical ascending")
416         << static_cast<int>(Qt::AscendingOrder)
417         << (QStringList()
418             << "c"
419                    << "<"
420                    << "h"
421                           << "<"
422                           << "2"
423                           << "0"
424                           << "1"
425                           << ">"
426                    << "g"
427                    << "i"
428                    << ">"
429             << "b"
430                    << "<"
431                    << "l"
432                    << "k"
433                           << "<"
434                           << "8"
435                           << "7"
436                           << "9"
437                           << ">"
438                    << "m"
439                    << ">"
440             << "a"
441                    << "<"
442                    << "z"
443                    << "y"
444                    << "x"
445                    << ">")
446         << (QStringList()
447             << "a"
448                    << "<"
449                    << "x"
450                    << "y"
451                    << "z"
452                    << ">"
453             << "b"
454                    << "<"
455                    << "k"
456                           << "<"
457                           << "7"
458                           << "8"
459                           << "9"
460                           << ">"
461                    << "l"
462                    << "m"
463                    << ">"
464             << "c"
465                    << "<"
466                    << "g"
467                    << "h"
468                           << "<"
469                           << "0"
470                           << "1"
471                           << "2"
472                           << ">"
473                    << "i"
474                    << ">");
475 }
476
477 void tst_QSortFilterProxyModel::sortHierarchy()
478 {
479     QFETCH(int, sortOrder);
480     QFETCH(QStringList, initial);
481     QFETCH(QStringList, expected);
482
483     buildHierarchy(initial, m_model);
484     checkHierarchy(initial, m_model);
485     checkHierarchy(initial, m_proxy);
486     m_proxy->sort(0, static_cast<Qt::SortOrder>(sortOrder));
487     checkHierarchy(initial, m_model);
488     checkHierarchy(expected, m_proxy);
489 }
490
491 void tst_QSortFilterProxyModel::insertRows_data()
492 {
493     QTest::addColumn<QStringList>("initial");
494     QTest::addColumn<QStringList>("expected");
495     QTest::addColumn<QStringList>("insert");
496     QTest::addColumn<int>("position");
497
498     QTest::newRow("insert one row in the middle")
499         << (QStringList()
500             << "One"
501             << "Two"
502             << "Four"
503             << "Five")
504         << (QStringList()
505             << "One"
506             << "Two"
507             << "Three"
508             << "Four"
509             << "Five")
510         << (QStringList()
511             << "Three")
512         << 2;
513
514     QTest::newRow("insert one row in the beginning")
515         << (QStringList()
516             << "Two"
517             << "Three"
518             << "Four"
519             << "Five")
520         << (QStringList()
521             << "One"
522             << "Two"
523             << "Three"
524             << "Four"
525             << "Five")
526         << (QStringList()
527             << "One")
528         << 0;
529
530     QTest::newRow("insert one row in the end")
531         << (QStringList()
532             << "One"
533             << "Two"
534             << "Three"
535             << "Four")
536         << (QStringList()
537             << "One"
538             << "Two"
539             << "Three"
540             << "Four"
541             << "Five")
542         << (QStringList()
543             <<"Five")
544         << 4;
545 }
546
547 void tst_QSortFilterProxyModel::insertRows()
548 {
549     QFETCH(QStringList, initial);
550     QFETCH(QStringList, expected);
551     QFETCH(QStringList, insert);
552     QFETCH(int, position);
553     // prepare model
554     m_model->insertRows(0, initial.count(), QModelIndex());
555     //m_model->insertColumns(0, 1, QModelIndex());
556     QCOMPARE(m_model->columnCount(QModelIndex()), 1);
557     QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
558     for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
559         QModelIndex index = m_model->index(row, 0, QModelIndex());
560         m_model->setData(index, initial.at(row), Qt::DisplayRole);
561     }
562     // make sure the model correct before insert
563     for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
564         QModelIndex index = m_model->index(row, 0, QModelIndex());
565         QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
566     }
567     // make sure the proxy is correct before insert
568     for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
569         QModelIndex index = m_proxy->index(row, 0, QModelIndex());
570         QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
571     }
572
573     // insert the row
574     m_proxy->insertRows(position, insert.count(), QModelIndex());
575     QCOMPARE(m_model->rowCount(QModelIndex()), expected.count());
576     QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count());
577
578     // set the data for the inserted row
579     for (int i = 0; i < insert.count(); ++i) {
580         QModelIndex index = m_proxy->index(position + i, 0, QModelIndex());
581         m_proxy->setData(index, insert.at(i), Qt::DisplayRole);
582     }
583
584     // make sure the model correct after insert
585     for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
586         QModelIndex index = m_model->index(row, 0, QModelIndex());
587         QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), expected.at(row));
588     }
589
590     // make sure the proxy is correct after insert
591     for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
592         QModelIndex index = m_proxy->index(row, 0, QModelIndex());
593         QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
594     }
595 }
596
597 void tst_QSortFilterProxyModel::prependRow()
598 {
599     //this tests that data is correctly handled by the sort filter when prepending a row
600     QStandardItemModel model;
601     QSortFilterProxyModel proxy;
602     proxy.setSourceModel(&model);
603
604     QStandardItem item("root");
605     model.appendRow(&item);
606
607     QStandardItem sub("sub");
608     item.appendRow(&sub);
609
610     sub.appendRow(new QStandardItem("test1"));
611     sub.appendRow(new QStandardItem("test2"));
612
613     QStandardItem sub2("sub2");
614     sub2.appendRow(new QStandardItem("sub3"));
615     item.insertRow(0, &sub2);
616
617     QModelIndex index_sub2 = proxy.mapFromSource(model.indexFromItem(&sub2));
618
619     QCOMPARE(sub2.rowCount(), proxy.rowCount(index_sub2));
620     QCOMPARE(proxy.rowCount(QModelIndex()), 1); //only the "root" item is there
621 }
622
623 void tst_QSortFilterProxyModel::removeRows_data()
624 {
625     QTest::addColumn<QStringList>("initial");
626     QTest::addColumn<int>("sortOrder");
627     QTest::addColumn<QString>("filter");
628     QTest::addColumn<int>("position");
629     QTest::addColumn<int>("count");
630     QTest::addColumn<bool>("success");
631     QTest::addColumn<QStringList>("expectedProxy");
632     QTest::addColumn<QStringList>("expectedSource");
633
634     QTest::newRow("remove one row in the middle [no sorting/filter]")
635         << (QStringList()
636             << "One"
637             << "Two"
638             << "Three"
639             << "Four"
640             << "Five")
641         << -1 // no sorting
642         << QString() // no filter
643         << 2 // position
644         << 1 // count
645         << true // success
646         << (QStringList() // expectedProxy
647             << "One"
648             << "Two"
649             << "Four"
650             << "Five")
651         << (QStringList() // expectedSource
652             << "One"
653             << "Two"
654             << "Four"
655             << "Five");
656
657     QTest::newRow("remove one row in the beginning [no sorting/filter]")
658         << (QStringList()
659             << "One"
660             << "Two"
661             << "Three"
662             << "Four"
663             << "Five")
664         << -1 // no sorting
665         << QString() // no filter
666         << 0 // position
667         << 1 // count
668         << true // success
669         << (QStringList() // expectedProxy
670             << "Two"
671             << "Three"
672             << "Four"
673             << "Five")
674         << (QStringList() // expectedSource
675             << "Two"
676             << "Three"
677             << "Four"
678             << "Five");
679
680     QTest::newRow("remove one row in the end [no sorting/filter]")
681         << (QStringList()
682             << "One"
683             << "Two"
684             << "Three"
685             << "Four"
686             << "Five")
687         << -1 // no sorting
688         << QString() // no filter
689         << 4 // position
690         << 1 // count
691         << true // success
692         << (QStringList() // expectedProxy
693             << "One"
694             << "Two"
695             << "Three"
696             << "Four")
697         << (QStringList() // expectedSource
698             << "One"
699             << "Two"
700             << "Three"
701             << "Four");
702
703     QTest::newRow("remove all [no sorting/filter]")
704         << (QStringList()
705             << "One"
706             << "Two"
707             << "Three"
708             << "Four"
709             << "Five")
710         << -1 // no sorting
711         << QString() // no filter
712         << 0 // position
713         << 5 // count
714         << true // success
715         << QStringList() // expectedProxy
716         << QStringList(); // expectedSource
717
718     QTest::newRow("remove one row past the end [no sorting/filter]")
719         << (QStringList()
720             << "One"
721             << "Two"
722             << "Three"
723             << "Four"
724             << "Five")
725         << -1 // no sorting
726         << QString() // no filter
727         << 5 // position
728         << 1 // count
729         << false // success
730         << (QStringList() // expectedProxy
731             << "One"
732             << "Two"
733             << "Three"
734             << "Four"
735             << "Five")
736         << (QStringList() // expectedSource
737             << "One"
738             << "Two"
739             << "Three"
740             << "Four"
741             << "Five");
742
743     QTest::newRow("remove row -1 [no sorting/filter]")
744         << (QStringList()
745             << "One"
746             << "Two"
747             << "Three"
748             << "Four"
749             << "Five")
750         << -1 // no sorting
751         << QString() // no filter
752         << -1 // position
753         << 1 // count
754         << false // success
755         << (QStringList() // expectedProxy
756             << "One"
757             << "Two"
758             << "Three"
759             << "Four"
760             << "Five")
761         << (QStringList() // expectedSource
762             << "One"
763             << "Two"
764             << "Three"
765             << "Four"
766             << "Five");
767
768     QTest::newRow("remove three rows in the middle [no sorting/filter]")
769         << (QStringList()
770             << "One"
771             << "Two"
772             << "Three"
773             << "Four"
774             << "Five")
775         << -1 // no sorting
776         << QString() // no filter
777         << 1 // position
778         << 3 // count
779         << true // success
780         << (QStringList() // expectedProxy
781             << "One"
782             << "Five")
783         << (QStringList() // expectedSource
784             << "One"
785             << "Five");
786
787     QTest::newRow("remove one row in the middle [ascending sorting, no filter]")
788         << (QStringList()
789             << "1"
790             << "5"
791             << "2"
792             << "4"
793             << "3")
794         << static_cast<int>(Qt::AscendingOrder)
795         << QString() // no filter
796         << 2 // position
797         << 1 // count
798         << true // success
799         << (QStringList() // expectedProxy
800             << "1"
801             << "2"
802             << "4"
803             << "5")
804         << (QStringList() // expectedSource
805             << "1"
806             << "5"
807             << "2"
808             << "4");
809
810     QTest::newRow("remove two rows in the middle [ascending sorting, no filter]")
811         << (QStringList()
812             << "1"
813             << "5"
814             << "2"
815             << "4"
816             << "3")
817         << static_cast<int>(Qt::AscendingOrder)
818         << QString() // no filter
819         << 2 // position
820         << 2 // count
821         << true // success
822         << (QStringList() // expectedProxy
823             << "1"
824             << "2"
825             << "5")
826         << (QStringList() // expectedSource
827             << "1"
828             << "5"
829             << "2");
830
831     QTest::newRow("remove two rows in the middle [descending sorting, no filter]")
832         << (QStringList()
833             << "1"
834             << "5"
835             << "2"
836             << "4"
837             << "3")
838         << static_cast<int>(Qt::DescendingOrder)
839         << QString() // no filter
840         << 2 // position
841         << 2 // count
842         << true // success
843         << (QStringList() // expectedProxy
844             << "5"
845             << "4"
846             << "1")
847         << (QStringList() // expectedSource
848             << "1"
849             << "5"
850             << "4");
851
852     QTest::newRow("remove one row in the middle [no sorting, filter=5|2|3]")
853         << (QStringList()
854             << "1"
855             << "5"
856             << "2"
857             << "4"
858             << "3")
859         << -1 // no sorting
860         << QString("5|2|3")
861         << 1 // position
862         << 1 // count
863         << true // success
864         << (QStringList() // expectedProxy
865             << "5"
866             << "3")
867         << (QStringList() // expectedSource
868             << "1"
869             << "5"
870             << "4"
871             << "3");
872
873     QTest::newRow("remove all [ascending sorting, no filter]")
874         << (QStringList()
875             << "1"
876             << "5"
877             << "2"
878             << "4"
879             << "3")
880         << static_cast<int>(Qt::AscendingOrder)
881         << QString() // no filter
882         << 0 // position
883         << 5 // count
884         << true // success
885         << QStringList() // expectedProxy
886         << QStringList(); // expectedSource
887 }
888
889 void tst_QSortFilterProxyModel::removeRows()
890 {
891     QFETCH(QStringList, initial);
892     QFETCH(int, sortOrder);
893     QFETCH(QString, filter);
894     QFETCH(int, position);
895     QFETCH(int, count);
896     QFETCH(bool, success);
897     QFETCH(QStringList, expectedProxy);
898     QFETCH(QStringList, expectedSource);
899
900     QStandardItemModel model;
901     QSortFilterProxyModel proxy;
902     proxy.setSourceModel(&model);
903
904     // prepare model
905     foreach (QString s, initial)
906         model.appendRow(new QStandardItem(s));
907
908     if (sortOrder != -1)
909         proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
910     if (!filter.isEmpty())
911         proxy.setFilterRegExp(QRegExp(filter));
912
913     // remove the rows
914     QCOMPARE(proxy.removeRows(position, count, QModelIndex()), success);
915     QCOMPARE(model.rowCount(QModelIndex()), expectedSource.count());
916     QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxy.count());
917
918     // make sure the model is correct after remove
919     for (int row = 0; row < model.rowCount(QModelIndex()); ++row)
920         QCOMPARE(model.item(row)->text(), expectedSource.at(row));
921
922     // make sure the proxy is correct after remove
923     for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
924         QModelIndex index = proxy.index(row, 0, QModelIndex());
925         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expectedProxy.at(row));
926     }
927 }
928
929 class MyFilteredColumnProxyModel : public QSortFilterProxyModel
930 {
931     Q_OBJECT
932 public:
933     MyFilteredColumnProxyModel(QObject *parent = 0)
934         : QSortFilterProxyModel(parent) { }
935 protected:
936     bool filterAcceptsColumn(int sourceColumn, const QModelIndex &) const
937     {
938         QString key = sourceModel()->headerData(sourceColumn, Qt::Horizontal).toString();
939         return key.contains(filterRegExp());
940     }
941 };
942
943 void tst_QSortFilterProxyModel::removeColumns_data()
944 {
945     QTest::addColumn<QStringList>("initial");
946     QTest::addColumn<QString>("filter");
947     QTest::addColumn<int>("position");
948     QTest::addColumn<int>("count");
949     QTest::addColumn<bool>("success");
950     QTest::addColumn<QStringList>("expectedProxy");
951     QTest::addColumn<QStringList>("expectedSource");
952
953     QTest::newRow("remove one column in the middle [no filter]")
954         << (QStringList()
955             << "1"
956             << "2"
957             << "3"
958             << "4"
959             << "5")
960         << QString() // no filter
961         << 2 // position
962         << 1 // count
963         << true // success
964         << (QStringList() // expectedProxy
965             << "1"
966             << "2"
967             << "4"
968             << "5")
969         << (QStringList() // expectedSource
970             << "1"
971             << "2"
972             << "4"
973             << "5");
974
975     QTest::newRow("remove one column in the end [no filter]")
976         << (QStringList()
977             << "1"
978             << "2"
979             << "3"
980             << "4"
981             << "5")
982         << QString() // no filter
983         << 4 // position
984         << 1 // count
985         << true // success
986         << (QStringList() // expectedProxy
987             << "1"
988             << "2"
989             << "3"
990             << "4")
991         << (QStringList() // expectedSource
992             << "1"
993             << "2"
994             << "3"
995             << "4");
996
997     QTest::newRow("remove one column past the end [no filter]")
998         << (QStringList()
999             << "1"
1000             << "2"
1001             << "3"
1002             << "4"
1003             << "5")
1004         << QString() // no filter
1005         << 5 // position
1006         << 1 // count
1007         << false // success
1008         << (QStringList() // expectedProxy
1009             << "1"
1010             << "2"
1011             << "3"
1012             << "4"
1013             << "5")
1014         << (QStringList() // expectedSource
1015             << "1"
1016             << "2"
1017             << "3"
1018             << "4"
1019             << "5");
1020
1021     QTest::newRow("remove column -1 [no filter]")
1022         << (QStringList()
1023             << "1"
1024             << "2"
1025             << "3"
1026             << "4"
1027             << "5")
1028         << QString() // no filter
1029         << -1 // position
1030         << 1 // count
1031         << false // success
1032         << (QStringList() // expectedProxy
1033             << "1"
1034             << "2"
1035             << "3"
1036             << "4"
1037             << "5")
1038         << (QStringList() // expectedSource
1039             << "1"
1040             << "2"
1041             << "3"
1042             << "4"
1043             << "5");
1044
1045     QTest::newRow("remove all columns [no filter]")
1046         << (QStringList()
1047             << "1"
1048             << "2"
1049             << "3"
1050             << "4"
1051             << "5")
1052         << QString() // no filter
1053         << 0 // position
1054         << 5 // count
1055         << true // success
1056         << QStringList() // expectedProxy
1057         << QStringList(); // expectedSource
1058
1059     QTest::newRow("remove one column in the middle [filter=1|3|5]")
1060         << (QStringList()
1061             << "1"
1062             << "2"
1063             << "3"
1064             << "4"
1065             << "5")
1066         << QString("1|3|5")
1067         << 1 // position
1068         << 1 // count
1069         << true // success
1070         << (QStringList() // expectedProxy
1071             << "1"
1072             << "5")
1073         << (QStringList() // expectedSource
1074             << "1"
1075             << "2"
1076             << "4"
1077             << "5");
1078
1079     QTest::newRow("remove one column in the end [filter=1|3|5]")
1080         << (QStringList()
1081             << "1"
1082             << "2"
1083             << "3"
1084             << "4"
1085             << "5")
1086         << QString("1|3|5")
1087         << 2 // position
1088         << 1 // count
1089         << true // success
1090         << (QStringList() // expectedProxy
1091             << "1"
1092             << "3")
1093         << (QStringList() // expectedSource
1094             << "1"
1095             << "2"
1096             << "3"
1097             << "4");
1098
1099     QTest::newRow("remove one column past the end [filter=1|3|5]")
1100         << (QStringList()
1101             << "1"
1102             << "2"
1103             << "3"
1104             << "4"
1105             << "5")
1106         << QString("1|3|5")
1107         << 3 // position
1108         << 1 // count
1109         << false // success
1110         << (QStringList() // expectedProxy
1111             << "1"
1112             << "3"
1113             << "5")
1114         << (QStringList() // expectedSource
1115             << "1"
1116             << "2"
1117             << "3"
1118             << "4"
1119             << "5");
1120
1121     QTest::newRow("remove all columns [filter=1|3|5]")
1122         << (QStringList()
1123             << "1"
1124             << "2"
1125             << "3"
1126             << "4"
1127             << "5")
1128         << QString("1|3|5")
1129         << 0 // position
1130         << 3 // count
1131         << true // success
1132         << QStringList() // expectedProxy
1133         << (QStringList() // expectedSource
1134             << "2"
1135             << "4");
1136 }
1137
1138 void tst_QSortFilterProxyModel::removeColumns()
1139 {
1140     QFETCH(QStringList, initial);
1141     QFETCH(QString, filter);
1142     QFETCH(int, position);
1143     QFETCH(int, count);
1144     QFETCH(bool, success);
1145     QFETCH(QStringList, expectedProxy);
1146     QFETCH(QStringList, expectedSource);
1147
1148     QStandardItemModel model;
1149     MyFilteredColumnProxyModel proxy;
1150     proxy.setSourceModel(&model);
1151     if (!filter.isEmpty())
1152         proxy.setFilterRegExp(QRegExp(filter));
1153
1154     // prepare model
1155     model.setHorizontalHeaderLabels(initial);
1156
1157     // remove the columns
1158     QCOMPARE(proxy.removeColumns(position, count, QModelIndex()), success);
1159     QCOMPARE(model.columnCount(QModelIndex()), expectedSource.count());
1160     QCOMPARE(proxy.columnCount(QModelIndex()), expectedProxy.count());
1161
1162     // make sure the model is correct after remove
1163     for (int col = 0; col < model.columnCount(QModelIndex()); ++col)
1164         QCOMPARE(model.horizontalHeaderItem(col)->text(), expectedSource.at(col));
1165
1166     // make sure the proxy is correct after remove
1167     for (int col = 0; col < proxy.columnCount(QModelIndex()); ++col) {
1168         QCOMPARE(proxy.headerData(col, Qt::Horizontal, Qt::DisplayRole).toString(),
1169                  expectedProxy.at(col));
1170     }
1171 }
1172
1173 void tst_QSortFilterProxyModel::filterColumns_data()
1174 {
1175     QTest::addColumn<QString>("pattern");
1176     QTest::addColumn<QStringList>("initial");
1177     QTest::addColumn<bool>("data");
1178
1179     QTest::newRow("all") << "a"
1180                          << (QStringList()
1181                              << "delta"
1182                              << "yankee"
1183                              << "bravo"
1184                              << "lima")
1185                          << true;
1186
1187     QTest::newRow("some") << "lie"
1188                           << (QStringList()
1189                               << "charlie"
1190                               << "juliet"
1191                               << "tango"
1192                               << "hotel")
1193                           << true;
1194
1195     QTest::newRow("nothing") << "zoo"
1196                              << (QStringList()
1197                                  << "foxtrot"
1198                                  << "uniform"
1199                                  << "alpha"
1200                                  << "golf")
1201                              << false;
1202 }
1203
1204 void tst_QSortFilterProxyModel::filterColumns()
1205 {
1206     QFETCH(QString, pattern);
1207     QFETCH(QStringList, initial);
1208     QFETCH(bool, data);
1209     // prepare model
1210     m_model->setColumnCount(initial.count());
1211     m_model->setRowCount(1);
1212     QCOMPARE(m_model->columnCount(QModelIndex()), initial.count());
1213     QCOMPARE(m_model->rowCount(QModelIndex()), 1);
1214     // set data
1215     QCOMPARE(m_model->rowCount(QModelIndex()), 1);
1216     for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) {
1217         QModelIndex index = m_model->index(0, col, QModelIndex());
1218         m_model->setData(index, initial.at(col), Qt::DisplayRole);
1219     }
1220     m_proxy->setFilterRegExp(pattern);
1221     m_proxy->setFilterKeyColumn(-1);
1222     // make sure the model is unchanged
1223     for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) {
1224         QModelIndex index = m_model->index(0, col, QModelIndex());
1225         QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(col));
1226     }
1227     // make sure the proxy is filtered
1228     QModelIndex index = m_proxy->index(0, 0, QModelIndex());
1229     QCOMPARE(index.isValid(), data);
1230 }
1231
1232 void tst_QSortFilterProxyModel::filter_data()
1233 {
1234     QTest::addColumn<QString>("pattern");
1235     QTest::addColumn<QStringList>("initial");
1236     QTest::addColumn<QStringList>("expected");
1237
1238     QTest::newRow("flat") << "e"
1239                           << (QStringList()
1240                            << "delta"
1241                            << "yankee"
1242                            << "bravo"
1243                            << "lima"
1244                            << "charlie"
1245                            << "juliet"
1246                            << "tango"
1247                            << "hotel"
1248                            << "uniform"
1249                            << "alpha"
1250                            << "echo"
1251                            << "golf"
1252                            << "quebec"
1253                            << "foxtrot"
1254                            << "india"
1255                            << "romeo"
1256                            << "november"
1257                            << "oskar"
1258                            << "zulu"
1259                            << "kilo"
1260                            << "whiskey"
1261                            << "mike"
1262                            << "papa"
1263                            << "sierra"
1264                            << "xray"
1265                            << "viktor")
1266                        << (QStringList()
1267                            << "delta"
1268                            << "yankee"
1269                            << "charlie"
1270                            << "juliet"
1271                            << "hotel"
1272                            << "echo"
1273                            << "quebec"
1274                            << "romeo"
1275                            << "november"
1276                            << "whiskey"
1277                            << "mike"
1278                            << "sierra");
1279 }
1280
1281 void tst_QSortFilterProxyModel::filter()
1282 {
1283     QFETCH(QString, pattern);
1284     QFETCH(QStringList, initial);
1285     QFETCH(QStringList, expected);
1286     // prepare model
1287     QVERIFY(m_model->insertRows(0, initial.count(), QModelIndex()));
1288     QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
1289     // set data
1290     QCOMPARE(m_model->columnCount(QModelIndex()), 1);
1291     for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
1292         QModelIndex index = m_model->index(row, 0, QModelIndex());
1293         m_model->setData(index, initial.at(row), Qt::DisplayRole);
1294     }
1295     m_proxy->setFilterRegExp(pattern);
1296     // make sure the proxy is unfiltered
1297     QCOMPARE(m_proxy->columnCount(QModelIndex()), 1);
1298     QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count());
1299     // make sure the model is unchanged
1300     for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
1301         QModelIndex index = m_model->index(row, 0, QModelIndex());
1302         QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
1303     }
1304     // make sure the proxy is filtered
1305     for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
1306         QModelIndex index = m_proxy->index(row, 0, QModelIndex());
1307         QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
1308     }
1309 }
1310
1311 void tst_QSortFilterProxyModel::filterHierarchy_data()
1312 {
1313     QTest::addColumn<QString>("pattern");
1314     QTest::addColumn<QStringList>("initial");
1315     QTest::addColumn<QStringList>("expected");
1316
1317     QTest::newRow("flat") << ".*oo"
1318         << (QStringList()
1319             << "foo" << "boo" << "baz" << "moo" << "laa" << "haa")
1320         << (QStringList()
1321             << "foo" << "boo" << "moo");
1322
1323     QTest::newRow("simple hierarchy") << "b.*z"
1324         << (QStringList() << "baz" << "<" << "boz" << "<" << "moo" << ">" << ">")
1325         << (QStringList() << "baz" << "<" << "boz" << ">");
1326 }
1327
1328 void tst_QSortFilterProxyModel::filterHierarchy()
1329 {
1330     QFETCH(QString, pattern);
1331     QFETCH(QStringList, initial);
1332     QFETCH(QStringList, expected);
1333     buildHierarchy(initial, m_model);
1334     m_proxy->setFilterRegExp(pattern);
1335     checkHierarchy(initial, m_model);
1336     checkHierarchy(expected, m_proxy);
1337 }
1338
1339 void tst_QSortFilterProxyModel::buildHierarchy(const QStringList &l, QAbstractItemModel *m)
1340 {
1341     int ind = 0;
1342     int row = 0;
1343     QStack<int> row_stack;
1344     QModelIndex parent;
1345     QStack<QModelIndex> parent_stack;
1346     for (int i = 0; i < l.count(); ++i) {
1347         QString token = l.at(i);
1348         if (token == "<") { // start table
1349             ++ind;
1350             parent_stack.push(parent);
1351             row_stack.push(row);
1352             parent = m->index(row - 1, 0, parent);
1353             row = 0;
1354             QVERIFY(m->insertColumns(0, 1, parent)); // add column
1355         } else if (token == ">") { // end table
1356             --ind;
1357             parent = parent_stack.pop();
1358             row = row_stack.pop();
1359         } else { // append row
1360             QVERIFY(m->insertRows(row, 1, parent));
1361             QModelIndex index = m->index(row, 0, parent);
1362             QVERIFY(index.isValid());
1363             m->setData(index, token, Qt::DisplayRole);
1364             ++row;
1365         }
1366     }
1367 }
1368
1369 void tst_QSortFilterProxyModel::checkHierarchy(const QStringList &l, const QAbstractItemModel *m)
1370 {
1371     int row = 0;
1372     int indent = 0;
1373     QStack<int> row_stack;
1374     QModelIndex parent;
1375     QStack<QModelIndex> parent_stack;
1376     for (int i = 0; i < l.count(); ++i) {
1377         QString token = l.at(i);
1378         if (token == "<") { // start table
1379             ++indent;
1380             parent_stack.push(parent);
1381             row_stack.push(row);
1382             parent = m->index(row - 1, 0, parent);
1383             QVERIFY(parent.isValid());
1384             row = 0;
1385         } else if (token == ">") { // end table
1386             --indent;
1387             parent = parent_stack.pop();
1388             row = row_stack.pop();
1389         } else { // compare row
1390             QModelIndex index = m->index(row, 0, parent);
1391             QVERIFY(index.isValid());
1392             QString str =  m->data(index, Qt::DisplayRole).toString();
1393             QCOMPARE(str, token);
1394             ++row;
1395         }
1396     }
1397 }
1398
1399 class TestModel: public QAbstractTableModel
1400 {
1401 public:
1402     int rowCount(const QModelIndex &) const { return 10000; }
1403     int columnCount(const QModelIndex &) const { return 1; }
1404     QVariant data(const QModelIndex &index, int role) const
1405     {
1406         if (role != Qt::DisplayRole)
1407             return QVariant();
1408         return QString::number(index.row());
1409     }
1410 };
1411
1412 void tst_QSortFilterProxyModel::filterTable()
1413 {
1414     TestModel model;
1415     QSortFilterProxyModel filter;
1416     filter.setSourceModel(&model);
1417     filter.setFilterRegExp("9");
1418
1419     for (int i = 0; i < filter.rowCount(); ++i)
1420         QVERIFY(filter.data(filter.index(i, 0)).toString().contains("9"));
1421 }
1422
1423 void tst_QSortFilterProxyModel::insertAfterSelect()
1424 {
1425     QStandardItemModel model(10, 2);
1426     for (int i = 0; i<10;i++)
1427         model.setData(model.index(i, 0), QVariant(i));
1428     QSortFilterProxyModel filter;
1429     filter.setSourceModel(&model);
1430     QTreeView view;
1431     view.setModel(&filter);
1432     view.show();
1433     QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex()));
1434     QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model());
1435     QVERIFY(firstIndex.isValid());
1436     int itemOffset = view.visualRect(firstIndex).width() / 2;
1437     QPoint p(itemOffset, 1);
1438     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
1439     QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
1440     model.insertRows(5, 1, QModelIndex());
1441     QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection
1442 }
1443
1444 void tst_QSortFilterProxyModel::removeAfterSelect()
1445 {
1446     QStandardItemModel model(10, 2);
1447     for (int i = 0; i<10;i++)
1448         model.setData(model.index(i, 0), QVariant(i));
1449     QSortFilterProxyModel filter;
1450     filter.setSourceModel(&model);
1451     QTreeView view;
1452     view.setModel(&filter);
1453     view.show();
1454     QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex()));
1455     QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model());
1456     QVERIFY(firstIndex.isValid());
1457     int itemOffset = view.visualRect(firstIndex).width() / 2;
1458     QPoint p(itemOffset, 1);
1459     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
1460     QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
1461     model.removeRows(5, 1, QModelIndex());
1462     QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection
1463 }
1464
1465 void tst_QSortFilterProxyModel::filterCurrent()
1466 {
1467     QStandardItemModel model(2, 1);
1468     model.setData(model.index(0, 0), QString("AAA"));
1469     model.setData(model.index(1, 0), QString("BBB"));
1470     QSortFilterProxyModel proxy;
1471     proxy.setSourceModel(&model);
1472     QTreeView view;
1473
1474     view.show();
1475     view.setModel(&proxy);
1476     QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)));
1477     QVERIFY(spy.isValid());
1478
1479     view.setCurrentIndex(proxy.index(0, 0));
1480     QCOMPARE(spy.count(), 1);
1481     proxy.setFilterRegExp(QRegExp("^B"));
1482     QCOMPARE(spy.count(), 2);
1483 }
1484
1485 void tst_QSortFilterProxyModel::changeSourceLayout()
1486 {
1487     QStandardItemModel model(2, 1);
1488     model.setData(model.index(0, 0), QString("b"));
1489     model.setData(model.index(1, 0), QString("a"));
1490     QSortFilterProxyModel proxy;
1491     proxy.setSourceModel(&model);
1492
1493     QList<QPersistentModelIndex> persistentSourceIndexes;
1494     QList<QPersistentModelIndex> persistentProxyIndexes;
1495     for (int row = 0; row < model.rowCount(); ++row) {
1496         persistentSourceIndexes.append(model.index(row, 0));
1497         persistentProxyIndexes.append(proxy.index(row, 0));
1498     }
1499
1500     // change layout of source model
1501     model.sort(0, Qt::AscendingOrder);
1502
1503     for (int row = 0; row < model.rowCount(); ++row) {
1504         QCOMPARE(persistentProxyIndexes.at(row).row(),
1505                  persistentSourceIndexes.at(row).row());
1506     }
1507 }
1508
1509 void tst_QSortFilterProxyModel::removeSourceRows_data()
1510 {
1511     QTest::addColumn<QStringList>("sourceItems");
1512     QTest::addColumn<int>("start");
1513     QTest::addColumn<int>("count");
1514     QTest::addColumn<int>("sortOrder");
1515     QTest::addColumn<IntPairList>("expectedRemovedProxyIntervals");
1516     QTest::addColumn<QStringList>("expectedProxyItems");
1517
1518     QTest::newRow("remove one, no sorting")
1519         << (QStringList() << "a" << "b") // sourceItems
1520         << 0 // start
1521         << 1 // count
1522         << -1 // sortOrder (no sorting)
1523         << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals
1524         << (QStringList() << "b") // expectedProxyItems
1525         ;
1526     QTest::newRow("remove one, ascending sort (same order)")
1527         << (QStringList() << "a" << "b") // sourceItems
1528         << 0 // start
1529         << 1 // count
1530         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1531         << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals
1532         << (QStringList() << "b") // expectedProxyItems
1533         ;
1534     QTest::newRow("remove one, ascending sort (reverse order)")
1535         << (QStringList() << "b" << "a") // sourceItems
1536         << 0 // start
1537         << 1 // count
1538         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1539         << (IntPairList() << IntPair(1, 1)) // expectedRemovedIntervals
1540         << (QStringList() << "a") // expectedProxyItems
1541         ;
1542     QTest::newRow("remove two, multiple proxy intervals")
1543         << (QStringList() << "c" << "d" << "a" << "b") // sourceItems
1544         << 1 // start
1545         << 2 // count
1546         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1547         << (IntPairList() << IntPair(3, 3) << IntPair(0, 0)) // expectedRemovedIntervals
1548         << (QStringList() << "b" << "c") // expectedProxyItems
1549         ;
1550     QTest::newRow("remove three, multiple proxy intervals")
1551         << (QStringList() << "b" << "d" << "f" << "a" << "c" << "e") // sourceItems
1552         << 3 // start
1553         << 3 // count
1554         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1555         << (IntPairList() << IntPair(4, 4) << IntPair(2, 2) << IntPair(0, 0)) // expectedRemovedIntervals
1556         << (QStringList() << "b" << "d" << "f") // expectedProxyItems
1557         ;
1558     QTest::newRow("remove all, single proxy intervals")
1559         << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
1560         << 0 // start
1561         << 6 // count
1562         << static_cast<int>(Qt::DescendingOrder) // sortOrder
1563         << (IntPairList() << IntPair(0, 5)) // expectedRemovedIntervals
1564         << QStringList() // expectedProxyItems
1565         ;
1566 }
1567
1568 // Check that correct proxy model rows are removed when rows are removed
1569 // from the source model
1570 void tst_QSortFilterProxyModel::removeSourceRows()
1571 {
1572     QFETCH(QStringList, sourceItems);
1573     QFETCH(int, start);
1574     QFETCH(int, count);
1575     QFETCH(int, sortOrder);
1576     QFETCH(IntPairList, expectedRemovedProxyIntervals);
1577     QFETCH(QStringList, expectedProxyItems);
1578
1579     QStandardItemModel model;
1580     QSortFilterProxyModel proxy;
1581
1582     proxy.setSourceModel(&model);
1583     model.insertColumns(0, 1);
1584     model.insertRows(0, sourceItems.count());
1585
1586     for (int i = 0; i < sourceItems.count(); ++i) {
1587         QModelIndex sindex = model.index(i, 0, QModelIndex());
1588         model.setData(sindex, sourceItems.at(i), Qt::DisplayRole);
1589         QModelIndex pindex = proxy.index(i, 0, QModelIndex());
1590         QCOMPARE(proxy.data(pindex, Qt::DisplayRole), model.data(sindex, Qt::DisplayRole));
1591     }
1592
1593     if (sortOrder != -1)
1594         proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
1595     (void)proxy.rowCount(QModelIndex()); // force mapping
1596
1597     QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
1598     QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
1599     QSignalSpy aboutToRemoveSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)));
1600     QSignalSpy aboutToInsertSpy(&proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)));
1601
1602     QVERIFY(removeSpy.isValid());
1603     QVERIFY(insertSpy.isValid());
1604     QVERIFY(aboutToRemoveSpy.isValid());
1605     QVERIFY(aboutToInsertSpy.isValid());
1606
1607     model.removeRows(start, count, QModelIndex());
1608
1609     QCOMPARE(aboutToRemoveSpy.count(), expectedRemovedProxyIntervals.count());
1610     for (int i = 0; i < aboutToRemoveSpy.count(); ++i) {
1611         QList<QVariant> args = aboutToRemoveSpy.at(i);
1612         QVERIFY(args.at(1).type() == QVariant::Int);
1613         QVERIFY(args.at(2).type() == QVariant::Int);
1614         QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first);
1615         QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second);
1616     }
1617     QCOMPARE(removeSpy.count(), expectedRemovedProxyIntervals.count());
1618     for (int i = 0; i < removeSpy.count(); ++i) {
1619         QList<QVariant> args = removeSpy.at(i);
1620         QVERIFY(args.at(1).type() == QVariant::Int);
1621         QVERIFY(args.at(2).type() == QVariant::Int);
1622         QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first);
1623         QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second);
1624     }
1625
1626     QCOMPARE(insertSpy.count(), 0);
1627     QCOMPARE(aboutToInsertSpy.count(), 0);
1628
1629     QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxyItems.count());
1630     for (int i = 0; i < expectedProxyItems.count(); ++i) {
1631         QModelIndex pindex = proxy.index(i, 0, QModelIndex());
1632         QCOMPARE(proxy.data(pindex, Qt::DisplayRole).toString(), expectedProxyItems.at(i));
1633     }
1634 }
1635
1636 void tst_QSortFilterProxyModel::insertSourceRows_data()
1637 {
1638     QTest::addColumn<QStringList>("sourceItems");
1639     QTest::addColumn<int>("start");
1640     QTest::addColumn<QStringList>("newItems");
1641     QTest::addColumn<int>("sortOrder");
1642     QTest::addColumn<QStringList>("proxyItems");
1643
1644     QTest::newRow("insert (1)")
1645         << (QStringList() << "c" << "b") // sourceItems
1646         << 1 // start
1647         << (QStringList() << "a") // newItems
1648         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1649         << (QStringList() << "a" << "b" << "c") // proxyItems
1650         ;
1651
1652     QTest::newRow("insert (2)")
1653         << (QStringList() << "d" << "b" << "c") // sourceItems
1654         << 3 // start
1655         << (QStringList() << "a") // newItems
1656         << static_cast<int>(Qt::DescendingOrder) // sortOrder
1657         << (QStringList() << "d" << "c" << "b" << "a") // proxyItems
1658         ;
1659 }
1660
1661 // Check that rows are inserted at correct position in proxy model when
1662 // rows are inserted into the source model
1663 void tst_QSortFilterProxyModel::insertSourceRows()
1664 {
1665     QFETCH(QStringList, sourceItems);
1666     QFETCH(int, start);
1667     QFETCH(QStringList, newItems);
1668     QFETCH(int, sortOrder);
1669     QFETCH(QStringList, proxyItems);
1670
1671     QStandardItemModel model;
1672     QSortFilterProxyModel proxy;
1673     proxy.setDynamicSortFilter(true);
1674
1675     proxy.setSourceModel(&model);
1676     model.insertColumns(0, 1);
1677     model.insertRows(0, sourceItems.count());
1678
1679     for (int i = 0; i < sourceItems.count(); ++i) {
1680         QModelIndex index = model.index(i, 0, QModelIndex());
1681         model.setData(index, sourceItems.at(i), Qt::DisplayRole);
1682     }
1683
1684     proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
1685     (void)proxy.rowCount(QModelIndex()); // force mapping
1686
1687     model.insertRows(start, newItems.size(), QModelIndex());
1688
1689     QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count());
1690     for (int i = 0; i < newItems.count(); ++i) {
1691         QModelIndex index = model.index(start + i, 0, QModelIndex());
1692         model.setData(index, newItems.at(i), Qt::DisplayRole);
1693     }
1694
1695     for (int i = 0; i < proxyItems.count(); ++i) {
1696         QModelIndex index = proxy.index(i, 0, QModelIndex());
1697         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i));
1698     }
1699 }
1700
1701 void tst_QSortFilterProxyModel::changeFilter_data()
1702 {
1703     QTest::addColumn<QStringList>("sourceItems");
1704     QTest::addColumn<int>("sortOrder");
1705     QTest::addColumn<QString>("initialFilter");
1706     QTest::addColumn<IntPairList>("initialRemoveIntervals");
1707     QTest::addColumn<QStringList>("initialProxyItems");
1708     QTest::addColumn<QString>("finalFilter");
1709     QTest::addColumn<IntPairList>("finalRemoveIntervals");
1710     QTest::addColumn<IntPairList>("insertIntervals");
1711     QTest::addColumn<QStringList>("finalProxyItems");
1712
1713     QTest::newRow("filter (1)")
1714         << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
1715         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1716         << "a|b|c" // initialFilter
1717         << (IntPairList() << IntPair(3, 5)) // initialRemoveIntervals
1718         << (QStringList() << "a" << "b" << "c") // initialProxyItems
1719         << "b|d|f" // finalFilter
1720         << (IntPairList() << IntPair(2, 2) << IntPair(0, 0)) // finalRemoveIntervals
1721         << (IntPairList() << IntPair(1, 2)) // insertIntervals
1722         << (QStringList() << "b" << "d" << "f") // finalProxyItems
1723         ;
1724
1725     QTest::newRow("filter (2)")
1726         << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
1727         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1728         << "a|c|e" // initialFilter
1729         << (IntPairList() << IntPair(5, 5) << IntPair(3, 3) << IntPair(1, 1)) // initialRemoveIntervals
1730         << (QStringList() << "a" << "c" << "e") // initialProxyItems
1731         << "" // finalFilter
1732         << IntPairList() // finalRemoveIntervals
1733         << (IntPairList() << IntPair(3, 3) << IntPair(2, 2) << IntPair(1, 1)) // insertIntervals
1734         << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // finalProxyItems
1735         ;
1736
1737     QTest::newRow("filter (3)")
1738         << (QStringList() << "a" << "b" << "c") // sourceItems
1739         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1740         << "a" // initialFilter
1741         << (IntPairList() << IntPair(1, 2)) // initialRemoveIntervals
1742         << (QStringList() << "a") // initialProxyItems
1743         << "a" // finalFilter
1744         << IntPairList() // finalRemoveIntervals
1745         << IntPairList() // insertIntervals
1746         << (QStringList() << "a") // finalProxyItems
1747         ;
1748 }
1749
1750 // Check that rows are added/removed when filter changes
1751 void tst_QSortFilterProxyModel::changeFilter()
1752 {
1753     QFETCH(QStringList, sourceItems);
1754     QFETCH(int, sortOrder);
1755     QFETCH(QString, initialFilter);
1756     QFETCH(IntPairList, initialRemoveIntervals);
1757     QFETCH(QStringList, initialProxyItems);
1758     QFETCH(QString, finalFilter);
1759     QFETCH(IntPairList, finalRemoveIntervals);
1760     QFETCH(IntPairList, insertIntervals);
1761     QFETCH(QStringList, finalProxyItems);
1762
1763     QStandardItemModel model;
1764     QSortFilterProxyModel proxy;
1765
1766     proxy.setSourceModel(&model);
1767     model.insertColumns(0, 1);
1768     model.insertRows(0, sourceItems.count());
1769
1770     for (int i = 0; i < sourceItems.count(); ++i) {
1771         QModelIndex index = model.index(i, 0, QModelIndex());
1772         model.setData(index, sourceItems.at(i), Qt::DisplayRole);
1773     }
1774
1775     proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
1776     (void)proxy.rowCount(QModelIndex()); // force mapping
1777
1778     QSignalSpy initialRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
1779     QSignalSpy initialInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
1780
1781     QVERIFY(initialRemoveSpy.isValid());
1782     QVERIFY(initialInsertSpy.isValid());
1783
1784     proxy.setFilterRegExp(initialFilter);
1785
1786     QCOMPARE(initialRemoveSpy.count(), initialRemoveIntervals.count());
1787     QCOMPARE(initialInsertSpy.count(), 0);
1788     for (int i = 0; i < initialRemoveSpy.count(); ++i) {
1789         QList<QVariant> args = initialRemoveSpy.at(i);
1790         QVERIFY(args.at(1).type() == QVariant::Int);
1791         QVERIFY(args.at(2).type() == QVariant::Int);
1792         QCOMPARE(args.at(1).toInt(), initialRemoveIntervals.at(i).first);
1793         QCOMPARE(args.at(2).toInt(), initialRemoveIntervals.at(i).second);
1794     }
1795
1796     QCOMPARE(proxy.rowCount(QModelIndex()), initialProxyItems.count());
1797     for (int i = 0; i < initialProxyItems.count(); ++i) {
1798         QModelIndex index = proxy.index(i, 0, QModelIndex());
1799         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initialProxyItems.at(i));
1800     }
1801
1802     QSignalSpy finalRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
1803     QSignalSpy finalInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
1804
1805     QVERIFY(finalRemoveSpy.isValid());
1806     QVERIFY(finalInsertSpy.isValid());
1807
1808     proxy.setFilterRegExp(finalFilter);
1809
1810     QCOMPARE(finalRemoveSpy.count(), finalRemoveIntervals.count());
1811     for (int i = 0; i < finalRemoveSpy.count(); ++i) {
1812         QList<QVariant> args = finalRemoveSpy.at(i);
1813         QVERIFY(args.at(1).type() == QVariant::Int);
1814         QVERIFY(args.at(2).type() == QVariant::Int);
1815         QCOMPARE(args.at(1).toInt(), finalRemoveIntervals.at(i).first);
1816         QCOMPARE(args.at(2).toInt(), finalRemoveIntervals.at(i).second);
1817     }
1818
1819 #ifdef Q_OS_IRIX
1820     QEXPECT_FAIL("filter (2)", "Not reliable on IRIX", Abort);
1821 #endif
1822     QCOMPARE(finalInsertSpy.count(), insertIntervals.count());
1823     for (int i = 0; i < finalInsertSpy.count(); ++i) {
1824         QList<QVariant> args = finalInsertSpy.at(i);
1825         QVERIFY(args.at(1).type() == QVariant::Int);
1826         QVERIFY(args.at(2).type() == QVariant::Int);
1827         QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first);
1828         QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second);
1829     }
1830
1831     QCOMPARE(proxy.rowCount(QModelIndex()), finalProxyItems.count());
1832     for (int i = 0; i < finalProxyItems.count(); ++i) {
1833         QModelIndex index = proxy.index(i, 0, QModelIndex());
1834         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), finalProxyItems.at(i));
1835     }
1836 }
1837
1838 void tst_QSortFilterProxyModel::changeSourceData_data()
1839 {
1840     QTest::addColumn<QStringList>("sourceItems");
1841     QTest::addColumn<int>("sortOrder");
1842     QTest::addColumn<QString>("filter");
1843     QTest::addColumn<bool>("dynamic");
1844     QTest::addColumn<int>("row");
1845     QTest::addColumn<QString>("newValue");
1846     QTest::addColumn<IntPairList>("removeIntervals");
1847     QTest::addColumn<IntPairList>("insertIntervals");
1848     QTest::addColumn<QStringList>("proxyItems");
1849
1850     QTest::newRow("changeSourceData (1)")
1851         << (QStringList() << "c" << "b" << "a") // sourceItems
1852         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1853         << "" // filter
1854         << true // dynamic
1855         << 2 // row
1856         << "z" // newValue
1857         << IntPairList() // removeIntervals
1858         << IntPairList() // insertIntervals
1859         << (QStringList() << "b" << "c" << "z") // proxyItems
1860         ;
1861
1862     QTest::newRow("changeSourceData (2)")
1863         << (QStringList() << "b" << "c" << "z") // sourceItems
1864         << static_cast<int>(Qt::DescendingOrder) // sortOrder
1865         << "" // filter
1866         << true // dynamic
1867         << 1 // row
1868         << "a" // newValue
1869         << IntPairList() // removeIntervals
1870         << IntPairList() // insertIntervals
1871         << (QStringList() << "z" << "b" << "a") // proxyItems
1872         ;
1873
1874     QTest::newRow("changeSourceData (3)")
1875         << (QStringList() << "a" << "b") // sourceItems
1876         << static_cast<int>(Qt::DescendingOrder) // sortOrder
1877         << "" // filter
1878         << true // dynamic
1879         << 0 // row
1880         << "a" // newValue
1881         << IntPairList() // removeIntervals
1882         << IntPairList() // insertIntervals
1883         << (QStringList() << "b" << "a") // proxyItems
1884         ;
1885
1886     QTest::newRow("changeSourceData (4)")
1887         << (QStringList() << "a" << "b" << "c" << "d") // sourceItems
1888         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1889         << "a|c" // filter
1890         << true // dynamic
1891         << 1 // row
1892         << "x" // newValue
1893         << IntPairList() // removeIntervals
1894         << IntPairList() // insertIntervals
1895         << (QStringList() << "a" << "c") // proxyItems
1896         ;
1897
1898     QTest::newRow("changeSourceData (5)")
1899         << (QStringList() << "a" << "b" << "c" << "d") // sourceItems
1900         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1901         << "a|c|x" // filter
1902         << true // dynamic
1903         << 1 // row
1904         << "x" // newValue
1905         << IntPairList() // removeIntervals
1906         << (IntPairList() << IntPair(2, 2)) // insertIntervals
1907         << (QStringList() << "a" << "c" << "x") // proxyItems
1908         ;
1909
1910     QTest::newRow("changeSourceData (6)")
1911         << (QStringList() << "c" << "b" << "a") // sourceItems
1912         << static_cast<int>(Qt::AscendingOrder) // sortOrder
1913         << "" // filter
1914         << false // dynamic
1915         << 2 // row
1916         << "x" // newValue
1917         << IntPairList() // removeIntervals
1918         << IntPairList() // insertIntervals
1919         << (QStringList() << "x" << "b" << "c") // proxyItems
1920         ;
1921 }
1922
1923 void tst_QSortFilterProxyModel::changeSourceData()
1924 {
1925     QFETCH(QStringList, sourceItems);
1926     QFETCH(int, sortOrder);
1927     QFETCH(QString, filter);
1928     QFETCH(bool, dynamic);
1929     QFETCH(int, row);
1930     QFETCH(QString, newValue);
1931     QFETCH(IntPairList, removeIntervals);
1932     QFETCH(IntPairList, insertIntervals);
1933     QFETCH(QStringList, proxyItems);
1934
1935     QStandardItemModel model;
1936     QSortFilterProxyModel proxy;
1937
1938     proxy.setDynamicSortFilter(dynamic);
1939     proxy.setSourceModel(&model);
1940     model.insertColumns(0, 1);
1941     model.insertRows(0, sourceItems.count());
1942
1943     for (int i = 0; i < sourceItems.count(); ++i) {
1944         QModelIndex index = model.index(i, 0, QModelIndex());
1945         model.setData(index, sourceItems.at(i), Qt::DisplayRole);
1946     }
1947
1948     proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
1949     (void)proxy.rowCount(QModelIndex()); // force mapping
1950
1951     proxy.setFilterRegExp(filter);
1952
1953     QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
1954     QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
1955
1956     QVERIFY(removeSpy.isValid());
1957     QVERIFY(insertSpy.isValid());
1958
1959     {
1960         QModelIndex index = model.index(row, 0, QModelIndex());
1961         model.setData(index, newValue, Qt::DisplayRole);
1962     }
1963
1964     QCOMPARE(removeSpy.count(), removeIntervals.count());
1965     for (int i = 0; i < removeSpy.count(); ++i) {
1966         QList<QVariant> args = removeSpy.at(i);
1967         QVERIFY(args.at(1).type() == QVariant::Int);
1968         QVERIFY(args.at(2).type() == QVariant::Int);
1969         QCOMPARE(args.at(1).toInt(), removeIntervals.at(i).first);
1970         QCOMPARE(args.at(2).toInt(), removeIntervals.at(i).second);
1971     }
1972
1973     QCOMPARE(insertSpy.count(), insertIntervals.count());
1974     for (int i = 0; i < insertSpy.count(); ++i) {
1975         QList<QVariant> args = insertSpy.at(i);
1976         QVERIFY(args.at(1).type() == QVariant::Int);
1977         QVERIFY(args.at(2).type() == QVariant::Int);
1978         QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first);
1979         QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second);
1980     }
1981
1982     QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count());
1983     for (int i = 0; i < proxyItems.count(); ++i) {
1984         QModelIndex index = proxy.index(i, 0, QModelIndex());
1985         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i));
1986     }
1987 }
1988
1989 void tst_QSortFilterProxyModel::sortFilterRole()
1990 {
1991     QStandardItemModel model;
1992     QSortFilterProxyModel proxy;
1993     proxy.setSourceModel(&model);
1994     model.insertColumns(0, 1);
1995
1996     QList<QPair<QVariant, QVariant> > sourceItems;
1997     sourceItems = QList<QPair<QVariant, QVariant> >()
1998                   << QPair<QVariant, QVariant>("b", 3)
1999                   << QPair<QVariant, QVariant>("c", 2)
2000                   << QPair<QVariant, QVariant>("a", 1);
2001
2002     QList<int> orderedItems;
2003     orderedItems = QList<int>()
2004                   << 2 << 1;
2005
2006     model.insertRows(0, sourceItems.count());
2007     for (int i = 0; i < sourceItems.count(); ++i) {
2008         QModelIndex index = model.index(i, 0, QModelIndex());
2009         model.setData(index, sourceItems.at(i).first, Qt::DisplayRole);
2010         model.setData(index, sourceItems.at(i).second, Qt::UserRole);
2011     }
2012
2013     proxy.setFilterRegExp("2");
2014     QCOMPARE(proxy.rowCount(), 0); // Qt::DisplayRole is default role
2015
2016     proxy.setFilterRole(Qt::UserRole);
2017     QCOMPARE(proxy.rowCount(), 1);
2018
2019     proxy.setFilterRole(Qt::DisplayRole);
2020     QCOMPARE(proxy.rowCount(), 0);
2021
2022     proxy.setFilterRegExp("1|2|3");
2023     QCOMPARE(proxy.rowCount(), 0);
2024
2025     proxy.setFilterRole(Qt::UserRole);
2026     QCOMPARE(proxy.rowCount(), 3);
2027
2028     proxy.sort(0, Qt::AscendingOrder);
2029     QCOMPARE(proxy.rowCount(), 3);
2030
2031     proxy.setSortRole(Qt::UserRole);
2032     proxy.setFilterRole(Qt::DisplayRole);
2033     proxy.setFilterRegExp("a|c");
2034     QCOMPARE(proxy.rowCount(), orderedItems.count());
2035     for (int i = 0; i < proxy.rowCount(); ++i) {
2036         QModelIndex index = proxy.index(i, 0, QModelIndex());
2037         QCOMPARE(proxy.data(index, Qt::DisplayRole), sourceItems.at(orderedItems.at(i)).first);
2038     }
2039 }
2040
2041 void tst_QSortFilterProxyModel::selectionFilteredOut()
2042 {
2043     QStandardItemModel model(2, 1);
2044     model.setData(model.index(0, 0), QString("AAA"));
2045     model.setData(model.index(1, 0), QString("BBB"));
2046     QSortFilterProxyModel proxy;
2047     proxy.setSourceModel(&model);
2048     QTreeView view;
2049
2050     view.show();
2051     view.setModel(&proxy);
2052     QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)));
2053     QVERIFY(spy.isValid());
2054
2055     view.setCurrentIndex(proxy.index(0, 0));
2056     QCOMPARE(spy.count(), 1);
2057     proxy.setFilterRegExp(QRegExp("^B"));
2058     QCOMPARE(spy.count(), 2);
2059 }
2060
2061 void tst_QSortFilterProxyModel::match_data()
2062 {
2063     QTest::addColumn<QStringList>("sourceItems");
2064     QTest::addColumn<int>("sortOrder");
2065     QTest::addColumn<QString>("filter");
2066     QTest::addColumn<int>("proxyStartRow");
2067     QTest::addColumn<QString>("what");
2068     QTest::addColumn<int>("matchFlags");
2069     QTest::addColumn<IntList>("expectedProxyItems");
2070     QTest::newRow("1")
2071         << (QStringList() << "a") // sourceItems
2072         << static_cast<int>(Qt::AscendingOrder) // sortOrder
2073         << "" // filter
2074         << 0 // proxyStartRow
2075         << "a" // what
2076         << static_cast<int>(Qt::MatchExactly) // matchFlags
2077         << (IntList() << 0); // expectedProxyItems
2078     QTest::newRow("2")
2079         << (QStringList() << "a" << "b") // sourceItems
2080         << static_cast<int>(Qt::AscendingOrder) // sortOrder
2081         << "" // filter
2082         << 0 // proxyStartRow
2083         << "b" // what
2084         << static_cast<int>(Qt::MatchExactly) // matchFlags
2085         << (IntList() << 1); // expectedProxyItems
2086     QTest::newRow("3")
2087         << (QStringList() << "a" << "b") // sourceItems
2088         << static_cast<int>(Qt::DescendingOrder) // sortOrder
2089         << "" // filter
2090         << 0 // proxyStartRow
2091         << "a" // what
2092         << static_cast<int>(Qt::MatchExactly) // matchFlags
2093         << (IntList() << 1); // expectedProxyItems
2094     QTest::newRow("4")
2095         << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
2096         << static_cast<int>(Qt::AscendingOrder) // sortOrder
2097         << "" // filter
2098         << 1 // proxyStartRow
2099         << "a" // what
2100         << static_cast<int>(Qt::MatchExactly) // matchFlags
2101         << IntList(); // expectedProxyItems
2102     QTest::newRow("5")
2103         << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
2104         << static_cast<int>(Qt::AscendingOrder) // sortOrder
2105         << "a|b" // filter
2106         << 0 // proxyStartRow
2107         << "c" // what
2108         << static_cast<int>(Qt::MatchExactly) // matchFlags
2109         << IntList(); // expectedProxyItems
2110     QTest::newRow("6")
2111         << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
2112         << static_cast<int>(Qt::DescendingOrder) // sortOrder
2113         << "a|b" // filter
2114         << 0 // proxyStartRow
2115         << "b" // what
2116         << static_cast<int>(Qt::MatchExactly) // matchFlags
2117         << (IntList() << 0); // expectedProxyItems
2118 }
2119
2120 void tst_QSortFilterProxyModel::match()
2121 {
2122     QFETCH(QStringList, sourceItems);
2123     QFETCH(int, sortOrder);
2124     QFETCH(QString, filter);
2125     QFETCH(int, proxyStartRow);
2126     QFETCH(QString, what);
2127     QFETCH(int, matchFlags);
2128     QFETCH(IntList, expectedProxyItems);
2129
2130     QStandardItemModel model;
2131     QSortFilterProxyModel proxy;
2132
2133     proxy.setSourceModel(&model);
2134     model.insertColumns(0, 1);
2135     model.insertRows(0, sourceItems.count());
2136
2137     for (int i = 0; i < sourceItems.count(); ++i) {
2138         QModelIndex index = model.index(i, 0, QModelIndex());
2139         model.setData(index, sourceItems.at(i), Qt::DisplayRole);
2140     }
2141
2142     proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
2143     proxy.setFilterRegExp(filter);
2144
2145     QModelIndex startIndex = proxy.index(proxyStartRow, 0);
2146     QModelIndexList indexes = proxy.match(startIndex, Qt::DisplayRole, what,
2147                                           expectedProxyItems.count(),
2148                                           Qt::MatchFlags(matchFlags));
2149     QCOMPARE(indexes.count(), expectedProxyItems.count());
2150     for (int i = 0; i < indexes.count(); ++i)
2151         QCOMPARE(indexes.at(i).row(), expectedProxyItems.at(i));
2152 }
2153
2154 void tst_QSortFilterProxyModel::insertIntoChildrenlessItem()
2155 {
2156     QStandardItemModel model;
2157     QStandardItem *itemA = new QStandardItem("a");
2158     model.appendRow(itemA);
2159     QStandardItem *itemB = new QStandardItem("b");
2160     model.appendRow(itemB);
2161     QStandardItem *itemC = new QStandardItem("c");
2162     model.appendRow(itemC);
2163
2164     QSortFilterProxyModel proxy;
2165     proxy.setSourceModel(&model);
2166
2167     QSignalSpy colsInsertedSpy(&proxy, SIGNAL(columnsInserted(const QModelIndex&, int, int)));
2168     QSignalSpy rowsInsertedSpy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
2169
2170     QVERIFY(colsInsertedSpy.isValid());
2171     QVERIFY(rowsInsertedSpy.isValid());
2172
2173     (void)proxy.rowCount(QModelIndex()); // force mapping of "a", "b", "c"
2174     QCOMPARE(colsInsertedSpy.count(), 0);
2175     QCOMPARE(rowsInsertedSpy.count(), 0);
2176
2177     // now add a child to itemB ==> should get insert notification from the proxy
2178     itemB->appendRow(new QStandardItem("a.0"));
2179     QCOMPARE(colsInsertedSpy.count(), 1);
2180     QCOMPARE(rowsInsertedSpy.count(), 1);
2181
2182     QVariantList args = colsInsertedSpy.takeFirst();
2183     QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index()));
2184     QCOMPARE(qvariant_cast<int>(args.at(1)), 0);
2185     QCOMPARE(qvariant_cast<int>(args.at(2)), 0);
2186
2187     args = rowsInsertedSpy.takeFirst();
2188     QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index()));
2189     QCOMPARE(qvariant_cast<int>(args.at(1)), 0);
2190     QCOMPARE(qvariant_cast<int>(args.at(2)), 0);
2191 }
2192
2193 void tst_QSortFilterProxyModel::invalidateMappedChildren()
2194 {
2195     QStandardItemModel model;
2196
2197     QSortFilterProxyModel proxy;
2198     proxy.setSourceModel(&model);
2199
2200     QStandardItem *itemA = new QStandardItem("a");
2201     model.appendRow(itemA);
2202     QStandardItem *itemB = new QStandardItem("b");
2203     itemA->appendRow(itemB);
2204
2205     QStandardItem *itemC = new QStandardItem("c");
2206     itemB->appendRow(itemC);
2207     itemC->appendRow(new QStandardItem("d"));
2208
2209     // force mappings
2210     (void)proxy.hasChildren(QModelIndex());
2211     (void)proxy.hasChildren(proxy.mapFromSource(itemA->index()));
2212     (void)proxy.hasChildren(proxy.mapFromSource(itemB->index()));
2213     (void)proxy.hasChildren(proxy.mapFromSource(itemC->index()));
2214
2215     itemB->removeRow(0); // should invalidate mapping of itemC
2216     itemC = new QStandardItem("c");
2217     itemA->appendRow(itemC);
2218     itemC->appendRow(new QStandardItem("d"));
2219
2220     itemA->removeRow(1); // should invalidate mapping of itemC
2221     itemC = new QStandardItem("c");
2222     itemB->appendRow(itemC);
2223     itemC->appendRow(new QStandardItem("d"));
2224
2225     QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemA->index())), 1);
2226     QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemB->index())), 1);
2227     QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemC->index())), 1);
2228 }
2229
2230 class EvenOddFilterModel : public QSortFilterProxyModel
2231 {
2232 public:
2233     virtual bool filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const
2234     {
2235         if (srcParent.isValid())
2236             return (srcParent.row() % 2) ^ !(srcRow % 2);
2237         return (srcRow % 2);
2238     }
2239 };
2240
2241 void tst_QSortFilterProxyModel::insertRowIntoFilteredParent()
2242 {
2243     QStandardItemModel model;
2244     EvenOddFilterModel proxy;
2245     proxy.setSourceModel(&model);
2246
2247     QSignalSpy spy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
2248     QVERIFY(spy.isValid());
2249
2250     QStandardItem *itemA = new QStandardItem();
2251     model.appendRow(itemA); // A will be filtered
2252     QStandardItem *itemB = new QStandardItem();
2253     itemA->appendRow(itemB);
2254
2255     QCOMPARE(spy.count(), 0);
2256
2257     itemA->removeRow(0);
2258
2259     QCOMPARE(spy.count(), 0);
2260 }
2261
2262 void tst_QSortFilterProxyModel::filterOutParentAndFilterInChild()
2263 {
2264     QStandardItemModel model;
2265     QSortFilterProxyModel proxy;
2266     proxy.setSourceModel(&model);
2267
2268     proxy.setFilterRegExp("A|B");
2269     QStandardItem *itemA = new QStandardItem("A");
2270     model.appendRow(itemA); // not filtered
2271     QStandardItem *itemB = new QStandardItem("B");
2272     itemA->appendRow(itemB); // not filtered
2273     QStandardItem *itemC = new QStandardItem("C");
2274     itemA->appendRow(itemC); // filtered
2275
2276     QSignalSpy removedSpy(&proxy, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));
2277     QSignalSpy insertedSpy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
2278
2279     QVERIFY(removedSpy.isValid());
2280     QVERIFY(insertedSpy.isValid());
2281
2282     proxy.setFilterRegExp("C"); // A and B will be filtered out, C filtered in
2283
2284     // we should now have been notified that the subtree represented by itemA has been removed
2285     QCOMPARE(removedSpy.count(), 1);
2286     // we should NOT get any inserts; itemC should be filtered because its parent (itemA) is
2287     QCOMPARE(insertedSpy.count(), 0);
2288 }
2289
2290 void tst_QSortFilterProxyModel::sourceInsertRows()
2291 {
2292     QStandardItemModel model;
2293     QSortFilterProxyModel proxyModel;
2294     proxyModel.setSourceModel(&model);
2295
2296     model.insertColumns(0, 1, QModelIndex());
2297     model.insertRows(0, 2, QModelIndex());
2298
2299     {
2300       QModelIndex parent = model.index(0, 0, QModelIndex());
2301       model.insertColumns(0, 1, parent);
2302       model.insertRows(0, 1, parent);
2303     }
2304
2305     {
2306       QModelIndex parent = model.index(1, 0, QModelIndex());
2307       model.insertColumns(0, 1, parent);
2308       model.insertRows(0, 1, parent);
2309     }
2310
2311     model.insertRows(0, 1, QModelIndex());
2312     model.insertRows(0, 1, QModelIndex());
2313
2314     QVERIFY(true); // if you got here without asserting, it's all good
2315 }
2316
2317 void tst_QSortFilterProxyModel::sourceModelDeletion()
2318 {
2319     QSortFilterProxyModel proxyModel;
2320     {
2321         QStandardItemModel model;
2322         proxyModel.setSourceModel(&model);
2323         QCOMPARE(proxyModel.sourceModel(), static_cast<QAbstractItemModel*>(&model));
2324     }
2325     QCOMPARE(proxyModel.sourceModel(), static_cast<QAbstractItemModel*>(0));
2326 }
2327
2328 void tst_QSortFilterProxyModel::sortColumnTracking1()
2329 {
2330     QStandardItemModel model;
2331     QSortFilterProxyModel proxyModel;
2332     proxyModel.setSourceModel(&model);
2333
2334     model.insertColumns(0, 10);
2335     model.insertRows(0, 10);
2336
2337     proxyModel.sort(1);
2338     QCOMPARE(proxyModel.sortColumn(), 1);
2339
2340     model.insertColumn(8);
2341     QCOMPARE(proxyModel.sortColumn(), 1);
2342
2343     model.removeColumn(8);
2344     QCOMPARE(proxyModel.sortColumn(), 1);
2345
2346     model.insertColumn(2);
2347     QCOMPARE(proxyModel.sortColumn(), 1);
2348
2349     model.removeColumn(2);
2350     QCOMPARE(proxyModel.sortColumn(), 1);
2351
2352     model.insertColumn(1);
2353     QCOMPARE(proxyModel.sortColumn(), 2);
2354
2355     model.removeColumn(1);
2356     QCOMPARE(proxyModel.sortColumn(), 1);
2357
2358     model.removeColumn(1);
2359     QCOMPARE(proxyModel.sortColumn(), -1);
2360 }
2361
2362 void tst_QSortFilterProxyModel::sortColumnTracking2()
2363 {
2364     QStandardItemModel model;
2365     QSortFilterProxyModel proxyModel;
2366     proxyModel.setDynamicSortFilter(true);
2367     proxyModel.setSourceModel(&model);
2368
2369     proxyModel.sort(0);
2370     QCOMPARE(proxyModel.sortColumn(), 0);
2371
2372     QList<QStandardItem *> items;
2373     QStringList strings;
2374     strings << "foo" << "bar" << "some" << "others" << "item" << "aa" << "zz";
2375     foreach (QString s, strings)
2376         items  << new QStandardItem(s);
2377
2378     model.insertColumn(0,items);
2379     QCOMPARE(proxyModel.sortColumn(), 0);
2380     QCOMPARE(proxyModel.data(proxyModel.index(0,0)).toString(),QString::fromLatin1("aa"));
2381     QCOMPARE(proxyModel.data(proxyModel.index(strings.count()-1,0)).toString(),QString::fromLatin1("zz"));
2382 }
2383
2384 void tst_QSortFilterProxyModel::sortStable()
2385 {
2386     QStandardItemModel* model = new QStandardItemModel(5, 2);
2387     for (int r = 0; r < 5; r++) {
2388         for (int c = 0; c < 2; c++)  {
2389             QStandardItem* item = new QStandardItem(
2390                     QString("Row:%0, Column:%1").arg(r).arg(c) );
2391             for (int i = 0; i < 3; i++) {
2392                 QStandardItem* child = new QStandardItem(
2393                         QString("Item %0").arg(i) );
2394                 item->appendRow( child );
2395             }
2396             model->setItem(r, c, item);
2397         }
2398     }
2399     model->setHorizontalHeaderItem( 0, new QStandardItem( "Name" ));
2400     model->setHorizontalHeaderItem( 1, new QStandardItem( "Value" ));
2401
2402     QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(model);
2403     filterModel->setSourceModel(model);
2404
2405     QTreeView *view = new QTreeView;
2406     view->setModel(filterModel);
2407     QModelIndex firstRoot = filterModel->index(0,0);
2408     view->expand(firstRoot);
2409     view->setSortingEnabled(true);
2410
2411     view->model()->sort(1, Qt::DescendingOrder);
2412     QVariant lastItemData =filterModel->index(2,0, firstRoot).data();
2413     view->model()->sort(1, Qt::DescendingOrder);
2414     QCOMPARE(lastItemData, filterModel->index(2,0, firstRoot).data());
2415 }
2416
2417 void tst_QSortFilterProxyModel::hiddenColumns()
2418 {
2419     class MyStandardItemModel : public QStandardItemModel
2420     {
2421     public:
2422         MyStandardItemModel() : QStandardItemModel(0,5) {}
2423         void reset()
2424         { QStandardItemModel::reset(); }
2425         friend class tst_QSortFilterProxyModel;
2426     } model;
2427     QSortFilterProxyModel proxy;
2428     proxy.setSourceModel(&model);
2429
2430     QTableView view;
2431     view.setModel(&proxy);
2432
2433     view.hideColumn(0);
2434
2435     QVERIFY(view.isColumnHidden(0));
2436     model.blockSignals(true);
2437     model.setRowCount(1);
2438     model.blockSignals(false);
2439     model.reset();
2440
2441     // In the initial bug report that spawned this test, this would be false
2442     // because resetting model would also reset the hidden columns.
2443     QVERIFY(view.isColumnHidden(0));
2444 }
2445
2446 void tst_QSortFilterProxyModel::insertRowsSort()
2447 {
2448     QStandardItemModel model(2,2);
2449     QSortFilterProxyModel proxyModel;
2450     proxyModel.setSourceModel(&model);
2451
2452     proxyModel.sort(0);
2453     QCOMPARE(proxyModel.sortColumn(), 0);
2454
2455     model.insertColumns(0, 3, model.index(0,0));
2456     QCOMPARE(proxyModel.sortColumn(), 0);
2457
2458     model.removeColumns(0, 3, model.index(0,0));
2459     QCOMPARE(proxyModel.sortColumn(), 0);
2460 }
2461
2462 void tst_QSortFilterProxyModel::staticSorting()
2463 {
2464     QStandardItemModel model(0, 1);
2465     QSortFilterProxyModel proxy;
2466     proxy.setSourceModel(&model);
2467     proxy.setDynamicSortFilter(false);
2468     QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" ");
2469
2470     // prepare model
2471     QStandardItem *root = model.invisibleRootItem ();
2472     QList<QStandardItem *> items;
2473     for (int i = 0; i < initial.count(); ++i) {
2474         items.append(new QStandardItem(initial.at(i)));
2475     }
2476     root->insertRows(0, items);
2477     QCOMPARE(model.rowCount(QModelIndex()), initial.count());
2478     QCOMPARE(model.columnCount(QModelIndex()), 1);
2479
2480     // make sure the proxy is unsorted
2481     QCOMPARE(proxy.columnCount(QModelIndex()), 1);
2482     QCOMPARE(proxy.rowCount(QModelIndex()), initial.count());
2483     for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
2484         QModelIndex index = proxy.index(row, 0, QModelIndex());
2485         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initial.at(row));
2486     }
2487
2488     // sort
2489     proxy.sort(0);
2490
2491     QStringList expected = initial;
2492     expected.sort();
2493     // make sure the proxy is sorted
2494     for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
2495         QModelIndex index = proxy.index(row, 0, QModelIndex());
2496         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
2497     }
2498
2499     //update one item.
2500     items.first()->setData("girafe", Qt::DisplayRole);
2501
2502     // make sure the proxy is updated but not sorted
2503     expected.replaceInStrings("bateau", "girafe");
2504     for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
2505         QModelIndex index = proxy.index(row, 0, QModelIndex());
2506         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
2507     }
2508
2509     // sort again
2510     proxy.sort(0);
2511     expected.sort();
2512
2513     // make sure the proxy is sorted
2514     for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
2515         QModelIndex index = proxy.index(row, 0, QModelIndex());
2516         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
2517     }
2518 }
2519
2520 void tst_QSortFilterProxyModel::dynamicSorting()
2521 {
2522     QStringListModel model1;
2523     const QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" ");
2524     model1.setStringList(initial);
2525     QSortFilterProxyModel proxy1;
2526     proxy1.setDynamicSortFilter(false);
2527     proxy1.sort(0);
2528     proxy1.setSourceModel(&model1);
2529
2530     QCOMPARE(proxy1.columnCount(QModelIndex()), 1);
2531     //the model should not be sorted because sorting has not been set to dynamic yet.
2532     QCOMPARE(proxy1.rowCount(QModelIndex()), initial.count());
2533     for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
2534         QModelIndex index = proxy1.index(row, 0, QModelIndex());
2535         QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), initial.at(row));
2536     }
2537
2538     proxy1.setDynamicSortFilter(true);
2539
2540     //now the model should be sorted.
2541     QStringList expected = initial;
2542     expected.sort();
2543     for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
2544         QModelIndex index = proxy1.index(row, 0, QModelIndex());
2545         QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row));
2546     }
2547
2548     QStringList initial2 = initial;
2549     initial2.replaceInStrings("bateau", "girafe");
2550     model1.setStringList(initial2); //this will cause a reset
2551
2552     QStringList expected2 = initial2;
2553     expected2.sort();
2554
2555     //now the model should still be sorted.
2556     for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
2557         QModelIndex index = proxy1.index(row, 0, QModelIndex());
2558         QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected2.at(row));
2559     }
2560
2561     QStringListModel model2(initial);
2562     proxy1.setSourceModel(&model2);
2563
2564     //the model should again be sorted
2565     for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
2566         QModelIndex index = proxy1.index(row, 0, QModelIndex());
2567         QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row));
2568     }
2569
2570     //set up the sorting before seting the model up
2571     QSortFilterProxyModel proxy2;
2572     proxy2.sort(0);
2573     proxy2.setSourceModel(&model2);
2574     for (int row = 0; row < proxy2.rowCount(QModelIndex()); ++row) {
2575         QModelIndex index = proxy2.index(row, 0, QModelIndex());
2576         QCOMPARE(proxy2.data(index, Qt::DisplayRole).toString(), expected.at(row));
2577     }
2578 }
2579
2580 class QtTestModel: public QAbstractItemModel
2581 {
2582 public:
2583     QtTestModel(int _rows, int _cols, QObject *parent = 0)
2584         : QAbstractItemModel(parent)
2585         , rows(_rows)
2586         , cols(_cols)
2587         , wrongIndex(false)
2588     {
2589     }
2590
2591     bool canFetchMore(const QModelIndex &idx) const
2592     {
2593         return !fetched.contains(idx);
2594     }
2595
2596     void fetchMore(const QModelIndex &idx)
2597     {
2598         if (fetched.contains(idx))
2599             return;
2600         beginInsertRows(idx, 0, rows-1);
2601         fetched.insert(idx);
2602         endInsertRows();
2603     }
2604
2605     bool hasChildren(const QModelIndex & = QModelIndex()) const
2606     {
2607         return true;
2608     }
2609
2610     int rowCount(const QModelIndex& parent = QModelIndex()) const
2611     {
2612         return fetched.contains(parent) ? rows : 0;
2613     }
2614
2615     int columnCount(const QModelIndex& parent = QModelIndex()) const
2616     {
2617         Q_UNUSED(parent);
2618         return cols;
2619     }
2620
2621     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
2622     {
2623         if (row < 0 || column < 0 || column >= cols || row >= rows) {
2624             return QModelIndex();
2625         }
2626         QModelIndex i = createIndex(row, column, int(parent.internalId() + 1));
2627         parentHash[i] = parent;
2628         return i;
2629     }
2630
2631     QModelIndex parent(const QModelIndex &index) const
2632     {
2633         if (!parentHash.contains(index))
2634             return QModelIndex();
2635         return parentHash[index];
2636     }
2637
2638     QVariant data(const QModelIndex &idx, int role) const
2639     {
2640         if (!idx.isValid())
2641             return QVariant();
2642
2643         if (role == Qt::DisplayRole) {
2644             if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
2645                 wrongIndex = true;
2646                 qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
2647                 idx.internalPointer());
2648             }
2649             return QString("[%1,%2]").arg(idx.row()).arg(idx.column());
2650         }
2651         return QVariant();
2652     }
2653
2654     QSet<QModelIndex> fetched;
2655     int rows, cols;
2656     mutable bool wrongIndex;
2657     mutable QMap<QModelIndex,QModelIndex> parentHash;
2658 };
2659
2660 void tst_QSortFilterProxyModel::fetchMore()
2661 {
2662     QtTestModel model(10,10);
2663     QSortFilterProxyModel proxy;
2664     proxy.setSourceModel(&model);
2665     QVERIFY(proxy.canFetchMore(QModelIndex()));
2666     QVERIFY(proxy.hasChildren());
2667     while (proxy.canFetchMore(QModelIndex()))
2668         proxy.fetchMore(QModelIndex());
2669     QCOMPARE(proxy.rowCount(), 10);
2670     QCOMPARE(proxy.columnCount(), 10);
2671
2672     QModelIndex idx = proxy.index(1,1);
2673     QVERIFY(idx.isValid());
2674     QVERIFY(proxy.canFetchMore(idx));
2675     QVERIFY(proxy.hasChildren(idx));
2676     while (proxy.canFetchMore(idx))
2677         proxy.fetchMore(idx);
2678     QCOMPARE(proxy.rowCount(idx), 10);
2679     QCOMPARE(proxy.columnCount(idx), 10);
2680 }
2681
2682 void tst_QSortFilterProxyModel::hiddenChildren()
2683 {
2684     QStandardItemModel model;
2685     QSortFilterProxyModel proxy;
2686     proxy.setSourceModel(&model);
2687     proxy.setDynamicSortFilter(true);
2688
2689     QStandardItem *itemA = new QStandardItem("A VISIBLE");
2690     model.appendRow(itemA);
2691     QStandardItem *itemB = new QStandardItem("B VISIBLE");
2692     itemA->appendRow(itemB);
2693     QStandardItem *itemC = new QStandardItem("C");
2694     itemA->appendRow(itemC);
2695     proxy.setFilterRegExp("VISIBLE");
2696
2697     QCOMPARE(proxy.rowCount(QModelIndex()) , 1);
2698     QPersistentModelIndex indexA = proxy.index(0,0);
2699     QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("A VISIBLE"));
2700
2701     QCOMPARE(proxy.rowCount(indexA) , 1);
2702     QPersistentModelIndex indexB = proxy.index(0, 0, indexA);
2703     QCOMPARE(proxy.data(indexB).toString(), QString::fromLatin1("B VISIBLE"));
2704
2705     itemA->setText("A");
2706     QCOMPARE(proxy.rowCount(QModelIndex()), 0);
2707     QVERIFY(!indexA.isValid());
2708     QVERIFY(!indexB.isValid());
2709
2710     itemB->setText("B");
2711     itemA->setText("A VISIBLE");
2712     itemC->setText("C VISIBLE");
2713
2714     QCOMPARE(proxy.rowCount(QModelIndex()), 1);
2715     indexA = proxy.index(0,0);
2716     QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("A VISIBLE"));
2717
2718     QCOMPARE(proxy.rowCount(indexA) , 1);
2719     QModelIndex indexC = proxy.index(0, 0, indexA);
2720     QCOMPARE(proxy.data(indexC).toString(), QString::fromLatin1("C VISIBLE"));
2721
2722     proxy.setFilterRegExp("C");
2723     QCOMPARE(proxy.rowCount(QModelIndex()), 0);
2724     itemC->setText("invisible");
2725     itemA->setText("AC");
2726
2727     QCOMPARE(proxy.rowCount(QModelIndex()), 1);
2728     indexA = proxy.index(0,0);
2729     QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("AC"));
2730     QCOMPARE(proxy.rowCount(indexA) , 0);
2731 }
2732
2733 void tst_QSortFilterProxyModel::mapFromToSource()
2734 {
2735     QtTestModel source(10,10);
2736     source.fetchMore(QModelIndex());
2737     QSortFilterProxyModel proxy;
2738     proxy.setSourceModel(&source);
2739     QCOMPARE(proxy.mapFromSource(source.index(5, 4)), proxy.index(5, 4));
2740     QCOMPARE(proxy.mapToSource(proxy.index(3, 2)), source.index(3, 2));
2741     QCOMPARE(proxy.mapFromSource(QModelIndex()), QModelIndex());
2742     QCOMPARE(proxy.mapToSource(QModelIndex()), QModelIndex());
2743
2744 #ifdef QT_NO_DEBUG  //if Qt is compiled in debug mode, this will assert
2745     QTest::ignoreMessage(QtWarningMsg, "QSortFilterProxyModel: index from wrong model passed to mapToSource ");
2746     QCOMPARE(proxy.mapToSource(source.index(2, 3)), QModelIndex());
2747     QTest::ignoreMessage(QtWarningMsg, "QSortFilterProxyModel: index from wrong model passed to mapFromSource ");
2748     QCOMPARE(proxy.mapFromSource(proxy.index(6, 2)), QModelIndex());
2749 #endif
2750 }
2751
2752 static QStandardItem *addEntry(QStandardItem* pParent, const QString &description)
2753 {
2754     QStandardItem* pItem = new QStandardItem(description);
2755     pParent->appendRow(pItem);
2756     return pItem;
2757 }
2758
2759 void tst_QSortFilterProxyModel::removeRowsRecursive()
2760 {
2761     QStandardItemModel pModel;
2762     QStandardItem *pItem1    = new QStandardItem("root");
2763     pModel.appendRow(pItem1);
2764     QList<QStandardItem *> items;
2765
2766     QStandardItem *pItem11   = addEntry(pItem1,"Sub-heading");
2767     items << pItem11;
2768     QStandardItem *pItem111 = addEntry(pItem11,"A");
2769     items << pItem111;
2770     items << addEntry(pItem111,"A1");
2771     items << addEntry(pItem111,"A2");
2772     QStandardItem *pItem112 = addEntry(pItem11,"B");
2773     items << pItem112;
2774     items << addEntry(pItem112,"B1");
2775     items << addEntry(pItem112,"B2");
2776     QStandardItem *pItem1123 = addEntry(pItem112,"B3");
2777     items << pItem1123;
2778     items << addEntry(pItem1123,"B3-");
2779
2780     QSortFilterProxyModel proxy;
2781     proxy.setSourceModel(&pModel);
2782
2783     QList<QPersistentModelIndex> sourceIndexes;
2784     QList<QPersistentModelIndex> proxyIndexes;
2785     foreach (QStandardItem *item, items) {
2786         QModelIndex idx = item->index();
2787         sourceIndexes << idx;
2788         proxyIndexes << proxy.mapFromSource(idx);
2789     }
2790
2791     foreach (const QPersistentModelIndex &pidx, sourceIndexes)
2792         QVERIFY(pidx.isValid());
2793     foreach (const QPersistentModelIndex &pidx, proxyIndexes)
2794         QVERIFY(pidx.isValid());
2795
2796     QList<QStandardItem*> itemRow = pItem1->takeRow(0);
2797
2798     QCOMPARE(itemRow.count(), 1);
2799     QCOMPARE(itemRow.first(), pItem11);
2800
2801     foreach (const QPersistentModelIndex &pidx, sourceIndexes)
2802         QVERIFY(!pidx.isValid());
2803     foreach (const QPersistentModelIndex &pidx, proxyIndexes)
2804         QVERIFY(!pidx.isValid());
2805
2806     delete pItem11;
2807 }
2808
2809 void tst_QSortFilterProxyModel::doubleProxySelectionSetSourceModel()
2810 {
2811     QStandardItemModel *model1 = new QStandardItemModel;
2812     QStandardItem *parentItem = model1->invisibleRootItem();
2813     for (int i = 0; i < 4; ++i) {
2814         QStandardItem *item = new QStandardItem(QString("model1 item %0").arg(i));
2815         parentItem->appendRow(item);
2816         parentItem = item;
2817     }
2818
2819     QStandardItemModel *model2 = new QStandardItemModel;
2820     QStandardItem *parentItem2 = model2->invisibleRootItem();
2821     for (int i = 0; i < 4; ++i) {
2822         QStandardItem *item = new QStandardItem(QString("model2 item %0").arg(i));
2823         parentItem2->appendRow(item);
2824         parentItem2 = item;
2825     }
2826
2827     QSortFilterProxyModel *toggleProxy = new QSortFilterProxyModel;
2828     toggleProxy->setSourceModel(model1);
2829
2830     QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel;
2831     proxyModel->setSourceModel(toggleProxy);
2832
2833     QModelIndex mi = proxyModel->index(0, 0, proxyModel->index(0, 0, proxyModel->index(0, 0)));
2834     QItemSelectionModel ism(proxyModel);
2835     ism.select(mi, QItemSelectionModel::Select);
2836     QModelIndexList mil = ism.selectedIndexes();
2837     QCOMPARE(mil.count(), 1);
2838     QCOMPARE(mil.first(), mi);
2839
2840     toggleProxy->setSourceModel(model2);
2841     // No crash, it's good news!
2842     QVERIFY(ism.selection().isEmpty());
2843 }
2844
2845 void tst_QSortFilterProxyModel::appearsAndSort()
2846 {
2847     class PModel : public QSortFilterProxyModel
2848     {
2849     public:
2850         PModel() : mVisible(false) {};
2851     protected:
2852         bool filterAcceptsRow(int, const QModelIndex &) const
2853         {
2854             return mVisible;
2855         }
2856
2857     public:
2858         void updateXX()
2859         {
2860             mVisible = true;
2861             invalidate();
2862         }
2863     private:
2864         bool mVisible;
2865     } proxyModel;
2866
2867     QStringListModel sourceModel;
2868     QStringList list;
2869     list << "b" << "a" << "c";
2870     sourceModel.setStringList(list);
2871
2872     proxyModel.setSourceModel(&sourceModel);
2873     proxyModel.setDynamicSortFilter(true);
2874     proxyModel.sort(0, Qt::AscendingOrder);
2875
2876     QApplication::processEvents();
2877     QCOMPARE(sourceModel.rowCount(), 3);
2878     QCOMPARE(proxyModel.rowCount(), 0); //all rows are hidden at first;
2879
2880     QSignalSpy spyAbout1(&proxyModel, SIGNAL(layoutAboutToBeChanged()));
2881     QSignalSpy spyChanged1(&proxyModel, SIGNAL(layoutChanged()));
2882
2883     QVERIFY(spyAbout1.isValid());
2884     QVERIFY(spyChanged1.isValid());
2885
2886     //introducing secondProxyModel to test the layoutChange when many items appears at once
2887     QSortFilterProxyModel secondProxyModel;
2888     secondProxyModel.setSourceModel(&proxyModel);
2889     secondProxyModel.setDynamicSortFilter(true);
2890     secondProxyModel.sort(0, Qt::DescendingOrder);
2891     QCOMPARE(secondProxyModel.rowCount(), 0); //all rows are hidden at first;
2892     QSignalSpy spyAbout2(&secondProxyModel, SIGNAL(layoutAboutToBeChanged()));
2893     QSignalSpy spyChanged2(&secondProxyModel, SIGNAL(layoutChanged()));
2894
2895     QVERIFY(spyAbout2.isValid());
2896     QVERIFY(spyChanged2.isValid());
2897
2898     proxyModel.updateXX();
2899     QApplication::processEvents();
2900     //now rows should be visible, and sorted
2901     QCOMPARE(proxyModel.rowCount(), 3);
2902     QCOMPARE(proxyModel.data(proxyModel.index(0,0), Qt::DisplayRole).toString(), QString::fromLatin1("a"));
2903     QCOMPARE(proxyModel.data(proxyModel.index(1,0), Qt::DisplayRole).toString(), QString::fromLatin1("b"));
2904     QCOMPARE(proxyModel.data(proxyModel.index(2,0), Qt::DisplayRole).toString(), QString::fromLatin1("c"));
2905
2906     //now rows should be visible, and sorted
2907     QCOMPARE(secondProxyModel.rowCount(), 3);
2908     QCOMPARE(secondProxyModel.data(secondProxyModel.index(0,0), Qt::DisplayRole).toString(), QString::fromLatin1("c"));
2909     QCOMPARE(secondProxyModel.data(secondProxyModel.index(1,0), Qt::DisplayRole).toString(), QString::fromLatin1("b"));
2910     QCOMPARE(secondProxyModel.data(secondProxyModel.index(2,0), Qt::DisplayRole).toString(), QString::fromLatin1("a"));
2911
2912     QCOMPARE(spyAbout1.count(), 1);
2913     QCOMPARE(spyChanged1.count(), 1);
2914     QCOMPARE(spyAbout2.count(), 1);
2915     QCOMPARE(spyChanged2.count(), 1);
2916 }
2917
2918 void tst_QSortFilterProxyModel::unnecessaryDynamicSorting()
2919 {
2920     QStringListModel model;
2921     const QStringList initial = QString("bravo charlie delta echo").split(" ");
2922     model.setStringList(initial);
2923     QSortFilterProxyModel proxy;
2924     proxy.setDynamicSortFilter(false);
2925     proxy.setSourceModel(&model);
2926     proxy.sort(Qt::AscendingOrder);
2927
2928     //append two rows
2929     int maxrows = proxy.rowCount(QModelIndex());
2930     model.insertRows(maxrows, 2);
2931     model.setData(model.index(maxrows, 0), QString("alpha"));
2932     model.setData(model.index(maxrows + 1, 0), QString("fondue"));
2933
2934     //append new items to the initial string list and compare with model
2935     QStringList expected = initial;
2936     expected << QString("alpha") << QString("fondue");
2937
2938     //if bug 7716 is present, new rows were prepended, when they should have been appended
2939     for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
2940         QModelIndex index = proxy.index(row, 0, QModelIndex());
2941         QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
2942     }
2943 }
2944
2945 class SelectionProxyModel : QAbstractProxyModel
2946 {
2947     Q_OBJECT
2948 public:
2949     SelectionProxyModel()
2950         : QAbstractProxyModel(), selectionModel(0)
2951     {
2952     }
2953
2954     QModelIndex mapFromSource(QModelIndex const&) const
2955     { return QModelIndex(); }
2956
2957     QModelIndex mapToSource(QModelIndex const&) const
2958     { return QModelIndex(); }
2959
2960     QModelIndex index(int, int, const QModelIndex&) const
2961     { return QModelIndex(); }
2962
2963     QModelIndex parent(const QModelIndex&) const
2964     { return QModelIndex(); }
2965
2966     int rowCount(const QModelIndex&) const
2967     { return 0; }
2968
2969     int columnCount(const QModelIndex&) const
2970     { return 0; }
2971
2972     void setSourceModel( QAbstractItemModel *sourceModel )
2973     {
2974         beginResetModel();
2975         disconnect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()) );
2976         QAbstractProxyModel::setSourceModel( sourceModel );
2977         connect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()) );
2978         endResetModel();
2979     }
2980
2981     void setSelectionModel( QItemSelectionModel *_selectionModel )
2982     {
2983         selectionModel = _selectionModel;
2984     }
2985
2986 private slots:
2987     void sourceModelAboutToBeReset()
2988     {
2989         QVERIFY( selectionModel->selectedIndexes().size() == 1 );
2990         beginResetModel();
2991     }
2992
2993     void sourceModelReset()
2994     {
2995         endResetModel();
2996     }
2997
2998 private:
2999     QItemSelectionModel *selectionModel;
3000 };
3001
3002 void tst_QSortFilterProxyModel::testMultipleProxiesWithSelection()
3003 {
3004     QStringListModel model;
3005     const QStringList initial = QString("bravo charlie delta echo").split(" ");
3006     model.setStringList(initial);
3007
3008     QSortFilterProxyModel proxy;
3009     proxy.setSourceModel( &model );
3010
3011     SelectionProxyModel proxy1;
3012     QSortFilterProxyModel proxy2;
3013
3014     // Note that the order here matters. The order of the sourceAboutToBeReset
3015     // exposes the bug in QSortFilterProxyModel.
3016     proxy2.setSourceModel( &proxy );
3017     proxy1.setSourceModel( &proxy );
3018
3019     QItemSelectionModel selectionModel(&proxy2);
3020     proxy1.setSelectionModel( &selectionModel );
3021
3022     selectionModel.select( proxy2.index( 0, 0 ), QItemSelectionModel::Select );
3023
3024     // trick the proxy into emitting begin/end reset signals.
3025     proxy.setSourceModel(0);
3026 }
3027
3028 static bool isValid(const QItemSelection &selection)
3029 {
3030     foreach (const QItemSelectionRange &range, selection)
3031         if (!range.isValid())
3032             return false;
3033     return true;
3034 }
3035
3036 void tst_QSortFilterProxyModel::mapSelectionFromSource()
3037 {
3038     QStringListModel model;
3039     const QStringList initial = QString("bravo charlie delta echo").split(" ");
3040     model.setStringList(initial);
3041
3042     QSortFilterProxyModel proxy;
3043     proxy.setDynamicSortFilter(true);
3044     proxy.setFilterRegExp("d.*");
3045     proxy.setSourceModel(&model);
3046
3047     // Only "delta" remains.
3048     QVERIFY(proxy.rowCount() == 1);
3049
3050     QItemSelection selection;
3051     QModelIndex charlie = model.index(1, 0);
3052     selection.append(QItemSelectionRange(charlie, charlie));
3053     QModelIndex delta = model.index(2, 0);
3054     selection.append(QItemSelectionRange(delta, delta));
3055     QModelIndex echo = model.index(3, 0);
3056     selection.append(QItemSelectionRange(echo, echo));
3057
3058     QVERIFY(isValid(selection));
3059
3060     QItemSelection proxiedSelection = proxy.mapSelectionFromSource(selection);
3061
3062     // Only "delta" is in the mapped result.
3063     QVERIFY(proxiedSelection.size() == 1);
3064     QVERIFY(isValid(proxiedSelection));
3065 }
3066
3067 class Model10287 : public QStandardItemModel
3068 {
3069     Q_OBJECT
3070
3071 public:
3072     Model10287(QObject *parent = 0)
3073         : QStandardItemModel(0, 1, parent)
3074     {
3075         parentItem = new QStandardItem("parent");
3076         parentItem->setData(false, Qt::UserRole);
3077         appendRow(parentItem);
3078
3079         childItem = new QStandardItem("child");
3080         childItem->setData(true, Qt::UserRole);
3081         parentItem->appendRow(childItem);
3082
3083         childItem2 = new QStandardItem("child2");
3084         childItem2->setData(true, Qt::UserRole);
3085         parentItem->appendRow(childItem2);
3086     }
3087
3088     void removeChild()
3089     {
3090         childItem2->setData(false, Qt::UserRole);
3091         parentItem->removeRow(0);
3092     }
3093
3094 private:
3095     QStandardItem *parentItem, *childItem, *childItem2;
3096 };
3097
3098 class Proxy10287 : public QSortFilterProxyModel
3099 {
3100     Q_OBJECT
3101
3102 public:
3103     Proxy10287(QAbstractItemModel *model, QObject *parent = 0)
3104         : QSortFilterProxyModel(parent)
3105     {
3106         setSourceModel(model);
3107         setDynamicSortFilter(true);
3108     }
3109
3110 protected:
3111     virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
3112     {
3113         // Filter based on UserRole in model
3114         QModelIndex i = sourceModel()->index(source_row, 0, source_parent);
3115         return i.data(Qt::UserRole).toBool();
3116     }
3117 };
3118
3119 void tst_QSortFilterProxyModel::unnecessaryMapCreation()
3120 {
3121     Model10287 m;
3122     Proxy10287 p(&m);
3123     m.removeChild();
3124     // No assert failure, it passes.
3125 }
3126
3127 class FilteredColumnProxyModel : public QSortFilterProxyModel
3128 {
3129     Q_OBJECT
3130 public:
3131     FilteredColumnProxyModel(QObject *parent = 0)
3132         : QSortFilterProxyModel(parent)
3133     {
3134     }
3135
3136 protected:
3137     bool filterAcceptsColumn(int column, const QModelIndex & /* source_parent */) const
3138     {
3139         return column % 2 != 0;
3140     }
3141 };
3142
3143 void tst_QSortFilterProxyModel::filteredColumns()
3144 {
3145     DynamicTreeModel *model = new DynamicTreeModel(this);
3146
3147     FilteredColumnProxyModel *proxy = new FilteredColumnProxyModel(this);
3148     proxy->setSourceModel(model);
3149
3150     new ModelTest(proxy, this);
3151
3152     ModelInsertCommand *insertCommand = new ModelInsertCommand(model, this);
3153     insertCommand->setNumCols(2);
3154     insertCommand->setStartRow(0);
3155     insertCommand->setEndRow(0);
3156     // Parent is QModelIndex()
3157     insertCommand->doCommand();
3158 }
3159
3160 class ChangableHeaderData : public QStringListModel
3161 {
3162     Q_OBJECT
3163 public:
3164     explicit ChangableHeaderData(QObject *parent = 0)
3165       : QStringListModel(parent)
3166     {
3167
3168     }
3169
3170     void emitHeaderDataChanged()
3171     {
3172         headerDataChanged(Qt::Vertical, 0, rowCount() - 1);
3173     }
3174 };
3175
3176
3177 void tst_QSortFilterProxyModel::headerDataChanged()
3178 {
3179     ChangableHeaderData *model = new ChangableHeaderData(this);
3180
3181     QStringList numbers;
3182     for (int i = 0; i < 10; ++i)
3183         numbers.append(QString::number(i));
3184     model->setStringList(numbers);
3185
3186     QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
3187     proxy->setSourceModel(model);
3188
3189     new ModelTest(proxy, this);
3190
3191     model->emitHeaderDataChanged();
3192 }
3193
3194 void tst_QSortFilterProxyModel::resetInvalidate_data()
3195 {
3196     QTest::addColumn<int>("test");
3197     QTest::addColumn<bool>("works");
3198
3199     QTest::newRow("nothing") << 0 << false;
3200     QTest::newRow("reset") << 1 << true;
3201     QTest::newRow("invalidate") << 2 << true;
3202     QTest::newRow("invalidate_filter") << 3 << true;
3203 }
3204
3205 void tst_QSortFilterProxyModel::resetInvalidate()
3206 {
3207     QFETCH(int, test);
3208     QFETCH(bool, works);
3209
3210     struct Proxy : QSortFilterProxyModel {
3211         QString pattern;
3212         virtual bool filterAcceptsRow(int source_row, const QModelIndex&) const
3213         {
3214             return sourceModel()->data(sourceModel()->index(source_row, 0)).toString().contains(pattern);
3215         }
3216         void notifyChange(int test)
3217         {
3218             switch (test) {
3219             case 0: break;
3220             case 1: reset(); break;
3221             case 2: invalidate(); break;
3222             case 3: invalidateFilter(); break;
3223             }
3224         }
3225     };
3226
3227     QStringListModel sourceModel(QStringList() << "Poisson" << "Vache" << "Brebis"
3228                                                << "Elephant" << "Cochon" << "Serpent"
3229                                                << "Mouton" << "Ecureuil" << "Mouche");
3230     Proxy proxy;
3231     proxy.pattern = QString::fromLatin1("n");
3232     proxy.setSourceModel(&sourceModel);
3233
3234     QCOMPARE(proxy.rowCount(), 5);
3235     for (int i = 0; i < proxy.rowCount(); i++) {
3236         QVERIFY(proxy.data(proxy.index(i,0)).toString().contains('n'));
3237     }
3238
3239     proxy.pattern = QString::fromLatin1("o");
3240     proxy.notifyChange(test);
3241
3242     QCOMPARE(proxy.rowCount(), works ? 4 : 5);
3243     bool ok = true;
3244     for (int i = 0; i < proxy.rowCount(); i++) {
3245         if (!proxy.data(proxy.index(i,0)).toString().contains('o'))
3246             ok = false;
3247     }
3248     QCOMPARE(ok, works);
3249 }
3250
3251 Q_DECLARE_METATYPE(QList<QPersistentModelIndex>)
3252
3253 void tst_QSortFilterProxyModel::testParentLayoutChanged()
3254 {
3255     QStandardItemModel model;
3256     QStandardItem *parentItem = model.invisibleRootItem();
3257     for (int i = 0; i < 4; ++i) {
3258         {
3259             QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
3260             parentItem->appendRow(item);
3261         }
3262         {
3263             QStandardItem *item = new QStandardItem(QString("item 1%0").arg(i));
3264             parentItem->appendRow(item);
3265             parentItem = item;
3266         }
3267     }
3268
3269     QSortFilterProxyModel proxy;
3270     proxy.sort(0, Qt::AscendingOrder);
3271     proxy.setDynamicSortFilter(true);
3272
3273     proxy.setSourceModel(&model);
3274     proxy.setObjectName("proxy");
3275
3276     // When Proxy1 emits layoutChanged(QList<QPersistentModelIndex>) this
3277     // one will too, with mapped indexes.
3278     QSortFilterProxyModel proxy2;
3279     proxy2.sort(0, Qt::AscendingOrder);
3280     proxy2.setDynamicSortFilter(true);
3281
3282     proxy2.setSourceModel(&proxy);
3283     proxy2.setObjectName("proxy2");
3284
3285     qRegisterMetaType<QList<QPersistentModelIndex> >();
3286
3287     QSignalSpy dataChangedSpy(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
3288
3289     QVERIFY(dataChangedSpy.isValid());
3290
3291     // Verify that the no-arg signal is still emitted.
3292     QSignalSpy layoutAboutToBeChangedSpy(&proxy, SIGNAL(layoutAboutToBeChanged()));
3293     QSignalSpy layoutChangedSpy(&proxy, SIGNAL(layoutChanged()));
3294
3295     QVERIFY(layoutAboutToBeChangedSpy.isValid());
3296     QVERIFY(layoutChangedSpy.isValid());
3297
3298     QSignalSpy parentsAboutToBeChangedSpy(&proxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
3299     QSignalSpy parentsChangedSpy(&proxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
3300
3301     QVERIFY(parentsAboutToBeChangedSpy.isValid());
3302     QVERIFY(parentsChangedSpy.isValid());
3303
3304     QSignalSpy proxy2ParentsAboutToBeChangedSpy(&proxy2, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
3305     QSignalSpy proxy2ParentsChangedSpy(&proxy2, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
3306
3307     QVERIFY(proxy2ParentsAboutToBeChangedSpy.isValid());
3308     QVERIFY(proxy2ParentsChangedSpy.isValid());
3309
3310     QStandardItem *item = model.invisibleRootItem()->child(1)->child(1);
3311
3312     // Ensure mapped:
3313     proxy.mapFromSource(model.indexFromItem(item));
3314
3315     item->setData("Changed");
3316
3317     QCOMPARE(dataChangedSpy.size(), 1);
3318     QCOMPARE(layoutAboutToBeChangedSpy.size(), 1);
3319     QCOMPARE(layoutChangedSpy.size(), 1);
3320     QCOMPARE(parentsAboutToBeChangedSpy.size(), 1);
3321     QCOMPARE(parentsChangedSpy.size(), 1);
3322     QCOMPARE(proxy2ParentsAboutToBeChangedSpy.size(), 1);
3323     QCOMPARE(proxy2ParentsChangedSpy.size(), 1);
3324
3325     QVariantList beforeSignal = parentsAboutToBeChangedSpy.first();
3326     QVariantList afterSignal = parentsChangedSpy.first();
3327
3328     QCOMPARE(beforeSignal.size(), 1);
3329     QCOMPARE(afterSignal.size(), 1);
3330
3331     QList<QPersistentModelIndex> beforeParents = beforeSignal.first().value<QList<QPersistentModelIndex> >();
3332     QList<QPersistentModelIndex> afterParents = afterSignal.first().value<QList<QPersistentModelIndex> >();
3333
3334     QCOMPARE(beforeParents.size(), 1);
3335     QCOMPARE(afterParents.size(), 1);
3336
3337     QVERIFY(beforeParents.first().isValid());
3338     QVERIFY(beforeParents.first() == afterParents.first());
3339
3340     QVERIFY(beforeParents.first() == proxy.mapFromSource(model.indexFromItem(model.invisibleRootItem()->child(1))));
3341
3342     QList<QPersistentModelIndex> proxy2BeforeList = proxy2ParentsAboutToBeChangedSpy.first().first().value<QList<QPersistentModelIndex> >();
3343     QList<QPersistentModelIndex> proxy2AfterList = proxy2ParentsChangedSpy.first().first().value<QList<QPersistentModelIndex> >();
3344
3345     QCOMPARE(proxy2BeforeList.size(), beforeParents.size());
3346     QCOMPARE(proxy2AfterList.size(), afterParents.size());
3347     foreach (const QPersistentModelIndex &idx, proxy2BeforeList)
3348         QVERIFY(beforeParents.contains(proxy2.mapToSource(idx)));
3349     foreach (const QPersistentModelIndex &idx, proxy2AfterList)
3350         QVERIFY(afterParents.contains(proxy2.mapToSource(idx)));
3351 }
3352
3353 class SignalArgumentChecker : public QObject
3354 {
3355     Q_OBJECT
3356 public:
3357     SignalArgumentChecker(QAbstractItemModel *model, QAbstractProxyModel *proxy, QObject *parent = 0)
3358       : QObject(parent), m_model(model), m_proxy(proxy)
3359     {
3360         connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
3361         connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
3362         connect(proxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)), SLOT(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
3363         connect(proxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)), SLOT(layoutChanged(QList<QPersistentModelIndex>)));
3364     }
3365
3366 private slots:
3367     void rowsAboutToBeMoved(const QModelIndex &source, int, int, const QModelIndex &destination, int)
3368     {
3369         m_p1PersistentBefore = source;
3370         m_p2PersistentBefore = destination;
3371         m_p2FirstProxyChild = m_proxy->index(0, 0, m_proxy->mapFromSource(destination));
3372     }
3373
3374     void rowsMoved(const QModelIndex &source, int, int, const QModelIndex &destination, int)
3375     {
3376         m_p1PersistentAfter = source;
3377         m_p2PersistentAfter = destination;
3378     }
3379
3380     void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents)
3381     {
3382         QVERIFY(m_p1PersistentBefore.isValid());
3383         QVERIFY(m_p2PersistentBefore.isValid());
3384         QCOMPARE(parents.size(), 2);
3385         QVERIFY(parents.first() != parents.at(1));
3386         QVERIFY(parents.contains(m_proxy->mapFromSource(m_p1PersistentBefore)));
3387         QVERIFY(parents.contains(m_proxy->mapFromSource(m_p2PersistentBefore)));
3388     }
3389
3390     void layoutChanged(const QList<QPersistentModelIndex> &parents)
3391     {
3392         QVERIFY(m_p1PersistentAfter.isValid());
3393         QVERIFY(m_p2PersistentAfter.isValid());
3394         QCOMPARE(parents.size(), 2);
3395         QVERIFY(parents.first() != parents.at(1));
3396         QVERIFY(parents.contains(m_proxy->mapFromSource(m_p1PersistentAfter)));
3397         QVERIFY(parents.contains(m_proxy->mapFromSource(m_p2PersistentAfter)));
3398
3399         // In the source model, the rows were moved to row 1 in the parent.
3400         // m_p2FirstProxyChild was created with row 0 in the proxy.
3401         // The moved rows in the proxy do not appear at row 1 because of sorting.
3402         // Sorting causes them to appear at row 0 instead, pushing what used to
3403         // be row 0 in the proxy down by two rows.
3404         QCOMPARE(m_p2FirstProxyChild.row(), 2);
3405     }
3406
3407 private:
3408     QAbstractItemModel *m_model;
3409     QAbstractProxyModel *m_proxy;
3410     QPersistentModelIndex m_p1PersistentBefore;
3411     QPersistentModelIndex m_p2PersistentBefore;
3412     QPersistentModelIndex m_p1PersistentAfter;
3413     QPersistentModelIndex m_p2PersistentAfter;
3414
3415     QPersistentModelIndex m_p2FirstProxyChild;
3416 };
3417
3418 void tst_QSortFilterProxyModel::moveSourceRows()
3419 {
3420     qRegisterMetaType<QList<QPersistentModelIndex> >();
3421
3422     DynamicTreeModel model;
3423
3424     {
3425         ModelInsertCommand insertCommand(&model);
3426         insertCommand.setStartRow(0);
3427         insertCommand.setEndRow(9);
3428         insertCommand.doCommand();
3429     }
3430     {
3431         ModelInsertCommand insertCommand(&model);
3432         insertCommand.setAncestorRowNumbers(QList<int>() << 2);
3433         insertCommand.setStartRow(0);
3434         insertCommand.setEndRow(9);
3435         insertCommand.doCommand();
3436     }
3437     {
3438         ModelInsertCommand insertCommand(&model);
3439         insertCommand.setAncestorRowNumbers(QList<int>() << 5);
3440         insertCommand.setStartRow(0);
3441         insertCommand.setEndRow(9);
3442         insertCommand.doCommand();
3443     }
3444
3445     QSortFilterProxyModel proxy;
3446     proxy.setDynamicSortFilter(true);
3447     proxy.sort(0, Qt::AscendingOrder);
3448
3449     // We need to check the arguments at emission time
3450     SignalArgumentChecker checker(&model, &proxy);
3451
3452     proxy.setSourceModel(&model);
3453
3454     QSortFilterProxyModel filterProxy;
3455     filterProxy.setDynamicSortFilter(true);
3456     filterProxy.sort(0, Qt::AscendingOrder);
3457     filterProxy.setSourceModel(&proxy);
3458     filterProxy.setFilterRegExp("6"); // One of the parents
3459
3460     QSortFilterProxyModel filterBothProxy;
3461     filterBothProxy.setDynamicSortFilter(true);
3462     filterBothProxy.sort(0, Qt::AscendingOrder);
3463     filterBothProxy.setSourceModel(&proxy);
3464     filterBothProxy.setFilterRegExp("5"); // The parents are 6 and 3. This filters both out.
3465
3466     QSignalSpy modelBeforeSpy(&model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
3467     QSignalSpy modelAfterSpy(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
3468     QSignalSpy proxyBeforeMoveSpy(m_proxy, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
3469     QSignalSpy proxyAfterMoveSpy(m_proxy, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
3470     QSignalSpy proxyBeforeParentLayoutSpy(&proxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
3471     QSignalSpy proxyAfterParentLayoutSpy(&proxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
3472     QSignalSpy filterBeforeParentLayoutSpy(&filterProxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
3473     QSignalSpy filterAfterParentLayoutSpy(&filterProxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
3474     QSignalSpy filterBothBeforeParentLayoutSpy(&filterBothProxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
3475     QSignalSpy filterBothAfterParentLayoutSpy(&filterBothProxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
3476
3477     QVERIFY(modelBeforeSpy.isValid());
3478     QVERIFY(modelAfterSpy.isValid());
3479     QVERIFY(proxyBeforeMoveSpy.isValid());
3480     QVERIFY(proxyAfterMoveSpy.isValid());
3481     QVERIFY(proxyBeforeParentLayoutSpy.isValid());
3482     QVERIFY(proxyAfterParentLayoutSpy.isValid());
3483     QVERIFY(filterBeforeParentLayoutSpy.isValid());
3484     QVERIFY(filterAfterParentLayoutSpy.isValid());
3485     QVERIFY(filterBothBeforeParentLayoutSpy.isValid());
3486     QVERIFY(filterBothAfterParentLayoutSpy.isValid());
3487
3488     {
3489         ModelMoveCommand moveCommand(&model, 0);
3490         moveCommand.setAncestorRowNumbers(QList<int>() << 2);
3491         moveCommand.setDestAncestors(QList<int>() << 5);
3492         moveCommand.setStartRow(3);
3493         moveCommand.setEndRow(4);
3494         moveCommand.setDestRow(1);
3495         moveCommand.doCommand();
3496     }
3497
3498     // Proxy notifies layout change
3499     QCOMPARE(modelBeforeSpy.size(), 1);
3500     QCOMPARE(proxyBeforeParentLayoutSpy.size(), 1);
3501     QCOMPARE(modelAfterSpy.size(), 1);
3502     QCOMPARE(proxyAfterParentLayoutSpy.size(), 1);
3503
3504     // But it doesn't notify a move.
3505     QCOMPARE(proxyBeforeMoveSpy.size(), 0);
3506     QCOMPARE(proxyAfterMoveSpy.size(), 0);
3507
3508     QCOMPARE(filterBeforeParentLayoutSpy.size(), 1);
3509     QCOMPARE(filterAfterParentLayoutSpy.size(), 1);
3510
3511     QList<QPersistentModelIndex> filterBeforeParents = filterBeforeParentLayoutSpy.first().first().value<QList<QPersistentModelIndex> >();
3512     QList<QPersistentModelIndex> filterAfterParents = filterAfterParentLayoutSpy.first().first().value<QList<QPersistentModelIndex> >();
3513
3514     QCOMPARE(filterBeforeParents.size(), 1);
3515     QCOMPARE(filterAfterParents.size(), 1);
3516
3517     QCOMPARE(filterBothBeforeParentLayoutSpy.size(), 0);
3518     QCOMPARE(filterBothAfterParentLayoutSpy.size(), 0);
3519 }
3520
3521 class FilterProxy : public QSortFilterProxyModel
3522 {
3523     Q_OBJECT
3524 public:
3525     FilterProxy(QObject *parent = 0)
3526       : QSortFilterProxyModel(parent),
3527         mode(false)
3528     {
3529
3530     }
3531
3532 public slots:
3533     void setMode(bool on)
3534     {
3535         mode = on;
3536         invalidateFilter();
3537     }
3538
3539 protected:
3540     virtual bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const
3541     {
3542         if (mode) {
3543             if (!source_parent.isValid()) {
3544                 return true;
3545             } else {
3546                 return (source_row % 2) != 0;
3547             }
3548         } else {
3549             if (!source_parent.isValid()) {
3550                 return source_row >= 2 && source_row < 10;
3551             } else {
3552                 return true;
3553             }
3554         }
3555     }
3556
3557 private:
3558     bool mode;
3559 };
3560
3561 void tst_QSortFilterProxyModel::hierarchyFilterInvalidation()
3562 {
3563     QStandardItemModel model;
3564     for (int i = 0; i < 10; ++i) {
3565         QStandardItem *child = new QStandardItem(QString("Row %1").arg(i));
3566         for (int j = 0; j < 1; ++j) {
3567             child->appendRow(new QStandardItem(QString("Row %1/%2").arg(i).arg(j)));
3568         }
3569         model.appendRow(child);
3570     }
3571
3572     FilterProxy proxy;
3573     proxy.setSourceModel(&model);
3574
3575     QTreeView view;
3576     view.setModel(&proxy);
3577
3578     view.setCurrentIndex(proxy.index(2, 0).child(0, 0));
3579
3580     view.show();
3581     QTest::qWaitForWindowExposed(&view);
3582
3583     proxy.setMode(true);
3584 }
3585
3586 class FilterProxy2 : public QSortFilterProxyModel
3587 {
3588     Q_OBJECT
3589 public:
3590     FilterProxy2(QObject *parent = 0)
3591       : QSortFilterProxyModel(parent),
3592         mode(false)
3593     {
3594
3595     }
3596
3597 public slots:
3598     void setMode(bool on)
3599     {
3600         mode = on;
3601         invalidateFilter();
3602     }
3603
3604 protected:
3605     virtual bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const
3606     {
3607         if (source_parent.isValid()) {
3608             return true;
3609         } else {
3610             if (0 == source_row) {
3611                 return true;
3612             } else {
3613                 return !mode;
3614             }
3615         }
3616     }
3617
3618 private:
3619     bool mode;
3620 };
3621
3622 void tst_QSortFilterProxyModel::simpleFilterInvalidation()
3623 {
3624     QStandardItemModel model;
3625     for (int i = 0; i < 2; ++i) {
3626         QStandardItem *child = new QStandardItem(QString("Row %1").arg(i));
3627         child->appendRow(new QStandardItem("child"));
3628         model.appendRow(child);
3629     }
3630
3631     FilterProxy2 proxy;
3632     proxy.setSourceModel(&model);
3633
3634     QTreeView view;
3635     view.setModel(&proxy);
3636
3637     view.show();
3638     QTest::qWaitForWindowExposed(&view);
3639
3640     proxy.setMode(true);
3641     model.insertRow(0, new QStandardItem("extra"));
3642 }
3643
3644
3645 QTEST_MAIN(tst_QSortFilterProxyModel)
3646 #include "tst_qsortfilterproxymodel.moc"