/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../../../../src/widgets/dialogs/qsidebar_p.h" #include "../../../../../src/gui/itemmodels/qfilesystemmodel_p.h" #include "../../../../../src/widgets/dialogs/qfiledialog_p.h" #include #include #include #if defined(Q_OS_WIN) #include "../../../network-settings.h" #endif #if defined QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE Q_GUI_EXPORT bool qt_test_isFetchedRoot(); Q_GUI_EXPORT void qt_test_resetFetchedRoot(); QT_END_NAMESPACE #endif static QByteArray msgDoesNotExist(const QString &name) { return (QLatin1Char('"') + QDir::toNativeSeparators(name) + QLatin1String("\" does not exist.")).toLocal8Bit(); } class tst_QFileDialog2 : public QObject { Q_OBJECT public: tst_QFileDialog2(); private slots: void initTestCase(); void init(); void cleanup(); #ifdef QT_BUILD_INTERNAL void deleteDirAndFiles(); void listRoot(); void task227304_proxyOnFileDialog(); void task236402_dontWatchDeletedDir(); void task251321_sideBarHiddenEntries(); void task251341_sideBarRemoveEntries(); void task257579_sideBarWithNonCleanUrls(); #endif void heapCorruption(); void filter(); void showNameFilterDetails(); void unc(); void emptyUncPath(); #if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_MENU) void task143519_deleteAndRenameActionBehavior(); #endif void task178897_minimumSize(); void task180459_lastDirectory_data(); void task180459_lastDirectory(); #ifndef Q_OS_MAC void task227930_correctNavigationKeyboardBehavior(); #endif #if defined(Q_OS_WIN) void task226366_lowerCaseHardDriveWindows(); #endif void completionOnLevelAfterRoot(); void task233037_selectingDirectory(); void task235069_hideOnEscape_data(); void task235069_hideOnEscape(); void task203703_returnProperSeparator(); void task228844_ensurePreviousSorting(); void task239706_editableFilterCombo(); void task218353_relativePaths(); void task254490_selectFileMultipleTimes(); void task259105_filtersCornerCases(); void QTBUG4419_lineEditSelectAll(); void QTBUG6558_showDirsOnly(); void QTBUG4842_selectFilterWithHideNameFilterDetails(); void dontShowCompleterOnRoot(); void nameFilterParsing_data(); void nameFilterParsing(); private: void cleanupSettingsFile(); QTemporaryDir tempDir; }; tst_QFileDialog2::tst_QFileDialog2() : tempDir(QDir::tempPath() + "/tst_qfiledialog2.XXXXXX") { QCoreApplication::setAttribute(Qt::AA_DontUseNativeDialogs); } void tst_QFileDialog2::cleanupSettingsFile() { // clean up the sidebar between each test QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); settings.beginGroup(QLatin1String("FileDialog")); settings.remove(QString()); settings.endGroup(); settings.beginGroup(QLatin1String("Qt")); // Compatibility settings settings.remove(QLatin1String("filedialog")); settings.endGroup(); } void tst_QFileDialog2::initTestCase() { QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); QStandardPaths::setTestModeEnabled(true); cleanupSettingsFile(); } void tst_QFileDialog2::init() { QFileDialogPrivate::setLastVisitedDirectory(QUrl()); // populate the sidebar with some default settings QFileDialog fd; } void tst_QFileDialog2::cleanup() { cleanupSettingsFile(); } #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::listRoot() { QFileInfoGatherer fileInfoGatherer; fileInfoGatherer.start(); QTest::qWait(1500); qt_test_resetFetchedRoot(); QString dir(QDir::currentPath()); QFileDialog fd(0, QString(), dir); fd.show(); QCOMPARE(qt_test_isFetchedRoot(),false); fd.setDirectory(""); QTRY_COMPARE(qt_test_isFetchedRoot(),true); } #endif void tst_QFileDialog2::heapCorruption() { QList dialogs; for (int i=0; i < 10; i++) { QFileDialog *f = new QFileDialog(NULL); dialogs << f; } qDeleteAll(dialogs); } struct FriendlyQFileDialog : public QFileDialog { friend class tst_QFileDialog2; Q_DECLARE_PRIVATE(QFileDialog) }; #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::deleteDirAndFiles() { QString tempPath = tempDir.path() + "/QFileDialogTestDir4FullDelete"; QDir dir; QVERIFY(dir.mkpath(tempPath + "/foo")); QVERIFY(dir.mkpath(tempPath + "/foo/B")); QVERIFY(dir.mkpath(tempPath + "/foo/B")); QVERIFY(dir.mkpath(tempPath + "/foo/c")); QVERIFY(dir.mkpath(tempPath + "/bar")); QFile(tempPath + "/foo/a"); QTemporaryFile *t; t = new QTemporaryFile(tempPath + "/foo/aXXXXXX"); t->setAutoRemove(false); QVERIFY2(t->open(), qPrintable(t->errorString())); t->close(); delete t; t = new QTemporaryFile(tempPath + "/foo/B/yXXXXXX"); t->setAutoRemove(false); QVERIFY2(t->open(), qPrintable(t->errorString())); t->close(); delete t; FriendlyQFileDialog fd; fd.d_func()->removeDirectory(tempPath); QTRY_VERIFY(!QFileInfo::exists(tempPath)); } #endif void tst_QFileDialog2::filter() { QFileDialog fd; QAction *hiddenAction = fd.findChild("qt_show_hidden_action"); QVERIFY(hiddenAction); QVERIFY(hiddenAction->isEnabled()); QVERIFY(!hiddenAction->isChecked()); QDir::Filters filter = fd.filter(); filter |= QDir::Hidden; fd.setFilter(filter); QVERIFY(hiddenAction->isChecked()); } void tst_QFileDialog2::showNameFilterDetails() { QFileDialog fd; QComboBox *filters = fd.findChild("fileTypeCombo"); QVERIFY(filters); QVERIFY(!fd.testOption(QFileDialog::HideNameFilterDetails)); QStringList filterChoices; filterChoices << "Image files (*.png *.xpm *.jpg)" << "Text files (*.txt)" << "Any files (*.*)"; fd.setNameFilters(filterChoices); fd.setOption(QFileDialog::HideNameFilterDetails, true); QCOMPARE(filters->itemText(0), QString("Image files")); QCOMPARE(filters->itemText(1), QString("Text files")); QCOMPARE(filters->itemText(2), QString("Any files")); fd.setOption(QFileDialog::HideNameFilterDetails, false); QCOMPARE(filters->itemText(0), filterChoices.at(0)); QCOMPARE(filters->itemText(1), filterChoices.at(1)); QCOMPARE(filters->itemText(2), filterChoices.at(2)); } void tst_QFileDialog2::unc() { #if defined(Q_OS_WIN) // Only test UNC on Windows./ QString dir("\\\\" + QtNetworkSettings::winServerName() + "\\testsharewritable"); #else QString dir(QDir::currentPath()); #endif QVERIFY2(QFile::exists(dir), msgDoesNotExist(dir).constData()); QFileDialog fd(0, QString(), dir); QFileSystemModel *model = fd.findChild("qt_filesystem_model"); QVERIFY(model); QCOMPARE(model->index(fd.directory().absolutePath()), model->index(dir)); } void tst_QFileDialog2::emptyUncPath() { QFileDialog fd; fd.show(); QLineEdit *lineEdit = fd.findChild("fileNameEdit"); QVERIFY(lineEdit); // press 'keys' for the input for (int i = 0; i < 3 ; ++i) QTest::keyPress(lineEdit, Qt::Key_Backslash); QFileSystemModel *model = fd.findChild("qt_filesystem_model"); QVERIFY(model); } #if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_MENU) struct MenuCloser : public QObject { QWidget *w; explicit MenuCloser(QWidget *w) : w(w) {} void close() { QMenu *menu = w->findChild(); if (!menu) { qDebug("%s: cannot find file dialog child of type QMenu", Q_FUNC_INFO); w->close(); } QTest::keyClick(menu, Qt::Key_Escape); } }; static bool openContextMenu(QFileDialog &fd) { QListView *list = fd.findChild("listView"); if (!list) { qDebug("%s: didn't find file dialog child \"listView\"", Q_FUNC_INFO); return false; } QTimer timer; timer.setInterval(300); timer.setSingleShot(true); MenuCloser closer(&fd); QObject::connect(&timer, &QTimer::timeout, &closer, &MenuCloser::close); timer.start(); QContextMenuEvent cme(QContextMenuEvent::Mouse, QPoint(10, 10)); qApp->sendEvent(list->viewport(), &cme); // blocks until menu is closed again. return true; } void tst_QFileDialog2::task143519_deleteAndRenameActionBehavior() { // test based on task233037_selectingDirectory struct TestContext { explicit TestContext(const QString &path) : current(path) {} ~TestContext() { file.remove(); current.rmdir(test.dirName()); } QDir current; QDir test; QFile file; }; TestContext ctx(tempDir.path()); // setup testbed QVERIFY(ctx.current.mkdir("task143519_deleteAndRenameActionBehavior_test")); // ensure at least one item ctx.test = ctx.current; QVERIFY(ctx.test.cd("task143519_deleteAndRenameActionBehavior_test")); ctx.file.setFileName(ctx.test.absoluteFilePath("hello")); QVERIFY(ctx.file.open(QIODevice::WriteOnly)); QVERIFY(ctx.file.permissions() & QFile::WriteUser); ctx.file.close(); QFileDialog fd; fd.setViewMode(QFileDialog::List); fd.setDirectory(ctx.test.absolutePath()); fd.selectFile(ctx.file.fileName()); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); // grab some internals: QAction *rm = fd.findChild("qt_delete_action"); QVERIFY(rm); QAction *mv = fd.findChild("qt_rename_action"); QVERIFY(mv); // these are the real test cases: // defaults QVERIFY(openContextMenu(fd)); QCOMPARE(fd.selectedFiles(), QStringList(ctx.file.fileName())); QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); // change to non-defaults: fd.setOption(QFileDialog::ReadOnly, !fd.testOption(QFileDialog::ReadOnly)); QVERIFY(openContextMenu(fd)); QCOMPARE(fd.selectedFiles().size(), 1); QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); // and changed back to defaults: fd.setOption(QFileDialog::ReadOnly, !fd.testOption(QFileDialog::ReadOnly)); QVERIFY(openContextMenu(fd)); QCOMPARE(fd.selectedFiles().size(), 1); QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); } #endif // !QT_NO_CONTEXTMENU && !QT_NO_MENU void tst_QFileDialog2::task178897_minimumSize() { QFileDialog fd; QSize oldMs = fd.layout()->minimumSize(); QStringList history = fd.history(); history << QDir::toNativeSeparators("/verylongdirectory/" "aaaaaaaaaabbbbbbbbcccccccccccddddddddddddddeeeeeeeeeeeeffffffffffgggtggggggggghhhhhhhhiiiiiijjjk"); fd.setHistory(history); fd.show(); QSize ms = fd.layout()->minimumSize(); QVERIFY(ms.width() <= oldMs.width()); } void tst_QFileDialog2::task180459_lastDirectory_data() { QTest::addColumn("path"); QTest::addColumn("directory"); QTest::addColumn("isEnabled"); QTest::addColumn("result"); QTest::newRow("path+file") << QDir::homePath() + QDir::separator() + "Vugiu1co" << QDir::homePath() << true << QDir::homePath() + QDir::separator() + "Vugiu1co" ; QTest::newRow("no path") << "" << tempDir.path() << false << QString(); QTest::newRow("file") << "foo" << QDir::currentPath() << true << QDir::currentPath() + QDir::separator() + "foo" ; QTest::newRow("path") << QDir::homePath() << QDir::homePath() << false << QString(); QTest::newRow("path not existing") << "/usr/bin/foo/bar/foo/foo.txt" << tempDir.path() << true << tempDir.path() + QDir::separator() + "foo.txt"; } void tst_QFileDialog2::task180459_lastDirectory() { if (!QGuiApplication::platformName().compare(QLatin1String("cocoa"), Qt::CaseInsensitive)) QSKIP("Insignificant on OSX"); //QTBUG-39183 //first visit the temp directory and close the dialog QFileDialog *dlg = new QFileDialog(0, "", tempDir.path()); QFileSystemModel *model = dlg->findChild("qt_filesystem_model"); QVERIFY(model); QCOMPARE(model->index(tempDir.path()), model->index(dlg->directory().absolutePath())); delete dlg; QFETCH(QString, path); QFETCH(QString, directory); QFETCH(bool, isEnabled); QFETCH(QString, result); dlg = new QFileDialog(0, "", path); model = dlg->findChild("qt_filesystem_model"); QVERIFY(model); dlg->setAcceptMode(QFileDialog::AcceptSave); QCOMPARE(model->index(dlg->directory().absolutePath()), model->index(directory)); QDialogButtonBox *buttonBox = dlg->findChild("buttonBox"); QPushButton *button = buttonBox->button(QDialogButtonBox::Save); QVERIFY(button); QCOMPARE(button->isEnabled(), isEnabled); if (isEnabled) QCOMPARE(model->index(result), model->index(dlg->selectedFiles().first())); delete dlg; } class FilterDirModel : public QSortFilterProxyModel { public: FilterDirModel(QString root, QObject* parent=0):QSortFilterProxyModel(parent), m_root(root) {} ~FilterDirModel() {}; protected: bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override { QModelIndex parentIndex; parentIndex = source_parent; QString path; path = sourceModel()->index(source_row, 0, parentIndex).data(Qt::DisplayRole).toString(); do { path = parentIndex.data(Qt::DisplayRole).toString() + QLatin1Char('/') + path; parentIndex = parentIndex.parent(); } while(parentIndex.isValid()); QFileInfo info(path); if (info.isDir() && (QDir(path) != m_root)) return false; return true; } private: QDir m_root; }; class sortProxy : public QSortFilterProxyModel { public: sortProxy(QObject *parent) : QSortFilterProxyModel(parent) { } protected: virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override { QFileSystemModel * const model = qobject_cast(sourceModel()); const QFileInfo leftInfo(model->fileInfo(left)); const QFileInfo rightInfo(model->fileInfo(right)); if (leftInfo.isDir() == rightInfo.isDir()) return(leftInfo.filePath().compare(rightInfo.filePath(),Qt::CaseInsensitive) < 0); else if (leftInfo.isDir()) return(false); else return(true); } }; class CrashDialog : public QFileDialog { Q_OBJECT public: CrashDialog(QWidget *parent, const QString &caption, const QString &dir, const QString &filter) : QFileDialog(parent, caption, dir, filter) { sortProxy *proxyModel = new sortProxy(this); setProxyModel(proxyModel); } }; #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::task227304_proxyOnFileDialog() { QFileDialog fd(0, "", QDir::currentPath(), 0); fd.setProxyModel(new FilterDirModel(QDir::currentPath())); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QLineEdit *edit = fd.findChild("fileNameEdit"); QVERIFY(edit); QTest::keyClick(edit, Qt::Key_T); QTest::keyClick(edit, Qt::Key_S); QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); CrashDialog *dialog = new CrashDialog(0, QString("crash dialog test"), QDir::homePath(), QString("*") ); dialog->setFileMode(QFileDialog::ExistingFile); dialog->show(); QVERIFY(QTest::qWaitForWindowExposed(dialog)); QListView *list = dialog->findChild("listView"); QVERIFY(list); QTest::keyClick(list, Qt::Key_Down); QTest::keyClick(list, Qt::Key_Return); dialog->close(); fd.close(); QFileDialog fd2(0, "I should not crash with a proxy", tempDir.path(), {}); QSortFilterProxyModel *pm = new QSortFilterProxyModel; fd2.setProxyModel(pm); fd2.show(); QSidebar *sidebar = fd2.findChild("sidebar"); sidebar->setFocus(); sidebar->selectUrl(QUrl::fromLocalFile(QDir::homePath())); QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, {}, sidebar->visualRect(sidebar->model()->index(1, 0)).center()); QTest::qWait(250); //We shouldn't crash } #endif #ifndef Q_OS_MAC // The following test implies the folder created will appear first in // the list. On Mac files sorting depends on the locale and the order // displayed cannot be known for sure. void tst_QFileDialog2::task227930_correctNavigationKeyboardBehavior() { QDir current = QDir::currentPath(); current.mkdir("test"); current.cd("test"); QFile file("test/out.txt"); QFile file2("test/out2.txt"); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); QVERIFY(file2.open(QIODevice::WriteOnly | QIODevice::Text)); current.cdUp(); current.mkdir("test2"); QFileDialog fd; fd.setViewMode(QFileDialog::List); fd.setDirectory(current.absolutePath()); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); // Ensure LayoutRequest event is processed so that the list view // is sorted correctly to have the directory entires at the top. QCoreApplication::processEvents(); QListView *list = fd.findChild("listView"); QVERIFY(list); QTest::keyClick(list, Qt::Key_Down); QTest::keyClick(list, Qt::Key_Return); QTest::mouseClick(list->viewport(), Qt::LeftButton, {}); QTest::keyClick(list, Qt::Key_Down); QTest::keyClick(list, Qt::Key_Backspace); QTest::keyClick(list, Qt::Key_Down); QTest::keyClick(list, Qt::Key_Down); QTest::keyClick(list, Qt::Key_Return); QCOMPARE(fd.isVisible(), true); file.close(); file2.close(); file.remove(); file2.remove(); current.rmdir("test"); current.rmdir("test2"); } #endif #if defined(Q_OS_WIN) void tst_QFileDialog2::task226366_lowerCaseHardDriveWindows() { QFileDialog fd; fd.setDirectory(QDir::root().path()); fd.show(); QLineEdit *edit = fd.findChild("fileNameEdit"); QToolButton *buttonParent = fd.findChild("toParentButton"); QTest::qWait(200); QTest::mouseClick(buttonParent, Qt::LeftButton, {}, QPoint(0, 0)); QTest::qWait(2000); QTest::keyClick(edit, Qt::Key_C); QTest::qWait(200); QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); QTest::qWait(200); QCOMPARE(edit->text(), QString("C:/")); QTest::qWait(2000); //i clear my previous selection in the completer QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); edit->clear(); QTest::keyClick(edit, Qt::Key_C, Qt::ShiftModifier); QTest::qWait(200); QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); QCOMPARE(edit->text(), QString("C:/")); } #endif void tst_QFileDialog2::completionOnLevelAfterRoot() { QFileDialog fd; #if defined(Q_OS_WIN) fd.setDirectory("C:/"); QDir current = fd.directory(); QStringList entryList = current.entryList(QStringList(), QDir::Dirs); // Find a suitable test dir under c:-root: // - At least 6 characters long // - Ascii, letters only // - No another dir with same start QString testDir; foreach (const QString &entry, entryList) { if (entry.size() > 5 && QString(entry.toLatin1()).compare(entry) == 0) { bool invalid = false; for (int i = 0; i < 5; i++) { if (!entry.at(i).isLetter()) { invalid = true; break; } } if (!invalid) { foreach (const QString &check, entryList) { if (check.startsWith(entry.left(5), Qt::CaseInsensitive) && check != entry) { invalid = true; break; } } } if (!invalid) { testDir = entry; break; } } } if (testDir.isEmpty()) QSKIP("This test requires to have a unique directory of at least six ascii characters under c:/"); #else fd.setFilter(QDir::Hidden | QDir::AllDirs | QDir::Files | QDir::System); fd.setDirectory("/"); QDir etc("/etc"); if (!etc.exists()) QSKIP("This test requires to have an etc directory under /"); #endif fd.show(); QLineEdit *edit = fd.findChild("fileNameEdit"); QTest::qWait(2000); #if defined(Q_OS_WIN) //I love testlib :D for (int i = 0; i < 5; i++) QTest::keyClick(edit, testDir.at(i).toLower().toLatin1() - 'a' + Qt::Key_A); #else QTest::keyClick(edit, Qt::Key_E); QTest::keyClick(edit, Qt::Key_T); #endif QTest::qWait(200); QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); QTest::qWait(200); #if defined(Q_OS_WIN) QCOMPARE(edit->text(), testDir); #else QTRY_COMPARE(edit->text(), QString("etc")); #endif } void tst_QFileDialog2::task233037_selectingDirectory() { QDir current = QDir::currentPath(); current.mkdir("test"); QFileDialog fd; fd.setViewMode(QFileDialog::List); fd.setDirectory(current.absolutePath()); fd.setAcceptMode( QFileDialog::AcceptSave); fd.show(); QListView *list = fd.findChild("listView"); QTest::qWait(3000); // Wait for sort to settle (I need a signal). #ifdef QT_KEYPAD_NAVIGATION list->setEditFocus(true); #endif QTest::keyClick(list, Qt::Key_Down); QDialogButtonBox *buttonBox = fd.findChild("buttonBox"); QVERIFY(buttonBox); QPushButton *button = buttonBox->button(QDialogButtonBox::Save); QVERIFY(button); QVERIFY(button->isEnabled()); current.rmdir("test"); } void tst_QFileDialog2::task235069_hideOnEscape_data() { QTest::addColumn("childName"); QTest::addColumn("viewMode"); QTest::newRow("listView") << QStringLiteral("listView") << QFileDialog::List; QTest::newRow("fileNameEdit") << QStringLiteral("fileNameEdit") << QFileDialog::List; QTest::newRow("treeView") << QStringLiteral("treeView") << QFileDialog::Detail; } void tst_QFileDialog2::task235069_hideOnEscape() { QFETCH(QString, childName); QFETCH(QFileDialog::ViewMode, viewMode); QDir current = QDir::currentPath(); QFileDialog fd; QSignalSpy spyFinished(&fd, &QDialog::finished); QVERIFY(spyFinished.isValid()); QSignalSpy spyRejected(&fd, &QDialog::rejected); QVERIFY(spyRejected.isValid()); fd.setViewMode(viewMode); fd.setDirectory(current.absolutePath()); fd.setAcceptMode(QFileDialog::AcceptSave); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QWidget *child = fd.findChild(childName); QVERIFY(child); child->setFocus(); QTest::keyClick(child, Qt::Key_Escape); QCOMPARE(fd.isVisible(), false); QCOMPARE(spyFinished.count(), 1); // QTBUG-7690 QCOMPARE(spyRejected.count(), 1); // reject(), don't hide() } #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::task236402_dontWatchDeletedDir() { //THIS TEST SHOULD NOT DISPLAY WARNINGS QDir current = QDir::currentPath(); //make sure it is the first on the list current.mkdir("aaaaaaaaaa"); FriendlyQFileDialog fd; fd.setViewMode(QFileDialog::List); fd.setDirectory(current.absolutePath()); fd.setAcceptMode( QFileDialog::AcceptSave); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QListView *list = fd.findChild("listView"); QVERIFY(list); list->setFocus(); QTest::keyClick(list, Qt::Key_Return); QTest::keyClick(list, Qt::Key_Backspace); QTest::keyClick(list, Qt::Key_Down); fd.d_func()->removeDirectory(current.absolutePath() + "/aaaaaaaaaa/"); QTest::qWait(1000); } #endif void tst_QFileDialog2::task203703_returnProperSeparator() { QDir current = QDir::currentPath(); current.mkdir("aaaaaaaaaaaaaaaaaa"); QFileDialog fd; fd.setDirectory(current.absolutePath()); fd.setViewMode(QFileDialog::List); fd.setFileMode(QFileDialog::Directory); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QListView *list = fd.findChild("listView"); QVERIFY(list); list->setFocus(); QTest::keyClick(list, Qt::Key_Return); QDialogButtonBox *buttonBox = fd.findChild("buttonBox"); QVERIFY(buttonBox); QPushButton *button = buttonBox->button(QDialogButtonBox::Cancel); QVERIFY(button); QTest::keyClick(button, Qt::Key_Return); QString result = fd.selectedFiles().first(); QVERIFY(result.at(result.count() - 1) != '/'); QVERIFY(!result.contains('\\')); current.rmdir("aaaaaaaaaaaaaaaaaa"); } void tst_QFileDialog2::task228844_ensurePreviousSorting() { QDir current = QDir::currentPath(); current.mkdir("aaaaaaaaaaaaaaaaaa"); current.cd("aaaaaaaaaaaaaaaaaa"); current.mkdir("a"); current.mkdir("b"); current.mkdir("c"); current.mkdir("d"); current.mkdir("e"); current.mkdir("f"); current.mkdir("g"); QTemporaryFile *tempFile = new QTemporaryFile(current.absolutePath() + "/rXXXXXX"); QVERIFY2(tempFile->open(), qPrintable(tempFile->errorString())); current.cdUp(); QFileDialog fd; fd.setDirectory(current.absolutePath()); fd.setViewMode(QFileDialog::Detail); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QTreeView *tree = fd.findChild("treeView"); QVERIFY(tree); tree->header()->setSortIndicator(3,Qt::DescendingOrder); QDialogButtonBox *buttonBox = fd.findChild("buttonBox"); QVERIFY(buttonBox); QPushButton *button = buttonBox->button(QDialogButtonBox::Open); QVERIFY(button); QTest::mouseClick(button, Qt::LeftButton); QFileDialog fd2; fd2.setFileMode(QFileDialog::Directory); fd2.restoreState(fd.saveState()); current.cd("aaaaaaaaaaaaaaaaaa"); fd2.setDirectory(current.absolutePath()); fd2.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd2)); QTreeView *tree2 = fd2.findChild("treeView"); QVERIFY(tree2); tree2->setFocus(); QCOMPARE(tree2->rootIndex().data(QFileSystemModel::FilePathRole).toString(),current.absolutePath()); QDialogButtonBox *buttonBox2 = fd2.findChild("buttonBox"); QVERIFY(buttonBox2); QPushButton *button2 = buttonBox2->button(QDialogButtonBox::Open); QVERIFY(button2); fd2.selectFile("g"); QTest::mouseClick(button2, Qt::LeftButton); QCOMPARE(fd2.selectedFiles().first(), current.absolutePath() + QLatin1String("/g")); QFileDialog fd3(0, "This is a third file dialog", tempFile->fileName()); fd3.restoreState(fd.saveState()); fd3.setFileMode(QFileDialog::Directory); fd3.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd3)); QTreeView *tree3 = fd3.findChild("treeView"); QVERIFY(tree3); tree3->setFocus(); QCOMPARE(tree3->rootIndex().data(QFileSystemModel::FilePathRole).toString(), current.absolutePath()); QDialogButtonBox *buttonBox3 = fd3.findChild("buttonBox"); QVERIFY(buttonBox3); QPushButton *button3 = buttonBox3->button(QDialogButtonBox::Open); QVERIFY(button3); QTest::mouseClick(button3, Qt::LeftButton); QCOMPARE(fd3.selectedFiles().first(), tempFile->fileName()); current.cd("aaaaaaaaaaaaaaaaaa"); current.rmdir("a"); current.rmdir("b"); current.rmdir("c"); current.rmdir("d"); current.rmdir("e"); current.rmdir("f"); current.rmdir("g"); tempFile->close(); delete tempFile; current.cdUp(); current.rmdir("aaaaaaaaaaaaaaaaaa"); } void tst_QFileDialog2::task239706_editableFilterCombo() { QFileDialog d; d.setNameFilter("*.cpp *.h"); d.show(); QVERIFY(QTest::qWaitForWindowExposed(&d)); QList comboList = d.findChildren(); QComboBox *filterCombo = nullptr; foreach (QComboBox *combo, comboList) { if (combo->objectName() == QString("fileTypeCombo")) { filterCombo = combo; break; } } QVERIFY(filterCombo); filterCombo->setEditable(true); QTest::mouseClick(filterCombo, Qt::LeftButton); QTest::keyPress(filterCombo, Qt::Key_X); QTest::keyPress(filterCombo, Qt::Key_Enter); // should not trigger assertion failure } void tst_QFileDialog2::task218353_relativePaths() { QDir appDir = QDir::current(); QVERIFY(appDir.cdUp() != false); QFileDialog d(0, "TestDialog", ".."); QCOMPARE(d.directory().absolutePath(), appDir.absolutePath()); d.setDirectory(appDir.absolutePath() + QLatin1String("/non-existing-directory/../another-non-existing-dir/../")); QCOMPARE(d.directory().absolutePath(), appDir.absolutePath()); QDir::current().mkdir("test"); appDir = QDir::current(); d.setDirectory(appDir.absolutePath() + QLatin1String("/test/../test/../")); QCOMPARE(d.directory().absolutePath(), appDir.absolutePath()); appDir.rmdir("test"); } #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::task251321_sideBarHiddenEntries() { QFileDialog fd; QDir current = QDir::currentPath(); current.mkdir(".hidden"); QDir hiddenDir = QDir(".hidden"); hiddenDir.mkdir("subdir"); QDir hiddenSubDir = QDir(".hidden/subdir"); hiddenSubDir.mkdir("happy"); hiddenSubDir.mkdir("happy2"); QList urls; urls << QUrl::fromLocalFile(hiddenSubDir.absolutePath()); fd.setSidebarUrls(urls); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QSidebar *sidebar = fd.findChild("sidebar"); QVERIFY(sidebar); sidebar->setFocus(); sidebar->selectUrl(QUrl::fromLocalFile(hiddenSubDir.absolutePath())); QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, {}, sidebar->visualRect(sidebar->model()->index(0, 0)).center()); // give the background processes more time on windows mobile QTest::qWait(250); QFileSystemModel *model = fd.findChild("qt_filesystem_model"); QCOMPARE(model->rowCount(model->index(hiddenSubDir.absolutePath())), 2); hiddenSubDir.rmdir("happy2"); hiddenSubDir.rmdir("happy"); hiddenDir.rmdir("subdir"); current.rmdir(".hidden"); } #endif #if defined QT_BUILD_INTERNAL class MyQSideBar : public QSidebar { public : MyQSideBar(QWidget *parent = nullptr) : QSidebar(parent) {} void removeSelection() { QList idxs = selectionModel()->selectedIndexes(); QList indexes; for (int i = 0; i < idxs.count(); i++) indexes.append(idxs.at(i)); for (int i = 0; i < indexes.count(); ++i) if (!indexes.at(i).data(Qt::UserRole + 1).toUrl().path().isEmpty()) model()->removeRow(indexes.at(i).row()); } }; #endif #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::task251341_sideBarRemoveEntries() { QFileDialog fd; QDir current = QDir::currentPath(); current.mkdir("testDir"); QDir testSubDir = QDir("testDir"); QList urls; urls << QUrl::fromLocalFile(testSubDir.absolutePath()); urls << QUrl::fromLocalFile("NotFound"); fd.setSidebarUrls(urls); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QSidebar *sidebar = fd.findChild("sidebar"); QVERIFY(sidebar); sidebar->setFocus(); //We enter in the first bookmark sidebar->selectUrl(QUrl::fromLocalFile(testSubDir.absolutePath())); QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, {}, sidebar->visualRect(sidebar->model()->index(0, 0)).center()); QFileSystemModel *model = fd.findChild("qt_filesystem_model"); QVERIFY(model); //There is no file QCOMPARE(model->rowCount(model->index(testSubDir.absolutePath())), 0); //Icon is not enabled QUrlModel::EnabledRole QVariant value = sidebar->model()->index(0, 0).data(Qt::UserRole + 2); QCOMPARE(qvariant_cast(value), true); sidebar->setFocus(); //We enter in the second bookmark which is invalid sidebar->selectUrl(QUrl::fromLocalFile("NotFound")); QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, {}, sidebar->visualRect(sidebar->model()->index(1, 0)).center()); //We fallback to root because the entry in the bookmark is invalid QCOMPARE(model->rowCount(model->index("NotFound")), model->rowCount(model->index(model->rootPath()))); //Icon is not enabled QUrlModel::EnabledRole value = sidebar->model()->index(1, 0).data(Qt::UserRole + 2); QCOMPARE(qvariant_cast(value), false); MyQSideBar mySideBar; mySideBar.setModelAndUrls(model, urls); mySideBar.show(); mySideBar.selectUrl(QUrl::fromLocalFile(testSubDir.absolutePath())); QTest::qWait(1000); mySideBar.removeSelection(); //We remove the first entry QList expected; expected << QUrl::fromLocalFile("NotFound"); QCOMPARE(mySideBar.urls(), expected); mySideBar.selectUrl(QUrl::fromLocalFile("NotFound")); mySideBar.removeSelection(); //We remove the second entry expected.clear(); QCOMPARE(mySideBar.urls(), expected); current.rmdir("testDir"); } #endif void tst_QFileDialog2::task254490_selectFileMultipleTimes() { QString tempPath = tempDir.path(); QTemporaryFile *t; t = new QTemporaryFile; QVERIFY2(t->open(), qPrintable(t->errorString())); t->open(); QFileDialog fd(0, "TestFileDialog"); fd.setDirectory(tempPath); fd.setViewMode(QFileDialog::List); fd.setAcceptMode(QFileDialog::AcceptSave); fd.setFileMode(QFileDialog::AnyFile); //This should select the file in the QFileDialog fd.selectFile(t->fileName()); //This should clear the selection and write it into the filename line edit fd.selectFile("new_file.txt"); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); QLineEdit *lineEdit = fd.findChild("fileNameEdit"); QVERIFY(lineEdit); QCOMPARE(lineEdit->text(),QLatin1String("new_file.txt")); QListView *list = fd.findChild("listView"); QVERIFY(list); QCOMPARE(list->selectionModel()->selectedRows(0).count(), 0); t->deleteLater(); } #ifdef QT_BUILD_INTERNAL void tst_QFileDialog2::task257579_sideBarWithNonCleanUrls() { QDir dir(tempDir.path()); QLatin1String dirname("autotest_task257579"); dir.rmdir(dirname); //makes sure it doesn't exist any more QVERIFY(dir.mkdir(dirname)); QString url = dir.absolutePath() + QLatin1Char('/') + dirname + QLatin1String("/.."); QFileDialog fd; fd.setSidebarUrls(QList() << QUrl::fromLocalFile(url)); QSidebar *sidebar = fd.findChild("sidebar"); QCOMPARE(sidebar->urls().count(), 1); QVERIFY(sidebar->urls().first().toLocalFile() != url); QCOMPARE(sidebar->urls().first().toLocalFile(), QDir::cleanPath(url)); #ifdef Q_OS_WIN QCOMPARE(sidebar->model()->index(0,0).data().toString().toLower(), dir.dirName().toLower()); #else QCOMPARE(sidebar->model()->index(0,0).data().toString(), dir.dirName()); #endif //all tests are finished, we can remove the temporary dir QVERIFY(dir.rmdir(dirname)); } #endif void tst_QFileDialog2::task259105_filtersCornerCases() { QFileDialog fd(0, "TestFileDialog"); fd.setNameFilter(QLatin1String("All Files! (*);;Text Files (*.txt)")); fd.setOption(QFileDialog::HideNameFilterDetails, true); fd.show(); QVERIFY(QTest::qWaitForWindowExposed(&fd)); //Extensions are hidden QComboBox *filters = fd.findChild("fileTypeCombo"); QVERIFY(filters); QCOMPARE(filters->currentText(), QLatin1String("All Files!")); filters->setCurrentIndex(1); QCOMPARE(filters->currentText(), QLatin1String("Text Files")); //We should have the full names fd.setOption(QFileDialog::HideNameFilterDetails, false); filters->setCurrentIndex(0); QCOMPARE(filters->currentText(), QLatin1String("All Files! (*)")); filters->setCurrentIndex(1); QCOMPARE(filters->currentText(), QLatin1String("Text Files (*.txt)")); //Corner case undocumented of the task fd.setNameFilter(QLatin1String("\352 (I like cheese) All Files! (*);;Text Files (*.txt)")); QCOMPARE(filters->currentText(), QLatin1String("\352 (I like cheese) All Files! (*)")); filters->setCurrentIndex(1); QCOMPARE(filters->currentText(), QLatin1String("Text Files (*.txt)")); fd.setOption(QFileDialog::HideNameFilterDetails, true); filters->setCurrentIndex(0); QCOMPARE(filters->currentText(), QLatin1String("\352 (I like cheese) All Files!")); filters->setCurrentIndex(1); QCOMPARE(filters->currentText(), QLatin1String("Text Files")); fd.setOption(QFileDialog::HideNameFilterDetails, true); filters->setCurrentIndex(0); QCOMPARE(filters->currentText(), QLatin1String("\352 (I like cheese) All Files!")); filters->setCurrentIndex(1); QCOMPARE(filters->currentText(), QLatin1String("Text Files")); } void tst_QFileDialog2::QTBUG4419_lineEditSelectAll() { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("Window activation is not supported"); QString tempPath = tempDir.path(); QTemporaryFile temporaryFile(tempPath + "/tst_qfiledialog2_lineEditSelectAll.XXXXXX"); QVERIFY2(temporaryFile.open(), qPrintable(temporaryFile.errorString())); QFileDialog fd(0, "TestFileDialog", temporaryFile.fileName()); fd.setDirectory(tempPath); fd.setViewMode(QFileDialog::List); fd.setAcceptMode(QFileDialog::AcceptSave); fd.setFileMode(QFileDialog::AnyFile); fd.show(); fd.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&fd)); QCOMPARE(fd.isVisible(), true); QCOMPARE(QApplication::activeWindow(), static_cast(&fd)); QLineEdit *lineEdit = fd.findChild("fileNameEdit"); QVERIFY(lineEdit); QTRY_COMPARE(tempPath + QChar('/') + lineEdit->text(), temporaryFile.fileName()); QCOMPARE(tempPath + QChar('/') + lineEdit->selectedText(), temporaryFile.fileName()); } void tst_QFileDialog2::QTBUG6558_showDirsOnly() { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("Window activation is not supported"); const QString tempPath = tempDir.path(); QDir dirTemp(tempPath); const QString tempName = QLatin1String("showDirsOnly.") + QString::number(QRandomGenerator::global()->generate()); dirTemp.mkdir(tempName); dirTemp.cd(tempName); QTRY_VERIFY(dirTemp.exists()); const QString dirPath = dirTemp.absolutePath(); QDir dir(dirPath); //We create two dirs dir.mkdir("a"); dir.mkdir("b"); //Create a file QFile tempFile(dirPath + "/plop.txt"); tempFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&tempFile); out << "The magic number is: " << 49 << "\n"; tempFile.close(); QFileDialog fd(0, "TestFileDialog"); fd.setDirectory(dir.absolutePath()); fd.setViewMode(QFileDialog::List); fd.setAcceptMode(QFileDialog::AcceptSave); fd.setOption(QFileDialog::ShowDirsOnly, true); fd.show(); QApplication::setActiveWindow(&fd); QVERIFY(QTest::qWaitForWindowActive(&fd)); QCOMPARE(fd.isVisible(), true); QCOMPARE(QApplication::activeWindow(), static_cast(&fd)); QFileSystemModel *model = fd.findChild("qt_filesystem_model"); QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 2); fd.setOption(QFileDialog::ShowDirsOnly, false); QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 3); fd.setOption(QFileDialog::ShowDirsOnly, true); QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 2); QTRY_COMPARE(bool(fd.options() & QFileDialog::ShowDirsOnly), true); fd.setDirectory(QDir::homePath()); //We remove the dirs dir.rmdir("a"); dir.rmdir("b"); //we delete the file tempFile.remove(); dirTemp.cdUp(); dirTemp.rmdir(tempName); } void tst_QFileDialog2::QTBUG4842_selectFilterWithHideNameFilterDetails() { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("Window activation is not supported"); QStringList filtersStr; filtersStr << "Images (*.png *.xpm *.jpg)" << "Text files (*.txt)" << "XML files (*.xml)"; QString chosenFilterString("Text files (*.txt)"); QFileDialog fd(0, "TestFileDialog"); fd.setAcceptMode(QFileDialog::AcceptSave); fd.setOption(QFileDialog::HideNameFilterDetails, true); fd.setNameFilters(filtersStr); fd.selectNameFilter(chosenFilterString); fd.show(); QApplication::setActiveWindow(&fd); QVERIFY(QTest::qWaitForWindowActive(&fd)); QCOMPARE(fd.isVisible(), true); QCOMPARE(QApplication::activeWindow(), static_cast(&fd)); QComboBox *filters = fd.findChild("fileTypeCombo"); //We compare the current combobox text with the stripped version QCOMPARE(filters->currentText(), QString("Text files")); QFileDialog fd2(0, "TestFileDialog"); fd2.setAcceptMode(QFileDialog::AcceptSave); fd2.setOption(QFileDialog::HideNameFilterDetails, false); fd2.setNameFilters(filtersStr); fd2.selectNameFilter(chosenFilterString); fd2.show(); QApplication::setActiveWindow(&fd2); QVERIFY(QTest::qWaitForWindowActive(&fd2)); QCOMPARE(fd2.isVisible(), true); QCOMPARE(QApplication::activeWindow(), static_cast(&fd2)); QComboBox *filters2 = fd2.findChild("fileTypeCombo"); //We compare the current combobox text with the non stripped version QCOMPARE(filters2->currentText(), chosenFilterString); } void tst_QFileDialog2::dontShowCompleterOnRoot() { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("Window activation is not supported"); QFileDialog fd(0, "TestFileDialog"); fd.setAcceptMode(QFileDialog::AcceptSave); fd.show(); QApplication::setActiveWindow(&fd); QVERIFY(QTest::qWaitForWindowActive(&fd)); QCOMPARE(fd.isVisible(), true); QCOMPARE(QApplication::activeWindow(), static_cast(&fd)); fd.setDirectory(""); QLineEdit *lineEdit = fd.findChild("fileNameEdit"); QTRY_VERIFY(lineEdit->text().isEmpty()); //The gatherer thread will then return the result QApplication::processEvents(); QTRY_VERIFY(lineEdit->completer()->popup()->isHidden()); } void tst_QFileDialog2::nameFilterParsing_data() { QTest::addColumn("filterString"); QTest::addColumn("filters"); // QTBUG-47923: Do not trip over "*,v". QTest::newRow("text") << "plain text document (*.txt *.asc *,v *.doc)" << (QStringList() << "*.txt" << "*.asc" << "*,v" << "*.doc"); QTest::newRow("html") << "HTML document (*.html *.htm)" << (QStringList() << "*.html" << "*.htm"); } void tst_QFileDialog2::nameFilterParsing() { QFETCH(QString, filterString); QFETCH(QStringList, filters); QCOMPARE(QPlatformFileDialogHelper::cleanFilterList(filterString), filters); } QTEST_MAIN(tst_QFileDialog2) #include "tst_qfiledialog2.moc"