6#include <private/qwidgetitemdata_p.h>
10#include <private/qapplication_p.h>
11#include <private/qguiapplication_p.h>
12#include <qfontmetrics.h>
14#include <qactiongroup.h>
15#include <qheaderview.h>
16#if QT_CONFIG(shortcut)
17# include <qshortcut.h>
19#include <qgridlayout.h>
23#if QT_CONFIG(messagebox)
24#include <qmessagebox.h>
27#if QT_CONFIG(settings)
31#if QT_CONFIG(mimetype)
32#include <qmimedatabase.h>
34#if QT_CONFIG(regularexpression)
35#include <qregularexpression.h>
37#include <qapplication.h>
38#include <qstylepainter.h>
39#include "ui_qfiledialog.h"
43#elif defined(Q_OS_WIN)
44# include <QtCore/qt_windows.h>
47#include <private/qwasmlocalfileaccess_p.h>
54using namespace Qt::StringLiterals;
56Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
177
178
179
180
181
184
185
186
187
188
189
190
191
192
193
194
195
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
257
258
259
260
261
262
263
264
267
268
269
270
271
272
273
274
277
278
279
280
281
282
283
284
287
288
289
290
291
292
293
294
297
298
299
300
301
302
303
304
307
308
309
310
311
312
313
316
317
318
319
320
321
322
323
326
327
328
329
330
333
334
335
336
337
338
341
342
343
344
346QT_BEGIN_INCLUDE_NAMESPACE
348#if QT_CONFIG(shortcut)
349# include <qshortcut.h>
351QT_END_INCLUDE_NAMESPACE
354
355
356
357
358QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags f)
359 : QDialog(*
new QFileDialogPrivate, parent, f)
362 QFileDialogArgs args;
367
368
369
370
371
372
373QFileDialog::QFileDialog(QWidget *parent,
374 const QString &caption,
375 const QString &directory,
376 const QString &filter)
377 : QDialog(*
new QFileDialogPrivate, parent, { })
380 QFileDialogArgs args(QUrl::fromLocalFile(directory));
381 args.filter = filter;
382 args.caption = caption;
387
388
389QFileDialog::QFileDialog(
const QFileDialogArgs &args)
390 : QDialog(*
new QFileDialogPrivate, args.parent, { })
394 setFileMode(args.mode);
395 setOptions(args.options);
396 selectFile(args.selection);
400
401
402QFileDialog::~QFileDialog()
405#if QT_CONFIG(settings)
408 if (QPlatformFileDialogHelper *platformHelper = d->platformFileDialogHelper()) {
411 QObjectPrivate::disconnect(platformHelper, &QPlatformFileDialogHelper::directoryEntered,
412 d, &QFileDialogPrivate::nativeEnterDirectory);
417
418
419
420
421
422
423
424
425
426
427
428
429void QFileDialog::setSidebarUrls(
const QList<QUrl> &urls)
432 if (!d->nativeDialogInUse)
433 d->qFileDialogUi->sidebar->setUrls(urls);
437
438
439QList<QUrl> QFileDialog::sidebarUrls()
const
441 Q_D(
const QFileDialog);
442 return (d->nativeDialogInUse ? QList<QUrl>() : d->qFileDialogUi->sidebar->urls());
445static const qint32 QFileDialogMagic = 0xbe;
448
449
450
451
452
453QByteArray QFileDialog::saveState()
const
455 Q_D(
const QFileDialog);
458 QDataStream stream(&data, QIODevice::WriteOnly);
459 stream.setVersion(QDataStream::Qt_5_0);
461 stream << qint32(QFileDialogMagic);
462 stream << qint32(version);
463 if (d->usingWidgets()) {
464 stream << d->qFileDialogUi->splitter->saveState();
465 stream << d->qFileDialogUi->sidebar->urls();
467 stream << d->splitterState;
468 stream << d->sidebarUrls;
471 stream << *lastVisitedDir();
472 if (d->usingWidgets())
473 stream << d->qFileDialogUi->treeView->header()->saveState();
475 stream << d->headerData;
476 stream << qint32(viewMode());
481
482
483
484
485
486
487
488bool QFileDialog::restoreState(
const QByteArray &state)
491 QByteArray sd = state;
492 QDataStream stream(&sd, QIODevice::ReadOnly);
493 stream.setVersion(QDataStream::Qt_5_0);
497 QUrl currentDirectory;
504 if (marker != QFileDialogMagic || (v != 3 && v != 4))
507 stream >> d->splitterState
511 QString currentDirectoryString;
512 stream >> currentDirectoryString;
513 currentDirectory = QUrl::fromLocalFile(currentDirectoryString);
515 stream >> currentDirectory;
517 stream >> d->headerData
520 setDirectoryUrl(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir());
521 setViewMode(
static_cast<QFileDialog::ViewMode>(viewMode));
523 if (!d->usingWidgets())
526 return d->restoreWidgetState(history, -1);
530
531
532void QFileDialog::changeEvent(QEvent *e)
535 if (e->type() == QEvent::LanguageChange) {
536 d->retranslateWindowTitle();
537 d->retranslateStrings();
539 QDialog::changeEvent(e);
542QFileDialogPrivate::QFileDialogPrivate()
544#if QT_CONFIG(proxymodel)
548 currentHistoryLocation(-1),
549 renameAction(
nullptr),
550 deleteAction(
nullptr),
551 showHiddenAction(
nullptr),
552 useDefaultCaption(
true),
553 qFileDialogUi(
nullptr),
554 options(QFileDialogOptions::create())
558QFileDialogPrivate::~QFileDialogPrivate()
562void QFileDialogPrivate::initHelper(QPlatformDialogHelper *h)
565 auto *fileDialogHelper =
static_cast<QPlatformFileDialogHelper *>(h);
566 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::fileSelected,
567 this, &QFileDialogPrivate::emitUrlSelected);
568 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::filesSelected,
569 this, &QFileDialogPrivate::emitUrlsSelected);
570 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::currentChanged,
571 this, &QFileDialogPrivate::nativeCurrentChanged);
572 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::directoryEntered,
573 this, &QFileDialogPrivate::nativeEnterDirectory);
574 QObject::connect(fileDialogHelper, &QPlatformFileDialogHelper::filterSelected,
575 q, &QFileDialog::filterSelected);
576 fileDialogHelper->setOptions(options);
579void QFileDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
582 options->setWindowTitle(q->windowTitle());
583 options->setHistory(q->history());
585 options->setSidebarUrls(qFileDialogUi->sidebar->urls());
586 if (options->initiallySelectedNameFilter().isEmpty())
587 options->setInitiallySelectedNameFilter(q->selectedNameFilter());
588 if (options->initiallySelectedFiles().isEmpty())
589 options->setInitiallySelectedFiles(userSelectedFiles());
592void QFileDialogPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
594 if (code == QDialog::Accepted) {
596 q->setViewMode(
static_cast<QFileDialog::ViewMode>(options->viewMode()));
597 q->setSidebarUrls(options->sidebarUrls());
598 q->setHistory(options->history());
602void QFileDialogPrivate::retranslateWindowTitle()
605 if (!useDefaultCaption || setWindowTitle != q->windowTitle())
607 if (q->acceptMode() == QFileDialog::AcceptOpen) {
608 const QFileDialog::FileMode fileMode = q->fileMode();
609 if (fileMode == QFileDialog::Directory)
610 q->setWindowTitle(QFileDialog::tr(
"Find Directory"));
612 q->setWindowTitle(QFileDialog::tr(
"Open"));
614 q->setWindowTitle(QFileDialog::tr(
"Save As"));
616 setWindowTitle = q->windowTitle();
619void QFileDialogPrivate::setLastVisitedDirectory(
const QUrl &dir)
621 *lastVisitedDir() = dir;
624void QFileDialogPrivate::updateLookInLabel()
626 if (options->isLabelExplicitlySet(QFileDialogOptions::LookIn))
627 setLabelTextControl(QFileDialog::LookIn, options->labelText(QFileDialogOptions::LookIn));
630void QFileDialogPrivate::updateFileNameLabel()
632 if (options->isLabelExplicitlySet(QFileDialogOptions::FileName)) {
633 setLabelTextControl(QFileDialog::FileName, options->labelText(QFileDialogOptions::FileName));
635 switch (q_func()->fileMode()) {
636 case QFileDialog::Directory:
637 setLabelTextControl(QFileDialog::FileName, QFileDialog::tr(
"Directory:"));
640 setLabelTextControl(QFileDialog::FileName, QFileDialog::tr(
"File &name:"));
646void QFileDialogPrivate::updateFileTypeLabel()
648 if (options->isLabelExplicitlySet(QFileDialogOptions::FileType))
649 setLabelTextControl(QFileDialog::FileType, options->labelText(QFileDialogOptions::FileType));
652void QFileDialogPrivate::updateOkButtonText(
bool saveAsOnFolder)
656 if (saveAsOnFolder) {
657 setLabelTextControl(QFileDialog::Accept, QFileDialog::tr(
"&Open"));
658 }
else if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) {
659 setLabelTextControl(QFileDialog::Accept, options->labelText(QFileDialogOptions::Accept));
662 switch (q->fileMode()) {
663 case QFileDialog::Directory:
664 setLabelTextControl(QFileDialog::Accept, QFileDialog::tr(
"&Choose"));
667 setLabelTextControl(QFileDialog::Accept,
668 q->acceptMode() == QFileDialog::AcceptOpen ?
669 QFileDialog::tr(
"&Open") :
670 QFileDialog::tr(
"&Save"));
676void QFileDialogPrivate::updateCancelButtonText()
678 if (options->isLabelExplicitlySet(QFileDialogOptions::Reject))
679 setLabelTextControl(QFileDialog::Reject, options->labelText(QFileDialogOptions::Reject));
682void QFileDialogPrivate::retranslateStrings()
686 if (options->useDefaultNameFilters())
687 q->setNameFilter(QFileDialogOptions::defaultNameFilterString());
691 QList<QAction*> actions = qFileDialogUi->treeView->header()->actions();
692 QAbstractItemModel *abstractModel = model;
693#if QT_CONFIG(proxymodel)
695 abstractModel = proxyModel;
697 const int total = qMin(abstractModel->columnCount(QModelIndex()),
int(actions.size() + 1));
698 for (
int i = 1; i < total; ++i) {
699 actions.at(i - 1)->setText(QFileDialog::tr(
"Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
703 renameAction->setText(QFileDialog::tr(
"&Rename"));
704 deleteAction->setText(QFileDialog::tr(
"&Delete"));
705 showHiddenAction->setText(QFileDialog::tr(
"Show &hidden files"));
706 newFolderAction->setText(QFileDialog::tr(
"&New Folder"));
707 qFileDialogUi->retranslateUi(q);
709 updateFileNameLabel();
710 updateFileTypeLabel();
711 updateCancelButtonText();
714void QFileDialogPrivate::emitFilesSelected(
const QStringList &files)
717 emit q->filesSelected(files);
718 if (files.size() == 1)
719 emit q->fileSelected(files.first());
722bool QFileDialogPrivate::canBeNativeDialog()
const
726 const QDialog *
const q =
static_cast<
const QDialog*>(q_ptr);
727 if (nativeDialogInUse)
729 if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
730 || q->testAttribute(Qt::WA_DontShowOnScreen)
731 || (options->options() & QFileDialog::DontUseNativeDialog)) {
735 return strcmp(QFileDialog::staticMetaObject.className(), q->metaObject()->className()) == 0;
738bool QFileDialogPrivate::usingWidgets()
const
740 return !nativeDialogInUse && qFileDialogUi;
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759void QFileDialog::setOption(Option option,
bool on)
761 const QFileDialog::Options previousOptions = options();
762 if (!(previousOptions & option) != !on)
763 setOptions(previousOptions ^ option);
767
768
769
770
771
772bool QFileDialog::testOption(Option option)
const
774 Q_D(
const QFileDialog);
775 return d->options->testOption(
static_cast<QFileDialogOptions::FileDialogOption>(option));
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796void QFileDialog::setOptions(Options options)
800 Options changed = (options ^ QFileDialog::options());
804 d->options->setOptions(QFileDialogOptions::FileDialogOptions(
int(options)));
806 if (options & DontUseNativeDialog) {
807 d->nativeDialogInUse =
false;
811 if (d->usingWidgets()) {
812 if (changed & DontResolveSymlinks)
813 d->model->setResolveSymlinks(!(options & DontResolveSymlinks));
814 if (changed & ReadOnly) {
815 bool ro = (options & ReadOnly);
816 d->model->setReadOnly(ro);
817 d->qFileDialogUi->newFolderButton->setEnabled(!ro);
818 d->renameAction->setEnabled(!ro);
819 d->deleteAction->setEnabled(!ro);
822 if (changed & DontUseCustomDirectoryIcons) {
823 QFileIconProvider::Options providerOptions = iconProvider()->options();
824 providerOptions.setFlag(QFileIconProvider::DontUseCustomDirectoryIcons,
825 options & DontUseCustomDirectoryIcons);
826 iconProvider()->setOptions(providerOptions);
830 if (changed & HideNameFilterDetails)
831 setNameFilters(d->options->nameFilters());
833 if (changed & ShowDirsOnly)
834 setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files);
837QFileDialog::Options QFileDialog::options()
const
839 Q_D(
const QFileDialog);
840 static_assert((
int)QFileDialog::ShowDirsOnly == (
int)QFileDialogOptions::ShowDirsOnly);
841 static_assert((
int)QFileDialog::DontResolveSymlinks == (
int)QFileDialogOptions::DontResolveSymlinks);
842 static_assert((
int)QFileDialog::DontConfirmOverwrite == (
int)QFileDialogOptions::DontConfirmOverwrite);
843 static_assert((
int)QFileDialog::DontUseNativeDialog == (
int)QFileDialogOptions::DontUseNativeDialog);
844 static_assert((
int)QFileDialog::ReadOnly == (
int)QFileDialogOptions::ReadOnly);
845 static_assert((
int)QFileDialog::HideNameFilterDetails == (
int)QFileDialogOptions::HideNameFilterDetails);
846 static_assert((
int)QFileDialog::DontUseCustomDirectoryIcons == (
int)QFileDialogOptions::DontUseCustomDirectoryIcons);
847 return QFileDialog::Options(
int(d->options->options()));
851
852
853
854
855
856
857void QFileDialog::open(QObject *receiver,
const char *member)
860 const char *signal = (fileMode() == ExistingFiles) ? SIGNAL(filesSelected(QStringList))
861 : SIGNAL(fileSelected(QString));
862 connect(
this, signal, receiver, member);
863 d->signalToDisconnectOnClose = signal;
864 d->receiverToDisconnectOnClose = receiver;
865 d->memberToDisconnectOnClose = member;
872
873
874void QFileDialog::setVisible(
bool visible)
877 QDialog::setVisible(visible);
881
882
883
884
885
886void QFileDialogPrivate::setVisible(
bool visible)
890 const auto q =
static_cast<QDialog *>(q_ptr);
892 if (canBeNativeDialog()){
893 if (setNativeDialogVisible(visible)){
896 q->setAttribute(Qt::WA_DontShowOnScreen);
897#if QT_CONFIG(fscompleter)
899 if (!nativeDialogInUse)
900 completer->setModel(
nullptr);
902 }
else if (visible) {
904 q->setAttribute(Qt::WA_DontShowOnScreen,
false);
905#if QT_CONFIG(fscompleter)
906 if (!nativeDialogInUse) {
907 if (proxyModel !=
nullptr)
908 completer->setModel(proxyModel);
910 completer->setModel(model);
916 if (visible && usingWidgets())
917 qFileDialogUi->fileNameEdit->setFocus();
919 QDialogPrivate::setVisible(visible);
923
924
925
926void QFileDialogPrivate::goToUrl(
const QUrl &url)
930 QFileSystemModelPrivate::QFileSystemNode *node = model->d_func()->node(url.toLocalFile(),
true);
931 QModelIndex idx = model->d_func()->index(node);
936
937
938
939
942
943
944
945
946
947
948
949
950
951
952
953void QFileDialog::setDirectory(
const QString &directory)
956 QString newDirectory = directory;
958 if (!directory.isEmpty())
959 newDirectory = QDir::cleanPath(directory);
961 if (!directory.isEmpty() && newDirectory.isEmpty())
964 QUrl newDirUrl = QUrl::fromLocalFile(newDirectory);
965 QFileDialogPrivate::setLastVisitedDirectory(newDirUrl);
967 d->options->setInitialDirectory(QUrl::fromLocalFile(directory));
968 if (!d->usingWidgets()) {
969 d->setDirectory_sys(newDirUrl);
972 if (d->rootPath() == newDirectory)
974 QModelIndex root = d->model->setRootPath(newDirectory);
975 if (!d->nativeDialogInUse) {
976 d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled);
977 if (root != d->rootIndex()) {
978#if QT_CONFIG(fscompleter)
979 if (directory.endsWith(u'/'))
980 d->completer->setCompletionPrefix(newDirectory);
982 d->completer->setCompletionPrefix(newDirectory + u'/');
984 d->setRootIndex(root);
986 d->qFileDialogUi->listView->selectionModel()->clear();
991
992
993QDir QFileDialog::directory()
const
995 Q_D(
const QFileDialog);
996 if (d->nativeDialogInUse) {
997 QString dir = d->directory_sys().toLocalFile();
998 return QDir(dir.isEmpty() ? d->options->initialDirectory().toLocalFile() : dir);
1000 return d->rootPath();
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020void QFileDialog::setDirectoryUrl(
const QUrl &directory)
1023 if (!directory.isValid())
1026 QFileDialogPrivate::setLastVisitedDirectory(directory);
1027 d->options->setInitialDirectory(directory);
1029 if (d->nativeDialogInUse)
1030 d->setDirectory_sys(directory);
1031 else if (directory.isLocalFile())
1032 setDirectory(directory.toLocalFile());
1033 else if (Q_UNLIKELY(d->usingWidgets()))
1034 qWarning(
"Non-native QFileDialog supports only local files");
1038
1039
1040
1041
1042QUrl QFileDialog::directoryUrl()
const
1044 Q_D(
const QFileDialog);
1045 if (d->nativeDialogInUse)
1046 return d->directory_sys();
1048 return QUrl::fromLocalFile(directory().absolutePath());
1055#if defined(Q_OS_WIN)
1059#elif defined(Q_OS_MACOS)
1060 return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE) == 1;
1070 if (!QFileInfo(path).isAbsolute())
1072 if (path.startsWith(rootPath, isCaseSensitiveFileSystem(rootPath) ? Qt::CaseSensitive : Qt::CaseInsensitive))
1073 path.remove(0, rootPath.size());
1078 if (path.at(0) == QDir::separator()
1081 || path.at(0) == u'/'
1090
1091
1092
1093
1094void QFileDialog::selectFile(
const QString &filename)
1097 if (filename.isEmpty())
1100 if (!d->usingWidgets()) {
1102 if (QFileInfo(filename).isRelative()) {
1103 url = d->options->initialDirectory();
1104 QString path = url.path();
1105 if (!path.endsWith(u'/'))
1107 url.setPath(path + filename);
1109 url = QUrl::fromLocalFile(filename);
1111 d->selectFile_sys(url);
1112 d->options->setInitiallySelectedFiles(QList<QUrl>() << url);
1116 if (!QDir::isRelativePath(filename)) {
1117 QFileInfo info(filename);
1118 QString filenamePath = info.absoluteDir().path();
1120 if (d->model->rootPath() != filenamePath)
1121 setDirectory(filenamePath);
1124 QModelIndex index = d->model->index(filename);
1125 d->qFileDialogUi->listView->selectionModel()->clear();
1126 if (!isVisible() || !d->lineEdit()->hasFocus())
1127 d->lineEdit()->setText(index.isValid() ? index.data().toString() : fileFromPath(d->rootPath(), filename));
1131
1132
1133
1134
1135
1136
1137
1138void QFileDialog::selectUrl(
const QUrl &url)
1144 if (d->nativeDialogInUse)
1145 d->selectFile_sys(url);
1146 else if (url.isLocalFile())
1147 selectFile(url.toLocalFile());
1149 qWarning(
"Non-native QFileDialog supports only local files");
1153static QString homeDirFromPasswdEntry(
const QString &path,
const QByteArray &userName)
1155#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
1158 long bufSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
1161 QVarLengthArray<
char, 1024> buf(bufSize);
1163# if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0
< 199506L
)
1164 tmpPw = getpwnam_r(userName.constData(), &pw, buf.data(), buf.size());
1166 err = getpwnam_r(userName.constData(), &pw, buf.data(), buf.size(), &tmpPw);
1170 return QFile::decodeName(pw.pw_dir);
1172 passwd *pw = getpwnam(userName.constData());
1175 return QFile::decodeName(pw->pw_dir);
1179Q_AUTOTEST_EXPORT QString qt_tildeExpansion(
const QString &path)
1181 if (!path.startsWith(u'~'))
1184 if (path.size() == 1)
1185 return QDir::homePath();
1187 QStringView sv(path);
1188 const qsizetype sepIndex = sv.indexOf(QDir::separator());
1190 return QDir::homePath() + sv.sliced(1);
1192#if defined(Q_OS_VXWORKS) || defined(Q_OS_INTEGRITY)
1194 return QDir::homePath();
1195 return QDir::homePath() + sv.sliced(sepIndex);
1197 const qsizetype userNameLen = sepIndex != -1 ? sepIndex - strlen(
"~")
1198 : path.size() - strlen(
"~");
1199 const QByteArray userName = sv.sliced(1, userNameLen).toLocal8Bit();
1200 QString homePath = homeDirFromPasswdEntry(path, userName);
1203 return homePath + sv.sliced(sepIndex);
1209
1210
1211QStringList QFileDialogPrivate::typedFiles()
const
1213 Q_Q(
const QFileDialog);
1215 QString editText = lineEdit()->text();
1216 if (!editText.contains(u'"')) {
1218 const QString prefix = q->directory().absolutePath() + QDir::separator();
1219 if (QFile::exists(prefix + editText))
1222 files << qt_tildeExpansion(editText);
1230 QStringList tokens = editText.split(u'\"');
1231 for (
int i=0; i<tokens.size(); ++i) {
1235 const QString token = tokens.at(i);
1236 const QString prefix = q->directory().absolutePath() + QDir::separator();
1237 if (QFile::exists(prefix + token))
1240 files << qt_tildeExpansion(token);
1242 files << toInternal(tokens.at(i));
1246 return addDefaultSuffixToFiles(files);
1252QList<QUrl> QFileDialogPrivate::userSelectedFiles()
const
1256 if (!usingWidgets())
1257 return addDefaultSuffixToUrls(selectedFiles_sys());
1259 const QModelIndexList selectedRows = qFileDialogUi->listView->selectionModel()->selectedRows();
1260 files.reserve(selectedRows.size());
1261 for (
const QModelIndex &index : selectedRows)
1262 files.append(QUrl::fromLocalFile(index.data(QFileSystemModel::FilePathRole).toString()));
1264 if (files.isEmpty() && !lineEdit()->text().isEmpty()) {
1265 const QStringList typedFilesList = typedFiles();
1266 files.reserve(typedFilesList.size());
1267 for (
const QString &path : typedFilesList)
1268 files.append(QUrl::fromLocalFile(path));
1274QStringList QFileDialogPrivate::addDefaultSuffixToFiles(
const QStringList &filesToFix)
const
1277 for (
int i=0; i<filesToFix.size(); ++i) {
1278 QString name = toInternal(filesToFix.at(i));
1279 QFileInfo info(name);
1281 const QString defaultSuffix = options->defaultSuffix();
1282 if (!defaultSuffix.isEmpty() && !info.isDir() && !info.fileName().contains(u'.'))
1283 name += u'.' + defaultSuffix;
1285 if (info.isAbsolute()) {
1291 QString path = rootPath();
1292 if (!path.endsWith(u'/'))
1301QList<QUrl> QFileDialogPrivate::addDefaultSuffixToUrls(
const QList<QUrl> &urlsToFix)
const
1304 urls.reserve(urlsToFix.size());
1306 const QString defaultSuffix = options->defaultSuffix();
1307 for (QUrl url : urlsToFix) {
1308 if (!defaultSuffix.isEmpty()) {
1309 const QString urlPath = url.path();
1310 const auto idx = urlPath.lastIndexOf(u'/');
1311 if (idx != (urlPath.size() - 1) && !QStringView{urlPath}.mid(idx + 1).contains(u'.'))
1312 url.setPath(urlPath + u'.' + defaultSuffix);
1321
1322
1323
1324
1325
1326
1327QStringList QFileDialog::selectedFiles()
const
1329 Q_D(
const QFileDialog);
1332 const QList<QUrl> userSelectedFiles = d->userSelectedFiles();
1333 files.reserve(userSelectedFiles.size());
1334 for (
const QUrl &file : userSelectedFiles)
1335 files.append(file.toString(QUrl::PreferLocalFile));
1337 if (files.isEmpty() && d->usingWidgets()) {
1338 const FileMode fm = fileMode();
1339 if (fm != ExistingFile && fm != ExistingFiles)
1340 files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
1346
1347
1348
1349
1350
1351
1352
1353QList<QUrl> QFileDialog::selectedUrls()
const
1355 Q_D(
const QFileDialog);
1356 if (d->nativeDialogInUse) {
1357 return d->userSelectedFiles();
1360 const QStringList selectedFileList = selectedFiles();
1361 urls.reserve(selectedFileList.size());
1362 for (
const QString &file : selectedFileList)
1363 urls.append(QUrl::fromLocalFile(file));
1369
1370
1371
1374 if (filter.isEmpty())
1375 return QStringList();
1378 if (!filter.contains(sep) && filter.contains(u'\n'))
1381 return filter.split(sep);
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399void QFileDialog::setNameFilter(
const QString &filter)
1401 setNameFilters(qt_make_filter_list(filter));
1406
1407
1410#if QT_CONFIG(regularexpression)
1411 QStringList strippedFilters;
1412 static const QRegularExpression r(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp));
1413 strippedFilters.reserve(filters.size());
1414 for (
const QString &filter : filters) {
1416 auto match = r.match(filter);
1417 if (match.hasMatch())
1418 filterName = match.captured(1);
1419 strippedFilters.append(filterName.simplified());
1421 return strippedFilters;
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445void QFileDialog::setNameFilters(
const QStringList &filters)
1448 QStringList cleanedFilters;
1449 cleanedFilters.reserve(filters.size());
1450 for (
const QString &filter : filters)
1451 cleanedFilters << filter.simplified();
1453 d->options->setNameFilters(cleanedFilters);
1455 if (!d->usingWidgets())
1458 d->qFileDialogUi->fileTypeCombo->clear();
1459 if (cleanedFilters.isEmpty())
1462 if (testOption(HideNameFilterDetails))
1463 d->qFileDialogUi->fileTypeCombo->addItems(qt_strip_filters(cleanedFilters));
1465 d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters);
1467 d->useNameFilter(0);
1471
1472
1473
1474QStringList QFileDialog::nameFilters()
const
1476 return d_func()->options->nameFilters();
1480
1481
1482
1483
1484
1485void QFileDialog::selectNameFilter(
const QString &filter)
1488 d->options->setInitiallySelectedNameFilter(filter);
1489 if (!d->usingWidgets()) {
1490 d->selectNameFilter_sys(filter);
1494 if (testOption(HideNameFilterDetails)) {
1495 const QStringList filters = qt_strip_filters(qt_make_filter_list(filter));
1496 if (!filters.isEmpty())
1497 i = d->qFileDialogUi->fileTypeCombo->findText(filters.first());
1499 i = d->qFileDialogUi->fileTypeCombo->findText(filter);
1502 d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i);
1503 d->useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex());
1508
1509
1510
1511
1512QString QFileDialog::selectedNameFilter()
const
1514 Q_D(
const QFileDialog);
1515 if (!d->usingWidgets())
1516 return d->selectedNameFilter_sys();
1518 if (testOption(HideNameFilterDetails)) {
1519 const auto idx = d->qFileDialogUi->fileTypeCombo->currentIndex();
1520 if (idx >= 0 && idx < d->options->nameFilters().size())
1521 return d->options->nameFilters().at(d->qFileDialogUi->fileTypeCombo->currentIndex());
1523 return d->qFileDialogUi->fileTypeCombo->currentText();
1527
1528
1529
1530
1531QDir::Filters QFileDialog::filter()
const
1533 Q_D(
const QFileDialog);
1534 if (d->usingWidgets())
1535 return d->model->filter();
1536 return d->options->filter();
1540
1541
1542
1543
1544
1546void QFileDialog::setFilter(QDir::Filters filters)
1549 d->options->setFilter(filters);
1550 if (!d->usingWidgets()) {
1555 d->model->setFilter(filters);
1556 d->showHiddenAction->setChecked((filters & QDir::Hidden));
1559#if QT_CONFIG(mimetype)
1561static QString nameFilterForMime(
const QString &mimeType)
1564 QMimeType mime(db.mimeTypeForName(mimeType));
1565 if (mime.isValid()) {
1566 if (mime.isDefault()) {
1567 return QFileDialog::tr(
"All files (*)");
1569 const QString patterns = mime.globPatterns().join(u' ');
1570 return mime.comment() +
" ("_L1 + patterns + u')';
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593void QFileDialog::setMimeTypeFilters(
const QStringList &filters)
1596 QStringList nameFilters;
1597 for (
const QString &mimeType : filters) {
1598 const QString text = nameFilterForMime(mimeType);
1599 if (!text.isEmpty())
1600 nameFilters.append(text);
1602 setNameFilters(nameFilters);
1603 d->options->setMimeTypeFilters(filters);
1607
1608
1609
1610
1611
1612QStringList QFileDialog::mimeTypeFilters()
const
1614 return d_func()->options->mimeTypeFilters();
1618
1619
1620
1621
1622
1623void QFileDialog::selectMimeTypeFilter(
const QString &filter)
1626 d->options->setInitiallySelectedMimeTypeFilter(filter);
1628 const QString filterForMime = nameFilterForMime(filter);
1630 if (!d->usingWidgets()) {
1631 d->selectMimeTypeFilter_sys(filter);
1632 if (d->selectedMimeTypeFilter_sys().isEmpty() && !filterForMime.isEmpty()) {
1633 selectNameFilter(filterForMime);
1635 }
else if (!filterForMime.isEmpty()) {
1636 selectNameFilter(filterForMime);
1643
1644
1645
1646QString QFileDialog::selectedMimeTypeFilter()
const
1648 Q_D(
const QFileDialog);
1649 QString mimeTypeFilter;
1650 if (!d->usingWidgets())
1651 mimeTypeFilter = d->selectedMimeTypeFilter_sys();
1653#if QT_CONFIG(mimetype)
1654 if (mimeTypeFilter.isNull() && !d->options->mimeTypeFilters().isEmpty()) {
1655 const auto nameFilter = selectedNameFilter();
1656 const auto mimeTypes = d->options->mimeTypeFilters();
1657 for (
const auto &mimeType: mimeTypes) {
1658 QString filter = nameFilterForMime(mimeType);
1659 if (testOption(HideNameFilterDetails))
1660 filter = qt_strip_filters({ filter }).constFirst();
1661 if (filter == nameFilter) {
1662 mimeTypeFilter = mimeType;
1669 return mimeTypeFilter;
1673
1674
1675
1676
1677
1678
1679
1680
1681void QFileDialog::setViewMode(QFileDialog::ViewMode mode)
1684 d->options->setViewMode(
static_cast<QFileDialogOptions::ViewMode>(mode));
1685 if (!d->usingWidgets())
1688 d->showDetailsView();
1693QFileDialog::ViewMode QFileDialog::viewMode()
const
1695 Q_D(
const QFileDialog);
1696 if (!d->usingWidgets())
1697 return static_cast<QFileDialog::ViewMode>(d->options->viewMode());
1698 return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail);
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716void QFileDialog::setFileMode(QFileDialog::FileMode mode)
1719 d->options->setFileMode(
static_cast<QFileDialogOptions::FileMode>(mode));
1720 if (!d->usingWidgets())
1723 d->retranslateWindowTitle();
1726 QAbstractItemView::SelectionMode selectionMode;
1727 if (mode == QFileDialog::ExistingFiles)
1728 selectionMode = QAbstractItemView::ExtendedSelection;
1730 selectionMode = QAbstractItemView::SingleSelection;
1731 d->qFileDialogUi->listView->setSelectionMode(selectionMode);
1732 d->qFileDialogUi->treeView->setSelectionMode(selectionMode);
1734 d->model->setFilter(d->filterForMode(filter()));
1736 if (mode == Directory) {
1737 d->qFileDialogUi->fileTypeCombo->clear();
1738 d->qFileDialogUi->fileTypeCombo->addItem(tr(
"Directories"));
1739 d->qFileDialogUi->fileTypeCombo->setEnabled(
false);
1741 d->updateFileNameLabel();
1742 d->updateOkButtonText();
1743 d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
1744 d->updateOkButton();
1747QFileDialog::FileMode QFileDialog::fileMode()
const
1749 Q_D(
const QFileDialog);
1750 return static_cast<FileMode>(d->options->fileMode());
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
1766 d->options->setAcceptMode(
static_cast<QFileDialogOptions::AcceptMode>(mode));
1768 setAttribute(Qt::WA_DontShowOnScreen,
false);
1769 if (!d->usingWidgets())
1771 QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
1772 d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel);
1773 d->qFileDialogUi->buttonBox->button(button)->setEnabled(
false);
1774 d->updateOkButton();
1775 if (mode == AcceptSave) {
1776 d->qFileDialogUi->lookInCombo->setEditable(
false);
1778 d->retranslateWindowTitle();
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1794void QFileDialog::setSupportedSchemes(
const QStringList &schemes)
1797 d->options->setSupportedSchemes(schemes);
1800QStringList QFileDialog::supportedSchemes()
const
1802 return d_func()->options->supportedSchemes();
1806
1807
1808
1809QModelIndex QFileDialogPrivate::rootIndex()
const {
1810 return mapToSource(qFileDialogUi->listView->rootIndex());
1813QAbstractItemView *QFileDialogPrivate::currentView()
const {
1814 if (!qFileDialogUi->stackedWidget)
1816 if (qFileDialogUi->stackedWidget->currentWidget() == qFileDialogUi->listView->parent())
1817 return qFileDialogUi->listView;
1818 return qFileDialogUi->treeView;
1821QLineEdit *QFileDialogPrivate::lineEdit()
const {
1822 return (QLineEdit*)qFileDialogUi->fileNameEdit;
1825long QFileDialogPrivate::maxNameLength(
const QString &path)
1827#if defined(Q_OS_UNIX)
1828 return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX);
1829#elif defined(Q_OS_WIN)
1831 const QString drive = path.left(3);
1832 if (::GetVolumeInformation(
reinterpret_cast<
const wchar_t *>(drive.utf16()), NULL, 0, NULL, &maxLength, NULL, NULL, 0) ==
false)
1842
1843
1844void QFileDialogPrivate::setRootIndex(
const QModelIndex &index)
const {
1845 Q_ASSERT(index.isValid() ? index.model() == model :
true);
1846 QModelIndex idx = mapFromSource(index);
1847 qFileDialogUi->treeView->setRootIndex(idx);
1848 qFileDialogUi->listView->setRootIndex(idx);
1851
1852
1853
1854QModelIndex QFileDialogPrivate::select(
const QModelIndex &index)
const {
1855 Q_ASSERT(index.isValid() ? index.model() == model :
true);
1857 QModelIndex idx = mapFromSource(index);
1858 if (idx.isValid() && !qFileDialogUi->listView->selectionModel()->isSelected(idx))
1859 qFileDialogUi->listView->selectionModel()->select(idx,
1860 QItemSelectionModel::Select | QItemSelectionModel::Rows);
1864QFileDialog::AcceptMode QFileDialog::acceptMode()
const
1866 Q_D(
const QFileDialog);
1867 return static_cast<AcceptMode>(d->options->acceptMode());
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881void QFileDialog::setDefaultSuffix(
const QString &suffix)
1884 d->options->setDefaultSuffix(suffix);
1887QString QFileDialog::defaultSuffix()
const
1889 Q_D(
const QFileDialog);
1890 return d->options->defaultSuffix();
1894
1895
1896
1897void QFileDialog::setHistory(
const QStringList &paths)
1900 if (d->usingWidgets())
1901 d->qFileDialogUi->lookInCombo->setHistory(paths);
1909 const QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
1911 const QUrl url = idx.isValid()
1912 ? QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString()))
1916 urlModel->setUrls(list);
1920
1921
1922QStringList QFileDialog::history()
const
1924 Q_D(
const QFileDialog);
1925 if (!d->usingWidgets())
1926 return QStringList();
1927 QStringList currentHistory = d->qFileDialogUi->lookInCombo->history();
1929 QString newHistory = QDir::toNativeSeparators(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
1930 if (!currentHistory.contains(newHistory))
1931 currentHistory << newHistory;
1932 return currentHistory;
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953void QFileDialog::setItemDelegate(QAbstractItemDelegate *delegate)
1956 if (!d->usingWidgets())
1958 d->qFileDialogUi->listView->setItemDelegate(delegate);
1959 d->qFileDialogUi->treeView->setItemDelegate(delegate);
1963
1964
1965QAbstractItemDelegate *QFileDialog::itemDelegate()
const
1967 Q_D(
const QFileDialog);
1968 if (!d->usingWidgets())
1970 return d->qFileDialogUi->listView->itemDelegate();
1974
1975
1976void QFileDialog::setIconProvider(QAbstractFileIconProvider *provider)
1979 if (!d->usingWidgets())
1981 d->model->setIconProvider(provider);
1983 d->qFileDialogUi->sidebar->setUrls(d->qFileDialogUi->sidebar->urls());
1987
1988
1989QAbstractFileIconProvider *QFileDialog::iconProvider()
const
1991 Q_D(
const QFileDialog);
1994 return d->model->iconProvider();
1997void QFileDialogPrivate::setLabelTextControl(QFileDialog::DialogLabel label,
const QString &text)
2002 case QFileDialog::LookIn:
2003 qFileDialogUi->lookInLabel->setText(text);
2005 case QFileDialog::FileName:
2006 qFileDialogUi->fileNameLabel->setText(text);
2008 case QFileDialog::FileType:
2009 qFileDialogUi->fileTypeLabel->setText(text);
2011 case QFileDialog::Accept:
2012 if (q_func()->acceptMode() == QFileDialog::AcceptOpen) {
2013 if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Open))
2014 button->setText(text);
2016 if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Save))
2017 button->setText(text);
2020 case QFileDialog::Reject:
2021 if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel))
2022 button->setText(text);
2028
2029
2031void QFileDialog::setLabelText(DialogLabel label,
const QString &text)
2034 d->options->setLabelText(
static_cast<QFileDialogOptions::DialogLabel>(label), text);
2035 d->setLabelTextControl(label, text);
2039
2040
2041QString QFileDialog::labelText(DialogLabel label)
const
2043 Q_D(
const QFileDialog);
2044 if (!d->usingWidgets())
2045 return d->options->labelText(
static_cast<QFileDialogOptions::DialogLabel>(label));
2046 QPushButton *button;
2049 return d->qFileDialogUi->lookInLabel->text();
2051 return d->qFileDialogUi->fileNameLabel->text();
2053 return d->qFileDialogUi->fileTypeLabel->text();
2055 if (acceptMode() == AcceptOpen)
2056 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
2058 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
2060 return button->text();
2063 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
2065 return button->text();
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113QString QFileDialog::getOpenFileName(QWidget *parent,
2114 const QString &caption,
2116 const QString &filter,
2117 QString *selectedFilter,
2120 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2121 const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter,
2122 selectedFilter, options, schemes);
2123 if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
2124 return selectedUrl.toLocalFile();
2126 return selectedUrl.toString();
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
2157 const QString &caption,
2159 const QString &filter,
2160 QString *selectedFilter,
2162 const QStringList &supportedSchemes)
2164 QFileDialogArgs args(dir);
2165 args.parent = parent;
2166 args.caption = caption;
2167 args.filter = filter;
2168 args.mode = ExistingFile;
2169 args.options = options;
2171 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2172 dialog->setSupportedSchemes(supportedSchemes);
2173 if (selectedFilter && !selectedFilter->isEmpty())
2174 dialog->selectNameFilter(*selectedFilter);
2175 const int execResult = dialog->exec();
2176 if (
bool(dialog) && execResult == QDialog::Accepted) {
2178 *selectedFilter = dialog->selectedNameFilter();
2179 return dialog->selectedUrls().value(0);
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223QStringList QFileDialog::getOpenFileNames(QWidget *parent,
2224 const QString &caption,
2226 const QString &filter,
2227 QString *selectedFilter,
2230 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2231 const QList<QUrl> selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir),
2232 filter, selectedFilter, options, schemes);
2233 QStringList fileNames;
2234 fileNames.reserve(selectedUrls.size());
2235 for (
const QUrl &url : selectedUrls)
2236 fileNames.append(url.toString(QUrl::PreferLocalFile));
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
2269 const QString &caption,
2271 const QString &filter,
2272 QString *selectedFilter,
2274 const QStringList &supportedSchemes)
2276 QFileDialogArgs args(dir);
2277 args.parent = parent;
2278 args.caption = caption;
2279 args.filter = filter;
2280 args.mode = ExistingFiles;
2281 args.options = options;
2283 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2284 dialog->setSupportedSchemes(supportedSchemes);
2285 if (selectedFilter && !selectedFilter->isEmpty())
2286 dialog->selectNameFilter(*selectedFilter);
2287 const int execResult = dialog->exec();
2288 if (
bool(dialog) && execResult == QDialog::Accepted) {
2290 *selectedFilter = dialog->selectedNameFilter();
2291 return dialog->selectedUrls();
2293 return QList<QUrl>();
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315void QFileDialog::getOpenFileContent(
const QString &nameFilter,
const std::function<
void(
const QString &,
const QByteArray &)> &fileOpenCompleted, QWidget *parent)
2319 auto openFileImpl = std::make_shared<std::function<
void(
void)>>();
2321 QByteArray fileContent;
2322 *openFileImpl = [=]()
mutable {
2323 auto fileDialogClosed = [&](
bool fileSelected) {
2324 if (!fileSelected) {
2325 fileOpenCompleted(fileName, fileContent);
2326 openFileImpl.reset();
2329 auto acceptFile = [&](uint64_t size,
const std::string name) ->
char * {
2330 const uint64_t twoGB = 1ULL << 31;
2334 fileName = QString::fromStdString(name);
2335 fileContent.resize(size);
2336 return fileContent.data();
2338 auto fileContentReady = [&]()
mutable {
2339 fileOpenCompleted(fileName, fileContent);
2340 openFileImpl.reset();
2343 QWasmLocalFileAccess::openFile(nameFilter.toStdString(), fileDialogClosed, acceptFile, fileContentReady);
2348 QFileDialog *dialog =
new QFileDialog(parent);
2349 dialog->setFileMode(QFileDialog::ExistingFile);
2350 dialog->setNameFilter(nameFilter);
2351 dialog->setAttribute(Qt::WA_DeleteOnClose);
2353 auto fileSelected = [=](
const QString &fileName) {
2354 QByteArray fileContent;
2355 if (!fileName.isNull()) {
2356 QFile selectedFile(fileName);
2357 if (selectedFile.open(QIODevice::ReadOnly))
2358 fileContent = selectedFile.readAll();
2360 fileOpenCompleted(fileName, fileContent);
2363 connect(dialog, &QFileDialog::fileSelected, dialog, fileSelected);
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386void QFileDialog::saveFileContent(
const QByteArray &fileContent,
const QString &fileNameHint, QWidget *parent)
2390 QWasmLocalFileAccess::saveFile(fileContent, fileNameHint.toStdString());
2392 QFileDialog *dialog =
new QFileDialog(parent);
2393 dialog->setAcceptMode(QFileDialog::AcceptSave);
2394 dialog->setFileMode(QFileDialog::AnyFile);
2395 dialog->selectFile(fileNameHint);
2397 auto fileSelected = [=](
const QString &fileName) {
2398 if (!fileName.isNull()) {
2399 QFile selectedFile(fileName);
2400 if (selectedFile.open(QIODevice::WriteOnly))
2401 selectedFile.write(fileContent);
2405 connect(dialog, &QFileDialog::fileSelected, dialog, fileSelected);
2406 dialog->setAttribute(Qt::WA_DeleteOnClose);
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455QString QFileDialog::getSaveFileName(QWidget *parent,
2456 const QString &caption,
2458 const QString &filter,
2459 QString *selectedFilter,
2462 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2463 const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter,
2464 selectedFilter, options, schemes);
2465 if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
2466 return selectedUrl.toLocalFile();
2468 return selectedUrl.toString();
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498QUrl QFileDialog::getSaveFileUrl(QWidget *parent,
2499 const QString &caption,
2501 const QString &filter,
2502 QString *selectedFilter,
2504 const QStringList &supportedSchemes)
2506 QFileDialogArgs args(dir);
2507 args.parent = parent;
2508 args.caption = caption;
2509 args.filter = filter;
2510 args.mode = AnyFile;
2511 args.options = options;
2513 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2514 dialog->setSupportedSchemes(supportedSchemes);
2515 dialog->setAcceptMode(AcceptSave);
2516 if (selectedFilter && !selectedFilter->isEmpty())
2517 dialog->selectNameFilter(*selectedFilter);
2518 const int execResult = dialog->exec();
2519 if (
bool(dialog) && execResult == QDialog::Accepted) {
2521 *selectedFilter = dialog->selectedNameFilter();
2522 return dialog->selectedUrls().value(0);
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567QString QFileDialog::getExistingDirectory(QWidget *parent,
2568 const QString &caption,
2572 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2573 const QUrl selectedUrl =
2574 getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes);
2575 if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
2576 return selectedUrl.toLocalFile();
2578 return selectedUrl.toString();
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
2609 const QString &caption,
2612 const QStringList &supportedSchemes)
2614 QFileDialogArgs args(dir);
2615 args.parent = parent;
2616 args.caption = caption;
2617 args.mode = Directory;
2618 args.options = options;
2620 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2621 dialog->setSupportedSchemes(supportedSchemes);
2622 const int execResult = dialog->exec();
2623 if (
bool(dialog) && execResult == QDialog::Accepted)
2624 return dialog->selectedUrls().value(0);
2630 if (url.isLocalFile()) {
2631 QFileInfo info = local;
2632 if (!local.isAbsolute())
2633 info = QFileInfo(QDir::current(), url.toLocalFile());
2634 const QFileInfo pathInfo(info.absolutePath());
2635 if (!pathInfo.exists() || !pathInfo.isDir())
2637 if (info.exists() && info.isDir())
2638 return QUrl::fromLocalFile(QDir::cleanPath(info.absoluteFilePath()));
2639 return QUrl::fromLocalFile(pathInfo.absoluteFilePath());
2646#if QT_CONFIG(settings)
2647 if (lastVisitedDir()->isEmpty()) {
2648 QSettings settings(QSettings::UserScope, u"QtProject"_s);
2649 const QString &lastVisisted = settings.value(
"FileDialog/lastVisited", QString()).toString();
2650 *lastVisitedDir() = QUrl::fromLocalFile(lastVisisted);
2656
2657
2661 const QFileInfo local(url.toLocalFile());
2664 directory = _qt_get_directory(url, local);
2665 if (directory.isEmpty()) {
2667 const QUrl lastVisited = *lastVisitedDir();
2668 if (lastVisited != url)
2669 directory = _qt_get_directory(lastVisited, QFileInfo());
2671 if (directory.isEmpty())
2672 directory = QUrl::fromLocalFile(QDir::currentPath());
2675
2676
2677
2678 if (selection.isEmpty() && !url.isEmpty()) {
2679 if (url.isLocalFile()) {
2681 selection = local.fileName();
2684 selection = url.fileName();
2690
2691
2692void QFileDialog::done(
int result)
2696 QDialog::done(result);
2698 if (d->receiverToDisconnectOnClose) {
2699 disconnect(
this, d->signalToDisconnectOnClose,
2700 d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
2701 d->receiverToDisconnectOnClose =
nullptr;
2703 d->memberToDisconnectOnClose.clear();
2704 d->signalToDisconnectOnClose.clear();
2707bool QFileDialogPrivate::itemAlreadyExists(
const QString &fileName)
2709#if QT_CONFIG(messagebox)
2711 const QString msg = QFileDialog::tr(
"%1 already exists.\nDo you want to replace it?").arg(fileName);
2712 using B = QMessageBox;
2713 const auto res = B::warning(q, q->windowTitle(), msg, B::Yes | B::No, B::No);
2714 return res == B::Yes;
2719void QFileDialogPrivate::itemNotFound(
const QString &fileName, QFileDialog::FileMode mode)
2721#if QT_CONFIG(messagebox)
2723 const QString message = mode == QFileDialog::Directory
2724 ? QFileDialog::tr(
"%1\nDirectory not found.\n"
2725 "Please verify the correct directory name was given.")
2726 : QFileDialog::tr(
"%1\nFile not found.\nPlease verify the "
2727 "correct file name was given.");
2729 QMessageBox::warning(q, q->windowTitle(), message.arg(fileName));
2734
2735
2736void QFileDialog::accept()
2739 if (!d->usingWidgets()) {
2740 const QList<QUrl> urls = selectedUrls();
2743 d->emitUrlsSelected(urls);
2744 if (urls.size() == 1)
2745 d->emitUrlSelected(urls.first());
2750 const QStringList files = selectedFiles();
2751 if (files.isEmpty())
2753 QString lineEditText = d->lineEdit()->text();
2756 if (lineEditText ==
".."_L1) {
2757 d->navigateToParent();
2758 const QSignalBlocker blocker(d->qFileDialogUi->fileNameEdit);
2759 d->lineEdit()->selectAll();
2763 const auto mode = fileMode();
2766 QString fn = files.first();
2769 info = QFileInfo(d->getEnvironmentVariable(fn));
2770 if (!info.exists()) {
2771 d->itemNotFound(info.fileName(), mode);
2775 d->emitFilesSelected(files);
2782 QString fn = files.first();
2785 setDirectory(info.absoluteFilePath());
2789 if (!info.exists()) {
2790 const long maxNameLength = d->maxNameLength(info.path());
2791 if (maxNameLength >= 0 && info.fileName().size() > maxNameLength)
2796 if (!info.exists() || testOption(DontConfirmOverwrite) || acceptMode() == AcceptOpen) {
2797 d->emitFilesSelected(QStringList(fn));
2800 if (d->itemAlreadyExists(info.fileName())) {
2801 d->emitFilesSelected(QStringList(fn));
2810 for (
const auto &file : files) {
2811 QFileInfo info(file);
2813 info = QFileInfo(d->getEnvironmentVariable(file));
2814 if (!info.exists()) {
2815 d->itemNotFound(info.fileName(), mode);
2819 setDirectory(info.absoluteFilePath());
2820 d->lineEdit()->clear();
2824 d->emitFilesSelected(files);
2830#if QT_CONFIG(settings)
2831void QFileDialogPrivate::saveSettings()
2834 QSettings settings(QSettings::UserScope, u"QtProject"_s);
2835 settings.beginGroup(
"FileDialog");
2837 if (usingWidgets()) {
2838 settings.setValue(
"sidebarWidth", qFileDialogUi->splitter->sizes().constFirst());
2839 settings.setValue(
"shortcuts",
2840 QUrl::toStringList(qFileDialogUi->sidebar->urls(), QUrl::FullyEncoded));
2841 settings.setValue(
"treeViewHeader", qFileDialogUi->treeView->header()->saveState());
2843 QStringList historyUrls;
2844 const QStringList history = q->history();
2845 historyUrls.reserve(history.size());
2846 for (
const QString &path : history)
2847 historyUrls << QUrl::fromLocalFile(path).toString(QUrl::FullyEncoded);
2848 settings.setValue(
"history", historyUrls);
2849 settings.setValue(
"lastVisited", lastVisitedDir()->toString(QUrl::FullyEncoded));
2850 const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator(
"ViewMode"));
2851 settings.setValue(
"viewMode", QLatin1StringView(viewModeMeta.key(q->viewMode())));
2852 settings.setValue(
"qtVersion", QT_VERSION_STR
""_L1);
2855bool QFileDialogPrivate::restoreFromSettings()
2858 QSettings settings(QSettings::UserScope, u"QtProject"_s);
2859 if (!settings.childGroups().contains(
"FileDialog"_L1))
2861 settings.beginGroup(
"FileDialog");
2863 q->setDirectoryUrl(lastVisitedDir()->isEmpty() ? settings.value(
"lastVisited").toUrl() : *lastVisitedDir());
2865 QByteArray viewModeStr = settings.value(
"viewMode").toString().toLatin1();
2866 const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator(
"ViewMode"));
2868 int viewMode = viewModeMeta.keyToValue(viewModeStr.constData(), &ok);
2870 viewMode = QFileDialog::List;
2871 q->setViewMode(
static_cast<QFileDialog::ViewMode>(viewMode));
2873 sidebarUrls = QUrl::fromStringList(settings.value(
"shortcuts").toStringList());
2874 headerData = settings.value(
"treeViewHeader").toByteArray();
2876 if (!usingWidgets())
2879 QStringList history;
2880 const auto urlStrings = settings.value(
"history").toStringList();
2881 for (
const QString &urlStr : urlStrings) {
2883 if (url.isLocalFile())
2884 history << url.toLocalFile();
2887 return restoreWidgetState(history, settings.value(
"sidebarWidth", -1).toInt());
2891bool QFileDialogPrivate::restoreWidgetState(QStringList &history,
int splitterPosition)
2894 if (splitterPosition >= 0) {
2895 QList<
int> splitterSizes;
2896 splitterSizes.append(splitterPosition);
2897 splitterSizes.append(qFileDialogUi->splitter->widget(1)->sizeHint().width());
2898 qFileDialogUi->splitter->setSizes(splitterSizes);
2900 if (!qFileDialogUi->splitter->restoreState(splitterState))
2902 QList<
int> list = qFileDialogUi->splitter->sizes();
2903 if (list.size() >= 2 && (list.at(0) == 0 || list.at(1) == 0)) {
2904 for (
int i = 0; i < list.size(); ++i)
2905 list[i] = qFileDialogUi->splitter->widget(i)->sizeHint().width();
2906 qFileDialogUi->splitter->setSizes(list);
2910 qFileDialogUi->sidebar->setUrls(sidebarUrls);
2912 static const int MaxHistorySize = 5;
2913 if (history.size() > MaxHistorySize)
2914 history.erase(history.begin(), history.end() - MaxHistorySize);
2915 q->setHistory(history);
2917 QHeaderView *headerView = qFileDialogUi->treeView->header();
2918 if (!headerView->restoreState(headerData))
2921 QList<QAction*> actions = headerView->actions();
2922 QAbstractItemModel *abstractModel = model;
2923#if QT_CONFIG(proxymodel)
2925 abstractModel = proxyModel;
2927 const int total = qMin(abstractModel->columnCount(QModelIndex()),
int(actions.size() + 1));
2928 for (
int i = 1; i < total; ++i)
2929 actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i));
2935
2936
2937
2938
2939void QFileDialogPrivate::init(
const QFileDialogArgs &args)
2942 if (!args.caption.isEmpty()) {
2943 useDefaultCaption =
false;
2944 setWindowTitle = args.caption;
2945 q->setWindowTitle(args.caption);
2948 q->setAcceptMode(QFileDialog::AcceptOpen);
2949 nativeDialogInUse = platformFileDialogHelper() !=
nullptr;
2950 if (!nativeDialogInUse)
2952 q->setFileMode(QFileDialog::AnyFile);
2953 if (!args.filter.isEmpty())
2954 q->setNameFilter(args.filter);
2955 q->setDirectoryUrl(args.directory);
2956 if (args.directory.isLocalFile())
2957 q->selectFile(args.selection);
2959 q->selectUrl(args.directory);
2961#if QT_CONFIG(settings)
2964 if (!restoreFromSettings()) {
2965 const QSettings settings(QSettings::UserScope, u"QtProject"_s);
2966 q->restoreState(settings.value(
"Qt/filedialog").toByteArray());
2970#if defined(Q_EMBEDDED_SMALLSCREEN)
2971 qFileDialogUi->lookInLabel->setVisible(
false);
2972 qFileDialogUi->fileNameLabel->setVisible(
false);
2973 qFileDialogUi->fileTypeLabel->setVisible(
false);
2974 qFileDialogUi->sidebar->hide();
2977 const QSize sizeHint = q->sizeHint();
2978 if (sizeHint.isValid())
2979 q->resize(sizeHint);
2983
2984
2985
2986
2987void QFileDialogPrivate::createWidgets()
2996 QSize preSize = q->testAttribute(Qt::WA_Resized) ? q->size() : QSize();
2997 Qt::WindowStates preState = q->windowState();
2999 model =
new QFileSystemModel(q);
3000 model->setIconProvider(&defaultIconProvider);
3001 model->setFilter(options->filter());
3002 model->setObjectName(
"qt_filesystem_model"_L1);
3003 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
3004 model->setNameFilterDisables(helper->defaultNameFilterDisables());
3006 model->setNameFilterDisables(
false);
3007 model->d_func()->disableRecursiveSort =
true;
3008 QObjectPrivate::connect(model, &QFileSystemModel::fileRenamed,
3009 this, &QFileDialogPrivate::fileRenamed);
3010 QObjectPrivate::connect(model, &QFileSystemModel::rootPathChanged,
3011 this, &QFileDialogPrivate::pathChanged);
3012 QObjectPrivate::connect(model, &QFileSystemModel::rowsInserted,
3013 this, &QFileDialogPrivate::rowsInserted);
3014 model->setReadOnly(
false);
3016 qFileDialogUi.reset(
new Ui_QFileDialog());
3017 qFileDialogUi->setupUi(q);
3019 QList<QUrl> initialBookmarks;
3020 initialBookmarks << QUrl(
"file:"_L1)
3021 << QUrl::fromLocalFile(QDir::homePath());
3022 qFileDialogUi->sidebar->setModelAndUrls(model, initialBookmarks);
3023 QObjectPrivate::connect(qFileDialogUi->sidebar, &QSidebar::goToUrl,
3024 this, &QFileDialogPrivate::goToUrl);
3026 QObject::connect(qFileDialogUi->buttonBox, &QDialogButtonBox::accepted,
3027 q, &QFileDialog::accept);
3028 QObject::connect(qFileDialogUi->buttonBox, &QDialogButtonBox::rejected,
3029 q, &QFileDialog::reject);
3031 qFileDialogUi->lookInCombo->setFileDialogPrivate(
this);
3032 QObjectPrivate::connect(qFileDialogUi->lookInCombo, &QComboBox::textActivated,
3033 this, &QFileDialogPrivate::goToDirectory);
3035 qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert);
3036 qFileDialogUi->lookInCombo->setDuplicatesEnabled(
false);
3039#ifndef QT_NO_SHORTCUT
3040 qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit);
3042#if QT_CONFIG(fscompleter)
3043 completer =
new QFSCompleter(model, q);
3044 qFileDialogUi->fileNameEdit->setCompleter(completer);
3047 qFileDialogUi->fileNameEdit->setInputMethodHints(Qt::ImhNoPredictiveText);
3049 QObjectPrivate::connect(qFileDialogUi->fileNameEdit, &QLineEdit::textChanged,
3050 this, &QFileDialogPrivate::autoCompleteFileName);
3051 QObjectPrivate::connect(qFileDialogUi->fileNameEdit, &QLineEdit::textChanged,
3052 this, &QFileDialogPrivate::updateOkButton);
3053 QObject::connect(qFileDialogUi->fileNameEdit, &QLineEdit::returnPressed,
3054 q, &QFileDialog::accept);
3057 qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(
false);
3058 qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
3059 qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
3060 QObjectPrivate::connect(qFileDialogUi->fileTypeCombo, &QComboBox::activated,
3061 this, &QFileDialogPrivate::useNameFilter);
3062 QObject::connect(qFileDialogUi->fileTypeCombo, &QComboBox::textActivated,
3063 q, &QFileDialog::filterSelected);
3065 qFileDialogUi->listView->setFileDialogPrivate(
this);
3066 qFileDialogUi->listView->setModel(model);
3067 QObjectPrivate::connect(qFileDialogUi->listView, &QAbstractItemView::activated,
3068 this, &QFileDialogPrivate::enterDirectory);
3069 QObjectPrivate::connect(qFileDialogUi->listView, &QAbstractItemView::customContextMenuRequested,
3070 this, &QFileDialogPrivate::showContextMenu);
3071#ifndef QT_NO_SHORTCUT
3072 QShortcut *shortcut =
new QShortcut(QKeySequence::Delete, qFileDialogUi->listView);
3073 QObjectPrivate::connect(shortcut, &QShortcut::activated,
3074 this, &QFileDialogPrivate::deleteCurrent);
3077 qFileDialogUi->treeView->setFileDialogPrivate(
this);
3078 qFileDialogUi->treeView->setModel(model);
3079 QHeaderView *treeHeader = qFileDialogUi->treeView->header();
3080 QFontMetrics fm(q->font());
3081 treeHeader->resizeSection(0, fm.horizontalAdvance(
"wwwwwwwwwwwwwwwwwwwwwwwwww"_L1));
3082 treeHeader->resizeSection(1, fm.horizontalAdvance(
"128.88 GB"_L1));
3083 treeHeader->resizeSection(2, fm.horizontalAdvance(
"mp3Folder"_L1));
3084 treeHeader->resizeSection(3, fm.horizontalAdvance(
"10/29/81 02:02PM"_L1));
3085 treeHeader->setContextMenuPolicy(Qt::ActionsContextMenu);
3087 QActionGroup *showActionGroup =
new QActionGroup(q);
3088 showActionGroup->setExclusive(
false);
3089 QObjectPrivate::connect(showActionGroup, &QActionGroup::triggered,
3090 this, &QFileDialogPrivate::showHeader);
3092 QAbstractItemModel *abstractModel = model;
3093#if QT_CONFIG(proxymodel)
3095 abstractModel = proxyModel;
3097 for (
int i = 1; i < abstractModel->columnCount(QModelIndex()); ++i) {
3098 QAction *showHeader =
new QAction(showActionGroup);
3099 showHeader->setCheckable(
true);
3100 showHeader->setChecked(
true);
3101 treeHeader->addAction(showHeader);
3104 QScopedPointer<QItemSelectionModel> selModel(qFileDialogUi->treeView->selectionModel());
3105 qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel());
3107 QObjectPrivate::connect(qFileDialogUi->treeView, &QAbstractItemView::activated,
3108 this, &QFileDialogPrivate::enterDirectory);
3109 QObjectPrivate::connect(qFileDialogUi->treeView, &QAbstractItemView::customContextMenuRequested,
3110 this, &QFileDialogPrivate::showContextMenu);
3111#ifndef QT_NO_SHORTCUT
3112 shortcut =
new QShortcut(QKeySequence::Delete, qFileDialogUi->treeView);
3113 QObjectPrivate::connect(shortcut, &QShortcut::activated,
3114 this, &QFileDialogPrivate::deleteCurrent);
3118 QItemSelectionModel *selections = qFileDialogUi->listView->selectionModel();
3119 QObjectPrivate::connect(selections, &QItemSelectionModel::selectionChanged,
3120 this, &QFileDialogPrivate::selectionChanged);
3121 QObjectPrivate::connect(selections, &QItemSelectionModel::currentChanged,
3122 this, &QFileDialogPrivate::currentChanged);
3123 qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding);
3125 createToolButtons();
3126 createMenuActions();
3128#if QT_CONFIG(settings)
3131 if (!restoreFromSettings()) {
3132 const QSettings settings(QSettings::UserScope, u"QtProject"_s);
3133 q->restoreState(settings.value(
"Qt/filedialog").toByteArray());
3138 q->setFileMode(
static_cast<QFileDialog::FileMode>(options->fileMode()));
3139 q->setAcceptMode(
static_cast<QFileDialog::AcceptMode>(options->acceptMode()));
3140 q->setViewMode(
static_cast<QFileDialog::ViewMode>(options->viewMode()));
3141 q->setOptions(
static_cast<QFileDialog::Options>(
static_cast<
int>(options->options())));
3142 if (!options->sidebarUrls().isEmpty())
3143 q->setSidebarUrls(options->sidebarUrls());
3144 q->setDirectoryUrl(options->initialDirectory());
3145#if QT_CONFIG(mimetype)
3146 if (!options->mimeTypeFilters().isEmpty())
3147 q->setMimeTypeFilters(options->mimeTypeFilters());
3150 if (!options->nameFilters().isEmpty())
3151 q->setNameFilters(options->nameFilters());
3152 q->selectNameFilter(options->initiallySelectedNameFilter());
3153 q->setDefaultSuffix(options->defaultSuffix());
3154 q->setHistory(options->history());
3155 const auto initiallySelectedFiles = options->initiallySelectedFiles();
3156 if (initiallySelectedFiles.size() == 1)
3157 q->selectFile(initiallySelectedFiles.first().fileName());
3158 for (
const QUrl &url : initiallySelectedFiles)
3160 lineEdit()->selectAll();
3162 retranslateStrings();
3163 q->resize(preSize.isValid() ? preSize : q->sizeHint());
3164 q->setWindowState(preState);
3167void QFileDialogPrivate::showHeader(QAction *action)
3170 QActionGroup *actionGroup = qobject_cast<QActionGroup*>(q->sender());
3171 qFileDialogUi->treeView->header()->setSectionHidden(
int(actionGroup->actions().indexOf(action) + 1),
3172 !action->isChecked());
3175#if QT_CONFIG(proxymodel)
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
3189 if (!d->usingWidgets())
3191 if ((!proxyModel && !d->proxyModel)
3192 || (proxyModel == d->proxyModel))
3195 QModelIndex idx = d->rootIndex();
3197 QObjectPrivate::disconnect(d->proxyModel, &QAbstractProxyModel::rowsInserted,
3198 d, &QFileDialogPrivate::rowsInserted);
3200 QObjectPrivate::disconnect(d->model, &QAbstractItemModel::rowsInserted,
3201 d, &QFileDialogPrivate::rowsInserted);
3203 if (proxyModel !=
nullptr) {
3204 proxyModel->setParent(
this);
3205 d->proxyModel = proxyModel;
3206 proxyModel->setSourceModel(d->model);
3207 d->qFileDialogUi->listView->setModel(d->proxyModel);
3208 d->qFileDialogUi->treeView->setModel(d->proxyModel);
3209#if QT_CONFIG(fscompleter)
3210 d->completer->setModel(d->proxyModel);
3211 d->completer->proxyModel = d->proxyModel;
3213 QObjectPrivate::connect(d->proxyModel, &QAbstractItemModel::rowsInserted,
3214 d, &QFileDialogPrivate::rowsInserted);
3216 d->proxyModel =
nullptr;
3217 d->qFileDialogUi->listView->setModel(d->model);
3218 d->qFileDialogUi->treeView->setModel(d->model);
3219#if QT_CONFIG(fscompleter)
3220 d->completer->setModel(d->model);
3221 d->completer->sourceModel = d->model;
3222 d->completer->proxyModel =
nullptr;
3224 QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted,
3225 d, &QFileDialogPrivate::rowsInserted);
3227 QScopedPointer<QItemSelectionModel> selModel(d->qFileDialogUi->treeView->selectionModel());
3228 d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel());
3230 d->setRootIndex(idx);
3233 QItemSelectionModel *selections = d->qFileDialogUi->listView->selectionModel();
3234 QObjectPrivate::connect(selections, &QItemSelectionModel::selectionChanged,
3235 d, &QFileDialogPrivate::selectionChanged);
3236 QObjectPrivate::connect(selections, &QItemSelectionModel::currentChanged,
3237 d, &QFileDialogPrivate::currentChanged);
3241
3242
3243
3244
3245QAbstractProxyModel *QFileDialog::proxyModel()
const
3247 Q_D(
const QFileDialog);
3248 return d->proxyModel;
3253
3254
3255
3256
3257void QFileDialogPrivate::createToolButtons()
3260 qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack,
nullptr, q));
3261 qFileDialogUi->backButton->setAutoRaise(
true);
3262 qFileDialogUi->backButton->setEnabled(
false);
3263 QObjectPrivate::connect(qFileDialogUi->backButton, &QPushButton::clicked,
3264 this, &QFileDialogPrivate::navigateBackward);
3266 qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward,
nullptr, q));
3267 qFileDialogUi->forwardButton->setAutoRaise(
true);
3268 qFileDialogUi->forwardButton->setEnabled(
false);
3269 QObjectPrivate::connect(qFileDialogUi->forwardButton, &QPushButton::clicked,
3270 this, &QFileDialogPrivate::navigateForward);
3272 qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent,
nullptr, q));
3273 qFileDialogUi->toParentButton->setAutoRaise(
true);
3274 qFileDialogUi->toParentButton->setEnabled(
false);
3275 QObjectPrivate::connect(qFileDialogUi->toParentButton, &QPushButton::clicked,
3276 this, &QFileDialogPrivate::navigateToParent);
3278 qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView,
nullptr, q));
3279 qFileDialogUi->listModeButton->setAutoRaise(
true);
3280 qFileDialogUi->listModeButton->setDown(
true);
3281 QObjectPrivate::connect(qFileDialogUi->listModeButton, &QPushButton::clicked,
3282 this, &QFileDialogPrivate::showListView);
3284 qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView,
nullptr, q));
3285 qFileDialogUi->detailModeButton->setAutoRaise(
true);
3286 QObjectPrivate::connect(qFileDialogUi->detailModeButton, &QPushButton::clicked,
3287 this, &QFileDialogPrivate::showDetailsView);
3289 QSize toolSize(qFileDialogUi->fileNameEdit->sizeHint().height(), qFileDialogUi->fileNameEdit->sizeHint().height());
3290 qFileDialogUi->backButton->setFixedSize(toolSize);
3291 qFileDialogUi->listModeButton->setFixedSize(toolSize);
3292 qFileDialogUi->detailModeButton->setFixedSize(toolSize);
3293 qFileDialogUi->forwardButton->setFixedSize(toolSize);
3294 qFileDialogUi->toParentButton->setFixedSize(toolSize);
3296 qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder,
nullptr, q));
3297 qFileDialogUi->newFolderButton->setFixedSize(toolSize);
3298 qFileDialogUi->newFolderButton->setAutoRaise(
true);
3299 qFileDialogUi->newFolderButton->setEnabled(
false);
3300 QObjectPrivate::connect(qFileDialogUi->newFolderButton, &QPushButton::clicked,
3301 this, &QFileDialogPrivate::createDirectory);
3305
3306
3307
3308
3309void QFileDialogPrivate::createMenuActions()
3313 QAction *goHomeAction =
new QAction(q);
3314#ifndef QT_NO_SHORTCUT
3315 goHomeAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_H);
3317 QObjectPrivate::connect(goHomeAction, &QAction::triggered,
3318 this, &QFileDialogPrivate::goHome);
3319 q->addAction(goHomeAction);
3323 QAction *goToParent =
new QAction(q);
3324 goToParent->setObjectName(
"qt_goto_parent_action"_L1);
3325#ifndef QT_NO_SHORTCUT
3326 goToParent->setShortcut(Qt::CTRL | Qt::Key_Up);
3328 QObjectPrivate::connect(goToParent, &QAction::triggered,
3329 this, &QFileDialogPrivate::navigateToParent);
3330 q->addAction(goToParent);
3332 renameAction =
new QAction(q);
3333 renameAction->setEnabled(
false);
3334 renameAction->setObjectName(
"qt_rename_action"_L1);
3335 QObjectPrivate::connect(renameAction, &QAction::triggered,
3336 this, &QFileDialogPrivate::renameCurrent);
3338 deleteAction =
new QAction(q);
3339 deleteAction->setEnabled(
false);
3340 deleteAction->setObjectName(
"qt_delete_action"_L1);
3341 QObjectPrivate::connect(deleteAction, &QAction::triggered,
3342 this, &QFileDialogPrivate::deleteCurrent);
3344 showHiddenAction =
new QAction(q);
3345 showHiddenAction->setObjectName(
"qt_show_hidden_action"_L1);
3346 showHiddenAction->setCheckable(
true);
3347 QObjectPrivate::connect(showHiddenAction, &QAction::triggered,
3348 this, &QFileDialogPrivate::showHidden);
3350 newFolderAction =
new QAction(q);
3351 newFolderAction->setObjectName(
"qt_new_folder_action"_L1);
3352 QObjectPrivate::connect(newFolderAction, &QAction::triggered,
3353 this, &QFileDialogPrivate::createDirectory);
3356void QFileDialogPrivate::goHome()
3359 q->setDirectory(QDir::homePath());
3363void QFileDialogPrivate::saveHistorySelection()
3365 if (qFileDialogUi.isNull() || currentHistoryLocation < 0 || currentHistoryLocation >= currentHistory.size())
3367 auto &item = currentHistory[currentHistoryLocation];
3368 item.selection.clear();
3369 const auto selectedIndexes = qFileDialogUi->listView->selectionModel()->selectedRows();
3370 for (
const auto &index : selectedIndexes)
3371 item.selection.append(QPersistentModelIndex(index));
3375
3376
3377
3378
3379void QFileDialogPrivate::pathChanged(
const QString &newPath)
3382 qFileDialogUi->toParentButton->setEnabled(QFileInfo::exists(model->rootPath()));
3383 qFileDialogUi->sidebar->selectUrl(QUrl::fromLocalFile(newPath));
3384 q->setHistory(qFileDialogUi->lookInCombo->history());
3386 const QString newNativePath = QDir::toNativeSeparators(newPath);
3389 if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation).path != newNativePath) {
3390 if (currentHistoryLocation >= 0)
3391 saveHistorySelection();
3392 while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.size()) {
3393 currentHistory.removeLast();
3395 currentHistory.append({newNativePath, PersistentModelIndexList()});
3396 ++currentHistoryLocation;
3398 qFileDialogUi->forwardButton->setEnabled(currentHistory.size() - currentHistoryLocation > 1);
3399 qFileDialogUi->backButton->setEnabled(currentHistoryLocation > 0);
3402void QFileDialogPrivate::navigate(HistoryItem &historyItem)
3405 q->setDirectory(historyItem.path);
3407 if (qFileDialogUi.isNull() || historyItem.selection.isEmpty())
3409 if (std::any_of(historyItem.selection.cbegin(), historyItem.selection.cend(),
3410 [](
const QPersistentModelIndex &i) {
return !i.isValid(); })) {
3411 historyItem.selection.clear();
3415 QAbstractItemView *view = q->viewMode() == QFileDialog::List
3416 ?
static_cast<QAbstractItemView *>(qFileDialogUi->listView)
3417 :
static_cast<QAbstractItemView *>(qFileDialogUi->treeView);
3418 auto selectionModel = view->selectionModel();
3419 const QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Select
3420 | QItemSelectionModel::Rows;
3421 selectionModel->select(historyItem.selection.constFirst(),
3422 flags | QItemSelectionModel::Clear | QItemSelectionModel::Current);
3423 auto it = historyItem.selection.cbegin() + 1;
3424 const auto end = historyItem.selection.cend();
3425 for (; it != end; ++it)
3426 selectionModel->select(*it, flags);
3428 view->scrollTo(historyItem.selection.constFirst());
3432
3433
3434
3435
3436void QFileDialogPrivate::navigateBackward()
3438 if (!currentHistory.isEmpty() && currentHistoryLocation > 0) {
3439 saveHistorySelection();
3440 navigate(currentHistory[--currentHistoryLocation]);
3445
3446
3447
3448
3449void QFileDialogPrivate::navigateForward()
3451 if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) {
3452 saveHistorySelection();
3453 navigate(currentHistory[++currentHistoryLocation]);
3458
3459
3460
3461
3462
3463void QFileDialogPrivate::navigateToParent()
3466 QDir dir(model->rootDirectory());
3467 QString newDirectory;
3469 newDirectory = model->myComputer().toString();
3472 newDirectory = dir.absolutePath();
3474 q->setDirectory(newDirectory);
3475 emit q->directoryEntered(newDirectory);
3479
3480
3481
3482
3483void QFileDialogPrivate::createDirectory()
3486 qFileDialogUi->listView->clearSelection();
3488 QString newFolderString = QFileDialog::tr(
"New Folder");
3489 QString folderName = newFolderString;
3490 QString prefix = q->directory().absolutePath() + QDir::separator();
3491 if (QFile::exists(prefix + folderName)) {
3492 qlonglong suffix = 2;
3493 while (QFile::exists(prefix + folderName)) {
3494 folderName = newFolderString + QString::number(suffix++);
3498 QModelIndex parent = rootIndex();
3499 QModelIndex index = model->mkdir(parent, folderName);
3500 if (!index.isValid())
3503 index = select(index);
3504 if (index.isValid()) {
3505 qFileDialogUi->treeView->setCurrentIndex(index);
3506 currentView()->edit(index);
3510void QFileDialogPrivate::showListView()
3512 qFileDialogUi->listModeButton->setDown(
true);
3513 qFileDialogUi->detailModeButton->setDown(
false);
3514 qFileDialogUi->treeView->hide();
3515 qFileDialogUi->listView->show();
3516 qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->listView->parentWidget());
3517 qFileDialogUi->listView->doItemsLayout();
3520void QFileDialogPrivate::showDetailsView()
3522 qFileDialogUi->listModeButton->setDown(
false);
3523 qFileDialogUi->detailModeButton->setDown(
true);
3524 qFileDialogUi->listView->hide();
3525 qFileDialogUi->treeView->show();
3526 qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->treeView->parentWidget());
3527 qFileDialogUi->treeView->doItemsLayout();
3531
3532
3533
3534
3535void QFileDialogPrivate::showContextMenu(
const QPoint &position)
3541 QAbstractItemView *view =
nullptr;
3542 if (q->viewMode() == QFileDialog::Detail)
3543 view = qFileDialogUi->treeView;
3545 view = qFileDialogUi->listView;
3546 QModelIndex index = view->indexAt(position);
3547 index = mapToSource(index.sibling(index.row(), 0));
3549 QMenu *menu =
new QMenu(view);
3550 menu->setAttribute(Qt::WA_DeleteOnClose);
3552 if (index.isValid()) {
3554 const bool ro = model && model->isReadOnly();
3555 QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
3556 renameAction->setEnabled(!ro && p & QFile::WriteUser);
3557 menu->addAction(renameAction);
3558 deleteAction->setEnabled(!ro && p & QFile::WriteUser);
3559 menu->addAction(deleteAction);
3560 menu->addSeparator();
3562 menu->addAction(showHiddenAction);
3563 if (qFileDialogUi->newFolderButton->isVisible()) {
3564 newFolderAction->setEnabled(qFileDialogUi->newFolderButton->isEnabled());
3565 menu->addAction(newFolderAction);
3567 menu->popup(view->viewport()->mapToGlobal(position));
3573
3574
3575void QFileDialogPrivate::renameCurrent()
3578 QModelIndex index = qFileDialogUi->listView->currentIndex();
3579 index = index.sibling(index.row(), 0);
3580 if (q->viewMode() == QFileDialog::List)
3581 qFileDialogUi->listView->edit(index);
3583 qFileDialogUi->treeView->edit(index);
3586bool QFileDialogPrivate::removeDirectory(
const QString &path)
3588 QModelIndex modelIndex = model->index(path);
3589 return model->remove(modelIndex);
3593
3594
3595
3596
3597void QFileDialogPrivate::deleteCurrent()
3599 if (model->isReadOnly())
3602 const QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
3603 for (
auto it = list.crbegin(), end = list.crend(); it != end; ++it) {
3604 QPersistentModelIndex index = *it;
3605 if (index == qFileDialogUi->listView->rootIndex())
3608 index = mapToSource(index.sibling(index.row(), 0));
3609 if (!index.isValid())
3612 QString fileName = index.data(QFileSystemModel::FileNameRole).toString();
3613 QString filePath = index.data(QFileSystemModel::FilePathRole).toString();
3615 QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
3616#if QT_CONFIG(messagebox)
3618 if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), QFileDialog::tr(
"Delete"),
3619 QFileDialog::tr(
"'%1' is write protected.\nDo you want to delete it anyway?")
3621 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No))
3623 else if (QMessageBox::warning(q_func(), QFileDialog::tr(
"Delete"),
3624 QFileDialog::tr(
"Are you sure you want to delete '%1'?")
3626 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
3630 if (!index.isValid())
3634 if (!(p & QFile::WriteUser))
3638 if (model->isDir(index) && !model->fileInfo(index).isSymLink()) {
3639 if (!removeDirectory(filePath)) {
3640#if QT_CONFIG(messagebox)
3641 QMessageBox::warning(q, q->windowTitle(),
3642 QFileDialog::tr(
"Could not delete directory."));
3646 model->remove(index);
3651void QFileDialogPrivate::autoCompleteFileName(
const QString &text)
3653 if (text.startsWith(
"//"_L1) || text.startsWith(u'\\')) {
3654 qFileDialogUi->listView->selectionModel()->clearSelection();
3658 const QStringList multipleFiles = typedFiles();
3659 if (multipleFiles.size() > 0) {
3660 QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows();
3661 QList<QModelIndex> newFiles;
3662 for (
const auto &file : multipleFiles) {
3663 QModelIndex idx = model->index(file);
3664 if (oldFiles.removeAll(idx) == 0)
3665 newFiles.append(idx);
3667 for (
const auto &newFile : std::as_const(newFiles))
3669 if (lineEdit()->hasFocus()) {
3670 auto *sm = qFileDialogUi->listView->selectionModel();
3671 for (
const auto &oldFile : std::as_const(oldFiles))
3672 sm->select(oldFile, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
3678
3679
3680void QFileDialogPrivate::updateOkButton()
3683 QPushButton *button = qFileDialogUi->buttonBox->button((q->acceptMode() == QFileDialog::AcceptOpen)
3684 ? QDialogButtonBox::Open : QDialogButtonBox::Save);
3687 const QFileDialog::FileMode fileMode = q->fileMode();
3689 bool enableButton =
true;
3690 bool isOpenDirectory =
false;
3692 const QStringList files = q->selectedFiles();
3693 QString lineEditText = lineEdit()->text();
3695 if (lineEditText.startsWith(
"//"_L1) || lineEditText.startsWith(u'\\')) {
3696 button->setEnabled(
true);
3697 updateOkButtonText();
3701 if (files.isEmpty()) {
3702 enableButton =
false;
3703 }
else if (lineEditText ==
".."_L1) {
3704 isOpenDirectory =
true;
3707 case QFileDialog::Directory: {
3708 QString fn = files.first();
3709 QModelIndex idx = model->index(fn);
3711 idx = model->index(getEnvironmentVariable(fn));
3712 if (!idx.isValid() || !model->isDir(idx))
3713 enableButton =
false;
3716 case QFileDialog::AnyFile: {
3717 QString fn = files.first();
3719 QModelIndex idx = model->index(fn);
3723 fileDir = info.canonicalFilePath();
3725 fileDir = fn.mid(0, fn.lastIndexOf(u'/'));
3726 fileName = fn.mid(fileDir.size() + 1);
3728 if (lineEditText.contains(
".."_L1)) {
3729 fileDir = info.canonicalFilePath();
3730 fileName = info.fileName();
3733 if (fileDir == q->directory().canonicalPath() && fileName.isEmpty()) {
3734 enableButton =
false;
3737 if (idx.isValid() && model->isDir(idx)) {
3738 isOpenDirectory =
true;
3739 enableButton =
true;
3742 if (!idx.isValid()) {
3743 const long maxLength = maxNameLength(fileDir);
3744 enableButton = maxLength < 0 || fileName.size() <= maxLength;
3748 case QFileDialog::ExistingFile:
3749 case QFileDialog::ExistingFiles:
3750 for (
const auto &file : files) {
3751 QModelIndex idx = model->index(file);
3753 idx = model->index(getEnvironmentVariable(file));
3754 if (!idx.isValid()) {
3755 enableButton =
false;
3758 if (idx.isValid() && model->isDir(idx)) {
3759 isOpenDirectory =
true;
3769 button->setEnabled(enableButton);
3770 updateOkButtonText(isOpenDirectory);
3774
3775
3776void QFileDialogPrivate::currentChanged(
const QModelIndex &index)
3779 emit q_func()->currentChanged(index.data(QFileSystemModel::FilePathRole).toString());
3783
3784
3785
3786
3787
3788void QFileDialogPrivate::enterDirectory(
const QModelIndex &index)
3792 QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index;
3793 QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString();
3794 if (path.isEmpty() || model->isDir(sourceIndex)) {
3795 if (q->directory().path() == path)
3798 const QFileDialog::FileMode fileMode = q->fileMode();
3799 q->setDirectory(path);
3800 emit q->directoryEntered(path);
3801 if (fileMode == QFileDialog::Directory) {
3803 lineEdit()->setText(QString());
3804 lineEdit()->clear();
3808 if ((!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick,
nullptr, qFileDialogUi->treeView)
3809 || q->fileMode() != QFileDialog::ExistingFiles || !(QGuiApplication::keyboardModifiers() & Qt::CTRL))
3810 && index.model()->flags(index) & Qt::ItemIsEnabled) {
3817
3818
3819
3820
3821
3822void QFileDialogPrivate::goToDirectory(
const QString &path)
3824 enum { UrlRole = Qt::UserRole + 1 };
3826 #if QT_CONFIG(messagebox)
3829 QModelIndex index = qFileDialogUi->lookInCombo->model()->index(qFileDialogUi->lookInCombo->currentIndex(),
3830 qFileDialogUi->lookInCombo->modelColumn(),
3831 qFileDialogUi->lookInCombo->rootModelIndex());
3832 QString path2 = path;
3833 if (!index.isValid())
3834 index = mapFromSource(model->index(getEnvironmentVariable(path)));
3836 path2 = index.data(UrlRole).toUrl().toLocalFile();
3837 index = mapFromSource(model->index(path2));
3841 dir.setPath(getEnvironmentVariable(path2));
3843 if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) {
3844 enterDirectory(index);
3845#if QT_CONFIG(messagebox)
3847 QString message = QFileDialog::tr(
"%1\nDirectory not found.\nPlease verify the "
3848 "correct directory name was given.");
3849 QMessageBox::warning(q, q->windowTitle(), message.arg(path2));
3855
3856
3857
3858
3859
3860void QFileDialogPrivate::useNameFilter(
int index)
3862 QStringList nameFilters = options->nameFilters();
3863 if (index == nameFilters.size()) {
3864 QAbstractItemModel *comboModel = qFileDialogUi->fileTypeCombo->model();
3865 nameFilters.append(comboModel->index(comboModel->rowCount() - 1, 0).data().toString());
3866 options->setNameFilters(nameFilters);
3869 QString nameFilter = nameFilters.at(index);
3870 QStringList newNameFilters = QPlatformFileDialogHelper::cleanFilterList(nameFilter);
3871 if (q_func()->acceptMode() == QFileDialog::AcceptSave) {
3872 QString newNameFilterExtension;
3873 if (newNameFilters.size() > 0)
3874 newNameFilterExtension = QFileInfo(newNameFilters.at(0)).suffix();
3876 QString fileName = lineEdit()->text();
3877 const QString fileNameExtension = QFileInfo(fileName).suffix();
3878 if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) {
3879 const qsizetype fileNameExtensionLength = fileNameExtension.size();
3880 fileName.replace(fileName.size() - fileNameExtensionLength,
3881 fileNameExtensionLength, newNameFilterExtension);
3882 qFileDialogUi->listView->clearSelection();
3883 lineEdit()->setText(fileName);
3887 model->setNameFilters(newNameFilters);
3891
3892
3893
3894
3895
3896void QFileDialogPrivate::selectionChanged()
3898 const QFileDialog::FileMode fileMode = q_func()->fileMode();
3899 const QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
3900 bool stripDirs = fileMode != QFileDialog::Directory;
3902 QStringList allFiles;
3903 for (
const auto &index : indexes) {
3904 if (stripDirs && model->isDir(mapToSource(index)))
3906 allFiles.append(index.data().toString());
3908 if (allFiles.size() > 1)
3909 for (qsizetype i = 0; i < allFiles.size(); ++i) {
3910 allFiles.replace(i, QString(u'"' + allFiles.at(i) + u'"'));
3913 QString finalFiles = allFiles.join(u' ');
3914 if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible())
3915 lineEdit()->setText(finalFiles);
3921
3922
3923
3924
3925void QFileDialogPrivate::showHidden()
3928 QDir::Filters dirFilters = q->filter();
3929 dirFilters.setFlag(QDir::Hidden, showHiddenAction->isChecked());
3930 q->setFilter(dirFilters);
3934
3935
3936
3937
3938
3939void QFileDialogPrivate::rowsInserted(
const QModelIndex &parent)
3941 if (!qFileDialogUi->treeView
3942 || parent != qFileDialogUi->treeView->rootIndex()
3943 || !qFileDialogUi->treeView->selectionModel()
3944 || qFileDialogUi->treeView->selectionModel()->hasSelection()
3945 || qFileDialogUi->treeView->model()->rowCount(parent) == 0)
3949void QFileDialogPrivate::fileRenamed(
const QString &path,
const QString &oldName,
const QString &newName)
3951 const QFileDialog::FileMode fileMode = q_func()->fileMode();
3952 if (fileMode == QFileDialog::Directory) {
3953 if (path == rootPath() && lineEdit()->text() == oldName)
3954 lineEdit()->setText(newName);
3958void QFileDialogPrivate::emitUrlSelected(
const QUrl &file)
3961 emit q->urlSelected(file);
3962 if (file.isLocalFile())
3963 emit q->fileSelected(file.toLocalFile());
3966void QFileDialogPrivate::emitUrlsSelected(
const QList<QUrl> &files)
3969 emit q->urlsSelected(files);
3970 QStringList localFiles;
3971 for (
const QUrl &file : files)
3972 if (file.isLocalFile())
3973 localFiles.append(file.toLocalFile());
3974 if (!localFiles.isEmpty())
3975 emit q->filesSelected(localFiles);
3978void QFileDialogPrivate::nativeCurrentChanged(
const QUrl &file)
3981 emit q->currentUrlChanged(file);
3982 if (file.isLocalFile())
3983 emit q->currentChanged(file.toLocalFile());
3986void QFileDialogPrivate::nativeEnterDirectory(
const QUrl &directory)
3989 emit q->directoryUrlEntered(directory);
3990 if (!directory.isEmpty()) {
3991 *lastVisitedDir() = directory;
3992 if (directory.isLocalFile())
3993 emit q->directoryEntered(directory.toLocalFile());
3998
3999
4000
4001
4002
4003
4004bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
4006#if QT_CONFIG(shortcut)
4008 if (event->matches(QKeySequence::Cancel)) {
4013 switch (event->key()) {
4014 case Qt::Key_Backspace:
4019 if (event->key() == Qt::Key_Back || event->modifiers() == Qt::AltModifier) {
4030QString QFileDialogPrivate::getEnvironmentVariable(
const QString &string)
4033 if (string.size() > 1 && string.startsWith(u'$')) {
4034 return qEnvironmentVariable(QStringView{string}.mid(1).toLatin1().constData());
4037 if (string.size() > 2 && string.startsWith(u'%') && string.endsWith(u'%')) {
4038 return qEnvironmentVariable(QStringView{string}.mid(1, string.size() - 2).toLatin1().constData());
4046 urlModel =
new QUrlModel(
this);
4047 urlModel->showFullPath =
true;
4048 urlModel->setFileSystemModel(d_ptr->model);
4054 if (model()->rowCount() > 1)
4055 QComboBox::showPopup();
4057 urlModel->setUrls(QList<QUrl>());
4059 QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
4060 while (idx.isValid()) {
4061 QUrl url = QUrl::fromLocalFile(idx.data(QFileSystemModel::FilePathRole).toString());
4067 list.append(QUrl(
"file:"_L1));
4068 urlModel->addUrls(list, 0);
4069 idx = model()->index(model()->rowCount() - 1, 0);
4073 for (
int i = 0; i < m_history.size(); ++i) {
4074 QUrl path = QUrl::fromLocalFile(m_history.at(i));
4075 if (!urls.contains(path))
4078 if (urls.size() > 0) {
4079 model()->insertRow(model()->rowCount());
4080 idx = model()->index(model()->rowCount()-1, 0);
4082 model()->setData(idx, QFileDialog::tr(
"Recent Places"));
4083 QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model());
4085 Qt::ItemFlags flags = m->flags(idx);
4086 flags &= ~Qt::ItemIsEnabled;
4087 m->item(idx.row(), idx.column())->setFlags(flags);
4089 urlModel->addUrls(urls, -1,
false);
4093 QComboBox::showPopup();
4099 QStylePainter painter(
this);
4100 painter.setPen(palette().color(QPalette::Text));
4103 QStyleOptionComboBox opt;
4104 initStyleOption(&opt);
4106 QRect editRect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
4107 QStyle::SC_ComboBoxEditField,
this);
4108 int size = editRect.width() - opt.iconSize.width() - 4;
4109 opt.currentText = opt.fontMetrics.elidedText(opt.currentText, Qt::ElideMiddle, size);
4110 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
4113 painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
4119 setSelectionBehavior(QAbstractItemView::SelectRows);
4121 setResizeMode(QListView::Adjust);
4122 setEditTriggers(QAbstractItemView::EditKeyPressed);
4123 setContextMenuPolicy(Qt::CustomContextMenu);
4124#if QT_CONFIG(draganddrop)
4125 setDragDropMode(QAbstractItemView::InternalMove);
4131 int height = qMax(10, sizeHintForRow(0));
4132 return QSize(QListView::sizeHint().width() * 2, height * 30);
4137 if (!d_ptr->itemViewKeyboardEvent(e))
4138 QListView::keyPressEvent(e);
4145 setSelectionBehavior(QAbstractItemView::SelectRows);
4146 setRootIsDecorated(
false);
4147 setItemsExpandable(
false);
4148 setSortingEnabled(
true);
4149 header()->setSortIndicator(0, Qt::AscendingOrder);
4150 header()->setStretchLastSection(
false);
4151 setTextElideMode(Qt::ElideMiddle);
4152 setEditTriggers(QAbstractItemView::EditKeyPressed);
4153 setContextMenuPolicy(Qt::CustomContextMenu);
4154#if QT_CONFIG(draganddrop)
4155 setDragDropMode(QAbstractItemView::InternalMove);
4161 if (!d_ptr->itemViewKeyboardEvent(e))
4162 QTreeView::keyPressEvent(e);
4168 int height = qMax(10, sizeHintForRow(0));
4169 QSize sizeHint = header()->sizeHint();
4170 return QSize(sizeHint.width() * 4, height * 30);
4174
4175
4176
4177
4180
4181
4182
4185#if QT_CONFIG(shortcut)
4188 QLineEdit::keyPressEvent(e);
4189#if QT_CONFIG(shortcut)
4190 if (!e->matches(QKeySequence::Cancel) && key != Qt::Key_Back)
4195#if QT_CONFIG(fscompleter)
4197QString QFSCompleter::pathFromIndex(
const QModelIndex &index)
const
4199 const QFileSystemModel *dirModel;
4201 dirModel = qobject_cast<
const QFileSystemModel *>(proxyModel->sourceModel());
4203 dirModel = sourceModel;
4204 QString currentLocation = dirModel->rootPath();
4205 QString path = index.data(QFileSystemModel::FilePathRole).toString();
4206 if (!currentLocation.isEmpty() && path.startsWith(currentLocation)) {
4207#if defined(Q_OS_UNIX)
4208 if (currentLocation == QDir::separator())
4209 return path.remove(0, currentLocation.size());
4211 if (currentLocation.endsWith(u'/'))
4212 return path.remove(0, currentLocation.size());
4214 return path.remove(0, currentLocation.size()+1);
4216 return index.data(QFileSystemModel::FilePathRole).toString();
4219QStringList QFSCompleter::splitPath(
const QString &path)
const
4222 return QStringList(completionPrefix());
4224 QString pathCopy = QDir::toNativeSeparators(path);
4225 QChar sep = QDir::separator();
4226#if defined(Q_OS_WIN)
4227 if (pathCopy ==
"\\"_L1 || pathCopy ==
"\\\\"_L1)
4228 return QStringList(pathCopy);
4229 QString doubleSlash(
"\\\\"_L1);
4230 if (pathCopy.startsWith(doubleSlash))
4231 pathCopy = pathCopy.mid(2);
4233 doubleSlash.clear();
4234#elif defined(Q_OS_UNIX)
4236 QString tildeExpanded = qt_tildeExpansion(pathCopy);
4237 if (tildeExpanded != pathCopy) {
4238 QFileSystemModel *dirModel;
4240 dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel());
4242 dirModel = sourceModel;
4243 dirModel->fetchMore(dirModel->index(tildeExpanded));
4245 pathCopy = std::move(tildeExpanded);
4249#if defined(Q_OS_WIN)
4250 QStringList parts = pathCopy.split(sep, Qt::SkipEmptyParts);
4251 if (!doubleSlash.isEmpty() && !parts.isEmpty())
4252 parts[0].prepend(doubleSlash);
4253 if (pathCopy.endsWith(sep))
4254 parts.append(QString());
4256 QStringList parts = pathCopy.split(sep);
4257 if (pathCopy[0] == sep)
4261#if defined(Q_OS_WIN)
4262 bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(u':');
4264 bool startsFromRoot = pathCopy[0] == sep;
4266 if (parts.size() == 1 || (parts.size() > 1 && !startsFromRoot)) {
4267 const QFileSystemModel *dirModel;
4269 dirModel = qobject_cast<
const QFileSystemModel *>(proxyModel->sourceModel());
4271 dirModel = sourceModel;
4272 QString currentLocation = QDir::toNativeSeparators(dirModel->rootPath());
4273#if defined(Q_OS_WIN)
4274 if (currentLocation.endsWith(u':'))
4275 currentLocation.append(sep);
4277 if (currentLocation.contains(sep) && path != currentLocation) {
4278 QStringList currentLocationList = splitPath(currentLocation);
4279 while (!currentLocationList.isEmpty() && parts.size() > 0 && parts.at(0) ==
".."_L1) {
4280 parts.removeFirst();
4281 currentLocationList.removeLast();
4283 if (!currentLocationList.isEmpty() && currentLocationList.constLast().isEmpty())
4284 currentLocationList.removeLast();
4285 return currentLocationList + parts;
4296#include "moc_qfiledialog.cpp"
void setHistory(const QStringList &paths)
void setFileDialogPrivate(QFileDialogPrivate *d_pointer)
void showPopup() override
Displays the list of items in the combobox.
void setFileDialogPrivate(QFileDialogPrivate *d_pointer)
QSize sizeHint() const override
QSize sizeHint() const override
void setFileDialogPrivate(QFileDialogPrivate *d_pointer)
static QUrl _qt_get_directory(const QUrl &url, const QFileInfo &local)
static void _qt_init_lastVisited()
QStringList qt_strip_filters(const QStringList &filters)
QStringList qt_make_filter_list(const QString &filter)
static QString fileFromPath(const QString &rootPath, QString path)
static bool isCaseSensitiveFileSystem(const QString &path)
QFileDialogArgs(const QUrl &url={})