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

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