1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
50 #include "../../../../shared/filesystem.h"
52 class CsvCompleter : public QCompleter
56 CsvCompleter(QObject *parent = 0) : QCompleter(parent), csv(true) { }
58 QString pathFromIndex(const QModelIndex& sourceIndex) const;
60 void setCsvCompletion(bool set) { csv = set; }
63 QStringList splitPath(const QString &path) const {
64 return csv ? path.split(",") : QCompleter::splitPath(path);
71 QString CsvCompleter::pathFromIndex(const QModelIndex& si) const
74 return QCompleter::pathFromIndex(si);
82 QString t = model()->data(idx, completionRole()).toString();
84 QModelIndex parent = idx.parent();
85 idx = parent.sibling(parent.row(), si.column());
86 } while (idx.isValid());
88 if (list.count() == 1)
90 return list.join(",");
93 class tst_QCompleter : public QObject
103 void multipleWidgets();
106 void csMatchingOnCsSortedModel_data();
107 void csMatchingOnCsSortedModel();
108 void ciMatchingOnCiSortedModel_data();
109 void ciMatchingOnCiSortedModel();
111 void ciMatchingOnCsSortedModel_data();
112 void ciMatchingOnCsSortedModel();
113 void csMatchingOnCiSortedModel_data();
114 void csMatchingOnCiSortedModel();
116 void directoryModel_data();
117 void directoryModel();
118 void fileSystemModel_data();
119 void fileSystemModel();
121 void changingModel_data();
122 void changingModel();
124 void sortedEngineRowCount_data();
125 void sortedEngineRowCount();
126 void unsortedEngineRowCount_data();
127 void unsortedEngineRowCount();
130 void sortedEngineMapFromSource();
131 void unsortedEngineMapFromSource();
133 void historySearch();
135 void modelDeletion();
138 void dynamicSortOrder();
139 void disabledItems();
141 // task-specific tests below me
142 void task178797_activatedOnReturn();
143 void task189564_omitNonSelectableItems();
144 void task246056_setCompletionPrefix();
145 void task250064_lostFocus();
147 void task253125_lineEditCompletion_data();
148 void task253125_lineEditCompletion();
149 void task247560_keyboardNavigation();
150 void QTBUG_14292_filesystem();
153 void filter(bool assync = false);
156 CASE_SENSITIVELY_SORTED_MODEL,
157 CASE_INSENSITIVELY_SORTED_MODEL,
162 void setSourceModel(ModelType);
164 CsvCompleter *completer;
165 QTreeWidget *treeWidget;
166 const int completionColumn;
167 const int columnCount;
170 tst_QCompleter::tst_QCompleter() : completer(0), completionColumn(0), columnCount(3)
172 treeWidget = new QTreeWidget;
173 treeWidget->setColumnCount(columnCount);
176 tst_QCompleter::~tst_QCompleter()
182 void tst_QCompleter::setSourceModel(ModelType type)
185 QTreeWidgetItem *parent, *child;
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);
203 completer->setModel(treeWidget->model());
204 completer->setCompletionColumn(completionColumn);
206 case CASE_INSENSITIVELY_SORTED_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);
222 completer->setModel(treeWidget->model());
223 completer->setCompletionColumn(completionColumn);
224 if (type == CASE_INSENSITIVELY_SORTED_MODEL)
226 parent = new QTreeWidgetItem(treeWidget);
227 parent->setText(completionColumn, QLatin1String("p3,c3p3"));
228 parent = new QTreeWidgetItem(treeWidget);
229 parent->setText(completionColumn, QLatin1String("p2,c4p2"));
231 case DIRECTORY_MODEL:
232 completer->setCsvCompletion(false);
233 completer->setModel(new QDirModel(completer));
234 completer->setCompletionColumn(0);
236 case FILESYSTEM_MODEL:
237 completer->setCsvCompletion(false);
239 QFileSystemModel *m = new QFileSystemModel(completer);
241 completer->setModel(m);
243 completer->setCompletionColumn(0);
246 qDebug() << "Invalid type";
250 void tst_QCompleter::filter(bool assync)
252 QFETCH(QString, filterText);
253 QFETCH(QString, step);
254 QFETCH(QString, completion);
255 QFETCH(QString, completionText);
257 if (filterText.compare("FILTERING_OFF", Qt::CaseInsensitive) == 0) {
258 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
265 completer->setCompletionPrefix(filterText);
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;
275 QFAIL(qPrintable(QString(
276 "Problem with 'step' value in test data: %1 (only P, N, L and F are allowed)."
279 completer->setCurrentRow(row);
282 int r = QString::compare(completer->currentCompletion(), completionText, completer->caseSensitivity());
283 if (assync && r && times < 10) {
285 QTest::qWait(50*times);
291 // Testing get/set functions
292 void tst_QCompleter::getSetCheck()
294 QStandardItemModel model(3,3);
295 QCompleter completer(&model);
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());
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);
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);
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);
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));
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
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);
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);
357 void tst_QCompleter::csMatchingOnCsSortedModel_data()
360 completer = new CsvCompleter;
361 completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
362 completer->setCaseSensitivity(Qt::CaseSensitive);
363 setSourceModel(CASE_SENSITIVELY_SORTED_MODEL);
365 QTest::addColumn<QString>("filterText");
366 QTest::addColumn<QString>("step");
367 QTest::addColumn<QString>("completion");
368 QTest::addColumn<QString>("completionText");
370 #define ROWNAME(name) (qPrintable(QString("%1 %2").arg(name).arg(i)))
372 for (int i = 0; i < 2; i++) {
374 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
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" << "" << "" << "";
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," << "" << "" << "";
408 void tst_QCompleter::csMatchingOnCsSortedModel()
413 void tst_QCompleter::ciMatchingOnCiSortedModel_data()
416 completer = new CsvCompleter;
417 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
418 completer->setCaseSensitivity(Qt::CaseInsensitive);
419 setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
421 QTest::addColumn<QString>("filterText");
422 QTest::addColumn<QString>("step");
423 QTest::addColumn<QString>("completion");
424 QTest::addColumn<QString>("completionText");
426 for (int i = 0; i < 2; i++) {
428 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
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" << "" << "" << "";
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," << "" << "" << "";
461 void tst_QCompleter::ciMatchingOnCiSortedModel()
466 void tst_QCompleter::ciMatchingOnCsSortedModel_data()
469 completer = new CsvCompleter;
470 completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
471 setSourceModel(CASE_SENSITIVELY_SORTED_MODEL);
472 completer->setCaseSensitivity(Qt::CaseInsensitive);
474 QTest::addColumn<QString>("filterText");
475 QTest::addColumn<QString>("step");
476 QTest::addColumn<QString>("completion");
477 QTest::addColumn<QString>("completionText");
479 for (int i = 0; i < 2; i++) {
481 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
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" << "" << "" << "";
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," << "" << "" << "";
513 void tst_QCompleter::ciMatchingOnCsSortedModel()
518 void tst_QCompleter::csMatchingOnCiSortedModel_data()
521 completer = new CsvCompleter;
522 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
523 setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
524 completer->setCaseSensitivity(Qt::CaseSensitive);
526 QTest::addColumn<QString>("filterText");
527 QTest::addColumn<QString>("step");
528 QTest::addColumn<QString>("completion");
529 QTest::addColumn<QString>("completionText");
531 for (int i = 0; i < 2; i++) {
533 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
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" << "" << "" << "";
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," << "" << "" << "";
563 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
567 void tst_QCompleter::csMatchingOnCiSortedModel()
572 void tst_QCompleter::directoryModel_data()
576 completer = new CsvCompleter;
577 completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
578 setSourceModel(DIRECTORY_MODEL);
579 completer->setCaseSensitivity(Qt::CaseInsensitive);
581 QTest::addColumn<QString>("filterText");
582 QTest::addColumn<QString>("step");
583 QTest::addColumn<QString>("completion");
584 QTest::addColumn<QString>("completionText");
586 // NOTE: Add tests carefully, ensurely the paths exist on all systems
587 // Output is the sourceText; currentCompletionText()
589 for (int i = 0; i < 2; i++) {
591 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
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";
604 QTest::newRow("()") << "" << "" << "/" << "/";
605 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_OS_HPUX)
606 QTest::newRow("(/h)") << "/h" << "" << "home" << "/home";
608 QTest::newRow("(/et)") << "/et" << "" << "etc" << "/etc";
609 QTest::newRow("(/etc/passw)") << "/etc/passw" << "" << "passwd" << "/etc/passwd";
614 void tst_QCompleter::directoryModel()
619 void tst_QCompleter::fileSystemModel_data()
622 completer = new CsvCompleter;
623 completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
624 setSourceModel(FILESYSTEM_MODEL);
625 completer->setCaseSensitivity(Qt::CaseInsensitive);
627 QTest::addColumn<QString>("filterText");
628 QTest::addColumn<QString>("step");
629 QTest::addColumn<QString>("completion");
630 QTest::addColumn<QString>("completionText");
632 // NOTE: Add tests carefully, ensurely the paths exist on all systems
633 // Output is the sourceText; currentCompletionText()
635 for (int i = 0; i < 2; i++) {
637 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << "";
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";
650 QTest::newRow("()") << "" << "" << "/" << "/";
651 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_OS_HPUX)
652 QTest::newRow("(/h)") << "/h" << "" << "home" << "/home";
654 QTest::newRow("(/et)") << "/et" << "" << "etc" << "/etc";
655 QTest::newRow("(/etc/passw)") << "/etc/passw" << "" << "passwd" << "/etc/passwd";
660 void tst_QCompleter::fileSystemModel()
662 //QFileSystemModel is assync.
667 void tst_QCompleter::changingModel_data()
671 void tst_QCompleter::changingModel()
673 for (int i = 0; i < 2; i++) {
675 completer = new CsvCompleter;
676 completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
677 completer->setCaseSensitivity(Qt::CaseSensitive);
678 setSourceModel(CASE_SENSITIVELY_SORTED_MODEL);
681 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
684 completer->setCompletionPrefix("p");
685 completer->setCurrentRow(completer->completionCount() - 1);
686 QCOMPARE(completer->currentCompletion(), QString("p4"));
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"));
695 // Test removal of data
696 int p5index = treeWidget->indexOfTopLevelItem(&p5item);
697 treeWidget->takeTopLevelItem(p5index);
698 QCOMPARE(completer->currentCompletion(), QString(""));
702 QCOMPARE(completer->currentIndex(), QModelIndex());
706 void tst_QCompleter::testRowCount()
708 QFETCH(QString, filterText);
709 QFETCH(bool, hasChildren);
710 QFETCH(int, rowCount);
711 QFETCH(int, completionCount);
713 if (filterText.compare("FILTERING_OFF", Qt::CaseInsensitive) == 0) {
714 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
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);
726 void tst_QCompleter::sortedEngineRowCount_data()
729 completer = new CsvCompleter;
730 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
731 completer->setCaseSensitivity(Qt::CaseInsensitive);
732 setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
734 QTest::addColumn<QString>("filterText");
735 QTest::addColumn<bool>("hasChildren");
736 QTest::addColumn<int>("rowCount");
737 QTest::addColumn<int>("completionCount");
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;
746 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << false << 0 << 0;
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;
755 void tst_QCompleter::sortedEngineRowCount()
760 void tst_QCompleter::unsortedEngineRowCount_data()
763 completer = new CsvCompleter;
764 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
765 completer->setCaseSensitivity(Qt::CaseSensitive);
766 setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
768 QTest::addColumn<QString>("filterText");
769 QTest::addColumn<bool>("hasChildren");
770 QTest::addColumn<int>("rowCount");
771 QTest::addColumn<int>("completionCount");
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;
780 QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << false << 0 << 0;
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;
789 void tst_QCompleter::unsortedEngineRowCount()
794 void tst_QCompleter::currentRow()
797 completer = new CsvCompleter;
798 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
799 completer->setCaseSensitivity(Qt::CaseInsensitive);
800 setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
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));
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);
819 completer->setCompletionPrefix("well");
820 QCOMPARE(completer->currentRow(), -1);
823 void tst_QCompleter::sortedEngineMapFromSource()
826 completer = new CsvCompleter;
827 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
828 completer->setCaseSensitivity(Qt::CaseInsensitive);
829 setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL);
831 QModelIndex si1, si2, pi;
832 QAbstractItemModel *sourceModel = completer->model();
833 const QAbstractProxyModel *completionModel =
834 qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
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);
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);
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);
860 completer->setCompletionPrefix("whatever");
861 pi = completionModel->mapFromSource(si1);
862 QVERIFY(!pi.isValid());
865 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
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);
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);
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);
889 completer->setCompletionPrefix("whatever");
890 pi = completionModel->mapFromSource(si1);
891 QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2"));
894 void tst_QCompleter::unsortedEngineMapFromSource()
897 completer = new CsvCompleter;
898 completer->setCaseSensitivity(Qt::CaseInsensitive);
899 setSourceModel(HISTORY_MODEL); // case insensitively sorted model
900 completer->setModelSorting(QCompleter::UnsortedModel);
902 QModelIndex si, si2, si3, pi;
903 QAbstractItemModel *sourceModel = completer->model();
904 const QAbstractProxyModel *completionModel =
905 qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
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"));
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"));
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"));
933 completer->setCompletionPrefix("whatever");
934 pi = completionModel->mapFromSource(si);
935 QVERIFY(!pi.isValid());
936 pi = completionModel->mapFromSource(si2);
937 QVERIFY(!pi.isValid());
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);
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"));
957 completer->setCompletionPrefix("");
958 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
959 pi = completionModel->mapFromSource(si);
960 QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
963 completer->setCompletionPrefix("P");
964 pi = completionModel->mapFromSource(si);
965 QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
968 completer->setCompletionPrefix("P3");
969 pi = completionModel->mapFromSource(si);
970 QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
973 completer->setCompletionPrefix("whatever");
974 pi = completionModel->mapFromSource(si);
975 QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3"));
978 void tst_QCompleter::historySearch()
981 completer = new CsvCompleter;
982 completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
983 completer->setCaseSensitivity(Qt::CaseSensitive);
984 setSourceModel(HISTORY_MODEL);
986 const QAbstractProxyModel *completionModel =
987 qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
989 // "p3,c3p3" and "p2,c4p2" are added in the tree root
993 completer->setCurrentRow(10);
994 QCOMPARE(completer->currentCompletion(), QLatin1String("p3,c3p3"));
997 completer->setCompletionPrefix("p2");
998 completer->setCurrentRow(1);
999 QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2"));
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"));
1008 completer->setCompletionPrefix("whatever");
1009 QCOMPARE(completer->currentCompletion(), QString());
1012 completer->setCompletionPrefix("");
1013 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
1014 completer->setCurrentRow(10);
1015 QCOMPARE(completer->currentCompletion(), QLatin1String("p3,c3p3"));
1018 completer->setCompletionPrefix("p2");
1019 completer->setCurrentRow(1);
1020 QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2"));
1022 // comma separated text
1023 completer->setCompletionPrefix("p2,c4");
1024 QCOMPARE(completionModel->rowCount(), 5);
1027 completer->setCompletionPrefix("whatever");
1028 QCOMPARE(completer->currentCompletion(), QString());
1031 void tst_QCompleter::setters()
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
1046 completer->setModel(0);
1047 completer->setWidget(0);
1050 void tst_QCompleter::modelDeletion()
1053 completer = new CsvCompleter;
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());
1064 qApp->processEvents();
1066 QVERIFY(completer->completionCount() == 0);
1067 QVERIFY(completer->currentRow() == -1);
1070 void tst_QCompleter::multipleWidgets()
1073 list << "item1" << "item2" << "item2";
1074 QCompleter completer(list);
1075 completer.setCompletionMode(QCompleter::InlineCompletion);
1079 QApplication::setActiveWindow(&window);
1080 QVERIFY(QTest::qWaitForWindowActive(&window));
1081 QVERIFY(qApp->activeWindow() == &window);
1083 QFocusEvent focusIn(QEvent::FocusIn);
1084 QFocusEvent focusOut(QEvent::FocusOut);
1086 QComboBox *comboBox = new QComboBox(&window);
1087 comboBox->setEditable(true);
1088 comboBox->setCompleter(&completer);
1089 comboBox->setFocus();
1091 window.activateWindow();
1092 QApplication::setActiveWindow(&window);
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!
1102 QLineEdit *lineEdit = new QLineEdit(&window);
1103 lineEdit->setCompleter(&completer);
1105 lineEdit->setFocus();
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!
1116 void tst_QCompleter::focusIn()
1119 list << "item1" << "item2" << "item2";
1120 QCompleter completer(list);
1125 window.activateWindow();
1126 QApplication::setActiveWindow(&window);
1129 QTRY_COMPARE(qApp->activeWindow(), &window);
1131 QComboBox *comboBox = new QComboBox(&window);
1132 comboBox->setEditable(true);
1133 comboBox->setCompleter(&completer);
1135 comboBox->lineEdit()->setText("it");
1137 QLineEdit *lineEdit = new QLineEdit(&window);
1138 lineEdit->setCompleter(&completer);
1139 lineEdit->setText("it");
1142 QLineEdit *lineEdit2 = new QLineEdit(&window); // has no completer!
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);
1155 void tst_QCompleter::dynamicSortOrder()
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)));
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);
1171 root->sortChildren(0, Qt::DescendingOrder);
1172 completer.setCompletionPrefix("13");
1173 QCOMPARE(completer.completionCount(), 2);
1174 completer.setCompletionPrefix("1");
1175 QCOMPARE(completer.completionCount(), 12);
1178 void tst_QCompleter::disabledItems()
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);
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());
1203 void tst_QCompleter::task178797_activatedOnReturn()
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);
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);
1223 class task189564_StringListModel : public QStringListModel
1225 const QString omitString;
1226 Qt::ItemFlags flags(const QModelIndex &index) const
1228 Qt::ItemFlags flags = Qt::ItemIsEnabled;
1229 if (data(index, Qt::DisplayRole).toString() != omitString)
1230 flags |= Qt::ItemIsSelectable;
1234 task189564_StringListModel(const QString &omitString, QObject *parent = 0)
1235 : QStringListModel(parent)
1236 , omitString(omitString)
1241 void tst_QCompleter::task189564_omitNonSelectableItems()
1243 const QString prefix("a");
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);
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());
1264 class task246056_ComboBox : public QComboBox
1268 task246056_ComboBox()
1271 setInsertPolicy(NoInsert);
1273 completer()->setCompletionMode(QCompleter::PopupCompletion);
1274 completer()->setCompletionRole(Qt::DisplayRole);
1275 connect(lineEdit(), SIGNAL(editingFinished()), SLOT(setCompletionPrefix()));
1279 void setCompletionPrefix() { completer()->setCompletionPrefix(lineEdit()->text()); }
1282 void tst_QCompleter::task246056_setCompletionPrefix()
1284 task246056_ComboBox *comboBox = new task246056_ComboBox;
1285 QVERIFY(comboBox->completer());
1286 comboBox->addItem("");
1287 comboBox->addItem("a1");
1288 comboBox->addItem("a2");
1290 comboBox->setFocus();
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!
1298 class task250064_TextEdit : public QTextEdit
1301 QCompleter *completer;
1303 task250064_TextEdit()
1305 completer = new QCompleter;
1306 completer->setWidget(this);
1309 void keyPressEvent (QKeyEvent *e)
1312 QTextEdit::keyPressEvent(e);
1316 class task250064_Widget : public QWidget
1320 task250064_TextEdit *textEdit;
1322 task250064_Widget(task250064_TextEdit *textEdit)
1323 : textEdit(textEdit)
1325 QTabWidget *tabWidget = new QTabWidget;
1326 tabWidget->setFocusPolicy(Qt::ClickFocus);
1327 tabWidget->addTab(textEdit, "untitled");
1329 QVBoxLayout *layout = new QVBoxLayout(this);
1330 layout->addWidget(tabWidget);
1332 textEdit->setPlainText("bla bla bla");
1333 textEdit->setFocus();
1336 void setCompletionModel()
1338 textEdit->completer->setModel(0);
1342 void tst_QCompleter::task250064_lostFocus()
1344 task250064_TextEdit *textEdit = new task250064_TextEdit;
1345 task250064_Widget *widget = new task250064_Widget(textEdit);
1348 QTest::keyPress(textEdit, 'a');
1349 Qt::FocusPolicy origPolicy = textEdit->focusPolicy();
1350 QVERIFY(origPolicy != Qt::NoFocus);
1351 widget->setCompletionModel();
1352 QCOMPARE(textEdit->focusPolicy(), origPolicy);
1355 void tst_QCompleter::task253125_lineEditCompletion_data()
1357 QTest::addColumn<QStringList>("list");
1358 QTest::addColumn<int>("completionMode");
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";
1366 QTest::newRow("Inline") << list << (int)QCompleter::InlineCompletion;
1367 QTest::newRow("Filtered") << list << (int)QCompleter::PopupCompletion;
1368 QTest::newRow("Unfiltered") << list << (int)QCompleter::UnfilteredPopupCompletion;
1371 void tst_QCompleter::task253125_lineEditCompletion()
1373 QFETCH(QStringList, list);
1374 QFETCH(int, completionMode);
1376 QStringListModel *model = new QStringListModel;
1377 model->setStringList(list);
1379 QCompleter *completer = new QCompleter(list);
1380 completer->setModel(model);
1381 completer->setCompletionMode((QCompleter::CompletionMode)completionMode);
1384 edit.setCompleter(completer);
1387 QApplication::setActiveWindow(&edit);
1388 QVERIFY(QTest::qWaitForWindowActive(&edit));
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);
1395 QCOMPARE(edit.text(), QString("iota"));
1401 void tst_QCompleter::task247560_keyboardNavigation()
1403 QStandardItemModel model;
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)));
1412 QCompleter completer(&model);
1413 completer.setCompletionColumn(1);
1416 edit.setCompleter(&completer);
1419 QApplication::setActiveWindow(&edit);
1420 QVERIFY(QTest::qWaitForWindowActive(&edit));
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);
1427 QCOMPARE(edit.text(), QString("row 1 column 1"));
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);
1436 QCOMPARE(edit.text(), QString("row 3 column 1"));
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)
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))
1452 // Function to recurse over a tree model applying a function
1453 // taking index and depth, returning true to terminate recursion.
1455 template <class Function>
1456 bool recurseTreeModel(const QAbstractItemModel &m, Function f)
1458 const int rowCount = m.rowCount(QModelIndex());
1459 for (int row = 0; row < rowCount; ++row)
1460 if (recurseTreeModelIndex(m.index(row, 0, QModelIndex()), f))
1465 // Function applicable to the above recurseTreeModel() to search for a data item.
1466 class SearchFunction
1469 SearchFunction(const QString &needle, int role = Qt::DisplayRole) :
1470 m_needle(needle), m_role(role) {}
1472 bool operator()(const QModelIndex &idx, int /* depth */) const
1473 { return idx.data(m_role).toString() == m_needle; }
1476 const QString m_needle;
1480 // Function applicable to the above recurseTreeModel() for debug output
1485 DebugFunction(QDebug d) : m_d(d) {}
1487 bool operator()(const QModelIndex &idx, int depth)
1489 for (int i = 0; i < 4 * depth; ++i)
1491 m_d << idx.data(QFileSystemModel::FileNameRole).toString()
1499 QDebug operator<<(QDebug d, const QAbstractItemModel &m)
1501 QDebug dns = d.nospace();
1503 recurseTreeModel(m, DebugFunction(dns));
1507 static const char testDir1[] = "hello";
1508 static const char testDir2[] = "holla";
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.
1514 static inline bool testFileSystemReady(const QAbstractItemModel &model)
1516 return recurseTreeModel(model, SearchFunction(QLatin1String(testDir1), QFileSystemModel::FileNameRole))
1517 && recurseTreeModel(model, SearchFunction(QLatin1String(testDir2), QFileSystemModel::FileNameRole));
1520 void tst_QCompleter::QTBUG_14292_filesystem()
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.
1526 QFileSystemModel model;
1527 model.setRootPath(fs.path());
1529 QVERIFY(fs.createDirectory(QLatin1String(testDir1)));
1530 QVERIFY(fs.createDirectory(QLatin1String(testDir2)));
1534 comp.setModel(&model);
1535 edit.setCompleter(&comp);
1538 QApplication::setActiveWindow(&edit);
1539 QVERIFY(QTest::qWaitForWindowActive(&edit));
1540 QCOMPARE(QApplication::activeWindow(), &edit);
1542 QTRY_VERIFY(edit.hasFocus());
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
1568 QVERIFY(!comp.popup()->isVisible());
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());
1578 QApplication::setActiveWindow(&w);
1579 QVERIFY(QTest::qWaitForWindowActive(&w));
1580 QVERIFY(!edit.hasFocus() && !comp.popup()->hasFocus());
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
1585 QVERIFY(!comp.popup()->isVisible());
1588 QTEST_MAIN(tst_QCompleter)
1589 #include "tst_qcompleter.moc"