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