1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QFILEDIALOG_P_H
43 #define QFILEDIALOG_P_H
44 
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55 
56 #ifndef QT_NO_FILEDIALOG
57 
58 #include "qfiledialog.h"
59 #include "private/qdialog_p.h"
60 #include "qplatformdefs.h"
61 
62 #include "qfilesystemmodel_p.h"
63 #include <qlistview.h>
64 #include <qtreeview.h>
65 #include <qcombobox.h>
66 #include <qtoolbutton.h>
67 #include <qlabel.h>
68 #include <qevent.h>
69 #include <qlineedit.h>
70 #include <qurl.h>
71 #include <qstackedwidget.h>
72 #include <qdialogbuttonbox.h>
73 #include <qabstractproxymodel.h>
74 #include <qcompleter.h>
75 #include <qpointer.h>
76 #include <qdebug.h>
77 #include "qsidebar_p.h"
78 #include "qfscompleter_p.h"
79 #include "private/qguiplatformplugin_p.h"
80 
81 
82 #if defined (Q_OS_UNIX)
83 #include <unistd.h>
84 #endif
85 
86 QT_BEGIN_NAMESPACE
87 
88 class QFileDialogListView;
89 class QFileDialogTreeView;
90 class QFileDialogLineEdit;
91 class QGridLayout;
92 class QCompleter;
93 class QHBoxLayout;
94 class Ui_QFileDialog;
95 
96 
97 struct QFileDialogArgs
98 {
QFileDialogArgsQFileDialogArgs99     QFileDialogArgs() : parent(0), mode(QFileDialog::AnyFile) {}
100 
101     QWidget *parent;
102     QString caption;
103     QString directory;
104     QString selection;
105     QString filter;
106     QFileDialog::FileMode mode;
107     QFileDialog::Options options;
108 };
109 
110 #define UrlRole (Qt::UserRole + 1)
111 
112 class Q_AUTOTEST_EXPORT QFileDialogPrivate : public QDialogPrivate
113 {
114     Q_DECLARE_PUBLIC(QFileDialog)
115 
116 public:
117     QFileDialogPrivate();
118 
119     void createToolButtons();
120     void createMenuActions();
121     void createWidgets();
122 
123     void init(const QString &directory = QString(), const QString &nameFilter = QString(),
124               const QString &caption = QString());
125     bool itemViewKeyboardEvent(QKeyEvent *event);
126     QString getEnvironmentVariable(const QString &string);
127     static QString workingDirectory(const QString &path);
128     static QString initialSelection(const QString &path);
129     QStringList typedFiles() const;
130     QStringList addDefaultSuffixToFiles(const QStringList filesToFix) const;
131     bool removeDirectory(const QString &path);
132 
133     inline QModelIndex mapToSource(const QModelIndex &index) const;
134     inline QModelIndex mapFromSource(const QModelIndex &index) const;
135     inline QModelIndex rootIndex() const;
136     inline void setRootIndex(const QModelIndex &index) const;
137     inline QModelIndex select(const QModelIndex &index) const;
138     inline QString rootPath() const;
139 
140     QLineEdit *lineEdit() const;
141 
maxNameLength(const QString & path)142     int maxNameLength(const QString &path) {
143 #if defined(Q_OS_UNIX)
144         return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX);
145 #elif defined(Q_OS_WIN)
146 #ifndef Q_OS_WINCE
147         DWORD maxLength;
148         QString drive = path.left(3);
149         if (::GetVolumeInformation(reinterpret_cast<const wchar_t *>(drive.utf16()), NULL, 0, NULL, &maxLength, NULL, NULL, 0) == FALSE)
150             return -1;
151         return maxLength;
152 #else
153         Q_UNUSED(path);
154         return MAX_PATH;
155 #endif //Q_OS_WINCE
156 #else
157         Q_UNUSED(path);
158 #endif
159         return -1;
160     }
161 
basename(const QString & path)162     QString basename(const QString &path) const
163     {
164         int separator = QDir::toNativeSeparators(path).lastIndexOf(QDir::separator());
165         if (separator != -1)
166             return path.mid(separator + 1);
167         return path;
168     }
169 
filterForMode(QDir::Filters filters)170     QDir::Filters filterForMode(QDir::Filters filters) const
171     {
172         if (fileMode == QFileDialog::DirectoryOnly) {
173             filters |= QDir::Drives | QDir::AllDirs | QDir::Dirs;
174             filters &= ~QDir::Files;
175         } else {
176             filters |= QDir::Drives | QDir::AllDirs | QDir::Files | QDir::Dirs;
177         }
178         return filters;
179     }
180 
181     QAbstractItemView *currentView() const;
182 
toInternal(const QString & path)183     static inline QString toInternal(const QString &path)
184     {
185 #if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
186         QString n(path);
187         for (int i = 0; i < (int)n.length(); ++i)
188             if (n[i] == QLatin1Char('\\')) n[i] = QLatin1Char('/');
189 #if defined(Q_OS_WINCE)
190         if ((n.size() > 1) && (n.startsWith(QLatin1String("//"))))
191             n = n.mid(1);
192 #endif
193         return n;
194 #else // the compile should optimize away this
195         return path;
196 #endif
197     }
198 
199     void setLastVisitedDirectory(const QString &dir);
200     void retranslateWindowTitle();
201     void retranslateStrings();
202     void emitFilesSelected(const QStringList &files);
203 
204     void _q_goHome();
205     void _q_pathChanged(const QString &);
206     void _q_navigateBackward();
207     void _q_navigateForward();
208     void _q_navigateToParent();
209     void _q_createDirectory();
210     void _q_showListView();
211     void _q_showDetailsView();
212     void _q_showContextMenu(const QPoint &position);
213     void _q_renameCurrent();
214     void _q_deleteCurrent();
215     void _q_showHidden();
216     void _q_showHeader(QAction *);
217     void _q_updateOkButton();
218     void _q_currentChanged(const QModelIndex &index);
219     void _q_enterDirectory(const QModelIndex &index);
220     void _q_goToDirectory(const QString &);
221     void _q_useNameFilter(int index);
222     void _q_selectionChanged();
223     void _q_goToUrl(const QUrl &url);
224     void _q_autoCompleteFileName(const QString &);
225     void _q_rowsInserted(const QModelIndex & parent);
226     void _q_fileRenamed(const QString &path, const QString oldName, const QString newName);
227 
228     // layout
229 #ifndef QT_NO_PROXYMODEL
230     QAbstractProxyModel *proxyModel;
231 #endif
232 
233     // data
234     QStringList watching;
235     QFileSystemModel *model;
236 
237 #ifndef QT_NO_FSCOMPLETER
238     QFSCompleter *completer;
239 #endif //QT_NO_FSCOMPLETER
240 
241     QFileDialog::FileMode fileMode;
242     QFileDialog::AcceptMode acceptMode;
243     bool confirmOverwrite;
244     QString defaultSuffix;
245     QString setWindowTitle;
246 
247     QStringList currentHistory;
248     int currentHistoryLocation;
249 
250     QAction *renameAction;
251     QAction *deleteAction;
252     QAction *showHiddenAction;
253     QAction *newFolderAction;
254 
255     bool useDefaultCaption;
256     bool defaultFileTypes;
257     bool fileNameLabelExplicitlySat;
258     QStringList nameFilters;
259 
260     // Members for using native dialogs:
261     bool nativeDialogInUse;
262     // setVisible_sys returns true if it ends up showing a native
263     // dialog. Returning false means that a non-native dialog must be
264     // used instead.
265     bool canBeNativeDialog();
266     bool setVisible_sys(bool visible);
267     void deleteNativeDialog_sys();
268     QDialog::DialogCode dialogResultCode_sys();
269 
270     void setDirectory_sys(const QString &directory);
271     QString directory_sys() const;
272     void selectFile_sys(const QString &filename);
273     QStringList selectedFiles_sys() const;
274     void setFilter_sys();
275     void setNameFilters_sys(const QStringList &filters);
276     void selectNameFilter_sys(const QString &filter);
277     QString selectedNameFilter_sys() const;
278     //////////////////////////////////////////////
279 
280 #if defined(Q_WS_MAC)
281     void *mDelegate;
282 #ifndef QT_MAC_USE_COCOA
283     NavDialogRef mDialog;
284     bool mDialogStarted;
285     bool mDialogClosed;
286     QString mCurrentLocation;
287     QString mCurrentSelection;
288     QStringList mCurrentSelectionList;
289 
290     struct QtMacFilterName {
291         QString description;
292         QString regexp;
293         QString filter;
294     };
295     struct QtMacNavFilterInfo {
QtMacNavFilterInfoQtMacNavFilterInfo296         QtMacNavFilterInfo() : currentSelection(-1) {}
297         int currentSelection;
298         QList<QtMacFilterName> filters;
299     } filterInfo;
300 
301     static void qt_mac_filedialog_event_proc(const NavEventCallbackMessage msg, NavCBRecPtr p,
302                                              NavCallBackUserData data);
303     static Boolean qt_mac_filedialog_filter_proc(AEDesc *theItem, void *info, void *data,
304                                                  NavFilterModes);
305     bool showCarbonNavServicesDialog();
306     bool hideCarbonNavServicesDialog();
307     void createNavServicesDialog();
308 #else
309     bool showCocoaFilePanel();
310     bool hideCocoaFilePanel();
311 #endif
312     void createNSOpenSavePanelDelegate();
313     void QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath);
314     void QNSOpenSavePanelDelegate_panelClosed(bool accepted);
315     void QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir);
316     void QNSOpenSavePanelDelegate_filterSelected(int menuIndex);
317     void _q_macRunNativeAppModalPanel();
318     void mac_nativeDialogModalHelp();
319 #endif
320 
321     QScopedPointer<Ui_QFileDialog> qFileDialogUi;
322 
323     QString acceptLabel;
324 
325     QPointer<QObject> receiverToDisconnectOnClose;
326     QByteArray memberToDisconnectOnClose;
327     QByteArray signalToDisconnectOnClose;
328 
329     QFileDialog::Options opts;
330 
331     ~QFileDialogPrivate();
332 
333 private:
334     Q_DISABLE_COPY(QFileDialogPrivate)
335 };
336 
337 class QFileDialogLineEdit : public QLineEdit
338 {
339 public:
QLineEdit(parent)340     QFileDialogLineEdit(QWidget *parent = 0) : QLineEdit(parent), hideOnEsc(false), d_ptr(0){}
init(QFileDialogPrivate * d_pointer)341     void init(QFileDialogPrivate *d_pointer) {d_ptr = d_pointer; }
342     void keyPressEvent(QKeyEvent *e);
343     bool hideOnEsc;
344 private:
345     QFileDialogPrivate *d_ptr;
346 };
347 
348 class QFileDialogComboBox : public QComboBox
349 {
350 public:
QComboBox(parent)351     QFileDialogComboBox(QWidget *parent = 0) : QComboBox(parent), urlModel(0) {}
352     void init(QFileDialogPrivate *d_pointer);
353     void showPopup();
354     void setHistory(const QStringList &paths);
history()355     QStringList history() const { return m_history; }
356     void paintEvent(QPaintEvent *);
357 
358 private:
359     QUrlModel *urlModel;
360     QFileDialogPrivate *d_ptr;
361     QStringList m_history;
362 };
363 
364 class QFileDialogListView : public QListView
365 {
366 public:
367     QFileDialogListView(QWidget *parent = 0);
368     void init(QFileDialogPrivate *d_pointer);
369     QSize sizeHint() const;
370 protected:
371     void keyPressEvent(QKeyEvent *e);
372 private:
373     QFileDialogPrivate *d_ptr;
374 };
375 
376 class QFileDialogTreeView : public QTreeView
377 {
378 public:
379     QFileDialogTreeView(QWidget *parent);
380     void init(QFileDialogPrivate *d_pointer);
381     QSize sizeHint() const;
382 
383 protected:
384     void keyPressEvent(QKeyEvent *e);
385 private:
386     QFileDialogPrivate *d_ptr;
387 };
388 
mapToSource(const QModelIndex & index)389 inline QModelIndex QFileDialogPrivate::mapToSource(const QModelIndex &index) const {
390 #ifdef QT_NO_PROXYMODEL
391     return index;
392 #else
393     return proxyModel ? proxyModel->mapToSource(index) : index;
394 #endif
395 }
mapFromSource(const QModelIndex & index)396 inline QModelIndex QFileDialogPrivate::mapFromSource(const QModelIndex &index) const {
397 #ifdef QT_NO_PROXYMODEL
398     return index;
399 #else
400     return proxyModel ? proxyModel->mapFromSource(index) : index;
401 #endif
402 }
403 
rootPath()404 inline QString QFileDialogPrivate::rootPath() const {
405     return model->rootPath();
406 }
407 
408 #ifndef Q_WS_MAC
409     // Dummies for platforms that don't use native dialogs:
deleteNativeDialog_sys()410     inline void QFileDialogPrivate::deleteNativeDialog_sys() { qt_guiPlatformPlugin()->fileDialogDelete(q_func()); }
setVisible_sys(bool visible)411     inline bool QFileDialogPrivate::setVisible_sys(bool visible) { return qt_guiPlatformPlugin()->fileDialogSetVisible(q_func(), visible); }
dialogResultCode_sys()412     inline QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys(){ return qt_guiPlatformPlugin()->fileDialogResultCode(q_func()); }
setDirectory_sys(const QString & directory)413     inline void QFileDialogPrivate::setDirectory_sys(const QString &directory) { qt_guiPlatformPlugin()->fileDialogSetDirectory(q_func(), directory); }
directory_sys()414     inline QString QFileDialogPrivate::directory_sys() const { return qt_guiPlatformPlugin()->fileDialogDirectory(q_func()); }
selectFile_sys(const QString & filename)415     inline void QFileDialogPrivate::selectFile_sys(const QString &filename) { qt_guiPlatformPlugin()->fileDialogSelectFile(q_func(), filename); }
selectedFiles_sys()416     inline QStringList QFileDialogPrivate::selectedFiles_sys() const { return qt_guiPlatformPlugin()->fileDialogSelectedFiles(q_func()); }
setFilter_sys()417     inline void QFileDialogPrivate::setFilter_sys() { qt_guiPlatformPlugin()->fileDialogSetFilter(q_func()); }
setNameFilters_sys(const QStringList & filters)418     inline void QFileDialogPrivate::setNameFilters_sys(const QStringList &filters) { qt_guiPlatformPlugin()->fileDialogSetNameFilters(q_func(), filters); }
selectNameFilter_sys(const QString & filter)419     inline void QFileDialogPrivate::selectNameFilter_sys(const QString &filter) { qt_guiPlatformPlugin()->fileDialogSelectNameFilter(q_func(), filter); }
selectedNameFilter_sys()420     inline QString QFileDialogPrivate::selectedNameFilter_sys() const { return qt_guiPlatformPlugin()->fileDialogSelectedNameFilter(q_func()); }
421 #endif
422 
423 QT_END_NAMESPACE
424 
425 #endif // QT_NO_FILEDIALOG
426 
427 #endif // QFILEDIALOG_P_H
428