Use QStringList::join(QChar) overload where applicable [QtWidgets]
[profile/ivi/qtbase.git] / tests / auto / widgets / util / qcompleter / tst_qcompleter.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <QtGui>
44 #include <QtWidgets>
45 #include <QtDebug>
46 #include <QPair>
47 #include <QList>
48 #include <QPointer>
49
50 #include "../../../../shared/filesystem.h"
51
52 class CsvCompleter : public QCompleter
53 {
54     Q_OBJECT
55 public:
56     CsvCompleter(QObject *parent = 0) : QCompleter(parent), csv(true) { }
57
58     QString pathFromIndex(const QModelIndex& sourceIndex) const;
59
60     void setCsvCompletion(bool set) { csv = set; }
61
62 protected:
63     QStringList splitPath(const QString &path) const {
64         return csv ? path.split(",") : QCompleter::splitPath(path);
65     }
66
67 private:
68     bool csv;
69 };
70
71 QString CsvCompleter::pathFromIndex(const QModelIndex& si) const
72 {
73     if (!csv)
74         return QCompleter::pathFromIndex(si);
75
76     if (!si.isValid())
77         return QString();
78
79     QModelIndex idx = si;
80     QStringList list;
81     do {
82         QString t = model()->data(idx, completionRole()).toString();
83         list.prepend(t);
84         QModelIndex parent = idx.parent();
85         idx = parent.sibling(parent.row(), si.column());
86     } while (idx.isValid());
87
88     if (list.count() == 1)
89         return list[0];
90     return list.join(',');
91 }
92
93 class tst_QCompleter : public QObject
94 {
95     Q_OBJECT
96 public:
97     tst_QCompleter();
98     ~tst_QCompleter();
99
100 private slots:
101     void getSetCheck();
102
103     void multipleWidgets();
104     void focusIn();
105
106     void csMatchingOnCsSortedModel_data();
107     void csMatchingOnCsSortedModel();
108     void ciMatchingOnCiSortedModel_data();
109     void ciMatchingOnCiSortedModel();
110
111     void ciMatchingOnCsSortedModel_data();
112     void ciMatchingOnCsSortedModel();
113     void csMatchingOnCiSortedModel_data();
114     void csMatchingOnCiSortedModel();
115
116     void directoryModel_data();
117     void directoryModel();
118     void fileSystemModel_data();
119     void fileSystemModel();
120
121     void changingModel_data();
122     void changingModel();
123
124     void sortedEngineRowCount_data();
125     void sortedEngineRowCount();
126     void unsortedEngineRowCount_data();
127     void unsortedEngineRowCount();
128
129     void currentRow();
130     void sortedEngineMapFromSource();
131     void unsortedEngineMapFromSource();
132
133     void historySearch();
134
135     void modelDeletion();
136     void setters();
137
138     void dynamicSortOrder();
139     void disabledItems();
140
141     // task-specific tests below me
142     void task178797_activatedOnReturn();
143     void task189564_omitNonSelectableItems();
144     void task246056_setCompletionPrefix();
145     void task250064_lostFocus();
146
147     void task253125_lineEditCompletion_data();
148     void task253125_lineEditCompletion();
149     void task247560_keyboardNavigation();
150     void QTBUG_14292_filesystem();
151
152 private:
153     void filter(bool assync = false);
154     void testRowCount();
155     enum ModelType {
156         CASE_SENSITIVELY_SORTED_MODEL,
157         CASE_INSENSITIVELY_SORTED_MODEL,
158         DIRECTORY_MODEL,
159         HISTORY_MODEL,
160         FILESYSTEM_MODEL
161     };
162     void setSourceModel(ModelType);
163
164     CsvCompleter *completer;
165     QTreeWidget *treeWidget;
166     const int completionColumn;
167     const int columnCount;
168 };
169
170 tst_QCompleter::tst_QCompleter() : completer(0), completionColumn(0), columnCount(3)
171 {
172     treeWidget = new QTreeWidget;
173     treeWidget->setColumnCount(columnCount);
174 }
175
176 tst_QCompleter::~tst_QCompleter()
177 {
178     delete treeWidget;
179     delete completer;
180 }
181
182 void tst_QCompleter::setSourceModel(ModelType type)
183 {
184     QString text;
185     QTreeWidgetItem *parent, *child;
186     treeWidget->clear();
187     switch(type) {
188     case CASE_SENSITIVELY_SORTED_MODEL:
189         // Creates a tree model with top level items P0, P1, .., p0, p1,..
190         // Each of these items parents have children (for P0 - c0P0, c1P0,...)
191         for (int i = 0; i < 2; i++) {
192             for (int j = 0; j < 5; j++) {
193                 parent = new QTreeWidgetItem(treeWidget);
194                 text.sprintf("%c%i", i == 0 ? 'P' : 'p', j);
195                 parent->setText(completionColumn, text);
196                 for (int k = 0; k < 5; k++) {
197                     child = new QTreeWidgetItem(parent);
198                     QString t = QString().sprintf("c%i", k) + text;
199                     child->setText(completionColumn, t);
200                 }
201             }
202         }
203         completer->setModel(treeWidget->model());
204         completer->setCompletionColumn(completionColumn);
205         break;
206     case CASE_INSENSITIVELY_SORTED_MODEL:
207     case HISTORY_MODEL:
208         // Creates a tree model with top level items P0, p0, P1, p1,...
209         // Each of these items have children c0p0, c1p0,..
210         for (int i = 0; i < 5; i++) {
211             for (int j = 0; j < 2; j++) {
212                 parent = new QTreeWidgetItem(treeWidget);
213                 text.sprintf("%c%i", j == 0 ? 'P' : 'p', i);
214                 parent->setText(completionColumn, text);
215                 for (int k = 0; k < 5; k++) {
216                     child = new QTreeWidgetItem(parent);
217                     QString t = QString().sprintf("c%i", k) + text;
218                     child->setText(completionColumn, t);
219                 }
220             }
221         }
222         completer->setModel(treeWidget->model());
223         completer->setCompletionColumn(completionColumn);
224         if (type == CASE_INSENSITIVELY_SORTED_MODEL)
225             break;
226         parent = new QTreeWidgetItem(treeWidget);
227         parent->setText(completionColumn, QLatin1String("p3,c3p3"));
228         parent = new QTreeWidgetItem(treeWidget);
229         parent->setText(completionColumn, QLatin1String("p2,c4p2"));
230         break;
231     case DIRECTORY_MODEL:
232         completer->setCsvCompletion(false);
233         completer->setModel(new QDirModel(completer));
234         completer->setCompletionColumn(0);
235         break;
236     case FILESYSTEM_MODEL:
237         completer->setCsvCompletion(false);
238         {
239             QFileSystemModel *m = new QFileSystemModel(completer);
240             m->setRootPath("/");
241             completer->setModel(m);
242         }
243         completer->setCompletionColumn(0);
244         break;
245     default:
246         qDebug() << "Invalid type";
247     }
248 }
249
250 void tst_QCompleter::filter(bool assync)
251 {
252     QFETCH(QString, filterText);
253     QFETCH(QString, step);
254     QFETCH(QString, completion);
255     QFETCH(QString, completionText);
256
257     if (filterText.compare("FILTERING_OFF", Qt::CaseInsensitive) == 0) {
258         completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
259         return;
260     }
261
262     int times = 0;
263 retry:
264
265     completer->setCompletionPrefix(filterText);
266
267     for (int i = 0; i < step.length(); i++) {
268         int row = completer->currentRow();
269         switch (step[i].toUpper().toLatin1()) {
270         case 'P': --row; break;
271         case 'N': ++row; break;
272         case 'L': row = completer->completionCount() - 1; break;
273         case 'F': row = 0; break;
274         default:
275             QFAIL(qPrintable(QString(
276                 "Problem with 'step' value in test data: %1 (only P, N, L and F are allowed)."
277             ).arg(step[i])));
278         }
279         completer->setCurrentRow(row);
280     }
281
282     int r = QString::compare(completer->currentCompletion(), completionText, completer->caseSensitivity());
283     if (assync && r && times < 10) {
284         times++;
285         QTest::qWait(50*times);
286         goto retry;
287     }
288     QVERIFY(!r);
289 }
290
291 // Testing get/set functions
292 void tst_QCompleter::getSetCheck()
293 {
294     QStandardItemModel model(3,3);
295     QCompleter completer(&model);
296
297     // QString QCompleter::completionPrefix()
298     // void QCompleter::setCompletionPrefix(QString)
299     completer.setCompletionPrefix(QString("te"));
300     QCOMPARE(completer.completionPrefix(), QString("te"));
301     completer.setCompletionPrefix(QString());
302     QCOMPARE(completer.completionPrefix(), QString());
303
304     // ModelSorting QCompleter::modelSorting()
305     // void QCompleter::setModelSorting(ModelSorting)
306     completer.setModelSorting(QCompleter::CaseSensitivelySortedModel);
307     QCOMPARE(completer.modelSorting(), QCompleter::CaseSensitivelySortedModel);
308     completer.setModelSorting(QCompleter::CaseInsensitivelySortedModel);
309     QCOMPARE(completer.modelSorting(), QCompleter::CaseInsensitivelySortedModel);
310     completer.setModelSorting(QCompleter::UnsortedModel);
311     QCOMPARE(completer.modelSorting(), QCompleter::UnsortedModel);
312
313     // CompletionMode QCompleter::completionMode()
314     // void QCompleter::setCompletionMode(CompletionMode)
315     QCOMPARE(completer.completionMode(), QCompleter::PopupCompletion); // default value
316     completer.setCompletionMode(QCompleter::UnfilteredPopupCompletion);
317     QCOMPARE(completer.completionMode(), QCompleter::UnfilteredPopupCompletion);
318     completer.setCompletionMode(QCompleter::InlineCompletion);
319     QCOMPARE(completer.completionMode(), QCompleter::InlineCompletion);
320
321     // int QCompleter::completionColumn()
322     // void QCompleter::setCompletionColumn(int)
323     completer.setCompletionColumn(2);
324     QCOMPARE(completer.completionColumn(), 2);
325     completer.setCompletionColumn(1);
326     QCOMPARE(completer.completionColumn(), 1);
327
328     // int QCompleter::completionRole()
329     // void QCompleter::setCompletionRole(int)
330     QCOMPARE(completer.completionRole(), static_cast<int>(Qt::EditRole)); // default value
331     completer.setCompletionRole(Qt::DisplayRole);
332     QCOMPARE(completer.completionRole(), static_cast<int>(Qt::DisplayRole));
333
334     // int QCompleter::maxVisibleItems()
335     // void QCompleter::setMaxVisibleItems(int)
336     QCOMPARE(completer.maxVisibleItems(), 7); // default value
337     completer.setMaxVisibleItems(10);
338     QCOMPARE(completer.maxVisibleItems(), 10);
339     QTest::ignoreMessage(QtWarningMsg, "QCompleter::setMaxVisibleItems: "
340                          "Invalid max visible items (-2147483648) must be >= 0");
341     completer.setMaxVisibleItems(INT_MIN);
342     QCOMPARE(completer.maxVisibleItems(), 10); // Cannot be set to something negative => old value
343
344     // Qt::CaseSensitivity QCompleter::caseSensitivity()
345     // void QCompleter::setCaseSensitivity(Qt::CaseSensitivity)
346     QCOMPARE(completer.caseSensitivity(), Qt::CaseSensitive); // default value
347     completer.setCaseSensitivity(Qt::CaseInsensitive);
348     QCOMPARE(completer.caseSensitivity(), Qt::CaseInsensitive);
349
350     // bool QCompleter::wrapAround()
351     // void QCompleter::setWrapAround(bool)
352     QCOMPARE(completer.wrapAround(), true); // default value
353     completer.setWrapAround(false);
354     QCOMPARE(completer.wrapAround(), false);
355 }
356
357 void tst_QCompleter::csMatchingOnCsSortedModel_data()
358 {
359     delete completer;
360     completer = new CsvCompleter;
361     completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
362     completer->setCaseSensitivity(Qt::CaseSensitive);
363     setSourceModel(CASE_SENSITIVELY_SORTED_MODEL);
364
365     QTest::addColumn<QString>("filterText");
366     QTest::addColumn<QString>("step");
367     QTest::addColumn<QString>("completion");
368     QTest::addColumn<QString>("completionText");
369
370 #define ROWNAME(name) (qPrintable(QString("%1 %2").arg(name).arg(i)))
371
372     for (int i = 0; i < 2; i++) {
373          if (i == 1)
374              QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
375
376          // Plain text filter
377          QTest::newRow(ROWNAME("()")) << "" << "" << "P0" << "P0";
378          QTest::newRow(ROWNAME("()F")) << "" << "F" << "P0" << "P0";
379          QTest::newRow(ROWNAME("()L")) << "" << "L" << "p4" << "p4";
380          QTest::newRow(ROWNAME("()N")) << "" << "N" << "P1" << "P1";
381          QTest::newRow(ROWNAME("(P)")) << "P" << "" << "P0" << "P0";
382          QTest::newRow(ROWNAME("(P)F")) << "P" << "" << "P0" << "P0";
383          QTest::newRow(ROWNAME("(P)L")) << "P" << "L" << "P4" << "P4";
384          QTest::newRow(ROWNAME("(p)")) << "p" << "" << "p0" << "p0";
385          QTest::newRow(ROWNAME("(p)N")) << "p" << "N" << "p1" << "p1";
386          QTest::newRow(ROWNAME("(p)NN")) << "p" << "NN" << "p2" << "p2";
387          QTest::newRow(ROWNAME("(p)NNN")) << "p" << "NNN" << "p3" << "p3";
388          QTest::newRow(ROWNAME("(p)NNNN")) << "p" << "NNNN" << "p4" << "p4";
389          QTest::newRow(ROWNAME("(p1)")) << "p1" << "" << "p1" << "p1";
390          QTest::newRow(ROWNAME("(p11)")) << "p11" << "" << "" << "";
391
392          // Tree filter
393          QTest::newRow(ROWNAME("(P0,)")) << "P0," << "" << "c0P0" << "P0,c0P0";
394          QTest::newRow(ROWNAME("(P0,c)")) << "P0,c" << "" << "c0P0" << "P0,c0P0";
395          QTest::newRow(ROWNAME("(P0,c1)")) << "P0,c1" << "" << "c1P0" << "P0,c1P0";
396          QTest::newRow(ROWNAME("(P0,c3P0)")) << "P0,c3P0" << "" << "c3P0" << "P0,c3P0";
397          QTest::newRow(ROWNAME("(P3,c)F")) << "P3,c" << "F" << "c0P3" << "P3,c0P3";
398          QTest::newRow(ROWNAME("(P3,c)L")) << "P3,c" << "L" << "c4P3" << "P3,c4P3";
399          QTest::newRow(ROWNAME("(P3,c)N")) << "P3,c" << "N" << "c1P3" << "P3,c1P3";
400          QTest::newRow(ROWNAME("(P3,c)NN")) << "P3,c" << "NN" << "c2P3" << "P3,c2P3";
401          QTest::newRow(ROWNAME("(P3,,c)")) << "P3,,c" << "" << "" << "";
402          QTest::newRow(ROWNAME("(P3,c0P3,)")) << "P3,c0P3," << "" << "" << "";
403          QTest::newRow(ROWNAME("(P,)")) << "P," << "" << "" << "";
404      }
405 #undef ROWNAME
406 }
407
408 void tst_QCompleter::csMatchingOnCsSortedModel()
409 {
410     filter();
411 }
412
413 void tst_QCompleter::ciMatchingOnCiSortedModel_data()
414 {
415     delete completer;
416     completer = new CsvCompleter;
417     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
418     completer->setCaseSensitivity(Qt::CaseInsensitive);
419     setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
420
421     QTest::addColumn<QString>("filterText");
422     QTest::addColumn<QString>("step");
423     QTest::addColumn<QString>("completion");
424     QTest::addColumn<QString>("completionText");
425
426     for (int i = 0; i < 2; i++) {
427         if (i == 1)
428             QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
429
430         // Plain text filter
431         QTest::newRow("()") << "" << "" << "P0" << "P0";
432         QTest::newRow("()F") << "" << "F" << "P0" << "P0";
433         QTest::newRow("()L") << "" << "L" << "p4" << "p4";
434         QTest::newRow("()N") << "" << "N" << "p0" << "p0";
435         QTest::newRow("(P)") << "P" << "" << "P0" << "P0";
436         QTest::newRow("(P)F") << "P" << "" << "P0" << "P0";
437         QTest::newRow("(P)L") << "P" << "L" << "p4" << "p4";
438         QTest::newRow("(p)") << "p" << "" << "P0" << "P0";
439         QTest::newRow("(p)N") << "p" << "N" << "p0" << "p0";
440         QTest::newRow("(p)NN") << "p" << "NN" << "P1" << "P1";
441         QTest::newRow("(p)NNN") << "p" << "NNN" << "p1" << "p1";
442         QTest::newRow("(p1)") << "p1" << "" << "P1" << "P1";
443         QTest::newRow("(p1)N") << "p1" << "N" << "p1" << "p1";
444         QTest::newRow("(p11)") << "p11" << "" << "" << "";
445
446         //// Tree filter
447         QTest::newRow("(p0,)") << "p0," << "" << "c0P0" << "P0,c0P0";
448         QTest::newRow("(p0,c)") << "p0,c" << "" << "c0P0" << "P0,c0P0";
449         QTest::newRow("(p0,c1)") << "p0,c1" << "" << "c1P0" << "P0,c1P0";
450         QTest::newRow("(p0,c3P0)") << "p0,c3P0" << "" << "c3P0" << "P0,c3P0";
451         QTest::newRow("(p3,c)F") << "p3,c" << "F" << "c0P3" << "P3,c0P3";
452         QTest::newRow("(p3,c)L") << "p3,c" << "L" << "c4P3" << "P3,c4P3";
453         QTest::newRow("(p3,c)N") << "p3,c" << "N" << "c1P3" << "P3,c1P3";
454         QTest::newRow("(p3,c)NN") << "p3,c" << "NN" << "c2P3" << "P3,c2P3";
455         QTest::newRow("(p3,,c)") << "p3,,c" << "" << "" << "";
456         QTest::newRow("(p3,c0P3,)") << "p3,c0P3," << "" << "" << "";
457         QTest::newRow("(p,)") << "p," << "" << "" << "";
458     }
459 }
460
461 void tst_QCompleter::ciMatchingOnCiSortedModel()
462 {
463     filter();
464 }
465
466 void tst_QCompleter::ciMatchingOnCsSortedModel_data()
467 {
468     delete completer;
469     completer = new CsvCompleter;
470     completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
471     setSourceModel(CASE_SENSITIVELY_SORTED_MODEL);
472     completer->setCaseSensitivity(Qt::CaseInsensitive);
473
474     QTest::addColumn<QString>("filterText");
475     QTest::addColumn<QString>("step");
476     QTest::addColumn<QString>("completion");
477     QTest::addColumn<QString>("completionText");
478
479     for (int i = 0; i < 2; i++) {
480         if (i == 1)
481             QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
482
483         // Plain text filter
484         QTest::newRow("()") << "" << "" << "P0" << "P0";
485         QTest::newRow("()F") << "" << "F" << "P0" << "P0";
486         QTest::newRow("()L") << "" << "L" << "p4" << "p4";
487         QTest::newRow("(P)") << "P" << "" << "P0" << "P0";
488         QTest::newRow("(P)F") << "P" << "" << "P0" << "P0";
489         QTest::newRow("(P)L") << "P" << "L" << "p4" << "p4";
490         QTest::newRow("(p)") << "p" << "" << "P0" << "P0";
491         QTest::newRow("(p)N") << "p" << "N" << "P1" << "P1";
492         QTest::newRow("(p)NN") << "p" << "NN" << "P2" << "P2";
493         QTest::newRow("(p)NNN") << "p" << "NNN" << "P3" << "P3";
494         QTest::newRow("(p1)") << "p1" << "" << "P1" << "P1";
495         QTest::newRow("(p1)N") << "p1" << "N" << "p1" << "p1";
496         QTest::newRow("(p11)") << "p11" << "" << "" << "";
497
498         // Tree filter
499         QTest::newRow("(p0,)") << "p0," << "" << "c0P0" << "P0,c0P0";
500         QTest::newRow("(p0,c)") << "p0,c" << "" << "c0P0" << "P0,c0P0";
501         QTest::newRow("(p0,c1)") << "p0,c1" << "" << "c1P0" << "P0,c1P0";
502         QTest::newRow("(p0,c3P0)") << "p0,c3P0" << "" << "c3P0" << "P0,c3P0";
503         QTest::newRow("(p3,c)F") << "p3,c" << "F" << "c0P3" << "P3,c0P3";
504         QTest::newRow("(p3,c)L") << "p3,c" << "L" << "c4P3" << "P3,c4P3";
505         QTest::newRow("(p3,c)N") << "p3,c" << "N" << "c1P3" << "P3,c1P3";
506         QTest::newRow("(p3,c)NN") << "p3,c" << "NN" << "c2P3" << "P3,c2P3";
507         QTest::newRow("(p3,,c)") << "p3,,c" << "" << "" << "";
508         QTest::newRow("(p3,c0P3,)") << "p3,c0P3," << "" << "" << "";
509         QTest::newRow("(p,)") << "p," << "" << "" << "";
510     }
511 }
512
513 void tst_QCompleter::ciMatchingOnCsSortedModel()
514 {
515     filter();
516 }
517
518 void tst_QCompleter::csMatchingOnCiSortedModel_data()
519 {
520     delete completer;
521     completer = new CsvCompleter;
522     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
523     setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
524     completer->setCaseSensitivity(Qt::CaseSensitive);
525
526     QTest::addColumn<QString>("filterText");
527     QTest::addColumn<QString>("step");
528     QTest::addColumn<QString>("completion");
529     QTest::addColumn<QString>("completionText");
530
531     for (int i = 0; i < 2; i++) {
532         if (i == 1)
533             QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
534
535         // Plain text filter
536         QTest::newRow("()") << "" << "" << "P0" << "P0";
537         QTest::newRow("()F") << "" << "F" << "P0" << "P0";
538         QTest::newRow("()L") << "" << "L" << "p4" << "p4";
539         QTest::newRow("()N") << "" << "N" << "p0" << "p0";
540         QTest::newRow("(P)") << "P" << "" << "P0" << "P0";
541         QTest::newRow("(P)F") << "P" << "" << "P0" << "P0";
542         QTest::newRow("(P)L") << "P" << "L" << "P4" << "P4";
543         QTest::newRow("(p)") << "p" << "" << "p0" << "p0";
544         QTest::newRow("(p)N") << "p" << "N" << "p1" << "p1";
545         QTest::newRow("(p)NN") << "p" << "NN" << "p2" << "p2";
546         QTest::newRow("(p)NNN") << "p" << "NNN" << "p3" << "p3";
547         QTest::newRow("(p1)") << "p1" << "" << "p1" << "p1";
548         QTest::newRow("(p11)") << "p11" << "" << "" << "";
549
550         //// Tree filter
551         QTest::newRow("(p0,)") << "p0," << "" << "c0p0" << "p0,c0p0";
552         QTest::newRow("(p0,c)") << "p0,c" << "" << "c0p0" << "p0,c0p0";
553         QTest::newRow("(p0,c1)") << "p0,c1" << "" << "c1p0" << "p0,c1p0";
554         QTest::newRow("(p0,c3P0)") << "p0,c3p0" << "" << "c3p0" << "p0,c3p0";
555         QTest::newRow("(p3,c)F") << "p3,c" << "F" << "c0p3" << "p3,c0p3";
556         QTest::newRow("(p3,c)L") << "p3,c" << "L" << "c4p3" << "p3,c4p3";
557         QTest::newRow("(p3,c)N") << "p3,c" << "N" << "c1p3" << "p3,c1p3";
558         QTest::newRow("(p3,c)NN") << "p3,c" << "NN" << "c2p3" << "p3,c2p3";
559         QTest::newRow("(p3,,c)") << "p3,,c" << "" << "" << "";
560         QTest::newRow("(p3,c0P3,)") << "p3,c0P3," << "" << "" << "";
561         QTest::newRow("(p,)") << "p," << "" << "" << "";
562
563         QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
564     }
565 }
566
567 void tst_QCompleter::csMatchingOnCiSortedModel()
568 {
569     filter();
570 }
571
572 void tst_QCompleter::directoryModel_data()
573 {
574     delete completer;
575
576     completer = new CsvCompleter;
577     completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
578     setSourceModel(DIRECTORY_MODEL);
579     completer->setCaseSensitivity(Qt::CaseInsensitive);
580
581     QTest::addColumn<QString>("filterText");
582     QTest::addColumn<QString>("step");
583     QTest::addColumn<QString>("completion");
584     QTest::addColumn<QString>("completionText");
585
586     // NOTE: Add tests carefully, ensurely the paths exist on all systems
587     // Output is the sourceText; currentCompletionText()
588
589     for (int i = 0; i < 2; i++) {
590         if (i == 1)
591             QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
592
593 #if defined(Q_OS_WINCE)
594         QTest::newRow("()") << "" << "" << "/" << "/";
595         QTest::newRow("()") << "\\Program" << "" << "Program Files" << "\\Program Files";
596 #elif defined(Q_OS_WIN)
597         QTest::newRow("()") << "C" << "" << "C:" << "C:";
598         QTest::newRow("()") << "C:\\Program" << "" << "Program Files" << "C:\\Program Files";
599 #elif defined (Q_OS_MAC)
600         QTest::newRow("()") << "" << "" << "/" << "/";
601         QTest::newRow("(/a)") << "/a" << "" << "Applications" << "/Applications";
602         QTest::newRow("(/d)") << "/d" << "" << "Developer" << "/Developer";
603 #else
604         QTest::newRow("()") << "" << "" << "/" << "/";
605 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_OS_HPUX)
606         QTest::newRow("(/h)") << "/h" << "" << "home" << "/home";
607 #endif
608         QTest::newRow("(/et)") << "/et" << "" << "etc" << "/etc";
609         QTest::newRow("(/etc/passw)") << "/etc/passw" << "" << "passwd" << "/etc/passwd";
610 #endif
611     }
612 }
613
614 void tst_QCompleter::directoryModel()
615 {
616     filter();
617 }
618
619 void tst_QCompleter::fileSystemModel_data()
620 {
621     delete completer;
622     completer = new CsvCompleter;
623     completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
624     setSourceModel(FILESYSTEM_MODEL);
625     completer->setCaseSensitivity(Qt::CaseInsensitive);
626
627     QTest::addColumn<QString>("filterText");
628     QTest::addColumn<QString>("step");
629     QTest::addColumn<QString>("completion");
630     QTest::addColumn<QString>("completionText");
631
632     // NOTE: Add tests carefully, ensurely the paths exist on all systems
633     // Output is the sourceText; currentCompletionText()
634
635     for (int i = 0; i < 2; i++) {
636         if (i == 1)
637             QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
638
639 #if defined(Q_OS_WINCE)
640         QTest::newRow("()") << "" << "" << "/" << "/";
641         QTest::newRow("()") << "\\Program" << "" << "Program Files" << "\\Program Files";
642 #elif defined(Q_OS_WIN)
643         QTest::newRow("()") << "C" << "" << "C:" << "C:";
644         QTest::newRow("()") << "C:\\Program" << "" << "Program Files" << "C:\\Program Files";
645 #elif defined (Q_OS_MAC)
646         QTest::newRow("()") << "" << "" << "/" << "/";
647         QTest::newRow("(/a)") << "/a" << "" << "Applications" << "/Applications";
648 //        QTest::newRow("(/d)") << "/d" << "" << "Developer" << "/Developer";
649 #else
650         QTest::newRow("()") << "" << "" << "/" << "/";
651 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_OS_HPUX)
652         QTest::newRow("(/h)") << "/h" << "" << "home" << "/home";
653 #endif
654         QTest::newRow("(/et)") << "/et" << "" << "etc" << "/etc";
655         QTest::newRow("(/etc/passw)") << "/etc/passw" << "" << "passwd" << "/etc/passwd";
656 #endif
657     }
658 }
659
660 void tst_QCompleter::fileSystemModel()
661 {
662     //QFileSystemModel is assync.
663     filter(true);
664 }
665
666
667 void tst_QCompleter::changingModel_data()
668 {
669 }
670
671 void tst_QCompleter::changingModel()
672 {
673     for (int i = 0; i < 2; i++) {
674         delete completer;
675         completer = new CsvCompleter;
676         completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
677         completer->setCaseSensitivity(Qt::CaseSensitive);
678         setSourceModel(CASE_SENSITIVELY_SORTED_MODEL);
679
680         if (i == 1) {
681             completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
682         }
683
684         completer->setCompletionPrefix("p");
685         completer->setCurrentRow(completer->completionCount() - 1);
686         QCOMPARE(completer->currentCompletion(), QString("p4"));
687
688         // Test addition of data
689         QTreeWidgetItem p5item;
690         p5item.setText(completionColumn, "p5");
691         treeWidget->addTopLevelItem(&p5item);
692         completer->setCompletionPrefix("p5");
693         QCOMPARE(completer->currentCompletion(), QString("p5"));
694
695         // Test removal of data
696         int p5index = treeWidget->indexOfTopLevelItem(&p5item);
697         treeWidget->takeTopLevelItem(p5index);
698         QCOMPARE(completer->currentCompletion(), QString(""));
699
700         // Test clear
701         treeWidget->clear();
702         QCOMPARE(completer->currentIndex(), QModelIndex());
703     }
704 }
705
706 void tst_QCompleter::testRowCount()
707 {
708     QFETCH(QString, filterText);
709     QFETCH(bool, hasChildren);
710     QFETCH(int, rowCount);
711     QFETCH(int, completionCount);
712
713     if (filterText.compare("FILTERING_OFF", Qt::CaseInsensitive) == 0) {
714         completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
715         return;
716     }
717
718     completer->setCompletionPrefix(filterText);
719     const QAbstractItemModel *completionModel = completer->completionModel();
720     QCOMPARE(completionModel->rowCount(), rowCount);
721     QCOMPARE(completionCount, completionCount);
722     QCOMPARE(completionModel->hasChildren(), hasChildren);
723     QCOMPARE(completionModel->columnCount(), columnCount);
724 }
725
726 void tst_QCompleter::sortedEngineRowCount_data()
727 {
728     delete completer;
729     completer = new CsvCompleter;
730     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
731     completer->setCaseSensitivity(Qt::CaseInsensitive);
732     setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
733
734     QTest::addColumn<QString>("filterText");
735     QTest::addColumn<bool>("hasChildren");
736     QTest::addColumn<int>("rowCount");
737     QTest::addColumn<int>("completionCount");
738
739     QTest::newRow("whatever") << "whatever" << false << 0 << 0;
740     QTest::newRow("p") << "p" << true << 10 << 10;
741     QTest::newRow("p1") << "p1" << true << 2 << 2;
742     QTest::newRow("P1,") << "P1," << true << 5 << 5;
743     QTest::newRow("P1,c") << "P1,c" << true << 5 << 5;
744     QTest::newRow("P1,cc") << "P1,cc" << false << 0 << 0;
745
746     QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << false << 0 << 0;
747
748     QTest::newRow("whatever(filter off)") << "whatever" << true << 10 << 0;
749     QTest::newRow("p1(filter off)") << "p1" << true << 10 << 2;
750     QTest::newRow("p1,(filter off)") << "p1," << true << 5 << 5;
751     QTest::newRow("p1,c(filter off)") << "p1,c" << true << 5 << 5;
752     QTest::newRow("P1,cc(filter off)") << "P1,cc" << true << 5 << 0;
753 }
754
755 void tst_QCompleter::sortedEngineRowCount()
756 {
757     testRowCount();
758 }
759
760 void tst_QCompleter::unsortedEngineRowCount_data()
761 {
762     delete completer;
763     completer = new CsvCompleter;
764     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
765     completer->setCaseSensitivity(Qt::CaseSensitive);
766     setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
767
768     QTest::addColumn<QString>("filterText");
769     QTest::addColumn<bool>("hasChildren");
770     QTest::addColumn<int>("rowCount");
771     QTest::addColumn<int>("completionCount");
772
773     QTest::newRow("whatever") << "whatever" << false << 0 << 0;
774     QTest::newRow("p") << "p" << true << 5 << 5;
775     QTest::newRow("p1") << "p1" << true << 1 << 1;
776     QTest::newRow("P1,") << "P1," << true << 5 << 5;
777     QTest::newRow("P1,c") << "P1,c" << true << 5 << 5;
778     QTest::newRow("P1,cc") << "P1,cc" << false << 0 << 0;
779
780     QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << false << 0 << 0;
781
782     QTest::newRow("whatever(filter off)") << "whatever" << true << 10 << 0;
783     QTest::newRow("p1(filter off)") << "p1" << true << 10 << 1;
784     QTest::newRow("p1,(filter off)") << "p1," << true << 5 << 5;
785     QTest::newRow("p1,c(filter off)") << "p1,c" << true << 5 << 5;
786     QTest::newRow("P1,cc(filter off)") << "P1,cc" << true << 5 << 0;
787 }
788
789 void tst_QCompleter::unsortedEngineRowCount()
790 {
791     testRowCount();
792 }
793
794 void tst_QCompleter::currentRow()
795 {
796     delete completer;
797     completer = new CsvCompleter;
798     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
799     completer->setCaseSensitivity(Qt::CaseInsensitive);
800     setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
801
802     // blank text
803     completer->setCompletionPrefix("");
804     QCOMPARE(completer->currentRow(), 0);
805     QVERIFY(completer->setCurrentRow(4));
806     QCOMPARE(completer->currentRow(), 4);
807     QVERIFY(!completer->setCurrentRow(13));
808     QVERIFY(completer->setCurrentRow(4));
809
810     // some text
811      completer->setCompletionPrefix("p1");
812     QCOMPARE(completer->currentRow(), 0);
813     QVERIFY(completer->setCurrentRow(1));
814     QCOMPARE(completer->currentRow(), 1);
815     QVERIFY(!completer->setCurrentRow(2));
816     QCOMPARE(completer->currentRow(), 1);
817
818     // invalid text
819     completer->setCompletionPrefix("well");
820     QCOMPARE(completer->currentRow(), -1);
821 }
822
823 void tst_QCompleter::sortedEngineMapFromSource()
824 {
825     delete completer;
826     completer = new CsvCompleter;
827     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
828     completer->setCaseSensitivity(Qt::CaseInsensitive);
829     setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
830
831     QModelIndex si1, si2, pi;
832     QAbstractItemModel *sourceModel = completer->model();
833     const QAbstractProxyModel *completionModel =
834         qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
835
836     // Fitering ON
837     // empty
838     si1 = sourceModel->index(4, completionColumn); // "P2"
839     si2 = sourceModel->index(2, 0, si1); // "P2,c0P2"
840     pi = completionModel->mapFromSource(si1);
841     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
842     pi = completionModel->mapFromSource(si2);
843     QCOMPARE(pi.isValid(), false);
844
845     // some text
846     completer->setCompletionPrefix("p");
847     pi = completionModel->mapFromSource(si1);
848     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
849     pi = completionModel->mapFromSource(si2);
850     QCOMPARE(pi.isValid(), false);
851
852     // more text
853     completer->setCompletionPrefix("p2");
854     pi = completionModel->mapFromSource(si1);
855     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
856     pi = completionModel->mapFromSource(si2);
857     QCOMPARE(pi.isValid(), false);
858
859     // invalid text
860     completer->setCompletionPrefix("whatever");
861     pi = completionModel->mapFromSource(si1);
862     QVERIFY(!pi.isValid());
863
864     // Fitering OFF
865     completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
866     // empty
867     si1 = sourceModel->index(4, completionColumn); // "P2"
868     si2 = sourceModel->index(2, 0, si1); // "P2,c0P2"
869     pi = completionModel->mapFromSource(si1);
870     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
871     pi = completionModel->mapFromSource(si2);
872     QCOMPARE(pi.isValid(), false);
873
874     // some text
875     completer->setCompletionPrefix("p");
876     pi = completionModel->mapFromSource(si1);
877     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
878     pi = completionModel->mapFromSource(si2);
879     QCOMPARE(pi.isValid(), false);
880
881     // more text
882     completer->setCompletionPrefix("p2");
883     pi = completionModel->mapFromSource(si1);
884     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
885     pi = completionModel->mapFromSource(si2);
886     QCOMPARE(pi.isValid(), false);
887
888     // invalid text
889     completer->setCompletionPrefix("whatever");
890     pi = completionModel->mapFromSource(si1);
891     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
892 }
893
894 void tst_QCompleter::unsortedEngineMapFromSource()
895 {
896     delete completer;
897     completer = new CsvCompleter;
898     completer->setCaseSensitivity(Qt::CaseInsensitive);
899     setSourceModel(HISTORY_MODEL); // case insensitively sorted model
900     completer->setModelSorting(QCompleter::UnsortedModel);
901
902     QModelIndex si, si2, si3, pi;
903     QAbstractItemModel *sourceModel = completer->model();
904     const QAbstractProxyModel *completionModel =
905         qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
906
907     si = sourceModel->index(6, completionColumn); // "P3"
908     QCOMPARE(si.data().toString(), QLatin1String("P3"));
909     si2 = sourceModel->index(3, completionColumn, sourceModel->index(0, completionColumn)); // "P0,c3P0"
910     QCOMPARE(si2.data().toString(), QLatin1String("c3P0"));
911     si3 = sourceModel->index(10, completionColumn); // "p3,c3p3" (history)
912     QCOMPARE(si3.data().toString(), QLatin1String("p3,c3p3"));
913
914     // FILTERING ON
915     // empty
916     pi = completionModel->mapFromSource(si);
917     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
918     pi = completionModel->mapFromSource(si2);
919     QCOMPARE(pi.isValid(), false);
920     pi = completionModel->mapFromSource(si3);
921    QCOMPARE(completionModel->data(pi).toString(), QLatin1String("p3,c3p3"));
922
923     // some text
924     completer->setCompletionPrefix("P");
925     pi = completionModel->mapFromSource(si);
926     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
927     pi = completionModel->mapFromSource(si2);
928     QCOMPARE(pi.isValid(), false);
929     pi = completionModel->mapFromSource(si3);
930     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("p3,c3p3"));
931
932     // invalid text
933     completer->setCompletionPrefix("whatever");
934     pi = completionModel->mapFromSource(si);
935     QVERIFY(!pi.isValid());
936     pi = completionModel->mapFromSource(si2);
937     QVERIFY(!pi.isValid());
938
939     // tree matching
940     completer->setCompletionPrefix("P0,c");
941     pi = completionModel->mapFromSource(si);
942     QVERIFY(!pi.isValid());
943     pi = completionModel->mapFromSource(si2);
944     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("c3P0"));
945     pi = completionModel->mapFromSource(si3);
946     QCOMPARE(pi.isValid(), false);
947
948     // more tree matching
949     completer->setCompletionPrefix("p3,");
950     pi = completionModel->mapFromSource(si2);
951     QVERIFY(!pi.isValid());
952     pi = completionModel->mapFromSource(si3);
953     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("p3,c3p3"));
954
955     // FILTERING OFF
956     // empty
957     completer->setCompletionPrefix("");
958     completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
959     pi = completionModel->mapFromSource(si);
960     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
961
962     // some text
963     completer->setCompletionPrefix("P");
964     pi = completionModel->mapFromSource(si);
965     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
966
967     // more text
968     completer->setCompletionPrefix("P3");
969     pi = completionModel->mapFromSource(si);
970     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
971
972     // invalid text
973     completer->setCompletionPrefix("whatever");
974     pi = completionModel->mapFromSource(si);
975     QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
976 }
977
978 void tst_QCompleter::historySearch()
979 {
980     delete completer;
981     completer = new CsvCompleter;
982     completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
983     completer->setCaseSensitivity(Qt::CaseSensitive);
984     setSourceModel(HISTORY_MODEL);
985
986     const QAbstractProxyModel *completionModel =
987       qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
988
989     // "p3,c3p3" and "p2,c4p2" are added in the tree root
990
991     // FILTERING ON
992     // empty
993     completer->setCurrentRow(10);
994     QCOMPARE(completer->currentCompletion(), QLatin1String("p3,c3p3"));
995
996     // more text
997     completer->setCompletionPrefix("p2");
998     completer->setCurrentRow(1);
999     QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2"));
1000
1001     // comma separated text
1002     completer->setCompletionPrefix("p2,c4");
1003     completer->setCurrentRow(1);
1004     QCOMPARE(completionModel->rowCount(), 2);
1005     QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2"));
1006
1007     // invalid text
1008     completer->setCompletionPrefix("whatever");
1009     QCOMPARE(completer->currentCompletion(), QString());
1010
1011     // FILTERING OFF
1012     completer->setCompletionPrefix("");
1013     completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
1014     completer->setCurrentRow(10);
1015     QCOMPARE(completer->currentCompletion(), QLatin1String("p3,c3p3"));
1016
1017     // more text
1018     completer->setCompletionPrefix("p2");
1019     completer->setCurrentRow(1);
1020     QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2"));
1021
1022     // comma separated text
1023     completer->setCompletionPrefix("p2,c4");
1024     QCOMPARE(completionModel->rowCount(), 5);
1025
1026     // invalid text
1027     completer->setCompletionPrefix("whatever");
1028     QCOMPARE(completer->currentCompletion(), QString());
1029 }
1030
1031 void tst_QCompleter::setters()
1032 {
1033     delete completer;
1034     completer = new CsvCompleter;
1035     QVERIFY(completer->popup() != 0);
1036     QPointer<QDirModel> dirModel = new QDirModel(completer);
1037     QAbstractItemModel *oldModel = completer->model();
1038     completer->setModel(dirModel);
1039     QVERIFY(completer->popup()->model() != oldModel);
1040     QVERIFY(completer->popup()->model() == completer->completionModel());
1041     completer->setPopup(new QListView);
1042     QVERIFY(completer->popup()->model() == completer->completionModel());
1043     completer->setModel(new QStringListModel(completer));
1044     QVERIFY(dirModel == 0); // must have been deleted
1045
1046     completer->setModel(0);
1047     completer->setWidget(0);
1048 }
1049
1050 void tst_QCompleter::modelDeletion()
1051 {
1052     delete completer;
1053     completer = new CsvCompleter;
1054     QStringList list;
1055     list << "item1" << "item2" << "item3";
1056     QStringListModel *listModel = new QStringListModel(list);
1057     completer->setCompletionPrefix("i");
1058     completer->setModel(listModel);
1059     QVERIFY(completer->completionCount() == 3);
1060     QListView *view = new QListView;
1061     view->setModel(completer->completionModel());
1062     delete listModel;
1063     view->show();
1064     qApp->processEvents();
1065     delete view;
1066     QVERIFY(completer->completionCount() == 0);
1067     QVERIFY(completer->currentRow() == -1);
1068 }
1069
1070 void tst_QCompleter::multipleWidgets()
1071 {
1072     QStringList list;
1073     list << "item1" << "item2" << "item2";
1074     QCompleter completer(list);
1075     completer.setCompletionMode(QCompleter::InlineCompletion);
1076
1077     QWidget window;
1078     window.show();
1079     QApplication::setActiveWindow(&window);
1080     QVERIFY(QTest::qWaitForWindowActive(&window));
1081     QVERIFY(qApp->activeWindow() == &window);
1082
1083     QFocusEvent focusIn(QEvent::FocusIn);
1084     QFocusEvent focusOut(QEvent::FocusOut);
1085
1086     QComboBox *comboBox = new QComboBox(&window);
1087     comboBox->setEditable(true);
1088     comboBox->setCompleter(&completer);
1089     comboBox->setFocus();
1090     comboBox->show();
1091     window.activateWindow();
1092     QApplication::setActiveWindow(&window);
1093     QTest::qWait(50);
1094     QTRY_VERIFY(qApp->focusWidget() == comboBox);
1095     comboBox->lineEdit()->setText("it");
1096     QCOMPARE(comboBox->currentText(), QString("it")); // should not complete with setText
1097     QTest::keyPress(comboBox, 'e');
1098     QCOMPARE(comboBox->currentText(), QString("item1"));
1099     comboBox->clearEditText();
1100     QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change!
1101
1102     QLineEdit *lineEdit = new QLineEdit(&window);
1103     lineEdit->setCompleter(&completer);
1104     lineEdit->show();
1105     lineEdit->setFocus();
1106     QTest::qWait(50);
1107     QTRY_VERIFY(qApp->focusWidget() == lineEdit);
1108     lineEdit->setText("it");
1109     QCOMPARE(lineEdit->text(), QString("it")); // should not completer with setText
1110     QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change!
1111     QTest::keyPress(lineEdit, 'e');
1112     QCOMPARE(lineEdit->text(), QString("item1"));
1113     QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change!
1114 }
1115
1116 void tst_QCompleter::focusIn()
1117 {
1118     QStringList list;
1119     list << "item1" << "item2" << "item2";
1120     QCompleter completer(list);
1121
1122     QWidget window;
1123     window.show();
1124     QTest::qWait(100);
1125     window.activateWindow();
1126     QApplication::setActiveWindow(&window);
1127     QTest::qWait(100);
1128
1129     QTRY_COMPARE(qApp->activeWindow(), &window);
1130
1131     QComboBox *comboBox = new QComboBox(&window);
1132     comboBox->setEditable(true);
1133     comboBox->setCompleter(&completer);
1134     comboBox->show();
1135     comboBox->lineEdit()->setText("it");
1136
1137     QLineEdit *lineEdit = new QLineEdit(&window);
1138     lineEdit->setCompleter(&completer);
1139     lineEdit->setText("it");
1140     lineEdit->show();
1141
1142     QLineEdit *lineEdit2 = new QLineEdit(&window); // has no completer!
1143     lineEdit2->show();
1144
1145     comboBox->setFocus();
1146     QTRY_VERIFY(completer.widget() == comboBox);
1147     lineEdit->setFocus();
1148     QTRY_VERIFY(completer.widget() == lineEdit);
1149     comboBox->setFocus();
1150     QTRY_VERIFY(completer.widget() == comboBox);
1151     lineEdit2->setFocus();
1152     QTRY_VERIFY(completer.widget() == comboBox);
1153 }
1154
1155 void tst_QCompleter::dynamicSortOrder()
1156 {
1157     QStandardItemModel model;
1158     QCompleter completer(&model);
1159     completer.setModelSorting(QCompleter::CaseSensitivelySortedModel);
1160     QStandardItem *root = model.invisibleRootItem();
1161     for (int i = 0; i < 20; i++) {
1162         root->appendRow(new QStandardItem(QString("%1").arg(i)));
1163     }
1164     root->appendRow(new QStandardItem("13"));
1165     root->sortChildren(0, Qt::AscendingOrder);
1166     completer.setCompletionPrefix("1");
1167     QCOMPARE(completer.completionCount(), 12);
1168     completer.setCompletionPrefix("13");
1169     QCOMPARE(completer.completionCount(), 2);
1170
1171     root->sortChildren(0, Qt::DescendingOrder);
1172     completer.setCompletionPrefix("13");
1173     QCOMPARE(completer.completionCount(), 2);
1174     completer.setCompletionPrefix("1");
1175     QCOMPARE(completer.completionCount(), 12);
1176 }
1177
1178 void tst_QCompleter::disabledItems()
1179 {
1180     QLineEdit lineEdit;
1181     QStandardItemModel *model = new QStandardItemModel(&lineEdit);
1182     QStandardItem *suggestions = new QStandardItem("suggestions");
1183     suggestions->setEnabled(false);
1184     model->appendRow(suggestions);
1185     model->appendRow(new QStandardItem("suggestions Enabled"));
1186     QCompleter *completer = new QCompleter(model, &lineEdit);
1187     QSignalSpy spy(completer, SIGNAL(activated(const QString &)));
1188     lineEdit.setCompleter(completer);
1189     lineEdit.show();
1190
1191     QTest::keyPress(&lineEdit, Qt::Key_S);
1192     QTest::keyPress(&lineEdit, Qt::Key_U);
1193     QAbstractItemView *view = lineEdit.completer()->popup();
1194     QVERIFY(view->isVisible());
1195     QTest::mouseClick(view->viewport(), Qt::LeftButton, 0, view->visualRect(view->model()->index(0, 0)).center());
1196     QCOMPARE(spy.count(), 0);
1197     QVERIFY(view->isVisible());
1198     QTest::mouseClick(view->viewport(), Qt::LeftButton, 0, view->visualRect(view->model()->index(1, 0)).center());
1199     QCOMPARE(spy.count(), 1);
1200     QVERIFY(!view->isVisible());
1201 }
1202
1203 void tst_QCompleter::task178797_activatedOnReturn()
1204 {
1205     QStringList words;
1206     words << "foobar1" << "foobar2";
1207     QLineEdit *ledit = new QLineEdit;
1208     QCompleter *completer = new QCompleter(words);
1209     ledit->setCompleter(completer);
1210     QSignalSpy spy(completer, SIGNAL(activated(const QString)));
1211     QCOMPARE(spy.count(), 0);
1212     ledit->show();
1213     QTest::keyClick(ledit, Qt::Key_F);
1214     qApp->processEvents();
1215     QVERIFY(qApp->activePopupWidget());
1216     QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Down);
1217     qApp->processEvents();
1218     QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Return);
1219     qApp->processEvents();
1220     QCOMPARE(spy.count(), 1);
1221 }
1222
1223 class task189564_StringListModel : public QStringListModel
1224 {
1225     const QString omitString;
1226     Qt::ItemFlags flags(const QModelIndex &index) const
1227     {
1228         Qt::ItemFlags flags = Qt::ItemIsEnabled;
1229         if (data(index, Qt::DisplayRole).toString() != omitString)
1230             flags |= Qt::ItemIsSelectable;
1231         return flags;
1232     }
1233 public:
1234     task189564_StringListModel(const QString &omitString, QObject *parent = 0)
1235         : QStringListModel(parent)
1236         , omitString(omitString)
1237     {
1238     }
1239 };
1240
1241 void tst_QCompleter::task189564_omitNonSelectableItems()
1242 {
1243     const QString prefix("a");
1244     const int n = 5;
1245
1246     QStringList strings;
1247     for (int i = 0; i < n; ++i)
1248         strings << QString("%1%2").arg(prefix).arg(i);
1249     const QString omitString(strings.at(n / 2));
1250     task189564_StringListModel model(omitString);
1251     model.setStringList(strings);
1252     QCompleter completer_(&model);
1253     completer_.setCompletionPrefix(prefix);
1254
1255     QAbstractItemModel *completionModel = completer_.completionModel();
1256     QModelIndexList matches1 =
1257         completionModel->match(completionModel->index(0, 0), Qt::DisplayRole, prefix, -1);
1258     QCOMPARE(matches1.size(), n - 1);
1259     QModelIndexList matches2 =
1260         completionModel->match(completionModel->index(0, 0), Qt::DisplayRole, omitString);
1261     QVERIFY(matches2.isEmpty());
1262 }
1263
1264 class task246056_ComboBox : public QComboBox
1265 {
1266     Q_OBJECT
1267 public:
1268     task246056_ComboBox()
1269     {
1270         setEditable(true);
1271         setInsertPolicy(NoInsert);
1272         if (completer()) {
1273             completer()->setCompletionMode(QCompleter::PopupCompletion);
1274             completer()->setCompletionRole(Qt::DisplayRole);
1275             connect(lineEdit(), SIGNAL(editingFinished()), SLOT(setCompletionPrefix()));
1276         }
1277     }
1278 private slots:
1279     void setCompletionPrefix() { completer()->setCompletionPrefix(lineEdit()->text()); }
1280 };
1281
1282 void tst_QCompleter::task246056_setCompletionPrefix()
1283 {
1284     task246056_ComboBox *comboBox = new task246056_ComboBox;
1285     QVERIFY(comboBox->completer());
1286     comboBox->addItem("");
1287     comboBox->addItem("a1");
1288     comboBox->addItem("a2");
1289     comboBox->show();
1290     comboBox->setFocus();
1291     QTest::qWait(100);
1292     QTest::keyPress(comboBox, 'a');
1293     QTest::keyPress(comboBox->completer()->popup(), Qt::Key_Down);
1294     QTest::keyPress(comboBox->completer()->popup(), Qt::Key_Down);
1295     QTest::keyPress(comboBox->completer()->popup(), Qt::Key_Enter); // don't crash!
1296 }
1297
1298 class task250064_TextEdit : public QTextEdit
1299 {
1300 public:
1301     QCompleter *completer;
1302
1303     task250064_TextEdit()
1304     {
1305         completer = new QCompleter;
1306         completer->setWidget(this);
1307     }
1308
1309     void keyPressEvent (QKeyEvent *e)
1310     {
1311         completer->popup();
1312         QTextEdit::keyPressEvent(e);
1313     }
1314 };
1315
1316 class task250064_Widget : public QWidget
1317 {
1318     Q_OBJECT
1319 public:
1320     task250064_TextEdit *textEdit;
1321
1322     task250064_Widget(task250064_TextEdit *textEdit)
1323         : textEdit(textEdit)
1324     {
1325         QTabWidget *tabWidget = new QTabWidget;
1326         tabWidget->setFocusPolicy(Qt::ClickFocus);
1327         tabWidget->addTab(textEdit, "untitled");
1328
1329         QVBoxLayout *layout = new QVBoxLayout(this);
1330         layout->addWidget(tabWidget);
1331
1332         textEdit->setPlainText("bla bla bla");
1333         textEdit->setFocus();
1334     }
1335
1336     void setCompletionModel()
1337     {
1338         textEdit->completer->setModel(0);
1339     }
1340 };
1341
1342 void tst_QCompleter::task250064_lostFocus()
1343 {
1344     task250064_TextEdit *textEdit = new task250064_TextEdit;
1345     task250064_Widget *widget = new task250064_Widget(textEdit);
1346     widget->show();
1347     QTest::qWait(100);
1348     QTest::keyPress(textEdit, 'a');
1349     Qt::FocusPolicy origPolicy = textEdit->focusPolicy();
1350     QVERIFY(origPolicy != Qt::NoFocus);
1351     widget->setCompletionModel();
1352     QCOMPARE(textEdit->focusPolicy(), origPolicy);
1353 }
1354
1355 void tst_QCompleter::task253125_lineEditCompletion_data()
1356 {
1357     QTest::addColumn<QStringList>("list");
1358     QTest::addColumn<int>("completionMode");
1359
1360     QStringList list = QStringList()
1361         << "alpha" << "beta"    << "gamma"   << "delta" << "epsilon" << "zeta"
1362         << "eta"   << "theta"   << "iota"    << "kappa" << "lambda"  << "mu"
1363         << "nu"    << "xi"      << "omicron" << "pi"    << "rho"     << "sigma"
1364         << "tau"   << "upsilon" << "phi"     << "chi"   << "psi"     << "omega";
1365
1366     QTest::newRow("Inline") << list << (int)QCompleter::InlineCompletion;
1367     QTest::newRow("Filtered") << list << (int)QCompleter::PopupCompletion;
1368     QTest::newRow("Unfiltered") << list << (int)QCompleter::UnfilteredPopupCompletion;
1369 }
1370
1371 void tst_QCompleter::task253125_lineEditCompletion()
1372 {
1373     QFETCH(QStringList, list);
1374     QFETCH(int, completionMode);
1375
1376     QStringListModel *model = new QStringListModel;
1377     model->setStringList(list);
1378
1379     QCompleter *completer = new QCompleter(list);
1380     completer->setModel(model);
1381     completer->setCompletionMode((QCompleter::CompletionMode)completionMode);
1382
1383     QLineEdit edit;
1384     edit.setCompleter(completer);
1385     edit.show();
1386     edit.setFocus();
1387     QApplication::setActiveWindow(&edit);
1388     QVERIFY(QTest::qWaitForWindowActive(&edit));
1389
1390     QTest::keyClick(&edit, 'i');
1391     QCOMPARE(edit.completer()->currentCompletion(), QString("iota"));
1392     QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
1393     QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
1394
1395     QCOMPARE(edit.text(), QString("iota"));
1396
1397     delete completer;
1398     delete model;
1399 }
1400
1401 void tst_QCompleter::task247560_keyboardNavigation()
1402 {
1403     QStandardItemModel model;
1404
1405     for (int i = 0; i < 5; i++) {
1406         for (int j = 0; j < 5; j++) {
1407             model.setItem(i, j, new QStandardItem(QString("row %1 column %2").arg(i).arg(j)));
1408         }
1409     }
1410
1411
1412     QCompleter completer(&model);
1413     completer.setCompletionColumn(1);
1414
1415     QLineEdit edit;
1416     edit.setCompleter(&completer);
1417     edit.show();
1418     edit.setFocus();
1419     QApplication::setActiveWindow(&edit);
1420     QVERIFY(QTest::qWaitForWindowActive(&edit));
1421
1422     QTest::keyClick(&edit, 'r');
1423     QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
1424     QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
1425     QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
1426
1427     QCOMPARE(edit.text(), QString("row 1 column 1"));
1428
1429     edit.clear();
1430
1431     QTest::keyClick(&edit, 'r');
1432     QTest::keyClick(edit.completer()->popup(), Qt::Key_Up);
1433     QTest::keyClick(edit.completer()->popup(), Qt::Key_Up);
1434     QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
1435
1436     QCOMPARE(edit.text(), QString("row 3 column 1"));
1437 }
1438
1439 // Helpers for QTBUG_14292_filesystem: Recursion helper for below recurseTreeModel
1440 template <class Function>
1441 bool recurseTreeModelIndex(const QModelIndex &idx, Function f, int depth = 0)
1442 {
1443     if (f(idx, depth))
1444         return true;
1445     const int rowCount = idx.model()->rowCount(idx);
1446     for (int row = 0; row < rowCount; ++row)
1447         if (recurseTreeModelIndex(idx.child(row, 0), f, depth + 1))
1448             return true;
1449     return false;
1450 }
1451
1452 // Function to recurse over a tree model applying a function
1453 // taking index and depth, returning true to terminate recursion.
1454
1455 template <class Function>
1456 bool recurseTreeModel(const QAbstractItemModel &m, Function f)
1457 {
1458     const int rowCount = m.rowCount(QModelIndex());
1459     for (int row = 0; row < rowCount; ++row)
1460         if (recurseTreeModelIndex(m.index(row, 0, QModelIndex()), f))
1461             return true;
1462     return false;
1463 }
1464
1465 // Function applicable to the above recurseTreeModel() to search for a data item.
1466 class SearchFunction
1467 {
1468 public:
1469     SearchFunction(const QString &needle, int role = Qt::DisplayRole) :
1470         m_needle(needle), m_role(role) {}
1471
1472     bool operator()(const QModelIndex &idx, int /* depth */) const
1473         { return idx.data(m_role).toString() == m_needle; }
1474
1475 private:
1476     const QString m_needle;
1477     const int m_role;
1478 };
1479
1480 // Function applicable to the above recurseTreeModel() for debug output
1481 // of a model.
1482 class DebugFunction
1483 {
1484 public:
1485     DebugFunction(QDebug d) : m_d(d) {}
1486
1487     bool operator()(const QModelIndex &idx, int depth)
1488     {
1489         for (int i = 0; i < 4 * depth; ++i)
1490             m_d << ' ';
1491         m_d << idx.data(QFileSystemModel::FileNameRole).toString()
1492             << '\n';
1493         return false;
1494     }
1495 private:
1496     QDebug m_d;
1497 };
1498
1499 QDebug operator<<(QDebug d, const QAbstractItemModel &m)
1500 {
1501     QDebug dns = d.nospace();
1502     dns << '\n';
1503     recurseTreeModel(m, DebugFunction(dns));
1504     return d;
1505 }
1506
1507 static const char testDir1[] = "hello";
1508 static const char testDir2[] = "holla";
1509
1510 // Helper for QTBUG_14292_filesystem, checking whether both
1511 // test directories are seen by the file system model for usage
1512 // with QTRY_VERIFY.
1513
1514 static inline bool testFileSystemReady(const QAbstractItemModel &model)
1515 {
1516     return recurseTreeModel(model, SearchFunction(QLatin1String(testDir1), QFileSystemModel::FileNameRole))
1517            && recurseTreeModel(model, SearchFunction(QLatin1String(testDir2), QFileSystemModel::FileNameRole));
1518 }
1519
1520 void tst_QCompleter::QTBUG_14292_filesystem()
1521 {
1522     // This test tests whether the creation of subdirectories
1523     // does not cause completers based on file system models
1524     // to pop up the completion list due to file changed signals.
1525     FileSystem fs;
1526     QFileSystemModel model;
1527     model.setRootPath(fs.path());
1528
1529     QVERIFY(fs.createDirectory(QLatin1String(testDir1)));
1530     QVERIFY(fs.createDirectory(QLatin1String(testDir2)));
1531
1532     QLineEdit edit;
1533     QCompleter comp;
1534     comp.setModel(&model);
1535     edit.setCompleter(&comp);
1536
1537     edit.show();
1538     QApplication::setActiveWindow(&edit);
1539     QVERIFY(QTest::qWaitForWindowActive(&edit));
1540     QCOMPARE(QApplication::activeWindow(), &edit);
1541     edit.setFocus();
1542     QTRY_VERIFY(edit.hasFocus());
1543
1544     // Wait for all file system model slots/timers to trigger
1545     // until the model sees the subdirectories.
1546     QTRY_VERIFY(testFileSystemReady(model));
1547     // But this should not cause the combo to pop up.
1548     QVERIFY(!comp.popup()->isVisible());
1549     edit.setText(fs.path());
1550     QTest::keyClick(&edit, '/');
1551     QTRY_VERIFY(comp.popup()->isVisible());
1552     QCOMPARE(comp.popup()->model()->rowCount(), 2);
1553     QApplication::processEvents();
1554     QTest::keyClick(&edit, 'h');
1555     QCOMPARE(comp.popup()->model()->rowCount(), 2);
1556     QTest::keyClick(&edit, 'e');
1557     QCOMPARE(comp.popup()->model()->rowCount(), 1);
1558     QTest::keyClick(&edit, 'r');
1559     QTRY_VERIFY(!comp.popup()->isVisible());
1560     QVERIFY(fs.createDirectory(QStringLiteral("hero")));
1561     QTRY_VERIFY(comp.popup()->isVisible());
1562     QCOMPARE(comp.popup()->model()->rowCount(), 1);
1563     QTest::keyClick(comp.popup(), Qt::Key_Escape);
1564     QTRY_VERIFY(!comp.popup()->isVisible());
1565     QVERIFY(fs.createDirectory(QStringLiteral("nothingThere")));
1566     //there is no reason creating a file should open a popup, it did in Qt 4.7.0
1567     QTest::qWait(60);
1568     QVERIFY(!comp.popup()->isVisible());
1569
1570     QTest::keyClick(&edit, Qt::Key_Backspace);
1571     QTRY_VERIFY(comp.popup()->isVisible());
1572     QCOMPARE(comp.popup()->model()->rowCount(), 2);
1573     QTest::keyClick(&edit, 'm');
1574     QTRY_VERIFY(!comp.popup()->isVisible());
1575
1576     QWidget w;
1577     w.show();
1578     QApplication::setActiveWindow(&w);
1579     QVERIFY(QTest::qWaitForWindowActive(&w));
1580     QVERIFY(!edit.hasFocus() && !comp.popup()->hasFocus());
1581
1582     QVERIFY(fs.createDirectory(QStringLiteral("hemo")));
1583     //there is no reason creating a file should open a popup, it did in Qt 4.7.0
1584     QTest::qWait(60);
1585     QVERIFY(!comp.popup()->isVisible());
1586 }
1587
1588 QTEST_MAIN(tst_QCompleter)
1589 #include "tst_qcompleter.moc"