1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QFILEDIALOG_P_H
5#define QFILEDIALOG_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtWidgets/private/qtwidgetsglobal_p.h>
19
20#include "qfiledialog.h"
21#include "private/qdialog_p.h"
22#include "qplatformdefs.h"
23
24#include <QtGui/private/qfilesystemmodel_p.h>
25#include <qlistview.h>
26#include <qtreeview.h>
27#include <qcombobox.h>
28#include <qtoolbutton.h>
29#include <qlabel.h>
30#include <qevent.h>
31#include <qlineedit.h>
32#include <qurl.h>
33#include <qstackedwidget.h>
34#include <qdialogbuttonbox.h>
35#include <qabstractproxymodel.h>
36#include <qfileiconprovider.h>
37#if QT_CONFIG(completer)
38#include <qcompleter.h>
39#endif
40#include <qpointer.h>
41#include "qsidebar_p.h"
42#if QT_CONFIG(fscompleter)
43#include "qfscompleter_p.h"
44#endif
45
46#if defined (Q_OS_UNIX)
47#include <unistd.h>
48#endif
49
50QT_REQUIRE_CONFIG(filedialog);
51
52QT_BEGIN_NAMESPACE
53
54class QFileDialogListView;
55class QFileDialogTreeView;
56class QFileDialogLineEdit;
57class QGridLayout;
58class QCompleter;
59class QHBoxLayout;
60class Ui_QFileDialog;
61class QPlatformDialogHelper;
62
63struct QFileDialogArgs
64{
65 QFileDialogArgs(const QUrl &url = {});
66
67 QWidget *parent = nullptr;
68 QString caption;
69 QUrl directory;
70 QString selection;
71 QString filter;
72 QFileDialog::FileMode mode = QFileDialog::AnyFile;
73 QFileDialog::Options options = {};
74};
75
76class Q_WIDGETS_EXPORT QFileDialogPrivate : public QDialogPrivate
77{
78 Q_DECLARE_PUBLIC(QFileDialog)
79
80public:
81 using PersistentModelIndexList = QList<QPersistentModelIndex>;
82
83 struct HistoryItem
84 {
85 QString path;
86 PersistentModelIndexList selection;
87 };
88
89 QFileDialogPrivate();
90
91 QPlatformFileDialogHelper *platformFileDialogHelper() const
92 { return static_cast<QPlatformFileDialogHelper *>(platformHelper()); }
93
94 void createToolButtons();
95 void createMenuActions();
96 void createWidgets();
97
98 void init(const QFileDialogArgs &args);
99 bool itemViewKeyboardEvent(QKeyEvent *event);
100 QString getEnvironmentVariable(const QString &string);
101 QStringList typedFiles() const;
102 QList<QUrl> userSelectedFiles() const;
103 QStringList addDefaultSuffixToFiles(const QStringList &filesToFix) const;
104 QList<QUrl> addDefaultSuffixToUrls(const QList<QUrl> &urlsToFix) const;
105 bool removeDirectory(const QString &path);
106 void setLabelTextControl(QFileDialog::DialogLabel label, const QString &text);
107 inline void updateLookInLabel();
108 inline void updateFileNameLabel();
109 inline void updateFileTypeLabel();
110 void updateOkButtonText(bool saveAsOnFolder = false);
111 void updateCancelButtonText();
112
113 inline QModelIndex mapToSource(const QModelIndex &index) const;
114 inline QModelIndex mapFromSource(const QModelIndex &index) const;
115 inline QModelIndex rootIndex() const;
116 inline void setRootIndex(const QModelIndex &index) const;
117 inline QModelIndex select(const QModelIndex &index) const;
118 inline QString rootPath() const;
119
120 QLineEdit *lineEdit() const;
121
122 static long maxNameLength(const QString &path);
123
124 QString basename(const QString &path) const
125 {
126 const qsizetype separator = QDir::toNativeSeparators(pathName: path).lastIndexOf(c: QDir::separator());
127 if (separator != -1)
128 return path.mid(position: separator + 1);
129 return path;
130 }
131
132 QDir::Filters filterForMode(QDir::Filters filters) const
133 {
134 filters |= QDir::Drives | QDir::AllDirs | QDir::Dirs | QDir::Files;
135 if (q_func()->testOption(option: QFileDialog::ShowDirsOnly))
136 filters &= ~QDir::Files;
137 return filters;
138 }
139
140 QAbstractItemView *currentView() const;
141
142 static inline QString toInternal(const QString &path)
143 {
144#if defined(Q_OS_WIN)
145 QString n(path);
146 n.replace(u'\\', u'/');
147 return n;
148#else // the compile should optimize away this
149 return path;
150#endif
151 }
152
153#if QT_CONFIG(settings)
154 void saveSettings();
155 bool restoreFromSettings();
156#endif
157
158 bool restoreWidgetState(QStringList &history, int splitterPosition);
159 static void setLastVisitedDirectory(const QUrl &dir);
160 void retranslateWindowTitle();
161 void retranslateStrings();
162 void emitFilesSelected(const QStringList &files);
163 void saveHistorySelection();
164
165 void goHome();
166 void pathChanged(const QString &);
167 void navigate(HistoryItem &);
168 void navigateBackward();
169 void navigateForward();
170 void navigateToParent();
171 void createDirectory();
172 void showListView();
173 void showDetailsView();
174 void showContextMenu(const QPoint &position);
175 void renameCurrent();
176 void deleteCurrent();
177 void showHidden();
178 void showHeader(QAction *);
179 void updateOkButton();
180 void currentChanged(const QModelIndex &index);
181 void enterDirectory(const QModelIndex &index);
182 void emitUrlSelected(const QUrl &file);
183 void emitUrlsSelected(const QList<QUrl> &files);
184 void nativeCurrentChanged(const QUrl &file);
185 void nativeEnterDirectory(const QUrl &directory);
186 void goToDirectory(const QString &);
187 void useNameFilter(int index);
188 void selectionChanged();
189 void goToUrl(const QUrl &url);
190 void autoCompleteFileName(const QString &);
191 void rowsInserted(const QModelIndex & parent);
192 void fileRenamed(const QString &path, const QString &oldName, const QString &newName);
193
194 // layout
195#if QT_CONFIG(proxymodel)
196 QAbstractProxyModel *proxyModel;
197#endif
198
199 // data
200 QStringList watching;
201 QFileSystemModel *model;
202
203#if QT_CONFIG(fscompleter)
204 QFSCompleter *completer;
205#endif //QT_CONFIG(fscompleter)
206
207 QString setWindowTitle;
208
209 QList<HistoryItem> currentHistory;
210 int currentHistoryLocation;
211
212 QAction *renameAction;
213 QAction *deleteAction;
214 QAction *showHiddenAction;
215 QAction *newFolderAction;
216
217 bool useDefaultCaption;
218
219 // setVisible_sys returns true if it ends up showing a native
220 // dialog. Returning false means that a non-native dialog must be
221 // used instead.
222 bool canBeNativeDialog() const override;
223 void setVisible(bool visible) override;
224 inline bool usingWidgets() const;
225
226 inline void setDirectory_sys(const QUrl &directory);
227 inline QUrl directory_sys() const;
228 inline void selectFile_sys(const QUrl &filename);
229 inline QList<QUrl> selectedFiles_sys() const;
230 inline void setFilter_sys();
231 inline void selectMimeTypeFilter_sys(const QString &filter);
232 inline QString selectedMimeTypeFilter_sys() const;
233 inline void selectNameFilter_sys(const QString &filter);
234 inline QString selectedNameFilter_sys() const;
235 //////////////////////////////////////////////
236
237 QScopedPointer<Ui_QFileDialog> qFileDialogUi;
238
239 QString acceptLabel;
240
241 QPointer<QObject> receiverToDisconnectOnClose;
242 QByteArray memberToDisconnectOnClose;
243 QByteArray signalToDisconnectOnClose;
244
245 QSharedPointer<QFileDialogOptions> options;
246
247 // Memory of what was read from QSettings in restoreState() in case widgets are not used
248 QByteArray splitterState;
249 QByteArray headerData;
250 QList<QUrl> sidebarUrls;
251 QFileIconProvider defaultIconProvider;
252
253 ~QFileDialogPrivate();
254
255private:
256 virtual void initHelper(QPlatformDialogHelper *) override;
257 virtual void helperPrepareShow(QPlatformDialogHelper *) override;
258 virtual void helperDone(QDialog::DialogCode, QPlatformDialogHelper *) override;
259
260 void itemNotFound(const QString &fileName, QFileDialog::FileMode mode);
261 bool itemAlreadyExists(const QString &fileName);
262 Q_DISABLE_COPY_MOVE(QFileDialogPrivate)
263};
264
265class QFileDialogLineEdit : public QLineEdit
266{
267public:
268 QFileDialogLineEdit(QWidget *parent = nullptr) : QLineEdit(parent), d_ptr(nullptr){}
269 void setFileDialogPrivate(QFileDialogPrivate *d_pointer) {d_ptr = d_pointer; }
270 void keyPressEvent(QKeyEvent *e) override;
271 bool hideOnEsc;
272private:
273 QFileDialogPrivate *d_ptr;
274};
275
276class QFileDialogComboBox : public QComboBox
277{
278public:
279 QFileDialogComboBox(QWidget *parent = nullptr) :
280 QComboBox(parent), urlModel(nullptr), d_ptr(nullptr) {}
281 void setFileDialogPrivate(QFileDialogPrivate *d_pointer);
282 void showPopup() override;
283 void setHistory(const QStringList &paths);
284 QStringList history() const { return m_history; }
285 void paintEvent(QPaintEvent *) override;
286
287private:
288 QUrlModel *urlModel;
289 QFileDialogPrivate *d_ptr;
290 QStringList m_history;
291};
292
293class QFileDialogListView : public QListView
294{
295public:
296 QFileDialogListView(QWidget *parent = nullptr) : QListView(parent), d_ptr(nullptr) {}
297 void setFileDialogPrivate(QFileDialogPrivate *d_pointer);
298 QSize sizeHint() const override;
299protected:
300 void keyPressEvent(QKeyEvent *e) override;
301private:
302 QFileDialogPrivate *d_ptr;
303};
304
305class QFileDialogTreeView : public QTreeView
306{
307public:
308 QFileDialogTreeView(QWidget *parent) : QTreeView(parent), d_ptr(nullptr) {}
309 void setFileDialogPrivate(QFileDialogPrivate *d_pointer);
310 QSize sizeHint() const override;
311
312protected:
313 void keyPressEvent(QKeyEvent *e) override;
314private:
315 QFileDialogPrivate *d_ptr;
316};
317
318QModelIndex QFileDialogPrivate::mapToSource(const QModelIndex &index) const {
319#if QT_CONFIG(proxymodel)
320 return proxyModel ? proxyModel->mapToSource(proxyIndex: index) : index;
321#else
322 return index;
323#endif
324}
325QModelIndex QFileDialogPrivate::mapFromSource(const QModelIndex &index) const {
326#if QT_CONFIG(proxymodel)
327 return proxyModel ? proxyModel->mapFromSource(sourceIndex: index) : index;
328#else
329 return index;
330#endif
331}
332
333QString QFileDialogPrivate::rootPath() const
334{
335 return (model ? model->rootPath() : QStringLiteral("/"));
336}
337
338void QFileDialogPrivate::setDirectory_sys(const QUrl &directory)
339{
340 QPlatformFileDialogHelper *helper = platformFileDialogHelper();
341
342 if (!helper)
343 return;
344
345 if (helper->isSupportedUrl(url: directory))
346 helper->setDirectory(directory);
347}
348
349QUrl QFileDialogPrivate::directory_sys() const
350{
351 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
352 return helper->directory();
353 return QUrl();
354}
355
356void QFileDialogPrivate::selectFile_sys(const QUrl &filename)
357{
358 QPlatformFileDialogHelper *helper = platformFileDialogHelper();
359
360 if (!helper)
361 return;
362
363 if (helper->isSupportedUrl(url: filename))
364 helper->selectFile(filename);
365}
366
367QList<QUrl> QFileDialogPrivate::selectedFiles_sys() const
368{
369 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
370 return helper->selectedFiles();
371 return QList<QUrl>();
372}
373
374void QFileDialogPrivate::setFilter_sys()
375{
376 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
377 helper->setFilter();
378}
379
380void QFileDialogPrivate::selectMimeTypeFilter_sys(const QString &filter)
381{
382 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
383 helper->selectMimeTypeFilter(filter);
384}
385
386QString QFileDialogPrivate::selectedMimeTypeFilter_sys() const
387{
388 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
389 return helper->selectedMimeTypeFilter();
390
391 return QString();
392}
393
394void QFileDialogPrivate::selectNameFilter_sys(const QString &filter)
395{
396 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
397 helper->selectNameFilter(filter);
398}
399
400QString QFileDialogPrivate::selectedNameFilter_sys() const
401{
402 if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
403 return helper->selectedNameFilter();
404 return QString();
405}
406
407QT_END_NAMESPACE
408
409#endif // QFILEDIALOG_P_H
410

source code of qtbase/src/widgets/dialogs/qfiledialog_p.h