/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "qcompleter.h" #include #include #include #include #include #include #include "../../shared/util.h" //TESTED_CLASS= //TESTED_FILES= class CsvCompleter : public QCompleter { Q_OBJECT public: CsvCompleter(QObject *parent = 0) : QCompleter(parent), csv(true) { } QString pathFromIndex(const QModelIndex& sourceIndex) const; void setCsvCompletion(bool set) { csv = set; } protected: QStringList splitPath(const QString &path) const { return csv ? path.split(",") : QCompleter::splitPath(path); } private: bool csv; }; QString CsvCompleter::pathFromIndex(const QModelIndex& si) const { if (!csv) return QCompleter::pathFromIndex(si); if (!si.isValid()) return QString(); QModelIndex idx = si; QStringList list; do { QString t = model()->data(idx, completionRole()).toString(); list.prepend(t); QModelIndex parent = idx.parent(); idx = parent.sibling(parent.row(), si.column()); } while (idx.isValid()); if (list.count() == 1) return list[0]; return list.join(","); } class tst_QCompleter : public QObject { Q_OBJECT public: tst_QCompleter(); ~tst_QCompleter(); private slots: void multipleWidgets(); void focusIn(); void csMatchingOnCsSortedModel_data(); void csMatchingOnCsSortedModel(); void ciMatchingOnCiSortedModel_data(); void ciMatchingOnCiSortedModel(); void ciMatchingOnCsSortedModel_data(); void ciMatchingOnCsSortedModel(); void csMatchingOnCiSortedModel_data(); void csMatchingOnCiSortedModel(); void directoryModel_data(); void directoryModel(); void changingModel_data(); void changingModel(); void sortedEngineRowCount_data(); void sortedEngineRowCount(); void unsortedEngineRowCount_data(); void unsortedEngineRowCount(); void currentRow(); void sortedEngineMapFromSource(); void unsortedEngineMapFromSource(); void historySearch(); void modelDeletion(); void setters(); void dynamicSortOrder(); // task-specific tests below me void task178797_activatedOnReturn(); void task189564_omitNonSelectableItems(); void task246056_setCompletionPrefix(); void task250064_lostFocus(); private: void filter(); void testRowCount(); enum ModelType { CASE_SENSITIVELY_SORTED_MODEL, CASE_INSENSITIVELY_SORTED_MODEL, DIRECTORY_MODEL, HISTORY_MODEL }; void setSourceModel(ModelType); CsvCompleter *completer; QTreeWidget *treeWidget; const int completionColumn; const int columnCount; }; tst_QCompleter::tst_QCompleter() : completer(0), completionColumn(0), columnCount(3) { treeWidget = new QTreeWidget; treeWidget->setColumnCount(columnCount); } tst_QCompleter::~tst_QCompleter() { delete treeWidget; delete completer; } void tst_QCompleter::setSourceModel(ModelType type) { QString text; QTreeWidgetItem *parent, *child; treeWidget->clear(); switch(type) { case CASE_SENSITIVELY_SORTED_MODEL: // Creates a tree model with top level items P0, P1, .., p0, p1,.. // Each of these items parents have children (for P0 - c0P0, c1P0,...) for (int i = 0; i < 2; i++) { for (int j = 0; j < 5; j++) { parent = new QTreeWidgetItem(treeWidget); text.sprintf("%c%i", i == 0 ? 'P' : 'p', j); parent->setText(completionColumn, text); for (int k = 0; k < 5; k++) { child = new QTreeWidgetItem(parent); QString t = QString().sprintf("c%i", k) + text; child->setText(completionColumn, t); } } } completer->setModel(treeWidget->model()); completer->setCompletionColumn(completionColumn); break; case CASE_INSENSITIVELY_SORTED_MODEL: case HISTORY_MODEL: // Creates a tree model with top level items P0, p0, P1, p1,... // Each of these items have children c0p0, c1p0,.. for (int i = 0; i < 5; i++) { for (int j = 0; j < 2; j++) { parent = new QTreeWidgetItem(treeWidget); text.sprintf("%c%i", j == 0 ? 'P' : 'p', i); parent->setText(completionColumn, text); for (int k = 0; k < 5; k++) { child = new QTreeWidgetItem(parent); QString t = QString().sprintf("c%i", k) + text; child->setText(completionColumn, t); } } } completer->setModel(treeWidget->model()); completer->setCompletionColumn(completionColumn); if (type == CASE_INSENSITIVELY_SORTED_MODEL) break; parent = new QTreeWidgetItem(treeWidget); parent->setText(completionColumn, QLatin1String("p3,c3p3")); parent = new QTreeWidgetItem(treeWidget); parent->setText(completionColumn, QLatin1String("p2,c4p2")); break; case DIRECTORY_MODEL: completer->setCsvCompletion(false); completer->setModel(new QDirModel(completer)); completer->setCompletionColumn(0); break; default: qDebug() << "Invalid type"; } } void tst_QCompleter::filter() { QFETCH(QString, filterText); QFETCH(QString, step); QFETCH(QString, completion); QFETCH(QString, completionText); if (filterText.compare("FILTERING_OFF", Qt::CaseInsensitive) == 0) { completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); return; } completer->setCompletionPrefix(filterText); for (int i = 0; i < step.length(); i++) { int row = completer->currentRow(); switch (step[i].toUpper().toAscii()) { case 'P': --row; break; case 'N': ++row; break; case 'L': row = completer->completionCount() - 1; break; case 'F': row = 0; break; default: Q_ASSERT(false); } completer->setCurrentRow(row); } //QModelIndex si = completer->currentIndex(); //QCOMPARE(completer->model()->data(si).toString(), completion); QCOMPARE(completer->currentCompletion(), completionText); } void tst_QCompleter::csMatchingOnCsSortedModel_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseSensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseSensitive); setSourceModel(CASE_SENSITIVELY_SORTED_MODEL); QTest::addColumn("filterText"); QTest::addColumn("step"); QTest::addColumn("completion"); QTest::addColumn("completionText"); for (int i = 0; i < 2; i++) { if (i == 1) QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << ""; // Plain text filter QTest::newRow("()") << "" << "" << "P0" << "P0"; QTest::newRow("()F") << "" << "F" << "P0" << "P0"; QTest::newRow("()L") << "" << "L" << "p4" << "p4"; QTest::newRow("()L") << "" << "L" << "p4" << "p4"; QTest::newRow("()N") << "" << "N" << "P1" << "P1"; QTest::newRow("(P)") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)F") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)L") << "P" << "L" << "P4" << "P4"; QTest::newRow("(p)") << "p" << "" << "p0" << "p0"; QTest::newRow("(p)N") << "p" << "N" << "p1" << "p1"; QTest::newRow("(p)NN") << "p" << "NN" << "p2" << "p2"; QTest::newRow("(p)NNN") << "p" << "NNN" << "p3" << "p3"; QTest::newRow("(p)NNNN") << "p" << "NNNN" << "p4" << "p4"; QTest::newRow("(p1)") << "p1" << "" << "p1" << "p1"; QTest::newRow("(p11)") << "p11" << "" << "" << ""; // Tree filter QTest::newRow("(P0,)") << "P0," << "" << "c0P0" << "P0,c0P0"; QTest::newRow("(P0,c)") << "P0,c" << "" << "c0P0" << "P0,c0P0"; QTest::newRow("(P0,c1)") << "P0,c1" << "" << "c1P0" << "P0,c1P0"; QTest::newRow("(P0,c3P0)") << "P0,c3P0" << "" << "c3P0" << "P0,c3P0"; QTest::newRow("(P3,c)F") << "P3,c" << "F" << "c0P3" << "P3,c0P3"; QTest::newRow("(P3,c)L") << "P3,c" << "L" << "c4P3" << "P3,c4P3"; QTest::newRow("(P3,c)N") << "P3,c" << "N" << "c1P3" << "P3,c1P3"; QTest::newRow("(P3,c)NN") << "P3,c" << "NN" << "c2P3" << "P3,c2P3"; QTest::newRow("(P3,,c)") << "P3,,c" << "" << "" << ""; QTest::newRow("(P3,c0P3,)") << "P3,c0P3," << "" << "" << ""; QTest::newRow("(P,)") << "P," << "" << "" << ""; } } void tst_QCompleter::csMatchingOnCsSortedModel() { filter(); } void tst_QCompleter::ciMatchingOnCiSortedModel_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseInsensitive); setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL); QTest::addColumn("filterText"); QTest::addColumn("step"); QTest::addColumn("completion"); QTest::addColumn("completionText"); for (int i = 0; i < 2; i++) { if (i == 1) QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << ""; // Plain text filter QTest::newRow("()") << "" << "" << "P0" << "P0"; QTest::newRow("()F") << "" << "F" << "P0" << "P0"; QTest::newRow("()L") << "" << "L" << "p4" << "p4"; QTest::newRow("()N") << "" << "N" << "p0" << "p0"; QTest::newRow("(P)") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)F") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)L") << "P" << "L" << "p4" << "p4"; QTest::newRow("(p)") << "p" << "" << "P0" << "P0"; QTest::newRow("(p)N") << "p" << "N" << "p0" << "p0"; QTest::newRow("(p)NN") << "p" << "NN" << "P1" << "P1"; QTest::newRow("(p)NNN") << "p" << "NNN" << "p1" << "p1"; QTest::newRow("(p1)") << "p1" << "" << "P1" << "P1"; QTest::newRow("(p1)N") << "p1" << "N" << "p1" << "p1"; QTest::newRow("(p11)") << "p11" << "" << "" << ""; //// Tree filter QTest::newRow("(p0,)") << "p0," << "" << "c0P0" << "P0,c0P0"; QTest::newRow("(p0,c)") << "p0,c" << "" << "c0P0" << "P0,c0P0"; QTest::newRow("(p0,c1)") << "p0,c1" << "" << "c1P0" << "P0,c1P0"; QTest::newRow("(p0,c3P0)") << "p0,c3P0" << "" << "c3P0" << "P0,c3P0"; QTest::newRow("(p3,c)F") << "p3,c" << "F" << "c0P3" << "P3,c0P3"; QTest::newRow("(p3,c)L") << "p3,c" << "L" << "c4P3" << "P3,c4P3"; QTest::newRow("(p3,c)N") << "p3,c" << "N" << "c1P3" << "P3,c1P3"; QTest::newRow("(p3,c)NN") << "p3,c" << "NN" << "c2P3" << "P3,c2P3"; QTest::newRow("(p3,,c)") << "p3,,c" << "" << "" << ""; QTest::newRow("(p3,c0P3,)") << "p3,c0P3," << "" << "" << ""; QTest::newRow("(p,)") << "p," << "" << "" << ""; } } void tst_QCompleter::ciMatchingOnCiSortedModel() { filter(); } void tst_QCompleter::ciMatchingOnCsSortedModel_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseSensitivelySortedModel); setSourceModel(CASE_SENSITIVELY_SORTED_MODEL); completer->setCaseSensitivity(Qt::CaseInsensitive); QTest::addColumn("filterText"); QTest::addColumn("step"); QTest::addColumn("completion"); QTest::addColumn("completionText"); for (int i = 0; i < 2; i++) { if (i == 1) QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << ""; // Plain text filter QTest::newRow("()") << "" << "" << "P0" << "P0"; QTest::newRow("()F") << "" << "F" << "P0" << "P0"; QTest::newRow("()L") << "" << "L" << "p4" << "p4"; QTest::newRow("(P)") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)F") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)L") << "P" << "L" << "p4" << "p4"; QTest::newRow("(p)") << "p" << "" << "P0" << "P0"; QTest::newRow("(p)N") << "p" << "N" << "P1" << "P1"; QTest::newRow("(p)NN") << "p" << "NN" << "P2" << "P2"; QTest::newRow("(p)NNN") << "p" << "NNN" << "P3" << "P3"; QTest::newRow("(p1)") << "p1" << "" << "P1" << "P1"; QTest::newRow("(p1)N") << "p1" << "N" << "p1" << "p1"; QTest::newRow("(p11)") << "p11" << "" << "" << ""; // Tree filter QTest::newRow("(p0,)") << "p0," << "" << "c0P0" << "P0,c0P0"; QTest::newRow("(p0,c)") << "p0,c" << "" << "c0P0" << "P0,c0P0"; QTest::newRow("(p0,c1)") << "p0,c1" << "" << "c1P0" << "P0,c1P0"; QTest::newRow("(p0,c3P0)") << "p0,c3P0" << "" << "c3P0" << "P0,c3P0"; QTest::newRow("(p3,c)F") << "p3,c" << "F" << "c0P3" << "P3,c0P3"; QTest::newRow("(p3,c)L") << "p3,c" << "L" << "c4P3" << "P3,c4P3"; QTest::newRow("(p3,c)N") << "p3,c" << "N" << "c1P3" << "P3,c1P3"; QTest::newRow("(p3,c)NN") << "p3,c" << "NN" << "c2P3" << "P3,c2P3"; QTest::newRow("(p3,,c)") << "p3,,c" << "" << "" << ""; QTest::newRow("(p3,c0P3,)") << "p3,c0P3," << "" << "" << ""; QTest::newRow("(p,)") << "p," << "" << "" << ""; } } void tst_QCompleter::ciMatchingOnCsSortedModel() { filter(); } void tst_QCompleter::csMatchingOnCiSortedModel_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL); completer->setCaseSensitivity(Qt::CaseSensitive); QTest::addColumn("filterText"); QTest::addColumn("step"); QTest::addColumn("completion"); QTest::addColumn("completionText"); for (int i = 0; i < 2; i++) { if (i == 1) QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << ""; // Plain text filter QTest::newRow("()") << "" << "" << "P0" << "P0"; QTest::newRow("()F") << "" << "F" << "P0" << "P0"; QTest::newRow("()L") << "" << "L" << "p4" << "p4"; QTest::newRow("()N") << "" << "N" << "p0" << "p0"; QTest::newRow("(P)") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)F") << "P" << "" << "P0" << "P0"; QTest::newRow("(P)L") << "P" << "L" << "P4" << "P4"; QTest::newRow("(p)") << "p" << "" << "p0" << "p0"; QTest::newRow("(p)N") << "p" << "N" << "p1" << "p1"; QTest::newRow("(p)NN") << "p" << "NN" << "p2" << "p2"; QTest::newRow("(p)NNN") << "p" << "NNN" << "p3" << "p3"; QTest::newRow("(p1)") << "p1" << "" << "p1" << "p1"; QTest::newRow("(p11)") << "p11" << "" << "" << ""; //// Tree filter QTest::newRow("(p0,)") << "p0," << "" << "c0p0" << "p0,c0p0"; QTest::newRow("(p0,c)") << "p0,c" << "" << "c0p0" << "p0,c0p0"; QTest::newRow("(p0,c1)") << "p0,c1" << "" << "c1p0" << "p0,c1p0"; QTest::newRow("(p0,c3P0)") << "p0,c3p0" << "" << "c3p0" << "p0,c3p0"; QTest::newRow("(p3,c)F") << "p3,c" << "F" << "c0p3" << "p3,c0p3"; QTest::newRow("(p3,c)L") << "p3,c" << "L" << "c4p3" << "p3,c4p3"; QTest::newRow("(p3,c)N") << "p3,c" << "N" << "c1p3" << "p3,c1p3"; QTest::newRow("(p3,c)NN") << "p3,c" << "NN" << "c2p3" << "p3,c2p3"; QTest::newRow("(p3,,c)") << "p3,,c" << "" << "" << ""; QTest::newRow("(p3,c0P3,)") << "p3,c0P3," << "" << "" << ""; QTest::newRow("(p,)") << "p," << "" << "" << ""; QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << ""; } } void tst_QCompleter::csMatchingOnCiSortedModel() { filter(); } void tst_QCompleter::directoryModel_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseSensitivelySortedModel); setSourceModel(DIRECTORY_MODEL); completer->setCaseSensitivity(Qt::CaseInsensitive); QTest::addColumn("filterText"); QTest::addColumn("step"); QTest::addColumn("completion"); QTest::addColumn("completionText"); // NOTE: Add tests carefully, ensurely the paths exist on all systems // Output is the sourceText; currentCompletionText() for (int i = 0; i < 2; i++) { if (i == 1) QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << "" << "" << ""; #if defined(Q_OS_WINCE) QTest::newRow("()") << "" << "" << "/" << "/"; QTest::newRow("()") << "\\Program" << "" << "Program Files" << "\\Program Files"; #elif defined(Q_OS_WIN) QTest::newRow("()") << "C" << "" << "C:" << "C:"; QTest::newRow("()") << "C:\\Program" << "" << "Program Files" << "C:\\Program Files"; #elif defined (Q_OS_MAC) QTest::newRow("()") << "" << "" << "/" << "/"; QTest::newRow("(/a)") << "/a" << "" << "Applications" << "/Applications"; QTest::newRow("(/d)") << "/d" << "" << "Developer" << "/Developer"; #else QTest::newRow("()") << "" << "" << "/" << "/"; #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_OS_HPUX) QTest::newRow("(/h)") << "/h" << "" << "home" << "/home"; #endif QTest::newRow("(/et)") << "/et" << "" << "etc" << "/etc"; QTest::newRow("(/etc/passw)") << "/etc/passw" << "" << "passwd" << "/etc/passwd"; #endif } } void tst_QCompleter::directoryModel() { filter(); } void tst_QCompleter::changingModel_data() { } void tst_QCompleter::changingModel() { for (int i = 0; i < 2; i++) { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseSensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseSensitive); setSourceModel(CASE_SENSITIVELY_SORTED_MODEL); if (i == 1) { completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); } completer->setCompletionPrefix("p"); completer->setCurrentRow(completer->completionCount() - 1); QCOMPARE(completer->currentCompletion(), QString("p4")); // Test addition of data QTreeWidgetItem p5item; p5item.setText(completionColumn, "p5"); treeWidget->addTopLevelItem(&p5item); completer->setCompletionPrefix("p5"); QCOMPARE(completer->currentCompletion(), QString("p5")); // Test removal of data int p5index = treeWidget->indexOfTopLevelItem(&p5item); treeWidget->takeTopLevelItem(p5index); QCOMPARE(completer->currentCompletion(), QString("")); // Test clear treeWidget->clear(); QCOMPARE(completer->currentIndex(), QModelIndex()); } } void tst_QCompleter::testRowCount() { QFETCH(QString, filterText); QFETCH(bool, hasChildren); QFETCH(int, rowCount); QFETCH(int, completionCount); if (filterText.compare("FILTERING_OFF", Qt::CaseInsensitive) == 0) { completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); return; } completer->setCompletionPrefix(filterText); const QAbstractItemModel *completionModel = completer->completionModel(); QCOMPARE(completionModel->rowCount(), rowCount); QCOMPARE(completionCount, completionCount); QCOMPARE(completionModel->hasChildren(), hasChildren); QCOMPARE(completionModel->columnCount(), columnCount); } void tst_QCompleter::sortedEngineRowCount_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseInsensitive); setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL); QTest::addColumn("filterText"); QTest::addColumn("hasChildren"); QTest::addColumn("rowCount"); QTest::addColumn("completionCount"); QTest::newRow("whatever") << "whatever" << false << 0 << 0; QTest::newRow("p") << "p" << true << 10 << 10; QTest::newRow("p1") << "p1" << true << 2 << 2; QTest::newRow("P1,") << "P1," << true << 5 << 5; QTest::newRow("P1,c") << "P1,c" << true << 5 << 5; QTest::newRow("P1,cc") << "P1,cc" << false << 0 << 0; QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << false << 0 << 0; QTest::newRow("whatever(filter off)") << "whatever" << true << 10 << 0; QTest::newRow("p1(filter off)") << "p1" << true << 10 << 2; QTest::newRow("p1,(filter off)") << "p1," << true << 5 << 5; QTest::newRow("p1,c(filter off)") << "p1,c" << true << 5 << 5; QTest::newRow("P1,cc(filter off)") << "P1,cc" << true << 5 << 0; } void tst_QCompleter::sortedEngineRowCount() { testRowCount(); } void tst_QCompleter::unsortedEngineRowCount_data() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseSensitive); setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL); QTest::addColumn("filterText"); QTest::addColumn("hasChildren"); QTest::addColumn("rowCount"); QTest::addColumn("completionCount"); QTest::newRow("whatever") << "whatever" << false << 0 << 0; QTest::newRow("p") << "p" << true << 5 << 5; QTest::newRow("p1") << "p1" << true << 1 << 1; QTest::newRow("P1,") << "P1," << true << 5 << 5; QTest::newRow("P1,c") << "P1,c" << true << 5 << 5; QTest::newRow("P1,cc") << "P1,cc" << false << 0 << 0; QTest::newRow("FILTERING_OFF") << "FILTERING_OFF" << false << 0 << 0; QTest::newRow("whatever(filter off)") << "whatever" << true << 10 << 0; QTest::newRow("p1(filter off)") << "p1" << true << 10 << 1; QTest::newRow("p1,(filter off)") << "p1," << true << 5 << 5; QTest::newRow("p1,c(filter off)") << "p1,c" << true << 5 << 5; QTest::newRow("P1,cc(filter off)") << "P1,cc" << true << 5 << 0; } void tst_QCompleter::unsortedEngineRowCount() { testRowCount(); } void tst_QCompleter::currentRow() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseInsensitive); setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL); // blank text completer->setCompletionPrefix(""); QCOMPARE(completer->currentRow(), 0); QVERIFY(completer->setCurrentRow(4)); QCOMPARE(completer->currentRow(), 4); QVERIFY(!completer->setCurrentRow(13)); QVERIFY(completer->setCurrentRow(4)); // some text completer->setCompletionPrefix("p1"); QCOMPARE(completer->currentRow(), 0); QVERIFY(completer->setCurrentRow(1)); QCOMPARE(completer->currentRow(), 1); QVERIFY(!completer->setCurrentRow(2)); QCOMPARE(completer->currentRow(), 1); // invalid text completer->setCompletionPrefix("well"); QCOMPARE(completer->currentRow(), -1); } void tst_QCompleter::sortedEngineMapFromSource() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseInsensitive); setSourceModel(CASE_INSENSITIVELY_SORTED_MODEL); QModelIndex si1, si2, pi; QAbstractItemModel *sourceModel = completer->model(); const QAbstractProxyModel *completionModel = qobject_cast(completer->completionModel()); // Fitering ON // empty si1 = sourceModel->index(4, completionColumn); // "P2" si2 = sourceModel->index(2, 0, si1); // "P2,c0P2" pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); // some text completer->setCompletionPrefix("p"); pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); // more text completer->setCompletionPrefix("p2"); pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); // invalid text completer->setCompletionPrefix("whatever"); pi = completionModel->mapFromSource(si1); QVERIFY(!pi.isValid()); // Fitering OFF completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); // empty si1 = sourceModel->index(4, completionColumn); // "P2" si2 = sourceModel->index(2, 0, si1); // "P2,c0P2" pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); // some text completer->setCompletionPrefix("p"); pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); // more text completer->setCompletionPrefix("p2"); pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); // invalid text completer->setCompletionPrefix("whatever"); pi = completionModel->mapFromSource(si1); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P2")); } void tst_QCompleter::unsortedEngineMapFromSource() { delete completer; completer = new CsvCompleter; completer->setCaseSensitivity(Qt::CaseInsensitive); setSourceModel(HISTORY_MODEL); // case insensitively sorted model completer->setModelSorting(QCompleter::UnsortedModel); QModelIndex si, si2, si3, pi; QAbstractItemModel *sourceModel = completer->model(); const QAbstractProxyModel *completionModel = qobject_cast(completer->completionModel()); si = sourceModel->index(6, completionColumn); // "P3" QCOMPARE(si.data().toString(), QLatin1String("P3")); si2 = sourceModel->index(3, completionColumn, sourceModel->index(0, completionColumn)); // "P0,c3P0" QCOMPARE(si2.data().toString(), QLatin1String("c3P0")); si3 = sourceModel->index(10, completionColumn); // "p3,c3p3" (history) QCOMPARE(si3.data().toString(), QLatin1String("p3,c3p3")); // FILTERING ON // empty pi = completionModel->mapFromSource(si); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); pi = completionModel->mapFromSource(si3); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("p3,c3p3")); // some text completer->setCompletionPrefix("P"); pi = completionModel->mapFromSource(si); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3")); pi = completionModel->mapFromSource(si2); QCOMPARE(pi.isValid(), false); pi = completionModel->mapFromSource(si3); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("p3,c3p3")); // invalid text completer->setCompletionPrefix("whatever"); pi = completionModel->mapFromSource(si); QVERIFY(!pi.isValid()); pi = completionModel->mapFromSource(si2); QVERIFY(!pi.isValid()); // tree matching completer->setCompletionPrefix("P0,c"); pi = completionModel->mapFromSource(si); QVERIFY(!pi.isValid()); pi = completionModel->mapFromSource(si2); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("c3P0")); pi = completionModel->mapFromSource(si3); QCOMPARE(pi.isValid(), false); // more tree matching completer->setCompletionPrefix("p3,"); pi = completionModel->mapFromSource(si2); QVERIFY(!pi.isValid()); pi = completionModel->mapFromSource(si3); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("p3,c3p3")); // FILTERING OFF // empty completer->setCompletionPrefix(""); completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); pi = completionModel->mapFromSource(si); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3")); // some text completer->setCompletionPrefix("P"); pi = completionModel->mapFromSource(si); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3")); // more text completer->setCompletionPrefix("P3"); pi = completionModel->mapFromSource(si); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3")); // invalid text completer->setCompletionPrefix("whatever"); pi = completionModel->mapFromSource(si); QCOMPARE(completionModel->data(pi).toString(), QLatin1String("P3")); } void tst_QCompleter::historySearch() { delete completer; completer = new CsvCompleter; completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity(Qt::CaseSensitive); setSourceModel(HISTORY_MODEL); const QAbstractProxyModel *completionModel = qobject_cast(completer->completionModel()); // "p3,c3p3" and "p2,c4p2" are added in the tree root // FILTERING ON // empty completer->setCurrentRow(10); QCOMPARE(completer->currentCompletion(), QLatin1String("p3,c3p3")); // more text completer->setCompletionPrefix("p2"); completer->setCurrentRow(1); QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2")); // comma separated text completer->setCompletionPrefix("p2,c4"); completer->setCurrentRow(1); QCOMPARE(completionModel->rowCount(), 2); QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2")); // invalid text completer->setCompletionPrefix("whatever"); QCOMPARE(completer->currentCompletion(), QString()); // FILTERING OFF completer->setCompletionPrefix(""); completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); completer->setCurrentRow(10); QCOMPARE(completer->currentCompletion(), QLatin1String("p3,c3p3")); // more text completer->setCompletionPrefix("p2"); completer->setCurrentRow(1); QCOMPARE(completer->currentCompletion(), QLatin1String("p2,c4p2")); // comma separated text completer->setCompletionPrefix("p2,c4"); QCOMPARE(completionModel->rowCount(), 5); // invalid text completer->setCompletionPrefix("whatever"); QCOMPARE(completer->currentCompletion(), QString()); } void tst_QCompleter::setters() { delete completer; completer = new CsvCompleter; QVERIFY(completer->popup() != 0); QPointer dirModel = new QDirModel(completer); QAbstractItemModel *oldModel = completer->model(); completer->setModel(dirModel); QVERIFY(completer->popup()->model() != oldModel); QVERIFY(completer->popup()->model() == completer->completionModel()); completer->setPopup(new QListView); QVERIFY(completer->popup()->model() == completer->completionModel()); completer->setModel(new QStringListModel(completer)); QVERIFY(dirModel == 0); // must have been deleted completer->setModel(0); completer->setWidget(0); } void tst_QCompleter::modelDeletion() { delete completer; completer = new CsvCompleter; QStringList list; list << "item1" << "item2" << "item3"; QStringListModel *listModel = new QStringListModel(list); completer->setCompletionPrefix("i"); completer->setModel(listModel); QVERIFY(completer->completionCount() == 3); QListView *view = new QListView; view->setModel(completer->completionModel()); delete listModel; view->show(); qApp->processEvents(); delete view; QVERIFY(completer->completionCount() == 0); QVERIFY(completer->currentRow() == -1); } void tst_QCompleter::multipleWidgets() { QStringList list; list << "item1" << "item2" << "item2"; QCompleter completer(list); completer.setCompletionMode(QCompleter::InlineCompletion); QWidget window; window.show(); QApplication::setActiveWindow(&window); QTRY_VERIFY(qApp->activeWindow() == &window); QFocusEvent focusIn(QEvent::FocusIn); QFocusEvent focusOut(QEvent::FocusOut); QComboBox *comboBox = new QComboBox(&window); comboBox->setEditable(true); comboBox->setCompleter(&completer); comboBox->setFocus(); comboBox->show(); window.activateWindow(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&window); #endif QTest::qWait(5000); QTRY_VERIFY(qApp->focusWidget() == comboBox); comboBox->lineEdit()->setText("it"); QCOMPARE(comboBox->currentText(), QString("it")); // should not complete with setText QTest::keyPress(comboBox, 'e'); QCOMPARE(comboBox->currentText(), QString("item1")); comboBox->clearEditText(); QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change! QLineEdit *lineEdit = new QLineEdit(&window); lineEdit->setCompleter(&completer); lineEdit->show(); lineEdit->setFocus(); QTest::qWait(5000); lineEdit->setText("it"); QCOMPARE(lineEdit->text(), QString("it")); // should not completer with setText QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change! QTest::keyPress(lineEdit, 'e'); QCOMPARE(lineEdit->text(), QString("item1")); QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change! } void tst_QCompleter::focusIn() { QStringList list; list << "item1" << "item2" << "item2"; QCompleter completer(list); QWidget window; window.show(); QTest::qWait(100); window.activateWindow(); QTest::qWait(100); QTRY_COMPARE(qApp->activeWindow(), &window); QComboBox *comboBox = new QComboBox(&window); comboBox->setEditable(true); comboBox->setCompleter(&completer); comboBox->show(); comboBox->lineEdit()->setText("it"); QLineEdit *lineEdit = new QLineEdit(&window); lineEdit->setCompleter(&completer); lineEdit->setText("it"); lineEdit->show(); QLineEdit *lineEdit2 = new QLineEdit(&window); // has no completer! lineEdit2->show(); comboBox->setFocus(); QTRY_VERIFY(completer.widget() == comboBox); lineEdit->setFocus(); QTRY_VERIFY(completer.widget() == lineEdit); comboBox->setFocus(); QTRY_VERIFY(completer.widget() == comboBox); lineEdit2->setFocus(); QTRY_VERIFY(completer.widget() == comboBox); } void tst_QCompleter::dynamicSortOrder() { QStandardItemModel model; QCompleter completer(&model); completer.setModelSorting(QCompleter::CaseSensitivelySortedModel); QStandardItem *root = model.invisibleRootItem(); for (int i = 0; i < 20; i++) { root->appendRow(new QStandardItem(QString("%1").arg(i))); } root->appendRow(new QStandardItem("13")); root->sortChildren(0, Qt::AscendingOrder); completer.setCompletionPrefix("1"); QCOMPARE(completer.completionCount(), 12); completer.setCompletionPrefix("13"); QCOMPARE(completer.completionCount(), 2); root->sortChildren(0, Qt::DescendingOrder); completer.setCompletionPrefix("13"); QCOMPARE(completer.completionCount(), 2); completer.setCompletionPrefix("1"); QCOMPARE(completer.completionCount(), 12); } void tst_QCompleter::task178797_activatedOnReturn() { QStringList words; words << "foobar1" << "foobar2"; QLineEdit *ledit = new QLineEdit; QCompleter *completer = new QCompleter(words); ledit->setCompleter(completer); QSignalSpy spy(completer, SIGNAL(activated(const QString))); QCOMPARE(spy.count(), 0); ledit->show(); QTest::keyClick(ledit, Qt::Key_F); qApp->processEvents(); QVERIFY(qApp->activePopupWidget()); QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Down); qApp->processEvents(); QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Return); qApp->processEvents(); QCOMPARE(spy.count(), 1); } class task189564_StringListModel : public QStringListModel { const QString omitString; Qt::ItemFlags flags(const QModelIndex &index) const { Qt::ItemFlags flags = Qt::ItemIsEnabled; if (data(index, Qt::DisplayRole).toString() != omitString) flags |= Qt::ItemIsSelectable; return flags; } public: task189564_StringListModel(const QString &omitString, QObject *parent = 0) : QStringListModel(parent) , omitString(omitString) { } }; void tst_QCompleter::task189564_omitNonSelectableItems() { const QString prefix("a"); Q_ASSERT(!prefix.isEmpty()); const int n = 5; Q_ASSERT(n > 0); QStringList strings; for (int i = 0; i < n; ++i) strings << QString("%1%2").arg(prefix).arg(i); const QString omitString(strings.at(n / 2)); task189564_StringListModel model(omitString); model.setStringList(strings); QCompleter completer_(&model); completer_.setCompletionPrefix(prefix); QAbstractItemModel *completionModel = completer_.completionModel(); QModelIndexList matches1 = completionModel->match(completionModel->index(0, 0), Qt::DisplayRole, prefix, -1); QCOMPARE(matches1.size(), n - 1); QModelIndexList matches2 = completionModel->match(completionModel->index(0, 0), Qt::DisplayRole, omitString); QVERIFY(matches2.isEmpty()); } class task246056_ComboBox : public QComboBox { Q_OBJECT public: task246056_ComboBox() { setEditable(true); setInsertPolicy(NoInsert); Q_ASSERT(completer()); completer()->setCompletionMode(QCompleter::PopupCompletion); completer()->setCompletionRole(Qt::DisplayRole); connect(lineEdit(), SIGNAL(editingFinished()), SLOT(setCompletionPrefix())); } private slots: void setCompletionPrefix() { completer()->setCompletionPrefix(lineEdit()->text()); } }; void tst_QCompleter::task246056_setCompletionPrefix() { task246056_ComboBox *comboBox = new task246056_ComboBox; comboBox->addItem(""); comboBox->addItem("a1"); comboBox->addItem("a2"); comboBox->show(); comboBox->setFocus(); QTest::qWait(100); QTest::keyPress(comboBox, 'a'); QTest::keyPress(comboBox->completer()->popup(), Qt::Key_Down); QTest::keyPress(comboBox->completer()->popup(), Qt::Key_Down); QTest::keyPress(comboBox->completer()->popup(), Qt::Key_Enter); // don't crash! } class task250064_TextEdit : public QTextEdit { public: QCompleter *completer; task250064_TextEdit() { completer = new QCompleter; completer->setWidget(this); } void keyPressEvent (QKeyEvent *e) { completer->popup(); QTextEdit::keyPressEvent(e); } }; class task250064_Widget : public QWidget { Q_OBJECT public: task250064_TextEdit *textEdit; task250064_Widget(task250064_TextEdit *textEdit) : textEdit(textEdit) { QTabWidget *tabWidget = new QTabWidget; tabWidget->setFocusPolicy(Qt::ClickFocus); tabWidget->addTab(textEdit, "untitled"); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(tabWidget); textEdit->setPlainText("bla bla bla"); textEdit->setFocus(); } void setCompletionModel() { textEdit->completer->setModel(0); } }; void tst_QCompleter::task250064_lostFocus() { task250064_TextEdit *textEdit = new task250064_TextEdit; task250064_Widget *widget = new task250064_Widget(textEdit); widget->show(); QTest::qWait(100); QTest::keyPress(textEdit, 'a'); Qt::FocusPolicy origPolicy = textEdit->focusPolicy(); QVERIFY(origPolicy != Qt::NoFocus); widget->setCompletionModel(); QCOMPARE(textEdit->focusPolicy(), origPolicy); } QTEST_MAIN(tst_QCompleter) #include "tst_qcompleter.moc"