/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the Qt3Support module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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.1, 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. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $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" | |
#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<QString> qfd_cleanup_string; | |
static void qt_cleanup_fd_pixmaps(); | |
typedef QList<QPixmap *> FDPixmaps; | |
Q_GLOBAL_STATIC_WITH_INITIALIZER(FDPixmaps, qfd_pixmaps, qAddPostRoutine(qt_cleanup_fd_pixmaps)) | |
static void qt_cleanup_fd_pixmaps() | |
{ | |
qDeleteAll(*qfd_pixmaps()); | |
} | |
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; | |
} | |
#if defined(Q_WS_WIN) | |
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_pixmaps()->append(openFolderIcon); | |
symLinkDirIcon = new QPixmap((const char **)link_dir_xpm); | |
qfd_pixmaps()->append(symLinkDirIcon); | |
symLinkFileIcon = new QPixmap((const char **)link_file_xpm); | |
qfd_pixmaps()->append(symLinkFileIcon); | |
fileIcon = new QPixmap((const char **)file_xpm); | |
qfd_pixmaps()->append(fileIcon); | |
closedFolderIcon = new QPixmap((const char **)closed_xpm); | |
qfd_pixmaps()->append(closedFolderIcon); | |
detailViewIcon = new QPixmap((const char **)detailedview_xpm); | |
qfd_pixmaps()->append(detailViewIcon); | |
multiColumnListViewIcon = new QPixmap((const char **)mclistview_xpm); | |
qfd_pixmaps()->append(multiColumnListViewIcon); | |
cdToParentIcon = new QPixmap((const char **)cdtoparent_xpm); | |
qfd_pixmaps()->append(cdToParentIcon); | |
newFolderIcon = new QPixmap((const char **)newfolder_xpm); | |
qfd_pixmaps()->append(newFolderIcon); | |
previewInfoViewIcon | |
= new QPixmap((const char **)previewinfoview_xpm); | |
qfd_pixmaps()->append(previewInfoViewIcon); | |
previewContentsViewIcon | |
= new QPixmap((const char **)previewcontentsview_xpm); | |
qfd_pixmaps()->append(previewContentsViewIcon); | |
startCopyIcon = new QPixmap((const char **)start_xpm); | |
qfd_pixmaps()->append(startCopyIcon); | |
endCopyIcon = new QPixmap((const char **)end_xpm); | |
qfd_pixmaps()->append(endCopyIcon); | |
goBackIcon = new QPixmap((const char **)back_xpm); | |
qfd_pixmaps()->append(goBackIcon); | |
fifteenTransparentPixels = new QPixmap(closedFolderIcon->width(), 1); | |
qfd_pixmaps()->append(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); | |
void emitDoRename(); | |
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) | |
emitDoRename(); | |
} | |
void QRenameEdit::slotReturnPressed() | |
{ | |
emitDoRename(); | |
} | |
void QRenameEdit::emitDoRename() | |
{ | |
doRenameAlreadyEmitted = true; | |
emit doRename(); | |
doRenameAlreadyEmitted = false; | |
} | |
/************************************************************************ | |
* | |
* 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 (!qstrcmp(style()->className(), "QWindowsStyle")) | |
{ | |
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::fromLatin1("\"%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::fromLatin1("\"%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->isVisibleTo(const_cast<Q3FileDialog *>(this))) | |
return Info; | |
else if (d->contentsPreview | |
&& d->contentsPreviewWidget->isVisibleTo(const_cast<Q3FileDialog *>(this))) | |
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; | |
wchar_t buf[1024]; | |
DWORD bsz = sizeof(buf) / sizeof(wchar_t); | |
int r = RegQueryValueEx(key, (wchar_t*)subKey.utf16(), 0, 0, (LPBYTE)buf, &bsz); | |
if (r == ERROR_SUCCESS) { | |
s = QString::fromWCharArray(buf); | |
} else if (r == ERROR_MORE_DATA) { | |
char *ptr = new char[bsz+1]; | |
r = RegQueryValueEx(key, (wchar_t*)subKey.utf16(), 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; | |
QString s; | |
UINT res = 0; | |
// ---------- get default folder pixmap | |
const wchar_t iconFolder[] = L"folder\\DefaultIcon"; // workaround for Borland | |
int r = RegOpenKeyEx(HKEY_CLASSES_ROOT, iconFolder, 0, KEY_READ, &k); | |
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 | |
res = ExtractIconEx((wchar_t*)lst[0].simplifyWhiteSpace().utf16(), lst[1].simplifyWhiteSpace().toInt(), 0, &si, 1); | |
} | |
if (res) { | |
defaultFolder = fromHICON(si); | |
defaultFolder.setMask(defaultFolder.createHeuristicMask()); | |
*closedFolderIcon = defaultFolder; | |
DestroyIcon(si); | |
} else { | |
defaultFolder = *closedFolderIcon; | |
} | |
} else { | |
RegCloseKey(k); | |
} | |
//------------------------------- get default file pixmap | |
res = ExtractIconEx(L"shell32.dll", 0, 0, &si, 1); | |
if (res) { | |
defaultFile = fromHICON(si); | |
defaultFile.setMask(defaultFile.createHeuristicMask()); | |
*fileIcon = defaultFile; | |
DestroyIcon(si); | |
} else { | |
defaultFile = *fileIcon; | |
} | |
//------------------------------- get default exe pixmap | |
#ifndef Q_OS_WINCE | |
res = ExtractIconEx(L"shell32.dll", 2, 0, &si, 1); | |
#else | |
res = 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 = RegOpenKeyEx(HKEY_CLASSES_ROOT, (wchar_t*)ext.utf16(), 0, KEY_READ, &k); | |
QString s; | |
if (r == ERROR_SUCCESS) { | |
s = getWindowsRegString(k, QString()); | |
} else { | |
cache[key] = defaultFile; | |
RegCloseKey(k); | |
return &defaultFile; | |
} | |
RegCloseKey(k); | |
r = RegOpenKeyEx(HKEY_CLASSES_ROOT, (wchar_t*)QString(s + QLatin1String("\\DefaultIcon")).utf16(), | |
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); | |
res = ExtractIconEx((wchar_t*)filepath.utf16(), lst[1].stripWhiteSpace().toInt(), 0, &si, 1); | |
} | |
} | |
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()) { | |
res = ExtractIconEx((wchar_t*)fi.absFilePath().utf16(), -1, 0, 0, 1); | |
if (res) | |
res = ExtractIconEx((wchar_t*)fi.absFilePath().utf16(), res - 1, 0, &si, 1); | |
} | |
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(QLatin1Char('/'))) | |
file.append(QLatin1Char('/')); | |
file += inf.name(); | |
if (GetFileAttributes((wchar_t*)file.utf16()) & 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 |