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

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

trunk: Merged in qt 4.6.2 sources.

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