1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qvariant.h>
43#include <private/qwidgetitemdata_p.h>
44#include "qfiledialog.h"
45
46#ifndef QT_NO_FILEDIALOG
47#include "qfiledialog_p.h"
48#include <qfontmetrics.h>
49#include <qaction.h>
50#include <qheaderview.h>
51#include <qshortcut.h>
52#include <qgridlayout.h>
53#include <qmenu.h>
54#include <qmessagebox.h>
55#include <qinputdialog.h>
56#include <stdlib.h>
57#include <qsettings.h>
58#include <qdebug.h>
59#include <qapplication.h>
60#include <qstylepainter.h>
61#include <private/qfileiconprovider_p.h>
62#if !defined(Q_WS_WINCE) && !defined(Q_OS_SYMBIAN)
63#include "ui_qfiledialog.h"
64#else
65#define Q_EMBEDDED_SMALLSCREEN
66#include "ui_qfiledialog_embedded.h"
67#if defined(Q_OS_WINCE)
68extern bool qt_priv_ptr_valid;
69#endif
70#if defined(Q_OS_UNIX)
71#include <pwd.h>
72#endif
73#endif
74
75QT_BEGIN_NAMESPACE
76
77Q_GLOBAL_STATIC(QString, lastVisitedDir)
78
79/*
80 \internal
81
82 Exported hooks that can be used to customize the static functions.
83 */
84typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options);
85Q_GUI_EXPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook = 0;
86
87typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
88Q_GUI_EXPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook = 0;
89
90typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
91Q_GUI_EXPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook = 0;
92
93typedef QString (*_qt_filedialog_save_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
94Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook = 0;
95
96/*!
97 \class QFileDialog
98 \brief The QFileDialog class provides a dialog that allow users to select files or directories.
99 \ingroup standard-dialogs
100
101
102 The QFileDialog class enables a user to traverse the file system in
103 order to select one or many files or a directory.
104
105 The easiest way to create a QFileDialog is to use the static
106 functions. On Windows, Mac OS X, KDE and GNOME, these static functions will
107 call the native file dialog when possible.
108
109 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 0
110
111 In the above example, a modal QFileDialog is created using a static
112 function. The dialog initially displays the contents of the "/home/jana"
113 directory, and displays files matching the patterns given in the
114 string "Image Files (*.png *.jpg *.bmp)". The parent of the file dialog
115 is set to \e this, and the window title is set to "Open Image".
116
117 If you want to use multiple filters, separate each one with
118 \e two semicolons. For example:
119
120 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 1
121
122 You can create your own QFileDialog without using the static
123 functions. By calling setFileMode(), you can specify what the user must
124 select in the dialog:
125
126 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 2
127
128 In the above example, the mode of the file dialog is set to
129 AnyFile, meaning that the user can select any file, or even specify a
130 file that doesn't exist. This mode is useful for creating a
131 "Save As" file dialog. Use ExistingFile if the user must select an
132 existing file, or \l Directory if only a directory may be selected.
133 See the \l QFileDialog::FileMode enum for the complete list of modes.
134
135 The fileMode property contains the mode of operation for the dialog;
136 this indicates what types of objects the user is expected to select.
137 Use setNameFilter() to set the dialog's file filter. For example:
138
139 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 3
140
141 In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"},
142 this means that only files with the extension \c png, \c xpm,
143 or \c jpg will be shown in the QFileDialog. You can apply
144 several filters by using setNameFilters(). Use selectNameFilter() to select
145 one of the filters you've given as the file dialog's default filter.
146
147 The file dialog has two view modes: \l{QFileDialog::}{List} and
148 \l{QFileDialog::}{Detail}.
149 \l{QFileDialog::}{List} presents the contents of the current directory
150 as a list of file and directory names. \l{QFileDialog::}{Detail} also
151 displays a list of file and directory names, but provides additional
152 information alongside each name, such as the file size and modification
153 date. Set the mode with setViewMode():
154
155 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 4
156
157 The last important function you will need to use when creating your
158 own file dialog is selectedFiles().
159
160 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 5
161
162 In the above example, a modal file dialog is created and shown. If
163 the user clicked OK, the file they selected is put in \c fileName.
164
165 The dialog's working directory can be set with setDirectory().
166 Each file in the current directory can be selected using
167 the selectFile() function.
168
169 The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
170 how to use QFileDialog as well as other built-in Qt dialogs.
171
172 \sa QDir, QFileInfo, QFile, QPrintDialog, QColorDialog, QFontDialog, {Standard Dialogs Example},
173 {Application Example}
174*/
175
176/*!
177 \enum QFileDialog::AcceptMode
178
179 \value AcceptOpen
180 \value AcceptSave
181*/
182
183/*!
184 \enum QFileDialog::ViewMode
185
186 This enum describes the view mode of the file dialog; i.e. what
187 information about each file will be displayed.
188
189 \value Detail Displays an icon, a name, and details for each item in
190 the directory.
191 \value List Displays only an icon and a name for each item in the
192 directory.
193
194 \sa setViewMode()
195*/
196
197/*!
198 \enum QFileDialog::FileMode
199
200 This enum is used to indicate what the user may select in the file
201 dialog; i.e. what the dialog will return if the user clicks OK.
202
203 \value AnyFile The name of a file, whether it exists or not.
204 \value ExistingFile The name of a single existing file.
205 \value Directory The name of a directory. Both files and
206 directories are displayed.
207 \value ExistingFiles The names of zero or more existing files.
208
209 This value is obsolete since Qt 4.5:
210
211 \value DirectoryOnly Use \c Directory and setOption(ShowDirsOnly, true) instead.
212
213 \sa setFileMode()
214*/
215
216/*!
217 \enum QFileDialog::Option
218
219 \value ShowDirsOnly Only show directories in the file dialog. By
220 default both files and directories are shown. (Valid only in the
221 \l Directory file mode.)
222
223 \value DontResolveSymlinks Don't resolve symlinks in the file
224 dialog. By default symlinks are resolved.
225
226 \value DontConfirmOverwrite Don't ask for confirmation if an
227 existing file is selected. By default confirmation is requested.
228
229 \value DontUseNativeDialog Don't use the native file dialog. By
230 default, the native file dialog is used unless you use a subclass
231 of QFileDialog that contains the Q_OBJECT macro.
232
233 \value ReadOnly Indicates that the model is readonly.
234
235 \value HideNameFilterDetails Indicates if the file name filter details are
236 hidden or not.
237
238 \value DontUseSheet In previous versions of Qt, the static
239 functions would create a sheet by default if the static function
240 was given a parent. This is no longer supported and does nothing in Qt 4.5, The
241 static functions will always be an application modal dialog. If
242 you want to use sheets, use QFileDialog::open() instead.
243
244 \value DontUseCustomDirectoryIcons Always use the default directory icon.
245 Some platforms allow the user to set a different icon. Custom icon lookup
246 cause a big performance impact over network or removable drives. Setting this
247 will affect the behavior of the icon provider. This enum value was added in Qt 4.8.6.
248*/
249
250/*!
251 \enum QFileDialog::DialogLabel
252
253 \value LookIn
254 \value FileName
255 \value FileType
256 \value Accept
257 \value Reject
258*/
259
260/*!
261 \fn void QFileDialog::filesSelected(const QStringList &selected)
262
263 When the selection changes and the dialog is accepted, this signal is
264 emitted with the (possibly empty) list of \a selected files.
265
266 \sa currentChanged(), QDialog::Accepted
267*/
268
269
270/*!
271 \fn void QFileDialog::fileSelected(const QString &file)
272
273 When the selection changes and the dialog is accepted, this signal is
274 emitted with the (possibly empty) selected \a file.
275
276 \sa currentChanged(), QDialog::Accepted
277*/
278
279
280/*!
281 \fn void QFileDialog::currentChanged(const QString &path)
282
283 When the current file changes, this signal is emitted with the
284 new file name as the \a path parameter.
285
286 \sa filesSelected()
287*/
288
289/*!
290 \fn void QFileDialog::directoryEntered(const QString &directory)
291 \since 4.3
292
293 This signal is emitted when the user enters a \a directory.
294*/
295
296/*!
297 \fn void QFileDialog::filterSelected(const QString &filter)
298 \since 4.3
299
300 This signal is emitted when the user selects a \a filter.
301*/
302
303#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
304bool Q_GUI_EXPORT qt_use_native_dialogs = true; // for the benefit of testing tools, until we have a proper API
305#endif
306
307QT_BEGIN_INCLUDE_NAMESPACE
308#ifdef Q_WS_WIN
309#include <qwindowsstyle.h>
310#endif
311#include <qshortcut.h>
312#ifdef Q_WS_MAC
313#include <qmacstyle_mac.h>
314#endif
315QT_END_INCLUDE_NAMESPACE
316
317/*!
318 \fn QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags flags)
319
320 Constructs a file dialog with the given \a parent and widget \a flags.
321*/
322QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags f)
323 : QDialog(*new QFileDialogPrivate, parent, f)
324{
325 Q_D(QFileDialog);
326 d->init();
327 d->lineEdit()->selectAll();
328}
329
330/*!
331 Constructs a file dialog with the given \a parent and \a caption that
332 initially displays the contents of the specified \a directory.
333 The contents of the directory are filtered before being shown in the
334 dialog, using a semicolon-separated list of filters specified by
335 \a filter.
336*/
337QFileDialog::QFileDialog(QWidget *parent,
338 const QString &caption,
339 const QString &directory,
340 const QString &filter)
341 : QDialog(*new QFileDialogPrivate, parent, 0)
342{
343 Q_D(QFileDialog);
344 d->init(directory, filter, caption);
345 d->lineEdit()->selectAll();
346}
347
348/*!
349 \internal
350*/
351QFileDialog::QFileDialog(const QFileDialogArgs &args)
352 : QDialog(*new QFileDialogPrivate, args.parent, 0)
353{
354 Q_D(QFileDialog);
355 d->init(args.directory, args.filter, args.caption);
356 setFileMode(args.mode);
357 setOptions(args.options);
358 selectFile(args.selection);
359 d->lineEdit()->selectAll();
360}
361
362/*!
363 Destroys the file dialog.
364*/
365QFileDialog::~QFileDialog()
366{
367 Q_D(QFileDialog);
368#ifndef QT_NO_SETTINGS
369 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
370 settings.beginGroup(QLatin1String("Qt"));
371 settings.setValue(QLatin1String("filedialog"), saveState());
372#endif
373 d->deleteNativeDialog_sys();
374}
375
376/*!
377 \since 4.3
378 Sets the \a urls that are located in the sidebar.
379
380 For instance:
381
382 \snippet doc/src/snippets/filedialogurls.cpp 0
383
384 The file dialog will then look like this:
385
386 \image filedialogurls.png
387
388 \sa sidebarUrls()
389*/
390void QFileDialog::setSidebarUrls(const QList<QUrl> &urls)
391{
392 Q_D(QFileDialog);
393 d->qFileDialogUi->sidebar->setUrls(urls);
394}
395
396/*!
397 \since 4.3
398 Returns a list of urls that are currently in the sidebar
399*/
400QList<QUrl> QFileDialog::sidebarUrls() const
401{
402 Q_D(const QFileDialog);
403 return d->qFileDialogUi->sidebar->urls();
404}
405
406static const qint32 QFileDialogMagic = 0xbe;
407
408const char *qt_file_dialog_filter_reg_exp =
409"^(.*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$";
410
411/*!
412 \since 4.3
413 Saves the state of the dialog's layout, history and current directory.
414
415 Typically this is used in conjunction with QSettings to remember the size
416 for a future session. A version number is stored as part of the data.
417*/
418QByteArray QFileDialog::saveState() const
419{
420 Q_D(const QFileDialog);
421 int version = 3;
422 QByteArray data;
423 QDataStream stream(&data, QIODevice::WriteOnly);
424
425 stream << qint32(QFileDialogMagic);
426 stream << qint32(version);
427 stream << d->qFileDialogUi->splitter->saveState();
428 stream << d->qFileDialogUi->sidebar->urls();
429 stream << history();
430 stream << *lastVisitedDir();
431 stream << d->qFileDialogUi->treeView->header()->saveState();
432 stream << qint32(viewMode());
433 return data;
434}
435
436/*!
437 \since 4.3
438 Restores the dialogs's layout, history and current directory to the \a state specified.
439
440 Typically this is used in conjunction with QSettings to restore the size
441 from a past session.
442
443 Returns false if there are errors
444*/
445bool QFileDialog::restoreState(const QByteArray &state)
446{
447 Q_D(QFileDialog);
448 int version = 3;
449 QByteArray sd = state;
450 QDataStream stream(&sd, QIODevice::ReadOnly);
451 if (stream.atEnd())
452 return false;
453 QByteArray splitterState;
454 QByteArray headerData;
455 QList<QUrl> bookmarks;
456 QStringList history;
457 QString currentDirectory;
458 qint32 marker;
459 qint32 v;
460 qint32 viewMode;
461 stream >> marker;
462 stream >> v;
463 if (marker != QFileDialogMagic || v != version)
464 return false;
465
466 stream >> splitterState
467 >> bookmarks
468 >> history
469 >> currentDirectory
470 >> headerData
471 >> viewMode;
472
473 if (!d->qFileDialogUi->splitter->restoreState(splitterState))
474 return false;
475 QList<int> list = d->qFileDialogUi->splitter->sizes();
476 if (list.count() >= 2 && list.at(0) == 0 && list.at(1) == 0) {
477 for (int i = 0; i < list.count(); ++i)
478 list[i] = d->qFileDialogUi->splitter->widget(i)->sizeHint().width();
479 d->qFileDialogUi->splitter->setSizes(list);
480 }
481
482 d->qFileDialogUi->sidebar->setUrls(bookmarks);
483 while (history.count() > 5)
484 history.pop_front();
485 setHistory(history);
486 setDirectory(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir());
487 QHeaderView *headerView = d->qFileDialogUi->treeView->header();
488 if (!headerView->restoreState(headerData))
489 return false;
490
491 QList<QAction*> actions = headerView->actions();
492 QAbstractItemModel *abstractModel = d->model;
493#ifndef QT_NO_PROXYMODEL
494 if (d->proxyModel)
495 abstractModel = d->proxyModel;
496#endif
497 int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1);
498 for (int i = 1; i < total; ++i)
499 actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i));
500
501 setViewMode(ViewMode(viewMode));
502 return true;
503}
504
505/*!
506 \reimp
507*/
508void QFileDialog::changeEvent(QEvent *e)
509{
510 Q_D(QFileDialog);
511 if (e->type() == QEvent::LanguageChange) {
512 d->retranslateWindowTitle();
513 d->retranslateStrings();
514 }
515 QDialog::changeEvent(e);
516}
517
518QFileDialogPrivate::QFileDialogPrivate()
519 :
520#ifndef QT_NO_PROXYMODEL
521 proxyModel(0),
522#endif
523 model(0),
524 fileMode(QFileDialog::AnyFile),
525 acceptMode(QFileDialog::AcceptOpen),
526 currentHistoryLocation(-1),
527 renameAction(0),
528 deleteAction(0),
529 showHiddenAction(0),
530 useDefaultCaption(true),
531 defaultFileTypes(true),
532 fileNameLabelExplicitlySat(false),
533 nativeDialogInUse(false),
534#ifdef Q_WS_MAC
535 mDelegate(0),
536#ifndef QT_MAC_USE_COCOA
537 mDialog(0),
538 mDialogStarted(false),
539 mDialogClosed(true),
540#endif
541#endif
542 qFileDialogUi(0)
543{
544}
545
546QFileDialogPrivate::~QFileDialogPrivate()
547{
548}
549
550void QFileDialogPrivate::retranslateWindowTitle()
551{
552 Q_Q(QFileDialog);
553 if (!useDefaultCaption || setWindowTitle != q->windowTitle())
554 return;
555 if (acceptMode == QFileDialog::AcceptOpen) {
556 if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory)
557 q->setWindowTitle(QFileDialog::tr("Find Directory"));
558 else
559 q->setWindowTitle(QFileDialog::tr("Open"));
560 } else
561 q->setWindowTitle(QFileDialog::tr("Save As"));
562
563 setWindowTitle = q->windowTitle();
564}
565
566void QFileDialogPrivate::setLastVisitedDirectory(const QString &dir)
567{
568 *lastVisitedDir() = dir;
569}
570
571void QFileDialogPrivate::retranslateStrings()
572{
573 Q_Q(QFileDialog);
574 /* WIDGETS */
575 if (defaultFileTypes)
576 q->setNameFilter(QFileDialog::tr("All Files (*)"));
577
578 QList<QAction*> actions = qFileDialogUi->treeView->header()->actions();
579 QAbstractItemModel *abstractModel = model;
580#ifndef QT_NO_PROXYMODEL
581 if (proxyModel)
582 abstractModel = proxyModel;
583#endif
584 int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1);
585 for (int i = 1; i < total; ++i) {
586 actions.at(i - 1)->setText(QFileDialog::tr("Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
587 }
588
589 /* MENU ACTIONS */
590 renameAction->setText(QFileDialog::tr("&Rename"));
591 deleteAction->setText(QFileDialog::tr("&Delete"));
592 showHiddenAction->setText(QFileDialog::tr("Show &hidden files"));
593 newFolderAction->setText(QFileDialog::tr("&New Folder"));
594 qFileDialogUi->retranslateUi(q);
595
596 if (!fileNameLabelExplicitlySat){
597 if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) {
598 q->setLabelText(QFileDialog::FileName, QFileDialog::tr("Directory:"));
599 } else {
600 q->setLabelText(QFileDialog::FileName, QFileDialog::tr("File &name:"));
601 }
602 fileNameLabelExplicitlySat = false;
603 }
604}
605
606void QFileDialogPrivate::emitFilesSelected(const QStringList &files)
607{
608 Q_Q(QFileDialog);
609 emit q->filesSelected(files);
610 if (files.count() == 1)
611 emit q->fileSelected(files.first());
612}
613
614bool QFileDialogPrivate::canBeNativeDialog()
615{
616 Q_Q(QFileDialog);
617 if (nativeDialogInUse)
618 return true;
619 if (q->testAttribute(Qt::WA_DontShowOnScreen))
620 return false;
621 if (opts & QFileDialog::DontUseNativeDialog)
622 return false;
623
624 QLatin1String staticName(QFileDialog::staticMetaObject.className());
625 QLatin1String dynamicName(q->metaObject()->className());
626 return (staticName == dynamicName);
627}
628
629/*!
630 \since 4.5
631 Sets the given \a option to be enabled if \a on is true; otherwise,
632 clears the given \a option.
633
634 \sa options, testOption()
635*/
636void QFileDialog::setOption(Option option, bool on)
637{
638 Q_D(QFileDialog);
639 if (!(d->opts & option) != !on)
640 setOptions(d->opts ^ option);
641}
642
643/*!
644 \since 4.5
645
646 Returns true if the given \a option is enabled; otherwise, returns
647 false.
648
649 \sa options, setOption()
650*/
651bool QFileDialog::testOption(Option option) const
652{
653 Q_D(const QFileDialog);
654 return (d->opts & option) != 0;
655}
656
657/*!
658 \property QFileDialog::options
659 \brief the various options that affect the look and feel of the dialog
660 \since 4.5
661
662 By default, all options are disabled.
663
664 Options should be set before showing the dialog. Setting them while the
665 dialog is visible is not guaranteed to have an immediate effect on the
666 dialog (depending on the option and on the platform).
667
668 \sa setOption(), testOption()
669*/
670void QFileDialog::setOptions(Options options)
671{
672 Q_D(QFileDialog);
673
674 Options changed = (options ^ d->opts);
675 if (!changed)
676 return;
677
678 d->opts = options;
679 if (changed & DontResolveSymlinks)
680 d->model->setResolveSymlinks(!(options & DontResolveSymlinks));
681 if (changed & ReadOnly) {
682 bool ro = (options & ReadOnly);
683 d->model->setReadOnly(ro);
684 d->qFileDialogUi->newFolderButton->setEnabled(!ro);
685 d->renameAction->setEnabled(!ro);
686 d->deleteAction->setEnabled(!ro);
687 }
688 if (changed & HideNameFilterDetails)
689 setNameFilters(d->nameFilters);
690
691 if (changed & ShowDirsOnly)
692 setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files);
693
694 if (changed & DontUseCustomDirectoryIcons)
695 iconProvider()->d_ptr->setUseCustomDirectoryIcons(!(options & DontUseCustomDirectoryIcons));
696}
697
698QFileDialog::Options QFileDialog::options() const
699{
700 Q_D(const QFileDialog);
701 return d->opts;
702}
703
704/*!
705 \overload
706
707 \since 4.5
708
709 This function connects one of its signals to the slot specified by \a receiver
710 and \a member. The specific signal depends is filesSelected() if fileMode is
711 ExistingFiles and fileSelected() if fileMode is anything else.
712
713 The signal will be disconnected from the slot when the dialog is closed.
714*/
715void QFileDialog::open(QObject *receiver, const char *member)
716{
717 Q_D(QFileDialog);
718 const char *signal = (fileMode() == ExistingFiles) ? SIGNAL(filesSelected(QStringList))
719 : SIGNAL(fileSelected(QString));
720 connect(this, signal, receiver, member);
721 d->signalToDisconnectOnClose = signal;
722 d->receiverToDisconnectOnClose = receiver;
723 d->memberToDisconnectOnClose = member;
724
725 QDialog::open();
726}
727
728
729/*!
730 \reimp
731*/
732void QFileDialog::setVisible(bool visible)
733{
734 Q_D(QFileDialog);
735 if (visible){
736 if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
737 return;
738 } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
739 return;
740
741 if (d->canBeNativeDialog()){
742 if (d->setVisible_sys(visible)){
743 d->nativeDialogInUse = true;
744 // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
745 // updates the state correctly, but skips showing the non-native version:
746 setAttribute(Qt::WA_DontShowOnScreen);
747#ifndef QT_NO_FSCOMPLETER
748 //So the completer don't try to complete and therefore to show a popup
749 d->completer->setModel(0);
750#endif
751 } else {
752 d->nativeDialogInUse = false;
753 setAttribute(Qt::WA_DontShowOnScreen, false);
754#ifndef QT_NO_FSCOMPLETER
755 if (d->proxyModel != 0)
756 d->completer->setModel(d->proxyModel);
757 else
758 d->completer->setModel(d->model);
759#endif
760 }
761 }
762
763 if (!d->nativeDialogInUse)
764 d->qFileDialogUi->fileNameEdit->setFocus();
765
766 QDialog::setVisible(visible);
767}
768
769/*!
770 \internal
771 set the directory to url
772*/
773void QFileDialogPrivate::_q_goToUrl(const QUrl &url)
774{
775 //The shortcut in the side bar may have a parent that is not fetched yet (e.g. an hidden file)
776 //so we force the fetching
777 QFileSystemModelPrivate::QFileSystemNode *node = model->d_func()->node(url.toLocalFile(), true);
778 QModelIndex idx = model->d_func()->index(node);
779 _q_enterDirectory(idx);
780}
781
782/*!
783 \fn void QFileDialog::setDirectory(const QDir &directory)
784
785 \overload
786*/
787
788/*!
789 Sets the file dialog's current \a directory.
790*/
791void QFileDialog::setDirectory(const QString &directory)
792{
793 Q_D(QFileDialog);
794 QString newDirectory = directory;
795 QFileInfo info(directory);
796 //we remove .. and . from the given path if exist
797 if (!directory.isEmpty())
798 newDirectory = QDir::cleanPath(directory);
799
800 if (!directory.isEmpty() && newDirectory.isEmpty())
801 return;
802
803 d->setLastVisitedDirectory(newDirectory);
804
805 if (d->nativeDialogInUse){
806 d->setDirectory_sys(newDirectory);
807 return;
808 }
809 if (d->rootPath() == newDirectory)
810 return;
811 QModelIndex root = d->model->setRootPath(newDirectory);
812 d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled);
813 if (root != d->rootIndex()) {
814#ifndef QT_NO_FSCOMPLETER
815 if (directory.endsWith(QLatin1Char('/')))
816 d->completer->setCompletionPrefix(newDirectory);
817 else
818 d->completer->setCompletionPrefix(newDirectory + QLatin1Char('/'));
819#endif
820 d->setRootIndex(root);
821 }
822 d->qFileDialogUi->listView->selectionModel()->clear();
823}
824
825/*!
826 Returns the directory currently being displayed in the dialog.
827*/
828QDir QFileDialog::directory() const
829{
830 Q_D(const QFileDialog);
831 return QDir(d->nativeDialogInUse ? d->directory_sys() : d->rootPath());
832}
833
834/*!
835 Selects the given \a filename in the file dialog.
836
837 \sa selectedFiles()
838*/
839void QFileDialog::selectFile(const QString &filename)
840{
841 Q_D(QFileDialog);
842 if (filename.isEmpty())
843 return;
844
845 if (d->nativeDialogInUse){
846 d->selectFile_sys(filename);
847 return;
848 }
849
850 if (!QDir::isRelativePath(filename)) {
851 QFileInfo info(filename);
852 QString filenamePath = info.absoluteDir().path();
853
854 if (d->model->rootPath() != filenamePath)
855 setDirectory(filenamePath);
856 }
857
858 QModelIndex index = d->model->index(filename);
859 QString file;
860 if (!index.isValid()) {
861 // save as dialog where we want to input a default value
862 QString text = filename;
863 if (QFileInfo(filename).isAbsolute()) {
864 QString current = d->rootPath();
865 text.remove(current);
866 if (text.at(0) == QDir::separator()
867#ifdef Q_OS_WIN
868 //On Windows both cases can happen
869 || text.at(0) == QLatin1Char('/')
870#endif
871 )
872 text = text.remove(0,1);
873 }
874 file = text;
875 } else {
876 file = index.data().toString();
877 }
878 d->qFileDialogUi->listView->selectionModel()->clear();
879 if (!isVisible() || !d->lineEdit()->hasFocus())
880 d->lineEdit()->setText(file);
881}
882
883#ifdef Q_OS_UNIX
884Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0)
885{
886 if (expanded != 0)
887 *expanded = false;
888 if (!path.startsWith(QLatin1Char('~')))
889 return path;
890 QString ret = path;
891#if !defined(Q_OS_INTEGRITY)
892 QStringList tokens = ret.split(QDir::separator());
893 if (tokens.first() == QLatin1String("~")) {
894 ret.replace(0, 1, QDir::homePath());
895 } else {
896 QString userName = tokens.first();
897 userName.remove(0, 1);
898#if defined(Q_OS_VXWORKS)
899 const QString homePath = QDir::homePath();
900#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
901 passwd pw;
902 passwd *tmpPw;
903 char buf[200];
904 const int bufSize = sizeof(buf);
905 int err = 0;
906#if defined(Q_OS_SOLARIS) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0 < 199506L)
907 tmpPw = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize);
908#else
909 err = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize, &tmpPw);
910#endif
911 if (err || !tmpPw)
912 return ret;
913 const QString homePath = QString::fromLocal8Bit(pw.pw_dir);
914#else
915 passwd *pw = getpwnam(userName.toLocal8Bit().constData());
916 if (!pw)
917 return ret;
918 const QString homePath = QString::fromLocal8Bit(pw->pw_dir);
919#endif
920 ret.replace(0, tokens.first().length(), homePath);
921 }
922 if (expanded != 0)
923 *expanded = true;
924#endif
925 return ret;
926}
927#endif
928
929/**
930 Returns the text in the line edit which can be one or more file names
931 */
932QStringList QFileDialogPrivate::typedFiles() const
933{
934#ifdef Q_OS_UNIX
935 Q_Q(const QFileDialog);
936#endif
937 QStringList files;
938 QString editText = lineEdit()->text();
939 if (!editText.contains(QLatin1Char('"'))) {
940#ifdef Q_OS_UNIX
941 const QString prefix = q->directory().absolutePath() + QDir::separator();
942 if (QFile::exists(prefix + editText))
943 files << editText;
944 else
945 files << qt_tildeExpansion(editText);
946#else
947 files << editText;
948#endif
949 } else {
950 // " is used to separate files like so: "file1" "file2" "file3" ...
951 // ### need escape character for filenames with quotes (")
952 QStringList tokens = editText.split(QLatin1Char('\"'));
953 for (int i=0; i<tokens.size(); ++i) {
954 if ((i % 2) == 0)
955 continue; // Every even token is a separator
956#ifdef Q_OS_UNIX
957 const QString token = tokens.at(i);
958 const QString prefix = q->directory().absolutePath() + QDir::separator();
959 if (QFile::exists(prefix + token))
960 files << token;
961 else
962 files << qt_tildeExpansion(token);
963#else
964 files << toInternal(tokens.at(i));
965#endif
966 }
967 }
968 return addDefaultSuffixToFiles(files);
969}
970
971QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesToFix) const
972{
973 QStringList files;
974 for (int i=0; i<filesToFix.size(); ++i) {
975 QString name = toInternal(filesToFix.at(i));
976 QFileInfo info(name);
977 // if the filename has no suffix, add the default suffix
978 if (!defaultSuffix.isEmpty() && !info.isDir() && name.lastIndexOf(QLatin1Char('.')) == -1)
979 name += QLatin1Char('.') + defaultSuffix;
980 if (info.isAbsolute()) {
981 files.append(name);
982 } else {
983 // at this point the path should only have Qt path separators.
984 // This check is needed since we might be at the root directory
985 // and on Windows it already ends with slash.
986 QString path = rootPath();
987 if (!path.endsWith(QLatin1Char('/')))
988 path += QLatin1Char('/');
989 path += name;
990 files.append(path);
991 }
992 }
993 return files;
994}
995
996
997/*!
998 Returns a list of strings containing the absolute paths of the
999 selected files in the dialog. If no files are selected, or
1000 the mode is not ExistingFiles or ExistingFile, selectedFiles() contains the current path in the viewport.
1001
1002 \sa selectedNameFilter(), selectFile()
1003*/
1004QStringList QFileDialog::selectedFiles() const
1005{
1006 Q_D(const QFileDialog);
1007 if (d->nativeDialogInUse)
1008 return d->addDefaultSuffixToFiles(d->selectedFiles_sys());
1009
1010 QModelIndexList indexes = d->qFileDialogUi->listView->selectionModel()->selectedRows();
1011 QStringList files;
1012 for (int i = 0; i < indexes.count(); ++i)
1013 files.append(indexes.at(i).data(QFileSystemModel::FilePathRole).toString());
1014
1015 if (files.isEmpty() && !d->lineEdit()->text().isEmpty())
1016 files = d->typedFiles();
1017
1018 if (files.isEmpty() && !(d->fileMode == ExistingFile || d->fileMode == ExistingFiles))
1019 files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
1020 return files;
1021}
1022
1023/*
1024 Makes a list of filters from ;;-separated text.
1025 Used by the mac and windows implementations
1026*/
1027QStringList qt_make_filter_list(const QString &filter)
1028{
1029 QString f(filter);
1030
1031 if (f.isEmpty())
1032 return QStringList();
1033
1034 QString sep(QLatin1String(";;"));
1035 int i = f.indexOf(sep, 0);
1036 if (i == -1) {
1037 if (f.indexOf(QLatin1Char('\n'), 0) != -1) {
1038 sep = QLatin1Char('\n');
1039 i = f.indexOf(sep, 0);
1040 }
1041 }
1042
1043 return f.split(sep);
1044}
1045
1046/*!
1047 \since 4.4
1048
1049 Sets the filter used in the file dialog to the given \a filter.
1050
1051 If \a filter contains a pair of parentheses containing one or more
1052 of \bold{anything*something}, separated by spaces, then only the
1053 text contained in the parentheses is used as the filter. This means
1054 that these calls are all equivalent:
1055
1056 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 6
1057
1058 \sa setNameFilters()
1059*/
1060void QFileDialog::setNameFilter(const QString &filter)
1061{
1062 setNameFilters(qt_make_filter_list(filter));
1063}
1064
1065/*!
1066 \obsolete
1067
1068 Use setNameFilter() instead.
1069*/
1070void QFileDialog::setFilter(const QString &filter)
1071{
1072 setNameFilter(filter);
1073}
1074
1075/*!
1076 \property QFileDialog::nameFilterDetailsVisible
1077 \obsolete
1078 \brief This property holds whether the filter details is shown or not.
1079 \since 4.4
1080
1081 When this property is true (the default), the filter details are shown
1082 in the combo box. When the property is set to false, these are hidden.
1083
1084 Use setOption(HideNameFilterDetails, !\e enabled) or
1085 !testOption(HideNameFilterDetails).
1086*/
1087void QFileDialog::setNameFilterDetailsVisible(bool enabled)
1088{
1089 setOption(HideNameFilterDetails, !enabled);
1090}
1091
1092bool QFileDialog::isNameFilterDetailsVisible() const
1093{
1094 return !testOption(HideNameFilterDetails);
1095}
1096
1097
1098/*
1099 Strip the filters by removing the details, e.g. (*.*).
1100*/
1101QStringList qt_strip_filters(const QStringList &filters)
1102{
1103 QStringList strippedFilters;
1104 QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
1105 for (int i = 0; i < filters.count(); ++i) {
1106 QString filterName;
1107 int index = r.indexIn(filters[i]);
1108 if (index >= 0)
1109 filterName = r.cap(1);
1110 strippedFilters.append(filterName.simplified());
1111 }
1112 return strippedFilters;
1113}
1114
1115
1116/*!
1117 \since 4.4
1118
1119 Sets the \a filters used in the file dialog.
1120
1121 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 7
1122*/
1123void QFileDialog::setNameFilters(const QStringList &filters)
1124{
1125 Q_D(QFileDialog);
1126 d->defaultFileTypes = (filters == QStringList(QFileDialog::tr("All Files (*)")));
1127 QStringList cleanedFilters;
1128 for (int i = 0; i < filters.count(); ++i) {
1129 cleanedFilters << filters[i].simplified();
1130 }
1131 d->nameFilters = cleanedFilters;
1132
1133 if (d->nativeDialogInUse){
1134 d->setNameFilters_sys(cleanedFilters);
1135 return;
1136 }
1137
1138 d->qFileDialogUi->fileTypeCombo->clear();
1139 if (cleanedFilters.isEmpty())
1140 return;
1141
1142 if (testOption(HideNameFilterDetails))
1143 d->qFileDialogUi->fileTypeCombo->addItems(qt_strip_filters(cleanedFilters));
1144 else
1145 d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters);
1146
1147 d->_q_useNameFilter(0);
1148}
1149
1150/*!
1151 \obsolete
1152
1153 Use setNameFilters() instead.
1154*/
1155void QFileDialog::setFilters(const QStringList &filters)
1156{
1157 setNameFilters(filters);
1158}
1159
1160/*!
1161 \since 4.4
1162
1163 Returns the file type filters that are in operation on this file
1164 dialog.
1165*/
1166QStringList QFileDialog::nameFilters() const
1167{
1168 return d_func()->nameFilters;
1169}
1170
1171/*!
1172 \obsolete
1173
1174 Use nameFilters() instead.
1175*/
1176
1177QStringList QFileDialog::filters() const
1178{
1179 return nameFilters();
1180}
1181
1182/*!
1183 \since 4.4
1184
1185 Sets the current file type \a filter. Multiple filters can be
1186 passed in \a filter by separating them with semicolons or spaces.
1187
1188 \sa setNameFilter(), setNameFilters(), selectedNameFilter()
1189*/
1190void QFileDialog::selectNameFilter(const QString &filter)
1191{
1192 Q_D(QFileDialog);
1193 if (d->nativeDialogInUse) {
1194 d->selectNameFilter_sys(filter);
1195 return;
1196 }
1197 int i = -1;
1198 if (testOption(HideNameFilterDetails)) {
1199 const QStringList filters = qt_strip_filters(qt_make_filter_list(filter));
1200 if (!filters.isEmpty())
1201 i = d->qFileDialogUi->fileTypeCombo->findText(filters.first());
1202 } else {
1203 i = d->qFileDialogUi->fileTypeCombo->findText(filter);
1204 }
1205 if (i >= 0) {
1206 d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i);
1207 d->_q_useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex());
1208 }
1209}
1210
1211/*!
1212 \obsolete
1213
1214 Use selectNameFilter() instead.
1215*/
1216
1217void QFileDialog::selectFilter(const QString &filter)
1218{
1219 selectNameFilter(filter);
1220}
1221
1222/*!
1223 \since 4.4
1224
1225 Returns the filter that the user selected in the file dialog.
1226
1227 \sa selectedFiles()
1228*/
1229QString QFileDialog::selectedNameFilter() const
1230{
1231 Q_D(const QFileDialog);
1232 if (d->nativeDialogInUse)
1233 return d->selectedNameFilter_sys();
1234
1235 return d->qFileDialogUi->fileTypeCombo->currentText();
1236}
1237
1238/*!
1239 \obsolete
1240
1241 Use selectedNameFilter() instead.
1242*/
1243QString QFileDialog::selectedFilter() const
1244{
1245 return selectedNameFilter();
1246}
1247
1248/*!
1249 \since 4.4
1250
1251 Returns the filter that is used when displaying files.
1252
1253 \sa setFilter()
1254*/
1255QDir::Filters QFileDialog::filter() const
1256{
1257 Q_D(const QFileDialog);
1258 return d->model->filter();
1259}
1260
1261/*!
1262 \since 4.4
1263
1264 Sets the filter used by the model to \a filters. The filter is used
1265 to specify the kind of files that should be shown.
1266
1267 \sa filter()
1268*/
1269
1270void QFileDialog::setFilter(QDir::Filters filters)
1271{
1272 Q_D(QFileDialog);
1273 d->model->setFilter(filters);
1274 if (d->nativeDialogInUse){
1275 d->setFilter_sys();
1276 return;
1277 }
1278
1279 d->showHiddenAction->setChecked((filters & QDir::Hidden));
1280}
1281
1282/*!
1283 \property QFileDialog::viewMode
1284 \brief the way files and directories are displayed in the dialog
1285
1286 By default, the \c Detail mode is used to display information about
1287 files and directories.
1288
1289 \sa ViewMode
1290*/
1291void QFileDialog::setViewMode(QFileDialog::ViewMode mode)
1292{
1293 Q_D(QFileDialog);
1294 if (mode == Detail)
1295 d->_q_showDetailsView();
1296 else
1297 d->_q_showListView();
1298}
1299
1300QFileDialog::ViewMode QFileDialog::viewMode() const
1301{
1302 Q_D(const QFileDialog);
1303 return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail);
1304}
1305
1306/*!
1307 \property QFileDialog::fileMode
1308 \brief the file mode of the dialog
1309
1310 The file mode defines the number and type of items that the user is
1311 expected to select in the dialog.
1312
1313 By default, this property is set to AnyFile.
1314
1315 This function will set the labels for the FileName and
1316 \l{QFileDialog::}{Accept} \l{DialogLabel}s. It is possible to set
1317 custom text after the call to setFileMode().
1318
1319 \sa FileMode
1320*/
1321void QFileDialog::setFileMode(QFileDialog::FileMode mode)
1322{
1323 Q_D(QFileDialog);
1324 d->fileMode = mode;
1325 d->retranslateWindowTitle();
1326
1327 // keep ShowDirsOnly option in sync with fileMode (BTW, DirectoryOnly is obsolete)
1328 setOption(ShowDirsOnly, mode == DirectoryOnly);
1329
1330 // set selection mode and behavior
1331 QAbstractItemView::SelectionMode selectionMode;
1332 if (mode == QFileDialog::ExistingFiles)
1333 selectionMode = QAbstractItemView::ExtendedSelection;
1334 else
1335 selectionMode = QAbstractItemView::SingleSelection;
1336 d->qFileDialogUi->listView->setSelectionMode(selectionMode);
1337 d->qFileDialogUi->treeView->setSelectionMode(selectionMode);
1338 // set filter
1339 d->model->setFilter(d->filterForMode(filter()));
1340 // setup file type for directory
1341 QString buttonText = (d->acceptMode == AcceptOpen ? tr("&Open") : tr("&Save"));
1342 if (mode == DirectoryOnly || mode == Directory) {
1343 d->qFileDialogUi->fileTypeCombo->clear();
1344 d->qFileDialogUi->fileTypeCombo->addItem(tr("Directories"));
1345 d->qFileDialogUi->fileTypeCombo->setEnabled(false);
1346
1347 if (!d->fileNameLabelExplicitlySat){
1348 setLabelText(FileName, tr("Directory:"));
1349 d->fileNameLabelExplicitlySat = false;
1350 }
1351 buttonText = tr("&Choose");
1352 } else {
1353 if (!d->fileNameLabelExplicitlySat){
1354 setLabelText(FileName, tr("File &name:"));
1355 d->fileNameLabelExplicitlySat = false;
1356 }
1357 }
1358 setLabelText(Accept, buttonText);
1359 if (d->nativeDialogInUse){
1360 d->setFilter_sys();
1361 return;
1362 }
1363
1364 d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
1365 d->_q_updateOkButton();
1366}
1367
1368QFileDialog::FileMode QFileDialog::fileMode() const
1369{
1370 Q_D(const QFileDialog);
1371 return d->fileMode;
1372}
1373
1374/*!
1375 \property QFileDialog::acceptMode
1376 \brief the accept mode of the dialog
1377
1378 The action mode defines whether the dialog is for opening or saving files.
1379
1380 By default, this property is set to \l{AcceptOpen}.
1381
1382 \sa AcceptMode
1383*/
1384void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
1385{
1386 Q_D(QFileDialog);
1387 d->acceptMode = mode;
1388 bool directoryMode = (d->fileMode == Directory || d->fileMode == DirectoryOnly);
1389 QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
1390 d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel);
1391 d->qFileDialogUi->buttonBox->button(button)->setEnabled(false);
1392 d->_q_updateOkButton();
1393 if (mode == AcceptOpen && directoryMode)
1394 setLabelText(Accept, tr("&Choose"));
1395 else
1396 setLabelText(Accept, (mode == AcceptOpen ? tr("&Open") : tr("&Save")));
1397 if (mode == AcceptSave) {
1398 d->qFileDialogUi->lookInCombo->setEditable(false);
1399 }
1400 d->retranslateWindowTitle();
1401#if defined(Q_WS_MAC)
1402 d->deleteNativeDialog_sys();
1403 setAttribute(Qt::WA_DontShowOnScreen, false);
1404#endif
1405}
1406
1407/*
1408 Returns the file system model index that is the root index in the
1409 views
1410*/
1411QModelIndex QFileDialogPrivate::rootIndex() const {
1412 return mapToSource(qFileDialogUi->listView->rootIndex());
1413}
1414
1415QAbstractItemView *QFileDialogPrivate::currentView() const {
1416 if (!qFileDialogUi->stackedWidget)
1417 return 0;
1418 if (qFileDialogUi->stackedWidget->currentWidget() == qFileDialogUi->listView->parent())
1419 return qFileDialogUi->listView;
1420 return qFileDialogUi->treeView;
1421}
1422
1423QLineEdit *QFileDialogPrivate::lineEdit() const {
1424 return (QLineEdit*)qFileDialogUi->fileNameEdit;
1425}
1426
1427/*
1428 Sets the view root index to be the file system model index
1429*/
1430void QFileDialogPrivate::setRootIndex(const QModelIndex &index) const {
1431 Q_ASSERT(index.isValid() ? index.model() == model : true);
1432 QModelIndex idx = mapFromSource(index);
1433 qFileDialogUi->treeView->setRootIndex(idx);
1434 qFileDialogUi->listView->setRootIndex(idx);
1435}
1436/*
1437 Select a file system model index
1438 returns the index that was selected (or not depending upon sortfilterproxymodel)
1439*/
1440QModelIndex QFileDialogPrivate::select(const QModelIndex &index) const {
1441 Q_ASSERT(index.isValid() ? index.model() == model : true);
1442
1443 QModelIndex idx = mapFromSource(index);
1444 if (idx.isValid() && !qFileDialogUi->listView->selectionModel()->isSelected(idx))
1445 qFileDialogUi->listView->selectionModel()->select(idx,
1446 QItemSelectionModel::Select | QItemSelectionModel::Rows);
1447 return idx;
1448}
1449
1450QFileDialog::AcceptMode QFileDialog::acceptMode() const
1451{
1452 Q_D(const QFileDialog);
1453 return d->acceptMode;
1454}
1455
1456/*!
1457 \property QFileDialog::readOnly
1458 \obsolete
1459 \brief Whether the filedialog is read-only
1460
1461 If this property is set to false, the file dialog will allow renaming,
1462 and deleting of files and directories and creating directories.
1463
1464 Use setOption(ReadOnly, \e enabled) or testOption(ReadOnly) instead.
1465*/
1466void QFileDialog::setReadOnly(bool enabled)
1467{
1468 setOption(ReadOnly, enabled);
1469}
1470
1471bool QFileDialog::isReadOnly() const
1472{
1473 return testOption(ReadOnly);
1474}
1475
1476/*!
1477 \property QFileDialog::resolveSymlinks
1478 \obsolete
1479 \brief whether the filedialog should resolve shortcuts
1480
1481 If this property is set to true, the file dialog will resolve
1482 shortcuts or symbolic links.
1483
1484 Use setOption(DontResolveSymlinks, !\a enabled) or
1485 !testOption(DontResolveSymlinks).
1486*/
1487void QFileDialog::setResolveSymlinks(bool enabled)
1488{
1489 setOption(DontResolveSymlinks, !enabled);
1490}
1491
1492bool QFileDialog::resolveSymlinks() const
1493{
1494 return !testOption(DontResolveSymlinks);
1495}
1496
1497/*!
1498 \property QFileDialog::confirmOverwrite
1499 \obsolete
1500 \brief whether the filedialog should ask before accepting a selected file,
1501 when the accept mode is AcceptSave
1502
1503 Use setOption(DontConfirmOverwrite, !\e enabled) or
1504 !testOption(DontConfirmOverwrite) instead.
1505*/
1506void QFileDialog::setConfirmOverwrite(bool enabled)
1507{
1508 setOption(DontConfirmOverwrite, !enabled);
1509}
1510
1511bool QFileDialog::confirmOverwrite() const
1512{
1513 return !testOption(DontConfirmOverwrite);
1514}
1515
1516/*!
1517 \property QFileDialog::defaultSuffix
1518 \brief suffix added to the filename if no other suffix was specified
1519
1520 This property specifies a string that will be added to the
1521 filename if it has no suffix already. The suffix is typically
1522 used to indicate the file type (e.g. "txt" indicates a text
1523 file).
1524*/
1525void QFileDialog::setDefaultSuffix(const QString &suffix)
1526{
1527 Q_D(QFileDialog);
1528 d->defaultSuffix = suffix;
1529}
1530
1531QString QFileDialog::defaultSuffix() const
1532{
1533 Q_D(const QFileDialog);
1534 return d->defaultSuffix;
1535}
1536
1537/*!
1538 Sets the browsing history of the filedialog to contain the given
1539 \a paths.
1540*/
1541void QFileDialog::setHistory(const QStringList &paths)
1542{
1543 Q_D(QFileDialog);
1544 d->qFileDialogUi->lookInCombo->setHistory(paths);
1545}
1546
1547void QFileDialogComboBox::setHistory(const QStringList &paths)
1548{
1549 m_history = paths;
1550 // Only populate the first item, showPopup will populate the rest if needed
1551 QList<QUrl> list;
1552 QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
1553 //On windows the popup display the "C:\", convert to nativeSeparators
1554 QUrl url = QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString()));
1555 if (url.isValid())
1556 list.append(url);
1557 urlModel->setUrls(list);
1558}
1559
1560/*!
1561 Returns the browsing history of the filedialog as a list of paths.
1562*/
1563QStringList QFileDialog::history() const
1564{
1565 Q_D(const QFileDialog);
1566 QStringList currentHistory = d->qFileDialogUi->lookInCombo->history();
1567 //On windows the popup display the "C:\", convert to nativeSeparators
1568 QString newHistory = QDir::toNativeSeparators(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
1569 if (!currentHistory.contains(newHistory))
1570 currentHistory << newHistory;
1571 return currentHistory;
1572}
1573
1574/*!
1575 Sets the item delegate used to render items in the views in the
1576 file dialog to the given \a delegate.
1577
1578 \warning You should not share the same instance of a delegate between views.
1579 Doing so can cause incorrect or unintuitive editing behavior since each
1580 view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
1581 signal, and attempt to access, modify or close an editor that has already been closed.
1582
1583 Note that the model used is QFileSystemModel. It has custom item data roles, which is
1584 described by the \l{QFileSystemModel::}{Roles} enum. You can use a QFileIconProvider if
1585 you only want custom icons.
1586
1587 \sa itemDelegate(), setIconProvider(), QFileSystemModel
1588*/
1589void QFileDialog::setItemDelegate(QAbstractItemDelegate *delegate)
1590{
1591 Q_D(QFileDialog);
1592 d->qFileDialogUi->listView->setItemDelegate(delegate);
1593 d->qFileDialogUi->treeView->setItemDelegate(delegate);
1594}
1595
1596/*!
1597 Returns the item delegate used to render the items in the views in the filedialog.
1598*/
1599QAbstractItemDelegate *QFileDialog::itemDelegate() const
1600{
1601 Q_D(const QFileDialog);
1602 return d->qFileDialogUi->listView->itemDelegate();
1603}
1604
1605/*!
1606 Sets the icon provider used by the filedialog to the specified \a provider.
1607*/
1608void QFileDialog::setIconProvider(QFileIconProvider *provider)
1609{
1610 Q_D(QFileDialog);
1611 d->model->setIconProvider(provider);
1612 //It forces the refresh of all entries in the side bar, then we can get new icons
1613 d->qFileDialogUi->sidebar->setUrls(d->qFileDialogUi->sidebar->urls());
1614}
1615
1616/*!
1617 Returns the icon provider used by the filedialog.
1618*/
1619QFileIconProvider *QFileDialog::iconProvider() const
1620{
1621 Q_D(const QFileDialog);
1622 return d->model->iconProvider();
1623}
1624
1625/*!
1626 Sets the \a text shown in the filedialog in the specified \a label.
1627*/
1628void QFileDialog::setLabelText(DialogLabel label, const QString &text)
1629{
1630 Q_D(QFileDialog);
1631 QPushButton *button;
1632 switch (label) {
1633 case LookIn:
1634 d->qFileDialogUi->lookInLabel->setText(text);
1635 break;
1636 case FileName:
1637 d->qFileDialogUi->fileNameLabel->setText(text);
1638 d->fileNameLabelExplicitlySat = true;
1639 break;
1640 case FileType:
1641 d->qFileDialogUi->fileTypeLabel->setText(text);
1642 break;
1643 case Accept:
1644 d->acceptLabel = text;
1645 if (acceptMode() == AcceptOpen)
1646 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
1647 else
1648 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
1649 if (button)
1650 button->setText(text);
1651 break;
1652 case Reject:
1653 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
1654 if (button)
1655 button->setText(text);
1656 break;
1657 }
1658}
1659
1660/*!
1661 Returns the text shown in the filedialog in the specified \a label.
1662*/
1663QString QFileDialog::labelText(DialogLabel label) const
1664{
1665 QPushButton *button;
1666 Q_D(const QFileDialog);
1667 switch (label) {
1668 case LookIn:
1669 return d->qFileDialogUi->lookInLabel->text();
1670 case FileName:
1671 return d->qFileDialogUi->fileNameLabel->text();
1672 case FileType:
1673 return d->qFileDialogUi->fileTypeLabel->text();
1674 case Accept:
1675 if (acceptMode() == AcceptOpen)
1676 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
1677 else
1678 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
1679 if (button)
1680 return button->text();
1681 case Reject:
1682 button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
1683 if (button)
1684 return button->text();
1685 }
1686 return QString();
1687}
1688
1689/*
1690 For the native file dialogs
1691*/
1692
1693#if defined(Q_WS_WIN)
1694extern QString qt_win_get_open_file_name(const QFileDialogArgs &args,
1695 QString *initialDirectory,
1696 QString *selectedFilter);
1697
1698extern QString qt_win_get_save_file_name(const QFileDialogArgs &args,
1699 QString *initialDirectory,
1700 QString *selectedFilter);
1701
1702extern QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
1703 QString *initialDirectory,
1704 QString *selectedFilter);
1705
1706extern QString qt_win_get_existing_directory(const QFileDialogArgs &args);
1707#endif
1708
1709/*
1710 For Symbian file dialogs
1711*/
1712#if defined(Q_WS_S60)
1713extern QString qtSymbianGetOpenFileName(const QString &caption,
1714 const QString &dir,
1715 const QString &filter);
1716
1717extern QStringList qtSymbianGetOpenFileNames(const QString &caption,
1718 const QString &dir,
1719 const QString &filter);
1720
1721extern QString qtSymbianGetSaveFileName(const QString &caption,
1722 const QString &dir);
1723
1724extern QString qtSymbianGetExistingDirectory(const QString &caption,
1725 const QString &dir);
1726#endif
1727
1728/*!
1729 This is a convenience static function that returns an existing file
1730 selected by the user. If the user presses Cancel, it returns a null string.
1731
1732 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 8
1733
1734 The function creates a modal file dialog with the given \a parent widget.
1735 If \a parent is not 0, the dialog will be shown centered over the parent
1736 widget.
1737
1738 The file dialog's working directory will be set to \a dir. If \a dir
1739 includes a file name, the file will be selected. Only files that match the
1740 given \a filter are shown. The filter selected is set to \a selectedFilter.
1741 The parameters \a dir, \a selectedFilter, and \a filter may be empty
1742 strings. If you want multiple filters, separate them with ';;', for
1743 example:
1744
1745 \code
1746 "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
1747 \endcode
1748
1749 The \a options argument holds various options about how to run the dialog,
1750 see the QFileDialog::Option enum for more information on the flags you can
1751 pass.
1752
1753 The dialog's caption is set to \a caption. If \a caption is not specified
1754 then a default caption will be used.
1755
1756 On Windows, Mac OS X and Symbian^3, this static function will use the
1757 native file dialog and not a QFileDialog.
1758
1759 On Windows the dialog will spin a blocking modal event loop that will not
1760 dispatch any QTimers, and if \a parent is not 0 then it will position the
1761 dialog just below the parent's title bar.
1762
1763 On Unix/X11, the normal behavior of the file dialog is to resolve and
1764 follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
1765 the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
1766 \a options includes DontResolveSymlinks, the file dialog will treat
1767 symlinks as regular directories.
1768
1769 On Symbian^3 the parameter \a selectedFilter has no meaning and the
1770 \a options parameter is only used to define if the native file dialog is
1771 used.
1772
1773 \warning Do not delete \a parent during the execution of the dialog. If you
1774 want to do this, you should create the dialog yourself using one of the
1775 QFileDialog constructors.
1776
1777 \sa getOpenFileNames(), getSaveFileName(), getExistingDirectory()
1778*/
1779QString QFileDialog::getOpenFileName(QWidget *parent,
1780 const QString &caption,
1781 const QString &dir,
1782 const QString &filter,
1783 QString *selectedFilter,
1784 Options options)
1785{
1786 if (qt_filedialog_open_filename_hook && !(options & DontUseNativeDialog))
1787 return qt_filedialog_open_filename_hook(parent, caption, dir, filter, selectedFilter, options);
1788#if defined(Q_WS_S60)
1789 if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
1790 return qtSymbianGetOpenFileName(caption, dir, filter);
1791#endif
1792 QFileDialogArgs args;
1793 args.parent = parent;
1794 args.caption = caption;
1795 args.directory = QFileDialogPrivate::workingDirectory(dir);
1796 args.selection = QFileDialogPrivate::initialSelection(dir);
1797 args.filter = filter;
1798 args.mode = ExistingFile;
1799 args.options = options;
1800#if defined(Q_WS_WIN)
1801 if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
1802 return qt_win_get_open_file_name(args, &(args.directory), selectedFilter);
1803 }
1804#endif
1805
1806 // create a qt dialog
1807 QFileDialog dialog(args);
1808 if (selectedFilter && !selectedFilter->isEmpty())
1809 dialog.selectNameFilter(*selectedFilter);
1810 if (dialog.exec() == QDialog::Accepted) {
1811 if (selectedFilter)
1812 *selectedFilter = dialog.selectedFilter();
1813 return dialog.selectedFiles().value(0);
1814 }
1815 return QString();
1816}
1817
1818/*!
1819 This is a convenience static function that will return one or more existing
1820 files selected by the user.
1821
1822 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 9
1823
1824 This function creates a modal file dialog with the given \a parent widget.
1825 If \a parent is not 0, the dialog will be shown centered over the parent
1826 widget.
1827
1828 The file dialog's working directory will be set to \a dir. If \a dir
1829 includes a file name, the file will be selected. The filter is set to
1830 \a filter so that only those files which match the filter are shown. The
1831 filter selected is set to \a selectedFilter. The parameters \a dir,
1832 \a selectedFilter and \a filter may be empty strings. If you need multiple
1833 filters, separate them with ';;', for instance:
1834
1835 \code
1836 "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
1837 \endcode
1838
1839 The dialog's caption is set to \a caption. If \a caption is not specified
1840 then a default caption will be used.
1841
1842 On Windows, Mac OS X and Symbian^3, this static function will use the
1843 native file dialog and not a QFileDialog.
1844
1845 On Windows the dialog will spin a blocking modal event loop that will not
1846 dispatch any QTimers, and if \a parent is not 0 then it will position the
1847 dialog just below the parent's title bar.
1848
1849 On Unix/X11, the normal behavior of the file dialog is to resolve and
1850 follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
1851 the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}.
1852 The \a options argument holds various options about how to run the dialog,
1853 see the QFileDialog::Option enum for more information on the flags you can
1854 pass.
1855
1856 \note If you want to iterate over the list of files, you should iterate
1857 over a copy. For example:
1858
1859 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 10
1860
1861 On Symbian^3 the parameter \a selectedFilter has no meaning and the
1862 \a options parameter is only used to define if the native file dialog is
1863 used. On Symbian^3, this function can only return a single filename.
1864
1865 \warning Do not delete \a parent during the execution of the dialog. If you
1866 want to do this, you should create the dialog yourself using one of the
1867 QFileDialog constructors.
1868
1869 \sa getOpenFileName(), getSaveFileName(), getExistingDirectory()
1870*/
1871QStringList QFileDialog::getOpenFileNames(QWidget *parent,
1872 const QString &caption,
1873 const QString &dir,
1874 const QString &filter,
1875 QString *selectedFilter,
1876 Options options)
1877{
1878 if (qt_filedialog_open_filenames_hook && !(options & DontUseNativeDialog))
1879 return qt_filedialog_open_filenames_hook(parent, caption, dir, filter, selectedFilter, options);
1880#if defined(Q_WS_S60)
1881 if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
1882 return qtSymbianGetOpenFileNames(caption, dir, filter);
1883#endif
1884 QFileDialogArgs args;
1885 args.parent = parent;
1886 args.caption = caption;
1887 args.directory = QFileDialogPrivate::workingDirectory(dir);
1888 args.selection = QFileDialogPrivate::initialSelection(dir);
1889 args.filter = filter;
1890 args.mode = ExistingFiles;
1891 args.options = options;
1892
1893#if defined(Q_WS_WIN)
1894 if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
1895 return qt_win_get_open_file_names(args, &(args.directory), selectedFilter);
1896 }
1897#endif
1898
1899 // create a qt dialog
1900 QFileDialog dialog(args);
1901 if (selectedFilter && !selectedFilter->isEmpty())
1902 dialog.selectNameFilter(*selectedFilter);
1903 if (dialog.exec() == QDialog::Accepted) {
1904 if (selectedFilter)
1905 *selectedFilter = dialog.selectedFilter();
1906 return dialog.selectedFiles();
1907 }
1908 return QStringList();
1909}
1910
1911/*!
1912 This is a convenience static function that will return a file name selected
1913 by the user. The file does not have to exist.
1914
1915 It creates a modal file dialog with the given \a parent widget. If
1916 \a parent is not 0, the dialog will be shown centered over the parent
1917 widget.
1918
1919 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 11
1920
1921 The file dialog's working directory will be set to \a dir. If \a dir
1922 includes a file name, the file will be selected. Only files that match the
1923 \a filter are shown. The filter selected is set to \a selectedFilter. The
1924 parameters \a dir, \a selectedFilter, and \a filter may be empty strings.
1925 Multiple filters are separated with ';;'. For instance:
1926
1927 \code
1928 "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
1929 \endcode
1930
1931 The \a options argument holds various options about how to run the dialog,
1932 see the QFileDialog::Option enum for more information on the flags you can
1933 pass.
1934
1935 The default filter can be chosen by setting \a selectedFilter to the
1936 desired value.
1937
1938 The dialog's caption is set to \a caption. If \a caption is not specified,
1939 a default caption will be used.
1940
1941 On Windows, Mac OS X and Symbian^3, this static function will use the
1942 native file dialog and not a QFileDialog.
1943
1944 On Windows the dialog will spin a blocking modal event loop that will not
1945 dispatch any QTimers, and if \a parent is not 0 then it will position the
1946 dialog just below the parent's title bar. On Mac OS X, with its native file
1947 dialog, the filter argument is ignored.
1948
1949 On Unix/X11, the normal behavior of the file dialog is to resolve and
1950 follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
1951 the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
1952 \a options includes DontResolveSymlinks the file dialog will treat symlinks
1953 as regular directories.
1954
1955 On Symbian^3 the parameters \a filter and \a selectedFilter have no
1956 meaning. The \a options parameter is only used to define if the native file
1957 dialog is used.
1958
1959 \warning Do not delete \a parent during the execution of the dialog. If you
1960 want to do this, you should create the dialog yourself using one of the
1961 QFileDialog constructors.
1962
1963 \sa getOpenFileName(), getOpenFileNames(), getExistingDirectory()
1964*/
1965QString QFileDialog::getSaveFileName(QWidget *parent,
1966 const QString &caption,
1967 const QString &dir,
1968 const QString &filter,
1969 QString *selectedFilter,
1970 Options options)
1971{
1972 if (qt_filedialog_save_filename_hook && !(options & DontUseNativeDialog))
1973 return qt_filedialog_save_filename_hook(parent, caption, dir, filter, selectedFilter, options);
1974#if defined(Q_WS_S60)
1975 if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
1976 return qtSymbianGetSaveFileName(caption, dir);
1977#endif
1978 QFileDialogArgs args;
1979 args.parent = parent;
1980 args.caption = caption;
1981 args.directory = QFileDialogPrivate::workingDirectory(dir);
1982 args.selection = QFileDialogPrivate::initialSelection(dir);
1983 args.filter = filter;
1984 args.mode = AnyFile;
1985 args.options = options;
1986
1987#if defined(Q_WS_WIN)
1988 if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
1989 return qt_win_get_save_file_name(args, &(args.directory), selectedFilter);
1990 }
1991#endif
1992
1993 // create a qt dialog
1994 QFileDialog dialog(args);
1995 dialog.setAcceptMode(AcceptSave);
1996 if (selectedFilter && !selectedFilter->isEmpty())
1997 dialog.selectNameFilter(*selectedFilter);
1998 if (dialog.exec() == QDialog::Accepted) {
1999 if (selectedFilter)
2000 *selectedFilter = dialog.selectedFilter();
2001 return dialog.selectedFiles().value(0);
2002 }
2003
2004 return QString();
2005}
2006
2007/*!
2008 This is a convenience static function that will return an existing
2009 directory selected by the user.
2010
2011 \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 12
2012
2013 This function creates a modal file dialog with the given \a parent widget.
2014 If \a parent is not 0, the dialog will be shown centered over the parent
2015 widget.
2016
2017 The dialog's working directory is set to \a dir, and the caption is set to
2018 \a caption. Either of these may be an empty string in which case the
2019 current directory and a default caption will be used respectively.
2020
2021 The \a options argument holds various options about how to run the dialog,
2022 see the QFileDialog::Option enum for more information on the flags you can
2023 pass. To ensure a native file dialog, \l{QFileDialog::}{ShowDirsOnly} must
2024 be set.
2025
2026 On Windows, Mac OS X and Symbian^3, this static function will use the
2027 native file dialog and not a QFileDialog. On Windows CE, if the device has
2028 no native file dialog, a QFileDialog will be used.
2029
2030 On Unix/X11, the normal behavior of the file dialog is to resolve and
2031 follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
2032 the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
2033 \a options includes DontResolveSymlinks, the file dialog will treat
2034 symlinks as regular directories.
2035
2036 On Windows the dialog will spin a blocking modal event loop that will not
2037 dispatch any QTimers, and if \a parent is not 0 then it will position the
2038 dialog just below the parent's title bar.
2039
2040 On Symbian^3 the \a options parameter is only used to define if the native
2041 file dialog is used.
2042
2043 \warning Do not delete \a parent during the execution of the dialog. If you
2044 want to do this, you should create the dialog yourself using one of the
2045 QFileDialog constructors.
2046
2047 \sa getOpenFileName(), getOpenFileNames(), getSaveFileName()
2048*/
2049QString QFileDialog::getExistingDirectory(QWidget *parent,
2050 const QString &caption,
2051 const QString &dir,
2052 Options options)
2053{
2054 if (qt_filedialog_existing_directory_hook && !(options & DontUseNativeDialog))
2055 return qt_filedialog_existing_directory_hook(parent, caption, dir, options);
2056#if defined(Q_WS_S60)
2057 if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
2058 return qtSymbianGetExistingDirectory(caption, dir);
2059#endif
2060 QFileDialogArgs args;
2061 args.parent = parent;
2062 args.caption = caption;
2063 args.directory = QFileDialogPrivate::workingDirectory(dir);
2064 args.mode = (options & ShowDirsOnly ? DirectoryOnly : Directory);
2065 args.options = options;
2066
2067#if defined(Q_WS_WIN)
2068 if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog) && (options & ShowDirsOnly)
2069#if defined(Q_WS_WINCE)
2070 && qt_priv_ptr_valid
2071#endif
2072 ) {
2073 return qt_win_get_existing_directory(args);
2074 }
2075#endif
2076
2077 // create a qt dialog
2078 QFileDialog dialog(args);
2079 if (dialog.exec() == QDialog::Accepted) {
2080 return dialog.selectedFiles().value(0);
2081 }
2082 return QString();
2083}
2084
2085inline static QString _qt_get_directory(const QString &path)
2086{
2087 QFileInfo info = QFileInfo(QDir::current(), path);
2088 if (info.exists() && info.isDir())
2089 return QDir::cleanPath(info.absoluteFilePath());
2090 info.setFile(info.absolutePath());
2091 if (info.exists() && info.isDir())
2092 return info.absoluteFilePath();
2093 return QString();
2094}
2095/*
2096 Get the initial directory path
2097
2098 \sa initialSelection()
2099 */
2100QString QFileDialogPrivate::workingDirectory(const QString &path)
2101{
2102 if (!path.isEmpty()) {
2103 QString directory = _qt_get_directory(path);
2104 if (!directory.isEmpty())
2105 return directory;
2106 }
2107 QString directory = _qt_get_directory(*lastVisitedDir());
2108 if (!directory.isEmpty())
2109 return directory;
2110 return QDir::currentPath();
2111}
2112
2113/*
2114 Get the initial selection given a path. The initial directory
2115 can contain both the initial directory and initial selection
2116 /home/user/foo.txt
2117
2118 \sa workingDirectory()
2119 */
2120QString QFileDialogPrivate::initialSelection(const QString &path)
2121{
2122 if (!path.isEmpty()) {
2123 QFileInfo info(path);
2124 if (!info.isDir())
2125 return info.fileName();
2126 }
2127 return QString();
2128}
2129
2130/*!
2131 \reimp
2132*/
2133void QFileDialog::done(int result)
2134{
2135 Q_D(QFileDialog);
2136
2137 QDialog::done(result);
2138
2139 if (d->receiverToDisconnectOnClose) {
2140 disconnect(this, d->signalToDisconnectOnClose,
2141 d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
2142 d->receiverToDisconnectOnClose = 0;
2143 }
2144 d->memberToDisconnectOnClose.clear();
2145 d->signalToDisconnectOnClose.clear();
2146}
2147
2148/*!
2149 \reimp
2150*/
2151void QFileDialog::accept()
2152{
2153 Q_D(QFileDialog);
2154 QStringList files = selectedFiles();
2155 if (files.isEmpty())
2156 return;
2157 if (d->nativeDialogInUse){
2158 d->emitFilesSelected(files);
2159 QDialog::accept();
2160 return;
2161 }
2162
2163 QString lineEditText = d->lineEdit()->text();
2164 // "hidden feature" type .. and then enter, and it will move up a dir
2165 // special case for ".."
2166 if (lineEditText == QLatin1String("..")) {
2167 d->_q_navigateToParent();
2168 bool block = d->qFileDialogUi->fileNameEdit->blockSignals(true);
2169 d->lineEdit()->selectAll();
2170 d->qFileDialogUi->fileNameEdit->blockSignals(block);
2171 return;
2172 }
2173
2174 switch (d->fileMode) {
2175 case DirectoryOnly:
2176 case Directory: {
2177 QString fn = files.first();
2178 QFileInfo info(fn);
2179 if (!info.exists())
2180 info = QFileInfo(d->getEnvironmentVariable(fn));
2181 if (!info.exists()) {
2182#ifndef QT_NO_MESSAGEBOX
2183 QString message = tr("%1\nDirectory not found.\nPlease verify the "
2184 "correct directory name was given.");
2185 QMessageBox::warning(this, windowTitle(), message.arg(info.fileName()));
2186#endif // QT_NO_MESSAGEBOX
2187 return;
2188 }
2189 if (info.isDir()) {
2190 d->emitFilesSelected(files);
2191 QDialog::accept();
2192 }
2193 return;
2194 }
2195
2196 case AnyFile: {
2197 QString fn = files.first();
2198 QFileInfo info(fn);
2199 if (info.isDir()) {
2200 setDirectory(info.absoluteFilePath());
2201 return;
2202 }
2203
2204 if (!info.exists()) {
2205 int maxNameLength = d->maxNameLength(info.path());
2206 if (maxNameLength >= 0 && info.fileName().length() > maxNameLength)
2207 return;
2208 }
2209
2210 // check if we have to ask for permission to overwrite the file
2211 if (!info.exists() || !confirmOverwrite() || acceptMode() == AcceptOpen) {
2212 d->emitFilesSelected(QStringList(fn));
2213 QDialog::accept();
2214#ifndef QT_NO_MESSAGEBOX
2215 } else {
2216 if (QMessageBox::warning(this, windowTitle(),
2217 tr("%1 already exists.\nDo you want to replace it?")
2218 .arg(info.fileName()),
2219 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
2220 == QMessageBox::Yes) {
2221 d->emitFilesSelected(QStringList(fn));
2222 QDialog::accept();
2223 }
2224#endif
2225 }
2226 return;
2227 }
2228
2229 case ExistingFile:
2230 case ExistingFiles:
2231 for (int i = 0; i < files.count(); ++i) {
2232 QFileInfo info(files.at(i));
2233 if (!info.exists())
2234 info = QFileInfo(d->getEnvironmentVariable(files.at(i)));
2235 if (!info.exists()) {
2236#ifndef QT_NO_MESSAGEBOX
2237 QString message = tr("%1\nFile not found.\nPlease verify the "
2238 "correct file name was given.");
2239 QMessageBox::warning(this, windowTitle(), message.arg(info.fileName()));
2240#endif // QT_NO_MESSAGEBOX
2241 return;
2242 }
2243 if (info.isDir()) {
2244 setDirectory(info.absoluteFilePath());
2245 d->lineEdit()->clear();
2246 return;
2247 }
2248 }
2249 d->emitFilesSelected(files);
2250 QDialog::accept();
2251 return;
2252 }
2253}
2254
2255/*!
2256 \internal
2257
2258 Create widgets, layout and set default values
2259*/
2260void QFileDialogPrivate::init(const QString &directory, const QString &nameFilter,
2261 const QString &caption)
2262{
2263 Q_Q(QFileDialog);
2264 if (!caption.isEmpty()) {
2265 useDefaultCaption = false;
2266 setWindowTitle = caption;
2267 q->setWindowTitle(caption);
2268 }
2269
2270 createWidgets();
2271 createMenuActions();
2272 retranslateStrings();
2273 q->setFileMode(fileMode);
2274
2275#ifndef QT_NO_SETTINGS
2276 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
2277 settings.beginGroup(QLatin1String("Qt"));
2278 if (!directory.isEmpty())
2279 setLastVisitedDirectory(workingDirectory(directory));
2280 q->restoreState(settings.value(QLatin1String("filedialog")).toByteArray());
2281#endif
2282
2283#if defined(Q_EMBEDDED_SMALLSCREEN)
2284 qFileDialogUi->lookInLabel->setVisible(false);
2285 qFileDialogUi->fileNameLabel->setVisible(false);
2286 qFileDialogUi->fileTypeLabel->setVisible(false);
2287 qFileDialogUi->sidebar->hide();
2288#endif
2289 // Default case
2290 if (!nameFilter.isEmpty())
2291 q->setNameFilter(nameFilter);
2292 q->setAcceptMode(QFileDialog::AcceptOpen);
2293 q->setDirectory(workingDirectory(directory));
2294 q->selectFile(initialSelection(directory));
2295
2296 _q_updateOkButton();
2297 q->resize(q->sizeHint());
2298}
2299
2300/*!
2301 \internal
2302
2303 Create the widgets, set properties and connections
2304*/
2305void QFileDialogPrivate::createWidgets()
2306{
2307 Q_Q(QFileDialog);
2308 model = new QFileSystemModel(q);
2309 model->setObjectName(QLatin1String("qt_filesystem_model"));
2310#ifdef Q_WS_MAC
2311 model->setNameFilterDisables(true);
2312#else
2313 model->setNameFilterDisables(false);
2314#endif
2315 model->d_func()->disableRecursiveSort = true;
2316 QFileDialog::connect(model, SIGNAL(fileRenamed(QString,QString,QString)), q, SLOT(_q_fileRenamed(QString,QString,QString)));
2317 QFileDialog::connect(model, SIGNAL(rootPathChanged(QString)),
2318 q, SLOT(_q_pathChanged(QString)));
2319 QFileDialog::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
2320 q, SLOT(_q_rowsInserted(QModelIndex)));
2321 model->setReadOnly(false);
2322
2323 qFileDialogUi.reset(new Ui_QFileDialog());
2324 qFileDialogUi->setupUi(q);
2325
2326 QList<QUrl> initialBookmarks;
2327 initialBookmarks << QUrl::fromLocalFile(QLatin1String(""))
2328 << QUrl::fromLocalFile(QDir::homePath());
2329 qFileDialogUi->sidebar->init(model, initialBookmarks);
2330 QFileDialog::connect(qFileDialogUi->sidebar, SIGNAL(goToUrl(QUrl)),
2331 q, SLOT(_q_goToUrl(QUrl)));
2332
2333 QObject::connect(qFileDialogUi->buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
2334 QObject::connect(qFileDialogUi->buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
2335
2336
2337 qFileDialogUi->lookInCombo->init(this);
2338 QObject::connect(qFileDialogUi->lookInCombo, SIGNAL(activated(QString)), q, SLOT(_q_goToDirectory(QString)));
2339
2340 qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert);
2341 qFileDialogUi->lookInCombo->setDuplicatesEnabled(false);
2342
2343 // filename
2344 qFileDialogUi->fileNameEdit->init(this);
2345#ifndef QT_NO_SHORTCUT
2346 qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit);
2347#endif
2348#ifndef QT_NO_FSCOMPLETER
2349 completer = new QFSCompleter(model, q);
2350 qFileDialogUi->fileNameEdit->setCompleter(completer);
2351#endif // QT_NO_FSCOMPLETER
2352 QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
2353 q, SLOT(_q_autoCompleteFileName(QString)));
2354 QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
2355 q, SLOT(_q_updateOkButton()));
2356
2357 QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(returnPressed()), q, SLOT(accept()));
2358
2359 // filetype
2360 qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(false);
2361 qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
2362 qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
2363 QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(int)),
2364 q, SLOT(_q_useNameFilter(int)));
2365 QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(QString)),
2366 q, SIGNAL(filterSelected(QString)));
2367
2368 qFileDialogUi->listView->init(this);
2369 qFileDialogUi->listView->setModel(model);
2370 QObject::connect(qFileDialogUi->listView, SIGNAL(activated(QModelIndex)),
2371 q, SLOT(_q_enterDirectory(QModelIndex)));
2372 QObject::connect(qFileDialogUi->listView, SIGNAL(customContextMenuRequested(QPoint)),
2373 q, SLOT(_q_showContextMenu(QPoint)));
2374#ifndef QT_NO_SHORTCUT
2375 QShortcut *shortcut = new QShortcut(qFileDialogUi->listView);
2376 shortcut->setKey(QKeySequence(QLatin1String("Delete")));
2377 QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
2378#endif
2379
2380 qFileDialogUi->treeView->init(this);
2381 qFileDialogUi->treeView->setModel(model);
2382 QHeaderView *treeHeader = qFileDialogUi->treeView->header();
2383 QFontMetrics fm(q->font());
2384 treeHeader->resizeSection(0, fm.width(QLatin1String("wwwwwwwwwwwwwwwwwwwwwwwwww")));
2385 treeHeader->resizeSection(1, fm.width(QLatin1String("128.88 GB")));
2386 treeHeader->resizeSection(2, fm.width(QLatin1String("mp3Folder")));
2387 treeHeader->resizeSection(3, fm.width(QLatin1String("10/29/81 02:02PM")));
2388 treeHeader->setContextMenuPolicy(Qt::ActionsContextMenu);
2389
2390 QActionGroup *showActionGroup = new QActionGroup(q);
2391 showActionGroup->setExclusive(false);
2392 QObject::connect(showActionGroup, SIGNAL(triggered(QAction*)),
2393 q, SLOT(_q_showHeader(QAction*)));;
2394
2395 QAbstractItemModel *abstractModel = model;
2396#ifndef QT_NO_PROXYMODEL
2397 if (proxyModel)
2398 abstractModel = proxyModel;
2399#endif
2400 for (int i = 1; i < abstractModel->columnCount(QModelIndex()); ++i) {
2401 QAction *showHeader = new QAction(showActionGroup);
2402 showHeader->setCheckable(true);
2403 showHeader->setChecked(true);
2404 treeHeader->addAction(showHeader);
2405 }
2406
2407 QScopedPointer<QItemSelectionModel> selModel(qFileDialogUi->treeView->selectionModel());
2408 qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel());
2409
2410 QObject::connect(qFileDialogUi->treeView, SIGNAL(activated(QModelIndex)),
2411 q, SLOT(_q_enterDirectory(QModelIndex)));
2412 QObject::connect(qFileDialogUi->treeView, SIGNAL(customContextMenuRequested(QPoint)),
2413 q, SLOT(_q_showContextMenu(QPoint)));
2414#ifndef QT_NO_SHORTCUT
2415 shortcut = new QShortcut(qFileDialogUi->treeView);
2416 shortcut->setKey(QKeySequence(QLatin1String("Delete")));
2417 QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
2418#endif
2419
2420 // Selections
2421 QItemSelectionModel *selections = qFileDialogUi->listView->selectionModel();
2422 QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
2423 q, SLOT(_q_selectionChanged()));
2424 QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
2425 q, SLOT(_q_currentChanged(QModelIndex)));
2426 qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding);
2427
2428 createToolButtons();
2429}
2430
2431void QFileDialogPrivate::_q_showHeader(QAction *action)
2432{
2433 Q_Q(QFileDialog);
2434 QActionGroup *actionGroup = qobject_cast<QActionGroup*>(q->sender());
2435 qFileDialogUi->treeView->header()->setSectionHidden(actionGroup->actions().indexOf(action) + 1, !action->isChecked());
2436}
2437
2438#ifndef QT_NO_PROXYMODEL
2439/*!
2440 \since 4.3
2441
2442 Sets the model for the views to the given \a proxyModel. This is useful if you
2443 want to modify the underlying model; for example, to add columns, filter
2444 data or add drives.
2445
2446 Any existing proxy model will be removed, but not deleted. The file dialog
2447 will take ownership of the \a proxyModel.
2448
2449 \sa proxyModel()
2450*/
2451void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
2452{
2453 Q_D(QFileDialog);
2454 if ((!proxyModel && !d->proxyModel)
2455 || (proxyModel == d->proxyModel))
2456 return;
2457
2458 QModelIndex idx = d->rootIndex();
2459 if (d->proxyModel) {
2460 disconnect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
2461 this, SLOT(_q_rowsInserted(QModelIndex)));
2462 } else {
2463 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
2464 this, SLOT(_q_rowsInserted(QModelIndex)));
2465 }
2466
2467 if (proxyModel != 0) {
2468 proxyModel->setParent(this);
2469 d->proxyModel = proxyModel;
2470 proxyModel->setSourceModel(d->model);
2471 d->qFileDialogUi->listView->setModel(d->proxyModel);
2472 d->qFileDialogUi->treeView->setModel(d->proxyModel);
2473#ifndef QT_NO_FSCOMPLETER
2474 d->completer->setModel(d->proxyModel);
2475 d->completer->proxyModel = d->proxyModel;
2476#endif
2477 connect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
2478 this, SLOT(_q_rowsInserted(QModelIndex)));
2479 } else {
2480 d->proxyModel = 0;
2481 d->qFileDialogUi->listView->setModel(d->model);
2482 d->qFileDialogUi->treeView->setModel(d->model);
2483#ifndef QT_NO_FSCOMPLETER
2484 d->completer->setModel(d->model);
2485 d->completer->sourceModel = d->model;
2486 d->completer->proxyModel = 0;
2487#endif
2488 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
2489 this, SLOT(_q_rowsInserted(QModelIndex)));
2490 }
2491 QScopedPointer<QItemSelectionModel> selModel(d->qFileDialogUi->treeView->selectionModel());
2492 d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel());
2493
2494 d->setRootIndex(idx);
2495
2496 // reconnect selection
2497 QItemSelectionModel *selections = d->qFileDialogUi->listView->selectionModel();
2498 QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
2499 this, SLOT(_q_selectionChanged()));
2500 QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
2501 this, SLOT(_q_currentChanged(QModelIndex)));
2502}
2503
2504/*!
2505 Returns the proxy model used by the file dialog. By default no proxy is set.
2506
2507 \sa setProxyModel()
2508*/
2509QAbstractProxyModel *QFileDialog::proxyModel() const
2510{
2511 Q_D(const QFileDialog);
2512 return d->proxyModel;
2513}
2514#endif // QT_NO_PROXYMODEL
2515
2516/*!
2517 \internal
2518
2519 Create tool buttons, set properties and connections
2520*/
2521void QFileDialogPrivate::createToolButtons()
2522{
2523 Q_Q(QFileDialog);
2524 qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack, 0, q));
2525 qFileDialogUi->backButton->setAutoRaise(true);
2526 qFileDialogUi->backButton->setEnabled(false);
2527 QObject::connect(qFileDialogUi->backButton, SIGNAL(clicked()), q, SLOT(_q_navigateBackward()));
2528
2529 qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward, 0, q));
2530 qFileDialogUi->forwardButton->setAutoRaise(true);
2531 qFileDialogUi->forwardButton->setEnabled(false);
2532 QObject::connect(qFileDialogUi->forwardButton, SIGNAL(clicked()), q, SLOT(_q_navigateForward()));
2533
2534 qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent, 0, q));
2535 qFileDialogUi->toParentButton->setAutoRaise(true);
2536 qFileDialogUi->toParentButton->setEnabled(false);
2537 QObject::connect(qFileDialogUi->toParentButton, SIGNAL(clicked()), q, SLOT(_q_navigateToParent()));
2538
2539 qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView, 0, q));
2540 qFileDialogUi->listModeButton->setAutoRaise(true);
2541 qFileDialogUi->listModeButton->setDown(true);
2542 QObject::connect(qFileDialogUi->listModeButton, SIGNAL(clicked()), q, SLOT(_q_showListView()));
2543
2544 qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView, 0, q));
2545 qFileDialogUi->detailModeButton->setAutoRaise(true);
2546 QObject::connect(qFileDialogUi->detailModeButton, SIGNAL(clicked()), q, SLOT(_q_showDetailsView()));
2547
2548 QSize toolSize(qFileDialogUi->fileNameEdit->sizeHint().height(), qFileDialogUi->fileNameEdit->sizeHint().height());
2549 qFileDialogUi->backButton->setFixedSize(toolSize);
2550 qFileDialogUi->listModeButton->setFixedSize(toolSize);
2551 qFileDialogUi->detailModeButton->setFixedSize(toolSize);
2552 qFileDialogUi->forwardButton->setFixedSize(toolSize);
2553 qFileDialogUi->toParentButton->setFixedSize(toolSize);
2554
2555 qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder, 0, q));
2556 qFileDialogUi->newFolderButton->setFixedSize(toolSize);
2557 qFileDialogUi->newFolderButton->setAutoRaise(true);
2558 qFileDialogUi->newFolderButton->setEnabled(false);
2559 QObject::connect(qFileDialogUi->newFolderButton, SIGNAL(clicked()), q, SLOT(_q_createDirectory()));
2560}
2561
2562/*!
2563 \internal
2564
2565 Create actions which will be used in the right click.
2566*/
2567void QFileDialogPrivate::createMenuActions()
2568{
2569 Q_Q(QFileDialog);
2570
2571 QAction *goHomeAction = new QAction(q);
2572#ifndef QT_NO_SHORTCUT
2573 goHomeAction->setShortcut(Qt::CTRL + Qt::Key_H + Qt::SHIFT);
2574#endif
2575 QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome()));
2576 q->addAction(goHomeAction);
2577
2578 // ### TODO add Desktop & Computer actions
2579
2580 QAction *goToParent = new QAction(q);
2581 goToParent->setObjectName(QLatin1String("qt_goto_parent_action"));
2582#ifndef QT_NO_SHORTCUT
2583 goToParent->setShortcut(Qt::CTRL + Qt::UpArrow);
2584#endif
2585 QObject::connect(goToParent, SIGNAL(triggered()), q, SLOT(_q_navigateToParent()));
2586 q->addAction(goToParent);
2587
2588 renameAction = new QAction(q);
2589 renameAction->setEnabled(false);
2590 renameAction->setObjectName(QLatin1String("qt_rename_action"));
2591 QObject::connect(renameAction, SIGNAL(triggered()), q, SLOT(_q_renameCurrent()));
2592
2593 deleteAction = new QAction(q);
2594 deleteAction->setEnabled(false);
2595 deleteAction->setObjectName(QLatin1String("qt_delete_action"));
2596 QObject::connect(deleteAction, SIGNAL(triggered()), q, SLOT(_q_deleteCurrent()));
2597
2598 showHiddenAction = new QAction(q);
2599 showHiddenAction->setObjectName(QLatin1String("qt_show_hidden_action"));
2600 showHiddenAction->setCheckable(true);
2601 QObject::connect(showHiddenAction, SIGNAL(triggered()), q, SLOT(_q_showHidden()));
2602
2603 newFolderAction = new QAction(q);
2604 newFolderAction->setObjectName(QLatin1String("qt_new_folder_action"));
2605 QObject::connect(newFolderAction, SIGNAL(triggered()), q, SLOT(_q_createDirectory()));
2606}
2607
2608void QFileDialogPrivate::_q_goHome()
2609{
2610 Q_Q(QFileDialog);
2611 q->setDirectory(QDir::homePath());
2612}
2613
2614/*!
2615 \internal
2616
2617 Update history with new path, buttons, and combo
2618*/
2619void QFileDialogPrivate::_q_pathChanged(const QString &newPath)
2620{
2621 Q_Q(QFileDialog);
2622 QDir dir(model->rootDirectory());
2623 qFileDialogUi->toParentButton->setEnabled(dir.exists());
2624 qFileDialogUi->sidebar->selectUrl(QUrl::fromLocalFile(newPath));
2625 q->setHistory(qFileDialogUi->lookInCombo->history());
2626
2627 if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation) != QDir::toNativeSeparators(newPath)) {
2628 while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.count()) {
2629 currentHistory.removeLast();
2630 }
2631 currentHistory.append(QDir::toNativeSeparators(newPath));
2632 ++currentHistoryLocation;
2633 }
2634 qFileDialogUi->forwardButton->setEnabled(currentHistory.size() - currentHistoryLocation > 1);
2635 qFileDialogUi->backButton->setEnabled(currentHistoryLocation > 0);
2636}
2637
2638/*!
2639 \internal
2640
2641 Navigates to the last directory viewed in the dialog.
2642*/
2643void QFileDialogPrivate::_q_navigateBackward()
2644{
2645 Q_Q(QFileDialog);
2646 if (!currentHistory.isEmpty() && currentHistoryLocation > 0) {
2647 --currentHistoryLocation;
2648 QString previousHistory = currentHistory.at(currentHistoryLocation);
2649 q->setDirectory(previousHistory);
2650 }
2651}
2652
2653/*!
2654 \internal
2655
2656 Navigates to the last directory viewed in the dialog.
2657*/
2658void QFileDialogPrivate::_q_navigateForward()
2659{
2660 Q_Q(QFileDialog);
2661 if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) {
2662 ++currentHistoryLocation;
2663 QString nextHistory = currentHistory.at(currentHistoryLocation);
2664 q->setDirectory(nextHistory);
2665 }
2666}
2667
2668/*!
2669 \internal
2670
2671 Navigates to the parent directory of the currently displayed directory
2672 in the dialog.
2673*/
2674void QFileDialogPrivate::_q_navigateToParent()
2675{
2676 Q_Q(QFileDialog);
2677 QDir dir(model->rootDirectory());
2678 QString newDirectory;
2679 if (dir.isRoot()) {
2680 newDirectory = model->myComputer().toString();
2681 } else {
2682 dir.cdUp();
2683 newDirectory = dir.absolutePath();
2684 }
2685 q->setDirectory(newDirectory);
2686 emit q->directoryEntered(newDirectory);
2687}
2688
2689/*!
2690 \internal
2691
2692 Creates a new directory, first asking the user for a suitable name.
2693*/
2694void QFileDialogPrivate::_q_createDirectory()
2695{
2696 Q_Q(QFileDialog);
2697 qFileDialogUi->listView->clearSelection();
2698
2699 QString newFolderString = QFileDialog::tr("New Folder");
2700 QString folderName = newFolderString;
2701 QString prefix = q->directory().absolutePath() + QDir::separator();
2702 if (QFile::exists(prefix + folderName)) {
2703 qlonglong suffix = 2;
2704 while (QFile::exists(prefix + folderName)) {
2705 folderName = newFolderString + QString::number(suffix++);
2706 }
2707 }
2708
2709 QModelIndex parent = rootIndex();
2710 QModelIndex index = model->mkdir(parent, folderName);
2711 if (!index.isValid())
2712 return;
2713
2714 index = select(index);
2715 if (index.isValid()) {
2716 qFileDialogUi->treeView->setCurrentIndex(index);
2717 currentView()->edit(index);
2718 }
2719}
2720
2721void QFileDialogPrivate::_q_showListView()
2722{
2723 qFileDialogUi->listModeButton->setDown(true);
2724 qFileDialogUi->detailModeButton->setDown(false);
2725 qFileDialogUi->treeView->hide();
2726 qFileDialogUi->listView->show();
2727 qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->listView->parentWidget());
2728 qFileDialogUi->listView->doItemsLayout();
2729}
2730
2731void QFileDialogPrivate::_q_showDetailsView()
2732{
2733 qFileDialogUi->listModeButton->setDown(false);
2734 qFileDialogUi->detailModeButton->setDown(true);
2735 qFileDialogUi->listView->hide();
2736 qFileDialogUi->treeView->show();
2737 qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->treeView->parentWidget());
2738 qFileDialogUi->treeView->doItemsLayout();
2739}
2740
2741/*!
2742 \internal
2743
2744 Show the context menu for the file/dir under position
2745*/
2746void QFileDialogPrivate::_q_showContextMenu(const QPoint &position)
2747{
2748#ifdef QT_NO_MENU
2749 Q_UNUSED(position);
2750#else
2751 Q_Q(QFileDialog);
2752 QAbstractItemView *view = 0;
2753 if (q->viewMode() == QFileDialog::Detail)
2754 view = qFileDialogUi->treeView;
2755 else
2756 view = qFileDialogUi->listView;
2757 QModelIndex index = view->indexAt(position);
2758 index = mapToSource(index.sibling(index.row(), 0));
2759
2760 QMenu menu(view);
2761 if (index.isValid()) {
2762 // file context menu
2763 QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
2764 renameAction->setEnabled(p & QFile::WriteUser);
2765 menu.addAction(renameAction);
2766 deleteAction->setEnabled(p & QFile::WriteUser);
2767 menu.addAction(deleteAction);
2768 menu.addSeparator();
2769 }
2770 menu.addAction(showHiddenAction);
2771 if (qFileDialogUi->newFolderButton->isVisible()) {
2772 newFolderAction->setEnabled(qFileDialogUi->newFolderButton->isEnabled());
2773 menu.addAction(newFolderAction);
2774 }
2775 menu.exec(view->viewport()->mapToGlobal(position));
2776#endif // QT_NO_MENU
2777}
2778
2779/*!
2780 \internal
2781*/
2782void QFileDialogPrivate::_q_renameCurrent()
2783{
2784 Q_Q(QFileDialog);
2785 QModelIndex index = qFileDialogUi->listView->currentIndex();
2786 index = index.sibling(index.row(), 0);
2787 if (q->viewMode() == QFileDialog::List)
2788 qFileDialogUi->listView->edit(index);
2789 else
2790 qFileDialogUi->treeView->edit(index);
2791}
2792
2793bool QFileDialogPrivate::removeDirectory(const QString &path)
2794{
2795 QModelIndex modelIndex = model->index(path);
2796 return model->remove(modelIndex);
2797}
2798
2799/*!
2800 \internal
2801
2802 Deletes the currently selected item in the dialog.
2803*/
2804void QFileDialogPrivate::_q_deleteCurrent()
2805{
2806 if (model->isReadOnly())
2807 return;
2808
2809 QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
2810 for (int i = list.count() - 1; i >= 0; --i) {
2811 QModelIndex index = list.at(i);
2812 if (index == qFileDialogUi->listView->rootIndex())
2813 continue;
2814
2815 index = mapToSource(index.sibling(index.row(), 0));
2816 if (!index.isValid())
2817 continue;
2818
2819 QString fileName = index.data(QFileSystemModel::FileNameRole).toString();
2820 QString filePath = index.data(QFileSystemModel::FilePathRole).toString();
2821 bool isDir = model->isDir(index);
2822
2823 QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
2824#ifndef QT_NO_MESSAGEBOX
2825 Q_Q(QFileDialog);
2826 if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), q_func()->windowTitle(),
2827 QFileDialog::tr("'%1' is write protected.\nDo you want to delete it anyway?")
2828 .arg(fileName),
2829 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No))
2830 return;
2831 else if (QMessageBox::warning(q_func(), q_func()->windowTitle(),
2832 QFileDialog::tr("Are sure you want to delete '%1'?")
2833 .arg(fileName),
2834 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
2835 return;
2836
2837#else
2838 if (!(p & QFile::WriteUser))
2839 return;
2840#endif // QT_NO_MESSAGEBOX
2841
2842 // the event loop has run, we can NOT reuse index because the model might have removed it.
2843 if (isDir) {
2844 if (!removeDirectory(filePath)) {
2845#ifndef QT_NO_MESSAGEBOX
2846 QMessageBox::warning(q, q->windowTitle(),
2847 QFileDialog::tr("Could not delete directory."));
2848#endif
2849 }
2850 } else {
2851 model->remove(index);
2852 }
2853 }
2854}
2855
2856void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text)
2857{
2858 if (text.startsWith(QLatin1String("//")) || text.startsWith(QLatin1Char('\\'))) {
2859 qFileDialogUi->listView->selectionModel()->clearSelection();
2860 return;
2861 }
2862
2863 QStringList multipleFiles = typedFiles();
2864 if (multipleFiles.count() > 0) {
2865 QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows();
2866 QModelIndexList newFiles;
2867 for (int i = 0; i < multipleFiles.count(); ++i) {
2868 QModelIndex idx = model->index(multipleFiles.at(i));
2869 if (oldFiles.contains(idx))
2870 oldFiles.removeAll(idx);
2871 else
2872 newFiles.append(idx);
2873 }
2874 for (int i = 0; i < newFiles.count(); ++i)
2875 select(newFiles.at(i));
2876 if (lineEdit()->hasFocus())
2877 for (int i = 0; i < oldFiles.count(); ++i)
2878 qFileDialogUi->listView->selectionModel()->select(oldFiles.at(i),
2879 QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
2880 }
2881}
2882
2883/*!
2884 \internal
2885*/
2886void QFileDialogPrivate::_q_updateOkButton()
2887{
2888 Q_Q(QFileDialog);
2889 QPushButton *button = qFileDialogUi->buttonBox->button((acceptMode == QFileDialog::AcceptOpen)
2890 ? QDialogButtonBox::Open : QDialogButtonBox::Save);
2891 if (!button)
2892 return;
2893
2894 bool enableButton = true;
2895 bool isOpenDirectory = false;
2896
2897 QStringList files = q->selectedFiles();
2898 QString lineEditText = lineEdit()->text();
2899
2900 if (lineEditText.startsWith(QLatin1String("//")) || lineEditText.startsWith(QLatin1Char('\\'))) {
2901 button->setEnabled(true);
2902 if (acceptMode == QFileDialog::AcceptSave)
2903 button->setText(acceptLabel);
2904 return;
2905 }
2906
2907 if (files.isEmpty()) {
2908 enableButton = false;
2909 } else if (lineEditText == QLatin1String("..")) {
2910 isOpenDirectory = true;
2911 } else {
2912 switch (fileMode) {
2913 case QFileDialog::DirectoryOnly:
2914 case QFileDialog::Directory: {
2915 QString fn = files.first();
2916 QModelIndex idx = model->index(fn);
2917 if (!idx.isValid())
2918 idx = model->index(getEnvironmentVariable(fn));
2919 if (!idx.isValid() || !model->isDir(idx))
2920 enableButton = false;
2921 break;
2922 }
2923 case QFileDialog::AnyFile: {
2924 QString fn = files.first();
2925 QFileInfo info(fn);
2926 QModelIndex idx = model->index(fn);
2927 QString fileDir;
2928 QString fileName;
2929 if (info.isDir()) {
2930 fileDir = info.canonicalFilePath();
2931 } else {
2932 fileDir = fn.mid(0, fn.lastIndexOf(QLatin1Char('/')));
2933 fileName = fn.mid(fileDir.length() + 1);
2934 }
2935 if (lineEditText.contains(QLatin1String(".."))) {
2936 fileDir = info.canonicalFilePath();
2937 fileName = info.fileName();
2938 }
2939
2940 if (fileDir == q->directory().canonicalPath() && fileName.isEmpty()) {
2941 enableButton = false;
2942 break;
2943 }
2944 if (idx.isValid() && model->isDir(idx)) {
2945 isOpenDirectory = true;
2946 enableButton = true;
2947 break;
2948 }
2949 if (!idx.isValid()) {
2950 int maxLength = maxNameLength(fileDir);
2951 enableButton = maxLength < 0 || fileName.length() <= maxLength;
2952 }
2953 break;
2954 }
2955 case QFileDialog::ExistingFile:
2956 case QFileDialog::ExistingFiles:
2957 for (int i = 0; i < files.count(); ++i) {
2958 QModelIndex idx = model->index(files.at(i));
2959 if (!idx.isValid())
2960 idx = model->index(getEnvironmentVariable(files.at(i)));
2961 if (!idx.isValid()) {
2962 enableButton = false;
2963 break;
2964 }
2965 if (idx.isValid() && model->isDir(idx)) {
2966 isOpenDirectory = true;
2967 break;
2968 }
2969 }
2970 break;
2971 default:
2972 break;
2973 }
2974 }
2975
2976 button->setEnabled(enableButton);
2977 if (acceptMode == QFileDialog::AcceptSave)
2978 button->setText(isOpenDirectory ? QFileDialog::tr("&Open") : acceptLabel);
2979}
2980
2981/*!
2982 \internal
2983*/
2984void QFileDialogPrivate::_q_currentChanged(const QModelIndex &index)
2985{
2986 _q_updateOkButton();
2987 emit q_func()->currentChanged(index.data(QFileSystemModel::FilePathRole).toString());
2988}
2989
2990/*!
2991 \internal
2992
2993 This is called when the user double clicks on a file with the corresponding
2994 model item \a index.
2995*/
2996void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
2997{
2998 Q_Q(QFileDialog);
2999 // My Computer or a directory
3000 QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index;
3001 QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString();
3002 if (path.isEmpty() || model->isDir(sourceIndex)) {
3003 q->setDirectory(path);
3004 emit q->directoryEntered(path);
3005 if (fileMode == QFileDialog::Directory
3006 || fileMode == QFileDialog::DirectoryOnly) {
3007 // ### find out why you have to do both of these.
3008 lineEdit()->setText(QString());
3009 lineEdit()->clear();
3010 }
3011 } else {
3012 // Do not accept when shift-clicking to multi-select a file in environments with single-click-activation (KDE)
3013 if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)
3014 || q->fileMode() != QFileDialog::ExistingFiles || !(QApplication::keyboardModifiers() & Qt::CTRL)) {
3015 q->accept();
3016 }
3017 }
3018}
3019
3020/*!
3021 \internal
3022
3023 Changes the file dialog's current directory to the one specified
3024 by \a path.
3025*/
3026void QFileDialogPrivate::_q_goToDirectory(const QString &path)
3027{
3028 #ifndef QT_NO_MESSAGEBOX
3029 Q_Q(QFileDialog);
3030#endif
3031 QModelIndex index = qFileDialogUi->lookInCombo->model()->index(qFileDialogUi->lookInCombo->currentIndex(),
3032 qFileDialogUi->lookInCombo->modelColumn(),
3033 qFileDialogUi->lookInCombo->rootModelIndex());
3034 QString path2 = path;
3035 if (!index.isValid())
3036 index = mapFromSource(model->index(getEnvironmentVariable(path)));
3037 else {
3038 path2 = index.data(UrlRole).toUrl().toLocalFile();
3039 index = mapFromSource(model->index(path2));
3040 }
3041 QDir dir(path2);
3042 if (!dir.exists())
3043 dir = getEnvironmentVariable(path2);
3044
3045 if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) {
3046 _q_enterDirectory(index);
3047#ifndef QT_NO_MESSAGEBOX
3048 } else {
3049 QString message = QFileDialog::tr("%1\nDirectory not found.\nPlease verify the "
3050 "correct directory name was given.");
3051 QMessageBox::warning(q, q->windowTitle(), message.arg(path2));
3052#endif // QT_NO_MESSAGEBOX
3053 }
3054}
3055
3056// Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)"
3057QStringList qt_clean_filter_list(const QString &filter)
3058{
3059 QRegExp regexp(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
3060 QString f = filter;
3061 int i = regexp.indexIn(f);
3062 if (i >= 0)
3063 f = regexp.cap(2);
3064 return f.split(QLatin1Char(' '), QString::SkipEmptyParts);
3065}
3066
3067/*!
3068 \internal
3069
3070 Sets the current name filter to be nameFilter and
3071 update the qFileDialogUi->fileNameEdit when in AcceptSave mode with the new extension.
3072*/
3073void QFileDialogPrivate::_q_useNameFilter(int index)
3074{
3075 if (index == nameFilters.size()) {
3076 QAbstractItemModel *comboModel = qFileDialogUi->fileTypeCombo->model();
3077 nameFilters.append(comboModel->index(comboModel->rowCount() - 1, 0).data().toString());
3078 }
3079
3080 QString nameFilter = nameFilters.at(index);
3081 QStringList newNameFilters = qt_clean_filter_list(nameFilter);
3082 if (acceptMode == QFileDialog::AcceptSave) {
3083 QString newNameFilterExtension;
3084 if (newNameFilters.count() > 0)
3085 newNameFilterExtension = QFileInfo(newNameFilters.at(0)).suffix();
3086
3087 QString fileName = lineEdit()->text();
3088 const QString fileNameExtension = QFileInfo(fileName).suffix();
3089 if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) {
3090 const int fileNameExtensionLength = fileNameExtension.count();
3091 fileName.replace(fileName.count() - fileNameExtensionLength,
3092 fileNameExtensionLength, newNameFilterExtension);
3093 qFileDialogUi->listView->clearSelection();
3094 lineEdit()->setText(fileName);
3095 }
3096 }
3097
3098 model->setNameFilters(newNameFilters);
3099}
3100
3101/*!
3102 \internal
3103
3104 This is called when the model index corresponding to the current file is changed
3105 from \a index to \a current.
3106*/
3107void QFileDialogPrivate::_q_selectionChanged()
3108{
3109 QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
3110 bool stripDirs = (fileMode != QFileDialog::DirectoryOnly && fileMode != QFileDialog::Directory);
3111
3112 QStringList allFiles;
3113 for (int i = 0; i < indexes.count(); ++i) {
3114 if (stripDirs && model->isDir(mapToSource(indexes.at(i))))
3115 continue;
3116 allFiles.append(indexes.at(i).data().toString());
3117 }
3118 if (allFiles.count() > 1)
3119 for (int i = 0; i < allFiles.count(); ++i) {
3120 allFiles.replace(i, QString(QLatin1Char('"') + allFiles.at(i) + QLatin1Char('"')));
3121 }
3122
3123 QString finalFiles = allFiles.join(QLatin1String(" "));
3124 if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible())
3125 lineEdit()->setText(finalFiles);
3126 else
3127 _q_updateOkButton();
3128}
3129
3130/*!
3131 \internal
3132
3133 Includes hidden files and directories in the items displayed in the dialog.
3134*/
3135void QFileDialogPrivate::_q_showHidden()
3136{
3137 Q_Q(QFileDialog);
3138 QDir::Filters dirFilters = q->filter();
3139 if (showHiddenAction->isChecked())
3140 dirFilters |= QDir::Hidden;
3141 else
3142 dirFilters &= ~QDir::Hidden;
3143 q->setFilter(dirFilters);
3144}
3145
3146/*!
3147 \internal
3148
3149 When parent is root and rows have been inserted when none was there before
3150 then select the first one.
3151*/
3152void QFileDialogPrivate::_q_rowsInserted(const QModelIndex &parent)
3153{
3154 if (!qFileDialogUi->treeView
3155 || parent != qFileDialogUi->treeView->rootIndex()
3156 || !qFileDialogUi->treeView->selectionModel()
3157 || qFileDialogUi->treeView->selectionModel()->hasSelection()
3158 || qFileDialogUi->treeView->model()->rowCount(parent) == 0)
3159 return;
3160}
3161
3162void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString oldName, const QString newName)
3163{
3164 if (fileMode == QFileDialog::Directory || fileMode == QFileDialog::DirectoryOnly) {
3165 if (path == rootPath() && lineEdit()->text() == oldName)
3166 lineEdit()->setText(newName);
3167 }
3168}
3169
3170/*!
3171 \internal
3172
3173 For the list and tree view watch keys to goto parent and back in the history
3174
3175 returns true if handled
3176*/
3177bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
3178
3179 Q_Q(QFileDialog);
3180 switch (event->key()) {
3181 case Qt::Key_Backspace:
3182 _q_navigateToParent();
3183 return true;
3184 case Qt::Key_Back:
3185#ifdef QT_KEYPAD_NAVIGATION
3186 if (QApplication::keypadNavigationEnabled())
3187 return false;
3188#endif
3189 case Qt::Key_Left:
3190 if (event->key() == Qt::Key_Back || event->modifiers() == Qt::AltModifier) {
3191 _q_navigateBackward();
3192 return true;
3193 }
3194 break;
3195 case Qt::Key_Escape:
3196 q->hide();
3197 return true;
3198 default:
3199 break;
3200 }
3201 return false;
3202}
3203
3204QString QFileDialogPrivate::getEnvironmentVariable(const QString &string)
3205{
3206#ifdef Q_OS_UNIX
3207 if (string.size() > 1 && string.startsWith(QLatin1Char('$'))) {
3208 return QString::fromLocal8Bit(getenv(string.mid(1).toLatin1().constData()));
3209 }
3210#else
3211 if (string.size() > 2 && string.startsWith(QLatin1Char('%')) && string.endsWith(QLatin1Char('%'))) {
3212 return QString::fromLocal8Bit(qgetenv(string.mid(1, string.size() - 2).toLatin1().constData()));
3213 }
3214#endif
3215 return string;
3216}
3217
3218void QFileDialogComboBox::init(QFileDialogPrivate *d_pointer) {
3219 d_ptr = d_pointer;
3220 urlModel = new QUrlModel(this);
3221 urlModel->showFullPath = true;
3222 urlModel->setFileSystemModel(d_ptr->model);
3223 setModel(urlModel);
3224}
3225
3226void QFileDialogComboBox::showPopup()
3227{
3228 if (model()->rowCount() > 1)
3229 QComboBox::showPopup();
3230
3231 urlModel->setUrls(QList<QUrl>());
3232 QList<QUrl> list;
3233 QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
3234 while (idx.isValid()) {
3235 QUrl url = QUrl::fromLocalFile(idx.data(QFileSystemModel::FilePathRole).toString());
3236 if (url.isValid())
3237 list.append(url);
3238 idx = idx.parent();
3239 }
3240 // add "my computer"
3241 list.append(QUrl::fromLocalFile(QLatin1String("")));
3242 urlModel->addUrls(list, 0);
3243 idx = model()->index(model()->rowCount() - 1, 0);
3244
3245 // append history
3246 QList<QUrl> urls;
3247 for (int i = 0; i < m_history.count(); ++i) {
3248 QUrl path = QUrl::fromLocalFile(m_history.at(i));
3249 if (!urls.contains(path))
3250 urls.prepend(path);
3251 }
3252 if (urls.count() > 0) {
3253 model()->insertRow(model()->rowCount());
3254 idx = model()->index(model()->rowCount()-1, 0);
3255 // ### TODO maybe add a horizontal line before this
3256 model()->setData(idx, QFileDialog::tr("Recent Places"));
3257 QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model());
3258 if (m) {
3259 Qt::ItemFlags flags = m->flags(idx);
3260 flags &= ~Qt::ItemIsEnabled;
3261 m->item(idx.row(), idx.column())->setFlags(flags);
3262 }
3263 urlModel->addUrls(urls, -1, false);
3264 }
3265 setCurrentIndex(0);
3266
3267 QComboBox::showPopup();
3268}
3269
3270// Exact same as QComboBox::paintEvent(), except we elide the text.
3271void QFileDialogComboBox::paintEvent(QPaintEvent *)
3272{
3273 QStylePainter painter(this);
3274 painter.setPen(palette().color(QPalette::Text));
3275
3276 // draw the combobox frame, focusrect and selected etc.
3277 QStyleOptionComboBox opt;
3278 initStyleOption(&opt);
3279
3280 QRect editRect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
3281 QStyle::SC_ComboBoxEditField, this);
3282 int size = editRect.width() - opt.iconSize.width() - 4;
3283 opt.currentText = opt.fontMetrics.elidedText(opt.currentText, Qt::ElideMiddle, size);
3284 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
3285
3286 // draw the icon and text
3287 painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
3288}
3289
3290QFileDialogListView::QFileDialogListView(QWidget *parent) : QListView(parent)
3291{
3292}
3293
3294void QFileDialogListView::init(QFileDialogPrivate *d_pointer)
3295{
3296 d_ptr = d_pointer;
3297 setSelectionBehavior(QAbstractItemView::SelectRows);
3298 setWrapping(true);
3299 setResizeMode(QListView::Adjust);
3300 setEditTriggers(QAbstractItemView::EditKeyPressed);
3301 setContextMenuPolicy(Qt::CustomContextMenu);
3302#ifndef QT_NO_DRAGANDDROP
3303 setDragDropMode(QAbstractItemView::InternalMove);
3304#endif
3305}
3306
3307QSize QFileDialogListView::sizeHint() const
3308{
3309 int height = qMax(10, sizeHintForRow(0));
3310 return QSize(QListView::sizeHint().width() * 2, height * 30);
3311}
3312
3313void QFileDialogListView::keyPressEvent(QKeyEvent *e)
3314{
3315#ifdef QT_KEYPAD_NAVIGATION
3316 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
3317 QListView::keyPressEvent(e);
3318 return;
3319 }
3320#endif // QT_KEYPAD_NAVIGATION
3321
3322 if (!d_ptr->itemViewKeyboardEvent(e))
3323 QListView::keyPressEvent(e);
3324 e->accept();
3325}
3326
3327QFileDialogTreeView::QFileDialogTreeView(QWidget *parent) : QTreeView(parent)
3328{
3329}
3330
3331void QFileDialogTreeView::init(QFileDialogPrivate *d_pointer)
3332{
3333 d_ptr = d_pointer;
3334 setSelectionBehavior(QAbstractItemView::SelectRows);
3335 setRootIsDecorated(false);
3336 setItemsExpandable(false);
3337 setSortingEnabled(true);
3338 header()->setSortIndicator(0, Qt::AscendingOrder);
3339 header()->setStretchLastSection(false);
3340 setTextElideMode(Qt::ElideMiddle);
3341 setEditTriggers(QAbstractItemView::EditKeyPressed);
3342 setContextMenuPolicy(Qt::CustomContextMenu);
3343#ifndef QT_NO_DRAGANDDROP
3344 setDragDropMode(QAbstractItemView::InternalMove);
3345#endif
3346}
3347
3348void QFileDialogTreeView::keyPressEvent(QKeyEvent *e)
3349{
3350#ifdef QT_KEYPAD_NAVIGATION
3351 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
3352 QTreeView::keyPressEvent(e);
3353 return;
3354 }
3355#endif // QT_KEYPAD_NAVIGATION
3356
3357 if (!d_ptr->itemViewKeyboardEvent(e))
3358 QTreeView::keyPressEvent(e);
3359 e->accept();
3360}
3361
3362QSize QFileDialogTreeView::sizeHint() const
3363{
3364 int height = qMax(10, sizeHintForRow(0));
3365 QSize sizeHint = header()->sizeHint();
3366 return QSize(sizeHint.width() * 4, height * 30);
3367}
3368
3369/*!
3370 // FIXME: this is a hack to avoid propagating key press events
3371 // to the dialog and from there to the "Ok" button
3372*/
3373void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e)
3374{
3375#ifdef QT_KEYPAD_NAVIGATION
3376 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
3377 QLineEdit::keyPressEvent(e);
3378 return;
3379 }
3380#endif // QT_KEYPAD_NAVIGATION
3381
3382 int key = e->key();
3383 QLineEdit::keyPressEvent(e);
3384 if (key != Qt::Key_Escape)
3385 e->accept();
3386 if (hideOnEsc && (key == Qt::Key_Escape || key == Qt::Key_Return || key == Qt::Key_Enter)) {
3387 e->accept();
3388 hide();
3389 d_ptr->currentView()->setFocus(Qt::ShortcutFocusReason);
3390 }
3391}
3392
3393#ifndef QT_NO_FSCOMPLETER
3394
3395QString QFSCompleter::pathFromIndex(const QModelIndex &index) const
3396{
3397 const QFileSystemModel *dirModel;
3398 if (proxyModel)
3399 dirModel = qobject_cast<const QFileSystemModel *>(proxyModel->sourceModel());
3400 else
3401 dirModel = sourceModel;
3402 QString currentLocation = dirModel->rootPath();
3403 QString path = index.data(QFileSystemModel::FilePathRole).toString();
3404 if (!currentLocation.isEmpty() && path.startsWith(currentLocation)) {
3405#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE)
3406 if (currentLocation == QDir::separator())
3407 return path.mid(currentLocation.length());
3408#endif
3409 if (currentLocation.endsWith(QLatin1Char('/')))
3410 return path.mid(currentLocation.length());
3411 else
3412 return path.mid(currentLocation.length()+1);
3413 }
3414 return index.data(QFileSystemModel::FilePathRole).toString();
3415}
3416
3417QStringList QFSCompleter::splitPath(const QString &path) const
3418{
3419 if (path.isEmpty())
3420 return QStringList(completionPrefix());
3421
3422 QString pathCopy = QDir::toNativeSeparators(path);
3423 QString sep = QDir::separator();
3424#if defined(Q_OS_SYMBIAN)
3425 if (pathCopy == QLatin1String("\\"))
3426 return QStringList(pathCopy);
3427#elif defined(Q_OS_WIN)
3428 if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\"))
3429 return QStringList(pathCopy);
3430 QString doubleSlash(QLatin1String("\\\\"));
3431 if (pathCopy.startsWith(doubleSlash))
3432 pathCopy = pathCopy.mid(2);
3433 else
3434 doubleSlash.clear();
3435#elif defined(Q_OS_UNIX)
3436 bool expanded;
3437 pathCopy = qt_tildeExpansion(pathCopy, &expanded);
3438 if (expanded) {
3439 QFileSystemModel *dirModel;
3440 if (proxyModel)
3441 dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel());
3442 else
3443 dirModel = sourceModel;
3444 dirModel->fetchMore(dirModel->index(pathCopy));
3445 }
3446#endif
3447
3448 QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']'));
3449
3450#if defined(Q_OS_SYMBIAN)
3451 QStringList parts = pathCopy.split(re, QString::SkipEmptyParts);
3452 if (pathCopy.endsWith(sep))
3453 parts.append(QString());
3454#elif defined(Q_OS_WIN)
3455 QStringList parts = pathCopy.split(re, QString::SkipEmptyParts);
3456 if (!doubleSlash.isEmpty() && !parts.isEmpty())
3457 parts[0].prepend(doubleSlash);
3458 if (pathCopy.endsWith(sep))
3459 parts.append(QString());
3460#else
3461 QStringList parts = pathCopy.split(re);
3462 if (pathCopy[0] == sep[0]) // read the "/" at the beginning as the split removed it
3463 parts[0] = sep[0];
3464#endif
3465
3466#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
3467 bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':'));
3468#else
3469 bool startsFromRoot = pathCopy[0] == sep[0];
3470#endif
3471 if (parts.count() == 1 || (parts.count() > 1 && !startsFromRoot)) {
3472 const QFileSystemModel *dirModel;
3473 if (proxyModel)
3474 dirModel = qobject_cast<const QFileSystemModel *>(proxyModel->sourceModel());
3475 else
3476 dirModel = sourceModel;
3477 QString currentLocation = QDir::toNativeSeparators(dirModel->rootPath());
3478#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
3479 if (currentLocation.endsWith(QLatin1Char(':')))
3480 currentLocation.append(sep);
3481#endif
3482 if (currentLocation.contains(sep) && path != currentLocation) {
3483 QStringList currentLocationList = splitPath(currentLocation);
3484 while (!currentLocationList.isEmpty()
3485 && parts.count() > 0
3486 && parts.at(0) == QLatin1String("..")) {
3487 parts.removeFirst();
3488 currentLocationList.removeLast();
3489 }
3490 if (!currentLocationList.isEmpty() && currentLocationList.last().isEmpty())
3491 currentLocationList.removeLast();
3492 return currentLocationList + parts;
3493 }
3494 }
3495 return parts;
3496}
3497
3498#endif // QT_NO_COMPLETER
3499
3500#ifdef QT3_SUPPORT
3501/*!
3502 Use selectedFiles() instead.
3503
3504 \oldcode
3505 QString selected = dialog->selectedFile();
3506 \newcode
3507 QStringList files = dialog->selectedFiles();
3508 QString selected;
3509 if (!files.isEmpty())
3510 selected = files[0];
3511 \endcode
3512*/
3513QString QFileDialog::selectedFile() const
3514{
3515 QStringList files = selectedFiles();
3516 return files.size() ? files.at(0) : QString();
3517}
3518
3519/*!
3520 \typedef QFileDialog::Mode
3521
3522 Use QFileDialog::FileMode instead.
3523*/
3524
3525/*!
3526 \fn void QFileDialog::setMode(FileMode m)
3527
3528 Use setFileMode() instead.
3529*/
3530
3531/*!
3532 \fn FileMode QFileDialog::mode() const
3533
3534 Use fileMode() instead.
3535*/
3536
3537/*!
3538 \fn void QFileDialog::setDir(const QString &directory)
3539
3540 Use setDirectory() instead.
3541*/
3542
3543/*!
3544 \fn void QFileDialog::setDir( const QDir &directory )
3545
3546 Use setDirectory() instead.
3547*/
3548
3549/*!
3550 \fn QStringList QFileDialog::getOpenFileNames(const QString &filter,
3551 const QString &dir, QWidget *parent, const char* name,
3552 const QString &caption, QString *selectedFilter, bool resolveSymlinks)
3553
3554 Use the getOpenFileNames() overload that takes \a parent as the first
3555 argument instead.
3556*/
3557
3558/*!
3559 \fn QString QFileDialog::getOpenFileName(const QString &dir,
3560 const QString &filter, QWidget *parent = 0, const char *name,
3561 const QString &caption, QString *selectedFilter, bool resolveSymlinks)
3562
3563 Use the getOpenFileName() overload that takes \a parent as the first
3564 argument instead.
3565*/
3566
3567/*!
3568 \fn QString QFileDialog::getSaveFileName(const QString &dir,
3569 const QString &filter, QWidget *parent, const char *name,
3570 const QString &caption, QString *selectedFilter, bool resolveSymlinks)
3571
3572 Use the getSaveFileName() overload that takes \a parent as the first
3573 argument instead.
3574*/
3575
3576/*!
3577 \fn QString QFileDialog::getExistingDirectory(const QString &dir,
3578 QWidget *parent, const char *name, const QString &caption,
3579 bool dirOnly, bool resolveSymlinks)
3580
3581 Use the getExistingDirectory() overload that takes \a parent as
3582 the first argument instead.
3583*/
3584
3585#endif // QT3_SUPPORT
3586
3587QT_END_NAMESPACE
3588
3589#include "moc_qfiledialog.cpp"
3590
3591#endif // QT_NO_FILEDIALOG
3592