summaryrefslogtreecommitdiffstats
path: root/src/qt3support/dialogs
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 10:18:55 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 10:18:55 +0100
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/qt3support/dialogs
Long live Qt 4.5!
Diffstat (limited to 'src/qt3support/dialogs')
-rw-r--r--src/qt3support/dialogs/dialogs.pri16
-rw-r--r--src/qt3support/dialogs/q3filedialog.cpp6203
-rw-r--r--src/qt3support/dialogs/q3filedialog.h346
-rw-r--r--src/qt3support/dialogs/q3filedialog_mac.cpp569
-rw-r--r--src/qt3support/dialogs/q3filedialog_win.cpp749
-rw-r--r--src/qt3support/dialogs/q3progressdialog.cpp850
-rw-r--r--src/qt3support/dialogs/q3progressdialog.h149
-rw-r--r--src/qt3support/dialogs/q3tabdialog.cpp1076
-rw-r--r--src/qt3support/dialogs/q3tabdialog.h142
-rw-r--r--src/qt3support/dialogs/q3wizard.cpp906
-rw-r--r--src/qt3support/dialogs/q3wizard.h141
11 files changed, 11147 insertions, 0 deletions
diff --git a/src/qt3support/dialogs/dialogs.pri b/src/qt3support/dialogs/dialogs.pri
new file mode 100644
index 0000000000..7ea5fb27fa
--- /dev/null
+++ b/src/qt3support/dialogs/dialogs.pri
@@ -0,0 +1,16 @@
+# Qt compat module
+
+HEADERS += \
+ dialogs/q3filedialog.h \
+ dialogs/q3tabdialog.h \
+ dialogs/q3progressdialog.h \
+ dialogs/q3wizard.h
+
+SOURCES += \
+ dialogs/q3filedialog.cpp \
+ dialogs/q3progressdialog.cpp \
+ dialogs/q3tabdialog.cpp \
+ dialogs/q3wizard.cpp
+
+win32:SOURCES += dialogs/q3filedialog_win.cpp
+!embedded:mac:SOURCES += dialogs/q3filedialog_mac.cpp
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
diff --git a/src/qt3support/dialogs/q3filedialog.h b/src/qt3support/dialogs/q3filedialog.h
new file mode 100644
index 0000000000..c0a64cc61c
--- /dev/null
+++ b/src/qt3support/dialogs/q3filedialog.h
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef Q3FILEDIALOG_H
+#define Q3FILEDIALOG_H
+
+#include <QtCore/qdir.h>
+#include <QtGui/qdialog.h>
+#include <Qt3Support/q3urloperator.h>
+#include <Qt3Support/q3valuelist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class QAbstractButton;
+class QPushButton;
+class QLabel;
+class QWidget;
+class QFileDialog;
+class QTimer;
+class Q3NetworkOperation;
+class QLineEdit;
+class Q3ListViewItem;
+class Q3ListBoxItem;
+class Q3FileDialogPrivate;
+class Q3FileDialogQFileListView;
+class QUrlInfo;
+
+#ifndef QT_NO_FILEDIALOG
+
+class Q_COMPAT_EXPORT Q3FileIconProvider : public QObject
+{
+ Q_OBJECT
+public:
+ Q3FileIconProvider(QObject * parent = 0, const char* name = 0);
+ virtual const QPixmap * pixmap(const QFileInfo &);
+
+private:
+ Q_DISABLE_COPY(Q3FileIconProvider)
+};
+
+class Q_COMPAT_EXPORT Q3FilePreview
+{
+public:
+ Q3FilePreview();
+ virtual ~Q3FilePreview() {}
+ virtual void previewUrl(const Q3Url &url) = 0;
+
+};
+
+class Q_COMPAT_EXPORT Q3FileDialog : public QDialog
+{
+ Q_OBJECT
+ Q_ENUMS(Mode ViewMode PreviewMode)
+ // ##### Why are this read-only properties ?
+ Q_PROPERTY(QString selectedFile READ selectedFile)
+ Q_PROPERTY(QString selectedFilter READ selectedFilter)
+ Q_PROPERTY(QStringList selectedFiles READ selectedFiles)
+ // #### Should not we be able to set the path ?
+ Q_PROPERTY(QString dirPath READ dirPath)
+ Q_PROPERTY(bool showHiddenFiles READ showHiddenFiles WRITE setShowHiddenFiles)
+ Q_PROPERTY(Mode mode READ mode WRITE setMode)
+ Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode)
+ Q_PROPERTY(PreviewMode previewMode READ previewMode WRITE setPreviewMode)
+ Q_PROPERTY(bool infoPreview READ isInfoPreviewEnabled WRITE setInfoPreviewEnabled)
+ Q_PROPERTY(bool contentsPreview READ isContentsPreviewEnabled WRITE setContentsPreviewEnabled)
+
+public:
+ Q3FileDialog(const QString& dirName, const QString& filter = QString(),
+ QWidget* parent=0, const char* name=0, bool modal = false);
+ Q3FileDialog(QWidget* parent=0, const char* name=0, bool modal = false);
+ ~Q3FileDialog();
+
+ // recommended static functions
+
+ static QString getOpenFileName(const QString &initially = QString(),
+ const QString &filter = QString(),
+ QWidget *parent = 0, const char* name = 0,
+ const QString &caption = QString(),
+ QString *selectedFilter = 0,
+ bool resolveSymlinks = true);
+ static QString getSaveFileName(const QString &initially = QString(),
+ const QString &filter = QString(),
+ QWidget *parent = 0, const char* name = 0,
+ const QString &caption = QString(),
+ QString *selectedFilter = 0,
+ bool resolveSymlinks = true);
+ static QString getExistingDirectory(const QString &dir = QString(),
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString &caption = QString(),
+ bool dirOnly = true,
+ bool resolveSymlinks = true);
+ static QStringList getOpenFileNames(const QString &filter= QString(),
+ const QString &dir = QString(),
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString &caption = QString(),
+ QString *selectedFilter = 0,
+ bool resolveSymlinks = true);
+
+ // other static functions
+
+ static void setIconProvider(Q3FileIconProvider *);
+ static Q3FileIconProvider * iconProvider();
+
+ // non-static function for special needs
+
+ QString selectedFile() const;
+ QString selectedFilter() const;
+ virtual void setSelectedFilter(const QString&);
+ virtual void setSelectedFilter(int);
+
+ void setSelection(const QString &);
+
+ void selectAll(bool b);
+
+ QStringList selectedFiles() const;
+
+ QString dirPath() const;
+
+ void setDir(const QDir &);
+ const QDir *dir() const;
+
+ void setShowHiddenFiles(bool s);
+ bool showHiddenFiles() const;
+
+ void rereadDir();
+ void resortDir();
+
+ enum Mode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly };
+ void setMode(Mode);
+ Mode mode() const;
+
+ enum ViewMode { Detail, List };
+ enum PreviewMode { NoPreview, Contents, Info };
+ void setViewMode(ViewMode m);
+ ViewMode viewMode() const;
+ void setPreviewMode(PreviewMode m);
+ PreviewMode previewMode() const;
+
+ bool eventFilter(QObject *, QEvent *);
+
+ bool isInfoPreviewEnabled() const;
+ bool isContentsPreviewEnabled() const;
+ void setInfoPreviewEnabled(bool);
+ void setContentsPreviewEnabled(bool);
+
+ void setInfoPreview(QWidget *w, Q3FilePreview *preview);
+ void setContentsPreview(QWidget *w, Q3FilePreview *preview);
+
+ Q3Url url() const;
+
+ void addFilter(const QString &filter);
+
+public Q_SLOTS:
+ void done(int);
+ void setDir(const QString&);
+ void setUrl(const Q3UrlOperator &url);
+ void setFilter(const QString&);
+ void setFilters(const QString&);
+ void setFilters(const char **);
+ void setFilters(const QStringList&);
+
+protected:
+ void resizeEvent(QResizeEvent *);
+ void keyPressEvent(QKeyEvent *);
+
+ void addWidgets(QLabel *, QWidget *, QPushButton *);
+ void addToolButton(QAbstractButton *b, bool separator = false);
+ void addLeftWidget(QWidget *w);
+ void addRightWidget(QWidget *w);
+
+Q_SIGNALS:
+ void fileHighlighted(const QString&);
+ void fileSelected(const QString&);
+ void filesSelected(const QStringList&);
+ void dirEntered(const QString&);
+ void filterSelected(const QString&);
+
+private Q_SLOTS:
+ void detailViewSelectionChanged();
+ void listBoxSelectionChanged();
+ void changeMode(int);
+ void fileNameEditReturnPressed();
+ void stopCopy();
+ void removeProgressDia();
+
+ void fileSelected(int);
+ void fileHighlighted(int);
+ void dirSelected(int);
+ void pathSelected(int);
+
+ void updateFileNameEdit(Q3ListViewItem *);
+ void selectDirectoryOrFile(Q3ListViewItem *);
+ void popupContextMenu(Q3ListViewItem *, const QPoint &, int);
+ void popupContextMenu(Q3ListBoxItem *, const QPoint &);
+ void updateFileNameEdit(Q3ListBoxItem *);
+ void selectDirectoryOrFile(Q3ListBoxItem *);
+ void fileNameEditDone();
+
+ void okClicked();
+ void filterClicked(); // not used
+ void cancelClicked();
+
+ void cdUpClicked();
+ void newFolderClicked();
+
+ void fixupNameEdit();
+
+ void doMimeTypeLookup();
+
+ void updateGeometries();
+ void modeButtonsDestroyed();
+ void urlStart(Q3NetworkOperation *op);
+ void urlFinished(Q3NetworkOperation *op);
+ void dataTransferProgress(int bytesDone, int bytesTotal, Q3NetworkOperation *);
+ void insertEntry(const Q3ValueList<QUrlInfo> &fi, Q3NetworkOperation *op);
+ void removeEntry(Q3NetworkOperation *);
+ void createdDirectory(const QUrlInfo &info, Q3NetworkOperation *);
+ void itemChanged(Q3NetworkOperation *);
+ void goBack();
+
+private:
+ Q_DISABLE_COPY(Q3FileDialog)
+
+ enum PopupAction {
+ PA_Open = 0,
+ PA_Delete,
+ PA_Rename,
+ PA_SortName,
+ PA_SortSize,
+ PA_SortType,
+ PA_SortDate,
+ PA_SortUnsorted,
+ PA_Cancel,
+ PA_Reload,
+ PA_Hidden
+ };
+
+ void init();
+ bool trySetSelection(bool isDir, const Q3UrlOperator &, bool);
+ void deleteFile(const QString &filename);
+ void popupContextMenu(const QString &filename, bool withSort,
+ PopupAction &action, const QPoint &p);
+ void updatePreviews(const Q3Url &u);
+
+ QString fileName;
+
+ friend class Q3FileDialogQFileListView;
+ friend class QFileListBox;
+
+ Q3FileDialogPrivate *d;
+ Q3FileDialogQFileListView *files;
+
+ QLineEdit *nameEdit; // also filter
+ QPushButton *okB;
+ QPushButton *cancelB;
+
+#if defined(Q_WS_WIN)
+ static QString winGetOpenFileName(const QString &initialSelection,
+ const QString &filter,
+ QString* workingDirectory,
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString& caption = QString(),
+ QString* selectedFilter = 0);
+ static QString winGetSaveFileName(const QString &initialSelection,
+ const QString &filter,
+ QString* workingDirectory,
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString& caption = QString(),
+ QString* selectedFilter = 0);
+ static QStringList winGetOpenFileNames(const QString &filter,
+ QString* workingDirectory,
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString& caption = QString(),
+ QString* selectedFilter = 0);
+ static QString winGetExistingDirectory(const QString &initialDirectory,
+ QWidget* parent = 0,
+ const char* name = 0,
+ const QString& caption = QString());
+ static QString resolveLinkFile(const QString& linkfile);
+ int old_qt_ntfs_permission_lookup;
+#endif
+#if defined(Q_WS_MAC)
+ static QString macGetSaveFileName(const QString &, const QString &,
+ QString *, QWidget *, const char*,
+ const QString&, QString *);
+ static QStringList macGetOpenFileNames(const QString &, QString*,
+ QWidget *, const char *,
+ const QString&, QString *,
+ bool = true, bool = false);
+#endif
+};
+
+#endif // QT_NO_FILEDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3FILEDIALOG_H
diff --git a/src/qt3support/dialogs/q3filedialog_mac.cpp b/src/qt3support/dialogs/q3filedialog_mac.cpp
new file mode 100644
index 0000000000..f1c749ecb8
--- /dev/null
+++ b/src/qt3support/dialogs/q3filedialog_mac.cpp
@@ -0,0 +1,569 @@
+/****************************************************************************
+**
+** 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 "q3filedialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+/*****************************************************************************
+ Q3FileDialog debug facilities
+ *****************************************************************************/
+//#define DEBUG_FILEDIALOG_FILTERS
+
+#include "qapplication.h"
+#include <private/qapplication_p.h>
+#include <private/qt_mac_p.h>
+#include "qregexp.h"
+#include "qbuffer.h"
+#include "qstringlist.h"
+#include "qtextcodec.h"
+#include "qdesktopwidget.h"
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+/*****************************************************************************
+ Externals
+ *****************************************************************************/
+extern WindowPtr qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
+extern const char qt3_file_dialog_filter_reg_exp[]; //qfiledialog.cpp
+
+/*****************************************************************************
+ Q3FileDialog utility functions
+ *****************************************************************************/
+static UInt8 *str_buffer = NULL;
+static void cleanup_str_buffer()
+{
+ if(str_buffer) {
+ free(str_buffer);
+ str_buffer = NULL;
+ }
+}
+
+// Returns the wildcard part of a filter.
+struct qt_mac_filter_name {
+ QString description, regxp, filter;
+};
+static qt_mac_filter_name *extractFilter(const QString& rawFilter)
+{
+ qt_mac_filter_name *ret = new qt_mac_filter_name;
+ ret->filter = rawFilter;
+ QString result = rawFilter;
+ QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+ int index = r.indexIn(result);
+ if(index >= 0) {
+ ret->description = r.cap(1).trimmed();
+ result = r.cap(2);
+ }
+ if(ret->description.isEmpty())
+ ret->description = result;
+ ret->regxp = result.replace(QLatin1Char(' '), QLatin1Char(';'));
+ return ret;
+}
+
+// Makes a list of filters from ;;-separated text.
+static QList<qt_mac_filter_name*> makeFiltersList(const QString &filter)
+{
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("Q3FileDialog:%d - Got filter (%s)", __LINE__, filter.latin1());
+#endif
+ QString f(filter);
+ if(f.isEmpty())
+ f = Q3FileDialog::tr("All Files (*)");
+ if(f.isEmpty())
+ return QList<qt_mac_filter_name*>();
+ QString sep(QLatin1String(";;"));
+ int i = f.indexOf(sep, 0);
+ if(i == -1) {
+ sep = QLatin1String("\n");
+ if(f.indexOf(sep, 0) != -1)
+ i = f.indexOf(sep, 0);
+ }
+
+ QList<qt_mac_filter_name*> ret;
+ QStringList filts = f.split(sep);
+ for (QStringList::Iterator it = filts.begin(); it != filts.end(); ++it) {
+ qt_mac_filter_name *filter = extractFilter((*it));
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("Q3FileDialog:%d Split out filter (%d) '%s' '%s'", __LINE__, ret.count(),
+ filter->regxp.latin1(), filter->description.latin1());
+#endif
+ ret.append(filter);
+ }
+ return ret;
+}
+
+struct qt_mac_nav_filter_type {
+ int index;
+ QList<qt_mac_filter_name*> *filts;
+};
+
+static Boolean qt_mac_nav_filter(AEDesc *theItem, void *info,
+ void *myd, NavFilterModes)
+{
+ qt_mac_nav_filter_type *t = (qt_mac_nav_filter_type *)myd;
+ if(!t || !t->filts || t->index >= t->filts->count())
+ return true;
+
+ NavFileOrFolderInfo *theInfo = (NavFileOrFolderInfo *)info;
+ QString file;
+ qt_mac_filter_name *fn = t->filts->at(t->index);
+ if(!fn)
+ return true;
+ if(theItem->descriptorType == typeFSRef) {
+ FSRef ref;
+ AEGetDescData(theItem, &ref, sizeof(ref));
+ if(!str_buffer) {
+ qAddPostRoutine(cleanup_str_buffer);
+ str_buffer = (UInt8 *)malloc(1024);
+ }
+ FSRefMakePath(&ref, str_buffer, 1024);
+ file = QString::fromUtf8((const char *)str_buffer);
+ int slsh = file.lastIndexOf(QLatin1Char('/'));
+ if(slsh != -1)
+ file = file.right(file.length() - slsh - 1);
+ }
+ QStringList reg = fn->regxp.split(QLatin1String(";"));
+ for(QStringList::Iterator it = reg.begin(); it != reg.end(); ++it) {
+ QRegExp rg((*it), false, true);
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("Q3FileDialog:%d, asked to filter.. %s (%s)", __LINE__,
+ file.latin1(), (*it).latin1());
+#endif
+ if(rg.exactMatch(file))
+ return true;
+ }
+ return (theInfo->isFolder && !file.endsWith(QLatin1String(".app")));
+}
+
+//filter UPP stuff
+static NavObjectFilterUPP mac_navFilterUPP = NULL;
+static void cleanup_navFilterUPP()
+{
+ DisposeNavObjectFilterUPP(mac_navFilterUPP);
+ mac_navFilterUPP = NULL;
+}
+static const NavObjectFilterUPP make_navFilterUPP()
+{
+ if(mac_navFilterUPP)
+ return mac_navFilterUPP;
+ qAddPostRoutine(cleanup_navFilterUPP);
+ return mac_navFilterUPP = NewNavObjectFilterUPP(qt_mac_nav_filter);
+}
+//event UPP stuff
+static NavEventUPP mac_navProcUPP = NULL;
+static void cleanup_navProcUPP()
+{
+ DisposeNavEventUPP(mac_navProcUPP);
+ mac_navProcUPP = NULL;
+}
+static bool g_nav_blocking=true;
+static void qt_mac_filedialog_event_proc(const NavEventCallbackMessage msg,
+ NavCBRecPtr p, NavCallBackUserData myd)
+{
+ switch(msg) {
+ case kNavCBPopupMenuSelect: {
+ qt_mac_nav_filter_type *t = (qt_mac_nav_filter_type *)myd;
+ NavMenuItemSpec *s = (NavMenuItemSpec*)p->eventData.eventDataParms.param;
+ t->index = s->menuType;
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("Q3FileDialog:%d - Selected a filter: %ld", __LINE__, s->menuType);
+#endif
+ break; }
+ case kNavCBStart:
+ g_nav_blocking=true;
+ break;
+ case kNavCBUserAction:
+ g_nav_blocking=false;
+ break;
+ }
+}
+static const NavEventUPP make_navProcUPP()
+{
+ if(mac_navProcUPP)
+ return mac_navProcUPP;
+ qAddPostRoutine(cleanup_navProcUPP);
+ return mac_navProcUPP = NewNavEventUPP(qt_mac_filedialog_event_proc);
+}
+
+
+extern OSErr qt_mac_create_fsref(const QString &, FSRef *); //qglobal.cpp
+
+QStringList Q3FileDialog::macGetOpenFileNames(const QString &filter, QString *pwd,
+ QWidget *parent, const char* /*name*/,
+ const QString& caption, QString *selectedFilter,
+ bool multi, bool directory)
+{
+ OSErr err;
+ QStringList retstrl;
+
+ NavDialogCreationOptions options;
+ NavGetDefaultDialogCreationOptions(&options);
+ options.modality = kWindowModalityAppModal;
+ options.optionFlags |= kNavDontConfirmReplacement | kNavSupportPackages;
+ if (!multi)
+ options.optionFlags &= ~kNavAllowMultipleFiles;
+ if(!caption.isEmpty())
+ options.windowTitle = CFStringCreateWithCharacters(NULL, (UniChar *)caption.unicode(),
+ caption.length());
+
+ static const int w = 450, h = 350;
+ options.location.h = options.location.v = -1;
+ if(parent && parent->isVisible()) {
+ Qt::WindowType wt = parent->window()->windowType();
+ if (wt != Qt::Desktop && wt != Qt::Sheet && wt != Qt::Drawer) {
+ options.modality = kWindowModalityWindowModal;
+ options.parentWindow = qt_mac_window_for(parent);
+ } else {
+ parent = parent->window();
+ QString s = parent->windowTitle();
+ options.clientName = CFStringCreateWithCharacters(NULL, (UniChar *)s.unicode(), s.length());
+ options.location.h = (parent->x() + (parent->width() / 2)) - (w / 2);
+ options.location.v = (parent->y() + (parent->height() / 2)) - (h / 2);
+
+ QRect r = QApplication::desktop()->screenGeometry(
+ QApplication::desktop()->screenNumber(parent));
+ if(options.location.h + w > r.right())
+ options.location.h -= (options.location.h + w) - r.right() + 10;
+ if(options.location.v + h > r.bottom())
+ options.location.v -= (options.location.v + h) - r.bottom() + 10;
+ }
+ } else if(QWidget *p = qApp->mainWidget()) {
+ static int last_screen = -1;
+ int scr = QApplication::desktop()->screenNumber(p);
+ if(last_screen != scr) {
+ QRect r = QApplication::desktop()->screenGeometry(scr);
+ options.location.h = (r.x() + (r.width() / 2)) - (w / 2);
+ options.location.v = (r.y() + (r.height() / 2)) - (h / 2);
+ }
+ }
+
+ QList<qt_mac_filter_name*> filts = makeFiltersList(filter);
+ qt_mac_nav_filter_type t;
+ t.index = 0;
+ t.filts = &filts;
+ if(filts.count() > 1) {
+ int i = 0;
+ CFStringRef *arr = (CFStringRef *)malloc(sizeof(CFStringRef) * filts.count());
+ for (QList<qt_mac_filter_name*>::Iterator it = filts.begin(); it != filts.end(); ++it) {
+ QString rg = (*it)->description;
+ arr[i++] = CFStringCreateWithCharacters(NULL, (UniChar *)rg.unicode(), rg.length());
+ }
+ options.popupExtension = CFArrayCreate(NULL, (const void **)arr, filts.count(), NULL);
+ }
+
+ NavDialogRef dlg;
+ if(directory) {
+ if(NavCreateChooseFolderDialog(&options, make_navProcUPP(), NULL, NULL, &dlg)) {
+ qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
+ return retstrl;
+ }
+ } else {
+ if(NavCreateGetFileDialog(&options, NULL, make_navProcUPP(), NULL,
+ make_navFilterUPP(), (void *) (filts.isEmpty() ? NULL : &t),
+ &dlg)) {
+ qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
+ return retstrl;
+ }
+ }
+ if(pwd && !pwd->isEmpty()) {
+ FSRef fsref;
+ if(qt_mac_create_fsref(*pwd, &fsref) == noErr) {
+ AEDesc desc;
+ if(AECreateDesc(typeFSRef, &fsref, sizeof(FSRef), &desc) == noErr)
+ NavCustomControl(dlg, kNavCtlSetLocation, (void*)&desc);
+ }
+ }
+
+ NavDialogRun(dlg);
+ if (selectedFilter) {
+ NavMenuItemSpec navSpec;
+ bzero(&navSpec, sizeof(NavMenuItemSpec));
+ qt_mac_filter_name *sel_filt_name = makeFiltersList(*selectedFilter).at(0);
+ for (int i = 0; i < filts.count(); ++i) {
+ const qt_mac_filter_name *filter = filts.at(i);
+ if (sel_filt_name->description == filter->description
+ && sel_filt_name->regxp == filter->regxp
+ && sel_filt_name->filter == filter->filter) {
+ navSpec.menuType = i;
+ break;
+ }
+ }
+ NavCustomControl(dlg, kNavCtlSelectCustomType, &navSpec);
+ }
+ if(options.modality == kWindowModalityWindowModal) { //simulate modality
+ QWidget modal_widg(parent, __FILE__ "__modal_dlg",
+ Qt::WType_TopLevel | Qt::WStyle_Customize | Qt::WStyle_DialogBorder);
+ modal_widg.createWinId();
+ QApplicationPrivate::enterModal(&modal_widg);
+ while(g_nav_blocking)
+ qApp->processEvents(QEventLoop::WaitForMoreEvents);
+ QApplicationPrivate::leaveModal(&modal_widg);
+ }
+
+ if(!(NavDialogGetUserAction(dlg) &
+ (kNavUserActionOpen | kNavUserActionChoose | kNavUserActionNewFolder))) {
+ NavDialogDispose(dlg);
+ return retstrl;
+ }
+ NavReplyRecord ret;
+ NavDialogGetReply(dlg, &ret);
+ NavDialogDispose(dlg);
+
+ long count;
+ err = AECountItems(&(ret.selection), &count);
+ if(!ret.validRecord || err != noErr || !count) {
+ NavDisposeReply(&ret);
+ return retstrl;
+ }
+
+ for(long index = 1; index <= count; index++) {
+ FSRef ref;
+ err = AEGetNthPtr(&(ret.selection), index, typeFSRef, 0, 0, &ref, sizeof(ref), 0);
+ if(err != noErr)
+ break;
+
+ if(!str_buffer) {
+ qAddPostRoutine(cleanup_str_buffer);
+ str_buffer = (UInt8 *)malloc(1024);
+ }
+ FSRefMakePath(&ref, str_buffer, 1024);
+ retstrl.append(QString::fromUtf8((const char *)str_buffer));
+ }
+ NavDisposeReply(&ret);
+ if(selectedFilter)
+ *selectedFilter = filts.at(t.index)->filter;
+ while (!filts.isEmpty())
+ delete filts.takeFirst();
+ return retstrl;
+}
+
+// Copious copy and paste from qfiledialog.cpp. Fix in 4.0.
+static QString encodeFileName(const QString &fName)
+{
+ QString newStr;
+ QByteArray cName = fName.utf8();
+ const QByteArray sChars("<>#@\"&%$:,;?={}|^~[]\'`\\*");
+
+ 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;
+}
+
+QString Q3FileDialog::macGetSaveFileName(const QString &start, const QString &filter,
+ QString *, QWidget *parent, const char* /*name*/,
+ const QString& caption, QString *selectedFilter)
+{
+ OSErr err;
+ QString retstr;
+ NavDialogCreationOptions options;
+ NavGetDefaultDialogCreationOptions(&options);
+ static const int w = 450, h = 350;
+ options.optionFlags |= kNavDontConfirmReplacement;
+ options.modality = kWindowModalityAppModal;
+ options.location.h = options.location.v = -1;
+ QString workingDir;
+ QString initialSelection;
+ if (!start.isEmpty()) {
+ Q3UrlOperator u(encodeFileName(start));
+ if (u.isLocalFile() && QFileInfo(u.path()).isDir()) {
+ workingDir = start;
+ } else {
+ if (u.isLocalFile()) {
+ QFileInfo fi(u.dirPath());
+ if (fi.exists()) {
+ workingDir = u.dirPath();
+ initialSelection = u.fileName();
+ }
+ } else {
+ workingDir = u.toString();
+ }
+ }
+ if (!initialSelection.isEmpty())
+ options.saveFileName = CFStringCreateWithCharacters(0,
+ (UniChar *)initialSelection.unicode(),
+ initialSelection.length());
+ }
+ if(!caption.isEmpty())
+ options.windowTitle = CFStringCreateWithCharacters(NULL, (UniChar *)caption.unicode(),
+ caption.length());
+ if(parent && parent->isVisible()) {
+ Qt::WindowType wt = parent->window()->windowType();
+ if (wt != Qt::Desktop && wt != Qt::Sheet && wt != Qt::Drawer) {
+ options.modality = kWindowModalityWindowModal;
+ options.parentWindow = qt_mac_window_for(parent);
+ } else {
+ parent = parent->window();
+ QString s = parent->windowTitle();
+ options.clientName = CFStringCreateWithCharacters(NULL, (UniChar *)s.unicode(), s.length());
+ options.location.h = (parent->x() + (parent->width() / 2)) - (w / 2);
+ options.location.v = (parent->y() + (parent->height() / 2)) - (h / 2);
+
+ QRect r = QApplication::desktop()->screenGeometry(
+ QApplication::desktop()->screenNumber(parent));
+ if(options.location.h + w > r.right())
+ options.location.h -= (options.location.h + w) - r.right() + 10;
+ if(options.location.v + h > r.bottom())
+ options.location.v -= (options.location.v + h) - r.bottom() + 10;
+ }
+ } else if(QWidget *p = qApp->mainWidget()) {
+ static int last_screen = -1;
+ int scr = QApplication::desktop()->screenNumber(p);
+ if(last_screen != scr) {
+ QRect r = QApplication::desktop()->screenGeometry(scr);
+ options.location.h = (r.x() + (r.width() / 2)) - (w / 2);
+ options.location.v = (r.y() + (r.height() / 2)) - (h / 2);
+ }
+ }
+
+ QList<qt_mac_filter_name*> filts = makeFiltersList(filter);
+ qt_mac_nav_filter_type t;
+ t.index = 0;
+ t.filts = &filts;
+ if(filts.count() > 1) {
+ int i = 0;
+ CFStringRef *arr = (CFStringRef *)malloc(sizeof(CFStringRef) * filts.count());
+ for (QList<qt_mac_filter_name*>::Iterator it = filts.begin(); it != filts.end(); ++it) {
+ QString rg = (*it)->description;
+ arr[i++] = CFStringCreateWithCharacters(NULL, (UniChar *)rg.unicode(), rg.length());
+ }
+ options.popupExtension = CFArrayCreate(NULL, (const void **)arr, filts.count(), NULL);
+ }
+
+ NavDialogRef dlg;
+ if(NavCreatePutFileDialog(&options, 'cute', kNavGenericSignature, make_navProcUPP(),
+ (void *) (filts.isEmpty() ? NULL : &t), &dlg)) {
+ qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
+ return retstr;
+ }
+ if (!workingDir.isEmpty()) {
+ FSRef fsref;
+ if (qt_mac_create_fsref(workingDir, &fsref) == noErr) {
+ AEDesc desc;
+ if (AECreateDesc(typeFSRef, &fsref, sizeof(FSRef), &desc) == noErr)
+ NavCustomControl(dlg, kNavCtlSetLocation, (void*)&desc);
+ }
+ }
+ NavDialogRun(dlg);
+ if (selectedFilter) {
+ NavMenuItemSpec navSpec;
+ bzero(&navSpec, sizeof(NavMenuItemSpec));
+ qt_mac_filter_name *sel_filt_name = makeFiltersList(*selectedFilter).at(0);
+ for (int i = 0; i < filts.count(); ++i) {
+ const qt_mac_filter_name *filter = filts.at(i);
+ if (sel_filt_name->description == filter->description
+ && sel_filt_name->regxp == filter->regxp
+ && sel_filt_name->filter == filter->filter) {
+ navSpec.menuType = i;
+ break;
+ }
+ }
+ NavCustomControl(dlg, kNavCtlSelectCustomType, &navSpec);
+ }
+ if(options.modality == kWindowModalityWindowModal) { //simulate modality
+ QWidget modal_widg(parent, __FILE__ "__modal_dlg",
+ Qt::WType_TopLevel | Qt::WStyle_Customize | Qt::WStyle_DialogBorder);
+ modal_widg.createWinId();
+ QApplicationPrivate::enterModal(&modal_widg);
+ while(g_nav_blocking)
+ qApp->processEvents(QEventLoop::WaitForMoreEvents);
+ QApplicationPrivate::leaveModal(&modal_widg);
+ }
+
+ if(NavDialogGetUserAction(dlg) != kNavUserActionSaveAs) {
+ NavDialogDispose(dlg);
+ return retstr;
+ }
+ NavReplyRecord ret;
+ NavDialogGetReply(dlg, &ret);
+ NavDialogDispose(dlg);
+
+ long count;
+ err = AECountItems(&(ret.selection), &count);
+ if(!ret.validRecord || err != noErr || !count) {
+ NavDisposeReply(&ret);
+ return retstr;
+ }
+
+ AEKeyword keyword;
+ DescType type;
+ Size size;
+ FSRef ref;
+ err = AEGetNthPtr(&(ret.selection), 1, typeFSRef, &keyword,
+ &type, &ref, sizeof(ref), &size);
+ if(err == noErr) {
+ if(!str_buffer) {
+ qAddPostRoutine(cleanup_str_buffer);
+ str_buffer = (UInt8 *)malloc(1024);
+ }
+ FSRefMakePath(&ref, str_buffer, 1024);
+ retstr = QString::fromUtf8((const char *)str_buffer);
+ //now filename
+ CFStringGetCString(ret.saveFileName, (char *)str_buffer, 1024, kCFStringEncodingUTF8);
+ retstr += QLatin1String("/") + QString::fromUtf8((const char *)str_buffer);
+ }
+ NavDisposeReply(&ret);
+ if(selectedFilter)
+ *selectedFilter = filts.at(t.index)->filter;
+ while (!filts.isEmpty())
+ delete filts.takeFirst();
+ return retstr;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qt3support/dialogs/q3filedialog_win.cpp b/src/qt3support/dialogs/q3filedialog_win.cpp
new file mode 100644
index 0000000000..1be797a2d2
--- /dev/null
+++ b/src/qt3support/dialogs/q3filedialog_win.cpp
@@ -0,0 +1,749 @@
+/****************************************************************************
+**
+** 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 "q3filedialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+#include "qapplication.h"
+#include "private/qapplication_p.h"
+#include "qt_windows.h"
+#include "qregexp.h"
+#include "qbuffer.h"
+#include "qdir.h"
+#include "qstringlist.h"
+#include "qlibrary.h"
+
+#ifndef QT_NO_THREAD
+# include "private/qmutexpool_p.h"
+#endif
+
+#include <shlobj.h>
+
+#ifdef Q_OS_WINCE
+#include <commdlg.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// 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.
+typedef LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(BROWSEINFO*);
+static PtrSHBrowseForFolder ptrSHBrowseForFolder = 0;
+typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(LPITEMIDLIST,LPWSTR);
+static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 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"));
+ ptrSHBrowseForFolder = (PtrSHBrowseForFolder) lib.resolve("SHBrowseForFolderW");
+ ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList) lib.resolve("SHGetPathFromIDListW");
+ }
+ }
+#endif
+}
+#ifdef Q_OS_WINCE
+#define PtrSHBrowseForFolder SHBrowseForFolder ;
+#define PtrSHGetPathFromIDList SHGetPathFromIDList;
+#endif
+
+
+extern const char qt3_file_dialog_filter_reg_exp[]; // defined in qfiledialog.cpp
+
+const int maxNameLen = 1023;
+const int maxMultiLen = 65535;
+
+// Returns the wildcard part of a filter.
+static QString extractFilter(const QString& rawFilter)
+{
+ QString result = rawFilter;
+ QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+ int index = r.indexIn(result);
+ if (index >= 0)
+ result = r.cap(2);
+ return result.replace(QLatin1Char(' '), QLatin1Char(';'));
+}
+
+// Makes a list of filters from ;;-separated text.
+static QStringList makeFiltersList(const QString &filter)
+{
+ QString f(filter);
+
+ if (f.isEmpty())
+ f = Q3FileDialog::tr("All Files (*.*)");
+
+ if (f.isEmpty())
+ return QStringList();
+
+ int i = f.find(QLatin1String(";;"), 0);
+ QString sep(QLatin1String(";;"));
+ if (i == -1) {
+ if (f.find(QLatin1String("\n"), 0) != -1) {
+ sep = QLatin1String("\n");
+ i = f.find(sep, 0);
+ }
+ }
+
+ return QStringList::split(sep, f );
+}
+
+// Makes a NUL-oriented Windows filter from a Qt filter.
+static QString winFilter(const QString& filter)
+{
+ QStringList filterLst = makeFiltersList(filter);
+ QStringList::Iterator it = filterLst.begin();
+ QString winfilters;
+ for (; it != filterLst.end(); ++it) {
+ winfilters += *it;
+ winfilters += QChar::null;
+ winfilters += extractFilter(*it);
+ winfilters += QChar::null;
+ }
+ winfilters += QChar::null;
+ return winfilters;
+}
+
+static QString selFilter(const QString& filter, DWORD idx)
+{
+ QStringList filterLst = makeFiltersList(filter);
+ return filterLst[(int)idx - 1];
+}
+
+#ifndef Q_OS_WINCE
+// Static vars for OFNA funcs:
+static QByteArray aInitDir;
+static QByteArray aInitSel;
+static QByteArray aTitle;
+static QByteArray aFilter;
+// Use ANSI strings and API
+
+// If you change this, then make sure you change makeOFN (below) too
+static
+OPENFILENAMEA* makeOFNA(QWidget* parent,
+ const QString& initialSelection,
+ const QString& initialDirectory,
+ const QString& title,
+ const QString& filters,
+ Q3FileDialog::Mode mode)
+{
+ if (parent)
+ parent = parent->window();
+ else
+ parent = qApp->activeWindow();
+
+ aTitle = title.local8Bit();
+ aInitDir = QDir::toNativeSeparators(initialDirectory).local8Bit();
+ if (initialSelection.isEmpty())
+ aInitSel = "";
+ else
+ aInitSel = QDir::toNativeSeparators(initialSelection).local8Bit();
+ int maxLen = mode == Q3FileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
+ aInitSel.resize(maxLen + 1); // make room for return value
+ aFilter = filters.local8Bit();
+
+ OPENFILENAMEA* ofn = new OPENFILENAMEA;
+ memset(ofn, 0, sizeof(OPENFILENAMEA));
+
+#if defined(Q_CC_BOR) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0500)
+ // according to the MSDN, this should also be necessary for MSVC, but
+ // OPENFILENAME_SIZE_VERSION_400A is in not Microsoft header, as it seems
+ if (QApplication::winVersion()==Qt::WV_NT || QApplication::winVersion()&Qt::WV_DOS_based) {
+ ofn->lStructSize= OPENFILENAME_SIZE_VERSION_400A;
+ } else {
+ ofn->lStructSize= sizeof(OPENFILENAMEA);
+ }
+#else
+ ofn->lStructSize = sizeof(OPENFILENAMEA);
+#endif
+ ofn->hwndOwner = parent ? parent->winId() : 0;
+ ofn->lpstrFilter = aFilter;
+ ofn->lpstrFile = aInitSel.data();
+ ofn->nMaxFile = maxLen;
+ ofn->lpstrInitialDir = aInitDir.data();
+ ofn->lpstrTitle = aTitle.data();
+ ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY);
+
+ if (mode == Q3FileDialog::ExistingFile ||
+ mode == Q3FileDialog::ExistingFiles)
+ ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
+ if (mode == Q3FileDialog::ExistingFiles)
+ ofn->Flags |= (OFN_ALLOWMULTISELECT | OFN_EXPLORER);
+
+ return ofn;
+}
+
+static void cleanUpOFNA(OPENFILENAMEA** ofn)
+{
+ delete *ofn;
+ *ofn = 0;
+}
+#endif
+
+static QString tFilters, tTitle, tInitDir;
+
+#ifdef UNICODE
+// If you change this, then make sure you change makeOFNA (above) too
+static
+OPENFILENAME* makeOFN(QWidget* parent,
+ const QString& initialSelection,
+ const QString& initialDirectory,
+ const QString& title,
+ const QString& filters,
+ Q3FileDialog::Mode mode)
+{
+ if (parent)
+ parent = parent->window();
+ else
+ parent = qApp->activeWindow();
+
+ tInitDir = QDir::toNativeSeparators(initialDirectory);
+ tFilters = filters;
+ tTitle = title;
+ QString initSel = QDir::toNativeSeparators(initialSelection);
+
+ int maxLen = mode == Q3FileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
+ TCHAR *tInitSel = new TCHAR[maxLen+1];
+ if (initSel.length() > 0 && initSel.length() <= maxLen)
+ memcpy(tInitSel, initSel.ucs2(), (initSel.length()+1)*sizeof(QChar));
+ else
+ tInitSel[0] = 0;
+
+ OPENFILENAME* ofn = new OPENFILENAME;
+ memset(ofn, 0, sizeof(OPENFILENAME));
+
+#if defined(Q_CC_BOR) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0500)
+ // according to the MSDN, this should also be necessary for MSVC, but
+ // OPENFILENAME_SIZE_VERSION_400 is in not Microsoft header, as it seems
+ if (QApplication::winVersion()==Qt::WV_NT || QApplication::winVersion()&Qt::WV_DOS_based) {
+ ofn->lStructSize= OPENFILENAME_SIZE_VERSION_400;
+ } else {
+ ofn->lStructSize = sizeof(OPENFILENAME);
+ }
+#else
+ ofn->lStructSize = sizeof(OPENFILENAME);
+#endif
+ ofn->hwndOwner = parent ? parent->winId() : 0;
+ ofn->lpstrFilter = (TCHAR *)tFilters.ucs2();
+ ofn->lpstrFile = tInitSel;
+ ofn->nMaxFile = maxLen;
+ ofn->lpstrInitialDir = (TCHAR *)tInitDir.ucs2();
+ ofn->lpstrTitle = (TCHAR *)tTitle.ucs2();
+ ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY);
+
+ if (mode == Q3FileDialog::ExistingFile ||
+ mode == Q3FileDialog::ExistingFiles)
+ ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
+ if (mode == Q3FileDialog::ExistingFiles)
+ ofn->Flags |= (OFN_ALLOWMULTISELECT | OFN_EXPLORER);
+
+ return ofn;
+}
+
+
+static void cleanUpOFN(OPENFILENAME** ofn)
+{
+ delete (*ofn)->lpstrFile;
+ delete *ofn;
+ *ofn = 0;
+}
+
+#endif // UNICODE
+
+QString Q3FileDialog::winGetOpenFileName(const QString &initialSelection,
+ const QString &filter,
+ QString* initialDirectory,
+ QWidget *parent, const char* /*name*/,
+ const QString& caption,
+ QString* selectedFilter)
+{
+ QString result;
+
+ QString isel = initialSelection;
+
+ if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+ initialDirectory->remove(0, 5);
+ QFileInfo fi(*initialDirectory);
+
+ if (initialDirectory && !fi.isDir()) {
+ *initialDirectory = fi.dirPath(true);
+ if (isel.isEmpty())
+ isel = fi.fileName();
+ }
+
+ if (!fi.exists())
+ *initialDirectory = QDir::homeDirPath();
+
+ QString title = caption;
+ if (title.isNull())
+ title = tr("Open");
+
+ DWORD selFilIdx = 0;
+
+ int idx = 0;
+ if (selectedFilter && !selectedFilter->isEmpty()) {
+ QStringList filterLst = makeFiltersList(filter);
+ idx = filterLst.findIndex(*selectedFilter);
+ }
+
+ if (parent) {
+ QEvent e(QEvent::WindowBlocked);
+ QApplication::sendEvent(parent, &e);
+ QApplicationPrivate::enterModal(parent);
+ }
+ QT_WA({
+ // Use Unicode strings and API
+ OPENFILENAME* ofn = makeOFN(parent, isel,
+ *initialDirectory, title,
+ winFilter(filter), ExistingFile);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetOpenFileName(ofn)) {
+ result = QString::fromUcs2((ushort*)ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ }
+ cleanUpOFN(&ofn);
+ } , {
+ // Use ANSI strings and API
+ OPENFILENAMEA* ofn = makeOFNA(parent, isel,
+ *initialDirectory, title,
+ winFilter(filter), ExistingFile);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetOpenFileNameA(ofn)) {
+ result = QString::fromLocal8Bit(ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ }
+ cleanUpOFNA(&ofn);
+ });
+ if (parent) {
+ QApplicationPrivate::leaveModal(parent);
+ QEvent e(QEvent::WindowUnblocked);
+ QApplication::sendEvent(parent, &e);
+ }
+
+ if (result.isEmpty()) {
+ return result;
+ }
+ else {
+ QFileInfo fi(result);
+ *initialDirectory = fi.dirPath();
+ if (selectedFilter)
+ *selectedFilter = selFilter(filter, selFilIdx);
+ return fi.absFilePath();
+ }
+}
+
+
+QString Q3FileDialog::winGetSaveFileName(const QString &initialSelection,
+ const QString &filter,
+ QString* initialDirectory,
+ QWidget *parent, const char* /*name*/,
+ const QString& caption,
+ QString* selectedFilter)
+{
+ QString result;
+
+ QString isel = initialSelection;
+ if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+ initialDirectory->remove(0, 5);
+ QFileInfo fi(*initialDirectory);
+
+ if (initialDirectory && !fi.isDir()) {
+ *initialDirectory = fi.dirPath(true);
+ if (isel.isEmpty())
+ isel = fi.fileName();
+ }
+
+ if (!fi.exists())
+ *initialDirectory = QDir::homeDirPath();
+
+ QString title = caption;
+ if (title.isNull())
+ title = tr("Save As");
+
+ DWORD selFilIdx = 0;
+
+ int idx = 0;
+ if (selectedFilter && !selectedFilter->isEmpty()) {
+ QStringList filterLst = makeFiltersList(filter);
+ idx = filterLst.findIndex(*selectedFilter);
+ }
+
+ if (parent) {
+ QEvent e(QEvent::WindowBlocked);
+ QApplication::sendEvent(parent, &e);
+ QApplicationPrivate::enterModal(parent);
+ }
+ QT_WA({
+ // Use Unicode strings and API
+ OPENFILENAME* ofn = makeOFN(parent, isel,
+ *initialDirectory, title,
+ winFilter(filter), AnyFile);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetSaveFileName(ofn)) {
+ result = QString::fromUcs2((ushort*)ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ }
+ cleanUpOFN(&ofn);
+ } , {
+ // Use ANSI strings and API
+ OPENFILENAMEA* ofn = makeOFNA(parent, isel,
+ *initialDirectory, title,
+ winFilter(filter), AnyFile);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetSaveFileNameA(ofn)) {
+ result = QString::fromLocal8Bit(ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ }
+ cleanUpOFNA(&ofn);
+ });
+ if (parent) {
+ QApplicationPrivate::leaveModal(parent);
+ QEvent e(QEvent::WindowUnblocked);
+ QApplication::sendEvent(parent, &e);
+ }
+
+ if (result.isEmpty()) {
+ return result;
+ }
+ else {
+ QFileInfo fi(result);
+ *initialDirectory = fi.dirPath();
+ if (selectedFilter)
+ *selectedFilter = selFilter(filter, selFilIdx);
+ return fi.absFilePath();
+ }
+}
+
+
+
+QStringList Q3FileDialog::winGetOpenFileNames(const QString &filter,
+ QString* initialDirectory,
+ QWidget *parent,
+ const char* /*name*/,
+ const QString& caption,
+ QString* selectedFilter)
+{
+ QStringList result;
+ QFileInfo fi;
+ QDir dir;
+ QString isel;
+
+ if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+ initialDirectory->remove(0, 5);
+ fi = QFileInfo(*initialDirectory);
+
+ if (initialDirectory && !fi.isDir()) {
+ *initialDirectory = fi.dirPath(true);
+ isel = fi.fileName();
+ }
+
+ if (!fi.exists())
+ *initialDirectory = QDir::homeDirPath();
+
+ QString title = caption;
+ if (title.isNull())
+ title = tr("Open ");
+
+ DWORD selFilIdx = 0;
+
+ int idx = 0;
+ if (selectedFilter && !selectedFilter->isEmpty()) {
+ QStringList filterLst = makeFiltersList(filter);
+ idx = filterLst.findIndex(*selectedFilter);
+ }
+
+ if (parent) {
+ QEvent e(QEvent::WindowBlocked);
+ QApplication::sendEvent(parent, &e);
+ QApplicationPrivate::enterModal(parent);
+ }
+ QT_WA({
+ OPENFILENAME* ofn = makeOFN(parent, isel,
+ *initialDirectory, title,
+ winFilter(filter), ExistingFiles);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetOpenFileName(ofn)) {
+ QString fileOrDir = QString::fromUcs2((ushort*)ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ int offset = fileOrDir.length() + 1;
+ if (ofn->lpstrFile[offset] == 0) {
+ // Only one file selected; has full path
+ fi.setFile(fileOrDir);
+ QString res = fi.absFilePath();
+ if (!res.isEmpty())
+ result.append(res);
+ }
+ else {
+ // Several files selected; first string is path
+ dir.setPath(fileOrDir);
+ QString f;
+ while(!(f = QString::fromUcs2((ushort*)ofn->lpstrFile+offset)).isEmpty()) {
+ fi.setFile(dir, f);
+ QString res = fi.absFilePath();
+ if (!res.isEmpty())
+ result.append(res);
+ offset += f.length() + 1;
+ }
+ }
+ }
+ cleanUpOFN(&ofn);
+ } , {
+ OPENFILENAMEA* ofn = makeOFNA(parent, isel,
+ *initialDirectory, title,
+ winFilter(filter), ExistingFiles);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetOpenFileNameA(ofn)) {
+ QByteArray fileOrDir(ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ int offset = fileOrDir.length() + 1;
+ if (ofn->lpstrFile[offset] == '\0') {
+ // Only one file selected; has full path
+ fi.setFile(QString::fromLocal8Bit(fileOrDir));
+ QString res = fi.absFilePath();
+ if (!res.isEmpty())
+ result.append(res);
+ }
+ else {
+ // Several files selected; first string is path
+ dir.setPath(QString::fromLocal8Bit(fileOrDir));
+ QByteArray f;
+ while(!(f = QByteArray(ofn->lpstrFile + offset)).isEmpty()) {
+ fi.setFile(dir, QString::fromLocal8Bit(f));
+ QString res = fi.absFilePath();
+ if (!res.isEmpty())
+ result.append(res);
+ offset += f.length() + 1;
+ }
+ }
+ cleanUpOFNA(&ofn);
+ }
+ });
+ if (parent) {
+ QApplicationPrivate::leaveModal(parent);
+ QEvent e(QEvent::WindowUnblocked);
+ QApplication::sendEvent(parent, &e);
+ }
+
+ if (!result.isEmpty()) {
+ *initialDirectory = fi.dirPath(); // only save the path if there is a result
+ if (selectedFilter)
+ *selectedFilter = selFilter(filter, selFilIdx);
+ }
+ return result;
+}
+
+// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
+
+static int __stdcall winGetExistDirCallbackProc(HWND hwnd,
+ UINT uMsg,
+ LPARAM lParam,
+ LPARAM lpData)
+{
+#ifndef Q_OS_WINCE
+ if (uMsg == BFFM_INITIALIZED && lpData != 0) {
+ QString *initDir = (QString *)(lpData);
+ if (!initDir->isEmpty()) {
+ // ### Lars asks: is this correct for the A version????
+ QT_WA({
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, Q_ULONG(initDir->ucs2()));
+ } , {
+ SendMessageA(hwnd, BFFM_SETSELECTION, TRUE, Q_ULONG(initDir->ucs2()));
+ });
+ }
+ } else if (uMsg == BFFM_SELCHANGED) {
+ QT_WA({
+ resolveLibs();
+ TCHAR path[MAX_PATH];
+ ptrSHGetPathFromIDList(LPITEMIDLIST(lParam), path);
+ QString tmpStr = QString::fromUcs2((ushort*)path);
+ if (!tmpStr.isEmpty())
+ SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
+ else
+ SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, Q_ULONG(path));
+ } , {
+ char path[MAX_PATH];
+ SHGetPathFromIDListA(LPITEMIDLIST(lParam), path);
+ QString tmpStr = QString::fromLocal8Bit(path);
+ if (!tmpStr.isEmpty())
+ SendMessageA(hwnd, BFFM_ENABLEOK, 1, 1);
+ else
+ SendMessageA(hwnd, BFFM_ENABLEOK, 0, 0);
+ SendMessageA(hwnd, BFFM_SETSTATUSTEXT, 1, Q_ULONG(path));
+ });
+ }
+#endif
+ return 0;
+}
+
+#ifndef BIF_NEWDIALOGSTYLE
+#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
+#endif
+
+
+QString Q3FileDialog::winGetExistingDirectory(const QString& initialDirectory,
+ QWidget *parent,
+ const char* /*name*/,
+ const QString& caption)
+{
+#ifndef Q_OS_WINCE
+ QString currentDir = QDir::currentDirPath();
+ QString result;
+ if (parent)
+ parent = parent->window();
+ else
+ parent = qApp->activeWindow();
+ QString title = caption;
+ if (title.isNull())
+ title = tr("Select a Directory");
+
+ if (parent) {
+ QEvent e(QEvent::WindowBlocked);
+ QApplication::sendEvent(parent, &e);
+ QApplicationPrivate::enterModal(parent);
+ }
+ QT_WA({
+ resolveLibs();
+ QString initDir = QDir::toNativeSeparators(initialDirectory);
+ TCHAR path[MAX_PATH];
+ TCHAR initPath[MAX_PATH];
+ initPath[0] = 0;
+ path[0] = 0;
+ tTitle = title;
+ BROWSEINFO bi;
+ bi.hwndOwner = (parent ? parent->winId() : 0);
+ bi.pidlRoot = NULL;
+ bi.lpszTitle = (TCHAR*)tTitle.ucs2();
+ bi.pszDisplayName = initPath;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = winGetExistDirCallbackProc;
+ bi.lParam = Q_ULONG(&initDir);
+ LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
+ if (pItemIDList) {
+ ptrSHGetPathFromIDList(pItemIDList, path);
+ IMalloc *pMalloc;
+ if (SHGetMalloc(&pMalloc) != NOERROR)
+ result.clear();
+ else {
+ pMalloc->Free(pItemIDList);
+ pMalloc->Release();
+ result = QString::fromUcs2((ushort*)path);
+ }
+ } else
+ result.clear();
+ tTitle.clear();
+ } , {
+ QString initDir = QDir::toNativeSeparators(initialDirectory);
+ char path[MAX_PATH];
+ char initPath[MAX_PATH];
+ QByteArray ctitle = title.toLocal8Bit();
+ initPath[0]=0;
+ path[0]=0;
+ BROWSEINFOA bi;
+ bi.hwndOwner = (parent ? parent->winId() : 0);
+ bi.pidlRoot = NULL;
+ bi.lpszTitle = ctitle;
+ bi.pszDisplayName = initPath;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = winGetExistDirCallbackProc;
+ bi.lParam = Q_ULONG(&initDir);
+ LPITEMIDLIST pItemIDList = SHBrowseForFolderA(&bi);
+ if (pItemIDList) {
+ SHGetPathFromIDListA(pItemIDList, path);
+ IMalloc *pMalloc;
+ if (SHGetMalloc(&pMalloc) != NOERROR)
+ result.clear();
+ else {
+ pMalloc->Free(pItemIDList);
+ pMalloc->Release();
+ result = QString::fromLocal8Bit(path);
+ }
+ } else
+ result.clear();
+ });
+ if (parent) {
+ QApplicationPrivate::leaveModal(parent);
+ QEvent e(QEvent::WindowUnblocked);
+ QApplication::sendEvent(parent, &e);
+ }
+
+ // Due to a bug on Windows Me, we need to reset the current
+ // directory
+ if ((qWinVersion() == Qt::WV_98 || qWinVersion() == Qt::WV_Me) && QDir::currentDirPath() != currentDir)
+ QDir::setCurrent(currentDir);
+
+ if (!result.isEmpty())
+ result.replace(QLatin1String("\\"), QLatin1String("/"));
+ return result;
+#else
+ return QString();
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qt3support/dialogs/q3progressdialog.cpp b/src/qt3support/dialogs/q3progressdialog.cpp
new file mode 100644
index 0000000000..3c9ccfd115
--- /dev/null
+++ b/src/qt3support/dialogs/q3progressdialog.cpp
@@ -0,0 +1,850 @@
+/****************************************************************************
+**
+** 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 "q3progressdialog.h"
+
+#ifndef QT_NO_PROGRESSDIALOG
+
+#include "q3progressbar.h"
+#include "qapplication.h"
+#include "qcursor.h"
+#include "qdatetime.h"
+#include "qlabel.h"
+#include "qpainter.h"
+#include "qpushbutton.h"
+#include "qshortcut.h"
+#include "qstyle.h"
+#include "qtimer.h"
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+// If the operation is expected to take this long (as predicted by
+// progress time), show the progress dialog.
+static const int defaultShowTime = 4000;
+// Wait at least this long before attempting to make a prediction.
+static const int minWaitTime = 50;
+
+// Various layout values
+static const int margin_lr = 10;
+static const int margin_tb = 10;
+static const int spacing = 4;
+
+
+class Q3ProgressDialogData
+{
+public:
+ Q3ProgressDialogData(Q3ProgressDialog* that, QWidget* parent,
+ const QString& labelText,
+ int totalSteps) :
+ creator(parent),
+ label(new QLabel(labelText,that)),
+ cancel(0),
+ bar(new Q3ProgressBar(totalSteps, that)),
+ shown_once(false),
+ cancellation_flag(false),
+ showTime(defaultShowTime)
+ {
+ int align = that->style()->styleHint(QStyle::SH_ProgressDialog_TextLabelAlignment, 0, that);
+ label->setAlignment(Qt::Alignment(align));
+ }
+
+ QWidget *creator;
+ QLabel *label;
+ QPushButton *cancel;
+ Q3ProgressBar *bar;
+ bool shown_once;
+ bool cancellation_flag;
+ QTime starttime;
+#ifndef QT_NO_CURSOR
+ QCursor parentCursor;
+#endif
+ int showTime;
+ bool autoClose;
+ bool autoReset;
+ bool forceHide;
+};
+
+
+/*!
+ \class Q3ProgressDialog
+ \brief The Q3ProgressDialog class provides feedback on the progress of a slow operation.
+
+ \compat
+
+ A progress dialog is used to give the user an indication of how long
+ an operation is going to take, and to demonstrate that the
+ application has not frozen. It can also give the user an opportunity
+ to abort the operation.
+
+ A common problem with progress dialogs is that it is difficult to know
+ when to use them; operations take different amounts of time on different
+ hardware. Q3ProgressDialog offers a solution to this problem:
+ it estimates the time the operation will take (based on time for
+ steps), and only shows itself if that estimate is beyond minimumDuration()
+ (4 seconds by default).
+
+ Use setTotalSteps() (or the constructor) to set the number of
+ "steps" in the operation and call setProgress() as the operation
+ progresses. The step value can be chosen arbitrarily. It can be the
+ number of files copied, the number of bytes received, the number of
+ iterations through the main loop of your algorithm, or some other
+ suitable unit. Progress starts at 0, and the progress dialog shows
+ that the operation has finished when you call setProgress() with
+ totalSteps() as its argument.
+
+ The dialog automatically resets and hides itself at the end of the
+ operation. Use setAutoReset() and setAutoClose() to change this
+ behavior.
+
+ There are two ways of using Q3ProgressDialog: modal and modeless.
+
+ Using a modal Q3ProgressDialog is simpler for the programmer, but you
+ must call QApplication::processEvents() or
+ QEventLoop::processEvents(ExcludeUserInput) to keep the event loop
+ running to ensure that the application doesn't freeze. Do the
+ operation in a loop, call \l setProgress() at intervals, and check
+ for cancellation with wasCanceled(). For example:
+\snippet doc/src/snippets/code/src_qt3support_dialogs_q3progressdialog.cpp 0
+
+ A modeless progress dialog is suitable for operations that take
+ place in the background, where the user is able to interact with the
+ application. Such operations are typically based on QTimer (or
+ QObject::timerEvent()), QSocketNotifier, or QUrlOperator; or performed
+ in a separate thread. A Q3ProgressBar in the status bar of your main window
+ is often an alternative to a modeless progress dialog.
+
+ You need to have an event loop to be running, connect the
+ canceled() signal to a slot that stops the operation, and call \l
+ setProgress() at intervals. For example:
+\snippet doc/src/snippets/code/src_qt3support_dialogs_q3progressdialog.cpp 1
+
+
+ In both modes the progress dialog may be customized by
+ replacing the child widgets with custom widgets by using setLabel(),
+ setBar(), and setCancelButton().
+ The functions setLabelText() and setCancelButtonText()
+ set the texts shown.
+
+ \inlineimage qprogdlg-m.png Screenshot in Motif style
+ \inlineimage qprogdlg-w.png Screenshot in Windows style
+
+ \sa QDialog, Q3ProgressBar, {fowler}{GUI Design Handbook: Progress Indicator}
+*/
+
+
+/*!
+ Returns the QLabel currently being displayed above the progress bar.
+ This QLabel is owned by the Q3ProgressDialog.
+
+ \sa setLabel()
+*/
+QLabel *Q3ProgressDialog::label() const
+{
+ return d->label;
+}
+
+/*!
+ Returns the Q3ProgressBar currently being used to display progress.
+ This Q3ProgressBar is owned by the Q3ProgressDialog.
+
+ \sa setBar()
+*/
+Q3ProgressBar *Q3ProgressDialog::bar() const
+{
+ return d->bar;
+}
+
+
+/*!
+ Constructs a progress dialog.
+
+ Default settings:
+ \list
+ \i The label text is empty.
+ \i The cancel button text is (translated) "Cancel".
+ \i The total number of steps is 100.
+ \endlist
+
+ The \a creator argument is the widget to use as the dialog's parent.
+ The \a name, \a modal, and the widget flags, \a f, are
+ passed to the QDialog::QDialog() constructor. If \a modal is false (the
+ default), you must have an event loop proceeding for any redrawing
+ of the dialog to occur. If \a modal is true, the dialog ensures that
+ events are processed when needed.
+
+ \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
+ setTotalSteps()
+*/
+
+Q3ProgressDialog::Q3ProgressDialog(QWidget *creator, const char *name,
+ bool modal, Qt::WindowFlags f)
+ : QDialog(creator, f)
+{
+ setObjectName(QLatin1String(name));
+ setModal(modal);
+ init(creator, QString::fromLatin1(""), tr("Cancel"), 100);
+}
+
+/*!
+ Constructs a progress dialog.
+
+ The \a labelText is text used to remind the user what is progressing.
+
+ The \a cancelButtonText is the text to display on the cancel button,
+ or 0 if no cancel button is to be shown.
+
+ The \a totalSteps is the total number of steps in the operation for
+ which this progress dialog shows progress. For example, if the
+ operation is to examine 50 files, this value would be 50. Before
+ examining the first file, call setProgress(0). As each file is
+ processed call setProgress(1), setProgress(2), etc., finally
+ calling setProgress(50) after examining the last file.
+
+ The \a creator argument is the widget to use as the dialog's parent.
+ The \a name, \a modal, and widget flags, \a f, are passed to the
+ QDialog::QDialog() constructor. If \a modal is false (the default),
+ you will must have an event loop proceeding for any redrawing of
+ the dialog to occur. If \a modal is true, the dialog ensures that
+ events are processed when needed.
+
+
+ \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
+ setTotalSteps()
+*/
+
+Q3ProgressDialog::Q3ProgressDialog(const QString &labelText,
+ const QString &cancelButtonText,
+ int totalSteps,
+ QWidget *creator, const char *name,
+ bool modal, Qt::WindowFlags f)
+ : QDialog(creator, f)
+{
+ setObjectName(QLatin1String(name));
+ setModal(modal);
+ init(creator, labelText, cancelButtonText, totalSteps);
+}
+
+/*!
+ Constructs a progress dialog.
+
+ Default settings:
+ \list
+ \i The label text is empty.
+ \i The cancel button text is (translated) "Cancel".
+ \i The total number of steps is 100.
+ \endlist
+
+ The \a creator argument is the widget to use as the dialog's parent.
+ The widget flags, \a f, are passed to the QDialog::QDialog() constructor.
+
+ \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
+ setTotalSteps()
+*/
+Q3ProgressDialog::Q3ProgressDialog(QWidget *creator, Qt::WindowFlags f)
+ : QDialog(creator, f)
+{
+ init(creator, QString::fromLatin1(""), tr("Cancel"), 100);
+}
+
+/*!
+ Constructs a progress dialog.
+
+ The \a labelText is text used to remind the user what is progressing.
+
+ The \a cancelButtonText is the text to display on the cancel button,
+ or 0 if no cancel button is to be shown.
+
+ The \a totalSteps is the total number of steps in the operation for
+ which this progress dialog shows progress. For example, if the
+ operation is to examine 50 files, this value would be 50. Before
+ examining the first file, call setProgress(0). As each file is
+ processed call setProgress(1), setProgress(2), etc., finally
+ calling setProgress(50) after examining the last file.
+
+ The \a creator argument is the widget to use as the dialog's parent.
+ The widget flags, \a f, are passed to the
+ QDialog::QDialog() constructor.
+
+ \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
+ setTotalSteps()
+*/
+Q3ProgressDialog::Q3ProgressDialog(const QString &labelText,
+ const QString &cancelButtonText,
+ int totalSteps, QWidget *creator, Qt::WindowFlags f)
+ : QDialog(creator, f)
+{
+ init(creator, labelText, cancelButtonText, totalSteps);
+}
+
+/*!
+ Destroys the progress dialog.
+*/
+
+Q3ProgressDialog::~Q3ProgressDialog()
+{
+#ifndef QT_NO_CURSOR
+ if (d->creator)
+ d->creator->setCursor(d->parentCursor);
+#endif
+ delete d;
+}
+
+void Q3ProgressDialog::init(QWidget *creator,
+ const QString& lbl, const QString& canc,
+ int totstps)
+{
+ d = new Q3ProgressDialogData(this, creator, lbl, totstps);
+ d->autoClose = true;
+ d->autoReset = true;
+ d->forceHide = false;
+ setCancelButtonText(canc);
+ connect(this, SIGNAL(canceled()), this, SIGNAL(cancelled()));
+ connect(this, SIGNAL(canceled()), this, SLOT(cancel()));
+ forceTimer = new QTimer(this);
+ connect(forceTimer, SIGNAL(timeout()), this, SLOT(forceShow()));
+ layout();
+}
+
+/*!
+ \fn void Q3ProgressDialog::canceled()
+
+ This signal is emitted when the cancel button is clicked.
+ It is connected to the cancel() slot by default.
+
+ \sa wasCanceled()
+*/
+
+/*!
+ \fn void Q3ProgressDialog::cancelled()
+
+ Use canceled() instead.
+*/
+
+/*!
+ Sets the label to \a label. The progress dialog resizes to fit. The
+ label becomes owned by the progress dialog and will be deleted when
+ necessary, so do not pass the address of an object on the stack.
+
+ \sa setLabelText()
+*/
+
+void Q3ProgressDialog::setLabel(QLabel *label)
+{
+ delete d->label;
+ d->label = label;
+ if (label) {
+ if (label->parentWidget() == this) {
+ label->hide(); // until we resize
+ } else {
+ label->setParent(this, 0);
+ }
+ }
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ if (label)
+ label->show();
+}
+
+
+/*!
+ \property Q3ProgressDialog::labelText
+ \brief the label's text
+
+ The default text is an empty string.
+*/
+
+QString Q3ProgressDialog::labelText() const
+{
+ if (label())
+ return label()->text();
+ return QString();
+}
+
+void Q3ProgressDialog::setLabelText(const QString &text)
+{
+ if (label()) {
+ label()->setText(text);
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ }
+}
+
+
+/*!
+ Sets the cancel button to the push button, \a cancelButton. The
+ progress dialog takes ownership of this button which will be deleted
+ when necessary, so do not pass the address of an object that is on
+ the stack, i.e. use new() to create the button.
+
+ \sa setCancelButtonText()
+*/
+
+void Q3ProgressDialog::setCancelButton(QPushButton *cancelButton)
+{
+ delete d->cancel;
+ d->cancel = cancelButton;
+ if (cancelButton) {
+ if (cancelButton->parentWidget() == this) {
+ cancelButton->hide(); // until we resize
+ } else {
+ cancelButton->setParent(this, 0);
+ }
+ connect(d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled()));
+ new QShortcut(Qt::Key_Escape, this, SIGNAL(canceled()));
+ }
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ if (cancelButton)
+ cancelButton->show();
+}
+
+/*!
+ Sets the cancel button's text to \a cancelButtonText.
+ \sa setCancelButton()
+*/
+
+void Q3ProgressDialog::setCancelButtonText(const QString &cancelButtonText)
+{
+ if (!cancelButtonText.isNull()) {
+ if (d->cancel)
+ d->cancel->setText(cancelButtonText);
+ else
+ setCancelButton(new QPushButton(cancelButtonText, this));
+ } else {
+ setCancelButton(0);
+ }
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+}
+
+
+/*!
+ Sets the progress bar widget to \a bar. The progress dialog resizes to
+ fit. The progress dialog takes ownership of the progress \a bar which
+ will be deleted when necessary, so do not use a progress bar
+ allocated on the stack.
+*/
+
+void Q3ProgressDialog::setBar(Q3ProgressBar *bar)
+{
+#ifndef QT_NO_DEBUG
+ if (progress() > 0)
+ qWarning("Q3ProgressDialog::setBar: Cannot set a new progress bar "
+ "while the old one is active");
+#endif
+ delete d->bar;
+ d->bar = bar;
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+}
+
+
+/*!
+ \property Q3ProgressDialog::wasCanceled
+ \brief whether the dialog was canceled
+
+ \sa setProgress()
+*/
+
+bool Q3ProgressDialog::wasCanceled() const
+{
+ return d->cancellation_flag;
+}
+
+/*!
+ \property Q3ProgressDialog::wasCancelled
+ \brief whether the dialog was canceled
+ \since 4.2
+
+ Use \l wasCanceled instead.
+*/
+
+/*!
+ Use wasCanceled() instead.
+*/
+bool Q3ProgressDialog::wasCancelled() const
+{
+ return d->cancellation_flag;
+}
+
+/*!
+ \property Q3ProgressDialog::totalSteps
+ \brief the total number of steps
+
+ The default is 0.
+*/
+
+int Q3ProgressDialog::totalSteps() const
+{
+ if (d && d->bar)
+ return bar()->totalSteps();
+ return 0;
+}
+
+void Q3ProgressDialog::setTotalSteps(int totalSteps)
+{
+ bar()->setTotalSteps(totalSteps);
+}
+
+
+/*!
+ Resets the progress dialog.
+ The progress dialog becomes hidden if autoClose() is true.
+
+ \sa setAutoClose(), setAutoReset()
+*/
+
+void Q3ProgressDialog::reset()
+{
+#ifndef QT_NO_CURSOR
+ if (progress() >= 0) {
+ if (d->creator)
+ d->creator->setCursor(d->parentCursor);
+ }
+#endif
+ if (d->autoClose || d->forceHide)
+ hide();
+ bar()->reset();
+ d->cancellation_flag = false;
+ d->shown_once = false;
+ forceTimer->stop();
+}
+
+/*!
+ Resets the progress dialog. wasCanceled() becomes true until
+ the progress dialog is reset.
+ The progress dialog becomes hidden.
+*/
+
+void Q3ProgressDialog::cancel()
+{
+ d->forceHide = true;
+ reset();
+ d->forceHide = false;
+ d->cancellation_flag = true;
+}
+
+/*!
+ \property Q3ProgressDialog::progress
+ \brief the current amount of progress made.
+
+ For the progress dialog to work as expected, you should initially set
+ this property to 0 and finally set it to
+ Q3ProgressDialog::totalSteps(); you can call setProgress() any number of times
+ in-between.
+
+ \warning If the progress dialog is modal
+ (see Q3ProgressDialog::Q3ProgressDialog()),
+ this function calls QApplication::processEvents(), so take care that
+ this does not cause undesirable re-entrancy in your code. For example,
+ don't use a Q3ProgressDialog inside a paintEvent()!
+
+ \sa totalSteps
+*/
+
+int Q3ProgressDialog::progress() const
+{
+ return bar()->progress();
+}
+
+void Q3ProgressDialog::setProgress(int progress)
+{
+ if (progress == bar()->progress()
+ || (bar()->progress() == -1 && progress == bar()->totalSteps()))
+ return;
+
+ bar()->setProgress(progress);
+
+ if (d->shown_once) {
+ if (isModal())
+ qApp->processEvents();
+ } else {
+ if (progress == 0) {
+#ifndef QT_NO_CURSOR
+ if (d->creator) {
+ d->parentCursor = d->creator->cursor();
+ d->creator->setCursor(Qt::WaitCursor);
+ }
+#endif
+ d->starttime.start();
+ forceTimer->start(d->showTime);
+ return;
+ } else {
+ bool need_show;
+ int elapsed = d->starttime.elapsed();
+ if (elapsed >= d->showTime) {
+ need_show = true;
+ } else {
+ if (elapsed > minWaitTime) {
+ int estimate;
+ if ((totalSteps() - progress) >= INT_MAX / elapsed)
+ estimate = (totalSteps() - progress) / progress * elapsed;
+ else
+ estimate = elapsed * (totalSteps() - progress) / progress;
+ need_show = estimate >= d->showTime;
+ } else {
+ need_show = false;
+ }
+ }
+ if (need_show) {
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ show();
+ d->shown_once = true;
+ }
+ }
+#ifdef Q_WS_MAC
+ QApplication::flush();
+#endif
+ }
+
+ if (progress == bar()->totalSteps() && d->autoReset)
+ reset();
+}
+
+/*!
+ \overload
+
+ Sets the current amount of progress to \a progress and the total number of
+ steps to \a totalSteps.
+
+ \sa setTotalSteps()
+*/
+
+void Q3ProgressDialog::setProgress(int progress, int totalSteps)
+{
+ setTotalSteps(totalSteps);
+ setProgress(progress);
+}
+
+/*!
+ Returns a size that fits the contents of the progress dialog.
+ The progress dialog resizes itself as required, so you should not
+ need to call this yourself.
+*/
+
+QSize Q3ProgressDialog::sizeHint() const
+{
+ QSize sh = label()->sizeHint();
+ QSize bh = bar()->sizeHint();
+ int h = margin_tb*2 + bh.height() + sh.height() + spacing;
+ if (d->cancel)
+ h += d->cancel->sizeHint().height() + spacing;
+ return QSize(qMax(200, sh.width() + 2*margin_lr), h);
+}
+
+/*!\reimp
+*/
+void Q3ProgressDialog::resizeEvent(QResizeEvent *)
+{
+ layout();
+}
+
+/*!
+ \reimp
+*/
+void Q3ProgressDialog::changeEvent(QEvent *ev)
+{
+ if(ev->type() == QEvent::StyleChange)
+ layout();
+ QDialog::changeEvent(ev);
+}
+
+void Q3ProgressDialog::layout()
+{
+ int sp = spacing;
+ int mtb = margin_tb;
+ int mlr = qMin(width()/10, margin_lr);
+ const bool centered =
+ bool(style()->styleHint(QStyle::SH_ProgressDialog_CenterCancelButton, 0, this));
+
+ QSize cs = d->cancel ? d->cancel->sizeHint() : QSize(0,0);
+ QSize bh = bar()->sizeHint();
+ int cspc;
+ int lh = 0;
+
+ // Find spacing and sizes that fit. It is important that a progress
+ // dialog can be made very small if the user demands it so.
+ for (int attempt=5; attempt--;) {
+ cspc = d->cancel ? cs.height() + sp : 0;
+ lh = qMax(0, height() - mtb - bh.height() - sp - cspc);
+
+ if (lh < height()/4) {
+ // Getting cramped
+ sp /= 2;
+ mtb /= 2;
+ if (d->cancel) {
+ cs.setHeight(qMax(4,cs.height()-sp-2));
+ }
+ bh.setHeight(qMax(4,bh.height()-sp-1));
+ } else {
+ break;
+ }
+ }
+
+ if (d->cancel) {
+ d->cancel->setGeometry(
+ centered ? width()/2 - cs.width()/2 : width() - mlr - cs.width(),
+ height() - mtb - cs.height() + sp,
+ cs.width(), cs.height());
+ }
+
+ label()->setGeometry(mlr, 0, width()-mlr*2, lh);
+ bar()->setGeometry(mlr, lh+sp, width()-mlr*2, bh.height());
+}
+
+/*!
+ \property Q3ProgressDialog::minimumDuration
+ \brief the time that must pass before the dialog appears
+
+ If the expected duration of the task is less than the
+ minimumDuration, the dialog will not appear at all. This prevents
+ the dialog popping up for tasks that are quickly over. For tasks
+ that are expected to exceed the minimumDuration, the dialog will
+ pop up after the minimumDuration time or as soon as any progress
+ is set.
+
+ If set to 0, the dialog is always shown as soon as any progress is
+ set. The default is 4000 milliseconds.
+*/
+void Q3ProgressDialog::setMinimumDuration(int ms)
+{
+ d->showTime = ms;
+ if (bar()->progress() == 0) {
+ forceTimer->stop();
+ forceTimer->start(ms);
+ }
+}
+
+int Q3ProgressDialog::minimumDuration() const
+{
+ return d->showTime;
+}
+
+
+/*!
+ \reimp
+*/
+
+void Q3ProgressDialog::closeEvent(QCloseEvent *e)
+{
+ emit canceled();
+ QDialog::closeEvent(e);
+}
+
+/*!
+ \property Q3ProgressDialog::autoReset
+ \brief whether the progress dialog calls reset() as soon as progress() equals totalSteps()
+
+ The default is true.
+
+ \sa setAutoClose()
+*/
+
+void Q3ProgressDialog::setAutoReset(bool b)
+{
+ d->autoReset = b;
+}
+
+bool Q3ProgressDialog::autoReset() const
+{
+ return d->autoReset;
+}
+
+/*!
+ \property Q3ProgressDialog::autoClose
+ \brief whether the dialog gets hidden by reset()
+
+ The default is true.
+
+ \sa setAutoReset()
+*/
+
+void Q3ProgressDialog::setAutoClose(bool b)
+{
+ d->autoClose = b;
+}
+
+bool Q3ProgressDialog::autoClose() const
+{
+ return d->autoClose;
+}
+
+/*!
+ \reimp
+*/
+
+void Q3ProgressDialog::showEvent(QShowEvent *e)
+{
+ QDialog::showEvent(e);
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ forceTimer->stop();
+}
+
+/*!
+ Shows the dialog if it is still hidden after the algorithm has been started
+ and minimumDuration milliseconds have passed.
+
+ \sa setMinimumDuration()
+*/
+
+void Q3ProgressDialog::forceShow()
+{
+ if (d->shown_once || d->cancellation_flag)
+ return;
+
+ show();
+ d->shown_once = true;
+}
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qt3support/dialogs/q3progressdialog.h b/src/qt3support/dialogs/q3progressdialog.h
new file mode 100644
index 0000000000..4a4bc80882
--- /dev/null
+++ b/src/qt3support/dialogs/q3progressdialog.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef Q3PROGRESSDIALOG_H
+#define Q3PROGRESSDIALOG_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+#ifndef QT_NO_PROGRESSDIALOG
+
+class Q3ProgressDialogData;
+class QLabel;
+class QPushButton;
+class QTimer;
+class Q3ProgressBar;
+
+class Q_COMPAT_EXPORT Q3ProgressDialog : public QDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(bool wasCanceled READ wasCanceled)
+ Q_PROPERTY(bool wasCancelled READ wasCancelled DESIGNABLE false STORED false)
+ Q_PROPERTY(int totalSteps READ totalSteps WRITE setTotalSteps)
+ Q_PROPERTY(int progress READ progress WRITE setProgress)
+ Q_PROPERTY(bool autoReset READ autoReset WRITE setAutoReset)
+ Q_PROPERTY(bool autoClose READ autoClose WRITE setAutoClose)
+ Q_PROPERTY(int minimumDuration READ minimumDuration WRITE setMinimumDuration)
+ Q_PROPERTY(QString labelText READ labelText WRITE setLabelText)
+
+public:
+ Q3ProgressDialog(QWidget* parent, const char* name, bool modal=false,
+ Qt::WindowFlags f=0);
+ Q3ProgressDialog(const QString& labelText,
+ const QString &cancelButtonText, int totalSteps,
+ QWidget* parent=0, const char* name=0,
+ bool modal=false, Qt::WindowFlags f=0);
+ Q3ProgressDialog(QWidget* parent = 0, Qt::WindowFlags f = 0);
+ Q3ProgressDialog(const QString& labelText, const QString &cancelButtonText,
+ int totalSteps, QWidget* parent=0, Qt::WindowFlags f=0);
+ ~Q3ProgressDialog();
+
+ void setLabel(QLabel *);
+ void setCancelButton(QPushButton *);
+ void setBar(Q3ProgressBar *);
+
+ bool wasCanceled() const;
+ bool wasCancelled() const;
+
+ int totalSteps() const;
+ int progress() const;
+
+ QSize sizeHint() const;
+
+ QString labelText() const;
+
+ void setAutoReset(bool b);
+ bool autoReset() const;
+ void setAutoClose(bool b);
+ bool autoClose() const;
+
+public Q_SLOTS:
+ void cancel();
+ void reset();
+ void setTotalSteps(int totalSteps);
+ void setProgress(int progress);
+ void setProgress(int progress, int totalSteps);
+ void setLabelText(const QString &);
+ void setCancelButtonText(const QString &);
+
+ void setMinimumDuration(int ms);
+public:
+ int minimumDuration() const;
+
+Q_SIGNALS:
+ void canceled();
+ void cancelled();
+
+protected:
+ void resizeEvent(QResizeEvent *);
+ void closeEvent(QCloseEvent *);
+ void changeEvent(QEvent *);
+ void showEvent(QShowEvent *e);
+
+protected Q_SLOTS:
+ void forceShow();
+
+private:
+ void init(QWidget *creator, const QString& lbl, const QString &canc,
+ int totstps);
+ void layout();
+ QLabel *label() const;
+ Q3ProgressBar *bar() const;
+ Q3ProgressDialogData *d;
+ QTimer *forceTimer;
+
+private:
+ Q_DISABLE_COPY(Q3ProgressDialog)
+};
+
+#endif // QT_NO_PROGRESSDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3PROGRESSDIALOG_H
diff --git a/src/qt3support/dialogs/q3tabdialog.cpp b/src/qt3support/dialogs/q3tabdialog.cpp
new file mode 100644
index 0000000000..6242dcec80
--- /dev/null
+++ b/src/qt3support/dialogs/q3tabdialog.cpp
@@ -0,0 +1,1076 @@
+/****************************************************************************
+**
+** 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 "q3tabdialog.h"
+
+#include "qtabbar.h"
+#include "qtabwidget.h"
+#include "qpushbutton.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qapplication.h"
+#include "q3widgetstack.h"
+#include "qlayout.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt;
+
+/*!
+ \class Q3TabDialog
+ \compat
+ \brief The Q3TabDialog class provides a stack of tabbed widgets.
+
+ A tabbed dialog is one in which several "tab pages" are available.
+ By clicking on a tab page's tab or by pressing the indicated
+ Alt+\e{letter} key combination, the user can select which tab page
+ they want to use.
+
+ Q3TabDialog provides a tab bar consisting of single row of tabs at
+ the top; each tab has an associated widget which is that tab's
+ tab page. In addition, Q3TabDialog provides an OK button and the
+ following optional buttons: Apply, Cancel, Defaults and Help.
+
+ The normal way to use Q3TabDialog is to do the following in the
+ constructor:
+ \list 1
+ \i Create a Q3TabDialog.
+ \i Create a QWidget for each of the pages in the tab dialog, insert
+ children into it, set up geometry management for it, and use
+ addTab() (or insertTab()) to set up a tab and keyboard accelerator
+ for it.
+ \i Set up the buttons for the tab dialog using setOkButton(),
+ setApplyButton(), setDefaultsButton(), setCancelButton() and
+ setHelpButton().
+ \i Connect to the signals and slots.
+ \endlist
+
+ If you don't call addTab() the page you have created will not be
+ visible. Don't confuse the object name you supply to the
+ QWidget constructor and the tab label you supply to addTab();
+ addTab() takes user-visible name that appears on the widget's tab
+ and may identify an accelerator, whereas the widget name is used
+ primarily for debugging.
+
+ Almost all applications have to connect the applyButtonPressed()
+ signal to something. applyButtonPressed() is emitted when either OK
+ or Apply is clicked, and your slot must copy the dialog's state into
+ the application.
+
+ There are also several other signals which may be useful:
+ \list
+ \i cancelButtonPressed() is emitted when the user clicks Cancel.
+ \i defaultButtonPressed() is emitted when the user clicks Defaults;
+ the slot it is connected to should reset the state of the dialog to
+ the application defaults.
+ \i helpButtonPressed() is emitted when the user clicks Help.
+ \i aboutToShow() is emitted at the start of show(); if there is any
+ chance that the state of the application may change between the
+ creation of the tab dialog and the time show() is called, you must
+ connect this signal to a slot that resets the state of the dialog.
+ \i currentChanged() is emitted when the user selects a page.
+ \endlist
+
+ Each tab is either enabled or disabled at any given time (see
+ setTabEnabled()). If a tab is enabled the tab text is drawn in
+ black and the user can select that tab. If it is disabled the tab
+ is drawn in a different way and the user cannot select that tab.
+ Note that even if a tab is disabled, the page can still be visible;
+ for example, if all of the tabs happen to be disabled.
+
+ You can change a tab's label and iconset using changeTab(). A tab
+ page can be removed with removePage() and shown with showPage(). The
+ current page is given by currentPage().
+
+ Q3TabDialog does not support tabs on the sides or bottom, nor can
+ you set or retrieve the visible page. If you need more functionality
+ than Q3TabDialog provides, consider creating a QDialog and using a
+ QTabBar with QTabWidgets.
+
+ Most of the functionality in Q3TabDialog is provided by a QTabWidget.
+*/
+
+/*!
+ \fn void Q3TabDialog::selected(const QString &name)
+
+ This signal is emitted whenever a tab is selected (raised),
+ including during the first show(). \a name is the name of the
+ selected tab.
+
+ \sa raise()
+*/
+
+/*! \fn void Q3TabDialog::currentChanged(QWidget *widget)
+
+ This signal is emitted whenever the current page changes. \a widget
+ is the new current page.
+
+ \sa currentPage(), showPage(), tabLabel()
+*/
+
+class Q3TabDialogPrivate
+{
+public:
+ Q3TabDialogPrivate();
+
+ QTabWidget* tw;
+
+ QPushButton * ok;
+ QPushButton * cb;
+ QPushButton * db;
+ QPushButton * hb;
+ QPushButton * ab;
+
+ QBoxLayout * tll;
+};
+
+Q3TabDialogPrivate::Q3TabDialogPrivate()
+ : tw(0),
+ ok(0), cb(0), db(0), hb(0), ab(0),
+ tll(0)
+{ }
+
+/*!
+ Constructs a Q3TabDialog with only an OK button.
+ The \a parent, \a name, \a modal and widget flag, \a f, arguments
+ are passed on to the QDialog constructor.
+*/
+
+Q3TabDialog::Q3TabDialog(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f)
+ : QDialog(parent, name, modal, f)
+{
+ d = new Q3TabDialogPrivate;
+ Q_CHECK_PTR(d);
+
+ d->tw = new QTabWidget(this, "tab widget");
+ connect (d->tw, SIGNAL (selected(QString)), this, SIGNAL(selected(QString)));
+ connect (d->tw, SIGNAL (currentChanged(QWidget*)), this, SIGNAL(currentChanged(QWidget*)));
+
+ d->ok = new QPushButton(this, "ok");
+ Q_CHECK_PTR(d->ok);
+ d->ok->setText(tr("OK"));
+ d->ok->setDefault(true);
+ connect(d->ok, SIGNAL(clicked()),
+ this, SIGNAL(applyButtonPressed()));
+ connect(d->ok, SIGNAL(clicked()),
+ this, SLOT(accept()));
+}
+
+
+/*!
+ Destroys the tab dialog.
+*/
+
+Q3TabDialog::~Q3TabDialog()
+{
+ delete d;
+}
+
+
+/*!
+ Sets the font for the tabs to \a font.
+
+ If the widget is visible, the display is updated with the new font
+ immediately. There may be some geometry changes, depending on the
+ size of the old and new fonts.
+*/
+
+void Q3TabDialog::setFont(const QFont & font)
+{
+ QDialog::setFont(font);
+ setSizes();
+}
+
+
+/*!
+ \fn void Q3TabDialog::applyButtonPressed();
+
+ This signal is emitted when either the Apply or OK button is clicked.
+
+ It should be connected to a slot (or several slots) that change the
+ application's state according to the state of the dialog.
+
+ \sa cancelButtonPressed() defaultButtonPressed() setApplyButton()
+*/
+
+
+/*!
+ Returns true if the tab dialog has a Defaults button; otherwise
+ returns false.
+
+ \sa setDefaultButton() defaultButtonPressed() hasApplyButton()
+ hasCancelButton()
+*/
+
+bool Q3TabDialog::hasDefaultButton() const
+{
+ return d->db != 0;
+}
+
+
+/*!
+ Returns true if the tab dialog has a Help button; otherwise returns
+ false.
+
+ \sa setHelpButton() helpButtonPressed() hasApplyButton()
+ hasCancelButton()
+*/
+
+bool Q3TabDialog::hasHelpButton() const
+{
+ return d->hb != 0;
+}
+
+
+/*!
+ \fn void Q3TabDialog::cancelButtonPressed();
+
+ This signal is emitted when the Cancel button is clicked. It is
+ automatically connected to QDialog::reject(), which will hide the
+ dialog.
+
+ The Cancel button should not change the application's state at all,
+ so you should generally not need to connect it to any slot.
+
+ \sa applyButtonPressed() defaultButtonPressed() setCancelButton()
+*/
+
+
+/*!
+ Returns true if the tab dialog has a Cancel button; otherwise
+ returns false.
+
+ \sa setCancelButton() cancelButtonPressed() hasApplyButton()
+ hasDefaultButton()
+*/
+
+bool Q3TabDialog::hasCancelButton() const
+{
+ return d->cb != 0;
+}
+
+
+/*!
+ \fn void Q3TabDialog::defaultButtonPressed();
+
+ This signal is emitted when the Defaults button is pressed. It
+ should reset the dialog (but not the application) to the "factory
+ defaults".
+
+ The application's state should not be changed until the user clicks
+ Apply or OK.
+
+ \sa applyButtonPressed() cancelButtonPressed() setDefaultButton()
+*/
+
+
+/*!
+ \fn void Q3TabDialog::helpButtonPressed();
+
+ This signal is emitted when the Help button is pressed. It
+ could be used to present information about how to use the dialog.
+
+ \sa applyButtonPressed() cancelButtonPressed() setHelpButton()
+*/
+
+
+/*!
+ Returns true if the tab dialog has an Apply button; otherwise
+ returns false.
+
+ \sa setApplyButton() applyButtonPressed() hasCancelButton()
+ hasDefaultButton()
+*/
+
+bool Q3TabDialog::hasApplyButton() const
+{
+ return d->ab != 0;
+}
+
+
+/*!
+ Returns true if the tab dialog has an OK button; otherwise returns
+ false.
+
+ \sa setOkButton() hasApplyButton() hasCancelButton()
+ hasDefaultButton()
+*/
+
+bool Q3TabDialog::hasOkButton() const
+{
+ return d->ok != 0;
+}
+
+
+/*!
+ \fn void Q3TabDialog::aboutToShow()
+
+ This signal is emitted by show() when it is time to set the state of
+ the dialog's contents. The dialog should reflect the current state
+ of the application when it appears; if there is any possibility that
+ the state of the application may change between the time you call
+ Q3TabDialog() and show(), you should set the
+ dialog's state in a slot and connect this signal to it.
+
+ This applies mainly to Q3TabDialog objects that are kept around
+ hidden, rather than being created, shown, and deleted afterwards.
+
+ \sa applyButtonPressed(), QWidget::show(), cancelButtonPressed()
+*/
+
+
+/*!
+ \internal
+
+ Implemented to delay show()'ing of every page.
+*/
+void Q3TabDialog::show()
+{
+ // Reimplemented in order to delay show()'ing of every page
+ // except the initially visible one, and in order to emit the
+ // aboutToShow() signal.
+ if (window() == this)
+ d->tw->setFocus();
+ emit aboutToShow();
+ setSizes();
+ setUpLayout();
+ QDialog::show();
+}
+
+
+
+/*!
+ Adds another tab and page to the tab view.
+
+ The new page is \a child; the tab's label is \a label.
+ Note the difference between the widget name (which you supply to
+ widget constructors and to setTabEnabled(), for example) and the tab
+ label. The name is internal to the program and invariant, whereas
+ the label is shown on-screen and may vary according to language and
+ other factors.
+
+ If the tab's \a label contains an ampersand, the letter following
+ the ampersand is used as an accelerator for the tab, e.g. if the
+ label is "Bro&wse" then Alt+W becomes an accelerator which will
+ move the focus to this tab.
+
+ If you call addTab() after show() the screen will flicker and the
+ user may be confused.
+
+ \sa insertTab()
+*/
+
+void Q3TabDialog::addTab(QWidget * child, const QString &label)
+{
+ d->tw->addTab(child, label);
+}
+
+
+
+/*! \overload
+
+ This version of the function shows the \a iconset as well as the \a
+ label on the tab of \a child.
+*/
+void Q3TabDialog::addTab(QWidget *child, const QIcon& iconset, const QString &label)
+{
+ d->tw->addTab(child, iconset, label);
+}
+
+
+/*!
+ Inserts another tab and page to the tab view.
+
+ The new page is \a child; the tab's label is \a label.
+ Note the difference between the widget name (which you supply to
+ widget constructors and to setTabEnabled(), for example) and the tab
+ label. The name is internal to the program and invariant, whereas
+ the label is shown on-screen and may vary according to language and
+ other factors.
+
+ If the tab's \a label contains an ampersand, the letter following
+ the ampersand is used as an accelerator for the tab, e.g. if the
+ label is "Bro&wse" then Alt+W becomes an accelerator which will
+ move the focus to this tab.
+
+ If \a index is not specified, the tab is simply added. Otherwise
+ it is inserted at the specified position.
+
+ If you call insertTab() after show(), the screen will flicker and the
+ user may be confused.
+
+ \sa addTab()
+*/
+
+void Q3TabDialog::insertTab(QWidget * child, const QString &label, int index)
+{
+ d->tw->insertTab(child, label, index);
+}
+
+
+/*! \overload
+
+ This version of the function shows the \a iconset as well as the \a
+ label on the tab of \a child.
+ */
+void Q3TabDialog::insertTab(QWidget *child, const QIcon& iconset, const QString &label, int index)
+{
+ d->tw->insertTab(child, iconset, label, index);
+}
+
+/*!
+ Replaces the QTabBar heading the dialog by the given tab bar, \a tb.
+ Note that this must be called \e before any tabs have been added,
+ or the behavior is undefined.
+ \sa tabBar()
+*/
+void Q3TabDialog::setTabBar(QTabBar* tb)
+{
+ if (tb == 0){
+ qWarning("Q3TabDialog::setTabBar() called with null QTabBar pointer");
+ return;
+ }
+
+ d->tw->setTabBar(tb);
+ setUpLayout();
+}
+
+/*!
+ Returns the currently set QTabBar.
+ \sa setTabBar()
+*/
+QTabBar* Q3TabDialog::tabBar() const
+{
+ return d->tw->tabBar();
+}
+
+/*! Ensures that widget \a w is shown. This is mainly useful for accelerators.
+
+ \warning If used carelessly, this function can easily surprise or
+ confuse the user.
+
+ \sa QTabBar::setCurrentTab()
+*/
+
+void Q3TabDialog::showPage(QWidget * w)
+{
+ d->tw->showPage(w);
+}
+
+
+/*! \obsolete
+ Returns true if the page with object name \a name is enabled and
+ false if it is disabled.
+
+ If \a name is 0 or not the name of any of the pages, isTabEnabled()
+ returns false.
+
+ \sa setTabEnabled(), QWidget::isEnabled()
+*/
+
+bool Q3TabDialog::isTabEnabled(const char* name) const
+{
+ if (!name)
+ return false;
+ QObjectList l = this->queryList("QWidget", name, false, true);
+ if (!l.isEmpty()) {
+ for (int i = 0; i < l.size(); ++i) {
+ QObject *o = l.at(i);
+ if (!o->isWidgetType())
+ continue;
+ QWidget *w = static_cast<QWidget *>(o);
+ return d->tw->isTabEnabled(w);
+ }
+ }
+ return false;
+}
+
+
+/*!\obsolete
+
+ Finds the page with object name \a name, enables/disables it
+ according to the value of \a enable and redraws the page's tab
+ appropriately.
+
+ Q3TabDialog uses QWidget::setEnabled() internally, rather than keeping a
+ separate flag.
+
+ Note that even a disabled tab/page may be visible. If the page is
+ already visible Q3TabDialog will not hide it; if all the pages
+ are disabled Q3TabDialog will show one of them.
+
+ The object name is used (rather than the tab label) because the tab
+ text may not be invariant in multi-language applications.
+
+ \sa isTabEnabled(), QWidget::setEnabled()
+*/
+
+void Q3TabDialog::setTabEnabled(const char* name, bool enable)
+{
+ if (!name)
+ return;
+ QObjectList l = this->queryList("QWidget", name, false, true);
+ if (!l.isEmpty()) {
+ for (int i = 0; i < l.size(); ++i) {
+ QObject *o = l.at(i);
+ if(o->isWidgetType())
+ d->tw->setTabEnabled(static_cast<QWidget*>(o), enable);
+ }
+ }
+}
+
+
+/* ### SHOULD THIS BE HERE?
+ Adds an Apply button to the dialog. The button's text is set to \e
+ text (and defaults to "Apply").
+
+ The Apply button should apply the current settings in the dialog box
+ to the application, while keeping the dialog visible.
+
+ When Apply is clicked, the applyButtonPressed() signal is emitted.
+
+ If \a text is an empty string, no button is shown.
+
+ \sa setCancelButton() setDefaultButton() applyButtonPressed()
+*/
+
+
+/*!
+ Returns true if the page \a w is enabled; otherwise returns false.
+
+ \sa setTabEnabled(), QWidget::isEnabled()
+*/
+
+bool Q3TabDialog::isTabEnabled(QWidget* w) const
+{
+ return d->tw->isTabEnabled(w);
+}
+
+/*!
+ If \a enable is true the page \a w is enabled; otherwise \a w is
+ disabled. The page's tab is redrawn appropriately.
+
+ QTabWidget uses QWidget::setEnabled() internally, rather than keeping a
+ separate flag.
+
+ Note that even a disabled tab and tab page may be visible. If the
+ page is already visible QTabWidget will not hide it; if all the
+ pages are disabled QTabWidget will show one of them.
+
+ \sa isTabEnabled(), QWidget::setEnabled()
+*/
+
+void Q3TabDialog::setTabEnabled(QWidget* w, bool enable)
+{
+ d->tw->setTabEnabled(w, enable);
+}
+
+
+/*!
+ Adds an Apply button to the dialog. The button's text is set to \a
+ text.
+
+ The Apply button should apply the current settings in the dialog box
+ to the application while keeping the dialog visible.
+
+ When Apply is clicked, the applyButtonPressed() signal is emitted.
+
+ If \a text is an empty string, no button is shown.
+
+ \sa setCancelButton() setDefaultButton() applyButtonPressed()
+*/
+void Q3TabDialog::setApplyButton(const QString &text)
+{
+ if (text.isEmpty() && d->ab) {
+ delete d->ab;
+ d->ab = 0;
+ setSizes();
+ } else {
+ if (!d->ab) {
+ d->ab = new QPushButton(this, "apply settings");
+ connect(d->ab, SIGNAL(clicked()),
+ this, SIGNAL(applyButtonPressed()));
+ setUpLayout();
+ }
+ d->ab->setText(text);
+ setSizes();
+ //d->ab->show();
+ }
+}
+
+/*!
+ \overload
+
+ Adds an Apply button to the dialog. The button's text is set to
+ a localizable "Apply".
+ */
+void Q3TabDialog::setApplyButton()
+{
+ setApplyButton(tr("Apply"));
+}
+
+
+/*!
+ Adds a Help button to the dialog. The button's text is set to \a
+ text.
+
+ When Help is clicked, the helpButtonPressed() signal is emitted.
+
+ If \a text is an empty string, no button is shown.
+
+ \sa setApplyButton() setCancelButton() helpButtonPressed()
+*/
+
+void Q3TabDialog::setHelpButton(const QString &text)
+{
+ if (text.isEmpty()) {
+ delete d->hb;
+ d->hb = 0;
+ setSizes();
+ } else {
+ if (!d->hb) {
+ d->hb = new QPushButton(this, "give help");
+ connect(d->hb, SIGNAL(clicked()),
+ this, SIGNAL(helpButtonPressed()));
+ setUpLayout();
+ }
+ d->hb->setText(text);
+ setSizes();
+ //d->hb->show();
+ }
+}
+
+
+/*!
+ \overload
+
+ Adds a Help button to the dialog. The button's text is set to
+ a localizable "Help".
+ */
+void Q3TabDialog::setHelpButton()
+{
+ setHelpButton(tr("Help"));
+}
+
+/*!
+ Adds a Defaults button to the dialog. The button's text is set to \a
+ text.
+
+ The Defaults button should set the dialog (but not the application)
+ back to the application defaults.
+
+ When Defaults is clicked, the defaultButtonPressed() signal is emitted.
+
+ If \a text is an empty string, no button is shown.
+
+ \sa setApplyButton() setCancelButton() defaultButtonPressed()
+*/
+
+void Q3TabDialog::setDefaultButton(const QString &text)
+{
+ if (text.isEmpty()) {
+ delete d->db;
+ d->db = 0;
+ setSizes();
+ } else {
+ if (!d->db) {
+ d->db = new QPushButton(this, "back to default");
+ connect(d->db, SIGNAL(clicked()),
+ this, SIGNAL(defaultButtonPressed()));
+ setUpLayout();
+ }
+ d->db->setText(text);
+ setSizes();
+ //d->db->show();
+ }
+}
+
+
+/*!
+ \overload
+
+ Adds a Defaults button to the dialog. The button's text is set to
+ a localizable "Defaults".
+ */
+void Q3TabDialog::setDefaultButton()
+{
+ setDefaultButton(tr("Defaults"));
+}
+
+/*!
+ Adds a Cancel button to the dialog. The button's text is set to \a
+ text.
+
+ The cancel button should always return the application to the state
+ it was in before the tab view popped up, or if the user has clicked
+ Apply, back to the state immediately after the last Apply.
+
+ When Cancel is clicked, the cancelButtonPressed() signal is emitted.
+ The dialog is closed at the same time.
+
+ If \a text is an empty string, no button is shown.
+
+ \sa setApplyButton() setDefaultButton() cancelButtonPressed()
+*/
+
+void Q3TabDialog::setCancelButton(const QString &text)
+{
+ if (text.isEmpty()) {
+ delete d->cb;
+ d->cb = 0;
+ setSizes();
+ } else {
+ if (!d->cb) {
+ d->cb = new QPushButton(this, "cancel dialog");
+ connect(d->cb, SIGNAL(clicked()),
+ this, SIGNAL(cancelButtonPressed()));
+ connect(d->cb, SIGNAL(clicked()),
+ this, SLOT(reject()));
+ setUpLayout();
+ }
+ d->cb->setText(text);
+ setSizes();
+ //d->cb->show();
+ }
+}
+
+
+/*!
+ \overload
+
+ Adds a Cancel button to the dialog. The button's text is set to
+ a localizable "Cancel".
+ */
+
+void Q3TabDialog::setCancelButton()
+{
+ setCancelButton(tr("Cancel"));
+}
+
+/*! Sets up the layout manager for the tab dialog.
+
+ \sa setSizes() setApplyButton() setCancelButton() setDefaultButton()
+*/
+
+void Q3TabDialog::setUpLayout()
+{
+ // the next four are probably the same, really?
+ const int topMargin = 6;
+ const int leftMargin = 6;
+ const int rightMargin = 6;
+ const int bottomMargin = 6;
+ const int betweenButtonsMargin = 7;
+ const int aboveButtonsMargin = 8;
+
+ delete d->tll;
+ d->tll = new QBoxLayout(this, QBoxLayout::Down);
+
+ // top margin
+ d->tll->addSpacing(topMargin);
+
+ QBoxLayout * tmp = new QHBoxLayout();
+ d->tll->addLayout(tmp, 1);
+ tmp->addSpacing(leftMargin);
+ tmp->addWidget(d->tw, 1);
+ tmp->addSpacing(rightMargin + 2);
+
+ d->tll->addSpacing(aboveButtonsMargin + 2);
+ QBoxLayout * buttonRow = new QBoxLayout(QBoxLayout::RightToLeft);
+ d->tll->addLayout(buttonRow, 0);
+ d->tll->addSpacing(bottomMargin);
+
+ buttonRow->addSpacing(rightMargin);
+ if (d->cb) {
+ buttonRow->addWidget(d->cb, 0);
+ buttonRow->addSpacing(betweenButtonsMargin);
+ d->cb->raise();
+ }
+
+ if (d->ab) {
+ buttonRow->addWidget(d->ab, 0);
+ buttonRow->addSpacing(betweenButtonsMargin);
+ d->ab->raise();
+ }
+
+ if (d->db) {
+ buttonRow->addWidget(d->db, 0);
+ buttonRow->addSpacing(betweenButtonsMargin);
+ d->db->raise();
+ }
+
+ if (d->hb) {
+ buttonRow->addWidget(d->hb, 0);
+ buttonRow->addSpacing(betweenButtonsMargin);
+ d->hb->raise();
+ }
+
+ if (d->ok) {
+ buttonRow->addWidget(d->ok, 0);
+ buttonRow->addSpacing(betweenButtonsMargin);
+ d->ok->raise();
+ }
+
+ // add one custom widget here
+ buttonRow->addStretch(1);
+ // add another custom widget here
+
+ d->tll->activate();
+}
+
+
+/*! Sets up the minimum and maximum sizes for each child widget.
+
+ \sa setUpLayout() setFont()
+*/
+
+void Q3TabDialog::setSizes()
+{
+ // compute largest button size
+ QSize s(0, 0);
+ int bw = s.width();
+ int bh = s.height();
+
+ if (d->ok) {
+ s = d->ok->sizeHint();
+ if (s.width() > bw)
+ bw = s.width();
+ if (s.height() > bh)
+ bh = s.height();
+ }
+
+ if (d->ab) {
+ s = d->ab->sizeHint();
+ if (s.width() > bw)
+ bw = s.width();
+ if (s.height() > bh)
+ bh = s.height();
+ }
+
+ if (d->db) {
+ s = d->db->sizeHint();
+ if (s.width() > bw)
+ bw = s.width();
+ if (s.height() > bh)
+ bh = s.height();
+ }
+
+ if (d->hb) {
+ s = d->hb->sizeHint();
+ if (s.width() > bw)
+ bw = s.width();
+ if (s.height() > bh)
+ bh = s.height();
+ }
+
+ if (d->cb) {
+ s = d->cb->sizeHint();
+ if (s.width() > bw)
+ bw = s.width();
+ if (s.height() > bh)
+ bh = s.height();
+ }
+
+ // and set all the buttons to that size
+ if (d->ok)
+ d->ok->setFixedSize(bw, bh);
+ if (d->ab)
+ d->ab->setFixedSize(bw, bh);
+ if (d->db)
+ d->db->setFixedSize(bw, bh);
+ if (d->hb)
+ d->hb->setFixedSize(bw, bh);
+ if (d->cb)
+ d->cb->setFixedSize(bw, bh);
+
+ // fiddle the tab chain so the buttons are in their natural order
+ QWidget * w = d->ok;
+
+ if (d->hb) {
+ if (w)
+ setTabOrder(w, d->hb);
+ w = d->hb;
+ }
+ if (d->db) {
+ if (w)
+ setTabOrder(w, d->db);
+ w = d->db;
+ }
+ if (d->ab) {
+ if (w)
+ setTabOrder(w, d->ab);
+ w = d->ab;
+ }
+ if (d->cb) {
+ if (w)
+ setTabOrder(w, d->cb);
+ w = d->cb;
+ }
+ setTabOrder(w, d->tw);
+}
+
+/*!\reimp
+*/
+void Q3TabDialog::resizeEvent(QResizeEvent * e)
+{
+ QDialog::resizeEvent(e);
+}
+
+
+/*!\reimp
+*/
+void Q3TabDialog::paintEvent(QPaintEvent *)
+{
+}
+
+
+/*!
+ Adds an OK button to the dialog and sets the button's text to \a text.
+
+ When the OK button is clicked, the applyButtonPressed() signal is emitted,
+ and the current settings in the dialog box should be applied to
+ the application. The dialog then closes.
+
+ If \a text is an empty string, no button is shown.
+
+ \sa setCancelButton() setDefaultButton() applyButtonPressed()
+*/
+
+void Q3TabDialog::setOkButton(const QString &text)
+{
+ if (text.isEmpty()) {
+ delete d->ok;
+ d->ok = 0;
+ setSizes();
+ } else {
+ if (!d->ok) {
+ d->ok = new QPushButton(this, "ok");
+ connect(d->ok, SIGNAL(clicked()),
+ this, SIGNAL(applyButtonPressed()));
+ setUpLayout();
+ }
+ d->ok->setText(text);
+ setSizes();
+ //d->ok->show();
+ }
+}
+/*!
+ \overload
+
+ Adds an OK button to the dialog. The button's text is set to
+ a localizable "OK".
+ */
+
+void Q3TabDialog::setOkButton()
+{
+ setOkButton(tr("OK"));
+}
+
+
+/*
+ \overload
+ Old version of setOkButton(), provided for backward compatibility.
+*/
+void Q3TabDialog::setOKButton(const QString &text)
+{
+ // Ugly workaround for original "OK" default argument
+ QString newText(text);
+ if (text.isNull())
+ newText = QString::fromLatin1("OK");
+ setOkButton(newText);
+}
+
+
+/*! Returns the text in the tab for page \a w.
+*/
+
+QString Q3TabDialog::tabLabel(QWidget * w)
+{
+ return d->tw->tabLabel(w);
+}
+
+
+/*! \reimp
+*/
+void Q3TabDialog::styleChange(QStyle& s)
+{
+ QDialog::styleChange(s);
+ setSizes();
+}
+
+
+/*! Returns a pointer to the page currently being displayed by the
+tab dialog. The tab dialog does its best to make sure that this value
+is never 0 (but if you try hard enough, it can be).
+*/
+
+QWidget * Q3TabDialog::currentPage() const
+{
+ return d->tw->currentPage();
+}
+
+/*!
+ \overload
+ Defines a new \a label for the tab of page \a w
+ */
+void Q3TabDialog::changeTab(QWidget *w, const QString &label)
+{
+ d->tw->changeTab(w, label);
+}
+
+/*!
+ Changes tab page \a w's iconset to \a iconset and label to \a label.
+
+ */
+void Q3TabDialog::changeTab(QWidget *w, const QIcon& iconset, const QString &label)
+{
+ d->tw->changeTab(w, iconset, label);
+}
+
+/*! Removes page \a w from this stack of widgets. Does not
+ delete \a w.
+ \sa showPage(), QTabWidget::removePage()
+*/
+void Q3TabDialog::removePage(QWidget * w)
+{
+ d->tw->removePage(w);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/dialogs/q3tabdialog.h b/src/qt3support/dialogs/q3tabdialog.h
new file mode 100644
index 0000000000..3645df15ab
--- /dev/null
+++ b/src/qt3support/dialogs/q3tabdialog.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef Q3TABDIALOG_H
+#define Q3TABDIALOG_H
+
+#include <QtGui/qdialog.h>
+#include <QtGui/qicon.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class QTabBar;
+class QTab;
+class Q3TabDialogPrivate;
+
+class Q_COMPAT_EXPORT Q3TabDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ Q3TabDialog(QWidget* parent=0, const char* name=0, bool modal=false, Qt::WindowFlags f=0);
+ ~Q3TabDialog();
+
+ void show();
+ void setFont(const QFont & font);
+
+ void addTab(QWidget *, const QString &);
+ void addTab(QWidget *child, const QIcon& iconset, const QString &label);
+
+ void insertTab(QWidget *, const QString &, int index = -1);
+ void insertTab(QWidget *child, const QIcon& iconset, const QString &label, int index = -1);
+
+ void changeTab(QWidget *, const QString &);
+ void changeTab(QWidget *child, const QIcon& iconset, const QString &label);
+
+ bool isTabEnabled( QWidget *) const;
+ void setTabEnabled(QWidget *, bool);
+ bool isTabEnabled(const char*) const; // compatibility
+ void setTabEnabled(const char*, bool); // compatibility
+
+ void showPage(QWidget *);
+ void removePage(QWidget *);
+ QString tabLabel(QWidget *);
+
+ QWidget * currentPage() const;
+
+ void setDefaultButton(const QString &text);
+ void setDefaultButton();
+ bool hasDefaultButton() const;
+
+ void setHelpButton(const QString &text);
+ void setHelpButton();
+ bool hasHelpButton() const;
+
+ void setCancelButton(const QString &text);
+ void setCancelButton();
+ bool hasCancelButton() const;
+
+ void setApplyButton(const QString &text);
+ void setApplyButton();
+ bool hasApplyButton() const;
+
+#ifndef qdoc
+ void setOKButton(const QString &text = QString());
+#endif
+ void setOkButton(const QString &text);
+ void setOkButton();
+ bool hasOkButton() const;
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+ void styleChange(QStyle&);
+ void setTabBar(QTabBar*);
+ QTabBar* tabBar() const;
+
+Q_SIGNALS:
+ void aboutToShow();
+
+ void applyButtonPressed();
+ void cancelButtonPressed();
+ void defaultButtonPressed();
+ void helpButtonPressed();
+
+ void currentChanged(QWidget *);
+ void selected(const QString&); // obsolete
+
+private:
+ void setSizes();
+ void setUpLayout();
+
+ Q3TabDialogPrivate *d;
+
+ Q_DISABLE_COPY(Q3TabDialog)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3TABDIALOG_H
diff --git a/src/qt3support/dialogs/q3wizard.cpp b/src/qt3support/dialogs/q3wizard.cpp
new file mode 100644
index 0000000000..7a4af4702c
--- /dev/null
+++ b/src/qt3support/dialogs/q3wizard.cpp
@@ -0,0 +1,906 @@
+/****************************************************************************
+**
+** 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 "q3wizard.h"
+
+#include "qlayout.h"
+#include "qpushbutton.h"
+#include "qcursor.h"
+#include "qlabel.h"
+#include "qapplication.h"
+#include "qlist.h"
+#include "qpainter.h"
+#include "q3accel.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt;
+
+/*!
+ \class Q3Wizard
+ \compat
+ \brief The Q3Wizard class provides a framework for wizard dialogs.
+
+ A wizard is a special type of input dialog that consists of a
+ sequence of dialog pages. A wizard's purpose is to walk the user
+ through a process step by step. Wizards are useful for complex or
+ infrequently occurring tasks that people may find difficult to
+ learn or do.
+
+ Q3Wizard provides page titles and displays Next, Back, Finish,
+ Cancel, and Help push buttons, as appropriate to the current
+ position in the page sequence. These buttons can be
+ enabled/disabled using setBackEnabled(), setNextEnabled(),
+ setFinishEnabled() and setHelpEnabled().
+
+ Create and populate dialog pages that inherit from QWidget and add
+ them to the wizard using addPage(). Use insertPage() to add a
+ dialog page at a certain position in the page sequence. Use
+ removePage() to remove a page from the page sequence.
+
+ Use currentPage() to retrieve a pointer to the currently displayed
+ page. page() returns a pointer to the page at a certain position
+ in the page sequence.
+
+ Use pageCount() to retrieve the total number of pages in the page
+ sequence. indexOf() will return the index of a page in the page
+ sequence.
+
+ Q3Wizard provides functionality to mark pages as appropriate (or
+ not) in the current context with setAppropriate(). The idea is
+ that a page may be irrelevant and should be skipped depending on
+ the data entered by the user on a preceding page.
+
+ It is generally considered good design to provide a greater number
+ of simple pages with fewer choices rather than a smaller number of
+ complex pages.
+*/
+
+
+class Q3WizardPrivate
+{
+public:
+
+ virtual ~Q3WizardPrivate()
+ {
+ foreach(Page *page, pages)
+ delete page;
+ }
+
+ struct Page {
+ Page( QWidget * widget, const QString & title ):
+ w( widget ), t( title ),
+ backEnabled( true ), nextEnabled( true ), finishEnabled( false ),
+ helpEnabled( true ),
+ appropriate( true )
+ {}
+ QWidget * w;
+ QString t;
+ bool backEnabled;
+ bool nextEnabled;
+ bool finishEnabled;
+ bool helpEnabled;
+ bool appropriate;
+ };
+
+ QVBoxLayout * v;
+ Page * current;
+ QList<Page *> pages;
+ QLabel * title;
+ QPushButton * backButton;
+ QPushButton * nextButton;
+ QPushButton * finishButton;
+ QPushButton * cancelButton;
+ QPushButton * helpButton;
+
+ QFrame * hbar1, * hbar2;
+
+#ifndef QT_NO_ACCEL
+ Q3Accel * accel;
+ int backAccel;
+ int nextAccel;
+#endif
+
+ Page * page( const QWidget * w )
+ {
+ if ( !w )
+ return 0;
+ int i = pages.count();
+ while( --i >= 0 && pages.at( i ) && pages.at( i )->w != w ) { }
+ return i >= 0 ? pages.at( i ) : 0;
+ }
+
+};
+
+
+/*!
+ Constructs an empty wizard dialog. The \a parent, \a name, \a
+ modal and \a f arguments are passed to the QDialog constructor.
+*/
+
+Q3Wizard::Q3Wizard(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f )
+ : QDialog( parent, name, modal, f )
+{
+ d = new Q3WizardPrivate();
+ d->current = 0; // not quite true, but...
+ d->title = new QLabel( this, "title label" );
+
+ // create in nice tab order
+ d->nextButton = new QPushButton( this, "next" );
+ d->finishButton = new QPushButton( this, "finish" );
+ d->helpButton = new QPushButton( this, "help" );
+ d->backButton = new QPushButton( this, "back" );
+ d->cancelButton = new QPushButton( this, "cancel" );
+
+ d->v = 0;
+ d->hbar1 = 0;
+ d->hbar2 = 0;
+
+ d->cancelButton->setText( tr( "&Cancel" ) );
+ d->backButton->setText( tr( "< &Back" ) );
+ d->nextButton->setText( tr( "&Next >" ) );
+ d->finishButton->setText( tr( "&Finish" ) );
+ d->helpButton->setText( tr( "&Help" ) );
+
+ d->nextButton->setDefault( true );
+
+ connect( d->backButton, SIGNAL(clicked()),
+ this, SLOT(back()) );
+ connect( d->nextButton, SIGNAL(clicked()),
+ this, SLOT(next()) );
+ connect( d->finishButton, SIGNAL(clicked()),
+ this, SLOT(accept()) );
+ connect( d->cancelButton, SIGNAL(clicked()),
+ this, SLOT(reject()) );
+ connect( d->helpButton, SIGNAL(clicked()),
+ this, SLOT(help()) );
+
+#ifndef QT_NO_ACCEL
+ d->accel = new Q3Accel( this, "arrow-key accel" );
+ d->backAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Left );
+ d->accel->connectItem( d->backAccel, this, SLOT(back()) );
+ d->nextAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Right );
+ d->accel->connectItem( d->nextAccel, this, SLOT(next()) );
+#endif
+}
+
+
+/*!
+ Destroys the object and frees any allocated resources, including
+ all pages and controllers.
+*/
+
+Q3Wizard::~Q3Wizard()
+{
+ delete d;
+}
+
+
+/*!
+ \internal
+*/
+
+void Q3Wizard::setVisible(bool show)
+{
+ if ( show && !d->current ) {
+ // No page yet
+ if ( pageCount() > 0 )
+ showPage( d->pages.at( 0 )->w );
+ else
+ showPage( 0 );
+ }
+
+ QDialog::setVisible(show);
+}
+
+
+/*!
+ \internal
+*/
+
+void Q3Wizard::setFont( const QFont & font )
+{
+ QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
+ QDialog::setFont( font );
+}
+
+/*!
+ Adds \a page to the end of the page sequence, with the title, \a
+ title.
+*/
+
+void Q3Wizard::addPage( QWidget * page, const QString & title )
+{
+ if ( !page )
+ return;
+ if ( d->page( page ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "Q3Wizard::addPage(): already added %s/%s to %s/%s",
+ page->className(), page->name(),
+ className(), name() );
+#endif
+ return;
+ }
+ int i = d->pages.count();
+
+ if( i > 0 )
+ d->pages.at( i - 1 )->nextEnabled = true;
+
+ Q3WizardPrivate::Page * p = new Q3WizardPrivate::Page( page, title );
+ p->backEnabled = ( i > 0 );
+ d->pages.append( p );
+}
+
+/*!
+ Inserts \a page at position \a index into the page sequence, with
+ title \a title. If \a index is -1, the page will be appended to
+ the end of the wizard's page sequence.
+*/
+
+void Q3Wizard::insertPage( QWidget * page, const QString & title, int index )
+{
+ if ( !page )
+ return;
+ if ( d->page( page ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "Q3Wizard::insertPage(): already added %s/%s to %s/%s",
+ page->className(), page->name(),
+ className(), name() );
+#endif
+ return;
+ }
+
+ if ( index < 0 || index > (int)d->pages.count() )
+ index = d->pages.count();
+
+ if( index > 0 && ( index == (int)d->pages.count() ) )
+ d->pages.at( index - 1 )->nextEnabled = true;
+
+ Q3WizardPrivate::Page * p = new Q3WizardPrivate::Page( page, title );
+ p->backEnabled = ( index > 0 );
+ p->nextEnabled = ( index < (int)d->pages.count() );
+
+ d->pages.insert( index, p );
+}
+
+/*!
+ \fn void Q3Wizard::selected(const QString &title)
+
+ This signal is emitted when the current page changes. The
+ \a title parameter contains the title of the selected page.
+*/
+
+
+/*!
+ Makes \a page the current page and emits the selected() signal.
+
+ This virtual function is called whenever a different page is to
+ be shown, including the first time the Q3Wizard is shown.
+ By reimplementing it (and calling Q3Wizard::showPage()),
+ you can prepare each page prior to it being shown.
+*/
+
+void Q3Wizard::showPage( QWidget * page )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( p ) {
+ int i;
+ for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != p; i++ ) {}
+ bool notFirst( false );
+
+ if( i ) {
+ i--;
+ while( ( i >= 0 ) && !notFirst ) {
+ notFirst |= appropriate( d->pages.at( i )->w );
+ i--;
+ }
+ }
+ setBackEnabled( notFirst );
+ setNextEnabled( true );
+
+ page->show();
+ foreach(Q3WizardPrivate::Page *ppage, d->pages) {
+ if (ppage->w != page)
+ ppage->w->hide();
+ }
+
+ d->current = p;
+ }
+
+ layOut();
+ updateButtons();
+ emit selected( p ? p->t : QString() );
+}
+
+
+/*!
+ Returns the number of pages in the wizard.
+*/
+
+int Q3Wizard::pageCount() const
+{
+ return d->pages.count();
+}
+
+/*!
+ Returns the position of page \a page. If the page is not part of
+ the wizard -1 is returned.
+*/
+
+int Q3Wizard::indexOf( QWidget* page ) const
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( !p ) return -1;
+
+ return d->pages.indexOf( p );
+}
+
+/*!
+ Called when the user clicks the Back button; this function shows
+ the preceding relevant page in the sequence.
+
+ \sa appropriate()
+*/
+void Q3Wizard::back()
+{
+ int i = 0;
+
+ while( i < (int)d->pages.count() && d->pages.at( i ) &&
+ d->current && d->pages.at( i )->w != d->current->w )
+ i++;
+
+ i--;
+ while( i >= 0 && ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
+ i--;
+
+ if( i >= 0 )
+ if( d->pages.at( i ) )
+ showPage( d->pages.at( i )->w );
+}
+
+
+/*!
+ Called when the user clicks the Next button, this function shows
+ the next relevant page in the sequence.
+
+ \sa appropriate()
+*/
+void Q3Wizard::next()
+{
+ int i = 0;
+ while( i < (int)d->pages.count() && d->pages.at( i ) &&
+ d->current && d->pages.at( i )->w != d->current->w )
+ i++;
+ i++;
+ while( i <= (int)d->pages.count()-1 &&
+ ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
+ i++;
+ // if we fell of the end of the world, step back
+ while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) )
+ i--;
+ if ( d->pages.at( i ) )
+ showPage( d->pages.at( i )->w );
+}
+
+
+/*!
+ \fn void Q3Wizard::helpClicked()
+
+ This signal is emitted when the user clicks on the Help button.
+*/
+
+/*!
+ Called when the user clicks the Help button, this function emits
+ the helpClicked() signal.
+*/
+
+void Q3Wizard::help()
+{
+ QWidget *page = d->current ? d->current->w : 0;
+ if ( !page )
+ return;
+
+#if 0
+ Q3WizardPage *wpage = qobject_cast<Q3WizardPage*>(page);
+ if ( wpage )
+ emit wpage->helpClicked();
+#endif
+ emit helpClicked();
+}
+
+
+void Q3Wizard::setBackEnabled( bool enable )
+{
+ d->backButton->setEnabled( enable );
+#ifndef QT_NO_ACCEL
+ d->accel->setItemEnabled( d->backAccel, enable );
+#endif
+}
+
+
+void Q3Wizard::setNextEnabled( bool enable )
+{
+ d->nextButton->setEnabled( enable );
+#ifndef QT_NO_ACCEL
+ d->accel->setItemEnabled( d->nextAccel, enable );
+#endif
+}
+
+
+void Q3Wizard::setHelpEnabled( bool enable )
+{
+ d->helpButton->setEnabled( enable );
+}
+
+
+/*!
+ \fn void Q3Wizard::setFinish(QWidget *widget, bool finish)
+ \obsolete
+
+ Use setFinishEnabled() instead.
+*/
+
+/*!
+ If \a enable is true, page \a page has a Back button; otherwise \a
+ page has no Back button. By default all pages have this button.
+*/
+void Q3Wizard::setBackEnabled( QWidget * page, bool enable )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( !p )
+ return;
+
+ p->backEnabled = enable;
+ updateButtons();
+}
+
+
+/*!
+ If \a enable is true, page \a page has a Next button; otherwise
+ the Next button on \a page is disabled. By default all pages have
+ this button.
+*/
+
+void Q3Wizard::setNextEnabled( QWidget * page, bool enable )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( !p )
+ return;
+
+ p->nextEnabled = enable;
+ updateButtons();
+}
+
+
+/*!
+ If \a enable is true, page \a page has a Finish button; otherwise
+ \a page has no Finish button. By default \e no page has this
+ button.
+*/
+void Q3Wizard::setFinishEnabled( QWidget * page, bool enable )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( !p )
+ return;
+
+ p->finishEnabled = enable;
+ updateButtons();
+}
+
+
+/*!
+ If \a enable is true, page \a page has a Help button; otherwise \a
+ page has no Help button. By default all pages have this button.
+*/
+void Q3Wizard::setHelpEnabled( QWidget * page, bool enable )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( !p )
+ return;
+
+ p->helpEnabled = enable;
+ updateButtons();
+}
+
+
+/*!
+ Called when the Next button is clicked; this virtual function
+ returns true if \a page is relevant for display in the current
+ context; otherwise it is ignored by Q3Wizard and returns false. The
+ default implementation returns the value set using
+ setAppropriate(). The ultimate default is true.
+
+ \warning The last page of the wizard will be displayed if no page
+ is relevant in the current context.
+*/
+
+bool Q3Wizard::appropriate( QWidget * page ) const
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ return p ? p->appropriate : true;
+}
+
+
+/*!
+ If \a appropriate is true then page \a page is considered relevant
+ in the current context and should be displayed in the page
+ sequence; otherwise \a page should not be displayed in the page
+ sequence.
+
+ \sa appropriate()
+*/
+void Q3Wizard::setAppropriate( QWidget * page, bool appropriate )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( p )
+ p->appropriate = appropriate;
+}
+
+
+void Q3Wizard::updateButtons()
+{
+ if ( !d->current )
+ return;
+
+ int i;
+ for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != d->current; i++ ) {}
+ bool notFirst( false );
+ if( i ) {
+ i--;
+ while( ( i >= 0 ) && !notFirst ) {
+ notFirst |= appropriate( d->pages.at( i )->w );
+ i--;
+ }
+ }
+ setBackEnabled( d->current->backEnabled && notFirst );
+ setNextEnabled( d->current->nextEnabled );
+ d->finishButton->setEnabled( d->current->finishEnabled );
+ d->helpButton->setEnabled( d->current->helpEnabled );
+
+ if ( ( d->current->finishEnabled && !d->finishButton->isVisible() ) ||
+ ( d->current->backEnabled && !d->backButton->isVisible() ) ||
+ ( d->current->nextEnabled && !d->nextButton->isVisible() ) ||
+ ( d->current->helpEnabled && !d->helpButton->isVisible() ) )
+ layOut();
+}
+
+
+/*!
+ Returns a pointer to the current page in the sequence. Although
+ the wizard does its best to make sure that this value is never 0,
+ it can be if you try hard enough.
+*/
+
+QWidget * Q3Wizard::currentPage() const
+{
+ return d->current ? d->current->w : 0;
+}
+
+
+/*!
+ Returns the title of page \a page.
+*/
+
+QString Q3Wizard::title( QWidget * page ) const
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ return p ? p->t : QString();
+}
+
+/*!
+ Sets the title for page \a page to \a title.
+*/
+
+void Q3Wizard::setTitle( QWidget *page, const QString &title )
+{
+ Q3WizardPrivate::Page * p = d->page( page );
+ if ( p )
+ p->t = title;
+ if ( page == currentPage() )
+ d->title->setText( title );
+}
+
+/*!
+ \property Q3Wizard::titleFont
+ \brief the font used for page titles
+
+ The default is QApplication::font().
+*/
+QFont Q3Wizard::titleFont() const
+{
+ return d->title->font();
+}
+
+void Q3Wizard::setTitleFont( const QFont & font )
+{
+ d->title->setFont( font );
+}
+
+
+/*!
+ Returns a pointer to the dialog's Back button
+
+ By default, this button is connected to the back() slot, which is
+ virtual so you can reimplement it in a Q3Wizard subclass. Use
+ setBackEnabled() to enable/disable this button.
+*/
+QPushButton * Q3Wizard::backButton() const
+{
+ return d->backButton;
+}
+
+
+/*!
+ Returns a pointer to the dialog's Next button
+
+ By default, this button is connected to the next() slot, which is
+ virtual so you can reimplement it in a Q3Wizard subclass. Use
+ setNextEnabled() to enable/disable this button.
+*/
+QPushButton * Q3Wizard::nextButton() const
+{
+ return d->nextButton;
+}
+
+
+/*!
+ Returns a pointer to the dialog's Finish button
+
+ By default, this button is connected to the QDialog::accept()
+ slot, which is virtual so you can reimplement it in a Q3Wizard
+ subclass. Use setFinishEnabled() to enable/disable this button.
+*/
+QPushButton * Q3Wizard::finishButton() const
+{
+ return d->finishButton;
+}
+
+
+/*!
+ Returns a pointer to the dialog's Cancel button
+
+ By default, this button is connected to the QDialog::reject()
+ slot, which is virtual so you can reimplement it in a Q3Wizard
+ subclass.
+*/
+QPushButton * Q3Wizard::cancelButton() const
+{
+ return d->cancelButton;
+}
+
+
+/*!
+ Returns a pointer to the dialog's Help button
+
+ By default, this button is connected to the help() slot, which is
+ virtual so you can reimplement it in a Q3Wizard subclass. Use
+ setHelpEnabled() to enable/disable this button.
+*/
+QPushButton * Q3Wizard::helpButton() const
+{
+ return d->helpButton;
+}
+
+
+/*!
+ This virtual function is responsible for adding the buttons below
+ the bottom divider.
+
+ \a layout is the horizontal layout of the entire wizard.
+*/
+
+void Q3Wizard::layOutButtonRow( QHBoxLayout * layout )
+{
+ bool hasHelp = false;
+ bool hasEarlyFinish = false;
+
+ int i = d->pages.count() - 2;
+ while ( !hasEarlyFinish && i >= 0 ) {
+ if ( d->pages.at( i ) && d->pages.at( i )->finishEnabled )
+ hasEarlyFinish = true;
+ i--;
+ }
+ i = 0;
+ while ( !hasHelp && i < (int)d->pages.count() ) {
+ if ( d->pages.at( i ) && d->pages.at( i )->helpEnabled )
+ hasHelp = true;
+ i++;
+ }
+
+ QBoxLayout * h = new QBoxLayout( QBoxLayout::LeftToRight );
+ layout->addLayout( h );
+
+ if ( hasHelp )
+ h->addWidget( d->helpButton );
+ else
+ d->helpButton->hide();
+
+ h->addStretch( 42 );
+
+ h->addWidget( d->backButton );
+
+ h->addSpacing( 6 );
+
+ if (d->current == d->pages.at( d->pages.count()-1 ))
+ hasEarlyFinish = false;
+
+ if ( hasEarlyFinish ) {
+ d->nextButton->show();
+ d->finishButton->show();
+ h->addWidget( d->nextButton );
+ h->addSpacing( 12 );
+ h->addWidget( d->finishButton );
+ } else if ( d->pages.count() == 0 ||
+ (d->current && d->current->finishEnabled) ||
+ d->current == d->pages.at( d->pages.count()-1 ) ) {
+ d->nextButton->hide();
+ d->finishButton->show();
+ h->addWidget( d->finishButton );
+ } else {
+ d->nextButton->show();
+ d->finishButton->hide();
+ h->addWidget( d->nextButton );
+ }
+
+ // if last page is disabled - show finished btn. at lastpage-1
+ i = d->pages.count()-1;
+ if ( i >= 0 && !appropriate( d->pages.at( i )->w ) &&
+ d->current == d->pages.at( d->pages.count()-2 ) ) {
+ d->nextButton->hide();
+ d->finishButton->show();
+ h->addWidget( d->finishButton );
+ }
+
+ h->addSpacing( 12 );
+ h->addWidget( d->cancelButton );
+}
+
+
+/*!
+ This virtual function is responsible for laying out the title row.
+
+ \a layout is the horizontal layout for the wizard, and \a
+ title is the title for this page. This function is called every
+ time \a title changes.
+*/
+
+void Q3Wizard::layOutTitleRow( QHBoxLayout * layout, const QString & title )
+{
+ d->title->setText( title );
+ layout->addWidget( d->title, 10 );
+}
+
+
+/*
+
+*/
+
+void Q3Wizard::layOut()
+{
+ delete d->v;
+ d->v = new QVBoxLayout( this, 6, 0, "top-level layout" );
+
+ QHBoxLayout * l;
+ l = new QHBoxLayout( 6 );
+ d->v->addLayout( l, 0 );
+ layOutTitleRow( l, d->current ? d->current->t : QString() );
+
+ if ( ! d->hbar1 ) {
+ d->hbar1 = new QFrame( this, "<hr>", 0 );
+ d->hbar1->setFrameStyle( QFrame::Sunken + QFrame::HLine );
+ d->hbar1->setFixedHeight( 12 );
+ }
+
+ d->v->addWidget( d->hbar1 );
+
+ if (d->current)
+ d->v->addWidget(d->current->w, 10);
+
+ if ( ! d->hbar2 ) {
+ d->hbar2 = new QFrame( this, "<hr>", 0 );
+ d->hbar2->setFrameStyle( QFrame::Sunken + QFrame::HLine );
+ d->hbar2->setFixedHeight( 12 );
+ }
+ d->v->addWidget( d->hbar2 );
+
+ l = new QHBoxLayout( 6 );
+ d->v->addLayout( l );
+ layOutButtonRow( l );
+ d->v->activate();
+}
+
+
+/*!
+ \reimp
+*/
+
+bool Q3Wizard::eventFilter( QObject * o, QEvent * e )
+{
+ return QDialog::eventFilter( o, e );
+}
+
+
+/*!
+ Removes \a page from the page sequence but does not delete the
+ page. If \a page is currently being displayed, Q3Wizard will
+ display the page that precedes it, or the first page if this was
+ the first page.
+*/
+
+void Q3Wizard::removePage( QWidget * page )
+{
+ if ( !page )
+ return;
+
+ int i = d->pages.count();
+ QWidget* cp = currentPage();
+ while( --i >= 0 && d->pages.at( i ) && d->pages.at( i )->w != page ) { }
+ if ( i < 0 )
+ return;
+ delete d->pages.takeAt(i);
+ page->hide();
+
+ if( cp == page ) {
+ i--;
+ if( i < 0 )
+ i = 0;
+ if ( pageCount() > 0 )
+ showPage( Q3Wizard::page( i ) );
+ } else if (pageCount() > 0) {
+ showPage(cp);
+ }
+}
+
+
+/*!
+ Returns a pointer to the page at position \a index in the
+ sequence, or 0 if \a index is out of range. The first page has
+ index 0.
+*/
+
+QWidget* Q3Wizard::page( int index ) const
+{
+ if ( index >= pageCount() || index < 0 )
+ return 0;
+ return d->pages.at( index )->w;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/dialogs/q3wizard.h b/src/qt3support/dialogs/q3wizard.h
new file mode 100644
index 0000000000..2d74a7ec1c
--- /dev/null
+++ b/src/qt3support/dialogs/q3wizard.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef Q3WIZARD_H
+#define Q3WIZARD_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class QHBoxLayout;
+class Q3WizardPrivate;
+
+class Q_COMPAT_EXPORT Q3Wizard : public QDialog
+{
+ Q_OBJECT
+ Q_PROPERTY( QFont titleFont READ titleFont WRITE setTitleFont )
+
+public:
+ Q3Wizard( QWidget* parent=0, const char* name=0, bool modal=false, Qt::WindowFlags f=0 );
+ ~Q3Wizard();
+
+ void setVisible(bool);
+
+ void setFont( const QFont & font );
+
+ virtual void addPage( QWidget *, const QString & );
+ virtual void insertPage( QWidget*, const QString&, int );
+ virtual void removePage( QWidget * );
+
+ QString title( QWidget * ) const;
+ void setTitle( QWidget *, const QString & );
+ QFont titleFont() const;
+ void setTitleFont( const QFont & );
+
+ virtual void showPage( QWidget * );
+
+ QWidget * currentPage() const;
+
+ QWidget* page( int ) const;
+ int pageCount() const;
+ int indexOf( QWidget* ) const;
+
+ virtual bool appropriate( QWidget * ) const;
+ virtual void setAppropriate( QWidget *, bool );
+
+ QPushButton * backButton() const;
+ QPushButton * nextButton() const;
+ QPushButton * finishButton() const;
+ QPushButton * cancelButton() const;
+ QPushButton * helpButton() const;
+
+ bool eventFilter( QObject *, QEvent * );
+
+public Q_SLOTS:
+ virtual void setBackEnabled( QWidget *, bool );
+ virtual void setNextEnabled( QWidget *, bool );
+ virtual void setFinishEnabled( QWidget *, bool );
+
+ virtual void setHelpEnabled( QWidget *, bool );
+
+ // obsolete
+ virtual void setFinish( QWidget *, bool ) {}
+
+protected Q_SLOTS:
+ virtual void back();
+ virtual void next();
+ virtual void help();
+
+Q_SIGNALS:
+ void helpClicked();
+ void selected( const QString& );
+
+protected:
+ virtual void layOutButtonRow( QHBoxLayout * );
+ virtual void layOutTitleRow( QHBoxLayout *, const QString & );
+
+private:
+ void setBackEnabled( bool );
+ void setNextEnabled( bool );
+
+ void setHelpEnabled( bool );
+
+ void setNextPage( QWidget * );
+
+ void updateButtons();
+
+ void layOut();
+
+ Q3WizardPrivate *d;
+
+ Q_DISABLE_COPY(Q3Wizard)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3WIZARD_H