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