1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | |
32 | #include <qcoreapplication.h> |
33 | #include <qdebug.h> |
34 | #include <qfiledialog.h> |
35 | #include <qabstractitemdelegate.h> |
36 | #include <qdirmodel.h> |
37 | #include <qitemdelegate.h> |
38 | #include <qlistview.h> |
39 | #include <qcombobox.h> |
40 | #include <qpushbutton.h> |
41 | #include <qtoolbutton.h> |
42 | #include <qtreeview.h> |
43 | #include <qheaderview.h> |
44 | #include <qcompleter.h> |
45 | #include <qaction.h> |
46 | #include <qdialogbuttonbox.h> |
47 | #include <qsortfilterproxymodel.h> |
48 | #include <qlineedit.h> |
49 | #include <qlayout.h> |
50 | #include <qmenu.h> |
51 | #include <qrandom.h> |
52 | #include "../../../../../src/widgets/dialogs/qsidebar_p.h" |
53 | #include "../../../../../src/widgets/dialogs/qfilesystemmodel_p.h" |
54 | #include "../../../../../src/widgets/dialogs/qfiledialog_p.h" |
55 | |
56 | #include <private/qguiapplication_p.h> |
57 | |
58 | #include <qpa/qplatformdialoghelper.h> |
59 | #include <qpa/qplatformintegration.h> |
60 | |
61 | #if defined(Q_OS_WIN) |
62 | #include "../../../network-settings.h" |
63 | #endif |
64 | |
65 | #if defined QT_BUILD_INTERNAL |
66 | QT_BEGIN_NAMESPACE |
67 | Q_GUI_EXPORT bool qt_test_isFetchedRoot(); |
68 | Q_GUI_EXPORT void qt_test_resetFetchedRoot(); |
69 | QT_END_NAMESPACE |
70 | #endif |
71 | |
72 | static QByteArray msgDoesNotExist(const QString &name) |
73 | { |
74 | return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name) |
75 | + QLatin1String("\" does not exist." )).toLocal8Bit(); |
76 | } |
77 | |
78 | class tst_QFileDialog2 : public QObject |
79 | { |
80 | Q_OBJECT |
81 | |
82 | public: |
83 | tst_QFileDialog2(); |
84 | |
85 | private slots: |
86 | void initTestCase(); |
87 | void init(); |
88 | void cleanup(); |
89 | |
90 | #ifdef QT_BUILD_INTERNAL |
91 | void deleteDirAndFiles(); |
92 | void listRoot(); |
93 | void task227304_proxyOnFileDialog(); |
94 | void task236402_dontWatchDeletedDir(); |
95 | void task251321_sideBarHiddenEntries(); |
96 | void task251341_sideBarRemoveEntries(); |
97 | void task257579_sideBarWithNonCleanUrls(); |
98 | #endif |
99 | void heapCorruption(); |
100 | void filter(); |
101 | void showNameFilterDetails(); |
102 | void unc(); |
103 | void emptyUncPath(); |
104 | |
105 | #if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_MENU) |
106 | void task143519_deleteAndRenameActionBehavior(); |
107 | #endif |
108 | void task178897_minimumSize(); |
109 | void task180459_lastDirectory_data(); |
110 | void task180459_lastDirectory(); |
111 | #ifndef Q_OS_MAC |
112 | void task227930_correctNavigationKeyboardBehavior(); |
113 | #endif |
114 | #if defined(Q_OS_WIN) |
115 | void task226366_lowerCaseHardDriveWindows(); |
116 | #endif |
117 | void completionOnLevelAfterRoot(); |
118 | void task233037_selectingDirectory(); |
119 | void task235069_hideOnEscape_data(); |
120 | void task235069_hideOnEscape(); |
121 | void task203703_returnProperSeparator(); |
122 | void task228844_ensurePreviousSorting(); |
123 | void task239706_editableFilterCombo(); |
124 | void task218353_relativePaths(); |
125 | void task254490_selectFileMultipleTimes(); |
126 | void task259105_filtersCornerCases(); |
127 | |
128 | void QTBUG4419_lineEditSelectAll(); |
129 | void QTBUG6558_showDirsOnly(); |
130 | void QTBUG4842_selectFilterWithHideNameFilterDetails(); |
131 | void dontShowCompleterOnRoot(); |
132 | void nameFilterParsing_data(); |
133 | void nameFilterParsing(); |
134 | |
135 | private: |
136 | void cleanupSettingsFile(); |
137 | |
138 | QTemporaryDir tempDir; |
139 | }; |
140 | |
141 | tst_QFileDialog2::tst_QFileDialog2() |
142 | : tempDir(QDir::tempPath() + "/tst_qfiledialog2.XXXXXX" ) |
143 | { |
144 | QCoreApplication::setAttribute(attribute: Qt::AA_DontUseNativeDialogs); |
145 | } |
146 | |
147 | void tst_QFileDialog2::cleanupSettingsFile() |
148 | { |
149 | // clean up the sidebar between each test |
150 | QSettings settings(QSettings::UserScope, QLatin1String("QtProject" )); |
151 | settings.beginGroup(prefix: QLatin1String("FileDialog" )); |
152 | settings.remove(key: QString()); |
153 | settings.endGroup(); |
154 | settings.beginGroup(prefix: QLatin1String("Qt" )); // Compatibility settings |
155 | settings.remove(key: QLatin1String("filedialog" )); |
156 | settings.endGroup(); |
157 | } |
158 | |
159 | void tst_QFileDialog2::initTestCase() |
160 | { |
161 | QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); |
162 | QStandardPaths::setTestModeEnabled(true); |
163 | cleanupSettingsFile(); |
164 | } |
165 | |
166 | void tst_QFileDialog2::init() |
167 | { |
168 | QFileDialogPrivate::setLastVisitedDirectory(QUrl()); |
169 | // populate the sidebar with some default settings |
170 | QFileDialog fd; |
171 | } |
172 | |
173 | void tst_QFileDialog2::cleanup() |
174 | { |
175 | cleanupSettingsFile(); |
176 | } |
177 | |
178 | #ifdef QT_BUILD_INTERNAL |
179 | void tst_QFileDialog2::listRoot() |
180 | { |
181 | QFileInfoGatherer fileInfoGatherer; |
182 | fileInfoGatherer.start(); |
183 | QTest::qWait(ms: 1500); |
184 | qt_test_resetFetchedRoot(); |
185 | QString dir(QDir::currentPath()); |
186 | QFileDialog fd(0, QString(), dir); |
187 | fd.show(); |
188 | QCOMPARE(qt_test_isFetchedRoot(),false); |
189 | fd.setDirectory("" ); |
190 | QTRY_COMPARE(qt_test_isFetchedRoot(),true); |
191 | } |
192 | #endif |
193 | |
194 | void tst_QFileDialog2::heapCorruption() |
195 | { |
196 | QVector<QFileDialog*> dialogs; |
197 | for (int i=0; i < 10; i++) { |
198 | QFileDialog *f = new QFileDialog(NULL); |
199 | dialogs << f; |
200 | } |
201 | qDeleteAll(c: dialogs); |
202 | } |
203 | |
204 | struct FriendlyQFileDialog : public QFileDialog |
205 | { |
206 | friend class tst_QFileDialog2; |
207 | Q_DECLARE_PRIVATE(QFileDialog) |
208 | }; |
209 | |
210 | |
211 | #ifdef QT_BUILD_INTERNAL |
212 | void tst_QFileDialog2::deleteDirAndFiles() |
213 | { |
214 | QString tempPath = tempDir.path() + "/QFileDialogTestDir4FullDelete" ; |
215 | QDir dir; |
216 | QVERIFY(dir.mkpath(tempPath + "/foo" )); |
217 | QVERIFY(dir.mkpath(tempPath + "/foo/B" )); |
218 | QVERIFY(dir.mkpath(tempPath + "/foo/B" )); |
219 | QVERIFY(dir.mkpath(tempPath + "/foo/c" )); |
220 | QVERIFY(dir.mkpath(tempPath + "/bar" )); |
221 | QFile(tempPath + "/foo/a" ); |
222 | QTemporaryFile *t; |
223 | t = new QTemporaryFile(tempPath + "/foo/aXXXXXX" ); |
224 | t->setAutoRemove(false); |
225 | QVERIFY2(t->open(), qPrintable(t->errorString())); |
226 | t->close(); |
227 | delete t; |
228 | |
229 | t = new QTemporaryFile(tempPath + "/foo/B/yXXXXXX" ); |
230 | t->setAutoRemove(false); |
231 | QVERIFY2(t->open(), qPrintable(t->errorString())); |
232 | t->close(); |
233 | delete t; |
234 | FriendlyQFileDialog fd; |
235 | fd.d_func()->removeDirectory(path: tempPath); |
236 | QTRY_VERIFY(!QFileInfo::exists(tempPath)); |
237 | } |
238 | #endif |
239 | |
240 | void tst_QFileDialog2::filter() |
241 | { |
242 | QFileDialog fd; |
243 | QAction *hiddenAction = fd.findChild<QAction*>(aName: "qt_show_hidden_action" ); |
244 | QVERIFY(hiddenAction); |
245 | QVERIFY(hiddenAction->isEnabled()); |
246 | QVERIFY(!hiddenAction->isChecked()); |
247 | QDir::Filters filter = fd.filter(); |
248 | filter |= QDir::Hidden; |
249 | fd.setFilter(filter); |
250 | QVERIFY(hiddenAction->isChecked()); |
251 | } |
252 | |
253 | void tst_QFileDialog2::showNameFilterDetails() |
254 | { |
255 | QFileDialog fd; |
256 | QComboBox *filters = fd.findChild<QComboBox*>(aName: "fileTypeCombo" ); |
257 | QVERIFY(filters); |
258 | QVERIFY(!fd.testOption(QFileDialog::HideNameFilterDetails)); |
259 | |
260 | |
261 | QStringList filterChoices; |
262 | filterChoices << "Image files (*.png *.xpm *.jpg)" |
263 | << "Text files (*.txt)" |
264 | << "Any files (*.*)" ; |
265 | fd.setNameFilters(filterChoices); |
266 | |
267 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: true); |
268 | QCOMPARE(filters->itemText(0), QString("Image files" )); |
269 | QCOMPARE(filters->itemText(1), QString("Text files" )); |
270 | QCOMPARE(filters->itemText(2), QString("Any files" )); |
271 | |
272 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: false); |
273 | QCOMPARE(filters->itemText(0), filterChoices.at(0)); |
274 | QCOMPARE(filters->itemText(1), filterChoices.at(1)); |
275 | QCOMPARE(filters->itemText(2), filterChoices.at(2)); |
276 | } |
277 | |
278 | void tst_QFileDialog2::unc() |
279 | { |
280 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
281 | // Only test UNC on Windows./ |
282 | QString dir("\\\\" + QtNetworkSettings::winServerName() + "\\testsharewritable" ); |
283 | #else |
284 | QString dir(QDir::currentPath()); |
285 | #endif |
286 | QVERIFY2(QFile::exists(dir), msgDoesNotExist(dir).constData()); |
287 | QFileDialog fd(0, QString(), dir); |
288 | QFileSystemModel *model = fd.findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
289 | QVERIFY(model); |
290 | QCOMPARE(model->index(fd.directory().absolutePath()), model->index(dir)); |
291 | } |
292 | |
293 | void tst_QFileDialog2::emptyUncPath() |
294 | { |
295 | QFileDialog fd; |
296 | fd.show(); |
297 | QLineEdit *lineEdit = fd.findChild<QLineEdit*>(aName: "fileNameEdit" ); |
298 | QVERIFY(lineEdit); |
299 | // press 'keys' for the input |
300 | for (int i = 0; i < 3 ; ++i) |
301 | QTest::keyPress(widget: lineEdit, key: Qt::Key_Backslash); |
302 | QFileSystemModel *model = fd.findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
303 | QVERIFY(model); |
304 | } |
305 | |
306 | #if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_MENU) |
307 | struct : public QObject { |
308 | QWidget *; |
309 | explicit (QWidget *w) : w(w) {} |
310 | |
311 | void () |
312 | { |
313 | QMenu * = w->findChild<QMenu*>(); |
314 | if (!menu) { |
315 | qDebug(msg: "%s: cannot find file dialog child of type QMenu" , Q_FUNC_INFO); |
316 | w->close(); |
317 | } |
318 | QTest::keyClick(widget: menu, key: Qt::Key_Escape); |
319 | } |
320 | }; |
321 | static bool (QFileDialog &fd) |
322 | { |
323 | QListView *list = fd.findChild<QListView*>(aName: "listView" ); |
324 | if (!list) { |
325 | qDebug(msg: "%s: didn't find file dialog child \"listView\"" , Q_FUNC_INFO); |
326 | return false; |
327 | } |
328 | QTimer timer; |
329 | timer.setInterval(300); |
330 | timer.setSingleShot(true); |
331 | MenuCloser closer(&fd); |
332 | QObject::connect(sender: &timer, signal: &QTimer::timeout, receiver: &closer, slot: &MenuCloser::close); |
333 | timer.start(); |
334 | QContextMenuEvent cme(QContextMenuEvent::Mouse, QPoint(10, 10)); |
335 | qApp->sendEvent(receiver: list->viewport(), event: &cme); // blocks until menu is closed again. |
336 | return true; |
337 | } |
338 | |
339 | void tst_QFileDialog2::task143519_deleteAndRenameActionBehavior() |
340 | { |
341 | // test based on task233037_selectingDirectory |
342 | |
343 | struct TestContext { |
344 | explicit TestContext(const QString &path) : current(path) {} |
345 | ~TestContext() { |
346 | file.remove(); |
347 | current.rmdir(dirName: test.dirName()); |
348 | } |
349 | QDir current; |
350 | QDir test; |
351 | QFile file; |
352 | }; |
353 | |
354 | TestContext ctx(tempDir.path()); |
355 | |
356 | // setup testbed |
357 | QVERIFY(ctx.current.mkdir("task143519_deleteAndRenameActionBehavior_test" )); // ensure at least one item |
358 | ctx.test = ctx.current; |
359 | QVERIFY(ctx.test.cd("task143519_deleteAndRenameActionBehavior_test" )); |
360 | ctx.file.setFileName(ctx.test.absoluteFilePath(fileName: "hello" )); |
361 | QVERIFY(ctx.file.open(QIODevice::WriteOnly)); |
362 | QVERIFY(ctx.file.permissions() & QFile::WriteUser); |
363 | ctx.file.close(); |
364 | |
365 | QFileDialog fd; |
366 | fd.setViewMode(QFileDialog::List); |
367 | fd.setDirectory(ctx.test.absolutePath()); |
368 | fd.selectFile(filename: ctx.file.fileName()); |
369 | fd.show(); |
370 | |
371 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
372 | |
373 | // grab some internals: |
374 | QAction *rm = fd.findChild<QAction*>(aName: "qt_delete_action" ); |
375 | QVERIFY(rm); |
376 | QAction *mv = fd.findChild<QAction*>(aName: "qt_rename_action" ); |
377 | QVERIFY(mv); |
378 | |
379 | // these are the real test cases: |
380 | |
381 | // defaults |
382 | QVERIFY(openContextMenu(fd)); |
383 | QCOMPARE(fd.selectedFiles(), QStringList(ctx.file.fileName())); |
384 | QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); |
385 | QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); |
386 | |
387 | // change to non-defaults: |
388 | fd.setOption(option: QFileDialog::ReadOnly, on: !fd.testOption(option: QFileDialog::ReadOnly)); |
389 | |
390 | QVERIFY(openContextMenu(fd)); |
391 | QCOMPARE(fd.selectedFiles().size(), 1); |
392 | QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); |
393 | QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); |
394 | |
395 | // and changed back to defaults: |
396 | fd.setOption(option: QFileDialog::ReadOnly, on: !fd.testOption(option: QFileDialog::ReadOnly)); |
397 | |
398 | QVERIFY(openContextMenu(fd)); |
399 | QCOMPARE(fd.selectedFiles().size(), 1); |
400 | QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); |
401 | QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); |
402 | } |
403 | #endif // !QT_NO_CONTEXTMENU && !QT_NO_MENU |
404 | |
405 | void tst_QFileDialog2::task178897_minimumSize() |
406 | { |
407 | QFileDialog fd; |
408 | QSize oldMs = fd.layout()->minimumSize(); |
409 | QStringList history = fd.history(); |
410 | history << QDir::toNativeSeparators(pathName: "/verylongdirectory/" |
411 | "aaaaaaaaaabbbbbbbbcccccccccccddddddddddddddeeeeeeeeeeeeffffffffffgggtggggggggghhhhhhhhiiiiiijjjk" ); |
412 | fd.setHistory(history); |
413 | fd.show(); |
414 | |
415 | QSize ms = fd.layout()->minimumSize(); |
416 | QVERIFY(ms.width() <= oldMs.width()); |
417 | } |
418 | |
419 | void tst_QFileDialog2::task180459_lastDirectory_data() |
420 | { |
421 | QTest::addColumn<QString>(name: "path" ); |
422 | QTest::addColumn<QString>(name: "directory" ); |
423 | QTest::addColumn<bool>(name: "isEnabled" ); |
424 | QTest::addColumn<QString>(name: "result" ); |
425 | |
426 | QTest::newRow(dataTag: "path+file" ) << QDir::homePath() + QDir::separator() + "foo" |
427 | << QDir::homePath() << true |
428 | << QDir::homePath() + QDir::separator() + "foo" ; |
429 | QTest::newRow(dataTag: "no path" ) << "" |
430 | << tempDir.path() << false << QString(); |
431 | QTest::newRow(dataTag: "file" ) << "foo" |
432 | << QDir::currentPath() << true |
433 | << QDir::currentPath() + QDir::separator() + "foo" ; |
434 | QTest::newRow(dataTag: "path" ) << QDir::homePath() |
435 | << QDir::homePath() << false << QString(); |
436 | QTest::newRow(dataTag: "path not existing" ) << "/usr/bin/foo/bar/foo/foo.txt" |
437 | << tempDir.path() << true |
438 | << tempDir.path() + QDir::separator() + "foo.txt" ; |
439 | |
440 | } |
441 | |
442 | void tst_QFileDialog2::task180459_lastDirectory() |
443 | { |
444 | if (!QGuiApplication::platformName().compare(other: QLatin1String("cocoa" ), cs: Qt::CaseInsensitive)) |
445 | QSKIP("Insignificant on OSX" ); //QTBUG-39183 |
446 | //first visit the temp directory and close the dialog |
447 | QFileDialog *dlg = new QFileDialog(0, "" , tempDir.path()); |
448 | QFileSystemModel *model = dlg->findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
449 | QVERIFY(model); |
450 | QCOMPARE(model->index(tempDir.path()), model->index(dlg->directory().absolutePath())); |
451 | delete dlg; |
452 | |
453 | QFETCH(QString, path); |
454 | QFETCH(QString, directory); |
455 | QFETCH(bool, isEnabled); |
456 | QFETCH(QString, result); |
457 | |
458 | dlg = new QFileDialog(0, "" , path); |
459 | model = dlg->findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
460 | QVERIFY(model); |
461 | dlg->setAcceptMode(QFileDialog::AcceptSave); |
462 | QCOMPARE(model->index(dlg->directory().absolutePath()), model->index(directory)); |
463 | |
464 | QDialogButtonBox *buttonBox = dlg->findChild<QDialogButtonBox*>(aName: "buttonBox" ); |
465 | QPushButton *button = buttonBox->button(which: QDialogButtonBox::Save); |
466 | QVERIFY(button); |
467 | QCOMPARE(button->isEnabled(), isEnabled); |
468 | if (isEnabled) |
469 | QCOMPARE(model->index(result), model->index(dlg->selectedFiles().first())); |
470 | |
471 | delete dlg; |
472 | } |
473 | |
474 | |
475 | |
476 | class FilterDirModel : public QSortFilterProxyModel |
477 | { |
478 | |
479 | public: |
480 | FilterDirModel(QString root, QObject* parent=0):QSortFilterProxyModel(parent), m_root(root) |
481 | {} |
482 | ~FilterDirModel() |
483 | {}; |
484 | |
485 | protected: |
486 | bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const |
487 | { |
488 | QModelIndex parentIndex; |
489 | parentIndex = source_parent; |
490 | |
491 | QString path; |
492 | path = sourceModel()->index(row: source_row, column: 0, parent: parentIndex).data(arole: Qt::DisplayRole).toString(); |
493 | |
494 | do { |
495 | path = parentIndex.data(arole: Qt::DisplayRole).toString() + QLatin1Char('/') + path; |
496 | parentIndex = parentIndex.parent(); |
497 | } while(parentIndex.isValid()); |
498 | |
499 | QFileInfo info(path); |
500 | if (info.isDir() && (QDir(path) != m_root)) |
501 | return false; |
502 | return true; |
503 | } |
504 | |
505 | |
506 | private: |
507 | QDir m_root; |
508 | |
509 | |
510 | }; |
511 | |
512 | class sortProxy : public QSortFilterProxyModel |
513 | { |
514 | public: |
515 | sortProxy(QObject *parent) : QSortFilterProxyModel(parent) |
516 | { |
517 | } |
518 | protected: |
519 | virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const |
520 | { |
521 | QFileSystemModel * const model = qobject_cast<QFileSystemModel *>(object: sourceModel()); |
522 | const QFileInfo leftInfo(model->fileInfo(index: left)); |
523 | const QFileInfo rightInfo(model->fileInfo(index: right)); |
524 | |
525 | if (leftInfo.isDir() == rightInfo.isDir()) |
526 | return(leftInfo.filePath().compare(s: rightInfo.filePath(),cs: Qt::CaseInsensitive) < 0); |
527 | else if (leftInfo.isDir()) |
528 | return(false); |
529 | else |
530 | return(true); |
531 | } |
532 | }; |
533 | |
534 | class CrashDialog : public QFileDialog |
535 | { |
536 | Q_OBJECT |
537 | |
538 | public: |
539 | CrashDialog(QWidget *parent, const QString &caption, const |
540 | QString &dir, const QString &filter) |
541 | : QFileDialog(parent, caption, dir, filter) |
542 | { |
543 | sortProxy *proxyModel = new sortProxy(this); |
544 | setProxyModel(proxyModel); |
545 | } |
546 | }; |
547 | |
548 | #ifdef QT_BUILD_INTERNAL |
549 | void tst_QFileDialog2::task227304_proxyOnFileDialog() |
550 | { |
551 | QFileDialog fd(0, "" , QDir::currentPath(), 0); |
552 | fd.setProxyModel(new FilterDirModel(QDir::currentPath())); |
553 | fd.show(); |
554 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
555 | QLineEdit *edit = fd.findChild<QLineEdit*>(aName: "fileNameEdit" ); |
556 | QVERIFY(edit); |
557 | QTest::keyClick(widget: edit, key: Qt::Key_T); |
558 | QTest::keyClick(widget: edit, key: Qt::Key_S); |
559 | QTest::keyClick(widget: edit->completer()->popup(), key: Qt::Key_Down); |
560 | |
561 | CrashDialog *dialog = new CrashDialog(0, QString("crash dialog test" ), QDir::homePath(), QString("*" ) ); |
562 | dialog->setFileMode(QFileDialog::ExistingFile); |
563 | dialog->show(); |
564 | QVERIFY(QTest::qWaitForWindowExposed(dialog)); |
565 | |
566 | QListView *list = dialog->findChild<QListView*>(aName: "listView" ); |
567 | QVERIFY(list); |
568 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
569 | QTest::keyClick(widget: list, key: Qt::Key_Return); |
570 | |
571 | dialog->close(); |
572 | fd.close(); |
573 | |
574 | QFileDialog fd2(0, "I should not crash with a proxy" , tempDir.path(), {}); |
575 | QSortFilterProxyModel *pm = new QSortFilterProxyModel; |
576 | fd2.setProxyModel(pm); |
577 | fd2.show(); |
578 | QSidebar * = fd2.findChild<QSidebar*>(aName: "sidebar" ); |
579 | sidebar->setFocus(); |
580 | sidebar->selectUrl(url: QUrl::fromLocalFile(localfile: QDir::homePath())); |
581 | QTest::mouseClick(widget: sidebar->viewport(), button: Qt::LeftButton, stateKey: {}, |
582 | pos: sidebar->visualRect(index: sidebar->model()->index(row: 1, column: 0)).center()); |
583 | QTest::qWait(ms: 250); |
584 | //We shouldn't crash |
585 | } |
586 | #endif |
587 | |
588 | #ifndef Q_OS_MAC |
589 | // The following test implies the folder created will appear first in |
590 | // the list. On Mac files sorting depends on the locale and the order |
591 | // displayed cannot be known for sure. |
592 | void tst_QFileDialog2::task227930_correctNavigationKeyboardBehavior() |
593 | { |
594 | QDir current = QDir::currentPath(); |
595 | current.mkdir(dirName: "test" ); |
596 | current.cd(dirName: "test" ); |
597 | QFile file("test/out.txt" ); |
598 | QFile file2("test/out2.txt" ); |
599 | QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); |
600 | QVERIFY(file2.open(QIODevice::WriteOnly | QIODevice::Text)); |
601 | current.cdUp(); |
602 | current.mkdir(dirName: "test2" ); |
603 | QFileDialog fd; |
604 | fd.setViewMode(QFileDialog::List); |
605 | fd.setDirectory(current.absolutePath()); |
606 | fd.show(); |
607 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
608 | |
609 | // Ensure LayoutRequest event is processed so that the list view |
610 | // is sorted correctly to have the directory entires at the top. |
611 | QCoreApplication::processEvents(); |
612 | |
613 | QListView *list = fd.findChild<QListView*>(aName: "listView" ); |
614 | QVERIFY(list); |
615 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
616 | QTest::keyClick(widget: list, key: Qt::Key_Return); |
617 | QTest::mouseClick(widget: list->viewport(), button: Qt::LeftButton, stateKey: {}); |
618 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
619 | QTest::keyClick(widget: list, key: Qt::Key_Backspace); |
620 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
621 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
622 | QTest::keyClick(widget: list, key: Qt::Key_Return); |
623 | QCOMPARE(fd.isVisible(), true); |
624 | file.close(); |
625 | file2.close(); |
626 | file.remove(); |
627 | file2.remove(); |
628 | current.rmdir(dirName: "test" ); |
629 | current.rmdir(dirName: "test2" ); |
630 | } |
631 | #endif |
632 | |
633 | #if defined(Q_OS_WIN) |
634 | void tst_QFileDialog2::task226366_lowerCaseHardDriveWindows() |
635 | { |
636 | QFileDialog fd; |
637 | fd.setDirectory(QDir::root().path()); |
638 | fd.show(); |
639 | QLineEdit *edit = fd.findChild<QLineEdit*>("fileNameEdit" ); |
640 | QToolButton *buttonParent = fd.findChild<QToolButton*>("toParentButton" ); |
641 | QTest::qWait(200); |
642 | QTest::mouseClick(buttonParent, Qt::LeftButton,0,QPoint(0,0)); |
643 | QTest::qWait(2000); |
644 | QTest::keyClick(edit, Qt::Key_C); |
645 | QTest::qWait(200); |
646 | QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); |
647 | QTest::qWait(200); |
648 | QCOMPARE(edit->text(), QString("C:/" )); |
649 | QTest::qWait(2000); |
650 | //i clear my previous selection in the completer |
651 | QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); |
652 | edit->clear(); |
653 | QTest::keyClick(edit, (char)(Qt::Key_C | Qt::SHIFT)); |
654 | QTest::qWait(200); |
655 | QTest::keyClick(edit->completer()->popup(), Qt::Key_Down); |
656 | QCOMPARE(edit->text(), QString("C:/" )); |
657 | } |
658 | #endif |
659 | |
660 | void tst_QFileDialog2::completionOnLevelAfterRoot() |
661 | { |
662 | QFileDialog fd; |
663 | #if defined(Q_OS_WIN) |
664 | fd.setDirectory("C:/" ); |
665 | QDir current = fd.directory(); |
666 | QStringList entryList = current.entryList(QStringList(), QDir::Dirs); |
667 | // Find a suitable test dir under c:-root: |
668 | // - At least 6 characters long |
669 | // - Ascii, letters only |
670 | // - No another dir with same start |
671 | QString testDir; |
672 | foreach (const QString &entry, entryList) { |
673 | if (entry.size() > 5 && QString(entry.toLatin1()).compare(entry) == 0) { |
674 | bool invalid = false; |
675 | for (int i = 0; i < 5; i++) { |
676 | if (!entry.at(i).isLetter()) { |
677 | invalid = true; |
678 | break; |
679 | } |
680 | } |
681 | if (!invalid) { |
682 | foreach (const QString &check, entryList) { |
683 | if (check.startsWith(entry.left(5), Qt::CaseInsensitive) && check != entry) { |
684 | invalid = true; |
685 | break; |
686 | } |
687 | } |
688 | } |
689 | if (!invalid) { |
690 | testDir = entry; |
691 | break; |
692 | } |
693 | } |
694 | } |
695 | if (testDir.isEmpty()) |
696 | QSKIP("This test requires to have a unique directory of at least six ascii characters under c:/" ); |
697 | #else |
698 | fd.setFilter(QDir::Hidden | QDir::AllDirs | QDir::Files | QDir::System); |
699 | fd.setDirectory("/" ); |
700 | QDir etc("/etc" ); |
701 | if (!etc.exists()) |
702 | QSKIP("This test requires to have an etc directory under /" ); |
703 | #endif |
704 | fd.show(); |
705 | QLineEdit *edit = fd.findChild<QLineEdit*>(aName: "fileNameEdit" ); |
706 | QTest::qWait(ms: 2000); |
707 | #if defined(Q_OS_WIN) |
708 | //I love testlib :D |
709 | for (int i = 0; i < 5; i++) |
710 | QTest::keyClick(edit, testDir.at(i).toLower().toLatin1() - 'a' + Qt::Key_A); |
711 | #else |
712 | QTest::keyClick(widget: edit, key: Qt::Key_E); |
713 | QTest::keyClick(widget: edit, key: Qt::Key_T); |
714 | #endif |
715 | QTest::qWait(ms: 200); |
716 | QTest::keyClick(widget: edit->completer()->popup(), key: Qt::Key_Down); |
717 | QTest::qWait(ms: 200); |
718 | #if defined(Q_OS_WIN) |
719 | QCOMPARE(edit->text(), testDir); |
720 | #else |
721 | QTRY_COMPARE(edit->text(), QString("etc" )); |
722 | #endif |
723 | } |
724 | |
725 | void tst_QFileDialog2::task233037_selectingDirectory() |
726 | { |
727 | QDir current = QDir::currentPath(); |
728 | current.mkdir(dirName: "test" ); |
729 | QFileDialog fd; |
730 | fd.setViewMode(QFileDialog::List); |
731 | fd.setDirectory(current.absolutePath()); |
732 | fd.setAcceptMode( QFileDialog::AcceptSave); |
733 | fd.show(); |
734 | QListView *list = fd.findChild<QListView*>(aName: "listView" ); |
735 | QTest::qWait(ms: 3000); // Wait for sort to settle (I need a signal). |
736 | #ifdef QT_KEYPAD_NAVIGATION |
737 | list->setEditFocus(true); |
738 | #endif |
739 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
740 | QDialogButtonBox *buttonBox = fd.findChild<QDialogButtonBox*>(aName: "buttonBox" ); |
741 | QVERIFY(buttonBox); |
742 | QPushButton *button = buttonBox->button(which: QDialogButtonBox::Save); |
743 | QVERIFY(button); |
744 | QVERIFY(button->isEnabled()); |
745 | current.rmdir(dirName: "test" ); |
746 | } |
747 | |
748 | void tst_QFileDialog2::task235069_hideOnEscape_data() |
749 | { |
750 | QTest::addColumn<QString>(name: "childName" ); |
751 | QTest::addColumn<QFileDialog::ViewMode>(name: "viewMode" ); |
752 | QTest::newRow(dataTag: "listView" ) << QStringLiteral("listView" ) << QFileDialog::List; |
753 | QTest::newRow(dataTag: "fileNameEdit" ) << QStringLiteral("fileNameEdit" ) << QFileDialog::List; |
754 | QTest::newRow(dataTag: "treeView" ) << QStringLiteral("treeView" ) << QFileDialog::Detail; |
755 | } |
756 | |
757 | void tst_QFileDialog2::task235069_hideOnEscape() |
758 | { |
759 | QFETCH(QString, childName); |
760 | QFETCH(QFileDialog::ViewMode, viewMode); |
761 | QDir current = QDir::currentPath(); |
762 | |
763 | QFileDialog fd; |
764 | QSignalSpy spyFinished(&fd, &QDialog::finished); |
765 | QVERIFY(spyFinished.isValid()); |
766 | QSignalSpy spyRejected(&fd, &QDialog::rejected); |
767 | QVERIFY(spyRejected.isValid()); |
768 | fd.setViewMode(viewMode); |
769 | fd.setDirectory(current.absolutePath()); |
770 | fd.setAcceptMode(QFileDialog::AcceptSave); |
771 | fd.show(); |
772 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
773 | QWidget *child = fd.findChild<QWidget *>(aName: childName); |
774 | QVERIFY(child); |
775 | child->setFocus(); |
776 | QTest::keyClick(widget: child, key: Qt::Key_Escape); |
777 | QCOMPARE(fd.isVisible(), false); |
778 | QCOMPARE(spyFinished.count(), 1); // QTBUG-7690 |
779 | QCOMPARE(spyRejected.count(), 1); // reject(), don't hide() |
780 | } |
781 | |
782 | #ifdef QT_BUILD_INTERNAL |
783 | void tst_QFileDialog2::task236402_dontWatchDeletedDir() |
784 | { |
785 | //THIS TEST SHOULD NOT DISPLAY WARNINGS |
786 | QDir current = QDir::currentPath(); |
787 | //make sure it is the first on the list |
788 | current.mkdir(dirName: "aaaaaaaaaa" ); |
789 | FriendlyQFileDialog fd; |
790 | fd.setViewMode(QFileDialog::List); |
791 | fd.setDirectory(current.absolutePath()); |
792 | fd.setAcceptMode( QFileDialog::AcceptSave); |
793 | fd.show(); |
794 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
795 | QListView *list = fd.findChild<QListView*>(aName: "listView" ); |
796 | QVERIFY(list); |
797 | list->setFocus(); |
798 | QTest::keyClick(widget: list, key: Qt::Key_Return); |
799 | QTest::keyClick(widget: list, key: Qt::Key_Backspace); |
800 | QTest::keyClick(widget: list, key: Qt::Key_Down); |
801 | fd.d_func()->removeDirectory(path: current.absolutePath() + "/aaaaaaaaaa/" ); |
802 | QTest::qWait(ms: 1000); |
803 | } |
804 | #endif |
805 | |
806 | void tst_QFileDialog2::task203703_returnProperSeparator() |
807 | { |
808 | QDir current = QDir::currentPath(); |
809 | current.mkdir(dirName: "aaaaaaaaaaaaaaaaaa" ); |
810 | QFileDialog fd; |
811 | fd.setDirectory(current.absolutePath()); |
812 | fd.setViewMode(QFileDialog::List); |
813 | fd.setFileMode(QFileDialog::Directory); |
814 | fd.show(); |
815 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
816 | QListView *list = fd.findChild<QListView*>(aName: "listView" ); |
817 | QVERIFY(list); |
818 | list->setFocus(); |
819 | QTest::keyClick(widget: list, key: Qt::Key_Return); |
820 | QDialogButtonBox *buttonBox = fd.findChild<QDialogButtonBox*>(aName: "buttonBox" ); |
821 | QVERIFY(buttonBox); |
822 | QPushButton *button = buttonBox->button(which: QDialogButtonBox::Cancel); |
823 | QVERIFY(button); |
824 | QTest::keyClick(widget: button, key: Qt::Key_Return); |
825 | QString result = fd.selectedFiles().first(); |
826 | QVERIFY(result.at(result.count() - 1) != '/'); |
827 | QVERIFY(!result.contains('\\')); |
828 | current.rmdir(dirName: "aaaaaaaaaaaaaaaaaa" ); |
829 | } |
830 | |
831 | void tst_QFileDialog2::task228844_ensurePreviousSorting() |
832 | { |
833 | QDir current = QDir::currentPath(); |
834 | current.mkdir(dirName: "aaaaaaaaaaaaaaaaaa" ); |
835 | current.cd(dirName: "aaaaaaaaaaaaaaaaaa" ); |
836 | current.mkdir(dirName: "a" ); |
837 | current.mkdir(dirName: "b" ); |
838 | current.mkdir(dirName: "c" ); |
839 | current.mkdir(dirName: "d" ); |
840 | current.mkdir(dirName: "e" ); |
841 | current.mkdir(dirName: "f" ); |
842 | current.mkdir(dirName: "g" ); |
843 | QTemporaryFile *tempFile = new QTemporaryFile(current.absolutePath() + "/rXXXXXX" ); |
844 | QVERIFY2(tempFile->open(), qPrintable(tempFile->errorString())); |
845 | current.cdUp(); |
846 | |
847 | QFileDialog fd; |
848 | fd.setDirectory(current.absolutePath()); |
849 | fd.setViewMode(QFileDialog::Detail); |
850 | fd.show(); |
851 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
852 | QTreeView *tree = fd.findChild<QTreeView*>(aName: "treeView" ); |
853 | QVERIFY(tree); |
854 | tree->header()->setSortIndicator(logicalIndex: 3,order: Qt::DescendingOrder); |
855 | QDialogButtonBox *buttonBox = fd.findChild<QDialogButtonBox*>(aName: "buttonBox" ); |
856 | QVERIFY(buttonBox); |
857 | QPushButton *button = buttonBox->button(which: QDialogButtonBox::Open); |
858 | QVERIFY(button); |
859 | QTest::mouseClick(widget: button, button: Qt::LeftButton); |
860 | QFileDialog fd2; |
861 | fd2.setFileMode(QFileDialog::Directory); |
862 | fd2.restoreState(state: fd.saveState()); |
863 | current.cd(dirName: "aaaaaaaaaaaaaaaaaa" ); |
864 | fd2.setDirectory(current.absolutePath()); |
865 | fd2.show(); |
866 | QVERIFY(QTest::qWaitForWindowExposed(&fd2)); |
867 | QTreeView *tree2 = fd2.findChild<QTreeView*>(aName: "treeView" ); |
868 | QVERIFY(tree2); |
869 | tree2->setFocus(); |
870 | |
871 | QCOMPARE(tree2->rootIndex().data(QFileSystemModel::FilePathRole).toString(),current.absolutePath()); |
872 | |
873 | QDialogButtonBox *buttonBox2 = fd2.findChild<QDialogButtonBox*>(aName: "buttonBox" ); |
874 | QVERIFY(buttonBox2); |
875 | QPushButton *button2 = buttonBox2->button(which: QDialogButtonBox::Open); |
876 | QVERIFY(button2); |
877 | fd2.selectFile(filename: "g" ); |
878 | QTest::mouseClick(widget: button2, button: Qt::LeftButton); |
879 | QCOMPARE(fd2.selectedFiles().first(), current.absolutePath() + QLatin1String("/g" )); |
880 | |
881 | QFileDialog fd3(0, "This is a third file dialog" , tempFile->fileName()); |
882 | fd3.restoreState(state: fd.saveState()); |
883 | fd3.setFileMode(QFileDialog::Directory); |
884 | fd3.show(); |
885 | QVERIFY(QTest::qWaitForWindowExposed(&fd3)); |
886 | QTreeView *tree3 = fd3.findChild<QTreeView*>(aName: "treeView" ); |
887 | QVERIFY(tree3); |
888 | tree3->setFocus(); |
889 | |
890 | QCOMPARE(tree3->rootIndex().data(QFileSystemModel::FilePathRole).toString(), current.absolutePath()); |
891 | |
892 | QDialogButtonBox *buttonBox3 = fd3.findChild<QDialogButtonBox*>(aName: "buttonBox" ); |
893 | QVERIFY(buttonBox3); |
894 | QPushButton *button3 = buttonBox3->button(which: QDialogButtonBox::Open); |
895 | QVERIFY(button3); |
896 | QTest::mouseClick(widget: button3, button: Qt::LeftButton); |
897 | QCOMPARE(fd3.selectedFiles().first(), tempFile->fileName()); |
898 | |
899 | current.cd(dirName: "aaaaaaaaaaaaaaaaaa" ); |
900 | current.rmdir(dirName: "a" ); |
901 | current.rmdir(dirName: "b" ); |
902 | current.rmdir(dirName: "c" ); |
903 | current.rmdir(dirName: "d" ); |
904 | current.rmdir(dirName: "e" ); |
905 | current.rmdir(dirName: "f" ); |
906 | current.rmdir(dirName: "g" ); |
907 | tempFile->close(); |
908 | delete tempFile; |
909 | current.cdUp(); |
910 | current.rmdir(dirName: "aaaaaaaaaaaaaaaaaa" ); |
911 | } |
912 | |
913 | |
914 | void tst_QFileDialog2::task239706_editableFilterCombo() |
915 | { |
916 | QFileDialog d; |
917 | d.setNameFilter("*.cpp *.h" ); |
918 | d.show(); |
919 | QVERIFY(QTest::qWaitForWindowExposed(&d)); |
920 | |
921 | QList<QComboBox *> comboList = d.findChildren<QComboBox *>(); |
922 | QComboBox *filterCombo = 0; |
923 | foreach (QComboBox *combo, comboList) { |
924 | if (combo->objectName() == QString("fileTypeCombo" )) { |
925 | filterCombo = combo; |
926 | break; |
927 | } |
928 | } |
929 | QVERIFY(filterCombo); |
930 | filterCombo->setEditable(true); |
931 | QTest::mouseClick(widget: filterCombo, button: Qt::LeftButton); |
932 | QTest::keyPress(widget: filterCombo, key: Qt::Key_X); |
933 | QTest::keyPress(widget: filterCombo, key: Qt::Key_Enter); // should not trigger assertion failure |
934 | } |
935 | |
936 | void tst_QFileDialog2::task218353_relativePaths() |
937 | { |
938 | QDir appDir = QDir::current(); |
939 | QVERIFY(appDir.cdUp() != false); |
940 | QFileDialog d(0, "TestDialog" , ".." ); |
941 | QCOMPARE(d.directory().absolutePath(), appDir.absolutePath()); |
942 | |
943 | d.setDirectory(appDir.absolutePath() + QLatin1String("/non-existing-directory/../another-non-existing-dir/../" )); |
944 | QCOMPARE(d.directory().absolutePath(), appDir.absolutePath()); |
945 | |
946 | QDir::current().mkdir(dirName: "test" ); |
947 | appDir = QDir::current(); |
948 | d.setDirectory(appDir.absolutePath() + QLatin1String("/test/../test/../" )); |
949 | QCOMPARE(d.directory().absolutePath(), appDir.absolutePath()); |
950 | appDir.rmdir(dirName: "test" ); |
951 | } |
952 | |
953 | #ifdef QT_BUILD_INTERNAL |
954 | void tst_QFileDialog2::() |
955 | { |
956 | QFileDialog fd; |
957 | |
958 | QDir current = QDir::currentPath(); |
959 | current.mkdir(dirName: ".hidden" ); |
960 | QDir hiddenDir = QDir(".hidden" ); |
961 | hiddenDir.mkdir(dirName: "subdir" ); |
962 | QDir hiddenSubDir = QDir(".hidden/subdir" ); |
963 | hiddenSubDir.mkdir(dirName: "happy" ); |
964 | hiddenSubDir.mkdir(dirName: "happy2" ); |
965 | |
966 | QList<QUrl> urls; |
967 | urls << QUrl::fromLocalFile(localfile: hiddenSubDir.absolutePath()); |
968 | fd.setSidebarUrls(urls); |
969 | fd.show(); |
970 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
971 | |
972 | QSidebar * = fd.findChild<QSidebar*>(aName: "sidebar" ); |
973 | QVERIFY(sidebar); |
974 | sidebar->setFocus(); |
975 | sidebar->selectUrl(url: QUrl::fromLocalFile(localfile: hiddenSubDir.absolutePath())); |
976 | QTest::mouseClick(widget: sidebar->viewport(), button: Qt::LeftButton, stateKey: {}, |
977 | pos: sidebar->visualRect(index: sidebar->model()->index(row: 0, column: 0)).center()); |
978 | // give the background processes more time on windows mobile |
979 | QTest::qWait(ms: 250); |
980 | |
981 | QFileSystemModel *model = fd.findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
982 | QCOMPARE(model->rowCount(model->index(hiddenSubDir.absolutePath())), 2); |
983 | |
984 | hiddenSubDir.rmdir(dirName: "happy2" ); |
985 | hiddenSubDir.rmdir(dirName: "happy" ); |
986 | hiddenDir.rmdir(dirName: "subdir" ); |
987 | current.rmdir(dirName: ".hidden" ); |
988 | } |
989 | #endif |
990 | |
991 | #if defined QT_BUILD_INTERNAL |
992 | class : public QSidebar |
993 | { |
994 | public : |
995 | (QWidget *parent = 0) : QSidebar(parent) |
996 | {} |
997 | |
998 | void () { |
999 | QList<QModelIndex> idxs = selectionModel()->selectedIndexes(); |
1000 | QList<QPersistentModelIndex> indexes; |
1001 | for (int i = 0; i < idxs.count(); i++) |
1002 | indexes.append(t: idxs.at(i)); |
1003 | |
1004 | for (int i = 0; i < indexes.count(); ++i) |
1005 | if (!indexes.at(i).data(role: Qt::UserRole + 1).toUrl().path().isEmpty()) |
1006 | model()->removeRow(arow: indexes.at(i).row()); |
1007 | } |
1008 | }; |
1009 | #endif |
1010 | |
1011 | #ifdef QT_BUILD_INTERNAL |
1012 | void tst_QFileDialog2::() |
1013 | { |
1014 | QFileDialog fd; |
1015 | |
1016 | QDir current = QDir::currentPath(); |
1017 | current.mkdir(dirName: "testDir" ); |
1018 | QDir testSubDir = QDir("testDir" ); |
1019 | |
1020 | QList<QUrl> urls; |
1021 | urls << QUrl::fromLocalFile(localfile: testSubDir.absolutePath()); |
1022 | urls << QUrl::fromLocalFile(localfile: "NotFound" ); |
1023 | fd.setSidebarUrls(urls); |
1024 | fd.show(); |
1025 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
1026 | |
1027 | QSidebar * = fd.findChild<QSidebar*>(aName: "sidebar" ); |
1028 | QVERIFY(sidebar); |
1029 | sidebar->setFocus(); |
1030 | //We enter in the first bookmark |
1031 | sidebar->selectUrl(url: QUrl::fromLocalFile(localfile: testSubDir.absolutePath())); |
1032 | QTest::mouseClick(widget: sidebar->viewport(), button: Qt::LeftButton, stateKey: {}, |
1033 | pos: sidebar->visualRect(index: sidebar->model()->index(row: 0, column: 0)).center()); |
1034 | |
1035 | QFileSystemModel *model = fd.findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
1036 | QVERIFY(model); |
1037 | //There is no file |
1038 | QCOMPARE(model->rowCount(model->index(testSubDir.absolutePath())), 0); |
1039 | //Icon is not enabled QUrlModel::EnabledRole |
1040 | QVariant value = sidebar->model()->index(row: 0, column: 0).data(arole: Qt::UserRole + 2); |
1041 | QCOMPARE(qvariant_cast<bool>(value), true); |
1042 | |
1043 | sidebar->setFocus(); |
1044 | //We enter in the second bookmark which is invalid |
1045 | sidebar->selectUrl(url: QUrl::fromLocalFile(localfile: "NotFound" )); |
1046 | QTest::mouseClick(widget: sidebar->viewport(), button: Qt::LeftButton, stateKey: {}, |
1047 | pos: sidebar->visualRect(index: sidebar->model()->index(row: 1, column: 0)).center()); |
1048 | |
1049 | //We fallback to root because the entry in the bookmark is invalid |
1050 | QCOMPARE(model->rowCount(model->index("NotFound" )), model->rowCount(model->index(model->rootPath()))); |
1051 | //Icon is not enabled QUrlModel::EnabledRole |
1052 | value = sidebar->model()->index(row: 1, column: 0).data(arole: Qt::UserRole + 2); |
1053 | QCOMPARE(qvariant_cast<bool>(value), false); |
1054 | |
1055 | MyQSideBar ; |
1056 | mySideBar.setModelAndUrls(model, newUrls: urls); |
1057 | mySideBar.show(); |
1058 | mySideBar.selectUrl(url: QUrl::fromLocalFile(localfile: testSubDir.absolutePath())); |
1059 | QTest::qWait(ms: 1000); |
1060 | mySideBar.removeSelection(); |
1061 | |
1062 | //We remove the first entry |
1063 | QList<QUrl> expected; |
1064 | expected << QUrl::fromLocalFile(localfile: "NotFound" ); |
1065 | QCOMPARE(mySideBar.urls(), expected); |
1066 | |
1067 | mySideBar.selectUrl(url: QUrl::fromLocalFile(localfile: "NotFound" )); |
1068 | mySideBar.removeSelection(); |
1069 | |
1070 | //We remove the second entry |
1071 | expected.clear(); |
1072 | QCOMPARE(mySideBar.urls(), expected); |
1073 | |
1074 | current.rmdir(dirName: "testDir" ); |
1075 | } |
1076 | #endif |
1077 | |
1078 | void tst_QFileDialog2::task254490_selectFileMultipleTimes() |
1079 | { |
1080 | QString tempPath = tempDir.path(); |
1081 | QTemporaryFile *t; |
1082 | t = new QTemporaryFile; |
1083 | QVERIFY2(t->open(), qPrintable(t->errorString())); |
1084 | t->open(); |
1085 | QFileDialog fd(0, "TestFileDialog" ); |
1086 | |
1087 | fd.setDirectory(tempPath); |
1088 | fd.setViewMode(QFileDialog::List); |
1089 | fd.setAcceptMode(QFileDialog::AcceptSave); |
1090 | fd.setFileMode(QFileDialog::AnyFile); |
1091 | |
1092 | //This should select the file in the QFileDialog |
1093 | fd.selectFile(filename: t->fileName()); |
1094 | |
1095 | //This should clear the selection and write it into the filename line edit |
1096 | fd.selectFile(filename: "new_file.txt" ); |
1097 | |
1098 | fd.show(); |
1099 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
1100 | |
1101 | QLineEdit *lineEdit = fd.findChild<QLineEdit*>(aName: "fileNameEdit" ); |
1102 | QVERIFY(lineEdit); |
1103 | QCOMPARE(lineEdit->text(),QLatin1String("new_file.txt" )); |
1104 | QListView *list = fd.findChild<QListView*>(aName: "listView" ); |
1105 | QVERIFY(list); |
1106 | QCOMPARE(list->selectionModel()->selectedRows(0).count(), 0); |
1107 | |
1108 | t->deleteLater(); |
1109 | } |
1110 | |
1111 | #ifdef QT_BUILD_INTERNAL |
1112 | void tst_QFileDialog2::() |
1113 | { |
1114 | QDir dir(tempDir.path()); |
1115 | QLatin1String dirname("autotest_task257579" ); |
1116 | dir.rmdir(dirName: dirname); //makes sure it doesn't exist any more |
1117 | QVERIFY(dir.mkdir(dirname)); |
1118 | QString url = dir.absolutePath() + QLatin1Char('/') + dirname + QLatin1String("/.." ); |
1119 | QFileDialog fd; |
1120 | fd.setSidebarUrls(QList<QUrl>() << QUrl::fromLocalFile(localfile: url)); |
1121 | QSidebar * = fd.findChild<QSidebar*>(aName: "sidebar" ); |
1122 | QCOMPARE(sidebar->urls().count(), 1); |
1123 | QVERIFY(sidebar->urls().first().toLocalFile() != url); |
1124 | QCOMPARE(sidebar->urls().first().toLocalFile(), QDir::cleanPath(url)); |
1125 | |
1126 | #ifdef Q_OS_WIN |
1127 | QCOMPARE(sidebar->model()->index(0,0).data().toString().toLower(), dir.dirName().toLower()); |
1128 | #else |
1129 | QCOMPARE(sidebar->model()->index(0,0).data().toString(), dir.dirName()); |
1130 | #endif |
1131 | |
1132 | //all tests are finished, we can remove the temporary dir |
1133 | QVERIFY(dir.rmdir(dirname)); |
1134 | } |
1135 | #endif |
1136 | |
1137 | void tst_QFileDialog2::task259105_filtersCornerCases() |
1138 | { |
1139 | QFileDialog fd(0, "TestFileDialog" ); |
1140 | fd.setNameFilter(QLatin1String("All Files! (*);;Text Files (*.txt)" )); |
1141 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: true); |
1142 | fd.show(); |
1143 | QVERIFY(QTest::qWaitForWindowExposed(&fd)); |
1144 | |
1145 | //Extensions are hidden |
1146 | QComboBox *filters = fd.findChild<QComboBox*>(aName: "fileTypeCombo" ); |
1147 | QVERIFY(filters); |
1148 | QCOMPARE(filters->currentText(), QLatin1String("All Files!" )); |
1149 | filters->setCurrentIndex(1); |
1150 | QCOMPARE(filters->currentText(), QLatin1String("Text Files" )); |
1151 | |
1152 | //We should have the full names |
1153 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: false); |
1154 | filters->setCurrentIndex(0); |
1155 | QCOMPARE(filters->currentText(), QLatin1String("All Files! (*)" )); |
1156 | filters->setCurrentIndex(1); |
1157 | QCOMPARE(filters->currentText(), QLatin1String("Text Files (*.txt)" )); |
1158 | |
1159 | //Corner case undocumented of the task |
1160 | fd.setNameFilter(QLatin1String("\352 (I like cheese) All Files! (*);;Text Files (*.txt)" )); |
1161 | QCOMPARE(filters->currentText(), QLatin1String("\352 (I like cheese) All Files! (*)" )); |
1162 | filters->setCurrentIndex(1); |
1163 | QCOMPARE(filters->currentText(), QLatin1String("Text Files (*.txt)" )); |
1164 | |
1165 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: true); |
1166 | filters->setCurrentIndex(0); |
1167 | QCOMPARE(filters->currentText(), QLatin1String("\352 (I like cheese) All Files!" )); |
1168 | filters->setCurrentIndex(1); |
1169 | QCOMPARE(filters->currentText(), QLatin1String("Text Files" )); |
1170 | |
1171 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: true); |
1172 | filters->setCurrentIndex(0); |
1173 | QCOMPARE(filters->currentText(), QLatin1String("\352 (I like cheese) All Files!" )); |
1174 | filters->setCurrentIndex(1); |
1175 | QCOMPARE(filters->currentText(), QLatin1String("Text Files" )); |
1176 | } |
1177 | |
1178 | void tst_QFileDialog2::QTBUG4419_lineEditSelectAll() |
1179 | { |
1180 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
1181 | QSKIP("Window activation is not supported" ); |
1182 | |
1183 | QString tempPath = tempDir.path(); |
1184 | QTemporaryFile temporaryFile(tempPath + "/tst_qfiledialog2_lineEditSelectAll.XXXXXX" ); |
1185 | QVERIFY2(temporaryFile.open(), qPrintable(temporaryFile.errorString())); |
1186 | QFileDialog fd(0, "TestFileDialog" , temporaryFile.fileName()); |
1187 | |
1188 | fd.setDirectory(tempPath); |
1189 | fd.setViewMode(QFileDialog::List); |
1190 | fd.setAcceptMode(QFileDialog::AcceptSave); |
1191 | fd.setFileMode(QFileDialog::AnyFile); |
1192 | |
1193 | fd.show(); |
1194 | fd.activateWindow(); |
1195 | QVERIFY(QTest::qWaitForWindowActive(&fd)); |
1196 | QCOMPARE(fd.isVisible(), true); |
1197 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd)); |
1198 | |
1199 | QLineEdit *lineEdit = fd.findChild<QLineEdit*>(aName: "fileNameEdit" ); |
1200 | QVERIFY(lineEdit); |
1201 | |
1202 | QTRY_COMPARE(tempPath + QChar('/') + lineEdit->text(), temporaryFile.fileName()); |
1203 | QCOMPARE(tempPath + QChar('/') + lineEdit->selectedText(), temporaryFile.fileName()); |
1204 | } |
1205 | |
1206 | void tst_QFileDialog2::QTBUG6558_showDirsOnly() |
1207 | { |
1208 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
1209 | QSKIP("Window activation is not supported" ); |
1210 | |
1211 | const QString tempPath = tempDir.path(); |
1212 | QDir dirTemp(tempPath); |
1213 | const QString tempName = QLatin1String("showDirsOnly." ) + QString::number(QRandomGenerator::global()->generate()); |
1214 | dirTemp.mkdir(dirName: tempName); |
1215 | dirTemp.cd(dirName: tempName); |
1216 | QTRY_VERIFY(dirTemp.exists()); |
1217 | |
1218 | const QString dirPath = dirTemp.absolutePath(); |
1219 | QDir dir(dirPath); |
1220 | |
1221 | //We create two dirs |
1222 | dir.mkdir(dirName: "a" ); |
1223 | dir.mkdir(dirName: "b" ); |
1224 | |
1225 | //Create a file |
1226 | QFile tempFile(dirPath + "/plop.txt" ); |
1227 | tempFile.open(flags: QIODevice::WriteOnly | QIODevice::Text); |
1228 | QTextStream out(&tempFile); |
1229 | out << "The magic number is: " << 49 << "\n" ; |
1230 | tempFile.close(); |
1231 | |
1232 | QFileDialog fd(0, "TestFileDialog" ); |
1233 | |
1234 | fd.setDirectory(dir.absolutePath()); |
1235 | fd.setViewMode(QFileDialog::List); |
1236 | fd.setAcceptMode(QFileDialog::AcceptSave); |
1237 | fd.setOption(option: QFileDialog::ShowDirsOnly, on: true); |
1238 | fd.show(); |
1239 | |
1240 | QApplication::setActiveWindow(&fd); |
1241 | QVERIFY(QTest::qWaitForWindowActive(&fd)); |
1242 | QCOMPARE(fd.isVisible(), true); |
1243 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd)); |
1244 | |
1245 | QFileSystemModel *model = fd.findChild<QFileSystemModel*>(aName: "qt_filesystem_model" ); |
1246 | QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 2); |
1247 | |
1248 | fd.setOption(option: QFileDialog::ShowDirsOnly, on: false); |
1249 | QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 3); |
1250 | |
1251 | fd.setOption(option: QFileDialog::ShowDirsOnly, on: true); |
1252 | QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 2); |
1253 | |
1254 | fd.setFileMode(QFileDialog::DirectoryOnly); |
1255 | QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 2); |
1256 | QTRY_COMPARE(bool(fd.options() & QFileDialog::ShowDirsOnly), true); |
1257 | |
1258 | fd.setFileMode(QFileDialog::AnyFile); |
1259 | QTRY_COMPARE(model->rowCount(model->index(dir.absolutePath())), 3); |
1260 | QTRY_COMPARE(bool(fd.options() & QFileDialog::ShowDirsOnly), false); |
1261 | |
1262 | fd.setDirectory(QDir::homePath()); |
1263 | |
1264 | //We remove the dirs |
1265 | dir.rmdir(dirName: "a" ); |
1266 | dir.rmdir(dirName: "b" ); |
1267 | |
1268 | //we delete the file |
1269 | tempFile.remove(); |
1270 | |
1271 | dirTemp.cdUp(); |
1272 | dirTemp.rmdir(dirName: tempName); |
1273 | } |
1274 | |
1275 | void tst_QFileDialog2::QTBUG4842_selectFilterWithHideNameFilterDetails() |
1276 | { |
1277 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
1278 | QSKIP("Window activation is not supported" ); |
1279 | |
1280 | QStringList ; |
1281 | filtersStr << "Images (*.png *.xpm *.jpg)" << "Text files (*.txt)" << "XML files (*.xml)" ; |
1282 | QString chosenFilterString("Text files (*.txt)" ); |
1283 | |
1284 | QFileDialog fd(0, "TestFileDialog" ); |
1285 | fd.setAcceptMode(QFileDialog::AcceptSave); |
1286 | fd.setOption(option: QFileDialog::HideNameFilterDetails, on: true); |
1287 | fd.setNameFilters(filtersStr); |
1288 | fd.selectNameFilter(filter: chosenFilterString); |
1289 | fd.show(); |
1290 | |
1291 | QApplication::setActiveWindow(&fd); |
1292 | QVERIFY(QTest::qWaitForWindowActive(&fd)); |
1293 | QCOMPARE(fd.isVisible(), true); |
1294 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd)); |
1295 | |
1296 | QComboBox *filters = fd.findChild<QComboBox*>(aName: "fileTypeCombo" ); |
1297 | //We compare the current combobox text with the stripped version |
1298 | QCOMPARE(filters->currentText(), QString("Text files" )); |
1299 | |
1300 | QFileDialog fd2(0, "TestFileDialog" ); |
1301 | fd2.setAcceptMode(QFileDialog::AcceptSave); |
1302 | fd2.setOption(option: QFileDialog::HideNameFilterDetails, on: false); |
1303 | fd2.setNameFilters(filtersStr); |
1304 | fd2.selectNameFilter(filter: chosenFilterString); |
1305 | fd2.show(); |
1306 | |
1307 | QApplication::setActiveWindow(&fd2); |
1308 | QVERIFY(QTest::qWaitForWindowActive(&fd2)); |
1309 | QCOMPARE(fd2.isVisible(), true); |
1310 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd2)); |
1311 | |
1312 | QComboBox *filters2 = fd2.findChild<QComboBox*>(aName: "fileTypeCombo" ); |
1313 | //We compare the current combobox text with the non stripped version |
1314 | QCOMPARE(filters2->currentText(), chosenFilterString); |
1315 | |
1316 | } |
1317 | |
1318 | void tst_QFileDialog2::dontShowCompleterOnRoot() |
1319 | { |
1320 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
1321 | QSKIP("Window activation is not supported" ); |
1322 | |
1323 | QFileDialog fd(0, "TestFileDialog" ); |
1324 | fd.setAcceptMode(QFileDialog::AcceptSave); |
1325 | fd.show(); |
1326 | |
1327 | QApplication::setActiveWindow(&fd); |
1328 | QVERIFY(QTest::qWaitForWindowActive(&fd)); |
1329 | QCOMPARE(fd.isVisible(), true); |
1330 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&fd)); |
1331 | |
1332 | fd.setDirectory("" ); |
1333 | QLineEdit *lineEdit = fd.findChild<QLineEdit*>(aName: "fileNameEdit" ); |
1334 | QTRY_VERIFY(lineEdit->text().isEmpty()); |
1335 | |
1336 | //The gatherer thread will then return the result |
1337 | QApplication::processEvents(); |
1338 | |
1339 | QTRY_VERIFY(lineEdit->completer()->popup()->isHidden()); |
1340 | } |
1341 | |
1342 | void tst_QFileDialog2::nameFilterParsing_data() |
1343 | { |
1344 | QTest::addColumn<QString>(name: "filterString" ); |
1345 | QTest::addColumn<QStringList>(name: "filters" ); |
1346 | |
1347 | // QTBUG-47923: Do not trip over "*,v". |
1348 | QTest::newRow(dataTag: "text" ) << "plain text document (*.txt *.asc *,v *.doc)" |
1349 | << (QStringList() << "*.txt" << "*.asc" << "*,v" << "*.doc" ); |
1350 | QTest::newRow(dataTag: "html" ) << "HTML document (*.html *.htm)" |
1351 | << (QStringList() << "*.html" << "*.htm" ); |
1352 | } |
1353 | |
1354 | void tst_QFileDialog2::nameFilterParsing() |
1355 | { |
1356 | QFETCH(QString, filterString); |
1357 | QFETCH(QStringList, filters); |
1358 | QCOMPARE(QPlatformFileDialogHelper::cleanFilterList(filterString), filters); |
1359 | } |
1360 | |
1361 | QTEST_MAIN(tst_QFileDialog2) |
1362 | #include "tst_qfiledialog2.moc" |
1363 | |