summaryrefslogtreecommitdiffstats
path: root/src/qt3support/dialogs/q3filedialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt3support/dialogs/q3filedialog.cpp')
-rw-r--r--src/qt3support/dialogs/q3filedialog.cpp6203
1 files changed, 6203 insertions, 0 deletions
diff --git a/src/qt3support/dialogs/q3filedialog.cpp b/src/qt3support/dialogs/q3filedialog.cpp
new file mode 100644
index 0000000000..4874b6d940
--- /dev/null
+++ b/src/qt3support/dialogs/q3filedialog.cpp
@@ -0,0 +1,6203 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+
+#include "q3filedialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+#include "private/qapplication_p.h"
+#include "q3buttongroup.h"
+#include "q3header.h"
+#include "q3listview.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qcheckbox.h"
+#include "q3cleanuphandler.h"
+#include "qcombobox.h"
+#include "q3combobox.h"
+#include "q3cstring.h"
+#include "qcursor.h"
+#include "qdesktopwidget.h"
+#include "q3dragobject.h"
+#include "qevent.h"
+#include "qfile.h"
+#include "qlabel.h"
+#include "qlayout.h"
+#include "qlibrary.h"
+#include "qlineedit.h"
+#include "q3listbox.h"
+#include "qmap.h"
+#include "qmessagebox.h"
+#include "qmime.h"
+#include "qpainter.h"
+#include "qpointer.h"
+#include "q3popupmenu.h"
+#include "q3progressbar.h"
+#include "q3ptrvector.h"
+#include "qpushbutton.h"
+#include "qregexp.h"
+#include "qsplitter.h"
+#include "q3strlist.h"
+#include "qstyle.h"
+#include "qtimer.h"
+#include "qtoolbutton.h"
+#include "qtooltip.h"
+#include "q3widgetstack.h"
+#include "q3urloperator.h"
+#include "q3vbox.h"
+#include "qurlinfo.h"
+
+#ifdef Q_WS_WIN
+#ifndef QT_NO_THREAD
+# include "qwindowsstyle.h"
+# include "private/qmutexpool_p.h"
+#endif
+#endif // Q_WS_WIN
+
+#ifndef Q_OS_WINCE
+#include <time.h>
+#else
+#include <shellapi.h>
+#endif // Q_OS_WINCE
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef Q_WS_MAC
+#include "qmacstyle_mac.h"
+#include "private/qt_mac_p.h"
+#include "private/qunicodetables_p.h"
+#undef check
+#endif
+
+#if defined(Q_OS_OPENBSD)
+#include <sys/param.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/* XPM */
+static const char * const start_xpm[]={
+ "16 15 8 1",
+ "a c #cec6bd",
+ "# c #000000",
+ "e c #ffff00",
+ "b c #999999",
+ "f c #cccccc",
+ "d c #dcdcdc",
+ "c c #ffffff",
+ ". c None",
+ ".....######aaaaa",
+ "...bb#cccc##aaaa",
+ "..bcc#cccc#d#aaa",
+ ".bcef#cccc#dd#aa",
+ ".bcfe#cccc#####a",
+ ".bcef#ccccccccc#",
+ "bbbbbbbbbbbbccc#",
+ "bccccccccccbbcc#",
+ "bcefefefefee#bc#",
+ ".bcefefefefef#c#",
+ ".bcfefefefefe#c#",
+ "..bcfefefefeeb##",
+ "..bbbbbbbbbbbbb#",
+ "...#############",
+ "................"};
+
+/* XPM */
+static const char * const end_xpm[]={
+ "16 15 9 1",
+ "d c #a0a0a0",
+ "c c #c3c3c3",
+ "# c #cec6bd",
+ ". c #000000",
+ "f c #ffff00",
+ "e c #999999",
+ "g c #cccccc",
+ "b c #ffffff",
+ "a c None",
+ "......####aaaaaa",
+ ".bbbb..###aaaaaa",
+ ".bbbb.c.##aaaaaa",
+ ".bbbb....ddeeeea",
+ ".bbbbbbb.bbbbbe.",
+ ".bbbbbbb.bcfgfe.",
+ "eeeeeeeeeeeeefe.",
+ "ebbbbbbbbbbeege.",
+ "ebfgfgfgfgff.ee.",
+ "aebfgfgfgfgfg.e.",
+ "aebgfgfgfgfgf.e.",
+ "aaebgfgfgfgffe..",
+ "aaeeeeeeeeeeeee.",
+ "aaa.............",
+ "aaaaaaaaaaaaaaaa"};
+
+/* XPM */
+static const char* const open_xpm[]={
+ "16 16 6 1",
+ ". c None",
+ "b c #ffff00",
+ "d c #000000",
+ "* c #999999",
+ "c c #cccccc",
+ "a c #ffffff",
+ "................",
+ "................",
+ "...*****........",
+ "..*aaaaa*.......",
+ ".*abcbcba******.",
+ ".*acbcbcaaaaaa*d",
+ ".*abcbcbcbcbcb*d",
+ "*************b*d",
+ "*aaaaaaaaaa**c*d",
+ "*abcbcbcbcbbd**d",
+ ".*abcbcbcbcbcd*d",
+ ".*acbcbcbcbcbd*d",
+ "..*acbcbcbcbb*dd",
+ "..*************d",
+ "...ddddddddddddd",
+ "................"};
+
+/* XPM */
+static const char * const link_dir_xpm[]={
+ "16 16 10 1",
+ "h c #808080",
+ "g c #a0a0a0",
+ "d c #000000",
+ "b c #ffff00",
+ "f c #303030",
+ "# c #999999",
+ "a c #cccccc",
+ "e c #585858",
+ "c c #ffffff",
+ ". c None",
+ "................",
+ "................",
+ "..#####.........",
+ ".#ababa#........",
+ "#abababa######..",
+ "#cccccccccccc#d.",
+ "#cbababababab#d.",
+ "#cabababababa#d.",
+ "#cbababdddddddd.",
+ "#cababadccccccd.",
+ "#cbababdcececcd.",
+ "#cababadcefdfcd.",
+ "#cbababdccgdhcd.",
+ "#######dccchccd.",
+ ".dddddddddddddd.",
+ "................"};
+
+/* XPM */
+static const char * const link_file_xpm[]={
+ "16 16 10 1",
+ "h c #808080",
+ "g c #a0a0a0",
+ "d c #c3c3c3",
+ ". c #7f7f7f",
+ "c c #000000",
+ "b c #bfbfbf",
+ "f c #303030",
+ "e c #585858",
+ "a c #ffffff",
+ "# c None",
+ "################",
+ "..........######",
+ ".aaaaaaaab.#####",
+ ".aaaaaaaaba.####",
+ ".aaaaaaaacccc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaadc###",
+ ".aaaaaaaaaadc###",
+ ".aaaacccccccc###",
+ ".aaaacaaaaaac###",
+ ".aaaacaeaeaac###",
+ ".aaaacaefcfac###",
+ ".aaaacaagchac###",
+ ".ddddcaaahaac###",
+ "ccccccccccccc###"};
+
+/* XPM */
+static const char* const file_xpm[]={
+ "16 16 5 1",
+ ". c #7f7f7f",
+ "# c None",
+ "c c #000000",
+ "b c #bfbfbf",
+ "a c #ffffff",
+ "################",
+ "..........######",
+ ".aaaaaaaab.#####",
+ ".aaaaaaaaba.####",
+ ".aaaaaaaacccc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".aaaaaaaaaabc###",
+ ".bbbbbbbbbbbc###",
+ "ccccccccccccc###"};
+
+/* XPM */
+static const char * const closed_xpm[]={
+ "16 16 6 1",
+ ". c None",
+ "b c #ffff00",
+ "d c #000000",
+ "* c #999999",
+ "a c #cccccc",
+ "c c #ffffff",
+ "................",
+ "................",
+ "..*****.........",
+ ".*ababa*........",
+ "*abababa******..",
+ "*cccccccccccc*d.",
+ "*cbababababab*d.",
+ "*cabababababa*d.",
+ "*cbababababab*d.",
+ "*cabababababa*d.",
+ "*cbababababab*d.",
+ "*cabababababa*d.",
+ "*cbababababab*d.",
+ "**************d.",
+ ".dddddddddddddd.",
+ "................"};
+
+
+/* XPM */
+static const char* const cdtoparent_xpm[]={
+ "15 13 3 1",
+ ". c None",
+ "* c #000000",
+ "a c #ffff99",
+ "..*****........",
+ ".*aaaaa*.......",
+ "***************",
+ "*aaaaaaaaaaaaa*",
+ "*aaaa*aaaaaaaa*",
+ "*aaa***aaaaaaa*",
+ "*aa*****aaaaaa*",
+ "*aaaa*aaaaaaaa*",
+ "*aaaa*aaaaaaaa*",
+ "*aaaa******aaa*",
+ "*aaaaaaaaaaaaa*",
+ "*aaaaaaaaaaaaa*",
+ "***************"};
+
+
+/* XPM */
+static const char* const newfolder_xpm[] = {
+ "15 14 4 1",
+ " c None",
+ ". c #000000",
+ "+ c #FFFF00",
+ "@ c #FFFFFF",
+ " . ",
+ " ",
+ " . ",
+ " . . ",
+ " .... . . . ",
+ " .+@+@. . . ",
+ ".......... . .",
+ ".@+@+@+@+@.. ",
+ ".+@+@+@+@+. . ",
+ ".@+@+@+@+@. . ",
+ ".+@+@+@+@+. ",
+ ".@+@+@+@+@. ",
+ ".+@+@+@+@+. ",
+ "........... "};
+
+/* XPM */
+static const char* const detailedview_xpm[]={
+ "14 11 3 1",
+ ". c None",
+ "* c #000000",
+ "a c #000099",
+ ".****.***.***.",
+ "..............",
+ "aaaaaaaaaaaaaa",
+ "..............",
+ ".****.***.***.",
+ "..............",
+ ".****.***.***.",
+ "..............",
+ ".****.***.***.",
+ "..............",
+ ".****.***.***."};
+
+/* XPM */
+static const char* const previewinfoview_xpm[]={
+ "13 13 4 1",
+ ". c #00007f",
+ "a c black",
+ "# c #cec6bd",
+ "b c #000000",
+ "..#####aaaaaa",
+ ".#.#bb#a#####",
+ "...####a#bbb#",
+ "#######a#####",
+ "#######a#bb##",
+ "..#####a#####",
+ ".#.#bb#a#bbb#",
+ "...####a#####",
+ "#######a#bb##",
+ "#######a#####",
+ "..#####a#bbb#",
+ ".#.#bb#a#####",
+ "...####aaaaaa"};
+
+/* XPM */
+static const char* const previewcontentsview_xpm[]={
+ "14 13 5 1",
+ ". c #00007f",
+ "a c black",
+ "c c #7f007f",
+ "# c #cec6bd",
+ "b c #000000",
+ "..#####aaaaaaa",
+ ".#.#bb#a#####a",
+ "...####a#ccc#a",
+ "#######a#ccc#a",
+ "#######a#####a",
+ "..#####a#bbb#a",
+ ".#.#bb#a#####a",
+ "...####a#bbb#a",
+ "#######a#####a",
+ "#######a#bbb#a",
+ "..#####a#####a",
+ ".#.#bb#a#####a",
+ "...####aaaaaaa"};
+
+/* XPM */
+static const char* const mclistview_xpm[]={
+ "15 11 4 1",
+ "* c None",
+ "b c #000000",
+ ". c #000099",
+ "a c #ffffff",
+ "...*****...****",
+ ".a.*bbb*.a.*bbb",
+ "...*****...****",
+ "***************",
+ "...*****...****",
+ ".a.*bbb*.a.*bbb",
+ "...*****...****",
+ "***************",
+ "...*****...****",
+ ".a.*bbb*.a.*bbb",
+ "...*****...****"};
+
+/* XPM */
+static const char * const back_xpm [] = {
+ "13 11 3 1",
+ "a c #00ffff",
+ "# c #000000",
+ ". c None",
+ ".....#.......",
+ "....##.......",
+ "...#a#.......",
+ "..#aa########",
+ ".#aaaaaaaaaa#",
+ "#aaaaaaaaaaa#",
+ ".#aaaaaaaaaa#",
+ "..#aa########",
+ "...#a#.......",
+ "....##.......",
+ ".....#......."};
+
+static QPixmap * openFolderIcon = 0;
+static QPixmap * closedFolderIcon = 0;
+static QPixmap * detailViewIcon = 0;
+static QPixmap * multiColumnListViewIcon = 0;
+static QPixmap * cdToParentIcon = 0;
+static QPixmap * newFolderIcon = 0;
+static QPixmap * fifteenTransparentPixels = 0;
+static QPixmap * symLinkDirIcon = 0;
+static QPixmap * symLinkFileIcon = 0;
+static QPixmap * fileIcon = 0;
+static QPixmap * startCopyIcon = 0;
+static QPixmap * endCopyIcon = 0;
+static QPixmap * previewContentsViewIcon = 0;
+static QPixmap * previewInfoViewIcon = 0;
+static QPixmap *goBackIcon = 0;
+static Q3FileIconProvider * fileIconProvider = 0;
+static int lastWidth = 0;
+static int lastHeight = 0;
+static QString * workingDirectory = 0;
+
+static bool bShowHiddenFiles = false;
+static int sortFilesBy = (int)QDir::Name;
+static bool sortAscending = true;
+static bool detailViewMode = false;
+
+static Q3CleanupHandler<QPixmap> qfd_cleanup_pixmap;
+static Q3CleanupHandler<QString> qfd_cleanup_string;
+
+static QString toRootIfNotExists( const QString &path )
+{
+ if ( !path.isEmpty() )
+ return path;
+
+ QFileInfoList drives = QDir::drives();
+ Q_ASSERT( !drives.isEmpty() );
+ return drives.first().filePath();
+}
+
+static bool isDirectoryMode(int m)
+{
+ return m == Q3FileDialog::Directory || m == Q3FileDialog::DirectoryOnly;
+}
+
+static void updateLastSize(Q3FileDialog *that)
+{
+ int extWidth = 0;
+ int extHeight = 0;
+ if (that->extension() && that->extension()->isVisible()) {
+ if (that->orientation() == Qt::Vertical)
+ extHeight = that->extension()->height();
+ else
+ extWidth = that->extension()->width();
+ }
+ lastWidth = that->width() - extWidth;
+ lastHeight = that->height() - extHeight;
+}
+
+// Don't remove the lines below!
+//
+// resolving the W methods manually is needed, because Windows 95 doesn't include
+// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol
+// when Qt calls getEsistingDirectory(), etc.
+#if defined(Q_WS_WIN)
+
+typedef UINT (WINAPI *PtrExtractIconEx)(LPCTSTR,int,HICON*,HICON*,UINT);
+static PtrExtractIconEx ptrExtractIconEx = 0;
+
+static void resolveLibs()
+{
+#ifndef Q_OS_WINCE
+ static bool triedResolve = false;
+
+ if (!triedResolve) {
+#ifndef QT_NO_THREAD
+ // protect initialization
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
+ // check triedResolve again, since another thread may have already
+ // done the initialization
+ if (triedResolve) {
+ // another thread did initialize the security function pointers,
+ // so we shouldn't do it again.
+ return;
+ }
+#endif
+ triedResolve = true;
+ if (qt_winUnicode()) {
+ QLibrary lib(QLatin1String("shell32"));
+ ptrExtractIconEx = (PtrExtractIconEx) lib.resolve("ExtractIconExW");
+ }
+ }
+#endif
+}
+#ifdef Q_OS_WINCE
+#define PtrExtractIconEx ExtractIconEx
+#endif
+
+class QWindowsIconProvider : public Q3FileIconProvider
+{
+public:
+ QWindowsIconProvider(QObject *parent=0, const char *name=0);
+ ~QWindowsIconProvider();
+
+ const QPixmap * pixmap(const QFileInfo &fi);
+
+private:
+ QPixmap defaultFolder;
+ QPixmap defaultFile;
+ QPixmap defaultExe;
+ QPixmap pix;
+ int pixw, pixh;
+ QMap< QString, QPixmap > cache;
+
+};
+#endif
+
+static void makeVariables() {
+ if (!openFolderIcon) {
+ workingDirectory = new QString(toRootIfNotExists( QDir::currentDirPath() ));
+ qfd_cleanup_string.add(&workingDirectory);
+
+ openFolderIcon = new QPixmap((const char **)open_xpm);
+ qfd_cleanup_pixmap.add(&openFolderIcon);
+ symLinkDirIcon = new QPixmap((const char **)link_dir_xpm);
+ qfd_cleanup_pixmap.add(&symLinkDirIcon);
+ symLinkFileIcon = new QPixmap((const char **)link_file_xpm);
+ qfd_cleanup_pixmap.add(&symLinkFileIcon);
+ fileIcon = new QPixmap((const char **)file_xpm);
+ qfd_cleanup_pixmap.add(&fileIcon);
+ closedFolderIcon = new QPixmap((const char **)closed_xpm);
+ qfd_cleanup_pixmap.add(&closedFolderIcon);
+ detailViewIcon = new QPixmap((const char **)detailedview_xpm);
+ qfd_cleanup_pixmap.add(&detailViewIcon);
+ multiColumnListViewIcon = new QPixmap((const char **)mclistview_xpm);
+ qfd_cleanup_pixmap.add(&multiColumnListViewIcon);
+ cdToParentIcon = new QPixmap((const char **)cdtoparent_xpm);
+ qfd_cleanup_pixmap.add(&cdToParentIcon);
+ newFolderIcon = new QPixmap((const char **)newfolder_xpm);
+ qfd_cleanup_pixmap.add(&newFolderIcon);
+ previewInfoViewIcon
+ = new QPixmap((const char **)previewinfoview_xpm);
+ qfd_cleanup_pixmap.add(&previewInfoViewIcon);
+ previewContentsViewIcon
+ = new QPixmap((const char **)previewcontentsview_xpm);
+ qfd_cleanup_pixmap.add(&previewContentsViewIcon);
+ startCopyIcon = new QPixmap((const char **)start_xpm);
+ qfd_cleanup_pixmap.add(&startCopyIcon);
+ endCopyIcon = new QPixmap((const char **)end_xpm);
+ qfd_cleanup_pixmap.add(&endCopyIcon);
+ goBackIcon = new QPixmap((const char **)back_xpm);
+ qfd_cleanup_pixmap.add(&goBackIcon);
+ fifteenTransparentPixels = new QPixmap(closedFolderIcon->width(), 1);
+ qfd_cleanup_pixmap.add(&fifteenTransparentPixels);
+ QBitmap m(fifteenTransparentPixels->width(), 1);
+ m.fill(Qt::color0);
+ fifteenTransparentPixels->setMask(m);
+ bShowHiddenFiles = false;
+ sortFilesBy = (int)QDir::Name;
+ detailViewMode = false;
+#if defined(Q_WS_WIN)
+ if (!fileIconProvider)
+ fileIconProvider = new QWindowsIconProvider(qApp);
+#endif
+ }
+}
+
+/******************************************************************
+ *
+ * Definitions of view classes
+ *
+ ******************************************************************/
+
+class QRenameEdit : public QLineEdit
+{
+ Q_OBJECT
+
+public:
+ QRenameEdit(QWidget *parent);
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+
+signals:
+ void cancelRename();
+ void doRename();
+
+private slots:
+ void slotReturnPressed();
+
+private:
+ bool doRenameAlreadyEmitted;
+};
+
+QRenameEdit::QRenameEdit(QWidget *parent)
+ : QLineEdit(parent, "qt_rename_edit"), doRenameAlreadyEmitted(false)
+{
+ connect(this, SIGNAL(returnPressed()), SLOT(slotReturnPressed()));
+}
+
+class QFileListBox : public Q3ListBox
+{
+ friend class Q3FileDialog;
+
+ Q_OBJECT
+
+private:
+ QFileListBox(QWidget *parent, Q3FileDialog *d);
+
+ void clear();
+ void show();
+ void startRename(bool check = true);
+ void viewportMousePressEvent(QMouseEvent *e);
+ void viewportMouseReleaseEvent(QMouseEvent *e);
+ void viewportMouseDoubleClickEvent(QMouseEvent *e);
+ void viewportMouseMoveEvent(QMouseEvent *e);
+#ifndef QT_NO_DRAGANDDROP
+ void viewportDragEnterEvent(QDragEnterEvent *e);
+ void viewportDragMoveEvent(QDragMoveEvent *e);
+ void viewportDragLeaveEvent(QDragLeaveEvent *e);
+ void viewportDropEvent(QDropEvent *e);
+ bool acceptDrop(const QPoint &pnt, QWidget *source);
+ void setCurrentDropItem(const QPoint &pnt);
+#endif
+ void keyPressEvent(QKeyEvent *e);
+
+private slots:
+ void rename();
+ void cancelRename();
+ void doubleClickTimeout();
+ void changeDirDuringDrag();
+ void dragObjDestroyed();
+ void contentsMoved(int, int);
+
+private:
+ QRenameEdit *lined;
+ Q3FileDialog *filedialog;
+ bool renaming;
+ QTimer* renameTimer;
+ Q3ListBoxItem *renameItem, *dragItem;
+ QPoint pressPos, oldDragPos;
+ bool mousePressed;
+ int urls;
+ QString startDragDir;
+ Q3ListBoxItem *currDropItem;
+ QTimer *changeDirTimer;
+ bool firstMousePressEvent;
+ Q3UrlOperator startDragUrl;
+
+};
+
+
+class Q3FileDialogQFileListView : public Q3ListView
+{
+ Q_OBJECT
+
+public:
+ Q3FileDialogQFileListView(QWidget *parent, Q3FileDialog *d);
+
+ void clear();
+ void startRename(bool check = true);
+ void setSorting(int column, bool increasing = true);
+
+ QRenameEdit *lined;
+ bool renaming;
+ Q3ListViewItem *renameItem;
+
+private:
+ void viewportMousePressEvent(QMouseEvent *e);
+ void viewportMouseDoubleClickEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void viewportMouseReleaseEvent(QMouseEvent *e);
+ void viewportMouseMoveEvent(QMouseEvent *e);
+#ifndef QT_NO_DRAGANDDROP
+ void viewportDragEnterEvent(QDragEnterEvent *e);
+ void viewportDragMoveEvent(QDragMoveEvent *e);
+ void viewportDragLeaveEvent(QDragLeaveEvent *e);
+ void viewportDropEvent(QDropEvent *e);
+ bool acceptDrop(const QPoint &pnt, QWidget *source);
+ void setCurrentDropItem(const QPoint &pnt);
+#endif
+
+private slots:
+ void rename();
+ void cancelRename();
+ void changeSortColumn2(int column);
+ void doubleClickTimeout();
+ void changeDirDuringDrag();
+ void dragObjDestroyed();
+ void contentsMoved(int, int);
+
+private:
+ Q3FileDialog *filedialog;
+ QTimer* renameTimer;
+ QPoint pressPos, oldDragPos;
+ bool mousePressed;
+ int urls;
+ QString startDragDir;
+ Q3ListViewItem *currDropItem, *dragItem;
+ QTimer *changeDirTimer;
+ bool firstMousePressEvent;
+ bool ascending;
+ int sortcolumn;
+ Q3UrlOperator startDragUrl;
+
+};
+
+/****************************************************************************
+ *
+ * Classes for copy progress dialog
+ *
+ ****************************************************************************/
+
+class QFDProgressAnimation : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QFDProgressAnimation(QWidget *parent);
+ void start();
+
+private slots:
+ void next();
+
+protected:
+ void paintEvent(QPaintEvent *e);
+
+private:
+ int step;
+ QTimer *timer;
+
+};
+
+QFDProgressAnimation::QFDProgressAnimation(QWidget *parent)
+ : QWidget(parent, "qt_progressanimation")
+{
+ setFixedSize(300, 50);
+ step = -1;
+ next();
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()),
+ this, SLOT(next()));
+}
+
+void QFDProgressAnimation::start()
+{
+ timer->start(150, false);
+}
+
+void QFDProgressAnimation::next()
+{
+ ++step;
+ if (step > 10)
+ step = 0;
+ repaint();
+}
+
+void QFDProgressAnimation::paintEvent(QPaintEvent *)
+{
+ erase();
+
+ QPainter p;
+ p.begin(this);
+ if (step == 0) {
+ p.drawPixmap(5, (height() - startCopyIcon->height()) / 2,
+ *startCopyIcon);
+ p.drawPixmap(width() - 5 - openFolderIcon->width(),
+ (height() - openFolderIcon->height()) / 2 , *openFolderIcon);
+ } else if (step == 10) {
+ p.drawPixmap(5, (height() - openFolderIcon->height()) / 2,
+ *openFolderIcon);
+ p.drawPixmap(width() - 5 - endCopyIcon->width(),
+ (height() - endCopyIcon->height()) / 2 , *endCopyIcon);
+ } else {
+ p.drawPixmap(5, (height() - openFolderIcon->height()) / 2,
+ *openFolderIcon);
+ p.drawPixmap(width() - 5 - openFolderIcon->width(),
+ (height() - openFolderIcon->height()) / 2 , *openFolderIcon);
+ int x = 10 + openFolderIcon->width();
+ int w = width() - 2 * x;
+ int s = w / 9;
+ p.drawPixmap(x + s * step, (height() - fileIcon->height()) / 2 - fileIcon->height(),
+ *fileIcon);
+ }
+}
+
+
+class QFDProgressDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ QFDProgressDialog(QWidget *parent, const QString &fn, int steps);
+
+ void setReadProgress(int p);
+ void setWriteProgress(int p);
+ void setWriteLabel(const QString &s);
+
+signals:
+ void cancelled();
+
+private:
+ Q3ProgressBar *readBar;
+ Q3ProgressBar *writeBar;
+ QLabel *writeLabel;
+ QFDProgressAnimation *animation;
+
+};
+
+QFDProgressDialog::QFDProgressDialog(QWidget *parent, const QString &fn, int steps)
+ : QDialog(parent, "", true)
+{
+ setWindowTitle(Q3FileDialog::tr("Copy or Move a File"));
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setSpacing(5);
+ layout->setMargin(5);
+
+ animation = new QFDProgressAnimation(this);
+ layout->addWidget(animation);
+
+ layout->addWidget(new QLabel(Q3FileDialog::tr("Read: %1").arg(fn),
+ this, "qt_read_lbl"));
+ readBar = new Q3ProgressBar(steps, this, "qt_readbar");
+ readBar->reset();
+ readBar->setProgress(0);
+ layout->addWidget(readBar);
+ writeLabel = new QLabel(Q3FileDialog::tr("Write: %1").arg(QString()),
+ this, "qt_write_lbl");
+ layout->addWidget(writeLabel);
+ writeBar = new Q3ProgressBar(steps, this, "qt_writebar");
+ writeBar->reset();
+ writeBar->setProgress(0);
+ layout->addWidget(writeBar);
+
+ QPushButton *b = new QPushButton(Q3FileDialog::tr("Cancel"), this,
+ "qt_cancel_btn");
+ b->setFixedSize(b->sizeHint());
+ layout->addWidget(b);
+ connect(b, SIGNAL(clicked()),
+ this, SIGNAL(cancelled()));
+
+ animation->start();
+}
+
+void QFDProgressDialog::setReadProgress(int p)
+{
+ readBar->setProgress(p);
+}
+
+void QFDProgressDialog::setWriteProgress(int p)
+{
+ writeBar->setProgress(p);
+}
+
+void QFDProgressDialog::setWriteLabel(const QString &s)
+{
+ writeLabel->setText(Q3FileDialog::tr("Write: %1").arg(s));
+}
+
+/************************************************************************
+ *
+ * Private Q3FileDialog members
+ *
+ ************************************************************************/
+
+class Q3FileDialogPrivate {
+public:
+ ~Q3FileDialogPrivate();
+
+ QStringList history;
+
+ bool geometryDirty;
+ Q3ComboBox * paths;
+ QComboBox * types;
+ QLabel * pathL;
+ QLabel * fileL;
+ QLabel * typeL;
+
+ QVBoxLayout * topLevelLayout;
+ QHBoxLayout *buttonLayout, *leftLayout, *rightLayout;
+ Q3PtrList<QHBoxLayout> extraWidgetsLayouts;
+ Q3PtrList<QLabel> extraLabels;
+ Q3PtrList<QWidget> extraWidgets;
+ Q3PtrList<QWidget> extraButtons;
+ Q3PtrList<QAbstractButton> toolButtons;
+
+ Q3WidgetStack * stack;
+
+ QToolButton * cdToParent, *newFolder, * detailView, * mcView,
+ *previewInfo, *previewContents, *goBack;
+ Q3ButtonGroup * modeButtons;
+
+ QString currentFileName;
+ Q3ListViewItem *last;
+
+ Q3ListBoxItem *lastEFSelected;
+
+ struct File: public Q3ListViewItem {
+ File(Q3FileDialogPrivate * dlgp,
+ const QUrlInfo * fi, Q3ListViewItem * parent)
+ : Q3ListViewItem(parent, dlgp->last), info(*fi), d(dlgp), i(0), hasMimePixmap(false)
+ { setup(); dlgp->last = this; }
+ File(Q3FileDialogPrivate * dlgp,
+ const QUrlInfo * fi, Q3ListView * parent)
+ : Q3ListViewItem(parent, dlgp->last), info(*fi), d(dlgp), i(0), hasMimePixmap(false)
+ { setup(); dlgp->last = this; }
+ File(Q3FileDialogPrivate * dlgp,
+ const QUrlInfo * fi, Q3ListView * parent, Q3ListViewItem * after)
+ : Q3ListViewItem(parent, after), info(*fi), d(dlgp), i(0), hasMimePixmap(false)
+ { setup(); if (!nextSibling()) dlgp->last = this; }
+ ~File();
+
+ QString text(int column) const;
+ const QPixmap * pixmap(int) const;
+
+ QUrlInfo info;
+ Q3FileDialogPrivate * d;
+ Q3ListBoxItem *i;
+ bool hasMimePixmap;
+ };
+
+ class MCItem: public Q3ListBoxItem {
+ public:
+ MCItem(Q3ListBox *, Q3ListViewItem * item);
+ MCItem(Q3ListBox *, Q3ListViewItem * item, Q3ListBoxItem *after);
+ QString text() const;
+ const QPixmap *pixmap() const;
+ int height(const Q3ListBox *) const;
+ int width(const Q3ListBox *) const;
+ void paint(QPainter *);
+ Q3ListViewItem * i;
+ };
+
+ class UrlInfoList : public Q3PtrList<QUrlInfo> {
+ public:
+ UrlInfoList() { setAutoDelete(true); }
+ int compareItems(Q3PtrCollection::Item n1, Q3PtrCollection::Item n2) {
+ if (!n1 || !n2)
+ return 0;
+
+ QUrlInfo *i1 = (QUrlInfo *)n1;
+ QUrlInfo *i2 = (QUrlInfo *)n2;
+
+ if (i1->isDir() && !i2->isDir())
+ return -1;
+ if (!i1->isDir() && i2->isDir())
+ return 1;
+
+ if (i1->name() == QLatin1String(".."))
+ return -1;
+ if (i2->name() == QLatin1String(".."))
+ return 1;
+
+ if (sortFilesBy == QDir::Name) {
+#if defined(Q_OS_WIN32)
+ QString name1 = i1->name().lower();
+ QString name2 = i2->name().lower();
+ return name1.localeAwareCompare( name2 );
+#else
+ QString name1 = i1->name();
+ QString name2 = i2->name();
+ return name1.localeAwareCompare( name2 );
+#endif
+ }
+ if (QUrlInfo::equal(*i1, *i2, sortFilesBy))
+ return 0;
+ else if (QUrlInfo::greaterThan(*i1, *i2, sortFilesBy))
+ return 1;
+ else if (QUrlInfo::lessThan(*i1, *i2, sortFilesBy))
+ return -1;
+ // can't happen...
+ return 0;
+ }
+ QUrlInfo *operator[](int i) {
+ return at(i);
+ }
+ };
+
+ UrlInfoList sortedList;
+ Q3PtrList<File> pendingItems;
+
+ QFileListBox * moreFiles;
+
+ Q3FileDialog::Mode mode;
+
+ QString rw;
+ QString ro;
+ QString wo;
+ QString inaccessible;
+
+ QString symLinkToFile;
+ QString file;
+ QString symLinkToDir;
+ QString dir;
+ QString symLinkToSpecial;
+ QString special;
+ Q3WidgetStack *preview;
+ bool infoPreview, contentsPreview;
+ QSplitter *splitter;
+ Q3UrlOperator url, oldUrl;
+ QWidget *infoPreviewWidget, *contentsPreviewWidget;
+ Q3FilePreview *infoPreviewer, *contentsPreviewer;
+ bool hadDotDot;
+
+ bool ignoreNextKeyPress;
+ // ignores the next refresh operation in case the user forced a selection
+ bool ignoreNextRefresh;
+ QFDProgressDialog *progressDia;
+ bool checkForFilter;
+ bool ignoreStop;
+
+ QTimer *mimeTypeTimer;
+ const Q3NetworkOperation *currListChildren;
+
+ // this is similar to QUrl::encode but does encode "*" and
+ // doesn't encode whitespaces
+ static QString encodeFileName(const QString& fName) {
+
+ QString newStr;
+ Q3CString cName = fName.utf8();
+ const Q3CString sChars(
+#ifdef Q_WS_WIN
+ "#%"
+#else
+ "<>#@\"&%$:,;?={}|^~[]\'`\\*"
+#endif
+ );
+
+ int len = cName.length();
+ if (!len)
+ return QString();
+ for (int i = 0; i < len ;++i) {
+ uchar inCh = (uchar)cName[i];
+ if (inCh >= 128 || sChars.contains(inCh))
+ {
+ newStr += QLatin1Char('%');
+ ushort c = inCh / 16;
+ c += c > 9 ? 'A' - 10 : '0';
+ newStr += QLatin1Char((char)c);
+ c = inCh % 16;
+ c += c > 9 ? 'A' - 10 : '0';
+ newStr += QLatin1Char((char)c);
+ } else {
+ newStr += QLatin1Char((char)inCh);
+ }
+ }
+ return newStr;
+ }
+
+ static bool fileExists(const Q3UrlOperator &url, const QString& name)
+ {
+ Q3Url u(url, Q3FileDialogPrivate::encodeFileName(name));
+ if (u.isLocalFile()) {
+ QFileInfo f(u.path());
+ return f.exists();
+ } else {
+ Q3NetworkProtocol *p = Q3NetworkProtocol::getNetworkProtocol(url.protocol());
+ if (p && (p->supportedOperations()&Q3NetworkProtocol::OpListChildren)) {
+ QUrlInfo ui(url.info(name.isEmpty() ? QString::fromLatin1(".") : name));
+ return ui.isValid();
+ }
+ }
+ return true;
+ }
+
+#ifndef Q_NO_CURSOR
+ bool cursorOverride; // Remember if the cursor was overridden or not.
+#endif
+};
+
+Q3FileDialogPrivate::~Q3FileDialogPrivate()
+{
+ delete modeButtons;
+}
+
+
+
+/************************************************************************
+ *
+ * Internal class QRenameEdit
+ *
+ ************************************************************************/
+
+void QRenameEdit::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Escape)
+ emit cancelRename();
+ else
+ QLineEdit::keyPressEvent(e);
+ e->accept();
+}
+
+void QRenameEdit::focusOutEvent(QFocusEvent *)
+{
+ if (!doRenameAlreadyEmitted) {
+ doRenameAlreadyEmitted = true;
+ emit doRename();
+ }
+}
+
+void QRenameEdit::slotReturnPressed()
+{
+ doRenameAlreadyEmitted = true;
+ emit doRename();
+}
+
+/************************************************************************
+ *
+ * Internal class QFileListBox
+ *
+ ************************************************************************/
+
+QFileListBox::QFileListBox(QWidget *parent, Q3FileDialog *dlg)
+ : Q3ListBox(parent, "filelistbox"), filedialog(dlg),
+ renaming(false), renameItem(0), mousePressed(false),
+ firstMousePressEvent(true)
+{
+ changeDirTimer = new QTimer(this);
+ Q3VBox *box = new Q3VBox(viewport(), "qt_vbox");
+ box->setFrameStyle(QFrame::Box | QFrame::Plain);
+ lined = new QRenameEdit(box);
+ lined->setFixedHeight(lined->sizeHint().height());
+ box->hide();
+ box->setBackgroundRole(QPalette::Base);
+ renameTimer = new QTimer(this);
+ connect(lined, SIGNAL(doRename()),
+ this, SLOT (rename()));
+ connect(lined, SIGNAL(cancelRename()),
+ this, SLOT(cancelRename()));
+ connect(renameTimer, SIGNAL(timeout()),
+ this, SLOT(doubleClickTimeout()));
+ connect(changeDirTimer, SIGNAL(timeout()),
+ this, SLOT(changeDirDuringDrag()));
+ connect(this, SIGNAL(contentsMoving(int,int)),
+ this, SLOT(contentsMoved(int,int)));
+ viewport()->setAcceptDrops(true);
+ dragItem = 0;
+}
+
+void QFileListBox::show()
+{
+ setBackgroundRole(QPalette::Base);
+ viewport()->setBackgroundRole(QPalette::Base);
+ Q3ListBox::show();
+}
+
+void QFileListBox::keyPressEvent(QKeyEvent *e)
+{
+ if ((e->key() == Qt::Key_Enter ||
+ e->key() == Qt::Key_Return) &&
+ renaming)
+ return;
+
+ QString keyPressed = ((QKeyEvent *)e)->text().toLower();
+ QChar keyChar = keyPressed[0];
+ if (keyChar.isLetterOrNumber()) {
+ Q3ListBoxItem * i = 0;
+ if (currentItem() != -1)
+ i = item(currentItem());
+ else
+ i = firstItem();
+ if (i->next())
+ i = i->next();
+ else
+ i = firstItem();
+ while (i != item(currentItem())) {
+ QString it = text(index(i));
+ if (it[0].toLower() == keyChar) {
+ clearSelection();
+ setCurrentItem(i);
+ } else {
+ if (i->next())
+ i = i->next();
+ else {
+ if (!item(currentItem())) {
+ clearSelection();
+ break;
+ }
+ i = firstItem();
+ }
+ }
+ }
+ }
+ cancelRename();
+ Q3ListBox::keyPressEvent(e);
+}
+
+void QFileListBox::viewportMousePressEvent(QMouseEvent *e)
+{
+ pressPos = e->pos();
+ mousePressed = false;
+
+ bool didRename = renaming;
+
+ cancelRename();
+ if (!hasFocus() && !viewport()->hasFocus())
+ setFocus();
+
+ if (e->button() != Qt::LeftButton) {
+ Q3ListBox::viewportMousePressEvent(e);
+ firstMousePressEvent = false;
+ return;
+ }
+
+ int i = currentItem();
+ bool wasSelected = false;
+ if (i != -1)
+ wasSelected = item(i)->isSelected();
+ Q3ListBox::mousePressEvent(e);
+
+ Q3FileDialogPrivate::MCItem *i1 = (Q3FileDialogPrivate::MCItem*)item(currentItem());
+ if (i1)
+ mousePressed = (!((Q3FileDialogPrivate::File*)i1->i)->info.isDir())
+ || (filedialog->mode() == Q3FileDialog::Directory) || (filedialog->mode() == Q3FileDialog::DirectoryOnly);
+
+ if (itemAt(e->pos()) != item(i)) {
+ firstMousePressEvent = false;
+ return;
+ }
+
+ if (!firstMousePressEvent && !didRename && i == currentItem() && currentItem() != -1 &&
+ wasSelected && QUrlInfo(filedialog->d->url.info(QString(QLatin1Char('.')))).isWritable() && item(currentItem())->text() != QLatin1String("..")) {
+ renameTimer->start(QApplication::doubleClickInterval(), true);
+ renameItem = item(i);
+ }
+
+ firstMousePressEvent = false;
+}
+
+void QFileListBox::viewportMouseReleaseEvent(QMouseEvent *e)
+{
+ dragItem = 0;
+ Q3ListBox::viewportMouseReleaseEvent(e);
+ mousePressed = false;
+}
+
+void QFileListBox::viewportMouseDoubleClickEvent(QMouseEvent *e)
+{
+ renameTimer->stop();
+ Q3ListBox::viewportMouseDoubleClickEvent(e);
+}
+
+void QFileListBox::viewportMouseMoveEvent(QMouseEvent *e)
+{
+ if (!dragItem)
+ dragItem = itemAt(e->pos());
+ renameTimer->stop();
+#ifndef QT_NO_DRAGANDDROP
+ if ( (pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance() && mousePressed) {
+ Q3ListBoxItem *item = dragItem;
+ dragItem = 0;
+ if (item) {
+ if (!itemRect(item).contains(e->pos()))
+ return;
+ Q3UriDrag* drag = new Q3UriDrag(viewport());
+ QStringList files;
+ if (filedialog->mode() == Q3FileDialog::ExistingFiles)
+ files = filedialog->selectedFiles();
+ else
+ files = QStringList(filedialog->selectedFile());
+ drag->setFileNames(files);
+
+ if (lined->parentWidget()->isVisible())
+ cancelRename();
+
+ connect(drag, SIGNAL(destroyed()),
+ this, SLOT(dragObjDestroyed()));
+ drag->drag();
+
+ mousePressed = false;
+ }
+ } else
+#endif
+ {
+ Q3ListBox::viewportMouseMoveEvent(e);
+ }
+
+}
+
+void QFileListBox::dragObjDestroyed()
+{
+#ifndef QT_NO_DRAGANDDROP
+ //#######
+ //filedialog->rereadDir();
+#endif
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QFileListBox::viewportDragEnterEvent(QDragEnterEvent *e)
+{
+ startDragUrl = filedialog->d->url;
+ startDragDir = filedialog->dirPath();
+ currDropItem = 0;
+
+ if (!Q3UriDrag::canDecode(e)) {
+ e->ignore();
+ return;
+ }
+
+ QStringList l;
+ Q3UriDrag::decodeLocalFiles(e, l);
+ urls = (int)l.count();
+
+ if (acceptDrop(e->pos(), e->source())) {
+ e->accept();
+ setCurrentDropItem(e->pos());
+ } else {
+ e->ignore();
+ setCurrentDropItem(QPoint(-1, -1));
+ }
+
+ oldDragPos = e->pos();
+}
+
+void QFileListBox::viewportDragMoveEvent(QDragMoveEvent *e)
+{
+ if (acceptDrop(e->pos(), e->source())) {
+ switch (e->action()) {
+ case QDropEvent::Copy:
+ e->acceptAction();
+ break;
+ case QDropEvent::Move:
+ e->acceptAction();
+ break;
+ case QDropEvent::Link:
+ break;
+ default:
+ break;
+ }
+ if (oldDragPos != e->pos())
+ setCurrentDropItem(e->pos());
+ } else {
+ changeDirTimer->stop();
+ e->ignore();
+ setCurrentDropItem(QPoint(-1, -1));
+ }
+
+ oldDragPos = e->pos();
+}
+
+void QFileListBox::viewportDragLeaveEvent(QDragLeaveEvent *)
+{
+ changeDirTimer->stop();
+ setCurrentDropItem(QPoint(-1, -1));
+//########
+// if (startDragDir != filedialog->d->url)
+// filedialog->setUrl(startDragUrl);
+}
+
+void QFileListBox::viewportDropEvent(QDropEvent *e)
+{
+ changeDirTimer->stop();
+
+ if (!Q3UriDrag::canDecode(e)) {
+ e->ignore();
+ return;
+ }
+
+ Q3StrList l;
+ Q3UriDrag::decode(e, l);
+
+ bool move = e->action() == QDropEvent::Move;
+// bool supportAction = move || e->action() == QDropEvent::Copy;
+
+ Q3UrlOperator dest;
+ if (currDropItem)
+ dest = Q3UrlOperator(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text()));
+ else
+ dest = filedialog->d->url;
+ QStringList lst;
+ for (uint i = 0; i < l.count(); ++i) {
+ lst << QLatin1String(l.at(i));
+ }
+
+ filedialog->d->url.copy(lst, dest, move);
+
+ // ##### what is supportAction for?
+ e->acceptAction();
+ currDropItem = 0;
+}
+
+bool QFileListBox::acceptDrop(const QPoint &pnt, QWidget *source)
+{
+ Q3ListBoxItem *item = itemAt(pnt);
+ if (!item || (item && !itemRect(item).contains(pnt))) {
+ if (source == viewport() && startDragDir == filedialog->dirPath())
+ return false;
+ return true;
+ }
+
+ QUrlInfo fi(filedialog->d->url.info(item->text().isEmpty() ? QString::fromLatin1(".") : item->text()));
+
+ if (fi.isDir() && itemRect(item).contains(pnt))
+ return true;
+ return false;
+}
+
+void QFileListBox::setCurrentDropItem(const QPoint &pnt)
+{
+ changeDirTimer->stop();
+
+ Q3ListBoxItem *item = 0;
+ if (pnt != QPoint(-1, -1))
+ item = itemAt(pnt);
+ if (item && !QUrlInfo(filedialog->d->url.info(item->text().isEmpty() ? QString::fromLatin1(".") : item->text())).isDir())
+ item = 0;
+ if (item && !itemRect(item).contains(pnt))
+ item = 0;
+
+ currDropItem = item;
+ if (currDropItem)
+ setCurrentItem(currDropItem);
+ changeDirTimer->start(750);
+}
+#endif // QT_NO_DRAGANDDROP
+
+void QFileListBox::changeDirDuringDrag()
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (!currDropItem)
+ return;
+ changeDirTimer->stop();
+ Q3Url u(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text()));
+ filedialog->setDir(u);
+ currDropItem = 0;
+#endif
+}
+
+void QFileListBox::doubleClickTimeout()
+{
+ startRename();
+ renameTimer->stop();
+}
+
+void QFileListBox::startRename(bool check)
+{
+ if (check && (!renameItem || renameItem != item(currentItem())))
+ return;
+
+ int i = currentItem();
+ setSelected(i, true);
+ QRect r = itemRect(item(i));
+ int bdr = item(i)->pixmap() ?
+ item(i)->pixmap()->width() : 16;
+ int x = r.x() + bdr;
+ int y = r.y();
+ int w = item(i)->width(this) - bdr;
+ int h = qMax(lined->height() + 2, r.height());
+ y = y + r.height() / 2 - h / 2;
+
+ lined->parentWidget()->setGeometry(x, y, w + 6, h);
+ lined->setFocus();
+ lined->setText(item(i)->text());
+ lined->selectAll();
+ lined->setFrame(false);
+ lined->parentWidget()->show();
+ viewport()->setFocusProxy(lined);
+ renaming = true;
+}
+
+void QFileListBox::clear()
+{
+ cancelRename();
+ Q3ListBox::clear();
+}
+
+void QFileListBox::rename()
+{
+ if (!lined->text().isEmpty()) {
+ QString file = currentText();
+
+ if (lined->text() != file)
+ filedialog->d->url.rename(file, lined->text());
+ }
+ cancelRename();
+}
+
+void QFileListBox::cancelRename()
+{
+ renameItem = 0;
+ lined->parentWidget()->hide();
+ viewport()->setFocusProxy(this);
+ renaming = false;
+ updateItem(currentItem());
+ if (lined->hasFocus())
+ viewport()->setFocus();
+}
+
+void QFileListBox::contentsMoved(int, int)
+{
+ changeDirTimer->stop();
+#ifndef QT_NO_DRAGANDDROP
+ setCurrentDropItem(QPoint(-1, -1));
+#endif
+}
+
+/************************************************************************
+ *
+ * Internal class QFileListView
+ *
+ ************************************************************************/
+
+Q3FileDialogQFileListView::Q3FileDialogQFileListView(QWidget *parent, Q3FileDialog *dlg)
+ : Q3ListView(parent, "qt_filedlg_listview"), renaming(false), renameItem(0),
+ filedialog(dlg), mousePressed(false),
+ firstMousePressEvent(true)
+{
+ changeDirTimer = new QTimer(this);
+ Q3VBox *box = new Q3VBox(viewport(), "qt_vbox");
+ box->setFrameStyle(QFrame::Box | QFrame::Plain);
+ lined = new QRenameEdit(box);
+ lined->setFixedHeight(lined->sizeHint().height());
+ box->hide();
+ box->setBackgroundRole(QPalette::Base);
+ renameTimer = new QTimer(this);
+ connect(lined, SIGNAL(doRename()),
+ this, SLOT (rename()));
+ connect(lined, SIGNAL(cancelRename()),
+ this, SLOT(cancelRename()));
+ header()->setMovingEnabled(false);
+ connect(renameTimer, SIGNAL(timeout()),
+ this, SLOT(doubleClickTimeout()));
+ connect(changeDirTimer, SIGNAL(timeout()),
+ this, SLOT(changeDirDuringDrag()));
+ disconnect(header(), SIGNAL(sectionClicked(int)),
+ this, SLOT(changeSortColumn(int)));
+ connect(header(), SIGNAL(sectionClicked(int)),
+ this, SLOT(changeSortColumn2(int)));
+ connect(this, SIGNAL(contentsMoving(int,int)),
+ this, SLOT(contentsMoved(int,int)));
+
+ viewport()->setAcceptDrops(true);
+ sortcolumn = 0;
+ ascending = true;
+ dragItem = 0;
+}
+
+void Q3FileDialogQFileListView::setSorting(int column, bool increasing)
+{
+ if (column == -1) {
+ Q3ListView::setSorting(column, increasing);
+ return;
+ }
+
+ sortAscending = ascending = increasing;
+ sortcolumn = column;
+ switch (column) {
+ case 0:
+ sortFilesBy = QDir::Name;
+ break;
+ case 1:
+ sortFilesBy = QDir::Size;
+ break;
+ case 3:
+ sortFilesBy = QDir::Time;
+ break;
+ default:
+ sortFilesBy = QDir::Name; // #### ???
+ break;
+ }
+
+ filedialog->resortDir();
+}
+
+void Q3FileDialogQFileListView::changeSortColumn2(int column)
+{
+ int lcol = header()->mapToLogical(column);
+ setSorting(lcol, sortcolumn == lcol ? !ascending : true);
+}
+
+void Q3FileDialogQFileListView::keyPressEvent(QKeyEvent *e)
+{
+ if ((e->key() == Qt::Key_Enter ||
+ e->key() == Qt::Key_Return) &&
+ renaming)
+ return;
+
+ QString keyPressed = e->text().toLower();
+ QChar keyChar = keyPressed[0];
+ if (keyChar.isLetterOrNumber()) {
+ Q3ListViewItem * i = 0;
+ if (currentItem())
+ i = currentItem();
+ else
+ i = firstChild();
+ if (i->nextSibling())
+ i = i->nextSibling();
+ else
+ i = firstChild();
+ while (i != currentItem()) {
+ QString it = i->text(0);
+ if (it[0].toLower() == keyChar) {
+ clearSelection();
+ ensureItemVisible(i);
+ setCurrentItem(i);
+ } else {
+ if (i->nextSibling())
+ i = i->nextSibling();
+ else
+ i = firstChild();
+ }
+ }
+ return;
+ }
+
+ cancelRename();
+ Q3ListView::keyPressEvent(e);
+}
+
+void Q3FileDialogQFileListView::viewportMousePressEvent(QMouseEvent *e)
+{
+ pressPos = e->pos();
+ mousePressed = false;
+
+ bool didRename = renaming;
+ cancelRename();
+ if (!hasFocus() && !viewport()->hasFocus())
+ setFocus();
+
+ if (e->button() != Qt::LeftButton) {
+ Q3ListView::viewportMousePressEvent(e);
+ firstMousePressEvent = false;
+ return;
+ }
+
+ Q3ListViewItem *i = currentItem();
+ Q3ListView::viewportMousePressEvent(e);
+
+ Q3FileDialogPrivate::File *i1 = (Q3FileDialogPrivate::File*)currentItem();
+ if (i1)
+ mousePressed = !i1->info.isDir() || (filedialog->mode() == Q3FileDialog::Directory) || (filedialog->mode() == Q3FileDialog::DirectoryOnly);
+
+
+ if (itemAt(e->pos()) != i ||
+ e->x() + contentsX() > columnWidth(0)) {
+ firstMousePressEvent = false;
+ return;
+ }
+
+ if (!firstMousePressEvent && !didRename && i == currentItem() && currentItem() &&
+ QUrlInfo(filedialog->d->url.info(QString(QLatin1Char('.')))).isWritable() && currentItem()->text(0) != QLatin1String("..")) {
+ renameTimer->start(QApplication::doubleClickInterval(), true);
+ renameItem = currentItem();
+ }
+
+ firstMousePressEvent = false;
+}
+
+void Q3FileDialogQFileListView::viewportMouseDoubleClickEvent(QMouseEvent *e)
+{
+ renameTimer->stop();
+ Q3ListView::viewportMouseDoubleClickEvent(e);
+}
+
+void Q3FileDialogQFileListView::viewportMouseReleaseEvent(QMouseEvent *e)
+{
+ Q3ListView::viewportMouseReleaseEvent(e);
+ mousePressed = false;
+ dragItem = 0;
+}
+
+void Q3FileDialogQFileListView::viewportMouseMoveEvent(QMouseEvent *e)
+{
+ renameTimer->stop();
+ if (!dragItem)
+ dragItem = itemAt(e->pos());
+#ifndef QT_NO_DRAGANDDROP
+ if ( (pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance() && mousePressed) {
+ Q3ListViewItem *item = dragItem;
+ dragItem = 0;
+ if (item) {
+ Q3UriDrag* drag = new Q3UriDrag(viewport());
+ QStringList files;
+ if (filedialog->mode() == Q3FileDialog::ExistingFiles)
+ files = filedialog->selectedFiles();
+ else
+ files = QStringList(filedialog->selectedFile());
+ drag->setFileNames(files);
+
+ if (lined->isVisible())
+ cancelRename();
+
+ connect(drag, SIGNAL(destroyed()),
+ this, SLOT(dragObjDestroyed()));
+ drag->drag();
+
+ mousePressed = false;
+ }
+ }
+#endif
+}
+
+void Q3FileDialogQFileListView::dragObjDestroyed()
+{
+#ifndef QT_NO_DRAGANDDROP
+ //######
+ //filedialog->rereadDir();
+#endif
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void Q3FileDialogQFileListView::viewportDragEnterEvent(QDragEnterEvent *e)
+{
+ startDragUrl = filedialog->d->url;
+ startDragDir = filedialog->dirPath();
+ currDropItem = 0;
+
+ if (!Q3UriDrag::canDecode(e)) {
+ e->ignore();
+ return;
+ }
+
+ QStringList l;
+ Q3UriDrag::decodeLocalFiles(e, l);
+ urls = (int)l.count();
+
+ if (acceptDrop(e->pos(), e->source())) {
+ e->accept();
+ setCurrentDropItem(e->pos());
+ } else {
+ e->ignore();
+ setCurrentDropItem(QPoint(-1, -1));
+ }
+
+ oldDragPos = e->pos();
+}
+
+void Q3FileDialogQFileListView::viewportDragMoveEvent(QDragMoveEvent *e)
+{
+ if (acceptDrop(e->pos(), e->source())) {
+ if (oldDragPos != e->pos())
+ setCurrentDropItem(e->pos());
+ switch (e->action()) {
+ case QDropEvent::Copy:
+ e->acceptAction();
+ break;
+ case QDropEvent::Move:
+ e->acceptAction();
+ break;
+ case QDropEvent::Link:
+ break;
+ default:
+ break;
+ }
+ } else {
+ changeDirTimer->stop();
+ e->ignore();
+ setCurrentDropItem(QPoint(-1, -1));
+ }
+
+ oldDragPos = e->pos();
+}
+
+void Q3FileDialogQFileListView::viewportDragLeaveEvent(QDragLeaveEvent *)
+{
+ changeDirTimer->stop();
+ setCurrentDropItem(QPoint(-1, -1));
+//########
+// if (startDragDir != filedialog->d->url)
+// filedialog->setUrl(startDragUrl);
+}
+
+void Q3FileDialogQFileListView::viewportDropEvent(QDropEvent *e)
+{
+ changeDirTimer->stop();
+
+ if (!Q3UriDrag::canDecode(e)) {
+ e->ignore();
+ return;
+ }
+
+ QStringList l;
+ Q3UriDrag::decodeToUnicodeUris(e, l);
+
+ bool move = e->action() == QDropEvent::Move;
+// bool supportAction = move || e->action() == QDropEvent::Copy;
+
+ Q3UrlOperator dest;
+ if (currDropItem)
+ dest = Q3UrlOperator(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text(0)));
+ else
+ dest = filedialog->d->url;
+ filedialog->d->url.copy(l, dest, move);
+
+ // ##### what is supportAction for?
+ e->acceptAction();
+ currDropItem = 0;
+}
+
+bool Q3FileDialogQFileListView::acceptDrop(const QPoint &pnt, QWidget *source)
+{
+ Q3ListViewItem *item = itemAt(pnt);
+ if (!item || (item && !itemRect(item).contains(pnt))) {
+ if (source == viewport() && startDragDir == filedialog->dirPath())
+ return false;
+ return true;
+ }
+
+ QUrlInfo fi(filedialog->d->url.info(item->text(0).isEmpty() ? QString::fromLatin1(".") : item->text(0)));
+
+ if (fi.isDir() && itemRect(item).contains(pnt))
+ return true;
+ return false;
+}
+
+void Q3FileDialogQFileListView::setCurrentDropItem(const QPoint &pnt)
+{
+ changeDirTimer->stop();
+
+ Q3ListViewItem *item = itemAt(pnt);
+ if (pnt == QPoint(-1, -1))
+ item = 0;
+ if (item && !QUrlInfo(filedialog->d->url.info(item->text(0).isEmpty() ? QString::fromLatin1(".") : item->text(0))).isDir())
+ item = 0;
+
+ if (item && !itemRect(item).contains(pnt))
+ item = 0;
+
+ currDropItem = item;
+
+ if (currDropItem)
+ setCurrentItem(currDropItem);
+
+ changeDirTimer->start(750);
+}
+#endif // QT_NO_DRAGANDDROP
+
+void Q3FileDialogQFileListView::changeDirDuringDrag()
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (!currDropItem)
+ return;
+ changeDirTimer->stop();
+ Q3Url u(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text(0)));
+ filedialog->setDir(u);
+ currDropItem = 0;
+#endif // QT_NO_DRAGANDDROP
+}
+
+
+void Q3FileDialogQFileListView::doubleClickTimeout()
+{
+ startRename();
+ renameTimer->stop();
+}
+
+void Q3FileDialogQFileListView::startRename(bool check)
+{
+ if (check && (!renameItem || renameItem != currentItem()))
+ return;
+
+ Q3ListViewItem *i = currentItem();
+ setSelected(i, true);
+
+ QRect r = itemRect(i);
+ int bdr = i->pixmap(0) ?
+ i->pixmap(0)->width() : 16;
+ int x = r.x() + bdr;
+ int y = r.y();
+ int w = columnWidth(0) - bdr;
+ int h = qMax(lined->height() + 2, r.height());
+ y = y + r.height() / 2 - h / 2;
+
+ lined->parentWidget()->setGeometry(x, y, w + 6, h);
+ lined->setFocus();
+ lined->setText(i->text(0));
+ lined->selectAll();
+ lined->setFrame(false);
+ lined->parentWidget()->show();
+ viewport()->setFocusProxy(lined);
+ renaming = true;
+}
+
+void Q3FileDialogQFileListView::clear()
+{
+ cancelRename();
+ Q3ListView::clear();
+}
+
+void Q3FileDialogQFileListView::rename()
+{
+ if (!lined->text().isEmpty()) {
+ QString file = currentItem()->text(0);
+
+ if (lined->text() != file)
+ filedialog->d->url.rename(file, lined->text());
+ }
+ cancelRename();
+}
+
+void Q3FileDialogQFileListView::cancelRename()
+{
+ renameItem = 0;
+ lined->parentWidget()->hide();
+ viewport()->setFocusProxy(this);
+ renaming = false;
+ if (currentItem())
+ currentItem()->repaint();
+ if (lined->hasFocus())
+ viewport()->setFocus();
+}
+
+void Q3FileDialogQFileListView::contentsMoved(int, int)
+{
+ changeDirTimer->stop();
+#ifndef QT_NO_DRAGANDDROP
+ setCurrentDropItem(QPoint(-1, -1));
+#endif
+}
+
+
+Q3FileDialogPrivate::File::~File()
+{
+ if (d->pendingItems.findRef(this))
+ d->pendingItems.removeRef(this);
+}
+
+QString Q3FileDialogPrivate::File::text(int column) const
+{
+ makeVariables();
+
+ switch(column) {
+ case 0:
+ return info.name();
+ case 1:
+ if (info.isFile()) {
+ QIODevice::Offset size = info.size();
+ return QString::number(size);
+ } else {
+ return QString::fromLatin1("");
+ }
+ case 2:
+ if (info.isFile() && info.isSymLink()) {
+ return d->symLinkToFile;
+ } else if (info.isFile()) {
+ return d->file;
+ } else if (info.isDir() && info.isSymLink()) {
+ return d->symLinkToDir;
+ } else if (info.isDir()) {
+ return d->dir;
+ } else if (info.isSymLink()) {
+ return d->symLinkToSpecial;
+ } else {
+ return d->special;
+ }
+ case 3: {
+ return info.lastModified().toString(Qt::LocalDate);
+ }
+ case 4:
+ if (info.isReadable())
+ return info.isWritable() ? d->rw : d->ro;
+ else
+ return info.isWritable() ? d->wo : d->inaccessible;
+ }
+
+ return QString::fromLatin1("<--->");
+}
+
+const QPixmap * Q3FileDialogPrivate::File::pixmap(int column) const
+{
+ if (column) {
+ return 0;
+ } else if (Q3ListViewItem::pixmap(column)) {
+ return Q3ListViewItem::pixmap(column);
+ } else if (info.isSymLink()) {
+ if (info.isFile())
+ return symLinkFileIcon;
+ else
+ return symLinkDirIcon;
+ } else if (info.isDir()) {
+ return closedFolderIcon;
+ } else if (info.isFile()) {
+ return fileIcon;
+ } else {
+ return fifteenTransparentPixels;
+ }
+}
+
+Q3FileDialogPrivate::MCItem::MCItem(Q3ListBox * lb, Q3ListViewItem * item)
+ : Q3ListBoxItem()
+{
+ i = item;
+ if (lb)
+ lb->insertItem(this);
+}
+
+Q3FileDialogPrivate::MCItem::MCItem(Q3ListBox * lb, Q3ListViewItem * item, Q3ListBoxItem *after)
+ : Q3ListBoxItem()
+{
+ i = item;
+ if (lb)
+ lb->insertItem(this, after);
+}
+
+QString Q3FileDialogPrivate::MCItem::text() const
+{
+ return i->text(0);
+}
+
+
+const QPixmap *Q3FileDialogPrivate::MCItem::pixmap() const
+{
+ return i->pixmap(0);
+}
+
+
+int Q3FileDialogPrivate::MCItem::height(const Q3ListBox * lb) const
+{
+ int hf = lb->fontMetrics().height();
+ int hp = pixmap() ? pixmap()->height() : 0;
+ return qMax(hf, hp) + 2;
+}
+
+
+int Q3FileDialogPrivate::MCItem::width(const Q3ListBox * lb) const
+{
+ QFontMetrics fm = lb->fontMetrics();
+ int w = 2;
+ if (pixmap())
+ w += pixmap()->width() + 4;
+ else
+ w += 18;
+ w += fm.width(text());
+ w += -fm.minLeftBearing();
+ w += -fm.minRightBearing();
+ w += 6;
+ return w;
+}
+
+
+void Q3FileDialogPrivate::MCItem::paint(QPainter * ptr)
+{
+ QFontMetrics fm = ptr->fontMetrics();
+
+ int h;
+
+ if (pixmap())
+ h = qMax(fm.height(), pixmap()->height()) + 2;
+ else
+ h = fm.height() + 2;
+
+ const QPixmap * pm = pixmap();
+ if (pm)
+ ptr->drawPixmap(2, 1, *pm);
+
+ ptr->drawText(pm ? pm->width() + 4 : 22, h - fm.descent() - 2,
+ text());
+}
+
+static QStringList makeFiltersList(const QString &filter)
+{
+ if (filter.isEmpty())
+ return QStringList();
+
+ int i = filter.indexOf(QLatin1String(";;"), 0);
+ QString sep(QLatin1String(";;"));
+ if (i == -1) {
+ if (filter.contains(QLatin1Char('\n'))) {
+ sep = QLatin1Char('\n');
+ i = filter.indexOf(sep);
+ }
+ }
+
+ return QStringList::split(sep, filter);
+}
+
+/*!
+ \class Q3FileDialog
+ \brief The Q3FileDialog class provides dialogs that allow users to select files or directories.
+
+ \compat
+
+ The Q3FileDialog class enables a user to traverse their file system in
+ order to select one or many files or a directory.
+
+ The easiest way to create a Q3FileDialog is to use the static
+ functions. On Windows, these static functions will call the native
+ Windows file dialog and on Mac OS X, these static function will call
+ the native Mac OS X file dialog.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 0
+
+ In the above example, a modal Q3FileDialog is created using a static
+ function. The startup directory is set to "/home". The file filter
+ is set to "Images (*.png *.xpm *.jpg)". The parent of the file dialog
+ is set to \e this and it is given the identification name - "open file
+ dialog". The caption at the top of file dialog is set to "Choose a
+ file". If you want to use multiple filters, separate each one with
+ \e two semicolons, e.g.
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 1
+
+ You can create your own Q3FileDialog without using the static
+ functions. By calling setMode(), you can set what can be returned by
+ the Q3FileDialog.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 2
+
+ In the above example, the mode of the file dialog is set to \l
+ AnyFile, meaning that the user can select any file, or even specify a
+ file that doesn't exist. This mode is useful for creating a "File Save
+ As" file dialog. Use \l ExistingFile if the user must select an
+ existing file or \l Directory if only a directory may be selected.
+ (See the \l Q3FileDialog::Mode enum for the complete list of modes.)
+
+ You can retrieve the dialog's mode with mode(). Use setFilter() to set
+ the dialog's file filter, e.g.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 3
+
+ In the above example, the filter is set to "Images (*.png *.xpm
+ *.jpg)", this means that only files with the extension \c png, \c xpm
+ or \c jpg will be shown in the Q3FileDialog. You can apply
+ several filters by using setFilters() and add additional filters with
+ addFilter(). Use setSelectedFilter() to select one of the filters
+ you've given as the file dialog's default filter. Whenever the user
+ changes the filter the filterSelected() signal is emitted.
+
+ The file dialog has two view modes, Q3FileDialog::List which simply
+ lists file and directory names and Q3FileDialog::Detail which
+ displays additional information alongside each name, e.g. file size,
+ modification date, etc. Set the mode with setViewMode().
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 4
+
+ The last important function you will need to use when creating your
+ own file dialog is selectedFile().
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 5
+
+ In the above example, a modal file dialog is created and shown. If
+ the user clicked OK, then the file they selected is put in \c
+ fileName.
+
+ If you are using the \l ExistingFiles mode then you will need to use
+ selectedFiles() which will return the selected files in a QStringList.
+
+ The dialog's working directory can be set with setDir(). The display
+ of hidden files is controlled with setShowHiddenFiles(). The dialog
+ can be forced to re-read the directory with rereadDir() and re-sort
+ the directory with resortDir(). All the files in the current directory
+ can be selected with selectAll().
+
+ \section1 Creating and using preview widgets
+
+ There are two kinds of preview widgets that can be used with
+ Q3FileDialogs: \e content preview widgets and \e information preview
+ widgets. They are created and used in the same way except that the
+ function names differ, e.g. setContentsPreview() and setInfoPreview().
+
+ A preview widget is a widget that is placed inside a Q3FileDialog so
+ that the user can see either the contents of the file, or information
+ about the file.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 6
+
+ In the above snippet, we create a preview widget which inherits from
+ QLabel and Q3FilePreview. File preview widgets \e must inherit from
+ Q3FilePreview.
+
+ Inside the class we reimplement Q3FilePreview::previewUrl(), this is
+ where we determine what happens when a file is selected. In the
+ above example we only show a preview of the file if it is a valid
+ pixmap. Here's how to make a file dialog use a preview widget:
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 7
+
+ The first line creates an instance of our preview widget. We then
+ create our file dialog and call setContentsPreviewEnabled(true),
+ this tell the file dialog to preview the contents of the currently
+ selected file. We then call setContentsPreview() -- note that we pass
+ the same preview widget twice. Finally, before showing the file
+ dialog, we call setPreviewMode() setting the mode to \e Contents which
+ will show the contents preview of the file that the user has selected.
+
+ If you create another preview widget that is used for displaying
+ information about a file, create it in the same way as the contents
+ preview widget and call setInfoPreviewEnabled(), and
+ setInfoPreview(). Then the user will be able to switch between the
+ two preview modes.
+
+ For more information about creating a Q3FilePreview widget see
+ \l{Q3FilePreview}.
+*/
+
+
+/*! \enum Q3FileDialog::Mode
+
+ This enum is used to indicate what the user may select in the file
+ dialog, i.e. what the dialog will return if the user clicks OK.
+
+ \value AnyFile The name of a file, whether it exists or not.
+ \value ExistingFile The name of a single existing file.
+ \value Directory The name of a directory. Both files and directories
+ are displayed.
+ \value DirectoryOnly The name of a directory. The file dialog will only display directories.
+ \value ExistingFiles The names of zero or more existing files.
+
+ See setMode().
+*/
+
+/*!
+ \enum Q3FileDialog::ViewMode
+
+ This enum describes the view mode of the file dialog, i.e. what
+ information about each file will be displayed.
+
+ \value List Display file and directory names with icons.
+ \value Detail Display file and directory names with icons plus
+ additional information, such as file size and modification date.
+
+ See setViewMode().
+*/
+
+/*!
+ \enum Q3FileDialog::PreviewMode
+
+ This enum describes the preview mode of the file dialog.
+
+ \value NoPreview No preview is shown at all.
+ \value Contents Show a preview of the contents of the current file
+ using the contents preview widget.
+ \value Info Show information about the current file using the
+ info preview widget.
+
+ See setPreviewMode(), setContentsPreview() and setInfoPreview().
+*/
+
+/*!
+ \fn void Q3FileDialog::detailViewSelectionChanged()
+ \internal
+*/
+
+/*!
+ \fn void Q3FileDialog::listBoxSelectionChanged()
+ \internal
+*/
+
+extern const char qt3_file_dialog_filter_reg_exp[] = "([a-zA-Z0-9]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$";
+
+/*!
+ Constructs a file dialog called \a name, with the parent, \a parent.
+ If \a modal is true then the file dialog is modal; otherwise it is
+ modeless.
+*/
+
+Q3FileDialog::Q3FileDialog(QWidget *parent, const char *name, bool modal)
+ : QDialog(parent, name, modal,
+ (modal ?
+ (Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu) : Qt::WindowFlags(0)))
+{
+ init();
+ d->mode = ExistingFile;
+ d->types->insertItem(tr("All Files (*)"));
+ d->cursorOverride = false;
+ emit dirEntered(d->url.dirPath());
+ rereadDir();
+}
+
+
+/*!
+ Constructs a file dialog called \a name with the parent, \a parent.
+ If \a modal is true then the file dialog is modal; otherwise it is
+ modeless.
+
+ If \a dirName is specified then it will be used as the dialog's
+ working directory, i.e. it will be the directory that is shown when
+ the dialog appears. If \a filter is specified it will be used as the
+ dialog's file filter.
+
+*/
+
+Q3FileDialog::Q3FileDialog(const QString& dirName, const QString & filter,
+ QWidget *parent, const char *name, bool modal)
+ : QDialog(parent, name, modal,
+ (modal ? (Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu)
+ : Qt::WindowFlags(0)))
+{
+ init();
+ d->mode = ExistingFile;
+ rereadDir();
+ Q3UrlOperator u(dirName);
+ if (!dirName.isEmpty() && (!u.isLocalFile() || QDir(dirName).exists()))
+ setSelection(dirName);
+ else if (workingDirectory && !workingDirectory->isEmpty())
+ setDir(*workingDirectory);
+
+ if (!filter.isEmpty()) {
+ setFilters(filter);
+ if (!dirName.isEmpty()) {
+ int dotpos = dirName.indexOf(QLatin1Char('.'), 0, Qt::CaseInsensitive);
+ if (dotpos != -1) {
+ for (int b=0 ; b<d->types->count() ; b++) {
+ if (d->types->text(b).contains(dirName.right(dirName.length() - dotpos))) {
+ d->types->setCurrentItem(b);
+ setFilter(d->types->text(b));
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ d->types->insertItem(tr("All Files (*)"));
+ }
+}
+
+
+/*!
+ \internal
+ Initializes the file dialog.
+*/
+
+void Q3FileDialog::init()
+{
+ setSizeGripEnabled(true);
+ d = new Q3FileDialogPrivate();
+ d->mode = AnyFile;
+ d->last = 0;
+ d->lastEFSelected = 0;
+ d->moreFiles = 0;
+ d->infoPreview = false;
+ d->contentsPreview = false;
+ d->hadDotDot = false;
+ d->ignoreNextKeyPress = false;
+ d->progressDia = 0;
+ d->checkForFilter = false;
+ d->ignoreNextRefresh = false;
+ d->ignoreStop = false;
+ d->mimeTypeTimer = new QTimer(this);
+ d->cursorOverride = false;
+ connect(d->mimeTypeTimer, SIGNAL(timeout()),
+ this, SLOT(doMimeTypeLookup()));
+
+ d->url = Q3UrlOperator(toRootIfNotExists( QDir::currentDirPath() ));
+ d->oldUrl = d->url;
+ d->currListChildren = 0;
+
+ connect(&d->url, SIGNAL(start(Q3NetworkOperation*)),
+ this, SLOT(urlStart(Q3NetworkOperation*)));
+ connect(&d->url, SIGNAL(finished(Q3NetworkOperation*)),
+ this, SLOT(urlFinished(Q3NetworkOperation*)));
+ connect(&d->url, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
+ this, SLOT(insertEntry(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)));
+ connect(&d->url, SIGNAL(removed(Q3NetworkOperation*)),
+ this, SLOT(removeEntry(Q3NetworkOperation*)));
+ connect(&d->url, SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)),
+ this, SLOT(createdDirectory(QUrlInfo,Q3NetworkOperation*)));
+ connect(&d->url, SIGNAL(itemChanged(Q3NetworkOperation*)),
+ this, SLOT(itemChanged(Q3NetworkOperation*)));
+ connect(&d->url, SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)),
+ this, SLOT(dataTransferProgress(int,int,Q3NetworkOperation*)));
+
+ nameEdit = new QLineEdit(this, "name/filter editor");
+ nameEdit->setMaxLength(255); //_POSIX_MAX_PATH
+ connect(nameEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(fileNameEditDone()));
+ nameEdit->installEventFilter(this);
+
+ d->splitter = new QSplitter(this, "qt_splitter");
+
+ d->stack = new Q3WidgetStack(d->splitter, "files and more files");
+
+ d->splitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ files = new Q3FileDialogQFileListView(d->stack, this);
+ QFontMetrics fm = fontMetrics();
+ files->addColumn(tr("Name"));
+ files->addColumn(tr("Size"));
+ files->setColumnAlignment(1, Qt::AlignRight);
+ files->addColumn(tr("Type"));
+ files->addColumn(tr("Date"));
+ files->addColumn(tr("Attributes"));
+ files->header()->setStretchEnabled(true, 0);
+
+ files->setMinimumSize(50, 25 + 2*fm.lineSpacing());
+
+ connect(files, SIGNAL(selectionChanged()),
+ this, SLOT(detailViewSelectionChanged()));
+ connect(files, SIGNAL(currentChanged(Q3ListViewItem*)),
+ this, SLOT(updateFileNameEdit(Q3ListViewItem*)));
+ connect(files, SIGNAL(doubleClicked(Q3ListViewItem*)),
+ this, SLOT(selectDirectoryOrFile(Q3ListViewItem*)));
+ connect(files, SIGNAL(returnPressed(Q3ListViewItem*)),
+ this, SLOT(selectDirectoryOrFile(Q3ListViewItem*)));
+ connect(files, SIGNAL(contextMenuRequested(Q3ListViewItem*,QPoint,int)),
+ this, SLOT(popupContextMenu(Q3ListViewItem*,QPoint,int)));
+
+ files->installEventFilter(this);
+ files->viewport()->installEventFilter(this);
+
+ d->moreFiles = new QFileListBox(d->stack, this);
+ d->moreFiles->setRowMode(Q3ListBox::FitToHeight);
+ d->moreFiles->setVariableWidth(true);
+
+ connect(d->moreFiles, SIGNAL(selected(Q3ListBoxItem*)),
+ this, SLOT(selectDirectoryOrFile(Q3ListBoxItem*)));
+ connect(d->moreFiles, SIGNAL(selectionChanged()),
+ this, SLOT(listBoxSelectionChanged()));
+ connect(d->moreFiles, SIGNAL(highlighted(Q3ListBoxItem*)),
+ this, SLOT(updateFileNameEdit(Q3ListBoxItem*)));
+ connect(d->moreFiles, SIGNAL(contextMenuRequested(Q3ListBoxItem*,QPoint)),
+ this, SLOT(popupContextMenu(Q3ListBoxItem*,QPoint)));
+
+ d->moreFiles->installEventFilter(this);
+ d->moreFiles->viewport()->installEventFilter(this);
+
+ okB = new QPushButton(tr("&OK"), this, "OK"); //### Or "Save (see other "OK")
+ okB->setDefault(true);
+ okB->setEnabled(false);
+ connect(okB, SIGNAL(clicked()), this, SLOT(okClicked()));
+ cancelB = new QPushButton(tr("Cancel") , this, "Cancel");
+ connect(cancelB, SIGNAL(clicked()), this, SLOT(cancelClicked()));
+
+ d->paths = new Q3ComboBox(true, this, "directory history/editor");
+ d->paths->setDuplicatesEnabled(false);
+ d->paths->setInsertionPolicy(Q3ComboBox::NoInsertion);
+ makeVariables();
+
+ QFileInfoList rootDrives = QDir::drives();
+ for (int i = 0; i < rootDrives.size(); ++i) {
+ QFileInfo fi = rootDrives.at(i);
+ d->paths->insertItem(*openFolderIcon, fi.absFilePath());
+ }
+
+ if (QDir::homeDirPath().size()) {
+ if (!d->paths->listBox()->findItem(QDir::homeDirPath()))
+ d->paths->insertItem(*openFolderIcon, QDir::homeDirPath());
+ }
+
+ connect(d->paths, SIGNAL(activated(QString)),
+ this, SLOT(setDir(QString)));
+
+ d->paths->installEventFilter(this);
+ QObjectList ol = d->paths->queryList("QLineEdit");
+ if (ol.size())
+ ol.at(0)->installEventFilter(this);
+
+ d->geometryDirty = true;
+ d->types = new QComboBox(true, this, "file types");
+ d->types->setDuplicatesEnabled(false);
+ d->types->setEditable(false);
+ connect(d->types, SIGNAL(activated(QString)),
+ this, SLOT(setFilter(QString)));
+ connect(d->types, SIGNAL(activated(QString)),
+ this, SIGNAL(filterSelected(QString)));
+
+ d->pathL = new QLabel(d->paths, tr("Look &in:"), this, "qt_looin_lbl");
+ d->fileL = new QLabel(nameEdit, tr("File &name:"), this, "qt_filename_lbl");
+ d->typeL = new QLabel(d->types, tr("File &type:"), this, "qt_filetype_lbl");
+
+ d->goBack = new QToolButton(this, "go back");
+ d->goBack->setEnabled(false);
+ d->goBack->setFocusPolicy(Qt::TabFocus);
+ connect(d->goBack, SIGNAL(clicked()), this, SLOT(goBack()));
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->goBack, tr("Back"));
+#endif
+ d->goBack->setIconSet(*goBackIcon);
+
+ d->cdToParent = new QToolButton(this, "cd to parent");
+ d->cdToParent->setFocusPolicy(Qt::TabFocus);
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->cdToParent, tr("One directory up"));
+#endif
+ d->cdToParent->setIconSet(*cdToParentIcon);
+ connect(d->cdToParent, SIGNAL(clicked()),
+ this, SLOT(cdUpClicked()));
+
+ d->newFolder = new QToolButton(this, "new folder");
+ d->newFolder->setFocusPolicy(Qt::TabFocus);
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->newFolder, tr("Create New Folder"));
+#endif
+ d->newFolder->setIconSet(*newFolderIcon);
+ connect(d->newFolder, SIGNAL(clicked()),
+ this, SLOT(newFolderClicked()));
+
+ d->modeButtons = new Q3ButtonGroup(0, "invisible group");
+ connect(d->modeButtons, SIGNAL(destroyed()),
+ this, SLOT(modeButtonsDestroyed()));
+ d->modeButtons->setExclusive(true);
+ connect(d->modeButtons, SIGNAL(clicked(int)),
+ d->stack, SLOT(raiseWidget(int)));
+ connect(d->modeButtons, SIGNAL(clicked(int)),
+ this, SLOT(changeMode(int)));
+
+ d->mcView = new QToolButton(this, "mclistbox view");
+ d->mcView->setFocusPolicy(Qt::TabFocus);
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->mcView, tr("List View"));
+#endif
+ d->mcView->setIconSet(*multiColumnListViewIcon);
+ d->mcView->setToggleButton(true);
+ d->stack->addWidget(d->moreFiles, d->modeButtons->insert(d->mcView));
+ d->detailView = new QToolButton(this, "list view");
+ d->detailView->setFocusPolicy(Qt::TabFocus);
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->detailView, tr("Detail View"));
+#endif
+ d->detailView->setIconSet(*detailViewIcon);
+ d->detailView->setToggleButton(true);
+ d->stack->addWidget(files, d->modeButtons->insert(d->detailView));
+
+ d->previewInfo = new QToolButton(this, "preview info view");
+ d->previewInfo->setFocusPolicy(Qt::TabFocus);
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->previewInfo, tr("Preview File Info"));
+#endif
+ d->previewInfo->setIconSet(*previewInfoViewIcon);
+ d->previewInfo->setToggleButton(true);
+ d->modeButtons->insert(d->previewInfo);
+
+ d->previewContents = new QToolButton(this, "preview info view");
+#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
+ if ((qWinVersion() & Qt::WV_NT_based) > Qt::WV_NT)
+#else
+ if (!qstrcmp(style()->className(), "QWindowsStyle"))
+#endif
+ {
+ d->goBack->setAutoRaise(true);
+ d->cdToParent->setAutoRaise(true);
+ d->newFolder->setAutoRaise(true);
+ d->mcView->setAutoRaise(true);
+ d->detailView->setAutoRaise(true);
+ d->previewInfo->setAutoRaise(true);
+ d->previewContents->setAutoRaise(true);
+ }
+ d->previewContents->setFocusPolicy(Qt::TabFocus);
+#ifndef QT_NO_TOOLTIP
+ QToolTip::add(d->previewContents, tr("Preview File Contents"));
+#endif
+ d->previewContents->setIconSet(*previewContentsViewIcon);
+ d->previewContents->setToggleButton(true);
+ d->modeButtons->insert(d->previewContents);
+
+ connect(d->detailView, SIGNAL(clicked()),
+ d->moreFiles, SLOT(cancelRename()));
+ connect(d->detailView, SIGNAL(clicked()),
+ files, SLOT(cancelRename()));
+ connect(d->mcView, SIGNAL(clicked()),
+ d->moreFiles, SLOT(cancelRename()));
+ connect(d->mcView, SIGNAL(clicked()),
+ files, SLOT(cancelRename()));
+
+ d->stack->raiseWidget(d->moreFiles);
+ d->mcView->setOn(true);
+
+ QHBoxLayout *lay = new QHBoxLayout(this);
+ lay->setMargin(6);
+ d->leftLayout = new QHBoxLayout(lay, 5);
+ d->topLevelLayout = new QVBoxLayout((QWidget*)0, 5);
+ lay->addLayout(d->topLevelLayout, 1);
+
+ QHBoxLayout * h;
+
+ d->preview = new Q3WidgetStack(d->splitter, "qt_preview");
+
+ d->infoPreviewWidget = new QWidget(d->preview, "qt_preview_info");
+ d->contentsPreviewWidget = new QWidget(d->preview, "qt_preview_contents");
+ d->infoPreviewer = d->contentsPreviewer = 0;
+
+ h = new QHBoxLayout(0);
+ d->buttonLayout = h;
+ d->topLevelLayout->addLayout(h);
+ h->addWidget(d->pathL);
+ h->addSpacing(8);
+ h->addWidget(d->paths);
+ h->addSpacing(8);
+ if (d->goBack)
+ h->addWidget(d->goBack);
+ h->addWidget(d->cdToParent);
+ h->addSpacing(2);
+ h->addWidget(d->newFolder);
+ h->addSpacing(4);
+ h->addWidget(d->mcView);
+ h->addWidget(d->detailView);
+ h->addWidget(d->previewInfo);
+ h->addWidget(d->previewContents);
+
+ d->topLevelLayout->addWidget(d->splitter);
+
+ h = new QHBoxLayout();
+ d->topLevelLayout->addLayout(h);
+ h->addWidget(d->fileL);
+ h->addWidget(nameEdit);
+ h->addSpacing(15);
+ h->addWidget(okB);
+
+ h = new QHBoxLayout();
+ d->topLevelLayout->addLayout(h);
+ h->addWidget(d->typeL);
+ h->addWidget(d->types);
+ h->addSpacing(15);
+ h->addWidget(cancelB);
+
+ d->rightLayout = new QHBoxLayout(lay, 5);
+ d->topLevelLayout->setStretchFactor(d->mcView, 1);
+ d->topLevelLayout->setStretchFactor(files, 1);
+
+ updateGeometries();
+
+ if (d->goBack) {
+ setTabOrder(d->paths, d->goBack);
+ setTabOrder(d->goBack, d->cdToParent);
+ } else {
+ setTabOrder(d->paths, d->cdToParent);
+ }
+ setTabOrder(d->cdToParent, d->newFolder);
+ setTabOrder(d->newFolder, d->mcView);
+ setTabOrder(d->mcView, d->detailView);
+ setTabOrder(d->detailView, d->moreFiles);
+ setTabOrder(d->moreFiles, files);
+ setTabOrder(files, nameEdit);
+ setTabOrder(nameEdit, d->types);
+ setTabOrder(d->types, okB);
+ setTabOrder(okB, cancelB);
+
+ d->rw = tr("Read-write");
+ d->ro = tr("Read-only");
+ d->wo = tr("Write-only");
+ d->inaccessible = tr("Inaccessible");
+
+ d->symLinkToFile = tr("Symlink to File");
+ d->symLinkToDir = tr("Symlink to Directory");
+ d->symLinkToSpecial = tr("Symlink to Special");
+ d->file = tr("File");
+ d->dir = tr("Dir");
+ d->special = tr("Special");
+
+ if (lastWidth == 0) {
+ QRect screen = QApplication::desktop()->screenGeometry(pos());
+ if (screen.width() < 1024 || screen.height() < 768) {
+ resize(qMin(screen.width(), 420), qMin(screen.height(), 236));
+ } else {
+ QSize s = files->sizeHint();
+ s = QSize(s.width() + 300, s.height() + 82);
+
+ if (s.width() * 3 > screen.width() * 2)
+ s.setWidth(screen.width() * 2 / 3);
+
+ if (s.height() * 3 > screen.height() * 2)
+ s.setHeight(screen.height() * 2 / 3);
+ else if (s.height() * 3 < screen.height())
+ s.setHeight(screen.height() / 3);
+
+ resize(s);
+ }
+ updateLastSize(this);
+ } else {
+ resize(lastWidth, lastHeight);
+ }
+
+ if (detailViewMode) {
+ d->stack->raiseWidget(files);
+ d->mcView->setOn(false);
+ d->detailView->setOn(true);
+ }
+
+ d->preview->hide();
+ nameEdit->setFocus();
+
+ connect(nameEdit, SIGNAL(returnPressed()),
+ this, SLOT(fileNameEditReturnPressed()));
+}
+
+/*!
+ \internal
+*/
+
+void Q3FileDialog::fileNameEditReturnPressed()
+{
+ d->oldUrl = d->url;
+ if (!isDirectoryMode(d->mode)) {
+ okClicked();
+ } else {
+ d->currentFileName.clear();
+ if (nameEdit->text().isEmpty()) {
+ emit fileSelected(selectedFile());
+ accept();
+ } else {
+ QUrlInfo f;
+ Q3FileDialogPrivate::File * c
+ = (Q3FileDialogPrivate::File *)files->currentItem();
+ if (c && files->isSelected(c))
+ f = c->info;
+ else
+ f = QUrlInfo(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") : nameEdit->text()));
+ if (f.isDir()) {
+ setUrl(Q3UrlOperator(d->url,
+ Q3FileDialogPrivate::encodeFileName(nameEdit->text() + QLatin1Char('/'))));
+ d->checkForFilter = true;
+ trySetSelection(true, d->url, true);
+ d->checkForFilter = false;
+ }
+ }
+ nameEdit->setText(QString());
+ }
+}
+
+/*!
+ \internal
+ Update the info and content preview widgets to display \a u.
+*/
+
+void Q3FileDialog::updatePreviews(const Q3Url &u)
+{
+ if (d->infoPreviewer)
+ d->infoPreviewer->previewUrl(u);
+ if (d->contentsPreviewer)
+ d->contentsPreviewer->previewUrl(u);
+}
+
+/*!
+ \internal
+ Changes the preview mode to the mode specified at \a id.
+*/
+
+void Q3FileDialog::changeMode(int id)
+{
+ if (!d->infoPreview && !d->contentsPreview)
+ return;
+
+ QAbstractButton*btn = d->modeButtons->find(id);
+ if (!btn)
+ return;
+
+ if (btn == d->previewContents && !d->contentsPreview)
+ return;
+ if (btn == d->previewInfo && !d->infoPreview)
+ return;
+
+ if (btn != d->previewContents && btn != d->previewInfo) {
+ d->preview->hide();
+ } else {
+ if (files->currentItem())
+ updatePreviews(Q3Url(d->url, files->currentItem()->text(0)));
+ if (btn == d->previewInfo)
+ d->preview->raiseWidget(d->infoPreviewWidget);
+ else
+ d->preview->raiseWidget(d->contentsPreviewWidget);
+ d->preview->show();
+ }
+}
+
+/*!
+ Destroys the file dialog.
+*/
+
+Q3FileDialog::~Q3FileDialog()
+{
+ // since clear might call setContentsPos which would emit
+ // a signal and thus cause a recompute of sizes...
+ files->blockSignals(true);
+ d->moreFiles->blockSignals(true);
+ files->clear();
+ d->moreFiles->clear();
+ d->moreFiles->blockSignals(false);
+ files->blockSignals(false);
+
+#ifndef QT_NO_CURSOR
+ if (d->cursorOverride)
+ QApplication::restoreOverrideCursor();
+#endif
+
+ delete d;
+ d = 0;
+}
+
+
+/*!
+ \property Q3FileDialog::selectedFile
+
+ \brief the name of the selected file
+
+ If a file was selected selectedFile contains the file's name including
+ its absolute path; otherwise selectedFile is empty.
+
+ \sa QString::isEmpty(), selectedFiles, selectedFilter
+*/
+
+QString Q3FileDialog::selectedFile() const
+{
+ QString s = d->currentFileName;
+ // remove the protocol because we do not want to encode it...
+ QString prot = Q3Url(s).protocol();
+ if (!prot.isEmpty()) {
+ prot += QLatin1Char(':');
+ s.remove(0, prot.length());
+ }
+ Q3Url u(prot + Q3FileDialogPrivate::encodeFileName(s));
+ if (u.isLocalFile()) {
+ QString s = u.toString();
+ if (s.left(5) == QLatin1String("file:"))
+ s.remove((uint)0, 5);
+ return s;
+ }
+ return d->currentFileName;
+}
+
+/*!
+ \property Q3FileDialog::selectedFilter
+
+ \brief the filter which the user has selected in the file dialog
+
+ \sa filterSelected(), selectedFiles, selectedFile
+*/
+
+QString Q3FileDialog::selectedFilter() const
+{
+ return d->types->currentText();
+}
+
+/*! \overload
+
+ Sets the current filter selected in the file dialog to the
+ \a{n}-th filter in the filter list.
+
+ \sa filterSelected(), selectedFilter(), selectedFiles(), selectedFile()
+*/
+
+void Q3FileDialog::setSelectedFilter(int n)
+{
+ d->types->setCurrentItem(n);
+ QString f = d->types->currentText();
+ QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+ int index = r.indexIn(f);
+ if (index >= 0)
+ f = r.cap(2);
+ d->url.setNameFilter(f);
+ rereadDir();
+}
+
+/*!
+ Sets the current filter selected in the file dialog to the first
+ one that contains the text \a mask.
+*/
+
+void Q3FileDialog::setSelectedFilter(const QString& mask)
+{
+ int n;
+
+ for (n = 0; n < d->types->count(); n++) {
+ if (d->types->text(n).contains(mask, Qt::CaseInsensitive)) {
+ d->types->setCurrentItem(n);
+ QString f = mask;
+ QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+ int index = r.indexIn(f);
+ if (index >= 0)
+ f = r.cap(2);
+ d->url.setNameFilter(f);
+ rereadDir();
+ return;
+ }
+ }
+}
+
+/*!
+ \property Q3FileDialog::selectedFiles
+
+ \brief the list of selected files
+
+ If one or more files are selected, selectedFiles contains their
+ names including their absolute paths. If no files are selected or
+ the mode isn't ExistingFiles selectedFiles is an empty list.
+
+ It is more convenient to use selectedFile() if the mode is
+ \l ExistingFile, \c Directory or \c DirectoryOnly.
+
+ Note that if you want to iterate over the list, you should
+ iterate over a copy, e.g.
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 8
+
+ \sa selectedFile, selectedFilter, QList::isEmpty()
+*/
+
+QStringList Q3FileDialog::selectedFiles() const
+{
+ QStringList lst;
+
+ if (mode() == ExistingFiles) {
+ QStringList selectedLst;
+ QString selectedFiles = nameEdit->text();
+ if (selectedFiles.lastIndexOf(QLatin1Char('\"')) == -1) {
+ //probably because Enter was pressed on the nameEdit, so we have one file
+ //not in "" but raw
+ selectedLst.append(selectedFiles);
+ } else {
+ selectedFiles.truncate(selectedFiles.lastIndexOf(QLatin1Char('\"')));
+ selectedLst = selectedLst.split(QLatin1String("\" "), selectedFiles);
+ }
+ for (QStringList::Iterator it = selectedLst.begin(); it != selectedLst.end(); ++it) {
+ Q3Url u;
+ if ((*it)[0] == QLatin1Char('\"')) {
+ u = Q3Url(d->url, Q3FileDialogPrivate::encodeFileName((*it).mid(1)));
+ } else {
+ u = Q3Url(d->url, Q3FileDialogPrivate::encodeFileName((*it)));
+ }
+ if (u.isLocalFile()) {
+ QString s = u.toString();
+ if (s.left(5) == QLatin1String("file:"))
+ s.remove((uint)0, 5);
+ lst << s;
+ } else {
+ lst << u.toString();
+ }
+ }
+ }
+
+ return lst;
+}
+
+/*!
+ Sets the default selection to \a filename. If \a filename is
+ absolute, setDir() is also called to set the file dialog's working
+ directory to the filename's directory.
+
+ \omit
+ Only for external use. Not useful inside Q3FileDialog.
+ \endomit
+*/
+
+void Q3FileDialog::setSelection(const QString & filename)
+{
+ d->oldUrl = d->url;
+ QString nf = d->url.nameFilter();
+ if (Q3Url::isRelativeUrl(filename))
+ d->url = Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(filename));
+ else
+ d->url = Q3UrlOperator(filename);
+ d->url.setNameFilter(nf);
+ d->checkForFilter = true;
+ bool isDirOk;
+ bool isDir = d->url.isDir(&isDirOk);
+ if (!isDirOk)
+ isDir = d->url.path().right(1) == QString(QLatin1Char('/'));
+ if (!isDir) {
+ Q3UrlOperator u(d->url);
+ d->url.setPath(d->url.dirPath());
+ trySetSelection(false, u, true);
+ d->ignoreNextRefresh = true;
+ nameEdit->selectAll();
+ rereadDir();
+ emit dirEntered(d->url.dirPath());
+ } else {
+ if (!d->url.path().isEmpty() &&
+ d->url.path().right(1) != QString(QLatin1Char('/'))) {
+ QString p = d->url.path();
+ p += QLatin1Char('/');
+ d->url.setPath(p);
+ }
+ trySetSelection(true, d->url, false);
+ rereadDir();
+ emit dirEntered(d->url.dirPath());
+ nameEdit->setText(QString::fromLatin1(""));
+ }
+ d->checkForFilter = false;
+}
+
+/*!
+ \property Q3FileDialog::dirPath
+
+ \brief the file dialog's working directory
+
+ \sa dir(), setDir()
+*/
+
+QString Q3FileDialog::dirPath() const
+{
+ return d->url.dirPath();
+}
+
+
+/*!
+
+ Sets the filter used in the file dialog to \a newFilter.
+
+ If \a newFilter contains a pair of parentheses containing one or more
+ of "anything*something" separated by spaces or by
+ semicolons then only the text contained in the parentheses is used as
+ the filter. This means that these calls are all equivalent:
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 9
+
+ \sa setFilters()
+*/
+
+void Q3FileDialog::setFilter(const QString & newFilter)
+{
+ if (newFilter.isEmpty())
+ return;
+ QString f = newFilter;
+ QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+ int index = r.indexIn(f);
+ if (index >= 0)
+ f = r.cap(2);
+ d->url.setNameFilter(f);
+ if (d->types->count() == 1) {
+ d->types->clear();
+ d->types->insertItem(newFilter);
+ } else {
+ for (int i = 0; i < d->types->count(); ++i) {
+ if (d->types->text(i).left(newFilter.length()) == newFilter ||
+ d->types->text(i).left(f.length()) == f) {
+ d->types->setCurrentItem(i);
+ break;
+ }
+ }
+ }
+ rereadDir();
+}
+
+
+/*! \overload
+ Sets the file dialog's working directory to \a pathstr.
+
+ \sa dir()
+*/
+
+void Q3FileDialog::setDir(const QString & pathstr)
+{
+ QString dr = pathstr;
+ if (dr.isEmpty())
+ return;
+
+#if defined(Q_OS_UNIX)
+ if (dr.length() && dr[0] == QLatin1Char('~')) {
+ int i = 0;
+ while(i < (int)dr.length() && dr[i] != QLatin1Char('/'))
+ i++;
+ Q3CString user;
+ if (i == 1) {
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
+
+# ifndef _POSIX_LOGIN_NAME_MAX
+# define _POSIX_LOGIN_NAME_MAX 9
+# endif
+
+ char name[_POSIX_LOGIN_NAME_MAX];
+ if (::getlogin_r(name, _POSIX_LOGIN_NAME_MAX) == 0)
+ user = name;
+ else
+#else
+ user = ::getlogin();
+ if (user.isEmpty())
+#endif
+ user = qgetenv("LOGNAME");
+ } else
+ user = dr.mid(1, i-1).local8Bit();
+ dr = dr.mid(i, dr.length());
+ struct passwd *pw;
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_FREEBSD) && !defined(Q_OS_OPENBSD)
+ struct passwd mt_pw;
+ char buffer[2048];
+ if (::getpwnam_r(user, &mt_pw, buffer, 2048, &pw) == 0 && pw == &mt_pw)
+#else
+ pw = ::getpwnam(user);
+ if (pw)
+#endif
+ dr.prepend(QString::fromLocal8Bit(pw->pw_dir));
+ }
+#endif
+
+ setUrl(dr);
+}
+
+/*!
+ Returns the current directory shown in the file dialog.
+
+ The ownership of the QDir pointer is transferred to the caller, so
+ it must be deleted by the caller when no longer required.
+
+ \sa setDir()
+*/
+
+const QDir *Q3FileDialog::dir() const
+{
+ if (d->url.isLocalFile())
+ return new QDir(d->url.path());
+ else
+ return 0;
+}
+
+/*!
+ Sets the file dialog's working directory to \a dir.
+ \sa dir()
+*/
+
+void Q3FileDialog::setDir(const QDir &dir)
+{
+ d->oldUrl = d->url;
+ QString nf(d->url.nameFilter());
+ d->url = dir.canonicalPath();
+ d->url.setNameFilter(nf);
+ QUrlInfo i(d->url.info(nameEdit->text().isEmpty()? QString::fromLatin1(".") : nameEdit->text()));
+ d->checkForFilter = true;
+ trySetSelection(i.isDir(), Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(nameEdit->text())), false);
+ d->checkForFilter = false;
+ rereadDir();
+ emit dirEntered(d->url.path());
+}
+
+/*!
+ Sets the file dialog's working directory to the directory specified at \a url.
+
+ \sa url()
+*/
+
+void Q3FileDialog::setUrl(const Q3UrlOperator &url)
+{
+ d->oldUrl = d->url;
+ QString nf = d->url.nameFilter();
+
+ QString operatorPath = url.toString(false, false);
+ if (Q3Url::isRelativeUrl(operatorPath)) {
+ d->url = Q3Url(d->url, operatorPath);
+ } else {
+ d->url = url;
+ }
+ d->url.setNameFilter(nf);
+
+ d->checkForFilter = true;
+ if (!d->url.isDir()) {
+ Q3UrlOperator u = d->url;
+ d->url.setPath(d->url.dirPath());
+ trySetSelection(false, u, false);
+ rereadDir();
+ emit dirEntered(d->url.dirPath());
+ QString fn = u.fileName();
+ nameEdit->setText(fn);
+ } else {
+ trySetSelection(true, d->url, false);
+ rereadDir();
+ emit dirEntered(d->url.dirPath());
+ }
+ d->checkForFilter = false;
+}
+
+/*!
+ \property Q3FileDialog::showHiddenFiles
+
+ \brief whether hidden files are shown in the file dialog
+
+ The default is false, i.e. don't show hidden files.
+*/
+
+void Q3FileDialog::setShowHiddenFiles(bool s)
+{
+ if (s == bShowHiddenFiles)
+ return;
+
+ bShowHiddenFiles = s;
+ rereadDir();
+}
+
+bool Q3FileDialog::showHiddenFiles() const
+{
+ return bShowHiddenFiles;
+}
+
+/*!
+ Rereads the current directory shown in the file dialog.
+
+ The only time you will need to call this function is if the contents of
+ the directory change and you wish to refresh the file dialog to reflect
+ the change.
+
+ \sa resortDir()
+*/
+
+void Q3FileDialog::rereadDir()
+{
+#ifndef QT_NO_CURSOR
+ if (!d->cursorOverride) {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ d->cursorOverride = true;
+ }
+#endif
+ d->pendingItems.clear();
+ if (d->mimeTypeTimer->isActive())
+ d->mimeTypeTimer->stop();
+ d->currListChildren = d->url.listChildren();
+#ifndef QT_NO_CURSOR
+ if (d->cursorOverride) {
+ QApplication::restoreOverrideCursor();
+ d->cursorOverride = false;
+ }
+#endif
+}
+
+
+/*!
+ \fn void Q3FileDialog::fileHighlighted(const QString& file)
+
+ This signal is emitted when the user highlights the given \a file,
+ i.e. makes it the current file.
+
+ \sa fileSelected(), filesSelected()
+*/
+
+/*!
+ \fn void Q3FileDialog::fileSelected(const QString& file)
+
+ This signal is emitted when the user selects the given \a file.
+
+ \sa filesSelected(), fileHighlighted(), selectedFile()
+*/
+
+/*!
+ \fn void Q3FileDialog::filesSelected(const QStringList& files)
+
+ This signal is emitted when the user selects the given \a files in \e
+ ExistingFiles mode.
+
+ \sa fileSelected(), fileHighlighted(), selectedFiles()
+*/
+
+/*!
+ \fn void Q3FileDialog::dirEntered(const QString& directory)
+
+ This signal is emitted when the user enters the given \a directory.
+
+ \sa dir()
+*/
+
+/*!
+ \fn void Q3FileDialog::filterSelected(const QString& filter)
+
+ This signal is emitted when the user selects the given \a filter.
+
+ \sa selectedFilter()
+*/
+
+extern bool qt_resolve_symlinks; // defined in q3url.cpp
+extern Q_GUI_EXPORT bool qt_use_native_dialogs; //qtgui
+
+/*!
+ This is a convenience static function that returns an existing file
+ selected by the user. If the user pressed Cancel, it returns a null
+ string.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 10
+
+ The function creates a modal file dialog called \a name, with
+ parent, \a parent. If a parent is not 0, the dialog will be shown
+ centered over the parent.
+
+ The file dialog's working directory will be set to \a startWith. If \a
+ startWith includes a file name, the file will be selected. The filter
+ is set to \a filter so that only those files which match the filter
+ are shown. The filter selected is set to \a selectedFilter. The parameters
+ \a startWith, \a selectedFilter and \a filter may be an empty string.
+
+ The dialog's caption is set to \a caption. If \a caption is not
+ specified then a default caption will be used.
+
+ Under Windows and Mac OS X, this static function will use the native
+ file dialog and not a Q3FileDialog, unless the style of the application
+ is set to something other than the native style (Note that on Windows the
+ dialog will spin a blocking modal event loop that will not dispatch any
+ QTimers and if parent is not 0 then it will position the dialog just under
+ the parent's title bar).
+
+ Under Unix/X11, the normal behavior of the file dialog is to resolve
+ and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
+ the file dialog will change to /var/tmp after entering /usr/tmp.
+ If \a resolveSymlinks is false, the file dialog will treat
+ symlinks as regular directories.
+
+ \sa getOpenFileNames(), getSaveFileName(), getExistingDirectory()
+*/
+
+QString Q3FileDialog::getOpenFileName(const QString & startWith,
+ const QString& filter,
+ QWidget *parent, const char* name,
+ const QString& caption,
+ QString *selectedFilter,
+ bool resolveSymlinks)
+{
+ bool save_qt_resolve_symlinks = qt_resolve_symlinks;
+ qt_resolve_symlinks = resolveSymlinks;
+
+ QStringList filters;
+ if (!filter.isEmpty())
+ filters = makeFiltersList(filter);
+
+ makeVariables();
+ QString initialSelection;
+ //### Problem with the logic here: If a startWith is given and a file
+ // with that name exists in D->URL, the box will be opened at D->URL instead of
+ // the last directory used ('workingDirectory').
+ //
+ // hm... isn't that problem exactly the documented behaviour? the
+ // documented behaviour sounds meaningful.
+ if (!startWith.isEmpty()) {
+ Q3UrlOperator u(Q3FileDialogPrivate::encodeFileName(startWith));
+ if (u.isLocalFile() && QFileInfo(u.path()).isDir()) {
+ *workingDirectory = startWith;
+ } else {
+ if (u.isLocalFile()) {
+ QFileInfo fi(u.dirPath());
+ if (fi.exists()) {
+ *workingDirectory = u.dirPath();
+ initialSelection = u.fileName();
+ }
+ } else {
+ *workingDirectory = u.toString();
+ initialSelection.clear();
+ }
+ }
+ }
+
+ if (workingDirectory->isNull())
+ *workingDirectory = toRootIfNotExists( QDir::currentDirPath() );
+
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && qobject_cast<QWindowsStyle *>(qApp->style()))
+ return winGetOpenFileName(initialSelection, filter, workingDirectory,
+ parent, name, caption, selectedFilter);
+#elif defined(Q_WS_MAC)
+ if(qt_use_native_dialogs && qobject_cast<QMacStyle *>(qApp->style())) {
+ QStringList files = macGetOpenFileNames(filter, startWith.isEmpty() ? 0 : workingDirectory,
+ parent, name, caption, selectedFilter, false);
+ return files.isEmpty() ? QString() : files.first().normalized(QString::NormalizationForm_C);
+ }
+#endif
+
+ Q3FileDialog *dlg = new Q3FileDialog(*workingDirectory, QString(), parent, name ? name : "qt_filedlg_gofn", true);
+
+ if (!caption.isNull())
+ dlg->setWindowTitle(caption);
+ else
+ dlg->setWindowTitle(Q3FileDialog::tr("Open"));
+
+ dlg->setFilters(filters);
+ if (selectedFilter)
+ dlg->setFilter(*selectedFilter);
+ dlg->setMode(Q3FileDialog::ExistingFile);
+ QString result;
+ if (!initialSelection.isEmpty())
+ dlg->setSelection(initialSelection);
+ if (dlg->exec() == QDialog::Accepted) {
+ result = dlg->selectedFile();
+ *workingDirectory = dlg->d->url;
+ if (selectedFilter)
+ *selectedFilter = dlg->selectedFilter();
+ }
+ delete dlg;
+
+ qt_resolve_symlinks = save_qt_resolve_symlinks;
+
+ return result;
+}
+
+/*!
+ This is a convenience static function that will return a file name
+ selected by the user. The file does not have to exist.
+
+ It creates a modal file dialog called \a name, with parent, \a parent.
+ If a parent is not 0, the dialog will be shown centered over the
+ parent.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 11
+
+ The file dialog's working directory will be set to \a startWith. If \a
+ startWith includes a file name, the file will be selected. The filter
+ is set to \a filter so that only those files which match the filter
+ are shown. The filter selected is set to \a selectedFilter. The parameters
+ \a startWith, \a selectedFilter and \a filter may be an empty string.
+
+ The dialog's caption is set to \a caption. If \a caption is not
+ specified then a default caption will be used.
+
+ Under Windows and Mac OS X, this static function will use the native
+ file dialog and not a Q3FileDialog, unless the style of the application
+ is set to something other than the native style. (Note that on Windows the
+ dialog will spin a blocking modal event loop that will not dispatch any
+ QTimers and if parent is not 0 then it will position the dialog just under
+ the parent's title bar. And on the Mac the filter argument is ignored).
+
+ Under Unix/X11, the normal behavior of the file dialog is to resolve
+ and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
+ the file dialog will change to /var/tmp after entering /usr/tmp.
+ If \a resolveSymlinks is false, the file dialog will treat
+ symlinks as regular directories.
+
+ \sa getOpenFileName(), getOpenFileNames(), getExistingDirectory()
+*/
+
+QString Q3FileDialog::getSaveFileName(const QString & startWith,
+ const QString& filter,
+ QWidget *parent, const char* name,
+ const QString& caption,
+ QString *selectedFilter,
+ bool resolveSymlinks)
+{
+ bool save_qt_resolve_symlinks = qt_resolve_symlinks;
+ qt_resolve_symlinks = resolveSymlinks;
+
+ QStringList filters;
+ if (!filter.isEmpty())
+ filters = makeFiltersList(filter);
+
+ makeVariables();
+ QString initialSelection;
+ if (!startWith.isEmpty()) {
+ Q3UrlOperator u(Q3FileDialogPrivate::encodeFileName(startWith));
+ if (u.isLocalFile() && QFileInfo(u.path()).isDir()) {
+ *workingDirectory = startWith;
+ } else {
+ if (u.isLocalFile()) {
+ QFileInfo fi(u.dirPath());
+ if (fi.exists()) {
+ *workingDirectory = u.dirPath();
+ initialSelection = u.fileName();
+ }
+ } else {
+ *workingDirectory = u.toString();
+ initialSelection.clear();
+ }
+ }
+ }
+
+ if (workingDirectory->isNull())
+ *workingDirectory = toRootIfNotExists( QDir::currentDirPath() );
+
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && qobject_cast<QWindowsStyle *>(qApp->style()))
+ return winGetSaveFileName(initialSelection, filter, workingDirectory,
+ parent, name, caption, selectedFilter);
+#elif defined(Q_WS_MAC)
+ if(qt_use_native_dialogs && qobject_cast<QMacStyle *>(qApp->style()))
+ return macGetSaveFileName(initialSelection.isNull() ? startWith : initialSelection,
+ filter, startWith.isEmpty() ? 0 : workingDirectory, parent, name,
+ caption, selectedFilter).normalized(QString::NormalizationForm_C);
+#endif
+
+ Q3FileDialog *dlg = new Q3FileDialog(*workingDirectory, QString(), parent, name ? name : "qt_filedlg_gsfn", true);
+
+ if (!caption.isNull())
+ dlg->setWindowTitle(caption);
+ else
+ dlg->setWindowTitle(Q3FileDialog::tr("Save As"));
+
+ QString result;
+ dlg->setFilters(filters);
+ if (selectedFilter)
+ dlg->setFilter(*selectedFilter);
+ dlg->setMode(Q3FileDialog::AnyFile);
+ if (!initialSelection.isEmpty())
+ dlg->setSelection(initialSelection);
+ if (dlg->exec() == QDialog::Accepted) {
+ result = dlg->selectedFile();
+ *workingDirectory = dlg->d->url;
+ if (selectedFilter)
+ *selectedFilter = dlg->selectedFilter();
+ }
+ delete dlg;
+
+ qt_resolve_symlinks = save_qt_resolve_symlinks;
+
+ return result;
+}
+
+/*!
+ \internal
+ Activated when the "OK" button is clicked.
+*/
+
+void Q3FileDialog::okClicked()
+{
+ QString fn(nameEdit->text());
+
+#if defined(Q_WS_WIN)
+ QFileInfo fi(d->url.path() + fn);
+ if (fi.isSymLink()) {
+ nameEdit->setText(fi.symLinkTarget());
+ }
+#endif
+
+ if (fn.contains(QLatin1Char('*'))) {
+ addFilter(fn);
+ nameEdit->blockSignals(true);
+ nameEdit->setText(QString::fromLatin1(""));
+ nameEdit->blockSignals(false);
+ return;
+ }
+
+ *workingDirectory = d->url;
+ detailViewMode = files->isVisible();
+ updateLastSize(this);
+
+ if (isDirectoryMode(d->mode)) {
+ QUrlInfo f(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") : nameEdit->text()));
+ if (f.isDir()) {
+ d->currentFileName = d->url;
+ if (d->currentFileName.right(1) != QString(QLatin1Char('/')))
+ d->currentFileName += QLatin1Char('/');
+ if (f.name() != QString(QLatin1Char('.')))
+ d->currentFileName += f.name();
+ accept();
+ return;
+ }
+ // Since it's not a directory and we clicked ok, we
+ // don't really want to do anything else
+ return;
+ }
+
+ // if we're in multi-selection mode and something is selected,
+ // accept it and be done.
+ if (mode() == ExistingFiles) {
+ if (! nameEdit->text().isEmpty()) {
+ QStringList sf = selectedFiles();
+ bool isdir = false;
+ if (sf.count() == 1) {
+ Q3UrlOperator u(d->url, sf[0]);
+ bool ok;
+ isdir = u.isDir(&ok) && ok;
+ }
+ if (!isdir) {
+ emit filesSelected(sf);
+ accept();
+ return;
+ }
+ }
+ }
+
+ if (mode() == AnyFile) {
+ Q3UrlOperator u(d->url, Q3FileDialogPrivate::encodeFileName(nameEdit->text()));
+ if (!u.isDir()) {
+ d->currentFileName = u;
+ emit fileSelected(selectedFile());
+ accept();
+ return;
+ }
+ }
+
+ if (mode() == ExistingFile) {
+ if (!Q3FileDialogPrivate::fileExists(d->url, nameEdit->text()))
+ return;
+ }
+
+ // If selection is valid, return it, else try
+ // using selection as a directory to change to.
+ if (!d->currentFileName.isNull() && !d->currentFileName.contains(QLatin1Char('*'))) {
+ emit fileSelected(selectedFile());
+ accept();
+ } else {
+ QUrlInfo f;
+ Q3FileDialogPrivate::File * c
+ = (Q3FileDialogPrivate::File *)files->currentItem();
+ Q3FileDialogPrivate::MCItem * m
+ = (Q3FileDialogPrivate::MCItem *)d->moreFiles->item(d->moreFiles->currentItem());
+ if ((c && files->isVisible() && files->hasFocus())
+ || (m && d->moreFiles->isVisible())) {
+ if (c && files->isVisible())
+ f = c->info;
+ else
+ f = ((Q3FileDialogPrivate::File*)m->i)->info;
+ } else {
+ f = QUrlInfo(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") : nameEdit->text()));
+ }
+ if (f.isDir()) {
+#if defined(Q_WS_WIN)
+ if (f.isSymLink())
+ setUrl(Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(fn + QLatin1Char('/'))));
+ else
+#else
+ setUrl(Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(f.name() + QLatin1Char('/'))));
+#endif
+ d->checkForFilter = true;
+ trySetSelection(true, d->url, true);
+ d->checkForFilter = false;
+ } else {
+ if (!nameEdit->text().contains(QLatin1Char('/')) &&
+ !nameEdit->text().contains(QLatin1String("\\"))
+#if defined(Q_OS_WIN32)
+ && nameEdit->text()[1] != QLatin1Char(':')
+#endif
+ )
+ addFilter(nameEdit->text());
+ else if (nameEdit->text()[0] == QLatin1Char('/') ||
+ nameEdit->text()[0] == QLatin1Char('\\')
+#if defined(Q_OS_WIN32)
+ || nameEdit->text()[1] == QLatin1Char(':')
+#endif
+ )
+ setDir(nameEdit->text());
+ else if (nameEdit->text().left(3) == QLatin1String("../") || nameEdit->text().left(3) == QLatin1String("..\\"))
+ setDir(Q3Url(d->url.toString(), Q3FileDialogPrivate::encodeFileName(nameEdit->text())).toString());
+ }
+ nameEdit->setText(QLatin1String(""));
+ }
+}
+
+/*!
+ \internal
+ Activated when the "Filter" button is clicked.
+*/
+
+void Q3FileDialog::filterClicked()
+{
+ // unused
+}
+
+/*!
+ \internal
+ Activated when the "Cancel" button is clicked.
+*/
+
+void Q3FileDialog::cancelClicked()
+{
+ *workingDirectory = d->url;
+ detailViewMode = files->isVisible();
+ updateLastSize(this);
+ reject();
+}
+
+
+/*!\reimp
+*/
+
+void Q3FileDialog::resizeEvent(QResizeEvent * e)
+{
+ QDialog::resizeEvent(e);
+ updateGeometries();
+}
+
+/*
+ \internal
+ The only correct way to try to set currentFileName
+*/
+bool Q3FileDialog::trySetSelection(bool isDir, const Q3UrlOperator &u, bool updatelined)
+{
+ if (!isDir && !u.path().isEmpty() && u.path().right(1) == QString(QLatin1Char('/')))
+ isDir = true;
+ if (u.fileName().contains(QLatin1Char('*')) && d->checkForFilter) {
+ QString fn(u.fileName());
+ if (fn.contains(QLatin1Char('*'))) {
+ addFilter(fn);
+ d->currentFileName.clear();
+ d->url.setFileName(QString());
+ nameEdit->setText(QString::fromLatin1(""));
+ return false;
+ }
+ }
+
+ if (isDir && d->preview && d->preview->isVisible())
+ updatePreviews(u);
+
+ QString old = d->currentFileName;
+
+ if (isDirectoryMode(mode())) {
+ if (isDir)
+ d->currentFileName = u;
+ else
+ d->currentFileName.clear();
+ } else if (!isDir && mode() == ExistingFiles) {
+ d->currentFileName = u;
+ } else if (!isDir || (mode() == AnyFile && !isDir)) {
+ d->currentFileName = u;
+ } else {
+ d->currentFileName.clear();
+ }
+ if (updatelined && !d->currentFileName.isEmpty()) {
+ // If the selection is valid, or if its a directory, allow OK.
+ if (!d->currentFileName.isNull() || isDir) {
+ if (u.fileName() != QLatin1String("..")) {
+ QString fn = u.fileName();
+ nameEdit->setText(fn);
+ } else {
+ nameEdit->setText(QLatin1String(""));
+ }
+ } else
+ nameEdit->setText(QString::fromLatin1(""));
+ }
+
+ if (!d->currentFileName.isNull() || isDir) {
+ okB->setEnabled(true);
+ } else if (!isDirectoryMode(d->mode)) {
+ okB->setEnabled(false);
+ }
+
+ if (d->currentFileName.length() && old != d->currentFileName)
+ emit fileHighlighted(selectedFile());
+
+ return !d->currentFileName.isNull();
+}
+
+
+/*! Make sure the minimum and maximum sizes of everything are sane.
+*/
+
+void Q3FileDialog::updateGeometries()
+{
+ if (!d || !d->geometryDirty)
+ return;
+
+ d->geometryDirty = false;
+
+ QSize r, t;
+
+ // we really should use QSize::expandedTo()
+#define RM r.setWidth(qMax(r.width(),t.width())); \
+r.setHeight(qMax(r.height(),t.height()))
+
+ // labels first
+ r = d->pathL->sizeHint();
+ t = d->fileL->sizeHint();
+ RM;
+ t = d->typeL->sizeHint();
+ RM;
+ d->pathL->setFixedSize(d->pathL->sizeHint());
+ d->fileL->setFixedSize(r);
+ d->typeL->setFixedSize(r);
+
+ // single-line input areas
+ r = d->paths->sizeHint();
+ t = nameEdit->sizeHint();
+ RM;
+ t = d->types->sizeHint();
+ RM;
+ r.setWidth(t.width() * 2 / 3);
+ t.setWidth(QWIDGETSIZE_MAX);
+ t.setHeight(r.height());
+ d->paths->setMinimumSize(r);
+ d->paths->setMaximumSize(t);
+ nameEdit->setMinimumSize(r);
+ nameEdit->setMaximumSize(t);
+ d->types->setMinimumSize(r);
+ d->types->setMaximumSize(t);
+
+ // buttons on top row
+ r = QSize(0, d->paths->minimumSize().height());
+ t = QSize(21, 20);
+ RM;
+ if (r.height()+1 > r.width())
+ r.setWidth(r.height()+1);
+ if (d->goBack)
+ d->goBack->setFixedSize(r);
+ d->cdToParent->setFixedSize(r);
+ d->newFolder->setFixedSize(r);
+ d->mcView->setFixedSize(r);
+ d->detailView->setFixedSize(r);
+
+ QAbstractButton *b = 0;
+ if (!d->toolButtons.isEmpty()) {
+ for (b = d->toolButtons.first(); b; b = d->toolButtons.next())
+ b->setFixedSize(b->sizeHint().width(), r.height());
+ }
+
+ if (d->infoPreview) {
+ d->previewInfo->show();
+ d->previewInfo->setFixedSize(r);
+ } else {
+ d->previewInfo->hide();
+ d->previewInfo->setFixedSize(QSize(0, 0));
+ }
+
+ if (d->contentsPreview) {
+ d->previewContents->show();
+ d->previewContents->setFixedSize(r);
+ } else {
+ d->previewContents->hide();
+ d->previewContents->setFixedSize(QSize(0, 0));
+ }
+
+ // open/save, cancel
+ r = QSize(75, 20);
+ t = okB->sizeHint();
+ RM;
+ t = cancelB->sizeHint();
+ RM;
+
+ okB->setFixedSize(r);
+ cancelB->setFixedSize(r);
+
+ d->topLevelLayout->activate();
+
+#undef RM
+}
+
+
+/*! Updates the file name edit box to \a newItem in the file dialog
+ when the cursor moves in the listview.
+*/
+
+void Q3FileDialog::updateFileNameEdit(Q3ListViewItem * newItem)
+{
+ if (!newItem)
+ return;
+
+ if (mode() == ExistingFiles) {
+ detailViewSelectionChanged();
+ Q3Url u(d->url, Q3FileDialogPrivate::encodeFileName(((Q3FileDialogPrivate::File*)files->currentItem())->info.name()));
+ QFileInfo fi(u.toString(false, false));
+ if (!fi.isDir())
+ emit fileHighlighted(u.toString(false, false));
+ } else if (files->isSelected(newItem)) {
+ Q3FileDialogPrivate::File * i = (Q3FileDialogPrivate::File *)newItem;
+ if (i && i->i && !i->i->isSelected()) {
+ d->moreFiles->blockSignals(true);
+ d->moreFiles->setSelected(i->i, true);
+ d->moreFiles->blockSignals(false);
+ }
+ // Encode the filename in case it had any special characters in it
+ QString encFile = Q3FileDialogPrivate::encodeFileName(newItem->text(0));
+ trySetSelection(i->info.isDir(), Q3UrlOperator(d->url, encFile), true);
+ }
+}
+
+void Q3FileDialog::detailViewSelectionChanged()
+{
+ if (d->mode != ExistingFiles)
+ return;
+
+ nameEdit->clear();
+ QString str;
+ Q3ListViewItem * i = files->firstChild();
+ d->moreFiles->blockSignals(true);
+ while(i) {
+ if (d->moreFiles && isVisible()) {
+ Q3FileDialogPrivate::File *f = (Q3FileDialogPrivate::File *)i;
+ if (f->i && f->i->isSelected() != i->isSelected())
+ d->moreFiles->setSelected(f->i, i->isSelected());
+ }
+ if (i->isSelected() && !((Q3FileDialogPrivate::File *)i)->info.isDir())
+ str += QString(QLatin1String("\"%1\" ")).arg(i->text(0));
+ i = i->nextSibling();
+ }
+ d->moreFiles->blockSignals(false);
+ nameEdit->setText(str);
+ nameEdit->setCursorPosition(str.length());
+ okB->setEnabled(true);
+ if (d->preview && d->preview->isVisible() && files->currentItem()) {
+ Q3Url u = Q3Url(d->url, Q3FileDialogPrivate::encodeFileName(((Q3FileDialogPrivate::File*)files->currentItem())->info.name()));
+ updatePreviews(u);
+ }
+}
+
+void Q3FileDialog::listBoxSelectionChanged()
+{
+ if (d->mode != ExistingFiles)
+ return;
+
+ if (d->ignoreNextRefresh) {
+ d->ignoreNextRefresh = false;
+ return;
+ }
+
+ nameEdit->clear();
+ QString str;
+ Q3ListBoxItem * i = d->moreFiles->item(0);
+ Q3ListBoxItem * j = 0;
+ int index = 0;
+ files->blockSignals(true);
+ while(i) {
+ Q3FileDialogPrivate::MCItem *mcitem = (Q3FileDialogPrivate::MCItem *)i;
+ if (files && isVisible()) {
+ if (mcitem->i->isSelected() != mcitem->isSelected()) {
+ files->setSelected(mcitem->i, mcitem->isSelected());
+
+ // What happens here is that we want to emit signal highlighted for
+ // newly added items. But Q3ListBox apparently emits selectionChanged even
+ // when a user clicks on the same item twice. So, basically emulate the behaivor
+ // we have in the "Details" view which only emits highlighted the first time we
+ // click on the item. Perhaps at some point we should have a call to
+ // updateFileNameEdit(Q3ListViewItem) which also emits fileHighlighted() for
+ // ExistingFiles. For better or for worse, this clones the behaivor of the
+ // "Details" view quite well.
+ if (mcitem->isSelected() && i != d->lastEFSelected) {
+ Q3Url u(d->url, Q3FileDialogPrivate::encodeFileName(((Q3FileDialogPrivate::File*)(mcitem)->i)->info.name()));
+ d->lastEFSelected = i;
+ emit fileHighlighted(u.toString(false, false));
+ }
+ }
+ }
+ if (d->moreFiles->isSelected(i)
+ && !((Q3FileDialogPrivate::File*)(mcitem)->i)->info.isDir()) {
+ str += QString(QLatin1String("\"%1\" ")).arg(i->text());
+ if (j == 0)
+ j = i;
+ }
+ i = d->moreFiles->item(++index);
+ }
+
+ files->blockSignals(false);
+ nameEdit->setText(str);
+ nameEdit->setCursorPosition(str.length());
+ okB->setEnabled(true);
+ if (d->preview && d->preview->isVisible() && j) {
+ Q3Url u = Q3Url(d->url,
+ Q3FileDialogPrivate::encodeFileName(((Q3FileDialogPrivate::File*)((Q3FileDialogPrivate::MCItem*)j)->i)->info.name()));
+ updatePreviews(u);
+ }
+}
+
+/*! \overload */
+
+void Q3FileDialog::updateFileNameEdit(Q3ListBoxItem * newItem)
+{
+ if (!newItem)
+ return;
+ Q3FileDialogPrivate::MCItem * i = (Q3FileDialogPrivate::MCItem *)newItem;
+ if (i->i) {
+ i->i->listView()->setSelected(i->i, i->isSelected());
+ updateFileNameEdit(i->i);
+ }
+}
+
+
+/*! Updates the dialog when the file name edit changes. */
+
+void Q3FileDialog::fileNameEditDone()
+{
+ QUrlInfo f(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") : nameEdit->text()));
+ if (mode() != Q3FileDialog::ExistingFiles) {
+ Q3UrlOperator u(d->url, Q3FileDialogPrivate::encodeFileName(nameEdit->text()));
+ trySetSelection(f.isDir(), u, false);
+ if (d->preview && d->preview->isVisible())
+ updatePreviews(u);
+ }
+}
+
+
+
+/*! This private slot reacts to double-clicks in the list view. The item that
+was double-clicked is specified in \a newItem */
+
+void Q3FileDialog::selectDirectoryOrFile(Q3ListViewItem * newItem)
+{
+
+ *workingDirectory = d->url;
+ detailViewMode = files->isVisible();
+ updateLastSize(this);
+
+ if (!newItem)
+ return;
+
+ if (d->url.isLocalFile()) {
+ QFileInfo fi(d->url.path() + newItem->text(0));
+#if defined(Q_WS_WIN)
+ if (fi.isSymLink()) {
+ nameEdit->setText(fi.symLinkTarget());
+ okClicked();
+ return;
+ }
+#endif
+ }
+
+ Q3FileDialogPrivate::File * i = (Q3FileDialogPrivate::File *)newItem;
+
+ QString oldName = nameEdit->text();
+ if (i->info.isDir()) {
+ setUrl(Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(i->info.name()) + QLatin1Char('/')));
+ if (isDirectoryMode(mode())) {
+ QUrlInfo f (d->url.info(QString::fromLatin1(".")));
+ trySetSelection(f.isDir(), d->url, true);
+ }
+ } else if (newItem->isSelectable() &&
+ trySetSelection(i->info.isDir(), Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(i->info.name())), true)) {
+ if (!isDirectoryMode(mode())) {
+ if (mode() == ExistingFile) {
+ if (Q3FileDialogPrivate::fileExists(d->url, nameEdit->text())) {
+ emit fileSelected(selectedFile());
+ accept();
+ }
+ } else {
+ emit fileSelected(selectedFile());
+ accept();
+ }
+ }
+ } else if (isDirectoryMode(d->mode)) {
+ d->currentFileName = d->url;
+ accept();
+ }
+ if (!oldName.isEmpty() && !isDirectoryMode(mode()))
+ nameEdit->setText(oldName);
+}
+
+
+void Q3FileDialog::selectDirectoryOrFile(Q3ListBoxItem * newItem)
+{
+ if (!newItem)
+ return;
+
+ Q3FileDialogPrivate::MCItem * i = (Q3FileDialogPrivate::MCItem *)newItem;
+ if (i->i) {
+ i->i->listView()->setSelected(i->i, i->isSelected());
+ selectDirectoryOrFile(i->i);
+ }
+}
+
+
+void Q3FileDialog::popupContextMenu(Q3ListViewItem *item, const QPoint &p,
+ int)
+{
+ if (item) {
+ files->setCurrentItem(item);
+ files->setSelected(item, true);
+ }
+
+ PopupAction action;
+ popupContextMenu(item ? item->text(0) : QString(), true, action, p);
+
+ if (action == PA_Open)
+ selectDirectoryOrFile(item);
+ else if (action == PA_Rename)
+ files->startRename(false);
+ else if (action == PA_Delete)
+ deleteFile(item ? item->text(0) : QString());
+ else if (action == PA_Reload)
+ rereadDir();
+ else if (action == PA_Hidden) {
+ bShowHiddenFiles = !bShowHiddenFiles;
+ rereadDir();
+ } else if (action == PA_SortName) {
+ sortFilesBy = (int)QDir::Name;
+ sortAscending = true;
+ resortDir();
+ } else if (action == PA_SortSize) {
+ sortFilesBy = (int)QDir::Size;
+ sortAscending = true;
+ resortDir();
+ } else if (action == PA_SortDate) {
+ sortFilesBy = (int)QDir::Time;
+ sortAscending = true;
+ resortDir();
+ } else if (action == PA_SortUnsorted) {
+ sortFilesBy = (int)QDir::Unsorted;
+ sortAscending = true;
+ resortDir();
+ }
+
+}
+
+void Q3FileDialog::popupContextMenu(Q3ListBoxItem *item, const QPoint & p)
+{
+ PopupAction action;
+ popupContextMenu(item ? item->text() : QString(), false, action, p);
+
+ if (action == PA_Open)
+ selectDirectoryOrFile(item);
+ else if (action == PA_Rename)
+ d->moreFiles->startRename(false);
+ else if (action == PA_Delete)
+ deleteFile(item->text());
+ else if (action == PA_Reload)
+ rereadDir();
+ else if (action == PA_Hidden) {
+ bShowHiddenFiles = !bShowHiddenFiles;
+ rereadDir();
+ } else if (action == PA_SortName) {
+ sortFilesBy = (int)QDir::Name;
+ sortAscending = true;
+ resortDir();
+ } else if (action == PA_SortSize) {
+ sortFilesBy = (int)QDir::Size;
+ sortAscending = true;
+ resortDir();
+ } else if (action == PA_SortDate) {
+ sortFilesBy = (int)QDir::Time;
+ sortAscending = true;
+ resortDir();
+ } else if (action == PA_SortUnsorted) {
+ sortFilesBy = (int)QDir::Unsorted;
+ sortAscending = true;
+ resortDir();
+ }
+}
+
+void Q3FileDialog::popupContextMenu(const QString &filename, bool,
+ PopupAction &action, const QPoint &p)
+{
+ action = PA_Cancel;
+
+ bool glob = filename.isEmpty();
+
+ Q3PopupMenu m(0, "file dialog context menu");
+ m.setCheckable(true);
+
+ if (!glob) {
+ QString okt;
+ if (QUrlInfo(d->url.info(filename.isEmpty() ? QString::fromLatin1(".") : fileName)).isDir()) {
+ okt = tr("&Open");
+ } else {
+ if (mode() == AnyFile)
+ okt = tr("&Save");
+ else
+ okt = tr("&Open");
+ }
+ int ok = m.insertItem(okt);
+
+ m.insertSeparator();
+ int rename = m.insertItem(tr("&Rename"));
+ int del = m.insertItem(tr("&Delete"));
+
+ if (filename.isEmpty() || !QUrlInfo(d->url.info(filename)).isWritable() ||
+ filename == QLatin1String("..")) {
+ if (filename.isEmpty() || !QUrlInfo(d->url.info(filename)).isReadable())
+ m.setItemEnabled(ok, false);
+ m.setItemEnabled(rename, false);
+ m.setItemEnabled(del, false);
+ }
+
+ m.move(p);
+ int res = m.exec(QCursor::pos(), -1);
+
+ if (res == ok)
+ action = PA_Open;
+ else if (res == rename)
+ action = PA_Rename;
+ else if (res == del)
+ action = PA_Delete;
+ } else {
+ int reload = m.insertItem(tr("R&eload"));
+
+ Q3PopupMenu m2(0, "sort menu");
+
+ int sname = m2.insertItem(tr("Sort by &Name"));
+ //int stype = m2.insertItem(tr("Sort by &Type"));
+ int ssize = m2.insertItem(tr("Sort by &Size"));
+ int sdate = m2.insertItem(tr("Sort by &Date"));
+ m2.insertSeparator();
+ int sunsorted = m2.insertItem(tr("&Unsorted"));
+
+ //m2.setItemEnabled(stype, false);
+
+ if (sortFilesBy == (int)QDir::Name)
+ m2.setItemChecked(sname, true);
+ else if (sortFilesBy == (int)QDir::Size)
+ m2.setItemChecked(ssize, true);
+// else if (sortFilesBy == 0x16)
+// m2.setItemChecked(stype, true);
+ else if (sortFilesBy == (int)QDir::Time)
+ m2.setItemChecked(sdate, true);
+ else if (sortFilesBy == (int)QDir::Unsorted)
+ m2.setItemChecked(sunsorted, true);
+
+ m.insertItem(tr("Sort"), &m2);
+
+ m.insertSeparator();
+
+ int hidden = m.insertItem(tr("Show &hidden files"));
+ m.setItemChecked(hidden, bShowHiddenFiles);
+
+ m.move(p);
+ int res = m.exec(QCursor::pos(), -1);
+
+ if (res == reload)
+ action = PA_Reload;
+ else if (res == hidden)
+ action = PA_Hidden;
+ else if (res == sname)
+ action = PA_SortName;
+// else if (res == stype)
+// action = PA_SortType;
+ else if (res == sdate)
+ action = PA_SortDate;
+ else if (res == ssize)
+ action = PA_SortSize;
+ else if (res == sunsorted)
+ action = PA_SortUnsorted;
+ }
+
+}
+
+void Q3FileDialog::deleteFile(const QString &filename)
+{
+ if (filename.isEmpty())
+ return;
+
+ QString encoded = Q3FileDialogPrivate::encodeFileName(filename);
+ QUrlInfo fi(d->url.info(encoded.isEmpty() ? QString::fromLatin1(".") : encoded));
+ QString t = tr("the file");
+ if (fi.isDir())
+ t = tr("the directory");
+ if (fi.isSymLink())
+ t = tr("the symlink");
+
+ if (QMessageBox::warning(this,
+ tr("Delete %1").arg(t),
+ tr("<qt>Are you sure you wish to delete %1 \"%2\"?</qt>")
+ .arg(t).arg(filename),
+ tr("&Yes"), tr("&No"), QString(), 1) == 0)
+ d->url.remove(Q3FileDialogPrivate::encodeFileName(filename));
+
+}
+
+void Q3FileDialog::fileSelected(int )
+{
+ // unused
+}
+
+void Q3FileDialog::fileHighlighted(int)
+{
+ // unused
+}
+
+void Q3FileDialog::dirSelected(int)
+{
+ // unused
+}
+
+void Q3FileDialog::pathSelected(int)
+{
+ // unused
+}
+
+
+void Q3FileDialog::cdUpClicked()
+{
+ QString oldName = nameEdit->text();
+ setUrl(Q3UrlOperator(d->url, QLatin1String("..")));
+ if (!oldName.isEmpty())
+ nameEdit->setText(oldName);
+}
+
+void Q3FileDialog::newFolderClicked()
+{
+ QString foldername(tr("New Folder 1"));
+ int i = 0;
+ QStringList lst;
+ Q3ListViewItemIterator it(files);
+ for (; it.current(); ++it)
+ if (it.current()->text(0).contains(tr("New Folder")))
+ lst.append(it.current()->text(0));
+
+ if (!lst.count() == 0)
+ while (lst.contains(foldername))
+ foldername = tr("New Folder %1").arg(++i);
+
+ d->url.mkdir(foldername);
+}
+
+void Q3FileDialog::createdDirectory(const QUrlInfo &info, Q3NetworkOperation *)
+{
+ resortDir();
+ if (d->moreFiles->isVisible()) {
+ for (uint i = 0; i < d->moreFiles->count(); ++i) {
+ if (d->moreFiles->text(i) == info.name()) {
+ d->moreFiles->setCurrentItem(i);
+ d->moreFiles->startRename(false);
+ break;
+ }
+ }
+ } else {
+ Q3ListViewItem *item = files->firstChild();
+ while (item) {
+ if (item->text(0) == info.name()) {
+ files->setSelected(item, true);
+ files->setCurrentItem(item);
+ files->startRename(false);
+ break;
+ }
+ item = item->nextSibling();
+ }
+ }
+}
+
+
+/*!
+ This is a convenience static function that will return an existing directory
+ selected by the user.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 12
+
+ This function creates a modal file dialog called \a name, with
+ parent, \a parent. If parent is not 0, the dialog will be shown
+ centered over the parent.
+
+ The dialog's working directory is set to \a dir, and the caption is
+ set to \a caption. Either of these may be an empty string in which case
+ the current directory and a default caption will be used respectively.
+
+ If \a dirOnly is true, then only directories will be shown in
+ the file dialog; otherwise both directories and files will be shown.
+
+ Under Unix/X11, the normal behavior of the file dialog is to resolve
+ and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
+ the file dialog will change to /var/tmp after entering /usr/tmp.
+ If \a resolveSymlinks is false, the file dialog will treat
+ symlinks as regular directories.
+
+ Note that on Windows the dialog will spin a blocking modal event loop
+ that will not dispatch any QTimers and if parent is not 0 then it will
+ position the dialog just under the parent's title bar.
+
+ \sa getOpenFileName(), getOpenFileNames(), getSaveFileName()
+*/
+
+QString Q3FileDialog::getExistingDirectory(const QString & dir,
+ QWidget *parent,
+ const char* name,
+ const QString& caption,
+ bool dirOnly,
+ bool resolveSymlinks)
+{
+ bool save_qt_resolve_symlinks = qt_resolve_symlinks;
+ qt_resolve_symlinks = resolveSymlinks;
+
+ makeVariables();
+ QString wd;
+ if (workingDirectory)
+ wd = *workingDirectory;
+
+#if defined(Q_WS_WIN)
+ QString initialDir;
+ if (!dir.isEmpty()) {
+ Q3UrlOperator u(dir);
+ if (QFileInfo(u.path()).isDir())
+ initialDir = dir;
+ } else
+ initialDir.clear();
+ if (qt_use_native_dialogs && qobject_cast<QWindowsStyle *>(qApp->style()) && dirOnly)
+ return winGetExistingDirectory(initialDir, parent, name, caption);
+#endif
+#if defined(Q_WS_MAC)
+ if(qt_use_native_dialogs && qobject_cast<QMacStyle *>(qApp->style()))
+ return macGetOpenFileNames(QLatin1String(""), 0, parent, name, caption,
+ 0, false, true).first().normalized(QString::NormalizationForm_C);
+#endif
+
+ Q3FileDialog *dlg = new Q3FileDialog(parent, name ? name : "qt_filedlg_ged", true);
+
+ if (!caption.isNull())
+ dlg->setWindowTitle(caption);
+ else
+ dlg->setWindowTitle(Q3FileDialog::tr("Find Directory"));
+
+ dlg->setMode(dirOnly ? DirectoryOnly : Directory);
+
+ dlg->d->types->clear();
+ dlg->d->types->insertItem(Q3FileDialog::tr("Directories"));
+ dlg->d->types->setEnabled(false);
+
+ QString dir_(dir);
+ dir_ = dir_.simplified();
+ if (dir_.isEmpty() && !wd.isEmpty())
+ dir_ = wd;
+ Q3UrlOperator u(dir_);
+ if (u.isLocalFile()) {
+ if (!dir_.isEmpty()) {
+ QFileInfo f(u.path());
+ if (f.exists())
+ if (f.isDir()) {
+ dlg->setDir(dir_);
+ wd = dir_;
+ }
+ } else if (!wd.isEmpty()) {
+ Q3Url tempUrl(wd);
+ QFileInfo f(tempUrl.path());
+ if (f.isDir()) {
+ dlg->setDir(wd);
+ }
+ } else {
+ QString theDir = dir_;
+ if (theDir.isEmpty()) {
+ theDir = toRootIfNotExists( QDir::currentDirPath() );
+ } if (!theDir.isEmpty()) {
+ Q3Url tempUrl(theDir);
+ QFileInfo f(tempUrl.path());
+ if (f.isDir()) {
+ wd = theDir;
+ dlg->setDir(theDir);
+ }
+ }
+ }
+ } else {
+ dlg->setUrl(dir_);
+ }
+
+ QString result;
+ dlg->setSelection(dlg->d->url.toString());
+
+ if (dlg->exec() == QDialog::Accepted) {
+ result = dlg->selectedFile();
+ wd = result;
+ }
+ delete dlg;
+
+ if (!result.isEmpty() && result.right(1) != QString(QLatin1Char('/')))
+ result += QLatin1Char('/');
+
+ qt_resolve_symlinks = save_qt_resolve_symlinks;
+
+ return result;
+}
+
+
+/*!
+ \property Q3FileDialog::mode
+ \brief the file dialog's mode
+
+ The default mode is \l ExistingFile.
+*/
+
+void Q3FileDialog::setMode(Mode newMode)
+{
+ if (d->mode != newMode) {
+ d->mode = newMode;
+ QString sel = d->currentFileName;
+ int maxnamelen = 255; // _POSIX_MAX_PATH
+ if (isDirectoryMode(newMode)) {
+ files->setSelectionMode(Q3ListView::Single);
+ d->moreFiles->setSelectionMode(Q3ListBox::Single);
+ if (sel.isNull())
+ sel = QString::fromLatin1(".");
+ d->types->setEnabled(false);
+ } else if (newMode == ExistingFiles) {
+ maxnamelen = INT_MAX;
+ files->setSelectionMode(Q3ListView::Extended);
+ d->moreFiles->setSelectionMode(Q3ListBox::Extended);
+ d->types->setEnabled(true);
+ } else {
+ files->setSelectionMode(Q3ListView::Single);
+ d->moreFiles->setSelectionMode(Q3ListBox::Single);
+ d->types->setEnabled(true);
+ }
+ nameEdit->setMaxLength(maxnamelen);
+ rereadDir();
+ QUrlInfo f(d->url.info(QString(QLatin1Char('.'))));
+ trySetSelection(f.isDir(), d->url, false);
+ }
+
+ QString okt;
+ bool changeFilters = false;
+ if (mode() == AnyFile) {
+ okt = tr("&Save");
+ d->fileL->setText(tr("File &name:"));
+ if (d->types->count() == 1) {
+ d->types->setCurrentItem(0);
+ if (d->types->currentText() == QLatin1String("Directories")) {
+ changeFilters = true;
+ }
+ }
+ }
+ else if (mode() == Directory || mode() == DirectoryOnly) {
+ okt = tr("&OK");
+ d->fileL->setText(tr("Directory:"));
+ d->types->clear();
+ d->types->insertItem(tr("Directories"));
+ }
+ else {
+ okt = tr("&Open");
+ d->fileL->setText(tr("File &name:"));
+ if (d->types->count() == 1) {
+ d->types->setCurrentItem(0);
+ if (d->types->currentText() == QLatin1String("Directories")) {
+ changeFilters = true;
+ }
+ }
+ }
+
+ if (changeFilters) {
+ d->types->clear();
+ d->types->insertItem(tr("All Files (*)"));
+ }
+
+ okB->setText(okt);
+}
+
+Q3FileDialog::Mode Q3FileDialog::mode() const
+{
+ return d->mode;
+}
+
+/*! \reimp
+*/
+
+void Q3FileDialog::done(int i)
+{
+ if (i == QDialog::Accepted && (d->mode == ExistingFile || d->mode == ExistingFiles)) {
+ QStringList selection = selectedFiles();
+ for (int f = 0; f < selection.count(); f++) {
+ QString file = selection[f];
+ if (file.isNull())
+ continue;
+ if (d->url.isLocalFile() && !QFile::exists(file)) {
+ QMessageBox::information(this, tr("Error"),
+ tr("%1\nFile not found.\nCheck path and filename.").arg(file));
+ return;
+ }
+ }
+ }
+ QDialog::done(i);
+}
+
+/*!
+ \property Q3FileDialog::viewMode
+
+ \brief the file dialog's view mode
+
+ If you set the view mode to be \e Detail (the default), then you
+ will see the file's details, such as the size of the file and the
+ date the file was last modified in addition to the file's name.
+
+ If you set the view mode to be \e List, then you will just
+ see a list of the files and folders.
+
+ See \l Q3FileDialog::ViewMode
+*/
+
+
+Q3FileDialog::ViewMode Q3FileDialog::viewMode() const
+{
+ if (detailViewMode)
+ return Detail;
+ else
+ return List;
+}
+
+void Q3FileDialog::setViewMode(ViewMode m)
+{
+ if (m == Detail) {
+ detailViewMode = true;
+ d->stack->raiseWidget(files);
+ d->detailView->setOn(true);
+ d->mcView->setOn(false);
+ } else if (m == List) {
+ detailViewMode = false;
+ d->stack->raiseWidget(d->moreFiles);
+ d->detailView->setOn(false);
+ d->mcView->setOn(true);
+ }
+}
+
+
+/*!
+ \property Q3FileDialog::previewMode
+
+ \brief the preview mode for the file dialog
+
+ If you set the mode to be a mode other than \e NoPreview, you must
+ use setInfoPreview() or setContentsPreview() to set the dialog's
+ preview widget to your preview widget and enable the preview
+ widget(s) with setInfoPreviewEnabled() or
+ setContentsPreviewEnabled().
+
+ \sa infoPreview, contentsPreview, viewMode
+*/
+
+void Q3FileDialog::setPreviewMode(PreviewMode m)
+{
+ if (m == NoPreview) {
+ d->previewInfo->setOn(false);
+ d->previewContents->setOn(false);
+ } else if (m == Info && d->infoPreview) {
+ d->previewInfo->setOn(true);
+ d->previewContents->setOn(false);
+ changeMode(d->modeButtons->id(d->previewInfo));
+ } else if (m == Contents && d->contentsPreview) {
+ d->previewInfo->setOn(false);
+ d->previewContents->setOn(true);
+ changeMode(d->modeButtons->id(d->previewContents));
+ }
+}
+Q3FileDialog::PreviewMode Q3FileDialog::previewMode() const
+{
+ if (d->infoPreview && d->infoPreviewWidget->isVisible())
+ return Info;
+ else if (d->contentsPreview && d->contentsPreviewWidget->isVisible())
+ return Contents;
+
+ return NoPreview;
+}
+
+
+/*!
+ Adds the specified widgets to the bottom of the file dialog. The
+ label \a l is placed underneath the "file name" and the "file types"
+ labels. The widget \a w is placed underneath the file types combobox.
+ The button \a b is placed underneath the Cancel push button.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 13
+
+ If you don't want to have one of the widgets added, pass 0 in that
+ widget's position.
+
+ Every time you call this function, a new row of widgets will be added
+ to the bottom of the file dialog.
+
+ \sa addToolButton(), addLeftWidget(), addRightWidget()
+*/
+
+void Q3FileDialog::addWidgets(QLabel * l, QWidget * w, QPushButton * b)
+{
+ if (!l && !w && !b)
+ return;
+
+ d->geometryDirty = true;
+
+ QHBoxLayout *lay = new QHBoxLayout();
+ d->extraWidgetsLayouts.append(lay);
+ d->topLevelLayout->addLayout(lay);
+
+ if (!l)
+ l = new QLabel(this, "qt_intern_lbl");
+ d->extraLabels.append(l);
+ lay->addWidget(l);
+
+ if (!w)
+ w = new QWidget(this, "qt_intern_widget");
+ d->extraWidgets.append(w);
+ lay->addWidget(w);
+ lay->addSpacing(15);
+
+ if (b) {
+ d->extraButtons.append(b);
+ lay->addWidget(b);
+ } else {
+ QWidget *wid = new QWidget(this, "qt_extrabuttons_widget");
+ d->extraButtons.append(wid);
+ lay->addWidget(wid);
+ }
+
+ updateGeometries();
+}
+
+/*!
+ Adds the tool button \a b to the row of tool buttons at the top of the
+ file dialog. The button is appended to the right of
+ this row. If \a separator is true, a small space is inserted between the
+ last button of the row and the new button \a b.
+
+ \sa addWidgets(), addLeftWidget(), addRightWidget()
+*/
+
+void Q3FileDialog::addToolButton(QAbstractButton *b, bool separator)
+{
+ if (!b || !d->buttonLayout)
+ return;
+
+ d->geometryDirty = true;
+
+ d->toolButtons.append(b);
+ if (separator)
+ d->buttonLayout->addSpacing(8);
+ d->buttonLayout->addWidget(b);
+
+ updateGeometries();
+}
+
+/*!
+ Adds the widget \a w to the left-hand side of the file dialog.
+
+ \sa addRightWidget(), addWidgets(), addToolButton()
+*/
+
+void Q3FileDialog::addLeftWidget(QWidget *w)
+{
+ if (!w)
+ return;
+ d->geometryDirty = true;
+
+ d->leftLayout->addWidget(w);
+ d->leftLayout->addSpacing(5);
+
+ updateGeometries();
+}
+
+/*!
+ Adds the widget \a w to the right-hand side of the file dialog.
+
+ \sa addLeftWidget(), addWidgets(), addToolButton()
+*/
+
+void Q3FileDialog::addRightWidget(QWidget *w)
+{
+ if (!w)
+ return;
+ d->geometryDirty = true;
+
+ d->rightLayout->addSpacing(5);
+ d->rightLayout->addWidget(w);
+
+ updateGeometries();
+}
+
+/*! \reimp */
+
+void Q3FileDialog::keyPressEvent(QKeyEvent * ke)
+{
+ if (!d->ignoreNextKeyPress &&
+ ke && (ke->key() == Qt::Key_Enter ||
+ ke->key() == Qt::Key_Return)) {
+ ke->ignore();
+ if (d->paths->hasFocus()) {
+ ke->accept();
+ if (d->url == Q3Url(d->paths->currentText()))
+ nameEdit->setFocus();
+ } else if (d->types->hasFocus()) {
+ ke->accept();
+ // ### is there a suitable condition for this? only valid
+ // wildcards?
+ nameEdit->setFocus();
+ } else if (nameEdit->hasFocus()) {
+ if (d->currentFileName.isNull()) {
+ // maybe change directory
+ QUrlInfo i(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") :nameEdit->text()));
+ if (i.isDir()) {
+ nameEdit->setText(QString::fromLatin1(""));
+ setDir(Q3UrlOperator(d->url, Q3FileDialogPrivate::encodeFileName(i.name())));
+ }
+ ke->accept();
+ } else if (mode() == ExistingFiles) {
+ QUrlInfo i(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") : nameEdit->text()));
+ if (i.isFile()) {
+ Q3ListViewItem * i = files->firstChild();
+ while (i && nameEdit->text() != i->text(0))
+ i = i->nextSibling();
+ if (i)
+ files->setSelected(i, true);
+ else
+ ke->accept(); // strangely, means to ignore that event
+ }
+ }
+ } else if (files->hasFocus() || d->moreFiles->hasFocus()) {
+ ke->accept();
+ }
+ } else if (ke->key() == Qt::Key_Escape) {
+ ke->ignore();
+ }
+
+ d->ignoreNextKeyPress = false;
+
+ if (!ke->isAccepted()) {
+ QDialog::keyPressEvent(ke);
+ }
+}
+
+
+/*! \class Q3FileIconProvider
+
+ \brief The Q3FileIconProvider class provides icons for Q3FileDialog to
+ use.
+
+ \compat
+
+ By default Q3FileIconProvider is not used, but any application or
+ library can subclass it, reimplement pixmap() to return a suitable
+ icon, and make all Q3FileDialog objects use it by calling the static
+ function Q3FileDialog::setIconProvider().
+
+ It is advisable to make all the icons that Q3FileIconProvider returns be
+ the same size or at least the same width. This makes the list view
+ look much better.
+
+ \sa Q3FileDialog
+*/
+
+
+/*! Constructs an empty file icon provider called \a name, with the
+ parent \a parent.
+*/
+
+Q3FileIconProvider::Q3FileIconProvider(QObject * parent, const char* name)
+ : QObject(parent, name)
+{
+ // nothing necessary
+}
+
+
+/*!
+ Returns a pointer to a pixmap that should be used to
+ signify the file with the information \a info.
+
+ If pixmap() returns 0, Q3FileDialog draws the default pixmap.
+
+ The default implementation returns particular icons for files, directories,
+ link-files and link-directories. It returns a blank "icon" for other types.
+
+ If you return a pixmap here, it should measure 16x16 pixels.
+*/
+
+const QPixmap * Q3FileIconProvider::pixmap(const QFileInfo & info)
+{
+ if (info.isSymLink()) {
+ if (info.isFile())
+ return symLinkFileIcon;
+ else
+ return symLinkDirIcon;
+ } else if (info.isDir()) {
+ return closedFolderIcon;
+ } else if (info.isFile()) {
+ return fileIcon;
+ } else {
+ return fifteenTransparentPixels;
+ }
+}
+
+/*!
+ Sets the Q3FileIconProvider used by the file dialog to \a provider.
+
+ The default is that there is no Q3FileIconProvider and Q3FileDialog
+ just draws a folder icon next to each directory and nothing next
+ to files.
+
+ \sa Q3FileIconProvider, iconProvider()
+*/
+
+void Q3FileDialog::setIconProvider(Q3FileIconProvider * provider)
+{
+ fileIconProvider = provider;
+}
+
+
+/*!
+ Returns a pointer to the icon provider currently set on the file dialog.
+ By default there is no icon provider, and this function returns 0.
+
+ \sa setIconProvider(), Q3FileIconProvider
+*/
+
+Q3FileIconProvider * Q3FileDialog::iconProvider()
+{
+ return fileIconProvider;
+}
+
+
+#if defined(Q_WS_WIN)
+
+// ### FIXME: this code is duplicated in qdns.cpp
+static QString getWindowsRegString(HKEY key, const QString &subKey)
+{
+ QString s;
+ QT_WA({
+ char buf[1024];
+ DWORD bsz = sizeof(buf);
+ int r = RegQueryValueEx(key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz);
+ if (r == ERROR_SUCCESS) {
+ s = QString::fromUcs2((unsigned short *)buf);
+ } else if (r == ERROR_MORE_DATA) {
+ char *ptr = new char[bsz+1];
+ r = RegQueryValueEx(key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz);
+ if (r == ERROR_SUCCESS)
+ s = QLatin1String(ptr);
+ delete [] ptr;
+ }
+ } , {
+ char buf[512];
+ DWORD bsz = sizeof(buf);
+ int r = RegQueryValueExA(key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz);
+ if (r == ERROR_SUCCESS) {
+ s = QLatin1String(buf);
+ } else if (r == ERROR_MORE_DATA) {
+ char *ptr = new char[bsz+1];
+ r = RegQueryValueExA(key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz);
+ if (r == ERROR_SUCCESS)
+ s = QLatin1String(ptr);
+ delete [] ptr;
+ }
+ });
+ return s;
+}
+
+QPixmap fromHICON(HICON hIcon)
+{
+ ICONINFO icoInfo;
+ if (GetIconInfo(hIcon, &icoInfo) && icoInfo.hbmColor) {
+ return QPixmap::fromWinHBITMAP(icoInfo.hbmColor);
+ }
+ return QPixmap();
+}
+
+QWindowsIconProvider::QWindowsIconProvider(QObject *parent, const char *name)
+ : Q3FileIconProvider(parent, name)
+{
+ pixw = GetSystemMetrics(SM_CXSMICON);
+ pixh = GetSystemMetrics(SM_CYSMICON);
+
+ HKEY k;
+ HICON si;
+ int r;
+ QString s;
+ UINT res = 0;
+
+ // ---------- get default folder pixmap
+ const wchar_t iconFolder[] = L"folder\\DefaultIcon"; // workaround for Borland
+ QT_WA({
+ r = RegOpenKeyEx(HKEY_CLASSES_ROOT,
+ iconFolder,
+ 0, KEY_READ, &k);
+ } , {
+ r = RegOpenKeyExA(HKEY_CLASSES_ROOT,
+ "folder\\DefaultIcon",
+ 0, KEY_READ, &k);
+ });
+ resolveLibs();
+ if (r == ERROR_SUCCESS) {
+ s = getWindowsRegString(k, QString());
+ RegCloseKey(k);
+
+ QStringList lst = QStringList::split(QLatin1String(","), s);
+
+ if (lst.count() >= 2) { // don't just assume that lst has two entries
+#ifndef Q_OS_WINCE
+ QT_WA({
+ res = ptrExtractIconEx((TCHAR*)lst[0].simplifyWhiteSpace().ucs2(),
+ lst[1].simplifyWhiteSpace().toInt(),
+ 0, &si, 1);
+ } , {
+ res = ExtractIconExA(lst[0].simplifyWhiteSpace().local8Bit(),
+ lst[1].simplifyWhiteSpace().toInt(),
+ 0, &si, 1);
+ });
+#else
+ res = (UINT)ExtractIconEx((TCHAR*)lst[0].simplifyWhiteSpace().ucs2(),
+ lst[1].simplifyWhiteSpace().toInt(),
+ 0, &si, 1);
+#endif
+ }
+
+ if (res) {
+ defaultFolder = fromHICON(si);
+ defaultFolder.setMask(defaultFolder.createHeuristicMask());
+ *closedFolderIcon = defaultFolder;
+ DestroyIcon(si);
+ } else {
+ defaultFolder = *closedFolderIcon;
+ }
+ } else {
+ RegCloseKey(k);
+ }
+
+ //------------------------------- get default file pixmap
+#ifndef Q_OS_WINCE
+ QT_WA({
+ res = ptrExtractIconEx(L"shell32.dll",
+ 0, 0, &si, 1);
+ } , {
+ res = ExtractIconExA("shell32.dll",
+ 0, 0, &si, 1);
+ });
+#else
+ res = (UINT)ExtractIconEx(L"shell32.dll",
+ 0, 0, &si, 1);
+#endif
+
+ if (res) {
+ defaultFile = fromHICON(si);
+ defaultFile.setMask(defaultFile.createHeuristicMask());
+ *fileIcon = defaultFile;
+ DestroyIcon(si);
+ } else {
+ defaultFile = *fileIcon;
+ }
+
+ //------------------------------- get default exe pixmap
+#ifndef Q_OS_WINCE
+ QT_WA({
+ res = ptrExtractIconEx(L"shell32.dll",
+ 2, 0, &si, 1);
+ } , {
+ res = ExtractIconExA("shell32.dll",
+ 2, 0, &si, 1);
+ });
+#else
+ res = (UINT)ExtractIconEx(L"ceshell.dll",
+ 10, 0, &si, 1);
+#endif
+
+ if (res) {
+ defaultExe = fromHICON(si);
+ defaultExe.setMask(defaultExe.createHeuristicMask());
+ DestroyIcon(si);
+ } else {
+ defaultExe = *fileIcon;
+ }
+}
+
+QWindowsIconProvider::~QWindowsIconProvider()
+{
+ if (this == fileIconProvider)
+ fileIconProvider = 0;
+}
+
+const QPixmap * QWindowsIconProvider::pixmap(const QFileInfo &fi)
+{
+ if (fi.isSymLink()) {
+ QString real = fi.symLinkTarget();
+ if (!real.isEmpty())
+ return pixmap(QFileInfo(real));
+ }
+
+ QString ext = fi.extension(false).upper();
+ QString key = ext;
+ ext.prepend(QLatin1String("."));
+ QMap< QString, QPixmap >::Iterator it;
+
+ if (fi.isDir()) {
+ return &defaultFolder;
+ } else if (ext.toLower() != QLatin1String(".exe")) {
+ it = cache.find(key);
+ if (it != cache.end())
+ return &(*it);
+
+ HKEY k, k2;
+ int r;
+ QT_WA({
+ r = RegOpenKeyEx(HKEY_CLASSES_ROOT, (TCHAR*)ext.ucs2(),
+ 0, KEY_READ, &k);
+ } , {
+ r = RegOpenKeyExA(HKEY_CLASSES_ROOT, ext.local8Bit(),
+ 0, KEY_READ, &k);
+ });
+ QString s;
+ if (r == ERROR_SUCCESS) {
+ s = getWindowsRegString(k, QString());
+ } else {
+ cache[key] = defaultFile;
+ RegCloseKey(k);
+ return &defaultFile;
+ }
+ RegCloseKey(k);
+
+ QT_WA({
+ r = RegOpenKeyEx(HKEY_CLASSES_ROOT, (TCHAR*)QString(s + QLatin1String("\\DefaultIcon")).ucs2(),
+ 0, KEY_READ, &k2);
+ } , {
+ r = RegOpenKeyExA(HKEY_CLASSES_ROOT, QString(s + QLatin1String("\\DefaultIcon")).local8Bit() ,
+ 0, KEY_READ, &k2);
+ });
+ if (r == ERROR_SUCCESS) {
+ s = getWindowsRegString(k2, QString());
+ } else {
+ cache[key] = defaultFile;
+ RegCloseKey(k2);
+ return &defaultFile;
+ }
+ RegCloseKey(k2);
+
+ if (s.isEmpty())
+ return &defaultFile;
+
+ QStringList lst = QStringList::split(QLatin1String(","), s);
+
+ HICON si;
+ UINT res = 0;
+ if (lst.count() >= 2) { // don't just assume that lst has two entries
+ QString filepath = lst[0].stripWhiteSpace();
+ if (!filepath.isEmpty()) {
+ if (filepath.find(QLatin1String("%1")) != -1) {
+ filepath = filepath.arg(fi.filePath());
+ if (ext.toLower() == QLatin1String(".dll")) {
+ pix = defaultFile;
+ return &pix;
+ }
+ }
+ if (filepath[0] == QLatin1Char('"') && filepath[(int)filepath.length()-1] == QLatin1Char('"'))
+ filepath = filepath.mid(1, filepath.length()-2);
+
+ resolveLibs();
+#ifndef Q_OS_WINCE
+ QT_WA({
+ res = ptrExtractIconEx((TCHAR*)filepath.ucs2(), lst[1].stripWhiteSpace().toInt(),
+ 0, &si, 1);
+ } , {
+ res = ExtractIconExA(filepath.local8Bit(), lst[1].stripWhiteSpace().toInt(),
+ 0, &si, 1);
+ });
+#else
+ res = (UINT)ExtractIconEx((TCHAR*)filepath.ucs2(), lst[1].stripWhiteSpace().toInt(),
+ 0, &si, 1);
+#endif
+ }
+ }
+ if (res) {
+ pix = fromHICON(si);
+ pix.setMask(pix.createHeuristicMask());
+ DestroyIcon(si);
+ } else {
+ pix = defaultFile;
+ }
+
+ cache[key] = pix;
+ return &pix;
+ } else {
+ HICON si;
+ UINT res = 0;
+ if (!fi.absFilePath().isEmpty()) {
+#ifndef Q_OS_WINCE
+ QT_WA({
+ res = ptrExtractIconEx((TCHAR*)fi.absFilePath().ucs2(), -1,
+ 0, 0, 1);
+ } , {
+ res = ExtractIconExA(fi.absFilePath().local8Bit(), -1,
+ 0, 0, 1);
+ });
+
+ if (res) {
+ QT_WA({
+ res = ptrExtractIconEx((TCHAR*)fi.absFilePath().ucs2(), res - 1,
+ 0, &si, 1);
+ } , {
+ res = ExtractIconExA(fi.absFilePath().local8Bit(), res - 1,
+ 0, &si, 1);
+ });
+ }
+#else
+ res = (UINT)ExtractIconEx((TCHAR*)fi.absFilePath().ucs2(), -1,
+ 0, 0, 1);
+ if (res)
+ res = (UINT)ExtractIconEx((TCHAR*)fi.absFilePath().ucs2(), res - 1,
+ 0, &si, 1);
+#endif
+
+ }
+
+ if (res) {
+ pix = fromHICON(si);
+ pix.setMask(pix.createHeuristicMask());
+ DestroyIcon(si);
+ } else {
+ pix = defaultExe;
+ }
+
+ return &pix;
+ }
+
+ // can't happen!
+ return 0;
+}
+#endif
+
+
+
+/*!
+ \reimp
+*/
+bool Q3FileDialog::eventFilter(QObject * o, QEvent * e)
+{
+ if (e->type() == QEvent::KeyPress && ((QKeyEvent*)e)->key() == Qt::Key_F5) {
+ rereadDir();
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress && ((QKeyEvent*)e)->key() == Qt::Key_F2 &&
+ (o == files || o == files->viewport())) {
+ if (files->isVisible() && files->currentItem()) {
+ if (QUrlInfo(d->url.info(QString(QLatin1Char('.')))).isWritable() && files->currentItem()->text(0) != QLatin1String("..")) {
+ files->renameItem = files->currentItem();
+ files->startRename(true);
+ }
+ }
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress && ((QKeyEvent*)e)->key() == Qt::Key_F2 &&
+ (o == d->moreFiles || o == d->moreFiles->viewport())) {
+ if (d->moreFiles->isVisible() && d->moreFiles->currentItem() != -1) {
+ if (QUrlInfo(d->url.info(QString(QLatin1Char('.')))).isWritable() &&
+ d->moreFiles->item(d->moreFiles->currentItem())->text() != QLatin1String("..")) {
+ d->moreFiles->renameItem = d->moreFiles->item(d->moreFiles->currentItem());
+ d->moreFiles->startRename(true);
+ }
+ }
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress && d->moreFiles->renaming) {
+ d->moreFiles->lined->setFocus();
+ QApplication::sendEvent(d->moreFiles->lined, e);
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress && files->renaming) {
+ files->lined->setFocus();
+ QApplication::sendEvent(files->lined, e);
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress &&
+ ((QKeyEvent *)e)->key() == Qt::Key_Backspace &&
+ (o == files ||
+ o == d->moreFiles ||
+ o == files->viewport() ||
+ o == d->moreFiles->viewport())) {
+ cdUpClicked();
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress &&
+ ((QKeyEvent *)e)->key() == Qt::Key_Delete &&
+ (o == files ||
+ o == files->viewport())) {
+ if (files->currentItem())
+ deleteFile(files->currentItem()->text(0));
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (e->type() == QEvent::KeyPress &&
+ ((QKeyEvent *)e)->key() == Qt::Key_Delete &&
+ (o == d->moreFiles ||
+ o == d->moreFiles->viewport())) {
+ int c = d->moreFiles->currentItem();
+ if (c >= 0)
+ deleteFile(d->moreFiles->item(c)->text());
+ ((QKeyEvent *)e)->accept();
+ return true;
+ } else if (o == files && e->type() == QEvent::FocusOut && files->currentItem()) {
+ } else if (o == files && e->type() == QEvent::KeyPress) {
+ QTimer::singleShot(0, this, SLOT(fixupNameEdit()));
+ } else if (o == nameEdit && e->type() == QEvent::KeyPress && d->mode != AnyFile) {
+ if ((nameEdit->cursorPosition() == (int)nameEdit->text().length() || nameEdit->hasSelectedText()) &&
+ isprint(((QKeyEvent *)e)->ascii())) {
+#if defined(Q_WS_WIN)
+ QString nt(nameEdit->text().toLower());
+#else
+ QString nt(nameEdit->text());
+#endif
+ nt.truncate(nameEdit->cursorPosition());
+ nt += QLatin1Char((char)(((QKeyEvent *)e)->ascii()));
+ Q3ListViewItem * i = files->firstChild();
+#if defined(Q_WS_WIN)
+ while(i && i->text(0).left(nt.length()).toLower() != nt)
+#else
+ while(i && i->text(0).left(nt.length()) != nt)
+#endif
+ i = i->nextSibling();
+ if (i) {
+ nt = i->text(0);
+ int cp = nameEdit->cursorPosition()+1;
+ nameEdit->validateAndSet(nt, cp, cp, nt.length());
+ return true;
+ }
+ }
+ } else if (o == nameEdit && e->type() == QEvent::FocusIn) {
+ fileNameEditDone();
+ } else if (d->moreFiles->renaming && o != d->moreFiles->lined && e->type() == QEvent::FocusIn) {
+ d->moreFiles->lined->setFocus();
+ return true;
+ } else if (files->renaming && o != files->lined && e->type() == QEvent::FocusIn) {
+ files->lined->setFocus();
+ return true;
+ } else if ((o == d->moreFiles || o == d->moreFiles->viewport()) &&
+ e->type() == QEvent::FocusIn) {
+ if ((o == d->moreFiles->viewport() && !d->moreFiles->viewport()->hasFocus())
+ || (o == d->moreFiles && !d->moreFiles->hasFocus()))
+ ((QWidget*)o)->setFocus();
+ return false;
+ }
+
+ return QDialog::eventFilter(o, e);
+}
+
+/*!
+ Sets the filters used in the file dialog to \a filters. Each group
+ of filters must be separated by \c{;;} (\e two semicolons).
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 14
+
+*/
+
+void Q3FileDialog::setFilters(const QString &filters)
+{
+ QStringList lst = makeFiltersList(filters);
+ setFilters(lst);
+}
+
+/*!
+ \overload
+
+ \a types must be a null-terminated list of strings.
+
+*/
+
+void Q3FileDialog::setFilters(const char ** types)
+{
+ if (!types || !*types)
+ return;
+
+ d->types->clear();
+ while(types && *types) {
+ d->types->insertItem(QString::fromLatin1(*types));
+ types++;
+ }
+ d->types->setCurrentItem(0);
+ setFilter(d->types->text(0));
+}
+
+
+/*!
+ \overload
+
+ \a types is a list of filter strings.
+*/
+
+void Q3FileDialog::setFilters(const QStringList & types)
+{
+ if (types.count() < 1)
+ return;
+
+ d->types->clear();
+ for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it)
+ d->types->insertItem(*it);
+ d->types->setCurrentItem(0);
+ setFilter(d->types->text(0));
+}
+
+/*!
+ Adds the filter \a filter to the list of filters and makes it the
+ current filter.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 15
+
+ In the above example, a file dialog is created, and the file filter "Images
+ (*.png *.jpg *.xpm)" is added and is set as the current filter. The original
+ filter, "All Files (*)", is still available.
+
+ \sa setFilter(), setFilters()
+*/
+
+void Q3FileDialog::addFilter(const QString &filter)
+{
+ if (filter.isEmpty())
+ return;
+ QString f = filter;
+ QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+ int index = r.indexIn(f);
+ if (index >= 0)
+ f = r.cap(2);
+ for (int i = 0; i < d->types->count(); ++i) {
+ QString f2(d->types->text(i));
+ int index = r.indexIn(f2);
+ if (index >= 0)
+ f2 = r.cap(1);
+ if (f2 == f) {
+ d->types->setCurrentItem(i);
+ setFilter(f2);
+ return;
+ }
+ }
+
+ d->types->insertItem(filter);
+ d->types->setCurrentItem(d->types->count() - 1);
+ setFilter(d->types->text(d->types->count() - 1));
+}
+
+/*!
+ Since modeButtons is a top-level widget, it may be destroyed by the
+ kernel at application exit. Notice if this happens to
+ avoid double deletion.
+*/
+
+void Q3FileDialog::modeButtonsDestroyed()
+{
+ if (d)
+ d->modeButtons = 0;
+}
+
+
+/*!
+ This is a convenience static function that will return one or more
+ existing files selected by the user.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 16
+
+ This function creates a modal file dialog called \a name, with
+ parent \a parent. If \a parent is not 0, the dialog will be shown
+ centered over the parent.
+
+ The file dialog's working directory will be set to \a dir. If \a
+ dir includes a file name, the file will be selected. The filter
+ is set to \a filter so that only those files which match the filter
+ are shown. The filter selected is set to \a selectedFilter. The parameters
+ \a dir, \a selectedFilter and \a filter may be empty strings.
+
+ The dialog's caption is set to \a caption. If \a caption is not
+ specified then a default caption will be used.
+
+ Under Windows and Mac OS X, this static function will use the native
+ file dialog and not a Q3FileDialog, unless the style of the application
+ is set to something other than the native style. (Note that on Windows the
+ dialog will spin a blocking modal event loop that will not dispatch any
+ QTimers and if parent is not 0 then it will position the dialog just under
+ the parent's title bar).
+
+ Under Unix/X11, the normal behavior of the file dialog is to resolve
+ and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
+ the file dialog will change to /var/tmp after entering /usr/tmp.
+ If \a resolveSymlinks is false, the file dialog will treat
+ symlinks as regular directories.
+
+ Note that if you want to iterate over the list of files, you should
+ iterate over a copy, e.g.
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 17
+
+ \sa getOpenFileName(), getSaveFileName(), getExistingDirectory()
+*/
+
+QStringList Q3FileDialog::getOpenFileNames(const QString & filter,
+ const QString& dir,
+ QWidget *parent,
+ const char* name,
+ const QString& caption,
+ QString *selectedFilter,
+ bool resolveSymlinks)
+{
+ bool save_qt_resolve_symlinks = qt_resolve_symlinks;
+ qt_resolve_symlinks = resolveSymlinks;
+
+ QStringList filters;
+ if (!filter.isEmpty())
+ filters = makeFiltersList(filter);
+
+ makeVariables();
+
+ if (workingDirectory->isNull())
+ *workingDirectory = toRootIfNotExists( QDir::currentDirPath() );
+
+ if (!dir.isEmpty()) {
+ // #### works only correct for local files
+ Q3UrlOperator u(Q3FileDialogPrivate::encodeFileName(dir));
+ if (u.isLocalFile() && QFileInfo(u.path()).isDir()) {
+ *workingDirectory = dir;
+ } else {
+ *workingDirectory = u.toString();
+ }
+ }
+
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && qobject_cast<QWindowsStyle *>(qApp->style()))
+ return winGetOpenFileNames(filter, workingDirectory, parent, name, caption, selectedFilter);
+#elif defined(Q_WS_MAC)
+ if (qt_use_native_dialogs && qobject_cast<QMacStyle *>(qApp->style())) {
+ QStringList sl = macGetOpenFileNames(filter, dir.isEmpty() ? 0 : workingDirectory,
+ parent, name, caption, selectedFilter);
+ for (int i = 0; i < sl.count(); ++i)
+ sl.replace(i, sl.at(i).normalized(QString::NormalizationForm_C));
+ return sl;
+ }
+#endif
+
+ Q3FileDialog *dlg = new Q3FileDialog(*workingDirectory, QString(), parent, name ? name : "qt_filedlg_gofns", true);
+
+ if (!caption.isNull())
+ dlg->setWindowTitle(caption);
+ else
+ dlg->setWindowTitle(Q3FileDialog::tr("Open"));
+
+ dlg->setFilters(filters);
+ if (selectedFilter)
+ dlg->setFilter(*selectedFilter);
+ dlg->setMode(Q3FileDialog::ExistingFiles);
+ QString result;
+ QStringList lst;
+ if (dlg->exec() == QDialog::Accepted) {
+ lst = dlg->selectedFiles();
+ *workingDirectory = dlg->d->url;
+ if (selectedFilter)
+ *selectedFilter = dlg->selectedFilter();
+ }
+ delete dlg;
+
+ qt_resolve_symlinks = save_qt_resolve_symlinks;
+
+ return lst;
+}
+
+/*! Updates the line edit to match the speed-key usage in Q3ListView. */
+
+void Q3FileDialog::fixupNameEdit()
+{
+ if (files->currentItem()) {
+ if (((Q3FileDialogPrivate::File*)files->currentItem())->info.isFile())
+ nameEdit->setText(files->currentItem()->text(0));
+ }
+}
+
+/*!
+ Returns the URL of the current working directory in the file dialog.
+
+ \sa setUrl()
+*/
+
+Q3Url Q3FileDialog::url() const
+{
+ return d->url;
+}
+
+static bool isRoot(const Q3Url &u)
+{
+#if defined(Q_OS_UNIX)
+ if (u.path() == QString(QLatin1Char('/')))
+ return true;
+#elif defined(Q_OS_WIN32)
+ QString p = u.path();
+ if (p.length() == 3 &&
+ p.right(2) == QLatin1String(":/"))
+ return true;
+ if (p[0] == QLatin1Char('/') && p[1] == QLatin1Char('/')) {
+ int slashes = p.count(QLatin1Char('/'));
+ if (slashes <= 3)
+ return true;
+ if (slashes == 4 && p[(int)p.length() - 1] == QLatin1Char('/'))
+ return true;
+ }
+#else
+#if defined(Q_CC_GNU)
+#warning "case not covered.."
+#endif
+#endif
+
+ if (!u.isLocalFile() && u.path() == QString(QLatin1Char('/')))
+ return true;
+
+ return false;
+}
+
+#if defined(Q_WS_WIN)
+extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
+#endif
+
+void Q3FileDialog::urlStart(Q3NetworkOperation *op)
+{
+ if (!op)
+ return;
+
+#if defined(Q_WS_WIN)
+ old_qt_ntfs_permission_lookup = qt_ntfs_permission_lookup;
+ qt_ntfs_permission_lookup = 0;
+#endif
+ if (op->operation() == Q3NetworkProtocol::OpListChildren) {
+#ifndef QT_NO_CURSOR
+ if (!d->cursorOverride) {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ d->cursorOverride = true;
+ }
+#endif
+ if (isRoot(d->url))
+ d->cdToParent->setEnabled(false);
+ else
+ d->cdToParent->setEnabled(true);
+ d->mimeTypeTimer->stop();
+ d->sortedList.clear();
+ d->pendingItems.clear();
+ d->moreFiles->clearSelection();
+ files->clearSelection();
+ d->moreFiles->clear();
+ files->clear();
+ files->setSorting(-1);
+
+ QString s = d->url.toString(false, false);
+ bool found = false;
+ for (int i = 0; i < d->paths->count(); ++i) {
+#if defined(Q_WS_WIN)
+ if (d->paths->text(i).toLower() == s.toLower()) {
+#else
+ if (d->paths->text(i) == s) {
+#endif
+ found = true;
+ d->paths->setCurrentItem(i);
+ break;
+ }
+ }
+ if (!found) {
+ d->paths->insertItem(*openFolderIcon, s, -1);
+ d->paths->setCurrentItem(d->paths->count() - 1);
+ }
+ d->last = 0;
+ d->hadDotDot = false;
+
+ if (d->goBack && (d->history.isEmpty() || d->history.last() != d->url.toString())) {
+ d->history.append(d->url.toString());
+ if (d->history.count() > 1)
+ d->goBack->setEnabled(true);
+ }
+ }
+}
+
+void Q3FileDialog::urlFinished(Q3NetworkOperation *op)
+{
+ if (!op)
+ return;
+
+#ifndef QT_NO_CURSOR
+ if (op->operation() == Q3NetworkProtocol::OpListChildren &&
+ d->cursorOverride) {
+ QApplication::restoreOverrideCursor();
+ d->cursorOverride = false;
+ }
+#endif
+
+ if (op->state() == Q3NetworkProtocol::StFailed) {
+ if (d->paths->hasFocus())
+ d->ignoreNextKeyPress = true;
+
+ if (d->progressDia) {
+ d->ignoreStop = true;
+ d->progressDia->close();
+ delete d->progressDia;
+ d->progressDia = 0;
+ }
+
+ int ecode = op->errorCode();
+ QMessageBox::critical(this, tr("Error"), op->protocolDetail());
+
+ if (ecode == Q3NetworkProtocol::ErrListChildren || ecode == Q3NetworkProtocol::ErrParse ||
+ ecode == Q3NetworkProtocol::ErrUnknownProtocol || ecode == Q3NetworkProtocol::ErrLoginIncorrect ||
+ ecode == Q3NetworkProtocol::ErrValid || ecode == Q3NetworkProtocol::ErrHostNotFound ||
+ ecode == Q3NetworkProtocol::ErrFileNotExisting) {
+ d->url = d->oldUrl;
+ rereadDir();
+ } else {
+ // another error happened, no need to go back to last dir
+ }
+ } else if (op->operation() == Q3NetworkProtocol::OpListChildren &&
+ op == d->currListChildren) {
+ if (!d->hadDotDot && !isRoot(d->url)) {
+ bool ok = true;
+#if defined(Q_WS_WIN)
+ if (d->url.path().left(2) == QLatin1String("//"))
+ ok = false;
+#endif
+ if (ok) {
+ QUrlInfo ui(d->url.info(QLatin1String("..")));
+ ui.setName(QLatin1String(".."));
+ ui.setDir(true);
+ ui.setFile(false);
+ ui.setSymLink(false);
+ ui.setSize(0);
+ Q3ValueList<QUrlInfo> lst;
+ lst << ui;
+ insertEntry(lst, 0);
+ }
+ }
+ resortDir();
+ } else if (op->operation() == Q3NetworkProtocol::OpGet) {
+ } else if (op->operation() == Q3NetworkProtocol::OpPut) {
+ rereadDir();
+ if (d->progressDia) {
+ d->ignoreStop = true;
+ d->progressDia->close();
+ }
+ delete d->progressDia;
+ d->progressDia = 0;
+ }
+
+#if defined(Q_WS_WIN)
+ qt_ntfs_permission_lookup = old_qt_ntfs_permission_lookup;
+#endif
+}
+
+void Q3FileDialog::dataTransferProgress(int bytesDone, int bytesTotal, Q3NetworkOperation *op)
+{
+ if (!op)
+ return;
+
+ QString label;
+ Q3Url u(op->arg(0));
+ if (u.isLocalFile()) {
+ label = u.path();
+ } else {
+ label = QLatin1String("%1 (on %2)");
+ label = label.arg(u.path()).arg(u.host());
+ }
+
+ if (!d->progressDia) {
+ if (bytesDone < bytesTotal) {
+ d->ignoreStop = false;
+ d->progressDia = new QFDProgressDialog(this, label, bytesTotal);
+ connect(d->progressDia, SIGNAL(cancelled()),
+ this, SLOT(stopCopy()));
+ d->progressDia->show();
+ } else
+ return;
+ }
+
+ if (d->progressDia) {
+ if (op->operation() == Q3NetworkProtocol::OpGet) {
+ if (d->progressDia) {
+ d->progressDia->setReadProgress(bytesDone);
+ }
+ } else if (op->operation() == Q3NetworkProtocol::OpPut) {
+ if (d->progressDia) {
+ d->progressDia->setWriteLabel(label);
+ d->progressDia->setWriteProgress(bytesDone);
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+void Q3FileDialog::insertEntry(const Q3ValueList<QUrlInfo> &lst, Q3NetworkOperation *op)
+{
+ if (op && op->operation() == Q3NetworkProtocol::OpListChildren &&
+ op != d->currListChildren)
+ return;
+ Q3ValueList<QUrlInfo>::ConstIterator it = lst.begin();
+ for (; it != lst.end(); ++it) {
+ const QUrlInfo &inf = *it;
+ if (d->mode == DirectoryOnly && !inf.isDir())
+ continue;
+ if (inf.name() == QLatin1String("..")) {
+ d->hadDotDot = true;
+ if (isRoot(d->url))
+ continue;
+#if defined(Q_WS_WIN)
+ if (d->url.path().left(2) == QLatin1String("//"))
+ continue;
+#endif
+ } else if (inf.name() == QString(QLatin1Char('.')))
+ continue;
+
+#if defined(Q_WS_WIN)
+ // Workaround a Windows bug, '..' is apparantly hidden in directories
+ // that are one level away from root
+ if (!bShowHiddenFiles && inf.name() != QLatin1String("..")) {
+ if (d->url.isLocalFile()) {
+ QString file = d->url.path();
+ if (!file.endsWith(QLatin1String("/")))
+ file.append(QLatin1String("/"));
+ file += inf.name();
+ QT_WA({
+ if (GetFileAttributesW((TCHAR*)file.ucs2()) & FILE_ATTRIBUTE_HIDDEN)
+ continue;
+ } , {
+ if (GetFileAttributesA(file.local8Bit()) & FILE_ATTRIBUTE_HIDDEN)
+ continue;
+ });
+ } else {
+ if (inf.name() != QLatin1String("..") && inf.name()[0] == QLatin1Char('.'))
+ continue;
+ }
+ }
+#else
+ if (!bShowHiddenFiles && inf.name() != QLatin1String("..")) {
+ if (inf.name()[0] == QLatin1Char('.'))
+ continue;
+ }
+#endif
+ if (!d->url.isLocalFile()) {
+ Q3FileDialogPrivate::File * i = 0;
+ Q3FileDialogPrivate::MCItem *i2 = 0;
+ i = new Q3FileDialogPrivate::File(d, &inf, files);
+ i2 = new Q3FileDialogPrivate::MCItem(d->moreFiles, i);
+
+ if ((d->mode == ExistingFiles && inf.isDir())
+ || (isDirectoryMode(d->mode) && inf.isFile())) {
+ i->setSelectable(false);
+ i2->setSelectable(false);
+ }
+
+ i->i = i2;
+ }
+
+ d->sortedList.append(new QUrlInfo(inf));
+ }
+}
+
+void Q3FileDialog::removeEntry(Q3NetworkOperation *op)
+{
+ if (!op)
+ return;
+
+ QUrlInfo *i = 0;
+ Q3ListViewItemIterator it(files);
+ bool ok1 = false, ok2 = false;
+ for (i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next()) {
+ QString encName = Q3FileDialogPrivate::encodeFileName(
+ ((Q3FileDialogPrivate::File*)it.current())->info.name());
+ if (encName == op->arg(0)) {
+ d->pendingItems.removeRef((Q3FileDialogPrivate::File*)it.current());
+ delete ((Q3FileDialogPrivate::File*)it.current())->i;
+ delete it.current();
+ ok1 = true;
+ }
+ if (i && i->name() == op->arg(0)) {
+ d->sortedList.removeRef(i);
+ i = d->sortedList.prev();
+ ok2 = true;
+ }
+ if (ok1 && ok2)
+ break;
+ }
+}
+
+void Q3FileDialog::itemChanged(Q3NetworkOperation *op)
+{
+ if (!op)
+ return;
+
+ QUrlInfo *i = 0;
+ Q3ListViewItemIterator it1(files);
+ bool ok1 = false, ok2 = false;
+ // first check whether the new file replaces an existing file.
+ for (i = d->sortedList.first(); it1.current(); ++it1, i = d->sortedList.next()) {
+ if (((Q3FileDialogPrivate::File*)it1.current())->info.name() == op->arg(1)) {
+ delete ((Q3FileDialogPrivate::File*)it1.current())->i;
+ delete it1.current();
+ ok1 = true;
+ }
+ if (i && i->name() == op->arg(1)) {
+ d->sortedList.removeRef(i);
+ i = d->sortedList.prev();
+ ok2 = true;
+ }
+ if (ok1 && ok2)
+ break;
+ }
+
+ i = 0;
+ Q3ListViewItemIterator it(files);
+ ok1 = false;
+ ok2 = false;
+ for (i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next()) {
+ if (((Q3FileDialogPrivate::File*)it.current())->info.name() == op->arg(0)) {
+ ((Q3FileDialogPrivate::File*)it.current())->info.setName(op->arg(1));
+ ok1 = true;
+ }
+ if (i && i->name() == op->arg(0)) {
+ i->setName(op->arg(1));
+ ok2 = true;
+ }
+ if (ok1 && ok2)
+ break;
+ }
+
+ resortDir();
+}
+
+/*!
+ \property Q3FileDialog::infoPreview
+
+ \brief whether the file dialog can provide preview information about
+ the currently selected file
+
+ The default is false.
+*/
+bool Q3FileDialog::isInfoPreviewEnabled() const
+{
+ return d->infoPreview;
+}
+
+void Q3FileDialog::setInfoPreviewEnabled(bool info)
+{
+ if (info == d->infoPreview)
+ return;
+ d->geometryDirty = true;
+ d->infoPreview = info;
+ updateGeometries();
+}
+
+
+/*!
+ \property Q3FileDialog::contentsPreview
+
+ \brief whether the file dialog can provide a contents preview of the
+ currently selected file
+
+ The default is false.
+
+ \sa setContentsPreview() setInfoPreviewEnabled()
+*/
+// ### improve the above documentation: how is the preview done, how can I add
+// support for customized preview, etc.
+
+bool Q3FileDialog::isContentsPreviewEnabled() const
+{
+ return d->contentsPreview;
+}
+
+void Q3FileDialog::setContentsPreviewEnabled(bool contents)
+{
+ if (contents == d->contentsPreview)
+ return;
+ d->geometryDirty = true;
+ d->contentsPreview = contents;
+ updateGeometries();
+}
+
+
+/*!
+ Sets the widget to be used for displaying information about the file
+ to the widget \a w and a preview of that information to the
+ Q3FilePreview \a preview.
+
+ Normally you would create a preview widget that derives from both QWidget and
+ Q3FilePreview, so you should pass the same widget twice.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 18
+
+ \sa setContentsPreview(), setInfoPreviewEnabled(), setPreviewMode()
+
+*/
+
+void Q3FileDialog::setInfoPreview(QWidget *w, Q3FilePreview *preview)
+{
+ if (!w || !preview)
+ return;
+
+ if (d->infoPreviewWidget) {
+ d->preview->removeWidget(d->infoPreviewWidget);
+ if ((void*)d->infoPreviewer == (void*)d->infoPreviewWidget)
+ d->infoPreviewer = 0;
+ delete d->infoPreviewWidget;
+ }
+ if (d->infoPreviewer)
+ delete d->infoPreviewer;
+ d->infoPreviewWidget = w;
+ d->infoPreviewer = preview;
+ w->reparent(d->preview, 0, QPoint(0, 0));
+}
+
+/*!
+ Sets the widget to be used for displaying the contents of the file
+ to the widget \a w and a preview of those contents to the
+ Q3FilePreview \a preview.
+
+ Normally you would create a preview widget that derives from both QWidget and
+ Q3FilePreview, so you should pass the same widget twice.
+
+ \snippet doc/src/snippets/code/src_qt3support_dialogs_q3filedialog.cpp 19
+
+ \sa setContentsPreviewEnabled(), setInfoPreview(), setPreviewMode()
+*/
+
+void Q3FileDialog::setContentsPreview(QWidget *w, Q3FilePreview *preview)
+{
+ if (!w || !preview)
+ return;
+
+ if (d->contentsPreviewWidget) {
+ d->preview->removeWidget(d->contentsPreviewWidget);
+ if ((void*)d->contentsPreviewWidget == (void*)d->contentsPreviewer)
+ d->contentsPreviewer = 0;
+ delete d->contentsPreviewWidget;
+ }
+ if (d->contentsPreviewer)
+ delete d->contentsPreviewer;
+ d->contentsPreviewWidget = w;
+ d->contentsPreviewer = preview;
+ w->reparent(d->preview, 0, QPoint(0, 0));
+}
+
+/*!
+ Re-sorts the displayed directory.
+
+ \sa rereadDir()
+*/
+
+void Q3FileDialog::resortDir()
+{
+ d->mimeTypeTimer->stop();
+ d->pendingItems.clear();
+
+ Q3FileDialogPrivate::File *item = 0;
+ Q3FileDialogPrivate::MCItem *item2 = 0;
+
+ d->sortedList.sort();
+
+ if (files->childCount() > 0 || d->moreFiles->count() > 0) {
+ d->moreFiles->clear();
+ files->clear();
+ d->last = 0;
+ files->setSorting(-1);
+ }
+
+ QUrlInfo *i = sortAscending ? d->sortedList.first() : d->sortedList.last();
+ for (; i; i = sortAscending ? d->sortedList.next() : d->sortedList.prev()) {
+ item = new Q3FileDialogPrivate::File(d, i, files);
+ item2 = new Q3FileDialogPrivate::MCItem(d->moreFiles, item, item2);
+ item->i = item2;
+ d->pendingItems.append(item);
+ if ((d->mode == ExistingFiles && item->info.isDir()) ||
+ (isDirectoryMode(d->mode) && item->info.isFile())) {
+ item->setSelectable(false);
+ item2->setSelectable(false);
+ }
+ }
+
+ // ##### As the Q3FileIconProvider only support QFileInfo and no
+ // QUrlInfo it can be only used for local files at the moment. In
+ // 3.0 we have to change the API of Q3FileIconProvider to work on
+ // QUrlInfo so that also remote filesystems can be show mime-type
+ // specific icons.
+ if (d->url.isLocalFile())
+ d->mimeTypeTimer->start(0);
+}
+
+/*!
+ Stops the current copy operation.
+*/
+
+void Q3FileDialog::stopCopy()
+{
+ if (d->ignoreStop)
+ return;
+
+ d->url.blockSignals(true);
+ d->url.stop();
+ if (d->progressDia) {
+ d->ignoreStop = true;
+ QTimer::singleShot(100, this, SLOT(removeProgressDia()));
+ }
+ d->url.blockSignals(false);
+}
+
+/*!
+ \internal
+*/
+
+void Q3FileDialog::removeProgressDia()
+{
+ if (d->progressDia)
+ delete d->progressDia;
+ d->progressDia = 0;
+}
+
+/*!
+ \internal
+*/
+
+void Q3FileDialog::doMimeTypeLookup()
+{
+ if (!iconProvider()) {
+ d->pendingItems.clear();
+ d->mimeTypeTimer->stop();
+ return;
+ }
+
+ d->mimeTypeTimer->stop();
+ if (d->pendingItems.count() == 0) {
+ return;
+ }
+
+ QRect r;
+ Q3FileDialogPrivate::File *item = d->pendingItems.first();
+ if (item) {
+ QFileInfo fi;
+ if (d->url.isLocalFile()) {
+ fi.setFile(Q3Url(d->url.path(), Q3FileDialogPrivate::encodeFileName(item->info.name())).path(false));
+ } else
+ fi.setFile(item->info.name()); // #####
+ const QPixmap *p = iconProvider()->pixmap(fi);
+ if (p && p != item->pixmap(0) &&
+ (!item->pixmap(0) || p->serialNumber() != item->pixmap(0)->serialNumber()) &&
+ p != fifteenTransparentPixels) {
+ item->hasMimePixmap = true;
+
+ // evil hack to avoid much too much repaints!
+ QPointer<Q3FileDialog> that(this); // this may be deleted by an event handler
+ qApp->processEvents();
+ if (that.isNull())
+ return;
+ files->setUpdatesEnabled(false);
+ files->viewport()->setUpdatesEnabled(false);
+ if (item != d->pendingItems.first())
+ return;
+ item->setPixmap(0, *p);
+ qApp->processEvents();
+ if (that.isNull())
+ return;
+ files->setUpdatesEnabled(true);
+ files->viewport()->setUpdatesEnabled(true);
+
+ if (files->isVisible()) {
+ QRect ir(files->itemRect(item));
+ if (ir != QRect(0, 0, -1, -1)) {
+ r = r.united(ir);
+ }
+ } else {
+ QRect ir(d->moreFiles->itemRect(item->i));
+ if (ir != QRect(0, 0, -1, -1)) {
+ r = r.united(ir);
+ }
+ }
+ }
+ if (d->pendingItems.count())
+ d->pendingItems.removeFirst();
+ }
+
+ if (d->moreFiles->isVisible()) {
+ d->moreFiles->viewport()->repaint(r);
+ } else {
+ files->viewport()->repaint(r);
+ }
+
+ if (d->pendingItems.count())
+ d->mimeTypeTimer->start(0);
+ else if (d->moreFiles->isVisible())
+ d->moreFiles->triggerUpdate(true);
+}
+
+/*!
+ If \a b is true then all the files in the current directory are selected;
+ otherwise, they are deselected.
+*/
+
+void Q3FileDialog::selectAll(bool b)
+{
+ if (d->mode != ExistingFiles)
+ return;
+ d->moreFiles->selectAll(b);
+ files->selectAll(b);
+}
+
+void Q3FileDialog::goBack()
+{
+ if (!d->goBack || !d->goBack->isEnabled() || d->history.isEmpty())
+ return;
+ d->history.removeLast();
+ if (d->history.size() < 2)
+ d->goBack->setEnabled(false);
+ setUrl(d->history.last());
+}
+
+// a class with wonderfully inflexible flexibility. why doesn't it
+// just subclass QWidget in the first place? 'you have to derive your
+// preview widget from QWidget and from this class' indeed.
+
+/*!
+ \class Q3FilePreview
+ \brief The Q3FilePreview class provides file previewing in Q3FileDialog.
+
+ \compat
+
+ This class is an abstract base class which is used to implement
+ widgets that can display a preview of a file in a Q3FileDialog.
+
+ You must derive the preview widget from both QWidget and from this
+ class. Then you must reimplement this class's previewUrl() function,
+ which is called by the file dialog if the preview of a file
+ (specified as a URL) should be shown.
+
+ See also Q3FileDialog::setPreviewMode(), Q3FileDialog::setContentsPreview(),
+ Q3FileDialog::setInfoPreview(), Q3FileDialog::setInfoPreviewEnabled(),
+ Q3FileDialog::setContentsPreviewEnabled().
+*/
+
+/*!
+ Constructs the Q3FilePreview.
+*/
+
+Q3FilePreview::Q3FilePreview()
+{
+}
+
+/*!
+ \fn Q3FilePreview::~Q3FilePreview()
+
+ Destroys the file preview object.
+*/
+
+/*!
+ \fn void Q3FilePreview::previewUrl(const Q3Url &url)
+
+ This function is called by Q3FileDialog if a preview
+ for the \a url should be shown. Reimplement this
+ function to provide file previewing.
+*/
+
+
+QT_END_NAMESPACE
+
+#include "moc_q3filedialog.cpp"
+#include "q3filedialog.moc"
+
+#endif