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>
55using namespace Qt::StringLiterals;
57Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
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
175
178
179
180
181
182
185
186
187
188
189
190
191
192
193
194
195
196
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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
255
258
259
260
261
262
263
264
265
268
269
270
271
272
273
274
275
278
279
280
281
282
283
284
285
288
289
290
291
292
293
294
295
298
299
300
301
302
303
304
305
308
309
310
311
312
313
314
317
318
319
320
321
322
323
324
327
328
329
330
331
334
335
336
337
338
339
342
343
344
345
347QT_BEGIN_INCLUDE_NAMESPACE
349#if QT_CONFIG(shortcut)
350# include <qshortcut.h>
352QT_END_INCLUDE_NAMESPACE
355
356
357
358
359QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags f)
360 : QDialog(*
new QFileDialogPrivate, parent, f)
363 QFileDialogArgs args;
368
369
370
371
372
373
374QFileDialog::QFileDialog(QWidget *parent,
375 const QString &caption,
376 const QString &directory,
377 const QString &filter)
378 : QDialog(*
new QFileDialogPrivate, parent, { })
381 QFileDialogArgs args(QUrl::fromLocalFile(directory));
382 args.filter = filter;
383 args.caption = caption;
388
389
390QFileDialog::QFileDialog(
const QFileDialogArgs &args)
391 : QDialog(*
new QFileDialogPrivate, args.parent, { })
395 setFileMode(args.mode);
396 setOptions(args.options);
397 selectFile(args.selection);
401
402
403QFileDialog::~QFileDialog()
406#if QT_CONFIG(settings)
409 if (QPlatformFileDialogHelper *platformHelper = d->platformFileDialogHelper()) {
412 QObjectPrivate::disconnect(platformHelper, &QPlatformFileDialogHelper::directoryEntered,
413 d, &QFileDialogPrivate::nativeEnterDirectory);
418
419
420
421
422
423
424
425
426
427
428
429
430void QFileDialog::setSidebarUrls(
const QList<QUrl> &urls)
433 if (!d->nativeDialogInUse)
434 d->qFileDialogUi->sidebar->setUrls(urls);
438
439
440QList<QUrl> QFileDialog::sidebarUrls()
const
442 Q_D(
const QFileDialog);
443 return (d->nativeDialogInUse ? QList<QUrl>() : d->qFileDialogUi->sidebar->urls());
446static const qint32 QFileDialogMagic = 0xbe;
449
450
451
452
453
454QByteArray QFileDialog::saveState()
const
456 Q_D(
const QFileDialog);
459 QDataStream stream(&data, QIODevice::WriteOnly);
460 stream.setVersion(QDataStream::Qt_5_0);
462 stream << qint32(QFileDialogMagic);
463 stream << qint32(version);
464 if (d->usingWidgets()) {
465 stream << d->qFileDialogUi->splitter->saveState();
466 stream << d->qFileDialogUi->sidebar->urls();
468 stream << d->splitterState;
469 stream << d->sidebarUrls;
472 stream << *lastVisitedDir();
473 if (d->usingWidgets())
474 stream << d->qFileDialogUi->treeView->header()->saveState();
476 stream << d->headerData;
477 stream << qint32(viewMode());
482
483
484
485
486
487
488
489bool QFileDialog::restoreState(
const QByteArray &state)
492 QByteArray sd = state;
493 QDataStream stream(&sd, QIODevice::ReadOnly);
494 stream.setVersion(QDataStream::Qt_5_0);
498 QUrl currentDirectory;
505 if (marker != QFileDialogMagic || (v != 3 && v != 4))
508 stream >> d->splitterState
512 QString currentDirectoryString;
513 stream >> currentDirectoryString;
514 currentDirectory = QUrl::fromLocalFile(currentDirectoryString);
516 stream >> currentDirectory;
518 stream >> d->headerData
521 setDirectoryUrl(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir());
522 setViewMode(
static_cast<QFileDialog::ViewMode>(viewMode));
524 if (!d->usingWidgets())
527 return d->restoreWidgetState(history, -1);
531
532
533void QFileDialog::changeEvent(QEvent *e)
536 if (e->type() == QEvent::LanguageChange) {
537 d->retranslateWindowTitle();
538 d->retranslateStrings();
540 QDialog::changeEvent(e);
543QFileDialogPrivate::QFileDialogPrivate()
545#if QT_CONFIG(proxymodel)
549 currentHistoryLocation(-1),
550 renameAction(
nullptr),
551 deleteAction(
nullptr),
552 showHiddenAction(
nullptr),
553 useDefaultCaption(
true),
554 qFileDialogUi(
nullptr),
555 options(QFileDialogOptions::create())
559QFileDialogPrivate::~QFileDialogPrivate()
563void QFileDialogPrivate::initHelper(QPlatformDialogHelper *h)
566 auto *fileDialogHelper =
static_cast<QPlatformFileDialogHelper *>(h);
567 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::fileSelected,
568 this, &QFileDialogPrivate::emitUrlSelected);
569 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::filesSelected,
570 this, &QFileDialogPrivate::emitUrlsSelected);
571 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::currentChanged,
572 this, &QFileDialogPrivate::nativeCurrentChanged);
573 QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::directoryEntered,
574 this, &QFileDialogPrivate::nativeEnterDirectory);
575 QObject::connect(fileDialogHelper, &QPlatformFileDialogHelper::filterSelected,
576 q, &QFileDialog::filterSelected);
577 fileDialogHelper->setOptions(options);
580void QFileDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
583 options->setWindowTitle(q->windowTitle());
584 options->setHistory(q->history());
586 options->setSidebarUrls(qFileDialogUi->sidebar->urls());
587 if (options->initiallySelectedNameFilter().isEmpty())
588 options->setInitiallySelectedNameFilter(q->selectedNameFilter());
589 if (options->initiallySelectedFiles().isEmpty())
590 options->setInitiallySelectedFiles(userSelectedFiles());
593void QFileDialogPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
595 if (code == QDialog::Accepted) {
597 q->setViewMode(
static_cast<QFileDialog::ViewMode>(options->viewMode()));
598 q->setSidebarUrls(options->sidebarUrls());
599 q->setHistory(options->history());
603void QFileDialogPrivate::retranslateWindowTitle()
606 if (!useDefaultCaption || setWindowTitle != q->windowTitle())
608 if (q->acceptMode() == QFileDialog::AcceptOpen) {
609 const QFileDialog::FileMode fileMode = q->fileMode();
610 if (fileMode == QFileDialog::Directory)
611 q->setWindowTitle(QFileDialog::tr(
"Find Directory"));
613 q->setWindowTitle(QFileDialog::tr(
"Open"));
615 q->setWindowTitle(QFileDialog::tr(
"Save As"));
617 setWindowTitle = q->windowTitle();
620void QFileDialogPrivate::setLastVisitedDirectory(
const QUrl &dir)
622 *lastVisitedDir() = dir;
625void QFileDialogPrivate::updateLookInLabel()
627 if (options->isLabelExplicitlySet(QFileDialogOptions::LookIn))
628 setLabelTextControl(QFileDialog::LookIn, options->labelText(QFileDialogOptions::LookIn));
631void QFileDialogPrivate::updateFileNameLabel()
633 if (options->isLabelExplicitlySet(QFileDialogOptions::FileName)) {
634 setLabelTextControl(QFileDialog::FileName, options->labelText(QFileDialogOptions::FileName));
636 switch (q_func()->fileMode()) {
637 case QFileDialog::Directory:
638 setLabelTextControl(QFileDialog::FileName, QFileDialog::tr(
"Directory:"));
641 setLabelTextControl(QFileDialog::FileName, QFileDialog::tr(
"File &name:"));
647void QFileDialogPrivate::updateFileTypeLabel()
649 if (options->isLabelExplicitlySet(QFileDialogOptions::FileType))
650 setLabelTextControl(QFileDialog::FileType, options->labelText(QFileDialogOptions::FileType));
653void QFileDialogPrivate::updateOkButtonText(
bool saveAsOnFolder)
657 if (saveAsOnFolder) {
658 setLabelTextControl(QFileDialog::Accept, QFileDialog::tr(
"&Open"));
659 }
else if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) {
660 setLabelTextControl(QFileDialog::Accept, options->labelText(QFileDialogOptions::Accept));
663 switch (q->fileMode()) {
664 case QFileDialog::Directory:
665 setLabelTextControl(QFileDialog::Accept, QFileDialog::tr(
"&Choose"));
668 setLabelTextControl(QFileDialog::Accept,
669 q->acceptMode() == QFileDialog::AcceptOpen ?
670 QFileDialog::tr(
"&Open") :
671 QFileDialog::tr(
"&Save"));
677void QFileDialogPrivate::updateCancelButtonText()
679 if (options->isLabelExplicitlySet(QFileDialogOptions::Reject))
680 setLabelTextControl(QFileDialog::Reject, options->labelText(QFileDialogOptions::Reject));
683void QFileDialogPrivate::retranslateStrings()
687 if (options->useDefaultNameFilters())
688 q->setNameFilter(QFileDialogOptions::defaultNameFilterString());
692 QList<QAction*> actions = qFileDialogUi->treeView->header()->actions();
693 QAbstractItemModel *abstractModel = model;
694#if QT_CONFIG(proxymodel)
696 abstractModel = proxyModel;
698 const int total = qMin(abstractModel->columnCount(QModelIndex()),
int(actions.size() + 1));
699 for (
int i = 1; i < total; ++i) {
700 actions.at(i - 1)->setText(QFileDialog::tr(
"Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
704 renameAction->setText(QFileDialog::tr(
"&Rename"));
705 deleteAction->setText(QFileDialog::tr(
"&Delete"));
706 showHiddenAction->setText(QFileDialog::tr(
"Show &hidden files"));
707 newFolderAction->setText(QFileDialog::tr(
"&New Folder"));
708 qFileDialogUi->retranslateUi(q);
710 updateFileNameLabel();
711 updateFileTypeLabel();
712 updateCancelButtonText();
715void QFileDialogPrivate::emitFilesSelected(
const QStringList &files)
718 emit q->filesSelected(files);
719 if (files.size() == 1)
720 emit q->fileSelected(files.first());
723bool QFileDialogPrivate::canBeNativeDialog()
const
727 const QDialog *
const q =
static_cast<
const QDialog*>(q_ptr);
728 if (nativeDialogInUse)
730 if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
731 || q->testAttribute(Qt::WA_DontShowOnScreen)
732 || (options->options() & QFileDialog::DontUseNativeDialog)) {
736 return strcmp(QFileDialog::staticMetaObject.className(), q->metaObject()->className()) == 0;
739bool QFileDialogPrivate::usingWidgets()
const
741 return !nativeDialogInUse && qFileDialogUi;
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760void QFileDialog::setOption(Option option,
bool on)
762 const QFileDialog::Options previousOptions = options();
763 if (!(previousOptions & option) != !on)
764 setOptions(previousOptions ^ option);
768
769
770
771
772
773bool QFileDialog::testOption(Option option)
const
775 Q_D(
const QFileDialog);
776 return d->options->testOption(
static_cast<QFileDialogOptions::FileDialogOption>(option));
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797void QFileDialog::setOptions(Options options)
801 Options changed = (options ^ QFileDialog::options());
805 d->options->setOptions(QFileDialogOptions::FileDialogOptions(
int(options)));
807 if (options & DontUseNativeDialog) {
808 d->nativeDialogInUse =
false;
812 if (d->usingWidgets()) {
813 if (changed & DontResolveSymlinks)
814 d->model->setResolveSymlinks(!(options & DontResolveSymlinks));
815 if (changed & ReadOnly) {
816 bool ro = (options & ReadOnly);
817 d->model->setReadOnly(ro);
818 d->qFileDialogUi->newFolderButton->setEnabled(!ro);
819 d->renameAction->setEnabled(!ro);
820 d->deleteAction->setEnabled(!ro);
823 if (changed & DontUseCustomDirectoryIcons) {
824 QFileIconProvider::Options providerOptions = iconProvider()->options();
825 providerOptions.setFlag(QFileIconProvider::DontUseCustomDirectoryIcons,
826 options & DontUseCustomDirectoryIcons);
827 iconProvider()->setOptions(providerOptions);
831 if (changed & HideNameFilterDetails)
832 setNameFilters(d->options->nameFilters());
834 if (changed & ShowDirsOnly)
835 setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files);
838QFileDialog::Options QFileDialog::options()
const
840 Q_D(
const QFileDialog);
841 static_assert((
int)QFileDialog::ShowDirsOnly == (
int)QFileDialogOptions::ShowDirsOnly);
842 static_assert((
int)QFileDialog::DontResolveSymlinks == (
int)QFileDialogOptions::DontResolveSymlinks);
843 static_assert((
int)QFileDialog::DontConfirmOverwrite == (
int)QFileDialogOptions::DontConfirmOverwrite);
844 static_assert((
int)QFileDialog::DontUseNativeDialog == (
int)QFileDialogOptions::DontUseNativeDialog);
845 static_assert((
int)QFileDialog::ReadOnly == (
int)QFileDialogOptions::ReadOnly);
846 static_assert((
int)QFileDialog::HideNameFilterDetails == (
int)QFileDialogOptions::HideNameFilterDetails);
847 static_assert((
int)QFileDialog::DontUseCustomDirectoryIcons == (
int)QFileDialogOptions::DontUseCustomDirectoryIcons);
848 return QFileDialog::Options(
int(d->options->options()));
852
853
854
855
856
857
858void QFileDialog::open(QObject *receiver,
const char *member)
861 const char *signal = (fileMode() == ExistingFiles) ? SIGNAL(filesSelected(QStringList))
862 : SIGNAL(fileSelected(QString));
863 connect(
this, signal, receiver, member);
864 d->signalToDisconnectOnClose = signal;
865 d->receiverToDisconnectOnClose = receiver;
866 d->memberToDisconnectOnClose = member;
873
874
875void QFileDialog::setVisible(
bool visible)
878 QDialog::setVisible(visible);
882
883
884
885
886
887void QFileDialogPrivate::setVisible(
bool visible)
891 const auto q =
static_cast<QDialog *>(q_ptr);
893 if (canBeNativeDialog()){
894 if (setNativeDialogVisible(visible)){
897 q->setAttribute(Qt::WA_DontShowOnScreen);
898#if QT_CONFIG(fscompleter)
900 if (!nativeDialogInUse)
901 completer->setModel(
nullptr);
903 }
else if (visible) {
905 q->setAttribute(Qt::WA_DontShowOnScreen,
false);
906#if QT_CONFIG(fscompleter)
907 if (!nativeDialogInUse) {
908 if (proxyModel !=
nullptr)
909 completer->setModel(proxyModel);
911 completer->setModel(model);
917 if (visible && usingWidgets())
918 qFileDialogUi->fileNameEdit->setFocus();
920 QDialogPrivate::setVisible(visible);
924
925
926
927void QFileDialogPrivate::goToUrl(
const QUrl &url)
931 QFileSystemModelPrivate::QFileSystemNode *node = model->d_func()->node(url.toLocalFile(),
true);
932 QModelIndex idx = model->d_func()->index(node);
937
938
939
940
943
944
945
946
947
948
949
950
951
952
953
954void QFileDialog::setDirectory(
const QString &directory)
957 QString newDirectory = directory;
959 if (!directory.isEmpty())
960 newDirectory = QDir::cleanPath(directory);
962 if (!directory.isEmpty() && newDirectory.isEmpty())
965 QUrl newDirUrl = QUrl::fromLocalFile(newDirectory);
966 QFileDialogPrivate::setLastVisitedDirectory(newDirUrl);
968 d->options->setInitialDirectory(QUrl::fromLocalFile(directory));
969 if (!d->usingWidgets()) {
970 d->setDirectory_sys(newDirUrl);
973 if (d->rootPath() == newDirectory)
975 QModelIndex root = d->model->setRootPath(newDirectory);
976 if (!d->nativeDialogInUse) {
977 d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled);
978 if (root != d->rootIndex()) {
979#if QT_CONFIG(fscompleter)
980 if (directory.endsWith(u'/'))
981 d->completer->setCompletionPrefix(newDirectory);
983 d->completer->setCompletionPrefix(newDirectory + u'/');
985 d->setRootIndex(root);
987 d->qFileDialogUi->listView->selectionModel()->clear();
992
993
994QDir QFileDialog::directory()
const
996 Q_D(
const QFileDialog);
997 if (d->nativeDialogInUse) {
998 QString dir = d->directory_sys().toLocalFile();
999 return QDir(dir.isEmpty() ? d->options->initialDirectory().toLocalFile() : dir);
1001 return d->rootPath();
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021void QFileDialog::setDirectoryUrl(
const QUrl &directory)
1024 if (!directory.isValid())
1027 QFileDialogPrivate::setLastVisitedDirectory(directory);
1028 d->options->setInitialDirectory(directory);
1030 if (d->nativeDialogInUse)
1031 d->setDirectory_sys(directory);
1032 else if (directory.isLocalFile())
1033 setDirectory(directory.toLocalFile());
1034 else if (Q_UNLIKELY(d->usingWidgets()))
1035 qWarning(
"Non-native QFileDialog supports only local files");
1039
1040
1041
1042
1043QUrl QFileDialog::directoryUrl()
const
1045 Q_D(
const QFileDialog);
1046 if (d->nativeDialogInUse)
1047 return d->directory_sys();
1049 return QUrl::fromLocalFile(directory().absolutePath());
1056#if defined(Q_OS_WIN)
1060#elif defined(Q_OS_MACOS)
1061 return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE) == 1;
1071 if (!QFileInfo(path).isAbsolute())
1073 if (path.startsWith(rootPath, isCaseSensitiveFileSystem(rootPath) ? Qt::CaseSensitive : Qt::CaseInsensitive))
1074 path.remove(0, rootPath.size());
1079 if (path.at(0) == QDir::separator()
1082 || path.at(0) == u'/'
1091
1092
1093
1094
1095void QFileDialog::selectFile(
const QString &filename)
1098 if (filename.isEmpty())
1101 if (!d->usingWidgets()) {
1103 if (QFileInfo(filename).isRelative()) {
1104 url = d->options->initialDirectory();
1105 QString path = url.path();
1106 if (!path.endsWith(u'/'))
1108 url.setPath(path + filename);
1110 url = QUrl::fromLocalFile(filename);
1112 d->selectFile_sys(url);
1113 d->options->setInitiallySelectedFiles(QList<QUrl>() << url);
1117 if (!QDir::isRelativePath(filename)) {
1118 QFileInfo info(filename);
1119 QString filenamePath = info.absoluteDir().path();
1121 if (d->model->rootPath() != filenamePath)
1122 setDirectory(filenamePath);
1125 QModelIndex index = d->model->index(filename);
1126 d->qFileDialogUi->listView->selectionModel()->clear();
1127 if (!isVisible() || !d->lineEdit()->hasFocus())
1128 d->lineEdit()->setText(index.isValid() ? index.data().toString() : fileFromPath(d->rootPath(), filename));
1132
1133
1134
1135
1136
1137
1138
1139void QFileDialog::selectUrl(
const QUrl &url)
1145 if (d->nativeDialogInUse)
1146 d->selectFile_sys(url);
1147 else if (url.isLocalFile())
1148 selectFile(url.toLocalFile());
1150 qWarning(
"Non-native QFileDialog supports only local files");
1154static QString homeDirFromPasswdEntry(
const QString &path,
const QByteArray &userName)
1156#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
1159 long bufSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
1162 QVarLengthArray<
char, 1024> buf(bufSize);
1164# if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0
< 199506L
)
1165 tmpPw = getpwnam_r(userName.constData(), &pw, buf.data(), buf.size());
1167 err = getpwnam_r(userName.constData(), &pw, buf.data(), buf.size(), &tmpPw);
1171 return QFile::decodeName(pw.pw_dir);
1173 passwd *pw = getpwnam(userName.constData());
1176 return QFile::decodeName(pw->pw_dir);
1180Q_AUTOTEST_EXPORT QString qt_tildeExpansion(
const QString &path)
1182 if (!path.startsWith(u'~'))
1185 if (path.size() == 1)
1186 return QDir::homePath();
1188 QStringView sv(path);
1189 const qsizetype sepIndex = sv.indexOf(QDir::separator());
1191 return QDir::homePath() + sv.sliced(1);
1193#if defined(Q_OS_VXWORKS) || defined(Q_OS_INTEGRITY)
1195 return QDir::homePath();
1196 return QDir::homePath() + sv.sliced(sepIndex);
1198 const qsizetype userNameLen = sepIndex != -1 ? sepIndex - strlen(
"~")
1199 : path.size() - strlen(
"~");
1200 const QByteArray userName = sv.sliced(1, userNameLen).toLocal8Bit();
1201 QString homePath = homeDirFromPasswdEntry(path, userName);
1204 return homePath + sv.sliced(sepIndex);
1210
1211
1212QStringList QFileDialogPrivate::typedFiles()
const
1214 Q_Q(
const QFileDialog);
1216 QString editText = lineEdit()->text();
1217 if (!editText.contains(u'"')) {
1219 const QString prefix = q->directory().absolutePath() + QDir::separator();
1220 if (QFile::exists(prefix + editText))
1223 files << qt_tildeExpansion(editText);
1231 QStringList tokens = editText.split(u'\"');
1232 for (
int i=0; i<tokens.size(); ++i) {
1236 const QString token = tokens.at(i);
1237 const QString prefix = q->directory().absolutePath() + QDir::separator();
1238 if (QFile::exists(prefix + token))
1241 files << qt_tildeExpansion(token);
1243 files << toInternal(tokens.at(i));
1247 return addDefaultSuffixToFiles(files);
1253QList<QUrl> QFileDialogPrivate::userSelectedFiles()
const
1257 if (!usingWidgets())
1258 return addDefaultSuffixToUrls(selectedFiles_sys());
1260 const QModelIndexList selectedRows = qFileDialogUi->listView->selectionModel()->selectedRows();
1261 files.reserve(selectedRows.size());
1262 for (
const QModelIndex &index : selectedRows)
1263 files.append(QUrl::fromLocalFile(index.data(QFileSystemModel::FilePathRole).toString()));
1265 if (files.isEmpty() && !lineEdit()->text().isEmpty()) {
1266 const QStringList typedFilesList = typedFiles();
1267 files.reserve(typedFilesList.size());
1268 for (
const QString &path : typedFilesList)
1269 files.append(QUrl::fromLocalFile(path));
1275QStringList QFileDialogPrivate::addDefaultSuffixToFiles(
const QStringList &filesToFix)
const
1278 for (
int i=0; i<filesToFix.size(); ++i) {
1279 QString name = toInternal(filesToFix.at(i));
1280 QFileInfo info(name);
1282 const QString defaultSuffix = options->defaultSuffix();
1283 if (!defaultSuffix.isEmpty() && !info.isDir() && !info.fileName().contains(u'.'))
1284 name += u'.' + defaultSuffix;
1286 if (info.isAbsolute()) {
1292 QString path = rootPath();
1293 if (!path.endsWith(u'/'))
1302QList<QUrl> QFileDialogPrivate::addDefaultSuffixToUrls(
const QList<QUrl> &urlsToFix)
const
1305 urls.reserve(urlsToFix.size());
1307 const QString defaultSuffix = options->defaultSuffix();
1308 for (QUrl url : urlsToFix) {
1309 if (!defaultSuffix.isEmpty()) {
1310 const QString urlPath = url.path();
1311 const auto idx = urlPath.lastIndexOf(u'/');
1312 if (idx != (urlPath.size() - 1) && !QStringView{urlPath}.mid(idx + 1).contains(u'.'))
1313 url.setPath(urlPath + u'.' + defaultSuffix);
1322
1323
1324
1325
1326
1327
1328QStringList QFileDialog::selectedFiles()
const
1330 Q_D(
const QFileDialog);
1333 const QList<QUrl> userSelectedFiles = d->userSelectedFiles();
1334 files.reserve(userSelectedFiles.size());
1335 for (
const QUrl &file : userSelectedFiles)
1336 files.append(file.toString(QUrl::PreferLocalFile));
1338 if (files.isEmpty() && d->usingWidgets()) {
1339 const FileMode fm = fileMode();
1340 if (fm != ExistingFile && fm != ExistingFiles)
1341 files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
1347
1348
1349
1350
1351
1352
1353
1354QList<QUrl> QFileDialog::selectedUrls()
const
1356 Q_D(
const QFileDialog);
1357 if (d->nativeDialogInUse) {
1358 return d->userSelectedFiles();
1361 const QStringList selectedFileList = selectedFiles();
1362 urls.reserve(selectedFileList.size());
1363 for (
const QString &file : selectedFileList)
1364 urls.append(QUrl::fromLocalFile(file));
1370
1371
1372
1375 if (filter.isEmpty())
1376 return QStringList();
1379 if (!filter.contains(sep) && filter.contains(u'\n'))
1382 return filter.split(sep);
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400void QFileDialog::setNameFilter(
const QString &filter)
1402 setNameFilters(qt_make_filter_list(filter));
1407
1408
1411#if QT_CONFIG(regularexpression)
1412 QStringList strippedFilters;
1413 static const QRegularExpression r(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp));
1414 strippedFilters.reserve(filters.size());
1415 for (
const QString &filter : filters) {
1417 auto match = r.match(filter);
1418 if (match.hasMatch())
1419 filterName = match.captured(1);
1420 strippedFilters.append(filterName.simplified());
1422 return strippedFilters;
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446void QFileDialog::setNameFilters(
const QStringList &filters)
1449 QStringList cleanedFilters;
1450 cleanedFilters.reserve(filters.size());
1451 for (
const QString &filter : filters)
1452 cleanedFilters << filter.simplified();
1454 d->options->setNameFilters(cleanedFilters);
1456 if (!d->usingWidgets())
1459 d->qFileDialogUi->fileTypeCombo->clear();
1460 if (cleanedFilters.isEmpty())
1463 if (testOption(HideNameFilterDetails))
1464 d->qFileDialogUi->fileTypeCombo->addItems(qt_strip_filters(cleanedFilters));
1466 d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters);
1468 d->useNameFilter(0);
1472
1473
1474
1475QStringList QFileDialog::nameFilters()
const
1477 return d_func()->options->nameFilters();
1481
1482
1483
1484
1485
1486void QFileDialog::selectNameFilter(
const QString &filter)
1489 d->options->setInitiallySelectedNameFilter(filter);
1490 if (!d->usingWidgets()) {
1491 d->selectNameFilter_sys(filter);
1495 if (testOption(HideNameFilterDetails)) {
1496 const QStringList filters = qt_strip_filters(qt_make_filter_list(filter));
1497 if (!filters.isEmpty())
1498 i = d->qFileDialogUi->fileTypeCombo->findText(filters.first());
1500 i = d->qFileDialogUi->fileTypeCombo->findText(filter);
1503 d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i);
1504 d->useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex());
1509
1510
1511
1512
1513QString QFileDialog::selectedNameFilter()
const
1515 Q_D(
const QFileDialog);
1516 if (!d->usingWidgets())
1517 return d->selectedNameFilter_sys();
1519 if (testOption(HideNameFilterDetails)) {
1520 const auto idx = d->qFileDialogUi->fileTypeCombo->currentIndex();
1521 if (idx >= 0 && idx < d->options->nameFilters().size())
1522 return d->options->nameFilters().at(d->qFileDialogUi->fileTypeCombo->currentIndex());
1524 return d->qFileDialogUi->fileTypeCombo->currentText();
1528
1529
1530
1531
1532QDir::Filters QFileDialog::filter()
const
1534 Q_D(
const QFileDialog);
1535 if (d->usingWidgets())
1536 return d->model->filter();
1537 return d->options->filter();
1541
1542
1543
1544
1545
1547void QFileDialog::setFilter(QDir::Filters filters)
1550 d->options->setFilter(filters);
1551 if (!d->usingWidgets()) {
1556 d->model->setFilter(filters);
1557 d->showHiddenAction->setChecked((filters & QDir::Hidden));
1560#if QT_CONFIG(mimetype)
1562static QString nameFilterForMime(
const QString &mimeType)
1565 QMimeType mime(db.mimeTypeForName(mimeType));
1566 if (mime.isValid()) {
1567 if (mime.isDefault()) {
1568 return QFileDialog::tr(
"All files (*)");
1570 const QString patterns = mime.globPatterns().join(u' ');
1571 return mime.comment() +
" ("_L1 + patterns + u')';
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594void QFileDialog::setMimeTypeFilters(
const QStringList &filters)
1597 QStringList nameFilters;
1598 for (
const QString &mimeType : filters) {
1599 const QString text = nameFilterForMime(mimeType);
1600 if (!text.isEmpty())
1601 nameFilters.append(text);
1603 setNameFilters(nameFilters);
1604 d->options->setMimeTypeFilters(filters);
1608
1609
1610
1611
1612
1613QStringList QFileDialog::mimeTypeFilters()
const
1615 return d_func()->options->mimeTypeFilters();
1619
1620
1621
1622
1623
1624void QFileDialog::selectMimeTypeFilter(
const QString &filter)
1627 d->options->setInitiallySelectedMimeTypeFilter(filter);
1629 const QString filterForMime = nameFilterForMime(filter);
1631 if (!d->usingWidgets()) {
1632 d->selectMimeTypeFilter_sys(filter);
1633 if (d->selectedMimeTypeFilter_sys().isEmpty() && !filterForMime.isEmpty()) {
1634 selectNameFilter(filterForMime);
1636 }
else if (!filterForMime.isEmpty()) {
1637 selectNameFilter(filterForMime);
1644
1645
1646
1647QString QFileDialog::selectedMimeTypeFilter()
const
1649 Q_D(
const QFileDialog);
1650 QString mimeTypeFilter;
1651 if (!d->usingWidgets())
1652 mimeTypeFilter = d->selectedMimeTypeFilter_sys();
1654#if QT_CONFIG(mimetype)
1655 if (mimeTypeFilter.isNull() && !d->options->mimeTypeFilters().isEmpty()) {
1656 const auto nameFilter = selectedNameFilter();
1657 const auto mimeTypes = d->options->mimeTypeFilters();
1658 for (
const auto &mimeType: mimeTypes) {
1659 QString filter = nameFilterForMime(mimeType);
1660 if (testOption(HideNameFilterDetails))
1661 filter = qt_strip_filters({ filter }).constFirst();
1662 if (filter == nameFilter) {
1663 mimeTypeFilter = mimeType;
1670 return mimeTypeFilter;
1674
1675
1676
1677
1678
1679
1680
1681
1682void QFileDialog::setViewMode(QFileDialog::ViewMode mode)
1685 d->options->setViewMode(
static_cast<QFileDialogOptions::ViewMode>(mode));
1686 if (!d->usingWidgets())
1689 d->showDetailsView();
1694QFileDialog::ViewMode QFileDialog::viewMode()
const
1696 Q_D(
const QFileDialog);
1697 if (!d->usingWidgets())
1698 return static_cast<QFileDialog::ViewMode>(d->options->viewMode());
1699 return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail);
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717void QFileDialog::setFileMode(QFileDialog::FileMode mode)
1720 d->options->setFileMode(
static_cast<QFileDialogOptions::FileMode>(mode));
1721 if (!d->usingWidgets())
1724 d->retranslateWindowTitle();
1727 QAbstractItemView::SelectionMode selectionMode;
1728 if (mode == QFileDialog::ExistingFiles)
1729 selectionMode = QAbstractItemView::ExtendedSelection;
1731 selectionMode = QAbstractItemView::SingleSelection;
1732 d->qFileDialogUi->listView->setSelectionMode(selectionMode);
1733 d->qFileDialogUi->treeView->setSelectionMode(selectionMode);
1735 d->model->setFilter(d->filterForMode(filter()));
1737 if (mode == Directory) {
1738 d->qFileDialogUi->fileTypeCombo->clear();
1739 d->qFileDialogUi->fileTypeCombo->addItem(tr(
"Directories"));
1740 d->qFileDialogUi->fileTypeCombo->setEnabled(
false);
1742 d->updateFileNameLabel();
1743 d->updateOkButtonText();
1744 d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
1745 d->updateOkButton();
1748QFileDialog::FileMode QFileDialog::fileMode()
const
1750 Q_D(
const QFileDialog);
1751 return static_cast<FileMode>(d->options->fileMode());
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
1767 d->options->setAcceptMode(
static_cast<QFileDialogOptions::AcceptMode>(mode));
1769 setAttribute(Qt::WA_DontShowOnScreen,
false);
1770 if (!d->usingWidgets())
1772 QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
1773 d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel);
1774 d->qFileDialogUi->buttonBox->button(button)->setEnabled(
false);
1775 d->updateOkButton();
1776 if (mode == AcceptSave) {
1777 d->qFileDialogUi->lookInCombo->setEditable(
false);
1779 d->retranslateWindowTitle();
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1795void QFileDialog::setSupportedSchemes(
const QStringList &schemes)
1798 d->options->setSupportedSchemes(schemes);
1801QStringList QFileDialog::supportedSchemes()
const
1803 return d_func()->options->supportedSchemes();
1807
1808
1809
1810QModelIndex QFileDialogPrivate::rootIndex()
const {
1811 return mapToSource(qFileDialogUi->listView->rootIndex());
1814QAbstractItemView *QFileDialogPrivate::currentView()
const {
1815 if (!qFileDialogUi->stackedWidget)
1817 if (qFileDialogUi->stackedWidget->currentWidget() == qFileDialogUi->listView->parent())
1818 return qFileDialogUi->listView;
1819 return qFileDialogUi->treeView;
1822QLineEdit *QFileDialogPrivate::lineEdit()
const {
1823 return (QLineEdit*)qFileDialogUi->fileNameEdit;
1826long QFileDialogPrivate::maxNameLength(
const QString &path)
1828#if defined(Q_OS_UNIX)
1829 return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX);
1830#elif defined(Q_OS_WIN)
1832 const QString drive = path.left(3);
1833 if (::GetVolumeInformation(
reinterpret_cast<
const wchar_t *>(drive.utf16()), NULL, 0, NULL, &maxLength, NULL, NULL, 0) ==
false)
1843
1844
1845void QFileDialogPrivate::setRootIndex(
const QModelIndex &index)
const {
1846 Q_ASSERT(index.isValid() ? index.model() == model :
true);
1847 QModelIndex idx = mapFromSource(index);
1848 qFileDialogUi->treeView->setRootIndex(idx);
1849 qFileDialogUi->listView->setRootIndex(idx);
1852
1853
1854
1855QModelIndex QFileDialogPrivate::select(
const QModelIndex &index)
const {
1856 Q_ASSERT(index.isValid() ? index.model() == model :
true);
1858 QModelIndex idx = mapFromSource(index);
1859 if (idx.isValid() && !qFileDialogUi->listView->selectionModel()->isSelected(idx))
1860 qFileDialogUi->listView->selectionModel()->select(idx,
1861 QItemSelectionModel::Select | QItemSelectionModel::Rows);
1865QFileDialog::AcceptMode QFileDialog::acceptMode()
const
1867 Q_D(
const QFileDialog);
1868 return static_cast<AcceptMode>(d->options->acceptMode());
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882void QFileDialog::setDefaultSuffix(
const QString &suffix)
1885 d->options->setDefaultSuffix(suffix);
1888QString QFileDialog::defaultSuffix()
const
1890 Q_D(
const QFileDialog);
1891 return d->options->defaultSuffix();
1895
1896
1897
1898void QFileDialog::setHistory(
const QStringList &paths)
1901 if (d->usingWidgets())
1902 d->qFileDialogUi->lookInCombo->setHistory(paths);
1910 const QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
1912 const QUrl url = idx.isValid()
1913 ? QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString()))
1917 urlModel->setUrls(list);
1921
1922
1923QStringList QFileDialog::history()
const
1925 Q_D(
const QFileDialog);
1926 if (!d->usingWidgets())
1927 return QStringList();
1928 QStringList currentHistory = d->qFileDialogUi->lookInCombo->history();
1930 QString newHistory = QDir::toNativeSeparators(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
1931 if (!currentHistory.contains(newHistory))
1932 currentHistory << newHistory;
1933 return currentHistory;
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954void QFileDialog::setItemDelegate(QAbstractItemDelegate *delegate)
1957 if (!d->usingWidgets())
1959 d->qFileDialogUi->listView->setItemDelegate(delegate);
1960 d->qFileDialogUi->treeView->setItemDelegate(delegate);
1964
1965
1966QAbstractItemDelegate *QFileDialog::itemDelegate()
const
1968 Q_D(
const QFileDialog);
1969 if (!d->usingWidgets())
1971 return d->qFileDialogUi->listView->itemDelegate();
1975
1976
1977void QFileDialog::setIconProvider(QAbstractFileIconProvider *provider)
1980 if (!d->usingWidgets())
1982 d->model->setIconProvider(provider);
1984 d->qFileDialogUi->sidebar->setUrls(d->qFileDialogUi->sidebar->urls());
1988
1989
1990QAbstractFileIconProvider *QFileDialog::iconProvider()
const
1992 Q_D(
const QFileDialog);
1995 return d->model->iconProvider();
1998void QFileDialogPrivate::setLabelTextControl(QFileDialog::DialogLabel label,
const QString &text)
2003 case QFileDialog::LookIn:
2004 qFileDialogUi->lookInLabel->setText(text);
2006 case QFileDialog::FileName:
2007 qFileDialogUi->fileNameLabel->setText(text);
2009 case QFileDialog::FileType:
2010 qFileDialogUi->fileTypeLabel->setText(text);
2012 case QFileDialog::Accept:
2013 if (q_func()->acceptMode() == QFileDialog::AcceptOpen) {
2014 if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Open))
2015 button->setText(text);
2017 if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Save))
2018 button->setText(text);
2021 case QFileDialog::Reject:
2022 if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel))
2023 button->setText(text);
2029
2030
2032void QFileDialog::setLabelText(DialogLabel label,
const QString &text)
2035 d->options->setLabelText(
static_cast<QFileDialogOptions::DialogLabel>(label), text);
2036 d->setLabelTextControl(label, text);
2040
2041
2042QString QFileDialog::labelText(DialogLabel label)
const
2044 Q_D(
const QFileDialog);
2045 if (!d->usingWidgets())
2046 return d->options->labelText(
static_cast<QFileDialogOptions::DialogLabel>(label));
2047 QPushButton *button;
2050 return d->qFileDialogUi->lookInLabel->text();
2052 return d->qFileDialogUi->fileNameLabel->text();
2054 return d->qFileDialogUi->fileTypeLabel->text();
2056 if (acceptMode() == AcceptOpen)
2057 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
2059 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
2061 return button->text();
2064 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
2066 return button->text();
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
2113
2114QString QFileDialog::getOpenFileName(QWidget *parent,
2115 const QString &caption,
2117 const QString &filter,
2118 QString *selectedFilter,
2121 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2122 const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter,
2123 selectedFilter, options, schemes);
2124 if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
2125 return selectedUrl.toLocalFile();
2127 return selectedUrl.toString();
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
2156
2157QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
2158 const QString &caption,
2160 const QString &filter,
2161 QString *selectedFilter,
2163 const QStringList &supportedSchemes)
2165 QFileDialogArgs args(dir);
2166 args.parent = parent;
2167 args.caption = caption;
2168 args.filter = filter;
2169 args.mode = ExistingFile;
2170 args.options = options;
2172 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2173 dialog->setSupportedSchemes(supportedSchemes);
2174 if (selectedFilter && !selectedFilter->isEmpty())
2175 dialog->selectNameFilter(*selectedFilter);
2176 const int execResult = dialog->exec();
2177 if (
bool(dialog) && execResult == QDialog::Accepted) {
2179 *selectedFilter = dialog->selectedNameFilter();
2180 return dialog->selectedUrls().value(0);
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
2223
2224QStringList QFileDialog::getOpenFileNames(QWidget *parent,
2225 const QString &caption,
2227 const QString &filter,
2228 QString *selectedFilter,
2231 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2232 const QList<QUrl> selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir),
2233 filter, selectedFilter, options, schemes);
2234 QStringList fileNames;
2235 fileNames.reserve(selectedUrls.size());
2236 for (
const QUrl &url : selectedUrls)
2237 fileNames.append(url.toString(QUrl::PreferLocalFile));
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
2268
2269QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
2270 const QString &caption,
2272 const QString &filter,
2273 QString *selectedFilter,
2275 const QStringList &supportedSchemes)
2277 QFileDialogArgs args(dir);
2278 args.parent = parent;
2279 args.caption = caption;
2280 args.filter = filter;
2281 args.mode = ExistingFiles;
2282 args.options = options;
2284 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2285 dialog->setSupportedSchemes(supportedSchemes);
2286 if (selectedFilter && !selectedFilter->isEmpty())
2287 dialog->selectNameFilter(*selectedFilter);
2288 const int execResult = dialog->exec();
2289 if (
bool(dialog) && execResult == QDialog::Accepted) {
2291 *selectedFilter = dialog->selectedNameFilter();
2292 return dialog->selectedUrls();
2294 return QList<QUrl>();
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316void QFileDialog::getOpenFileContent(
const QString &nameFilter,
const std::function<
void(
const QString &,
const QByteArray &)> &fileOpenCompleted, QWidget *parent)
2320 auto openFileImpl = std::make_shared<std::function<
void(
void)>>();
2322 QByteArray fileContent;
2323 *openFileImpl = [=]()
mutable {
2324 auto fileDialogClosed = [&](
bool fileSelected) {
2325 if (!fileSelected) {
2326 fileOpenCompleted(fileName, fileContent);
2327 openFileImpl.reset();
2330 auto acceptFile = [&](uint64_t size,
const std::string name) ->
char * {
2331 const uint64_t twoGB = 1ULL << 31;
2335 fileName = QString::fromStdString(name);
2336 fileContent.resize(size);
2337 return fileContent.data();
2339 auto fileContentReady = [&]()
mutable {
2340 fileOpenCompleted(fileName, fileContent);
2341 openFileImpl.reset();
2344 QWasmLocalFileAccess::openFile(nameFilter.toStdString(), fileDialogClosed, acceptFile, fileContentReady);
2349 QFileDialog *dialog =
new QFileDialog(parent);
2350 dialog->setFileMode(QFileDialog::ExistingFile);
2351 dialog->setNameFilter(nameFilter);
2352 dialog->setAttribute(Qt::WA_DeleteOnClose);
2354 auto fileSelected = [=](
const QString &fileName) {
2355 QByteArray fileContent;
2356 if (!fileName.isNull()) {
2357 QFile selectedFile(fileName);
2358 if (selectedFile.open(QIODevice::ReadOnly))
2359 fileContent = selectedFile.readAll();
2361 fileOpenCompleted(fileName, fileContent);
2364 connect(dialog, &QFileDialog::fileSelected, dialog, fileSelected);
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387void QFileDialog::saveFileContent(
const QByteArray &fileContent,
const QString &fileNameHint, QWidget *parent)
2391 QWasmLocalFileAccess::saveFile(fileContent, fileNameHint.toStdString());
2393 QFileDialog *dialog =
new QFileDialog(parent);
2394 dialog->setAcceptMode(QFileDialog::AcceptSave);
2395 dialog->setFileMode(QFileDialog::AnyFile);
2396 dialog->selectFile(fileNameHint);
2398 auto fileSelected = [=](
const QString &fileName) {
2399 if (!fileName.isNull()) {
2400 QFile selectedFile(fileName);
2401 if (selectedFile.open(QIODevice::WriteOnly))
2402 selectedFile.write(fileContent);
2406 connect(dialog, &QFileDialog::fileSelected, dialog, fileSelected);
2407 dialog->setAttribute(Qt::WA_DeleteOnClose);
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
2455
2456QString QFileDialog::getSaveFileName(QWidget *parent,
2457 const QString &caption,
2459 const QString &filter,
2460 QString *selectedFilter,
2463 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2464 const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter,
2465 selectedFilter, options, schemes);
2466 if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
2467 return selectedUrl.toLocalFile();
2469 return selectedUrl.toString();
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
2498
2499QUrl QFileDialog::getSaveFileUrl(QWidget *parent,
2500 const QString &caption,
2502 const QString &filter,
2503 QString *selectedFilter,
2505 const QStringList &supportedSchemes)
2507 QFileDialogArgs args(dir);
2508 args.parent = parent;
2509 args.caption = caption;
2510 args.filter = filter;
2511 args.mode = AnyFile;
2512 args.options = options;
2514 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2515 dialog->setSupportedSchemes(supportedSchemes);
2516 dialog->setAcceptMode(AcceptSave);
2517 if (selectedFilter && !selectedFilter->isEmpty())
2518 dialog->selectNameFilter(*selectedFilter);
2519 const int execResult = dialog->exec();
2520 if (
bool(dialog) && execResult == QDialog::Accepted) {
2522 *selectedFilter = dialog->selectedNameFilter();
2523 return dialog->selectedUrls().value(0);
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
2567
2568QString QFileDialog::getExistingDirectory(QWidget *parent,
2569 const QString &caption,
2573 const QStringList schemes = QStringList(QStringLiteral(
"file"));
2574 const QUrl selectedUrl =
2575 getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes);
2576 if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
2577 return selectedUrl.toLocalFile();
2579 return selectedUrl.toString();
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
2608
2609QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
2610 const QString &caption,
2613 const QStringList &supportedSchemes)
2615 QFileDialogArgs args(dir);
2616 args.parent = parent;
2617 args.caption = caption;
2618 args.mode = Directory;
2619 args.options = options;
2621 QAutoPointer<QFileDialog> dialog(
new QFileDialog(args));
2622 dialog->setSupportedSchemes(supportedSchemes);
2623 const int execResult = dialog->exec();
2624 if (
bool(dialog) && execResult == QDialog::Accepted)
2625 return dialog->selectedUrls().value(0);
2631 if (url.isLocalFile()) {
2632 QFileInfo info = local;
2633 if (!local.isAbsolute())
2634 info = QFileInfo(QDir::current(), url.toLocalFile());
2635 const QFileInfo pathInfo(info.absolutePath());
2636 if (!pathInfo.exists() || !pathInfo.isDir())
2638 if (info.exists() && info.isDir())
2639 return QUrl::fromLocalFile(QDir::cleanPath(info.absoluteFilePath()));
2640 return QUrl::fromLocalFile(pathInfo.absoluteFilePath());
2647#if QT_CONFIG(settings)
2648 if (lastVisitedDir()->isEmpty()) {
2649 QSettings settings(QSettings::UserScope, u"QtProject"_s);
2650 const QString &lastVisisted = settings.value(
"FileDialog/lastVisited", QString()).toString();
2651 *lastVisitedDir() = QUrl::fromLocalFile(lastVisisted);
2657
2658
2662 const QFileInfo local(url.toLocalFile());
2665 directory = _qt_get_directory(url, local);
2666 if (directory.isEmpty()) {
2668 const QUrl lastVisited = *lastVisitedDir();
2669 if (lastVisited != url)
2670 directory = _qt_get_directory(lastVisited, QFileInfo());
2672 if (directory.isEmpty())
2673 directory = QUrl::fromLocalFile(QDir::currentPath());
2676
2677
2678
2679 if (selection.isEmpty() && !url.isEmpty()) {
2680 if (url.isLocalFile()) {
2682 selection = local.fileName();
2685 selection = url.fileName();
2691
2692
2693void QFileDialog::done(
int result)
2697 QDialog::done(result);
2699 if (d->receiverToDisconnectOnClose) {
2700 disconnect(
this, d->signalToDisconnectOnClose,
2701 d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
2702 d->receiverToDisconnectOnClose =
nullptr;
2704 d->memberToDisconnectOnClose.clear();
2705 d->signalToDisconnectOnClose.clear();
2708bool QFileDialogPrivate::itemAlreadyExists(
const QString &fileName)
2710#if QT_CONFIG(messagebox)
2712 const QString msg = QFileDialog::tr(
"%1 already exists.\nDo you want to replace it?").arg(fileName);
2713 using B = QMessageBox;
2714 const auto res = B::warning(q, q->windowTitle(), msg, B::Yes | B::No, B::No);
2715 return res == B::Yes;
2720void QFileDialogPrivate::itemNotFound(
const QString &fileName, QFileDialog::FileMode mode)
2722#if QT_CONFIG(messagebox)
2724 const QString message = mode == QFileDialog::Directory
2725 ? QFileDialog::tr(
"%1\nDirectory not found.\n"
2726 "Please verify the correct directory name was given.")
2727 : QFileDialog::tr(
"%1\nFile not found.\nPlease verify the "
2728 "correct file name was given.");
2730 QMessageBox::warning(q, q->windowTitle(), message.arg(fileName));
2735
2736
2737void QFileDialog::accept()
2740 if (!d->usingWidgets()) {
2741 const QList<QUrl> urls = selectedUrls();
2744 d->emitUrlsSelected(urls);
2745 if (urls.size() == 1)
2746 d->emitUrlSelected(urls.first());
2751 const QStringList files = selectedFiles();
2752 if (files.isEmpty())
2754 QString lineEditText = d->lineEdit()->text();
2757 if (lineEditText ==
".."_L1) {
2758 d->navigateToParent();
2759 const QSignalBlocker blocker(d->qFileDialogUi->fileNameEdit);
2760 d->lineEdit()->selectAll();
2764 const auto mode = fileMode();
2767 QString fn = files.first();
2770 info = QFileInfo(d->getEnvironmentVariable(fn));
2771 if (!info.exists()) {
2772 d->itemNotFound(info.fileName(), mode);
2776 d->emitFilesSelected(files);
2783 QString fn = files.first();
2786 setDirectory(info.absoluteFilePath());
2790 if (!info.exists()) {
2791 const long maxNameLength = d->maxNameLength(info.path());
2792 if (maxNameLength >= 0 && info.fileName().size() > maxNameLength)
2797 if (!info.exists() || testOption(DontConfirmOverwrite) || acceptMode() == AcceptOpen) {
2798 d->emitFilesSelected(QStringList(fn));
2801 if (d->itemAlreadyExists(info.fileName())) {
2802 d->emitFilesSelected(QStringList(fn));
2811 for (
const auto &file : files) {
2812 QFileInfo info(file);
2814 info = QFileInfo(d->getEnvironmentVariable(file));
2815 if (!info.exists()) {
2816 d->itemNotFound(info.fileName(), mode);
2820 setDirectory(info.absoluteFilePath());
2821 d->lineEdit()->clear();
2825 d->emitFilesSelected(files);
2831#if QT_CONFIG(settings)
2832void QFileDialogPrivate::saveSettings()
2835 QSettings settings(QSettings::UserScope, u"QtProject"_s);
2836 settings.beginGroup(
"FileDialog");
2838 if (usingWidgets()) {
2839 settings.setValue(
"sidebarWidth", qFileDialogUi->splitter->sizes().constFirst());
2840 settings.setValue(
"shortcuts",
2841 QUrl::toStringList(qFileDialogUi->sidebar->urls(), QUrl::FullyEncoded));
2842 settings.setValue(
"treeViewHeader", qFileDialogUi->treeView->header()->saveState());
2844 QStringList historyUrls;
2845 const QStringList history = q->history();
2846 historyUrls.reserve(history.size());
2847 for (
const QString &path : history)
2848 historyUrls << QUrl::fromLocalFile(path).toString(QUrl::FullyEncoded);
2849 settings.setValue(
"history", historyUrls);
2850 settings.setValue(
"lastVisited", lastVisitedDir()->toString(QUrl::FullyEncoded));
2851 const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator(
"ViewMode"));
2852 settings.setValue(
"viewMode", QLatin1StringView(viewModeMeta.key(q->viewMode())));
2853 settings.setValue(
"qtVersion", QT_VERSION_STR
""_L1);
2856bool QFileDialogPrivate::restoreFromSettings()
2859 QSettings settings(QSettings::UserScope, u"QtProject"_s);
2860 if (!settings.childGroups().contains(
"FileDialog"_L1))
2862 settings.beginGroup(
"FileDialog");
2864 q->setDirectoryUrl(lastVisitedDir()->isEmpty() ? settings.value(
"lastVisited").toUrl() : *lastVisitedDir());
2866 QByteArray viewModeStr = settings.value(
"viewMode").toString().toLatin1();
2867 const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator(
"ViewMode"));
2869 int viewMode = viewModeMeta.keyToValue(viewModeStr.constData(), &ok);
2871 viewMode = QFileDialog::List;
2872 q->setViewMode(
static_cast<QFileDialog::ViewMode>(viewMode));
2874 sidebarUrls = QUrl::fromStringList(settings.value(
"shortcuts").toStringList());
2875 headerData = settings.value(
"treeViewHeader").toByteArray();
2877 if (!usingWidgets())
2880 QStringList history;
2881 const auto urlStrings = settings.value(
"history").toStringList();
2882 for (
const QString &urlStr : urlStrings) {
2884 if (url.isLocalFile())
2885 history << url.toLocalFile();
2888 return restoreWidgetState(history, settings.value(
"sidebarWidth", -1).toInt());
2892bool QFileDialogPrivate::restoreWidgetState(QStringList &history,
int splitterPosition)
2895 if (splitterPosition >= 0) {
2896 QList<
int> splitterSizes;
2897 splitterSizes.append(splitterPosition);
2898 splitterSizes.append(qFileDialogUi->splitter->widget(1)->sizeHint().width());
2899 qFileDialogUi->splitter->setSizes(splitterSizes);
2901 if (!qFileDialogUi->splitter->restoreState(splitterState))
2903 QList<
int> list = qFileDialogUi->splitter->sizes();
2904 if (list.size() >= 2 && (list.at(0) == 0 || list.at(1) == 0)) {
2905 for (
int i = 0; i < list.size(); ++i)
2906 list[i] = qFileDialogUi->splitter->widget(i)->sizeHint().width();
2907 qFileDialogUi->splitter->setSizes(list);
2911 qFileDialogUi->sidebar->setUrls(sidebarUrls);
2913 static const int MaxHistorySize = 5;
2914 if (history.size() > MaxHistorySize)
2915 history.erase(history.begin(), history.end() - MaxHistorySize);
2916 q->setHistory(history);
2918 QHeaderView *headerView = qFileDialogUi->treeView->header();
2919 if (!headerView->restoreState(headerData))
2922 QList<QAction*> actions = headerView->actions();
2923 QAbstractItemModel *abstractModel = model;
2924#if QT_CONFIG(proxymodel)
2926 abstractModel = proxyModel;
2928 const int total = qMin(abstractModel->columnCount(QModelIndex()),
int(actions.size() + 1));
2929 for (
int i = 1; i < total; ++i)
2930 actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i));
2936
2937
2938
2939
2940void QFileDialogPrivate::init(
const QFileDialogArgs &args)
2943 if (!args.caption.isEmpty()) {
2944 useDefaultCaption =
false;
2945 setWindowTitle = args.caption;
2946 q->setWindowTitle(args.caption);
2949 q->setAcceptMode(QFileDialog::AcceptOpen);
2950 nativeDialogInUse = platformFileDialogHelper() !=
nullptr;
2951 if (!nativeDialogInUse)
2953 q->setFileMode(QFileDialog::AnyFile);
2954 if (!args.filter.isEmpty())
2955 q->setNameFilter(args.filter);
2956 q->setDirectoryUrl(args.directory);
2957 if (args.directory.isLocalFile())
2958 q->selectFile(args.selection);
2960 q->selectUrl(args.directory);
2962#if QT_CONFIG(settings)
2965 if (!restoreFromSettings()) {
2966 const QSettings settings(QSettings::UserScope, u"QtProject"_s);
2967 q->restoreState(settings.value(
"Qt/filedialog").toByteArray());
2971#if defined(Q_EMBEDDED_SMALLSCREEN)
2972 qFileDialogUi->lookInLabel->setVisible(
false);
2973 qFileDialogUi->fileNameLabel->setVisible(
false);
2974 qFileDialogUi->fileTypeLabel->setVisible(
false);
2975 qFileDialogUi->sidebar->hide();
2978 const QSize sizeHint = q->sizeHint();
2979 if (sizeHint.isValid())
2980 q->resize(sizeHint);
2984
2985
2986
2987
2988void QFileDialogPrivate::createWidgets()
2997 QSize preSize = q->testAttribute(Qt::WA_Resized) ? q->size() : QSize();
2998 Qt::WindowStates preState = q->windowState();
3000 model =
new QFileSystemModel(q);
3001 model->setIconProvider(&defaultIconProvider);
3002 model->setFilter(options->filter());
3003 model->setObjectName(
"qt_filesystem_model"_L1);
3004 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
3005 model->setNameFilterDisables(helper->defaultNameFilterDisables());
3007 model->setNameFilterDisables(
false);
3008 model->d_func()->disableRecursiveSort =
true;
3009 QObjectPrivate::connect(model, &QFileSystemModel::fileRenamed,
3010 this, &QFileDialogPrivate::fileRenamed);
3011 QObjectPrivate::connect(model, &QFileSystemModel::rootPathChanged,
3012 this, &QFileDialogPrivate::pathChanged);
3013 QObjectPrivate::connect(model, &QFileSystemModel::rowsInserted,
3014 this, &QFileDialogPrivate::rowsInserted);
3015 model->setReadOnly(
false);
3017 qFileDialogUi.reset(
new Ui_QFileDialog());
3018 qFileDialogUi->setupUi(q);
3020 QList<QUrl> initialBookmarks;
3021 initialBookmarks << QUrl(
"file:"_L1)
3022 << QUrl::fromLocalFile(QDir::homePath());
3023 qFileDialogUi->sidebar->setModelAndUrls(model, initialBookmarks);
3024 QObjectPrivate::connect(qFileDialogUi->sidebar, &QSidebar::goToUrl,
3025 this, &QFileDialogPrivate::goToUrl);
3027 QObject::connect(qFileDialogUi->buttonBox, &QDialogButtonBox::accepted,
3028 q, &QFileDialog::accept);
3029 QObject::connect(qFileDialogUi->buttonBox, &QDialogButtonBox::rejected,
3030 q, &QFileDialog::reject);
3032 qFileDialogUi->lookInCombo->setFileDialogPrivate(
this);
3033 QObjectPrivate::connect(qFileDialogUi->lookInCombo, &QComboBox::textActivated,
3034 this, &QFileDialogPrivate::goToDirectory);
3036 qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert);
3037 qFileDialogUi->lookInCombo->setDuplicatesEnabled(
false);
3040#ifndef QT_NO_SHORTCUT
3041 qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit);
3043#if QT_CONFIG(fscompleter)
3044 completer =
new QFSCompleter(model, q);
3045 qFileDialogUi->fileNameEdit->setCompleter(completer);
3048 qFileDialogUi->fileNameEdit->setInputMethodHints(Qt::ImhNoPredictiveText);
3050 QObjectPrivate::connect(qFileDialogUi->fileNameEdit, &QLineEdit::textChanged,
3051 this, &QFileDialogPrivate::autoCompleteFileName);
3052 QObjectPrivate::connect(qFileDialogUi->fileNameEdit, &QLineEdit::textChanged,
3053 this, &QFileDialogPrivate::updateOkButton);
3054 QObject::connect(qFileDialogUi->fileNameEdit, &QLineEdit::returnPressed,
3055 q, &QFileDialog::accept);
3058 qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(
false);
3059 qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
3060 qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
3061 QObjectPrivate::connect(qFileDialogUi->fileTypeCombo, &QComboBox::activated,
3062 this, &QFileDialogPrivate::useNameFilter);
3063 QObject::connect(qFileDialogUi->fileTypeCombo, &QComboBox::textActivated,
3064 q, &QFileDialog::filterSelected);
3066 qFileDialogUi->listView->setFileDialogPrivate(
this);
3067 qFileDialogUi->listView->setModel(model);
3068 QObjectPrivate::connect(qFileDialogUi->listView, &QAbstractItemView::activated,
3069 this, &QFileDialogPrivate::enterDirectory);
3070 QObjectPrivate::connect(qFileDialogUi->listView, &QAbstractItemView::customContextMenuRequested,
3071 this, &QFileDialogPrivate::showContextMenu);
3072#ifndef QT_NO_SHORTCUT
3073 QShortcut *shortcut =
new QShortcut(QKeySequence::Delete, qFileDialogUi->listView);
3074 QObjectPrivate::connect(shortcut, &QShortcut::activated,
3075 this, &QFileDialogPrivate::deleteCurrent);
3078 qFileDialogUi->treeView->setFileDialogPrivate(
this);
3079 qFileDialogUi->treeView->setModel(model);
3080 QHeaderView *treeHeader = qFileDialogUi->treeView->header();
3081 QFontMetrics fm(q->font());
3082 treeHeader->resizeSection(0, fm.horizontalAdvance(
"wwwwwwwwwwwwwwwwwwwwwwwwww"_L1));
3083 treeHeader->resizeSection(1, fm.horizontalAdvance(
"128.88 GB"_L1));
3084 treeHeader->resizeSection(2, fm.horizontalAdvance(
"mp3Folder"_L1));
3085 treeHeader->resizeSection(3, fm.horizontalAdvance(
"10/29/81 02:02PM"_L1));
3086 treeHeader->setContextMenuPolicy(Qt::ActionsContextMenu);
3088 QActionGroup *showActionGroup =
new QActionGroup(q);
3089 showActionGroup->setExclusive(
false);
3090 QObjectPrivate::connect(showActionGroup, &QActionGroup::triggered,
3091 this, &QFileDialogPrivate::showHeader);
3093 QAbstractItemModel *abstractModel = model;
3094#if QT_CONFIG(proxymodel)
3096 abstractModel = proxyModel;
3098 for (
int i = 1; i < abstractModel->columnCount(QModelIndex()); ++i) {
3099 QAction *showHeader =
new QAction(showActionGroup);
3100 showHeader->setCheckable(
true);
3101 showHeader->setChecked(
true);
3102 treeHeader->addAction(showHeader);
3105 std::unique_ptr<QItemSelectionModel> selModel(qFileDialogUi->treeView->selectionModel());
3106 qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel());
3108 QObjectPrivate::connect(qFileDialogUi->treeView, &QAbstractItemView::activated,
3109 this, &QFileDialogPrivate::enterDirectory);
3110 QObjectPrivate::connect(qFileDialogUi->treeView, &QAbstractItemView::customContextMenuRequested,
3111 this, &QFileDialogPrivate::showContextMenu);
3112#ifndef QT_NO_SHORTCUT
3113 shortcut =
new QShortcut(QKeySequence::Delete, qFileDialogUi->treeView);
3114 QObjectPrivate::connect(shortcut, &QShortcut::activated,
3115 this, &QFileDialogPrivate::deleteCurrent);
3119 QItemSelectionModel *selections = qFileDialogUi->listView->selectionModel();
3120 QObjectPrivate::connect(selections, &QItemSelectionModel::selectionChanged,
3121 this, &QFileDialogPrivate::selectionChanged);
3122 QObjectPrivate::connect(selections, &QItemSelectionModel::currentChanged,
3123 this, &QFileDialogPrivate::currentChanged);
3124 qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding);
3126 createToolButtons();
3127 createMenuActions();
3129#if QT_CONFIG(settings)
3132 if (!restoreFromSettings()) {
3133 const QSettings settings(QSettings::UserScope, u"QtProject"_s);
3134 q->restoreState(settings.value(
"Qt/filedialog").toByteArray());
3139 q->setFileMode(
static_cast<QFileDialog::FileMode>(options->fileMode()));
3140 q->setAcceptMode(
static_cast<QFileDialog::AcceptMode>(options->acceptMode()));
3141 q->setViewMode(
static_cast<QFileDialog::ViewMode>(options->viewMode()));
3142 q->setOptions(
static_cast<QFileDialog::Options>(
static_cast<
int>(options->options())));
3143 if (!options->sidebarUrls().isEmpty())
3144 q->setSidebarUrls(options->sidebarUrls());
3145 q->setDirectoryUrl(options->initialDirectory());
3146#if QT_CONFIG(mimetype)
3147 if (!options->mimeTypeFilters().isEmpty())
3148 q->setMimeTypeFilters(options->mimeTypeFilters());
3151 if (!options->nameFilters().isEmpty())
3152 q->setNameFilters(options->nameFilters());
3153 q->selectNameFilter(options->initiallySelectedNameFilter());
3154 q->setDefaultSuffix(options->defaultSuffix());
3155 q->setHistory(options->history());
3156 const auto initiallySelectedFiles = options->initiallySelectedFiles();
3157 if (initiallySelectedFiles.size() == 1)
3158 q->selectFile(initiallySelectedFiles.first().fileName());
3159 for (
const QUrl &url : initiallySelectedFiles)
3161 lineEdit()->selectAll();
3163 retranslateStrings();
3164 q->resize(preSize.isValid() ? preSize : q->sizeHint());
3165 q->setWindowState(preState);
3168void QFileDialogPrivate::showHeader(QAction *action)
3171 QActionGroup *actionGroup = qobject_cast<QActionGroup*>(q->sender());
3172 qFileDialogUi->treeView->header()->setSectionHidden(
int(actionGroup->actions().indexOf(action) + 1),
3173 !action->isChecked());
3176#if QT_CONFIG(proxymodel)
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
3190 if (!d->usingWidgets())
3192 if ((!proxyModel && !d->proxyModel)
3193 || (proxyModel == d->proxyModel))
3196 QModelIndex idx = d->rootIndex();
3198 QObjectPrivate::disconnect(d->proxyModel, &QAbstractProxyModel::rowsInserted,
3199 d, &QFileDialogPrivate::rowsInserted);
3201 QObjectPrivate::disconnect(d->model, &QAbstractItemModel::rowsInserted,
3202 d, &QFileDialogPrivate::rowsInserted);
3204 if (proxyModel !=
nullptr) {
3205 proxyModel->setParent(
this);
3206 d->proxyModel = proxyModel;
3207 proxyModel->setSourceModel(d->model);
3208 d->qFileDialogUi->listView->setModel(d->proxyModel);
3209 d->qFileDialogUi->treeView->setModel(d->proxyModel);
3210#if QT_CONFIG(fscompleter)
3211 d->completer->setModel(d->proxyModel);
3212 d->completer->proxyModel = d->proxyModel;
3214 QObjectPrivate::connect(d->proxyModel, &QAbstractItemModel::rowsInserted,
3215 d, &QFileDialogPrivate::rowsInserted);
3217 d->proxyModel =
nullptr;
3218 d->qFileDialogUi->listView->setModel(d->model);
3219 d->qFileDialogUi->treeView->setModel(d->model);
3220#if QT_CONFIG(fscompleter)
3221 d->completer->setModel(d->model);
3222 d->completer->sourceModel = d->model;
3223 d->completer->proxyModel =
nullptr;
3225 QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted,
3226 d, &QFileDialogPrivate::rowsInserted);
3228 std::unique_ptr<QItemSelectionModel> selModel(d->qFileDialogUi->treeView->selectionModel());
3229 d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel());
3231 d->setRootIndex(idx);
3234 QItemSelectionModel *selections = d->qFileDialogUi->listView->selectionModel();
3235 QObjectPrivate::connect(selections, &QItemSelectionModel::selectionChanged,
3236 d, &QFileDialogPrivate::selectionChanged);
3237 QObjectPrivate::connect(selections, &QItemSelectionModel::currentChanged,
3238 d, &QFileDialogPrivate::currentChanged);
3242
3243
3244
3245
3246QAbstractProxyModel *QFileDialog::proxyModel()
const
3248 Q_D(
const QFileDialog);
3249 return d->proxyModel;
3254
3255
3256
3257
3258void QFileDialogPrivate::createToolButtons()
3261 qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack,
nullptr, q));
3262 qFileDialogUi->backButton->setAutoRaise(
true);
3263 qFileDialogUi->backButton->setEnabled(
false);
3264 QObjectPrivate::connect(qFileDialogUi->backButton, &QPushButton::clicked,
3265 this, &QFileDialogPrivate::navigateBackward);
3267 qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward,
nullptr, q));
3268 qFileDialogUi->forwardButton->setAutoRaise(
true);
3269 qFileDialogUi->forwardButton->setEnabled(
false);
3270 QObjectPrivate::connect(qFileDialogUi->forwardButton, &QPushButton::clicked,
3271 this, &QFileDialogPrivate::navigateForward);
3273 qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent,
nullptr, q));
3274 qFileDialogUi->toParentButton->setAutoRaise(
true);
3275 qFileDialogUi->toParentButton->setEnabled(
false);
3276 QObjectPrivate::connect(qFileDialogUi->toParentButton, &QPushButton::clicked,
3277 this, &QFileDialogPrivate::navigateToParent);
3279 qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView,
nullptr, q));
3280 qFileDialogUi->listModeButton->setAutoRaise(
true);
3281 qFileDialogUi->listModeButton->setDown(
true);
3282 QObjectPrivate::connect(qFileDialogUi->listModeButton, &QPushButton::clicked,
3283 this, &QFileDialogPrivate::showListView);
3285 qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView,
nullptr, q));
3286 qFileDialogUi->detailModeButton->setAutoRaise(
true);
3287 QObjectPrivate::connect(qFileDialogUi->detailModeButton, &QPushButton::clicked,
3288 this, &QFileDialogPrivate::showDetailsView);
3290 QSize toolSize(qFileDialogUi->fileNameEdit->sizeHint().height(), qFileDialogUi->fileNameEdit->sizeHint().height());
3291 qFileDialogUi->backButton->setFixedSize(toolSize);
3292 qFileDialogUi->listModeButton->setFixedSize(toolSize);
3293 qFileDialogUi->detailModeButton->setFixedSize(toolSize);
3294 qFileDialogUi->forwardButton->setFixedSize(toolSize);
3295 qFileDialogUi->toParentButton->setFixedSize(toolSize);
3297 qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder,
nullptr, q));
3298 qFileDialogUi->newFolderButton->setFixedSize(toolSize);
3299 qFileDialogUi->newFolderButton->setAutoRaise(
true);
3300 qFileDialogUi->newFolderButton->setEnabled(
false);
3301 QObjectPrivate::connect(qFileDialogUi->newFolderButton, &QPushButton::clicked,
3302 this, &QFileDialogPrivate::createDirectory);
3306
3307
3308
3309
3310void QFileDialogPrivate::createMenuActions()
3314 QAction *goHomeAction =
new QAction(q);
3315#ifndef QT_NO_SHORTCUT
3316 goHomeAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_H);
3318 QObjectPrivate::connect(goHomeAction, &QAction::triggered,
3319 this, &QFileDialogPrivate::goHome);
3320 q->addAction(goHomeAction);
3324 QAction *goToParent =
new QAction(q);
3325 goToParent->setObjectName(
"qt_goto_parent_action"_L1);
3326#ifndef QT_NO_SHORTCUT
3327 goToParent->setShortcut(Qt::CTRL | Qt::Key_Up);
3329 QObjectPrivate::connect(goToParent, &QAction::triggered,
3330 this, &QFileDialogPrivate::navigateToParent);
3331 q->addAction(goToParent);
3333 renameAction =
new QAction(q);
3334 renameAction->setEnabled(
false);
3335 renameAction->setObjectName(
"qt_rename_action"_L1);
3336 QObjectPrivate::connect(renameAction, &QAction::triggered,
3337 this, &QFileDialogPrivate::renameCurrent);
3339 deleteAction =
new QAction(q);
3340 deleteAction->setEnabled(
false);
3341 deleteAction->setObjectName(
"qt_delete_action"_L1);
3342 QObjectPrivate::connect(deleteAction, &QAction::triggered,
3343 this, &QFileDialogPrivate::deleteCurrent);
3345 showHiddenAction =
new QAction(q);
3346 showHiddenAction->setObjectName(
"qt_show_hidden_action"_L1);
3347 showHiddenAction->setCheckable(
true);
3348 QObjectPrivate::connect(showHiddenAction, &QAction::triggered,
3349 this, &QFileDialogPrivate::showHidden);
3351 newFolderAction =
new QAction(q);
3352 newFolderAction->setObjectName(
"qt_new_folder_action"_L1);
3353 QObjectPrivate::connect(newFolderAction, &QAction::triggered,
3354 this, &QFileDialogPrivate::createDirectory);
3357void QFileDialogPrivate::goHome()
3360 q->setDirectory(QDir::homePath());
3364void QFileDialogPrivate::saveHistorySelection()
3366 if (!qFileDialogUi || currentHistoryLocation < 0 || currentHistoryLocation >= currentHistory.size())
3368 auto &item = currentHistory[currentHistoryLocation];
3369 item.selection.clear();
3370 const auto selectedIndexes = qFileDialogUi->listView->selectionModel()->selectedRows();
3371 for (
const auto &index : selectedIndexes)
3372 item.selection.append(QPersistentModelIndex(index));
3376
3377
3378
3379
3380void QFileDialogPrivate::pathChanged(
const QString &newPath)
3383 qFileDialogUi->toParentButton->setEnabled(QFileInfo::exists(model->rootPath()));
3384 qFileDialogUi->sidebar->selectUrl(QUrl::fromLocalFile(newPath));
3385 q->setHistory(qFileDialogUi->lookInCombo->history());
3387 const QString newNativePath = QDir::toNativeSeparators(newPath);
3390 if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation).path != newNativePath) {
3391 if (currentHistoryLocation >= 0)
3392 saveHistorySelection();
3393 while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.size()) {
3394 currentHistory.removeLast();
3396 currentHistory.append({newNativePath, PersistentModelIndexList()});
3397 ++currentHistoryLocation;
3399 qFileDialogUi->forwardButton->setEnabled(currentHistory.size() - currentHistoryLocation > 1);
3400 qFileDialogUi->backButton->setEnabled(currentHistoryLocation > 0);
3403void QFileDialogPrivate::navigate(HistoryItem &historyItem)
3406 q->setDirectory(historyItem.path);
3408 if (!qFileDialogUi || historyItem.selection.isEmpty())
3410 if (std::any_of(historyItem.selection.cbegin(), historyItem.selection.cend(),
3411 [](
const QPersistentModelIndex &i) {
return !i.isValid(); })) {
3412 historyItem.selection.clear();
3416 QAbstractItemView *view = q->viewMode() == QFileDialog::List
3417 ?
static_cast<QAbstractItemView *>(qFileDialogUi->listView)
3418 :
static_cast<QAbstractItemView *>(qFileDialogUi->treeView);
3419 auto selectionModel = view->selectionModel();
3420 const QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Select
3421 | QItemSelectionModel::Rows;
3422 selectionModel->select(historyItem.selection.constFirst(),
3423 flags | QItemSelectionModel::Clear | QItemSelectionModel::Current);
3424 auto it = historyItem.selection.cbegin() + 1;
3425 const auto end = historyItem.selection.cend();
3426 for (; it != end; ++it)
3427 selectionModel->select(*it, flags);
3429 view->scrollTo(historyItem.selection.constFirst());
3433
3434
3435
3436
3437void QFileDialogPrivate::navigateBackward()
3439 if (!currentHistory.isEmpty() && currentHistoryLocation > 0) {
3440 saveHistorySelection();
3441 navigate(currentHistory[--currentHistoryLocation]);
3446
3447
3448
3449
3450void QFileDialogPrivate::navigateForward()
3452 if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) {
3453 saveHistorySelection();
3454 navigate(currentHistory[++currentHistoryLocation]);
3459
3460
3461
3462
3463
3464void QFileDialogPrivate::navigateToParent()
3467 QDir dir(model->rootDirectory());
3468 QString newDirectory;
3470 newDirectory = model->myComputer().toString();
3473 newDirectory = dir.absolutePath();
3475 q->setDirectory(newDirectory);
3476 emit q->directoryEntered(newDirectory);
3480
3481
3482
3483
3484void QFileDialogPrivate::createDirectory()
3487 qFileDialogUi->listView->clearSelection();
3489 QString newFolderString = QFileDialog::tr(
"New Folder");
3490 QString folderName = newFolderString;
3491 QString prefix = q->directory().absolutePath() + QDir::separator();
3492 if (QFile::exists(prefix + folderName)) {
3493 qlonglong suffix = 2;
3494 while (QFile::exists(prefix + folderName)) {
3495 folderName = newFolderString + QString::number(suffix++);
3499 QModelIndex parent = rootIndex();
3500 QModelIndex index = model->mkdir(parent, folderName);
3501 if (!index.isValid())
3504 index = select(index);
3505 if (index.isValid()) {
3506 qFileDialogUi->treeView->setCurrentIndex(index);
3507 currentView()->edit(index);
3511void QFileDialogPrivate::showListView()
3513 qFileDialogUi->listModeButton->setDown(
true);
3514 qFileDialogUi->detailModeButton->setDown(
false);
3515 qFileDialogUi->treeView->hide();
3516 qFileDialogUi->listView->show();
3517 qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->listView->parentWidget());
3518 qFileDialogUi->listView->doItemsLayout();
3521void QFileDialogPrivate::showDetailsView()
3523 qFileDialogUi->listModeButton->setDown(
false);
3524 qFileDialogUi->detailModeButton->setDown(
true);
3525 qFileDialogUi->listView->hide();
3526 qFileDialogUi->treeView->show();
3527 qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->treeView->parentWidget());
3528 qFileDialogUi->treeView->doItemsLayout();
3532
3533
3534
3535
3536void QFileDialogPrivate::showContextMenu(
const QPoint &position)
3542 QAbstractItemView *view =
nullptr;
3543 if (q->viewMode() == QFileDialog::Detail)
3544 view = qFileDialogUi->treeView;
3546 view = qFileDialogUi->listView;
3547 QModelIndex index = view->indexAt(position);
3548 index = mapToSource(index.sibling(index.row(), 0));
3550 QMenu *menu =
new QMenu(view);
3551 menu->setAttribute(Qt::WA_DeleteOnClose);
3553 if (index.isValid()) {
3555 const bool ro = model && model->isReadOnly();
3556 QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
3557 renameAction->setEnabled(!ro && p & QFile::WriteUser);
3558 menu->addAction(renameAction);
3559 deleteAction->setEnabled(!ro && p & QFile::WriteUser);
3560 menu->addAction(deleteAction);
3561 menu->addSeparator();
3563 menu->addAction(showHiddenAction);
3564 if (qFileDialogUi->newFolderButton->isVisible()) {
3565 newFolderAction->setEnabled(qFileDialogUi->newFolderButton->isEnabled());
3566 menu->addAction(newFolderAction);
3568 menu->popup(view->viewport()->mapToGlobal(position));
3574
3575
3576void QFileDialogPrivate::renameCurrent()
3579 QModelIndex index = qFileDialogUi->listView->currentIndex();
3580 index = index.sibling(index.row(), 0);
3581 if (q->viewMode() == QFileDialog::List)
3582 qFileDialogUi->listView->edit(index);
3584 qFileDialogUi->treeView->edit(index);
3587bool QFileDialogPrivate::removeDirectory(
const QString &path)
3589 QModelIndex modelIndex = model->index(path);
3590 return model->remove(modelIndex);
3594
3595
3596
3597
3598void QFileDialogPrivate::deleteCurrent()
3600 if (model->isReadOnly())
3603 const QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
3604 for (
auto it = list.crbegin(), end = list.crend(); it != end; ++it) {
3605 QPersistentModelIndex index = *it;
3606 if (index == qFileDialogUi->listView->rootIndex())
3609 index = mapToSource(index.sibling(index.row(), 0));
3610 if (!index.isValid())
3613 QString fileName = index.data(QFileSystemModel::FileNameRole).toString();
3614 QString filePath = index.data(QFileSystemModel::FilePathRole).toString();
3616 QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
3617#if QT_CONFIG(messagebox)
3619 if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), QFileDialog::tr(
"Delete"),
3620 QFileDialog::tr(
"'%1' is write protected.\nDo you want to delete it anyway?")
3622 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No))
3624 else if (QMessageBox::warning(q_func(), QFileDialog::tr(
"Delete"),
3625 QFileDialog::tr(
"Are you sure you want to delete '%1'?")
3627 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
3631 if (!index.isValid())
3635 if (!(p & QFile::WriteUser))
3639 if (model->isDir(index) && !model->fileInfo(index).isSymLink()) {
3640 if (!removeDirectory(filePath)) {
3641#if QT_CONFIG(messagebox)
3642 QMessageBox::warning(q, q->windowTitle(),
3643 QFileDialog::tr(
"Could not delete directory."));
3647 model->remove(index);
3652void QFileDialogPrivate::autoCompleteFileName(
const QString &text)
3654 if (text.startsWith(
"//"_L1) || text.startsWith(u'\\')) {
3655 qFileDialogUi->listView->selectionModel()->clearSelection();
3659 const QStringList multipleFiles = typedFiles();
3660 if (multipleFiles.size() > 0) {
3661 QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows();
3662 QList<QModelIndex> newFiles;
3663 for (
const auto &file : multipleFiles) {
3664 QModelIndex idx = model->index(file);
3665 if (oldFiles.removeAll(idx) == 0)
3666 newFiles.append(idx);
3668 for (
const auto &newFile : std::as_const(newFiles))
3670 if (lineEdit()->hasFocus()) {
3671 auto *sm = qFileDialogUi->listView->selectionModel();
3672 for (
const auto &oldFile : std::as_const(oldFiles))
3673 sm->select(oldFile, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
3679
3680
3681void QFileDialogPrivate::updateOkButton()
3684 QPushButton *button = qFileDialogUi->buttonBox->button((q->acceptMode() == QFileDialog::AcceptOpen)
3685 ? QDialogButtonBox::Open : QDialogButtonBox::Save);
3688 const QFileDialog::FileMode fileMode = q->fileMode();
3690 bool enableButton =
true;
3691 bool isOpenDirectory =
false;
3693 const QStringList files = q->selectedFiles();
3694 QString lineEditText = lineEdit()->text();
3696 if (lineEditText.startsWith(
"//"_L1) || lineEditText.startsWith(u'\\')) {
3697 button->setEnabled(
true);
3698 updateOkButtonText();
3702 if (files.isEmpty()) {
3703 enableButton =
false;
3704 }
else if (lineEditText ==
".."_L1) {
3705 isOpenDirectory =
true;
3708 case QFileDialog::Directory: {
3709 QString fn = files.first();
3710 QModelIndex idx = model->index(fn);
3712 idx = model->index(getEnvironmentVariable(fn));
3713 if (!idx.isValid() || !model->isDir(idx))
3714 enableButton =
false;
3717 case QFileDialog::AnyFile: {
3718 QString fn = files.first();
3720 QModelIndex idx = model->index(fn);
3724 fileDir = info.canonicalFilePath();
3726 fileDir = fn.mid(0, fn.lastIndexOf(u'/'));
3727 fileName = fn.mid(fileDir.size() + 1);
3729 if (lineEditText.contains(
".."_L1)) {
3730 fileDir = info.canonicalFilePath();
3731 fileName = info.fileName();
3734 if (fileDir == q->directory().canonicalPath() && fileName.isEmpty()) {
3735 enableButton =
false;
3738 if (idx.isValid() && model->isDir(idx)) {
3739 isOpenDirectory =
true;
3740 enableButton =
true;
3743 if (!idx.isValid()) {
3744 const long maxLength = maxNameLength(fileDir);
3745 enableButton = maxLength < 0 || fileName.size() <= maxLength;
3749 case QFileDialog::ExistingFile:
3750 case QFileDialog::ExistingFiles:
3751 for (
const auto &file : files) {
3752 QModelIndex idx = model->index(file);
3754 idx = model->index(getEnvironmentVariable(file));
3755 if (!idx.isValid()) {
3756 enableButton =
false;
3759 if (idx.isValid() && model->isDir(idx)) {
3760 isOpenDirectory =
true;
3770 button->setEnabled(enableButton);
3771 updateOkButtonText(isOpenDirectory);
3775
3776
3777void QFileDialogPrivate::currentChanged(
const QModelIndex &index)
3780 emit q_func()->currentChanged(index.data(QFileSystemModel::FilePathRole).toString());
3784
3785
3786
3787
3788
3789void QFileDialogPrivate::enterDirectory(
const QModelIndex &index)
3793 QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index;
3794 QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString();
3795 if (path.isEmpty() || model->isDir(sourceIndex)) {
3796 if (q->directory().path() == path)
3799 const QFileDialog::FileMode fileMode = q->fileMode();
3800 q->setDirectory(path);
3801 emit q->directoryEntered(path);
3802 if (fileMode == QFileDialog::Directory) {
3804 lineEdit()->setText(QString());
3805 lineEdit()->clear();
3809 if ((!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick,
nullptr, qFileDialogUi->treeView)
3810 || q->fileMode() != QFileDialog::ExistingFiles || !(QGuiApplication::keyboardModifiers() & Qt::CTRL))
3811 && index.model()->flags(index) & Qt::ItemIsEnabled) {
3818
3819
3820
3821
3822
3823void QFileDialogPrivate::goToDirectory(
const QString &path)
3825 enum { UrlRole = Qt::UserRole + 1 };
3827 #if QT_CONFIG(messagebox)
3830 QModelIndex index = qFileDialogUi->lookInCombo->model()->index(qFileDialogUi->lookInCombo->currentIndex(),
3831 qFileDialogUi->lookInCombo->modelColumn(),
3832 qFileDialogUi->lookInCombo->rootModelIndex());
3833 QString path2 = path;
3834 if (!index.isValid())
3835 index = mapFromSource(model->index(getEnvironmentVariable(path)));
3837 path2 = index.data(UrlRole).toUrl().toLocalFile();
3838 index = mapFromSource(model->index(path2));
3842 dir.setPath(getEnvironmentVariable(path2));
3844 if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) {
3845 enterDirectory(index);
3846#if QT_CONFIG(messagebox)
3848 QString message = QFileDialog::tr(
"%1\nDirectory not found.\nPlease verify the "
3849 "correct directory name was given.");
3850 QMessageBox::warning(q, q->windowTitle(), message.arg(path2));
3856
3857
3858
3859
3860
3861void QFileDialogPrivate::useNameFilter(
int index)
3863 QStringList nameFilters = options->nameFilters();
3864 if (index == nameFilters.size()) {
3865 QAbstractItemModel *comboModel = qFileDialogUi->fileTypeCombo->model();
3866 nameFilters.append(comboModel->index(comboModel->rowCount() - 1, 0).data().toString());
3867 options->setNameFilters(nameFilters);
3870 QString nameFilter = nameFilters.at(index);
3871 QStringList newNameFilters = QPlatformFileDialogHelper::cleanFilterList(nameFilter);
3872 if (q_func()->acceptMode() == QFileDialog::AcceptSave) {
3873 QString newNameFilterExtension;
3874 if (newNameFilters.size() > 0)
3875 newNameFilterExtension = QFileInfo(newNameFilters.at(0)).suffix();
3877 QString fileName = lineEdit()->text();
3878 const QString fileNameExtension = QFileInfo(fileName).suffix();
3879 if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) {
3880 const qsizetype fileNameExtensionLength = fileNameExtension.size();
3881 fileName.replace(fileName.size() - fileNameExtensionLength,
3882 fileNameExtensionLength, newNameFilterExtension);
3883 qFileDialogUi->listView->clearSelection();
3884 lineEdit()->setText(fileName);
3888 model->setNameFilters(newNameFilters);
3892
3893
3894
3895
3896
3897void QFileDialogPrivate::selectionChanged()
3899 const QFileDialog::FileMode fileMode = q_func()->fileMode();
3900 const QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
3901 bool stripDirs = fileMode != QFileDialog::Directory;
3903 QStringList allFiles;
3904 for (
const auto &index : indexes) {
3905 if (stripDirs && model->isDir(mapToSource(index)))
3907 allFiles.append(index.data().toString());
3909 if (allFiles.size() > 1)
3910 for (qsizetype i = 0; i < allFiles.size(); ++i) {
3911 allFiles.replace(i, QString(u'"' + allFiles.at(i) + u'"'));
3914 QString finalFiles = allFiles.join(u' ');
3915 if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible())
3916 lineEdit()->setText(finalFiles);
3922
3923
3924
3925
3926void QFileDialogPrivate::showHidden()
3929 QDir::Filters dirFilters = q->filter();
3930 dirFilters.setFlag(QDir::Hidden, showHiddenAction->isChecked());
3931 q->setFilter(dirFilters);
3935
3936
3937
3938
3939
3940void QFileDialogPrivate::rowsInserted(
const QModelIndex &parent)
3942 if (!qFileDialogUi->treeView
3943 || parent != qFileDialogUi->treeView->rootIndex()
3944 || !qFileDialogUi->treeView->selectionModel()
3945 || qFileDialogUi->treeView->selectionModel()->hasSelection()
3946 || qFileDialogUi->treeView->model()->rowCount(parent) == 0)
3950void QFileDialogPrivate::fileRenamed(
const QString &path,
const QString &oldName,
const QString &newName)
3952 const QFileDialog::FileMode fileMode = q_func()->fileMode();
3953 if (fileMode == QFileDialog::Directory) {
3954 if (path == rootPath() && lineEdit()->text() == oldName)
3955 lineEdit()->setText(newName);
3959void QFileDialogPrivate::emitUrlSelected(
const QUrl &file)
3962 emit q->urlSelected(file);
3963 if (file.isLocalFile())
3964 emit q->fileSelected(file.toLocalFile());
3967void QFileDialogPrivate::emitUrlsSelected(
const QList<QUrl> &files)
3970 emit q->urlsSelected(files);
3971 QStringList localFiles;
3972 for (
const QUrl &file : files)
3973 if (file.isLocalFile())
3974 localFiles.append(file.toLocalFile());
3975 if (!localFiles.isEmpty())
3976 emit q->filesSelected(localFiles);
3979void QFileDialogPrivate::nativeCurrentChanged(
const QUrl &file)
3982 emit q->currentUrlChanged(file);
3983 if (file.isLocalFile())
3984 emit q->currentChanged(file.toLocalFile());
3987void QFileDialogPrivate::nativeEnterDirectory(
const QUrl &directory)
3990 emit q->directoryUrlEntered(directory);
3991 if (!directory.isEmpty()) {
3992 *lastVisitedDir() = directory;
3993 if (directory.isLocalFile())
3994 emit q->directoryEntered(directory.toLocalFile());
3999
4000
4001
4002
4003
4004
4005bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
4007#if QT_CONFIG(shortcut)
4009 if (event->matches(QKeySequence::Cancel)) {
4014 switch (event->key()) {
4015 case Qt::Key_Backspace:
4020 if (event->key() == Qt::Key_Back || event->modifiers() == Qt::AltModifier) {
4031QString QFileDialogPrivate::getEnvironmentVariable(
const QString &string)
4034 if (string.size() > 1 && string.startsWith(u'$')) {
4035 return qEnvironmentVariable(QStringView{string}.mid(1).toLatin1().constData());
4038 if (string.size() > 2 && string.startsWith(u'%') && string.endsWith(u'%')) {
4039 return qEnvironmentVariable(QStringView{string}.mid(1, string.size() - 2).toLatin1().constData());
4047 urlModel =
new QUrlModel(
this);
4048 urlModel->showFullPath =
true;
4049 urlModel->setFileSystemModel(d_ptr->model);
4055 if (model()->rowCount() > 1)
4056 QComboBox::showPopup();
4058 urlModel->setUrls(QList<QUrl>());
4060 QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
4061 while (idx.isValid()) {
4062 QUrl url = QUrl::fromLocalFile(idx.data(QFileSystemModel::FilePathRole).toString());
4068 list.append(QUrl(
"file:"_L1));
4069 urlModel->addUrls(list, 0);
4070 idx = model()->index(model()->rowCount() - 1, 0);
4074 for (
int i = 0; i < m_history.size(); ++i) {
4075 QUrl path = QUrl::fromLocalFile(m_history.at(i));
4076 if (!urls.contains(path))
4079 if (urls.size() > 0) {
4080 model()->insertRow(model()->rowCount());
4081 idx = model()->index(model()->rowCount()-1, 0);
4083 model()->setData(idx, QFileDialog::tr(
"Recent Places"));
4084 QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model());
4086 Qt::ItemFlags flags = m->flags(idx);
4087 flags &= ~Qt::ItemIsEnabled;
4088 m->item(idx.row(), idx.column())->setFlags(flags);
4090 urlModel->addUrls(urls, -1,
false);
4094 QComboBox::showPopup();
4100 QStylePainter painter(
this);
4101 painter.setPen(palette().color(QPalette::Text));
4104 QStyleOptionComboBox opt;
4105 initStyleOption(&opt);
4107 QRect editRect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
4108 QStyle::SC_ComboBoxEditField,
this);
4109 int size = editRect.width() - opt.iconSize.width() - 4;
4110 opt.currentText = opt.fontMetrics.elidedText(opt.currentText, Qt::ElideMiddle, size);
4111 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
4114 painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
4120 setSelectionBehavior(QAbstractItemView::SelectRows);
4122 setResizeMode(QListView::Adjust);
4123 setEditTriggers(QAbstractItemView::EditKeyPressed);
4124 setContextMenuPolicy(Qt::CustomContextMenu);
4125#if QT_CONFIG(draganddrop)
4126 setDragDropMode(QAbstractItemView::InternalMove);
4132 int height = qMax(10, sizeHintForRow(0));
4133 return QSize(QListView::sizeHint().width() * 2, height * 30);
4138 if (!d_ptr->itemViewKeyboardEvent(e))
4139 QListView::keyPressEvent(e);
4146 setSelectionBehavior(QAbstractItemView::SelectRows);
4147 setRootIsDecorated(
false);
4148 setItemsExpandable(
false);
4149 setSortingEnabled(
true);
4150 header()->setSortIndicator(0, Qt::AscendingOrder);
4151 header()->setStretchLastSection(
false);
4152 setTextElideMode(Qt::ElideMiddle);
4153 setEditTriggers(QAbstractItemView::EditKeyPressed);
4154 setContextMenuPolicy(Qt::CustomContextMenu);
4155#if QT_CONFIG(draganddrop)
4156 setDragDropMode(QAbstractItemView::InternalMove);
4162 if (!d_ptr->itemViewKeyboardEvent(e))
4163 QTreeView::keyPressEvent(e);
4169 int height = qMax(10, sizeHintForRow(0));
4170 QSize sizeHint = header()->sizeHint();
4171 return QSize(sizeHint.width() * 4, height * 30);
4175
4176
4177
4178
4181
4182
4183
4186#if QT_CONFIG(shortcut)
4189 QLineEdit::keyPressEvent(e);
4190#if QT_CONFIG(shortcut)
4191 if (!e->matches(QKeySequence::Cancel) && key != Qt::Key_Back)
4196#if QT_CONFIG(fscompleter)
4198QString QFSCompleter::pathFromIndex(
const QModelIndex &index)
const
4200 const QFileSystemModel *dirModel;
4202 dirModel = qobject_cast<
const QFileSystemModel *>(proxyModel->sourceModel());
4204 dirModel = sourceModel;
4205 QString currentLocation = dirModel->rootPath();
4206 QString path = index.data(QFileSystemModel::FilePathRole).toString();
4207 if (!currentLocation.isEmpty() && path.startsWith(currentLocation)) {
4208#if defined(Q_OS_UNIX)
4209 if (currentLocation == QDir::separator())
4210 return path.remove(0, currentLocation.size());
4212 if (currentLocation.endsWith(u'/'))
4213 return path.remove(0, currentLocation.size());
4215 return path.remove(0, currentLocation.size()+1);
4217 return index.data(QFileSystemModel::FilePathRole).toString();
4220QStringList QFSCompleter::splitPath(
const QString &path)
const
4223 return QStringList(completionPrefix());
4225 QString pathCopy = QDir::toNativeSeparators(path);
4226 QChar sep = QDir::separator();
4227#if defined(Q_OS_WIN)
4228 if (pathCopy ==
"\\"_L1 || pathCopy ==
"\\\\"_L1)
4229 return QStringList(pathCopy);
4230 QString doubleSlash(
"\\\\"_L1);
4231 if (pathCopy.startsWith(doubleSlash))
4232 pathCopy = pathCopy.mid(2);
4234 doubleSlash.clear();
4235#elif defined(Q_OS_UNIX)
4237 QString tildeExpanded = qt_tildeExpansion(pathCopy);
4238 if (tildeExpanded != pathCopy) {
4239 QFileSystemModel *dirModel;
4241 dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel());
4243 dirModel = sourceModel;
4244 dirModel->fetchMore(dirModel->index(tildeExpanded));
4246 pathCopy = std::move(tildeExpanded);
4250#if defined(Q_OS_WIN)
4251 QStringList parts = pathCopy.split(sep, Qt::SkipEmptyParts);
4252 if (!doubleSlash.isEmpty() && !parts.isEmpty())
4253 parts[0].prepend(doubleSlash);
4254 if (pathCopy.endsWith(sep))
4255 parts.append(QString());
4257 QStringList parts = pathCopy.split(sep);
4258 if (pathCopy[0] == sep)
4262#if defined(Q_OS_WIN)
4263 bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(u':');
4265 bool startsFromRoot = pathCopy[0] == sep;
4267 if (parts.size() == 1 || (parts.size() > 1 && !startsFromRoot)) {
4268 const QFileSystemModel *dirModel;
4270 dirModel = qobject_cast<
const QFileSystemModel *>(proxyModel->sourceModel());
4272 dirModel = sourceModel;
4273 QString currentLocation = QDir::toNativeSeparators(dirModel->rootPath());
4274#if defined(Q_OS_WIN)
4275 if (currentLocation.endsWith(u':'))
4276 currentLocation.append(sep);
4278 if (currentLocation.contains(sep) && path != currentLocation) {
4279 QStringList currentLocationList = splitPath(currentLocation);
4280 while (!currentLocationList.isEmpty() && parts.size() > 0 && parts.at(0) ==
".."_L1) {
4281 parts.removeFirst();
4282 currentLocationList.removeLast();
4284 if (!currentLocationList.isEmpty() && currentLocationList.constLast().isEmpty())
4285 currentLocationList.removeLast();
4286 return currentLocationList + parts;
4297#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={})