source: trunk/src/gui/dialogs/qfiledialog.cpp@ 858

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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