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

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

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

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