src/qt3support/dialogs/q3filedialog.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the Qt3Support module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qplatformdefs.h"
00025 
00026 #include "q3filedialog.h"
00027 
00028 #ifndef QT_NO_FILEDIALOG
00029 
00030 #include "private/qapplication_p.h"
00031 #include "q3buttongroup.h"
00032 #include "q3header.h"
00033 #include "q3listview.h"
00034 #include "qapplication.h"
00035 #include "qbitmap.h"
00036 #include "qcheckbox.h"
00037 #include "q3cleanuphandler.h"
00038 #include "qcombobox.h"
00039 #include "q3combobox.h"
00040 #include "q3cstring.h"
00041 #include "qcursor.h"
00042 #include "qdesktopwidget.h"
00043 #include "q3dragobject.h"
00044 #include "qevent.h"
00045 #include "qfile.h"
00046 #include "qlabel.h"
00047 #include "qlayout.h"
00048 #include "qlibrary.h"
00049 #include "qlineedit.h"
00050 #include "q3listbox.h"
00051 #include "qmap.h"
00052 #include "qmessagebox.h"
00053 #include "qmime.h"
00054 #include "qpainter.h"
00055 #include "qpointer.h"
00056 #include "q3popupmenu.h"
00057 #include "q3progressbar.h"
00058 #include "q3ptrvector.h"
00059 #include "qpushbutton.h"
00060 #include "qregexp.h"
00061 #include "qsplitter.h"
00062 #include "q3strlist.h"
00063 #include "qstyle.h"
00064 #include "qtimer.h"
00065 #include "qtoolbutton.h"
00066 #include "qtooltip.h"
00067 #include "q3widgetstack.h"
00068 #include "q3urloperator.h"
00069 #include "q3vbox.h"
00070 #include "qurlinfo.h"
00071 
00072 #ifdef Q_WS_WIN
00073 #ifndef QT_NO_THREAD
00074 #  include "qwindowsstyle.h"
00075 #  include "private/qmutexpool_p.h"
00076 #endif
00077 #endif // Q_WS_WIN
00078 
00079 #ifndef Q_OS_TEMP
00080 #include <time.h>
00081 #else
00082 #include <shellapi.h>
00083 #endif // Q_OS_TEMP
00084 #include <stdlib.h>
00085 #include <limits.h>
00086 #include <ctype.h>
00087 
00088 #ifdef Q_WS_MAC
00089 #include "qmacstyle_mac.h"
00090 #include "private/qt_mac_p.h"
00091 #include "private/qunicodetables_p.h"
00092 #undef check
00093 #endif
00094 
00095 /* XPM */
00096 static const char * const start_xpm[]={
00097     "16 15 8 1",
00098     "a c #cec6bd",
00099     "# c #000000",
00100     "e c #ffff00",
00101     "b c #999999",
00102     "f c #cccccc",
00103     "d c #dcdcdc",
00104     "c c #ffffff",
00105     ". c None",
00106     ".....######aaaaa",
00107     "...bb#cccc##aaaa",
00108     "..bcc#cccc#d#aaa",
00109     ".bcef#cccc#dd#aa",
00110     ".bcfe#cccc#####a",
00111     ".bcef#ccccccccc#",
00112     "bbbbbbbbbbbbccc#",
00113     "bccccccccccbbcc#",
00114     "bcefefefefee#bc#",
00115     ".bcefefefefef#c#",
00116     ".bcfefefefefe#c#",
00117     "..bcfefefefeeb##",
00118     "..bbbbbbbbbbbbb#",
00119     "...#############",
00120     "................"};
00121 
00122 /* XPM */
00123 static const char * const end_xpm[]={
00124     "16 15 9 1",
00125     "d c #a0a0a0",
00126     "c c #c3c3c3",
00127     "# c #cec6bd",
00128     ". c #000000",
00129     "f c #ffff00",
00130     "e c #999999",
00131     "g c #cccccc",
00132     "b c #ffffff",
00133     "a c None",
00134     "......####aaaaaa",
00135     ".bbbb..###aaaaaa",
00136     ".bbbb.c.##aaaaaa",
00137     ".bbbb....ddeeeea",
00138     ".bbbbbbb.bbbbbe.",
00139     ".bbbbbbb.bcfgfe.",
00140     "eeeeeeeeeeeeefe.",
00141     "ebbbbbbbbbbeege.",
00142     "ebfgfgfgfgff.ee.",
00143     "aebfgfgfgfgfg.e.",
00144     "aebgfgfgfgfgf.e.",
00145     "aaebgfgfgfgffe..",
00146     "aaeeeeeeeeeeeee.",
00147     "aaa.............",
00148     "aaaaaaaaaaaaaaaa"};
00149 
00150 /* XPM */
00151 static const char* const open_xpm[]={
00152     "16 16 6 1",
00153     ". c None",
00154     "b c #ffff00",
00155     "d c #000000",
00156     "* c #999999",
00157     "c c #cccccc",
00158     "a c #ffffff",
00159     "................",
00160     "................",
00161     "...*****........",
00162     "..*aaaaa*.......",
00163     ".*abcbcba******.",
00164     ".*acbcbcaaaaaa*d",
00165     ".*abcbcbcbcbcb*d",
00166     "*************b*d",
00167     "*aaaaaaaaaa**c*d",
00168     "*abcbcbcbcbbd**d",
00169     ".*abcbcbcbcbcd*d",
00170     ".*acbcbcbcbcbd*d",
00171     "..*acbcbcbcbb*dd",
00172     "..*************d",
00173     "...ddddddddddddd",
00174     "................"};
00175 
00176 /* XPM */
00177 static const char * const link_dir_xpm[]={
00178     "16 16 10 1",
00179     "h c #808080",
00180     "g c #a0a0a0",
00181     "d c #000000",
00182     "b c #ffff00",
00183     "f c #303030",
00184     "# c #999999",
00185     "a c #cccccc",
00186     "e c #585858",
00187     "c c #ffffff",
00188     ". c None",
00189     "................",
00190     "................",
00191     "..#####.........",
00192     ".#ababa#........",
00193     "#abababa######..",
00194     "#cccccccccccc#d.",
00195     "#cbababababab#d.",
00196     "#cabababababa#d.",
00197     "#cbababdddddddd.",
00198     "#cababadccccccd.",
00199     "#cbababdcececcd.",
00200     "#cababadcefdfcd.",
00201     "#cbababdccgdhcd.",
00202     "#######dccchccd.",
00203     ".dddddddddddddd.",
00204     "................"};
00205 
00206 /* XPM */
00207 static const char * const link_file_xpm[]={
00208     "16 16 10 1",
00209     "h c #808080",
00210     "g c #a0a0a0",
00211     "d c #c3c3c3",
00212     ". c #7f7f7f",
00213     "c c #000000",
00214     "b c #bfbfbf",
00215     "f c #303030",
00216     "e c #585858",
00217     "a c #ffffff",
00218     "# c None",
00219     "################",
00220     "..........######",
00221     ".aaaaaaaab.#####",
00222     ".aaaaaaaaba.####",
00223     ".aaaaaaaacccc###",
00224     ".aaaaaaaaaabc###",
00225     ".aaaaaaaaaabc###",
00226     ".aaaaaaaaaadc###",
00227     ".aaaaaaaaaadc###",
00228     ".aaaacccccccc###",
00229     ".aaaacaaaaaac###",
00230     ".aaaacaeaeaac###",
00231     ".aaaacaefcfac###",
00232     ".aaaacaagchac###",
00233     ".ddddcaaahaac###",
00234     "ccccccccccccc###"};
00235 
00236 /* XPM */
00237 static const char* const file_xpm[]={
00238     "16 16 5 1",
00239     ". c #7f7f7f",
00240     "# c None",
00241     "c c #000000",
00242     "b c #bfbfbf",
00243     "a c #ffffff",
00244     "################",
00245     "..........######",
00246     ".aaaaaaaab.#####",
00247     ".aaaaaaaaba.####",
00248     ".aaaaaaaacccc###",
00249     ".aaaaaaaaaabc###",
00250     ".aaaaaaaaaabc###",
00251     ".aaaaaaaaaabc###",
00252     ".aaaaaaaaaabc###",
00253     ".aaaaaaaaaabc###",
00254     ".aaaaaaaaaabc###",
00255     ".aaaaaaaaaabc###",
00256     ".aaaaaaaaaabc###",
00257     ".aaaaaaaaaabc###",
00258     ".bbbbbbbbbbbc###",
00259     "ccccccccccccc###"};
00260 
00261 /* XPM */
00262 static const char * const closed_xpm[]={
00263     "16 16 6 1",
00264     ". c None",
00265     "b c #ffff00",
00266     "d c #000000",
00267     "* c #999999",
00268     "a c #cccccc",
00269     "c c #ffffff",
00270     "................",
00271     "................",
00272     "..*****.........",
00273     ".*ababa*........",
00274     "*abababa******..",
00275     "*cccccccccccc*d.",
00276     "*cbababababab*d.",
00277     "*cabababababa*d.",
00278     "*cbababababab*d.",
00279     "*cabababababa*d.",
00280     "*cbababababab*d.",
00281     "*cabababababa*d.",
00282     "*cbababababab*d.",
00283     "**************d.",
00284     ".dddddddddddddd.",
00285     "................"};
00286 
00287 
00288 /* XPM */
00289 static const char* const cdtoparent_xpm[]={
00290     "15 13 3 1",
00291     ". c None",
00292     "* c #000000",
00293     "a c #ffff99",
00294     "..*****........",
00295     ".*aaaaa*.......",
00296     "***************",
00297     "*aaaaaaaaaaaaa*",
00298     "*aaaa*aaaaaaaa*",
00299     "*aaa***aaaaaaa*",
00300     "*aa*****aaaaaa*",
00301     "*aaaa*aaaaaaaa*",
00302     "*aaaa*aaaaaaaa*",
00303     "*aaaa******aaa*",
00304     "*aaaaaaaaaaaaa*",
00305     "*aaaaaaaaaaaaa*",
00306     "***************"};
00307 
00308 
00309 /* XPM */
00310 static const char* const newfolder_xpm[] = {
00311     "15 14 4 1",
00312     "        c None",
00313     ".        c #000000",
00314     "+        c #FFFF00",
00315     "@        c #FFFFFF",
00316     "          .    ",
00317     "               ",
00318     "          .    ",
00319     "       .     . ",
00320     "  ....  . . .  ",
00321     " .+@+@.  . .   ",
00322     "..........  . .",
00323     ".@+@+@+@+@..   ",
00324     ".+@+@+@+@+. .  ",
00325     ".@+@+@+@+@.  . ",
00326     ".+@+@+@+@+.    ",
00327     ".@+@+@+@+@.    ",
00328     ".+@+@+@+@+.    ",
00329     "...........    "};
00330 
00331 /* XPM */
00332 static const char* const detailedview_xpm[]={
00333     "14 11 3 1",
00334     ". c None",
00335     "* c #000000",
00336     "a c #000099",
00337     ".****.***.***.",
00338     "..............",
00339     "aaaaaaaaaaaaaa",
00340     "..............",
00341     ".****.***.***.",
00342     "..............",
00343     ".****.***.***.",
00344     "..............",
00345     ".****.***.***.",
00346     "..............",
00347     ".****.***.***."};
00348 
00349 /* XPM */
00350 static const char* const previewinfoview_xpm[]={
00351     "13 13 4 1",
00352     ". c #00007f",
00353     "a c black",
00354     "# c #cec6bd",
00355     "b c #000000",
00356     "..#####aaaaaa",
00357     ".#.#bb#a#####",
00358     "...####a#bbb#",
00359     "#######a#####",
00360     "#######a#bb##",
00361     "..#####a#####",
00362     ".#.#bb#a#bbb#",
00363     "...####a#####",
00364     "#######a#bb##",
00365     "#######a#####",
00366     "..#####a#bbb#",
00367     ".#.#bb#a#####",
00368     "...####aaaaaa"};
00369 
00370 /* XPM */
00371 static const char* const previewcontentsview_xpm[]={
00372     "14 13 5 1",
00373     ". c #00007f",
00374     "a c black",
00375     "c c #7f007f",
00376     "# c #cec6bd",
00377     "b c #000000",
00378     "..#####aaaaaaa",
00379     ".#.#bb#a#####a",
00380     "...####a#ccc#a",
00381     "#######a#ccc#a",
00382     "#######a#####a",
00383     "..#####a#bbb#a",
00384     ".#.#bb#a#####a",
00385     "...####a#bbb#a",
00386     "#######a#####a",
00387     "#######a#bbb#a",
00388     "..#####a#####a",
00389     ".#.#bb#a#####a",
00390     "...####aaaaaaa"};
00391 
00392 /* XPM */
00393 static const char* const mclistview_xpm[]={
00394     "15 11 4 1",
00395     "* c None",
00396     "b c #000000",
00397     ". c #000099",
00398     "a c #ffffff",
00399     "...*****...****",
00400     ".a.*bbb*.a.*bbb",
00401     "...*****...****",
00402     "***************",
00403     "...*****...****",
00404     ".a.*bbb*.a.*bbb",
00405     "...*****...****",
00406     "***************",
00407     "...*****...****",
00408     ".a.*bbb*.a.*bbb",
00409     "...*****...****"};
00410 
00411 /* XPM */
00412 static const char * const back_xpm [] = {
00413     "13 11 3 1",
00414     "a c #00ffff",
00415     "# c #000000",
00416     ". c None",
00417     ".....#.......",
00418     "....##.......",
00419     "...#a#.......",
00420     "..#aa########",
00421     ".#aaaaaaaaaa#",
00422     "#aaaaaaaaaaa#",
00423     ".#aaaaaaaaaa#",
00424     "..#aa########",
00425     "...#a#.......",
00426     "....##.......",
00427     ".....#......."};
00428 
00429 static QPixmap * openFolderIcon = 0;
00430 static QPixmap * closedFolderIcon = 0;
00431 static QPixmap * detailViewIcon = 0;
00432 static QPixmap * multiColumnListViewIcon = 0;
00433 static QPixmap * cdToParentIcon = 0;
00434 static QPixmap * newFolderIcon = 0;
00435 static QPixmap * fifteenTransparentPixels = 0;
00436 static QPixmap * symLinkDirIcon = 0;
00437 static QPixmap * symLinkFileIcon = 0;
00438 static QPixmap * fileIcon = 0;
00439 static QPixmap * startCopyIcon = 0;
00440 static QPixmap * endCopyIcon = 0;
00441 static QPixmap * previewContentsViewIcon = 0;
00442 static QPixmap * previewInfoViewIcon = 0;
00443 static QPixmap *goBackIcon = 0;
00444 static Q3FileIconProvider * fileIconProvider = 0;
00445 static int lastWidth = 0;
00446 static int lastHeight = 0;
00447 static QString * workingDirectory = 0;
00448 
00449 static bool bShowHiddenFiles = false;
00450 static int sortFilesBy = (int)QDir::Name;
00451 static bool sortAscending = true;
00452 static bool detailViewMode = false;
00453 
00454 static Q3CleanupHandler<QPixmap> qfd_cleanup_pixmap;
00455 static Q3CleanupHandler<QString> qfd_cleanup_string;
00456 
00457 static QString toRootIfNotExists( const QString &path )
00458 {
00459     if ( !path.isEmpty() )
00460         return path;
00461 
00462     QFileInfoList drives = QDir::drives();
00463     Q_ASSERT( !drives.isEmpty() );
00464     return drives.first().filePath();
00465 }
00466 
00467 static bool isDirectoryMode(int m)
00468 {
00469     return m == Q3FileDialog::Directory || m == Q3FileDialog::DirectoryOnly;
00470 }
00471 
00472 static void updateLastSize(Q3FileDialog *that)
00473 {
00474     int extWidth = 0;
00475     int extHeight = 0;
00476     if (that->extension() && that->extension()->isVisible()) {
00477         if (that->orientation() == Qt::Vertical)
00478             extHeight = that->extension()->height();
00479         else
00480             extWidth = that->extension()->width();
00481     }
00482     lastWidth = that->width() - extWidth;
00483     lastHeight = that->height() - extHeight;
00484 }
00485 
00486 // Don't remove the lines below!
00487 //
00488 // resolving the W methods manually is needed, because Windows 95 doesn't include
00489 // these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol
00490 // when Qt calls getEsistingDirectory(), etc.
00491 #if defined(Q_WS_WIN)
00492 
00493 typedef UINT (WINAPI *PtrExtractIconEx)(LPCTSTR,int,HICON*,HICON*,UINT);
00494 static PtrExtractIconEx ptrExtractIconEx = 0;
00495 
00496 static void resolveLibs()
00497 {
00498 #ifndef Q_OS_TEMP
00499     static bool triedResolve = false;
00500 
00501     if (!triedResolve) {
00502 #ifndef QT_NO_THREAD
00503         // protect initialization
00504         QMutexLocker locker(qt_global_mutexpool ?
00505                              qt_global_mutexpool->get(&triedResolve) : 0);
00506         // check triedResolve again, since another thread may have already
00507         // done the initialization
00508         if (triedResolve) {
00509             // another thread did initialize the security function pointers,
00510             // so we shouldn't do it again.
00511             return;
00512         }
00513 #endif
00514         triedResolve = true;
00515         if (qt_winUnicode()) {
00516             QLibrary lib("shell32");
00517             ptrExtractIconEx = (PtrExtractIconEx) lib.resolve("ExtractIconExW");
00518         }
00519     }
00520 #endif
00521 }
00522 #ifdef Q_OS_TEMP
00523 #define PtrExtractIconEx ExtractIconEx
00524 #endif
00525 
00526 class QWindowsIconProvider : public Q3FileIconProvider
00527 {
00528 public:
00529     QWindowsIconProvider(QObject *parent=0, const char *name=0);
00530     ~QWindowsIconProvider();
00531 
00532     const QPixmap * pixmap(const QFileInfo &fi);
00533 
00534 private:
00535     QPixmap defaultFolder;
00536     QPixmap defaultFile;
00537     QPixmap defaultExe;
00538     QPixmap pix;
00539     int pixw, pixh;
00540     QMap< QString, QPixmap > cache;
00541 
00542 };
00543 #endif
00544 
00545 static void makeVariables() {
00546     if (!openFolderIcon) {
00547         workingDirectory = new QString(::toRootIfNotExists( QDir::currentDirPath() ));
00548         qfd_cleanup_string.add(&workingDirectory);
00549 
00550         openFolderIcon = new QPixmap((const char **)open_xpm);
00551         qfd_cleanup_pixmap.add(&openFolderIcon);
00552         symLinkDirIcon = new QPixmap((const char **)link_dir_xpm);
00553         qfd_cleanup_pixmap.add(&symLinkDirIcon);
00554         symLinkFileIcon = new QPixmap((const char **)link_file_xpm);
00555         qfd_cleanup_pixmap.add(&symLinkFileIcon);
00556         fileIcon = new QPixmap((const char **)file_xpm);
00557         qfd_cleanup_pixmap.add(&fileIcon);
00558         closedFolderIcon = new QPixmap((const char **)closed_xpm);
00559         qfd_cleanup_pixmap.add(&closedFolderIcon);
00560         detailViewIcon = new QPixmap((const char **)detailedview_xpm);
00561         qfd_cleanup_pixmap.add(&detailViewIcon);
00562         multiColumnListViewIcon = new QPixmap((const char **)mclistview_xpm);
00563         qfd_cleanup_pixmap.add(&multiColumnListViewIcon);
00564         cdToParentIcon = new QPixmap((const char **)cdtoparent_xpm);
00565         qfd_cleanup_pixmap.add(&cdToParentIcon);
00566         newFolderIcon = new QPixmap((const char **)newfolder_xpm);
00567         qfd_cleanup_pixmap.add(&newFolderIcon);
00568         previewInfoViewIcon
00569             = new QPixmap((const char **)previewinfoview_xpm);
00570         qfd_cleanup_pixmap.add(&previewInfoViewIcon);
00571         previewContentsViewIcon
00572             = new QPixmap((const char **)previewcontentsview_xpm);
00573         qfd_cleanup_pixmap.add(&previewContentsViewIcon);
00574         startCopyIcon = new QPixmap((const char **)start_xpm);
00575         qfd_cleanup_pixmap.add(&startCopyIcon);
00576         endCopyIcon = new QPixmap((const char **)end_xpm);
00577         qfd_cleanup_pixmap.add(&endCopyIcon);
00578         goBackIcon = new QPixmap((const char **)back_xpm);
00579         qfd_cleanup_pixmap.add(&goBackIcon);
00580         fifteenTransparentPixels = new QPixmap(closedFolderIcon->width(), 1);
00581         qfd_cleanup_pixmap.add(&fifteenTransparentPixels);
00582         QBitmap m(fifteenTransparentPixels->width(), 1);
00583         m.fill(Qt::color0);
00584         fifteenTransparentPixels->setMask(m);
00585         bShowHiddenFiles = false;
00586         sortFilesBy = (int)QDir::Name;
00587         detailViewMode = false;
00588 #if defined(Q_WS_WIN)
00589         if (!fileIconProvider)
00590             fileIconProvider = new QWindowsIconProvider(qApp);
00591 #endif
00592     }
00593 }
00594 
00595 /******************************************************************
00596  *
00597  * Definitions of view classes
00598  *
00599  ******************************************************************/
00600 
00601 class QRenameEdit : public QLineEdit
00602 {
00603     Q_OBJECT
00604 
00605 public:
00606     QRenameEdit(QWidget *parent);
00607 
00608 protected:
00609     void keyPressEvent(QKeyEvent *e);
00610     void focusOutEvent(QFocusEvent *e);
00611 
00612 signals:
00613     void cancelRename();
00614     void doRename();
00615 
00616 private slots:
00617     void slotReturnPressed();
00618 
00619 private:
00620     bool doRenameAlreadyEmitted;
00621 };
00622 
00623 QRenameEdit::QRenameEdit(QWidget *parent)
00624     : QLineEdit(parent, "qt_rename_edit"), doRenameAlreadyEmitted(false)
00625 {
00626     connect(this, SIGNAL(returnPressed()), SLOT(slotReturnPressed()));
00627 }
00628 
00629 class QFileListBox : public Q3ListBox
00630 {
00631     friend class Q3FileDialog;
00632 
00633     Q_OBJECT
00634 
00635 private:
00636     QFileListBox(QWidget *parent, Q3FileDialog *d);
00637 
00638     void clear();
00639     void show();
00640     void startRename(bool check = true);
00641     void viewportMousePressEvent(QMouseEvent *e);
00642     void viewportMouseReleaseEvent(QMouseEvent *e);
00643     void viewportMouseDoubleClickEvent(QMouseEvent *e);
00644     void viewportMouseMoveEvent(QMouseEvent *e);
00645 #ifndef QT_NO_DRAGANDDROP
00646     void viewportDragEnterEvent(QDragEnterEvent *e);
00647     void viewportDragMoveEvent(QDragMoveEvent *e);
00648     void viewportDragLeaveEvent(QDragLeaveEvent *e);
00649     void viewportDropEvent(QDropEvent *e);
00650     bool acceptDrop(const QPoint &pnt, QWidget *source);
00651     void setCurrentDropItem(const QPoint &pnt);
00652 #endif
00653     void keyPressEvent(QKeyEvent *e);
00654 
00655 private slots:
00656     void rename();
00657     void cancelRename();
00658     void doubleClickTimeout();
00659     void changeDirDuringDrag();
00660     void dragObjDestroyed();
00661     void contentsMoved(int, int);
00662 
00663 private:
00664     QRenameEdit *lined;
00665     Q3FileDialog *filedialog;
00666     bool renaming;
00667     QTimer* renameTimer;
00668     Q3ListBoxItem *renameItem, *dragItem;
00669     QPoint pressPos, oldDragPos;
00670     bool mousePressed;
00671     int urls;
00672     QString startDragDir;
00673     Q3ListBoxItem *currDropItem;
00674     QTimer *changeDirTimer;
00675     bool firstMousePressEvent;
00676     Q3UrlOperator startDragUrl;
00677 
00678 };
00679 
00680 
00681 class Q3FileDialogQFileListView : public Q3ListView
00682 {
00683     Q_OBJECT
00684 
00685 public:
00686     Q3FileDialogQFileListView(QWidget *parent, Q3FileDialog *d);
00687 
00688     void clear();
00689     void startRename(bool check = true);
00690     void setSorting(int column, bool increasing = true);
00691 
00692     QRenameEdit *lined;
00693     bool renaming;
00694     Q3ListViewItem *renameItem;
00695 
00696 private:
00697     void viewportMousePressEvent(QMouseEvent *e);
00698     void viewportMouseDoubleClickEvent(QMouseEvent *e);
00699     void keyPressEvent(QKeyEvent *e);
00700     void viewportMouseReleaseEvent(QMouseEvent *e);
00701     void viewportMouseMoveEvent(QMouseEvent *e);
00702 #ifndef QT_NO_DRAGANDDROP
00703     void viewportDragEnterEvent(QDragEnterEvent *e);
00704     void viewportDragMoveEvent(QDragMoveEvent *e);
00705     void viewportDragLeaveEvent(QDragLeaveEvent *e);
00706     void viewportDropEvent(QDropEvent *e);
00707     bool acceptDrop(const QPoint &pnt, QWidget *source);
00708     void setCurrentDropItem(const QPoint &pnt);
00709 #endif
00710 
00711 private slots:
00712     void rename();
00713     void cancelRename();
00714     void changeSortColumn2(int column);
00715     void doubleClickTimeout();
00716     void changeDirDuringDrag();
00717     void dragObjDestroyed();
00718     void contentsMoved(int, int);
00719 
00720 private:
00721     Q3FileDialog *filedialog;
00722     QTimer* renameTimer;
00723     QPoint pressPos, oldDragPos;
00724     bool mousePressed;
00725     int urls;
00726     QString startDragDir;
00727     Q3ListViewItem *currDropItem, *dragItem;
00728     QTimer *changeDirTimer;
00729     bool firstMousePressEvent;
00730     bool ascending;
00731     int sortcolumn;
00732     Q3UrlOperator startDragUrl;
00733 
00734 };
00735 
00736 /****************************************************************************
00737  *
00738  * Classes for copy progress dialog
00739  *
00740  ****************************************************************************/
00741 
00742 class QFDProgressAnimation : public QWidget
00743 {
00744     Q_OBJECT
00745 
00746 public:
00747     QFDProgressAnimation(QWidget *parent);
00748     void start();
00749 
00750 private slots:
00751     void next();
00752 
00753 protected:
00754     void paintEvent(QPaintEvent *e);
00755 
00756 private:
00757     int step;
00758     QTimer *timer;
00759 
00760 };
00761 
00762 QFDProgressAnimation::QFDProgressAnimation(QWidget *parent)
00763     : QWidget(parent, "qt_progressanimation")
00764 {
00765     setFixedSize(300, 50);
00766     step = -1;
00767     next();
00768     timer = new QTimer(this);
00769     connect(timer, SIGNAL(timeout()),
00770              this, SLOT(next()));
00771 }
00772 
00773 void QFDProgressAnimation::start()
00774 {
00775     timer->start(150, false);
00776 }
00777 
00778 void QFDProgressAnimation::next()
00779 {
00780     ++step;
00781     if (step > 10)
00782         step = 0;
00783     repaint();
00784 }
00785 
00786 void QFDProgressAnimation::paintEvent(QPaintEvent *)
00787 {
00788     erase();
00789 
00790     QPainter p;
00791     p.begin(this);
00792     if (step == 0) {
00793         p.drawPixmap(5, (height() - startCopyIcon->height()) / 2,
00794                       *startCopyIcon);
00795         p.drawPixmap(width() - 5 - openFolderIcon->width(),
00796                       (height() - openFolderIcon->height()) / 2 , *openFolderIcon);
00797     } else if (step == 10) {
00798         p.drawPixmap(5, (height() - openFolderIcon->height()) / 2,
00799                       *openFolderIcon);
00800         p.drawPixmap(width() - 5 - endCopyIcon->width(),
00801                       (height() - endCopyIcon->height()) / 2 , *endCopyIcon);
00802     } else {
00803         p.drawPixmap(5, (height() - openFolderIcon->height()) / 2,
00804                       *openFolderIcon);
00805         p.drawPixmap(width() - 5 - openFolderIcon->width(),
00806                       (height() - openFolderIcon->height()) / 2 , *openFolderIcon);
00807         int x = 10 + openFolderIcon->width();
00808         int w = width() - 2 * x;
00809         int s = w / 9;
00810         p.drawPixmap(x + s * step, (height() - fileIcon->height()) / 2 - fileIcon->height(),
00811                       *fileIcon);
00812     }
00813 }
00814 
00815 
00816 class QFDProgressDialog : public QDialog
00817 {
00818     Q_OBJECT
00819 
00820 public:
00821     QFDProgressDialog(QWidget *parent, const QString &fn, int steps);
00822 
00823     void setReadProgress(int p);
00824     void setWriteProgress(int p);
00825     void setWriteLabel(const QString &s);
00826 
00827 signals:
00828     void cancelled();
00829 
00830 private:
00831     Q3ProgressBar *readBar;
00832     Q3ProgressBar *writeBar;
00833     QLabel *writeLabel;
00834     QFDProgressAnimation *animation;
00835 
00836 };
00837 
00838 QFDProgressDialog::QFDProgressDialog(QWidget *parent, const QString &fn, int steps)
00839     : QDialog(parent, "", true)
00840 {
00841     setWindowTitle(Q3FileDialog::tr("Copy or Move a File"));
00842     QVBoxLayout *layout = new QVBoxLayout(this);
00843     layout->setSpacing(5);
00844     layout->setMargin(5);
00845 
00846     animation = new QFDProgressAnimation(this);
00847     layout->addWidget(animation);
00848 
00849     layout->addWidget(new QLabel(Q3FileDialog::tr("Read: %1").arg(fn),
00850                        this, "qt_read_lbl"));
00851     readBar = new Q3ProgressBar(steps, this, "qt_readbar");
00852     readBar->reset();
00853     readBar->setProgress(0);
00854     layout->addWidget(readBar);
00855     writeLabel = new QLabel(Q3FileDialog::tr("Write: %1").arg(QString()),
00856                              this, "qt_write_lbl");
00857     layout->addWidget(writeLabel);
00858     writeBar = new Q3ProgressBar(steps, this, "qt_writebar");
00859     writeBar->reset();
00860     writeBar->setProgress(0);
00861     layout->addWidget(writeBar);
00862 
00863     QPushButton *b = new QPushButton(Q3FileDialog::tr("Cancel"), this,
00864                                       "qt_cancel_btn");
00865     b->setFixedSize(b->sizeHint());
00866     layout->addWidget(b);
00867     connect(b, SIGNAL(clicked()),
00868              this, SIGNAL(cancelled()));
00869 
00870     animation->start();
00871 }
00872 
00873 void QFDProgressDialog::setReadProgress(int p)
00874 {
00875     readBar->setProgress(p);
00876 }
00877 
00878 void QFDProgressDialog::setWriteProgress(int p)
00879 {
00880     writeBar->setProgress(p);
00881 }
00882 
00883 void QFDProgressDialog::setWriteLabel(const QString &s)
00884 {
00885     writeLabel->setText(Q3FileDialog::tr("Write: %1").arg(s));
00886 }
00887 
00888 /************************************************************************
00889  *
00890  * Private Q3FileDialog members
00891  *
00892  ************************************************************************/
00893 
00894 class Q3FileDialogPrivate {
00895 public:
00896     ~Q3FileDialogPrivate();
00897 
00898     QStringList history;
00899 
00900     bool geometryDirty;
00901     Q3ComboBox * paths;
00902     QComboBox * types;
00903     QLabel * pathL;
00904     QLabel * fileL;
00905     QLabel * typeL;
00906 
00907     QVBoxLayout * topLevelLayout;
00908     QHBoxLayout *buttonLayout, *leftLayout, *rightLayout;
00909     Q3PtrList<QHBoxLayout> extraWidgetsLayouts;
00910     Q3PtrList<QLabel> extraLabels;
00911     Q3PtrList<QWidget> extraWidgets;
00912     Q3PtrList<QWidget> extraButtons;
00913     Q3PtrList<QAbstractButton> toolButtons;
00914 
00915     Q3WidgetStack * stack;
00916 
00917     QToolButton * cdToParent, *newFolder, * detailView, * mcView,
00918         *previewInfo, *previewContents, *goBack;
00919     Q3ButtonGroup * modeButtons;
00920 
00921     QString currentFileName;
00922     Q3ListViewItem *last;
00923 
00924     Q3ListBoxItem *lastEFSelected;
00925 
00926     struct File: public Q3ListViewItem {
00927         File(Q3FileDialogPrivate * dlgp,
00928               const QUrlInfo * fi, Q3ListViewItem * parent)
00929             : Q3ListViewItem(parent, dlgp->last), info(*fi), d(dlgp), i(0), hasMimePixmap(false)
00930         { setup(); dlgp->last = this; }
00931         File(Q3FileDialogPrivate * dlgp,
00932               const QUrlInfo * fi, Q3ListView * parent)
00933             : Q3ListViewItem(parent, dlgp->last), info(*fi), d(dlgp), i(0), hasMimePixmap(false)
00934         { setup(); dlgp->last = this; }
00935         File(Q3FileDialogPrivate * dlgp,
00936               const QUrlInfo * fi, Q3ListView * parent, Q3ListViewItem * after)
00937             : Q3ListViewItem(parent, after), info(*fi), d(dlgp), i(0), hasMimePixmap(false)
00938         { setup(); if (!nextSibling()) dlgp->last = this; }
00939         ~File();
00940 
00941         QString text(int column) const;
00942         const QPixmap * pixmap(int) const;
00943 
00944         QUrlInfo info;
00945         Q3FileDialogPrivate * d;
00946         Q3ListBoxItem *i;
00947         bool hasMimePixmap;
00948     };
00949 
00950     class MCItem: public Q3ListBoxItem {
00951     public:
00952         MCItem(Q3ListBox *, Q3ListViewItem * item);
00953         MCItem(Q3ListBox *, Q3ListViewItem * item, Q3ListBoxItem *after);
00954         QString text() const;
00955         const QPixmap *pixmap() const;
00956         int height(const Q3ListBox *) const;
00957         int width(const Q3ListBox *) const;
00958         void paint(QPainter *);
00959         Q3ListViewItem * i;
00960     };
00961 
00962     class UrlInfoList : public Q3PtrList<QUrlInfo> {
00963     public:
00964         UrlInfoList() { setAutoDelete(true); }
00965         int compareItems(Q3PtrCollection::Item n1, Q3PtrCollection::Item n2) {
00966             if (!n1 || !n2)
00967                 return 0;
00968 
00969             QUrlInfo *i1 = (QUrlInfo *)n1;
00970             QUrlInfo *i2 = (QUrlInfo *)n2;
00971 
00972             if (i1->isDir() && !i2->isDir())
00973                 return -1;
00974             if (!i1->isDir() && i2->isDir())
00975                 return 1;
00976 
00977             if (i1->name() == "..")
00978                 return -1;
00979             if (i2->name() == "..")
00980                 return 1;
00981 
00982             if (sortFilesBy == QDir::Name) {
00983 #if defined(Q_OS_WIN32)
00984     QString name1 = i1->name().lower();
00985     QString name2 = i2->name().lower();
00986     return name1.localeAwareCompare( name2 );
00987 #else
00988     QString name1 = i1->name();
00989     QString name2 = i2->name();
00990     return name1.localeAwareCompare( name2 );
00991 #endif
00992             }
00993             if (QUrlInfo::equal(*i1, *i2, sortFilesBy))
00994                 return 0;
00995             else if (QUrlInfo::greaterThan(*i1, *i2, sortFilesBy))
00996                 return 1;
00997             else if (QUrlInfo::lessThan(*i1, *i2, sortFilesBy))
00998                 return -1;
00999             // can't happen...
01000             return 0;
01001         }
01002         QUrlInfo *operator[](int i) {
01003             return at(i);
01004         }
01005     };
01006 
01007     UrlInfoList sortedList;
01008     Q3PtrList<File> pendingItems;
01009 
01010     QFileListBox * moreFiles;
01011 
01012     Q3FileDialog::Mode mode;
01013 
01014     QString rw;
01015     QString ro;
01016     QString wo;
01017     QString inaccessible;
01018 
01019     QString symLinkToFile;
01020     QString file;
01021     QString symLinkToDir;
01022     QString dir;
01023     QString symLinkToSpecial;
01024     QString special;
01025     Q3WidgetStack *preview;
01026     bool infoPreview, contentsPreview;
01027     QSplitter *splitter;
01028     Q3UrlOperator url, oldUrl;
01029     QWidget *infoPreviewWidget, *contentsPreviewWidget;
01030     Q3FilePreview *infoPreviewer, *contentsPreviewer;
01031     bool hadDotDot;
01032 
01033     bool ignoreNextKeyPress;
01034     // ignores the next refresh operation in case the user forced a selection
01035     bool ignoreNextRefresh;
01036     QFDProgressDialog *progressDia;
01037     bool checkForFilter;
01038     bool ignoreStop;
01039 
01040     QTimer *mimeTypeTimer;
01041     const Q3NetworkOperation *currListChildren;
01042 
01043     // this is similar to QUrl::encode but does encode "*" and
01044     // doesn't encode whitespaces
01045     static QString encodeFileName(const QString& fName) {
01046 
01047         QString newStr;
01048         Q3CString cName = fName.utf8();
01049         const Q3CString sChars(
01050 #ifdef Q_WS_WIN
01051             "#%"
01052 #else
01053             "<>#@\"&%$:,;?={}|^~[]\'`\\*"
01054 #endif
01055            );
01056 
01057         int len = cName.length();
01058         if (!len)
01059             return QString();
01060         for (int i = 0; i < len ;++i) {
01061             uchar inCh = (uchar)cName[i];
01062             if (inCh >= 128 || sChars.contains(inCh))
01063             {
01064                 newStr += QChar('%');
01065                 ushort c = inCh / 16;
01066                 c += c > 9 ? 'A' - 10 : '0';
01067                 newStr += (char)c;
01068                 c = inCh % 16;
01069                 c += c > 9 ? 'A' - 10 : '0';
01070                 newStr += (char)c;
01071             } else {
01072                 newStr += (char)inCh;
01073             }
01074         }
01075         return newStr;
01076     }
01077 
01078     static bool fileExists(const Q3UrlOperator &url, const QString& name)
01079     {
01080         Q3Url u(url, Q3FileDialogPrivate::encodeFileName(name));
01081         if (u.isLocalFile()) {
01082             QFileInfo f(u.path());
01083             return f.exists();
01084         } else {
01085             Q3NetworkProtocol *p = Q3NetworkProtocol::getNetworkProtocol(url.protocol());
01086             if (p && (p->supportedOperations()&Q3NetworkProtocol::OpListChildren)) {
01087                 QUrlInfo ui(url.info(name.isEmpty() ? QString::fromLatin1(".") : name));
01088                 return ui.isValid();
01089             }
01090         }
01091         return true;
01092     }
01093 
01094 #ifndef Q_NO_CURSOR
01095     bool cursorOverride; // Remember if the cursor was overridden or not.
01096 #endif
01097 };
01098 
01099 Q3FileDialogPrivate::~Q3FileDialogPrivate()
01100 {
01101     delete modeButtons;
01102 }
01103 
01104 
01105 
01106 /************************************************************************
01107  *
01108  * Internal class QRenameEdit
01109  *
01110  ************************************************************************/
01111 
01112 void QRenameEdit::keyPressEvent(QKeyEvent *e)
01113 {
01114     if (e->key() == Qt::Key_Escape)
01115         emit cancelRename();
01116     else
01117         QLineEdit::keyPressEvent(e);
01118     e->accept();
01119 }
01120 
01121 void QRenameEdit::focusOutEvent(QFocusEvent *)
01122 {
01123     if (!doRenameAlreadyEmitted) {
01124         doRenameAlreadyEmitted = true;
01125         emit doRename();
01126     }
01127 }
01128 
01129 void QRenameEdit::slotReturnPressed()
01130 {
01131     doRenameAlreadyEmitted = true;
01132     emit doRename();
01133 }
01134 
01135 /************************************************************************
01136  *
01137  * Internal class QFileListBox
01138  *
01139  ************************************************************************/
01140 
01141 QFileListBox::QFileListBox(QWidget *parent, Q3FileDialog *dlg)
01142     : Q3ListBox(parent, "filelistbox"), filedialog(dlg),
01143       renaming(false), renameItem(0), mousePressed(false),
01144       firstMousePressEvent(true)
01145 {
01146     changeDirTimer = new QTimer(this);
01147     Q3VBox *box = new Q3VBox(viewport(), "qt_vbox");
01148     box->setFrameStyle(QFrame::Box | QFrame::Plain);
01149     lined = new QRenameEdit(box);
01150     lined->setFixedHeight(lined->sizeHint().height());
01151     box->hide();
01152     box->setBackgroundRole(QPalette::Base);
01153     renameTimer = new QTimer(this);
01154     connect(lined, SIGNAL(doRename()),
01155              this, SLOT (rename()));
01156     connect(lined, SIGNAL(cancelRename()),
01157              this, SLOT(cancelRename()));
01158     connect(renameTimer, SIGNAL(timeout()),
01159              this, SLOT(doubleClickTimeout()));
01160     connect(changeDirTimer, SIGNAL(timeout()),
01161              this, SLOT(changeDirDuringDrag()));
01162     connect(this, SIGNAL(contentsMoving(int,int)),
01163              this, SLOT(contentsMoved(int,int)));
01164     viewport()->setAcceptDrops(true);
01165     dragItem = 0;
01166 }
01167 
01168 void QFileListBox::show()
01169 {
01170     setBackgroundRole(QPalette::Base);
01171     viewport()->setBackgroundRole(QPalette::Base);
01172     Q3ListBox::show();
01173 }
01174 
01175 void QFileListBox::keyPressEvent(QKeyEvent *e)
01176 {
01177     if ((e->key() == Qt::Key_Enter ||
01178            e->key() == Qt::Key_Return) &&
01179          renaming)
01180         return;
01181 
01182     QString keyPressed = ((QKeyEvent *)e)->text().toLower();
01183     QChar keyChar = keyPressed[0];
01184     if (keyChar.isLetterOrNumber()) {
01185         Q3ListBoxItem * i = 0;
01186         if (currentItem())
01187         i = item(currentItem());
01188         else
01189         i = firstItem();
01190         if (i->next())
01191         i = i->next();
01192         else
01193         i = firstItem();
01194         while (i != item(currentItem())) {
01195             QString it = text(index(i));
01196             if (it[0].toLower() == keyChar) {
01197             clearSelection();
01198             setCurrentItem(i);
01199             } else {
01200             if (i->next())
01201             i = i->next();
01202             else
01203             i = firstItem();
01204             }
01205         }
01206     }
01207     cancelRename();
01208     Q3ListBox::keyPressEvent(e);
01209 }
01210 
01211 void QFileListBox::viewportMousePressEvent(QMouseEvent *e)
01212 {
01213     pressPos = e->pos();
01214     mousePressed = false;
01215 
01216     bool didRename = renaming;
01217 
01218     cancelRename();
01219     if (!hasFocus() && !viewport()->hasFocus())
01220         setFocus();
01221 
01222     if (e->button() != Qt::LeftButton) {
01223         Q3ListBox::viewportMousePressEvent(e);
01224         firstMousePressEvent = false;
01225         return;
01226     }
01227 
01228     int i = currentItem();
01229     bool wasSelected = false;
01230     if (i != -1)
01231         wasSelected = item(i)->isSelected();
01232     Q3ListBox::mousePressEvent(e);
01233 
01234     Q3FileDialogPrivate::MCItem *i1 = (Q3FileDialogPrivate::MCItem*)item(currentItem());
01235     if (i1)
01236         mousePressed =  (!((Q3FileDialogPrivate::File*)i1->i)->info.isDir())
01237                         || (filedialog->mode() == Q3FileDialog::Directory) || (filedialog->mode() == Q3FileDialog::DirectoryOnly);
01238 
01239     if (itemAt(e->pos()) != item(i)) {
01240         firstMousePressEvent = false;
01241         return;
01242     }
01243 
01244      if (!firstMousePressEvent && !didRename && i == currentItem() && currentItem() != -1 &&
01245           wasSelected && QUrlInfo(filedialog->d->url.info(".")).isWritable() && item(currentItem())->text() != "..") {
01246         renameTimer->start(QApplication::doubleClickInterval(), true);
01247         renameItem = item(i);
01248     }
01249 
01250     firstMousePressEvent = false;
01251 }
01252 
01253 void QFileListBox::viewportMouseReleaseEvent(QMouseEvent *e)
01254 {
01255     dragItem = 0;
01256     Q3ListBox::viewportMouseReleaseEvent(e);
01257     mousePressed = false;
01258 }
01259 
01260 void QFileListBox::viewportMouseDoubleClickEvent(QMouseEvent *e)
01261 {
01262     renameTimer->stop();
01263     Q3ListBox::viewportMouseDoubleClickEvent(e);
01264 }
01265 
01266 void QFileListBox::viewportMouseMoveEvent(QMouseEvent *e)
01267 {
01268     if (!dragItem)
01269         dragItem = itemAt(e->pos());
01270     renameTimer->stop();
01271 #ifndef QT_NO_DRAGANDDROP
01272     if ( (pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance() && mousePressed) {
01273         Q3ListBoxItem *item = dragItem;
01274         dragItem = 0;
01275         if (item) {
01276             if (!itemRect(item).contains(e->pos()))
01277                 return;
01278             Q3UriDrag* drag = new Q3UriDrag(viewport());
01279             QStringList files;
01280             if (filedialog->mode() == Q3FileDialog::ExistingFiles)
01281                 files = filedialog->selectedFiles();
01282             else
01283                 files = QStringList(filedialog->selectedFile());
01284             drag->setFileNames(files);
01285 
01286             if (lined->parentWidget()->isVisible())
01287                 cancelRename();
01288 
01289             connect(drag, SIGNAL(destroyed()),
01290                      this, SLOT(dragObjDestroyed()));
01291             drag->drag();
01292 
01293             mousePressed = false;
01294         }
01295     } else
01296 #endif
01297     {
01298         Q3ListBox::viewportMouseMoveEvent(e);
01299     }
01300 
01301 }
01302 
01303 void QFileListBox::dragObjDestroyed()
01304 {
01305 #ifndef QT_NO_DRAGANDDROP
01306     //#######
01307     //filedialog->rereadDir();
01308 #endif
01309 }
01310 
01311 #ifndef QT_NO_DRAGANDDROP
01312 void QFileListBox::viewportDragEnterEvent(QDragEnterEvent *e)
01313 {
01314     startDragUrl = filedialog->d->url;
01315     startDragDir = filedialog->dirPath();
01316     currDropItem = 0;
01317 
01318     if (!Q3UriDrag::canDecode(e)) {
01319         e->ignore();
01320         return;
01321     }
01322 
01323     QStringList l;
01324     Q3UriDrag::decodeLocalFiles(e, l);
01325     urls = (int)l.count();
01326 
01327     if (acceptDrop(e->pos(), e->source())) {
01328         e->accept();
01329         setCurrentDropItem(e->pos());
01330     } else {
01331         e->ignore();
01332         setCurrentDropItem(QPoint(-1, -1));
01333     }
01334 
01335     oldDragPos = e->pos();
01336 }
01337 
01338 void QFileListBox::viewportDragMoveEvent(QDragMoveEvent *e)
01339 {
01340     if (acceptDrop(e->pos(), e->source())) {
01341         switch (e->action()) {
01342         case QDropEvent::Copy:
01343             e->acceptAction();
01344             break;
01345         case QDropEvent::Move:
01346             e->acceptAction();
01347             break;
01348         case QDropEvent::Link:
01349             break;
01350         default:
01351             break;
01352         }
01353         if (oldDragPos != e->pos())
01354             setCurrentDropItem(e->pos());
01355     } else {
01356         changeDirTimer->stop();
01357         e->ignore();
01358         setCurrentDropItem(QPoint(-1, -1));
01359     }
01360 
01361     oldDragPos = e->pos();
01362 }
01363 
01364 void QFileListBox::viewportDragLeaveEvent(QDragLeaveEvent *)
01365 {
01366     changeDirTimer->stop();
01367     setCurrentDropItem(QPoint(-1, -1));
01368 //########
01369 //     if (startDragDir != filedialog->d->url)
01370 //        filedialog->setUrl(startDragUrl);
01371 }
01372 
01373 void QFileListBox::viewportDropEvent(QDropEvent *e)
01374 {
01375     changeDirTimer->stop();
01376 
01377     if (!Q3UriDrag::canDecode(e)) {
01378         e->ignore();
01379         return;
01380     }
01381 
01382     Q3StrList l;
01383     Q3UriDrag::decode(e, l);
01384 
01385     bool move = e->action() == QDropEvent::Move;
01386 //     bool supportAction = move || e->action() == QDropEvent::Copy;
01387 
01388     Q3UrlOperator dest;
01389     if (currDropItem)
01390         dest = Q3UrlOperator(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text()));
01391     else
01392         dest = filedialog->d->url;
01393     QStringList lst;
01394     for (uint i = 0; i < l.count(); ++i) {
01395         lst << l.at(i);
01396     }
01397 
01398     filedialog->d->url.copy(lst, dest, move);
01399 
01400     // ##### what is supportAction for?
01401     e->acceptAction();
01402     currDropItem = 0;
01403 }
01404 
01405 bool QFileListBox::acceptDrop(const QPoint &pnt, QWidget *source)
01406 {
01407     Q3ListBoxItem *item = itemAt(pnt);
01408     if (!item || item && !itemRect(item).contains(pnt)) {
01409         if (source == viewport() && startDragDir == filedialog->dirPath())
01410             return false;
01411         return true;
01412     }
01413 
01414     QUrlInfo fi(filedialog->d->url.info(item->text().isEmpty() ? QString::fromLatin1(".") : item->text()));
01415 
01416     if (fi.isDir() && itemRect(item).contains(pnt))
01417         return true;
01418     return false;
01419 }
01420 
01421 void QFileListBox::setCurrentDropItem(const QPoint &pnt)
01422 {
01423     changeDirTimer->stop();
01424 
01425     Q3ListBoxItem *item = 0;
01426     if (pnt != QPoint(-1, -1))
01427         item = itemAt(pnt);
01428     if (item && !QUrlInfo(filedialog->d->url.info(item->text().isEmpty() ? QString::fromLatin1(".") : item->text())).isDir())
01429         item = 0;
01430     if (item && !itemRect(item).contains(pnt))
01431         item = 0;
01432 
01433     currDropItem = item;
01434     if (currDropItem)
01435         setCurrentItem(currDropItem);
01436     changeDirTimer->start(750);
01437 }
01438 #endif // QT_NO_DRAGANDDROP
01439 
01440 void QFileListBox::changeDirDuringDrag()
01441 {
01442 #ifndef QT_NO_DRAGANDDROP
01443     if (!currDropItem)
01444         return;
01445     changeDirTimer->stop();
01446     Q3Url u(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text()));
01447     filedialog->setDir(u);
01448     currDropItem = 0;
01449 #endif
01450 }
01451 
01452 void QFileListBox::doubleClickTimeout()
01453 {
01454     startRename();
01455     renameTimer->stop();
01456 }
01457 
01458 void QFileListBox::startRename(bool check)
01459 {
01460     if (check && (!renameItem || renameItem != item(currentItem())))
01461         return;
01462 
01463     int i = currentItem();
01464     setSelected(i, true);
01465     QRect r = itemRect(item(i));
01466     int bdr = item(i)->pixmap() ?
01467               item(i)->pixmap()->width() : 16;
01468     int x = r.x() + bdr;
01469     int y = r.y();
01470     int w = item(i)->width(this) - bdr;
01471     int h = qMax(lined->height() + 2, r.height());
01472     y = y + r.height() / 2 - h / 2;
01473 
01474     lined->parentWidget()->setGeometry(x, y, w + 6, h);
01475     lined->setFocus();
01476     lined->setText(item(i)->text());
01477     lined->selectAll();
01478     lined->setFrame(false);
01479     lined->parentWidget()->show();
01480     viewport()->setFocusProxy(lined);
01481     renaming = true;
01482 }
01483 
01484 void QFileListBox::clear()
01485 {
01486     cancelRename();
01487     Q3ListBox::clear();
01488 }
01489 
01490 void QFileListBox::rename()
01491 {
01492     if (!lined->text().isEmpty()) {
01493         QString file = currentText();
01494 
01495         if (lined->text() != file)
01496             filedialog->d->url.rename(file, lined->text());
01497     }
01498     cancelRename();
01499 }
01500 
01501 void QFileListBox::cancelRename()
01502 {
01503     renameItem = 0;
01504     lined->parentWidget()->hide();
01505     viewport()->setFocusProxy(this);
01506     renaming = false;
01507     updateItem(currentItem());
01508     if (lined->hasFocus())
01509         viewport()->setFocus();
01510 }
01511 
01512 void QFileListBox::contentsMoved(int, int)
01513 {
01514     changeDirTimer->stop();
01515 #ifndef QT_NO_DRAGANDDROP
01516     setCurrentDropItem(QPoint(-1, -1));
01517 #endif
01518 }
01519 
01520 /************************************************************************
01521  *
01522  * Internal class QFileListView
01523  *
01524  ************************************************************************/
01525 
01526 Q3FileDialogQFileListView::Q3FileDialogQFileListView(QWidget *parent, Q3FileDialog *dlg)
01527     : Q3ListView(parent, "qt_filedlg_listview"), renaming(false), renameItem(0),
01528     filedialog(dlg), mousePressed(false),
01529     firstMousePressEvent(true)
01530 {
01531     changeDirTimer = new QTimer(this);
01532     Q3VBox *box = new Q3VBox(viewport(), "qt_vbox");
01533     box->setFrameStyle(QFrame::Box | QFrame::Plain);
01534     lined = new QRenameEdit(box);
01535     lined->setFixedHeight(lined->sizeHint().height());
01536     box->hide();
01537     box->setBackgroundRole(QPalette::Base);
01538     renameTimer = new QTimer(this);
01539     connect(lined, SIGNAL(doRename()),
01540              this, SLOT (rename()));
01541     connect(lined, SIGNAL(cancelRename()),
01542              this, SLOT(cancelRename()));
01543     header()->setMovingEnabled(false);
01544     connect(renameTimer, SIGNAL(timeout()),
01545              this, SLOT(doubleClickTimeout()));
01546     connect(changeDirTimer, SIGNAL(timeout()),
01547              this, SLOT(changeDirDuringDrag()));
01548     disconnect(header(), SIGNAL(sectionClicked(int)),
01549                 this, SLOT(changeSortColumn(int)));
01550     connect(header(), SIGNAL(sectionClicked(int)),
01551              this, SLOT(changeSortColumn2(int)));
01552     connect(this, SIGNAL(contentsMoving(int,int)),
01553              this, SLOT(contentsMoved(int,int)));
01554 
01555     viewport()->setAcceptDrops(true);
01556     sortcolumn = 0;
01557     ascending = true;
01558     dragItem = 0;
01559 }
01560 
01561 void Q3FileDialogQFileListView::setSorting(int column, bool increasing)
01562 {
01563     if (column == -1) {
01564         Q3ListView::setSorting(column, increasing);
01565         return;
01566     }
01567 
01568     sortAscending = ascending = increasing;
01569     sortcolumn = column;
01570     switch (column) {
01571     case 0:
01572         sortFilesBy = QDir::Name;
01573         break;
01574     case 1:
01575         sortFilesBy = QDir::Size;
01576         break;
01577     case 3:
01578         sortFilesBy = QDir::Time;
01579         break;
01580     default:
01581         sortFilesBy = QDir::Name; // #### ???
01582         break;
01583     }
01584 
01585     filedialog->resortDir();
01586 }
01587 
01588 void Q3FileDialogQFileListView::changeSortColumn2(int column)
01589 {
01590     int lcol = header()->mapToLogical(column);
01591     setSorting(lcol, sortcolumn == lcol ? !ascending : true);
01592 }
01593 
01594 void Q3FileDialogQFileListView::keyPressEvent(QKeyEvent *e)
01595 {
01596     if ((e->key() == Qt::Key_Enter ||
01597            e->key() == Qt::Key_Return) &&
01598          renaming)
01599         return;
01600 
01601     QString keyPressed = e->text().toLower();
01602     QChar keyChar = keyPressed[0];
01603     if (keyChar.isLetterOrNumber()) {
01604         Q3ListViewItem * i = 0;
01605         if (currentItem())
01606         i = currentItem();
01607         else
01608         i = firstChild();
01609         if (i->nextSibling())
01610         i = i->nextSibling();
01611         else
01612         i = firstChild();
01613         while (i != currentItem()) {
01614             QString it = i->text(0);
01615             if (it[0].toLower() == keyChar) {
01616             clearSelection();
01617             ensureItemVisible(i);
01618             setCurrentItem(i);
01619             } else {
01620             if (i->nextSibling())
01621             i = i->nextSibling();
01622             else
01623             i = firstChild();
01624             }
01625         }
01626         return;
01627     }
01628 
01629     cancelRename();
01630     Q3ListView::keyPressEvent(e);
01631 }
01632 
01633 void Q3FileDialogQFileListView::viewportMousePressEvent(QMouseEvent *e)
01634 {
01635     pressPos = e->pos();
01636     mousePressed = false;
01637 
01638     bool didRename = renaming;
01639     cancelRename();
01640     if (!hasFocus() && !viewport()->hasFocus())
01641         setFocus();
01642 
01643     if (e->button() != Qt::LeftButton) {
01644         Q3ListView::viewportMousePressEvent(e);
01645         firstMousePressEvent = false;
01646         return;
01647     }
01648 
01649     Q3ListViewItem *i = currentItem();
01650     Q3ListView::viewportMousePressEvent(e);
01651 
01652     Q3FileDialogPrivate::File *i1 = (Q3FileDialogPrivate::File*)currentItem();
01653     if (i1)
01654         mousePressed = !i1->info.isDir() || (filedialog->mode() == Q3FileDialog::Directory) || (filedialog->mode() == Q3FileDialog::DirectoryOnly);
01655 
01656 
01657     if (itemAt(e->pos()) != i ||
01658          e->x() + contentsX() > columnWidth(0)) {
01659         firstMousePressEvent = false;
01660         return;
01661     }
01662 
01663     if (!firstMousePressEvent && !didRename && i == currentItem() && currentItem() &&
01664          QUrlInfo(filedialog->d->url.info(".")).isWritable() && currentItem()->text(0) != "..") {
01665         renameTimer->start(QApplication::doubleClickInterval(), true);
01666         renameItem = currentItem();
01667     }
01668 
01669     firstMousePressEvent = false;
01670 }
01671 
01672 void Q3FileDialogQFileListView::viewportMouseDoubleClickEvent(QMouseEvent *e)
01673 {
01674     renameTimer->stop();
01675     Q3ListView::viewportMouseDoubleClickEvent(e);
01676 }
01677 
01678 void Q3FileDialogQFileListView::viewportMouseReleaseEvent(QMouseEvent *e)
01679 {
01680     Q3ListView::viewportMouseReleaseEvent(e);
01681     mousePressed = false;
01682     dragItem = 0;
01683 }
01684 
01685 void Q3FileDialogQFileListView::viewportMouseMoveEvent(QMouseEvent *e)
01686 {
01687     renameTimer->stop();
01688     if (!dragItem)
01689         dragItem = itemAt(e->pos());
01690 #ifndef QT_NO_DRAGANDDROP
01691     if ( (pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance() && mousePressed) {
01692         Q3ListViewItem *item = dragItem;
01693         dragItem = 0;
01694         if (item) {
01695             Q3UriDrag* drag = new Q3UriDrag(viewport());
01696             QStringList files;
01697             if (filedialog->mode() == Q3FileDialog::ExistingFiles)
01698                 files = filedialog->selectedFiles();
01699             else
01700                 files = QStringList(filedialog->selectedFile());
01701             drag->setFileNames(files);
01702 
01703             if (lined->isVisible())
01704                 cancelRename();
01705 
01706             connect(drag, SIGNAL(destroyed()),
01707                      this, SLOT(dragObjDestroyed()));
01708             drag->drag();
01709 
01710             mousePressed = false;
01711         }
01712     }
01713 #endif
01714 }
01715 
01716 void Q3FileDialogQFileListView::dragObjDestroyed()
01717 {
01718 #ifndef QT_NO_DRAGANDDROP
01719     //######
01720     //filedialog->rereadDir();
01721 #endif
01722 }
01723 
01724 #ifndef QT_NO_DRAGANDDROP
01725 void Q3FileDialogQFileListView::viewportDragEnterEvent(QDragEnterEvent *e)
01726 {
01727     startDragUrl = filedialog->d->url;
01728     startDragDir = filedialog->dirPath();
01729     currDropItem = 0;
01730 
01731     if (!Q3UriDrag::canDecode(e)) {
01732         e->ignore();
01733         return;
01734     }
01735 
01736     QStringList l;
01737     Q3UriDrag::decodeLocalFiles(e, l);
01738     urls = (int)l.count();
01739 
01740     if (acceptDrop(e->pos(), e->source())) {
01741         e->accept();
01742         setCurrentDropItem(e->pos());
01743     } else {
01744         e->ignore();
01745         setCurrentDropItem(QPoint(-1, -1));
01746     }
01747 
01748     oldDragPos = e->pos();
01749 }
01750 
01751 void Q3FileDialogQFileListView::viewportDragMoveEvent(QDragMoveEvent *e)
01752 {
01753     if (acceptDrop(e->pos(), e->source())) {
01754         if (oldDragPos != e->pos())
01755             setCurrentDropItem(e->pos());
01756         switch (e->action()) {
01757         case QDropEvent::Copy:
01758             e->acceptAction();
01759             break;
01760         case QDropEvent::Move:
01761             e->acceptAction();
01762             break;
01763         case QDropEvent::Link:
01764             break;
01765         default:
01766             break;
01767         }
01768     } else {
01769         changeDirTimer->stop();
01770         e->ignore();
01771         setCurrentDropItem(QPoint(-1, -1));
01772     }
01773 
01774     oldDragPos = e->pos();
01775 }
01776 
01777 void Q3FileDialogQFileListView::viewportDragLeaveEvent(QDragLeaveEvent *)
01778 {
01779     changeDirTimer->stop();
01780     setCurrentDropItem(QPoint(-1, -1));
01781 //########
01782 //     if (startDragDir != filedialog->d->url)
01783 //        filedialog->setUrl(startDragUrl);
01784 }
01785 
01786 void Q3FileDialogQFileListView::viewportDropEvent(QDropEvent *e)
01787 {
01788     changeDirTimer->stop();
01789 
01790     if (!Q3UriDrag::canDecode(e)) {
01791         e->ignore();
01792         return;
01793     }
01794 
01795     QStringList l;
01796     Q3UriDrag::decodeToUnicodeUris(e, l);
01797 
01798     bool move = e->action() == QDropEvent::Move;
01799 //     bool supportAction = move || e->action() == QDropEvent::Copy;
01800 
01801     Q3UrlOperator dest;
01802     if (currDropItem)
01803         dest = Q3UrlOperator(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text(0)));
01804     else
01805         dest = filedialog->d->url;
01806     filedialog->d->url.copy(l, dest, move);
01807 
01808     // ##### what is supportAction for?
01809     e->acceptAction();
01810     currDropItem = 0;
01811 }
01812 
01813 bool Q3FileDialogQFileListView::acceptDrop(const QPoint &pnt, QWidget *source)
01814 {
01815     Q3ListViewItem *item = itemAt(pnt);
01816     if (!item || item && !itemRect(item).contains(pnt)) {
01817         if (source == viewport() && startDragDir == filedialog->dirPath())
01818             return false;
01819         return true;
01820     }
01821 
01822     QUrlInfo fi(filedialog->d->url.info(item->text(0).isEmpty() ? QString::fromLatin1(".") : item->text(0)));
01823 
01824     if (fi.isDir() && itemRect(item).contains(pnt))
01825         return true;
01826     return false;
01827 }
01828 
01829 void Q3FileDialogQFileListView::setCurrentDropItem(const QPoint &pnt)
01830 {
01831     changeDirTimer->stop();
01832 
01833     Q3ListViewItem *item = itemAt(pnt);
01834     if (pnt == QPoint(-1, -1))
01835         item = 0;
01836     if (item && !QUrlInfo(filedialog->d->url.info(item->text(0).isEmpty() ? QString::fromLatin1(".") : item->text(0))).isDir())
01837         item = 0;
01838 
01839     if (item && !itemRect(item).contains(pnt))
01840         item = 0;
01841 
01842     currDropItem = item;
01843 
01844     if (currDropItem)
01845         setCurrentItem(currDropItem);
01846 
01847     changeDirTimer->start(750);
01848 }
01849 #endif // QT_NO_DRAGANDDROP
01850 
01851 void Q3FileDialogQFileListView::changeDirDuringDrag()
01852 {
01853 #ifndef QT_NO_DRAGANDDROP
01854     if (!currDropItem)
01855         return;
01856     changeDirTimer->stop();
01857     Q3Url u(filedialog->d->url, Q3FileDialogPrivate::encodeFileName(currDropItem->text(0)));
01858     filedialog->setDir(u);
01859     currDropItem = 0;
01860 #endif // QT_NO_DRAGANDDROP
01861 }
01862 
01863 
01864 void Q3FileDialogQFileListView::doubleClickTimeout()
01865 {
01866     startRename();
01867     renameTimer->stop();
01868 }
01869 
01870 void Q3FileDialogQFileListView::startRename(bool check)
01871 {
01872     if (check && (!renameItem || renameItem != currentItem()))
01873         return;
01874 
01875     Q3ListViewItem *i = currentItem();
01876     setSelected(i, true);
01877 
01878     QRect r = itemRect(i);
01879     int bdr = i->pixmap(0) ?
01880               i->pixmap(0)->width() : 16;
01881     int x = r.x() + bdr;
01882     int y = r.y();
01883     int w = columnWidth(0) - bdr;
01884     int h = qMax(lined->height() + 2, r.height());
01885     y = y + r.height() / 2 - h / 2;
01886 
01887     lined->parentWidget()->setGeometry(x, y, w + 6, h);
01888     lined->setFocus();
01889     lined->setText(i->text(0));
01890     lined->selectAll();
01891     lined->setFrame(false);
01892     lined->parentWidget()->show();
01893     viewport()->setFocusProxy(lined);
01894     renaming = true;
01895 }
01896 
01897 void Q3FileDialogQFileListView::clear()
01898 {
01899     cancelRename();
01900     Q3ListView::clear();
01901 }
01902 
01903 void Q3FileDialogQFileListView::rename()
01904 {
01905     if (!lined->text().isEmpty()) {
01906         QString file = currentItem()->text(0);
01907 
01908         if (lined->text() != file)
01909             filedialog->d->url.rename(file, lined->text());
01910     }
01911     cancelRename();
01912 }
01913 
01914 void Q3FileDialogQFileListView::cancelRename()
01915 {
01916     renameItem = 0;
01917     lined->parentWidget()->hide();
01918     viewport()->setFocusProxy(this);
01919     renaming = false;
01920     if (currentItem())
01921         currentItem()->repaint();
01922     if (lined->hasFocus())
01923         viewport()->setFocus();
01924 }
01925 
01926 void Q3FileDialogQFileListView::contentsMoved(int, int)
01927 {
01928     changeDirTimer->stop();
01929 #ifndef QT_NO_DRAGANDDROP
01930     setCurrentDropItem(QPoint(-1, -1));
01931 #endif
01932 }
01933 
01934 
01935 Q3FileDialogPrivate::File::~File()
01936 {
01937     if (d->pendingItems.findRef(this))
01938         d->pendingItems.removeRef(this);
01939 }
01940 
01941 QString Q3FileDialogPrivate::File::text(int column) const
01942 {
01943     makeVariables();
01944 
01945     switch(column) {
01946     case 0:
01947         return info.name();
01948     case 1:
01949         if (info.isFile()) {
01950             QIODevice::Offset size = info.size();
01951             return QString::number(size);
01952         } else {
01953             return QString::fromLatin1("");
01954         }
01955     case 2:
01956         if (info.isFile() && info.isSymLink()) {
01957             return d->symLinkToFile;
01958         } else if (info.isFile()) {
01959             return d->file;
01960         } else if (info.isDir() && info.isSymLink()) {
01961             return d->symLinkToDir;
01962         } else if (info.isDir()) {
01963             return d->dir;
01964         } else if (info.isSymLink()) {
01965             return d->symLinkToSpecial;
01966         } else {
01967             return d->special;
01968         }
01969     case 3: {
01970         return info.lastModified().toString(Qt::LocalDate);
01971     }
01972     case 4:
01973         if (info.isReadable())
01974             return info.isWritable() ? d->rw : d->ro;
01975         else
01976             return info.isWritable() ? d->wo : d->inaccessible;
01977     }
01978 
01979     return QString::fromLatin1("<--->");
01980 }
01981 
01982 const QPixmap * Q3FileDialogPrivate::File::pixmap(int column) const
01983 {
01984     if (column) {
01985         return 0;
01986     } else if (Q3ListViewItem::pixmap(column)) {
01987         return Q3ListViewItem::pixmap(column);
01988     } else if (info.isSymLink()) {
01989         if (info.isFile())
01990             return symLinkFileIcon;
01991         else
01992             return symLinkDirIcon;
01993     } else if (info.isDir()) {
01994         return closedFolderIcon;
01995     } else if (info.isFile()) {
01996         return fileIcon;
01997     } else {
01998         return fifteenTransparentPixels;
01999     }
02000 }
02001 
02002 Q3FileDialogPrivate::MCItem::MCItem(Q3ListBox * lb, Q3ListViewItem * item)
02003     : Q3ListBoxItem()
02004 {
02005     i = item;
02006     if (lb)
02007         lb->insertItem(this);
02008 }
02009 
02010 Q3FileDialogPrivate::MCItem::MCItem(Q3ListBox * lb, Q3ListViewItem * item, Q3ListBoxItem *after)
02011     : Q3ListBoxItem()
02012 {
02013     i = item;
02014     if (lb)
02015         lb->insertItem(this, after);
02016 }
02017 
02018 QString Q3FileDialogPrivate::MCItem::text() const
02019 {
02020     return i->text(0);
02021 }
02022 
02023 
02024 const QPixmap *Q3FileDialogPrivate::MCItem::pixmap() const
02025 {
02026     return i->pixmap(0);
02027 }
02028 
02029 
02030 int Q3FileDialogPrivate::MCItem::height(const Q3ListBox * lb) const
02031 {
02032     int hf = lb->fontMetrics().height();
02033     int hp = pixmap() ? pixmap()->height() : 0;
02034     return qMax(hf, hp) + 2;
02035 }
02036 
02037 
02038 int Q3FileDialogPrivate::MCItem::width(const Q3ListBox * lb) const
02039 {
02040     QFontMetrics fm = lb->fontMetrics();
02041     int w = 2;
02042     if (pixmap())
02043         w += pixmap()->width() + 4;
02044     else
02045         w += 18;
02046     w += fm.width(text());
02047     w += -fm.minLeftBearing();
02048     w += -fm.minRightBearing();
02049     w += 6;
02050     return w;
02051 }
02052 
02053 
02054 void Q3FileDialogPrivate::MCItem::paint(QPainter * ptr)
02055 {
02056     QFontMetrics fm = ptr->fontMetrics();
02057 
02058     int h;
02059 
02060     if (pixmap())
02061         h = qMax(fm.height(), pixmap()->height()) + 2;
02062     else
02063         h = fm.height() + 2;
02064 
02065     const QPixmap * pm = pixmap();
02066     if (pm)
02067         ptr->drawPixmap(2, 1, *pm);
02068 
02069     ptr->drawText(pm ? pm->width() + 4 : 22, h - fm.descent() - 2,
02070                    text());
02071 }
02072 
02073 static QStringList makeFiltersList(const QString &filter)
02074 {
02075     if (filter.isEmpty())
02076         return QStringList();
02077 
02078     int i = filter.indexOf(";;", 0);
02079     QString sep(";;");
02080     if (i == -1) {
02081         if (filter.contains('\n')) {
02082             sep = "\n";
02083             i = filter.indexOf(sep);
02084         }
02085     }
02086 
02087     return QStringList::split(sep, filter);
02088 }
02089 
02305 extern const char qt3_file_dialog_filter_reg_exp[] = "([a-zA-Z0-9]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$";
02306 
02313 Q3FileDialog::Q3FileDialog(QWidget *parent, const char *name, bool modal)
02314     : QDialog(parent, name, modal,
02315                (modal ?
02316                 (Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu) : Qt::WindowFlags(0)))
02317 {
02318     init();
02319     d->mode = ExistingFile;
02320     d->types->insertItem(tr("All Files (*)"));
02321     d->cursorOverride = false;
02322     emit dirEntered(d->url.dirPath());
02323     rereadDir();
02324 }
02325 
02326 
02339 Q3FileDialog::Q3FileDialog(const QString& dirName, const QString & filter,
02340                           QWidget *parent, const char *name, bool modal)
02341     : QDialog(parent, name, modal,
02342               (modal ? (Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu)
02343                : Qt::WindowFlags(0)))
02344 {
02345     init();
02346     d->mode = ExistingFile;
02347     rereadDir();
02348     Q3UrlOperator u(dirName);
02349     if (!dirName.isEmpty() && (!u.isLocalFile() || QDir(dirName).exists()))
02350         setSelection(dirName);
02351     else if (workingDirectory && !workingDirectory->isEmpty())
02352         setDir(*workingDirectory);
02353 
02354     if (!filter.isEmpty()) {
02355         setFilters(filter);
02356         if (!dirName.isEmpty()) {
02357             int dotpos = dirName.indexOf(QChar('.'), 0, Qt::CaseInsensitive);
02358             if (dotpos != -1) {
02359                 for (int b=0 ; b<d->types->count() ; b++) {
02360                     if (d->types->text(b).contains(dirName.right(dirName.length() - dotpos))) {
02361                         d->types->setCurrentItem(b);
02362                         setFilter(d->types->text(b));
02363                         return;
02364                     }
02365                 }
02366             }
02367         }
02368     } else {
02369         d->types->insertItem(tr("All Files (*)"));
02370     }
02371 }
02372 
02373 
02379 void Q3FileDialog::init()
02380 {
02381     setSizeGripEnabled(true);
02382     d = new Q3FileDialogPrivate();
02383     d->mode = AnyFile;
02384     d->last = 0;
02385     d->lastEFSelected = 0;
02386     d->moreFiles = 0;
02387     d->infoPreview = false;
02388     d->contentsPreview = false;
02389     d->hadDotDot = false;
02390     d->ignoreNextKeyPress = false;
02391     d->progressDia = 0;
02392     d->checkForFilter = false;
02393     d->ignoreNextRefresh = false;
02394     d->ignoreStop = false;
02395     d->mimeTypeTimer = new QTimer(this);
02396     d->cursorOverride = false;
02397     connect(d->mimeTypeTimer, SIGNAL(timeout()),
02398              this, SLOT(doMimeTypeLookup()));
02399 
02400     d->url = Q3UrlOperator(::toRootIfNotExists( QDir::currentDirPath() ));
02401     d->oldUrl = d->url;
02402     d->currListChildren = 0;
02403 
02404     connect(&d->url, SIGNAL(start(Q3NetworkOperation*)),
02405              this, SLOT(urlStart(Q3NetworkOperation*)));
02406     connect(&d->url, SIGNAL(finished(Q3NetworkOperation*)),
02407              this, SLOT(urlFinished(Q3NetworkOperation*)));
02408     connect(&d->url, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
02409              this, SLOT(insertEntry(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)));
02410     connect(&d->url, SIGNAL(removed(Q3NetworkOperation*)),
02411              this, SLOT(removeEntry(Q3NetworkOperation*)));
02412     connect(&d->url, SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)),
02413              this, SLOT(createdDirectory(QUrlInfo,Q3NetworkOperation*)));
02414     connect(&d->url, SIGNAL(itemChanged(Q3NetworkOperation*)),
02415              this, SLOT(itemChanged(Q3NetworkOperation*)));
02416     connect(&d->url, SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)),
02417              this, SLOT(dataTransferProgress(int,int,Q3NetworkOperation*)));
02418 
02419     nameEdit = new QLineEdit(this, "name/filter editor");
02420     nameEdit->setMaxLength(255); //_POSIX_MAX_PATH
02421     connect(nameEdit, SIGNAL(textChanged(QString)),
02422              this, SLOT(fileNameEditDone()));
02423     nameEdit->installEventFilter(this);
02424 
02425     d->splitter = new QSplitter(this, "qt_splitter");
02426 
02427     d->stack = new Q3WidgetStack(d->splitter, "files and more files");
02428 
02429     d->splitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
02430 
02431     files = new Q3FileDialogQFileListView(d->stack, this);
02432     QFontMetrics fm = fontMetrics();
02433     files->addColumn(tr("Name"));
02434     files->addColumn(tr("Size"));
02435     files->setColumnAlignment(1, Qt::AlignRight);
02436     files->addColumn(tr("Type"));
02437     files->addColumn(tr("Date"));
02438     files->addColumn(tr("Attributes"));
02439     files->header()->setStretchEnabled(true, 0);
02440 
02441     files->setMinimumSize(50, 25 + 2*fm.lineSpacing());
02442 
02443     connect(files, SIGNAL(selectionChanged()),
02444             this, SLOT(detailViewSelectionChanged()));
02445     connect(files, SIGNAL(currentChanged(Q3ListViewItem*)),
02446             this, SLOT(updateFileNameEdit(Q3ListViewItem*)));
02447     connect(files, SIGNAL(doubleClicked(Q3ListViewItem*)),
02448             this, SLOT(selectDirectoryOrFile(Q3ListViewItem*)));
02449     connect(files, SIGNAL(returnPressed(Q3ListViewItem*)),
02450             this, SLOT(selectDirectoryOrFile(Q3ListViewItem*)));
02451     connect(files, SIGNAL(contextMenuRequested(Q3ListViewItem*,QPoint,int)),
02452             this, SLOT(popupContextMenu(Q3ListViewItem*,QPoint,int)));
02453 
02454     files->installEventFilter(this);
02455     files->viewport()->installEventFilter(this);
02456 
02457     d->moreFiles = new QFileListBox(d->stack, this);
02458     d->moreFiles->setRowMode(Q3ListBox::FitToHeight);
02459     d->moreFiles->setVariableWidth(true);
02460 
02461     connect(d->moreFiles, SIGNAL(selected(Q3ListBoxItem*)),
02462              this, SLOT(selectDirectoryOrFile(Q3ListBoxItem*)));
02463     connect(d->moreFiles, SIGNAL(selectionChanged()),
02464              this, SLOT(listBoxSelectionChanged()));
02465     connect(d->moreFiles, SIGNAL(highlighted(Q3ListBoxItem*)),
02466       this, SLOT(updateFileNameEdit(Q3ListBoxItem*)));
02467     connect(d->moreFiles, SIGNAL(contextMenuRequested(Q3ListBoxItem*,QPoint)),
02468              this, SLOT(popupContextMenu(Q3ListBoxItem*,QPoint)));
02469 
02470     d->moreFiles->installEventFilter(this);
02471     d->moreFiles->viewport()->installEventFilter(this);
02472 
02473     okB = new QPushButton(tr("&OK"), this, "OK"); //### Or "Save (see other "OK")
02474     okB->setDefault(true);
02475     okB->setEnabled(false);
02476     connect(okB, SIGNAL(clicked()), this, SLOT(okClicked()));
02477     cancelB = new QPushButton(tr("Cancel") , this, "Cancel");
02478     connect(cancelB, SIGNAL(clicked()), this, SLOT(cancelClicked()));
02479 
02480     d->paths = new Q3ComboBox(true, this, "directory history/editor");
02481     d->paths->setDuplicatesEnabled(false);
02482     d->paths->setInsertionPolicy(Q3ComboBox::NoInsertion);
02483     makeVariables();
02484 
02485     QFileInfoList rootDrives = QDir::drives();
02486     for (int i = 0; i < rootDrives.size(); ++i) {
02487         QFileInfo fi = rootDrives.at(i);
02488         d->paths->insertItem(*openFolderIcon, fi.absFilePath());
02489     }
02490 
02491     if (QDir::homeDirPath().size()) {
02492         if (!d->paths->listBox()->findItem(QDir::homeDirPath()))
02493             d->paths->insertItem(*openFolderIcon, QDir::homeDirPath());
02494     }
02495 
02496     connect(d->paths, SIGNAL(activated(QString)),
02497              this, SLOT(setDir(QString)));
02498 
02499     d->paths->installEventFilter(this);
02500     QObjectList ol = d->paths->queryList("QLineEdit");
02501     if (ol.size())
02502         ol.at(0)->installEventFilter(this);
02503 
02504     d->geometryDirty = true;
02505     d->types = new QComboBox(true, this, "file types");
02506     d->types->setDuplicatesEnabled(false);
02507     d->types->setEditable(false);
02508     connect(d->types, SIGNAL(activated(QString)),
02509              this, SLOT(setFilter(QString)));
02510     connect(d->types, SIGNAL(activated(QString)),
02511              this, SIGNAL(filterSelected(QString)));
02512 
02513     d->pathL = new QLabel(d->paths, tr("Look &in:"), this, "qt_looin_lbl");
02514     d->fileL = new QLabel(nameEdit, tr("File &name:"), this, "qt_filename_lbl");
02515     d->typeL = new QLabel(d->types, tr("File &type:"), this, "qt_filetype_lbl");
02516 
02517     d->goBack = new QToolButton(this, "go back");
02518     d->goBack->setEnabled(false);
02519     d->goBack->setFocusPolicy(Qt::TabFocus);
02520     connect(d->goBack, SIGNAL(clicked()), this, SLOT(goBack()));
02521 #ifndef QT_NO_TOOLTIP
02522     QToolTip::add(d->goBack, tr("Back"));
02523 #endif
02524     d->goBack->setIconSet(*goBackIcon);
02525 
02526     d->cdToParent = new QToolButton(this, "cd to parent");
02527     d->cdToParent->setFocusPolicy(Qt::TabFocus);
02528 #ifndef QT_NO_TOOLTIP
02529     QToolTip::add(d->cdToParent, tr("One directory up"));
02530 #endif
02531     d->cdToParent->setIconSet(*cdToParentIcon);
02532     connect(d->cdToParent, SIGNAL(clicked()),
02533              this, SLOT(cdUpClicked()));
02534 
02535     d->newFolder = new QToolButton(this, "new folder");
02536     d->newFolder->setFocusPolicy(Qt::TabFocus);
02537 #ifndef QT_NO_TOOLTIP
02538     QToolTip::add(d->newFolder, tr("Create New Folder"));
02539 #endif
02540     d->newFolder->setIconSet(*newFolderIcon);
02541     connect(d->newFolder, SIGNAL(clicked()),
02542              this, SLOT(newFolderClicked()));
02543 
02544     d->modeButtons = new Q3ButtonGroup(0, "invisible group");
02545     connect(d->modeButtons, SIGNAL(destroyed()),
02546              this, SLOT(modeButtonsDestroyed()));
02547     d->modeButtons->setExclusive(true);
02548     connect(d->modeButtons, SIGNAL(clicked(int)),
02549              d->stack, SLOT(raiseWidget(int)));
02550     connect(d->modeButtons, SIGNAL(clicked(int)),
02551              this, SLOT(changeMode(int)));
02552 
02553     d->mcView = new QToolButton(this, "mclistbox view");
02554     d->mcView->setFocusPolicy(Qt::TabFocus);
02555 #ifndef QT_NO_TOOLTIP
02556     QToolTip::add(d->mcView, tr("List View"));
02557 #endif
02558     d->mcView->setIconSet(*multiColumnListViewIcon);
02559     d->mcView->setToggleButton(true);
02560     d->stack->addWidget(d->moreFiles, d->modeButtons->insert(d->mcView));
02561     d->detailView = new QToolButton(this, "list view");
02562     d->detailView->setFocusPolicy(Qt::TabFocus);
02563 #ifndef QT_NO_TOOLTIP
02564     QToolTip::add(d->detailView, tr("Detail View"));
02565 #endif
02566     d->detailView->setIconSet(*detailViewIcon);
02567     d->detailView->setToggleButton(true);
02568     d->stack->addWidget(files, d->modeButtons->insert(d->detailView));
02569 
02570     d->previewInfo = new QToolButton(this, "preview info view");
02571     d->previewInfo->setFocusPolicy(Qt::TabFocus);
02572 #ifndef QT_NO_TOOLTIP
02573     QToolTip::add(d->previewInfo, tr("Preview File Info"));
02574 #endif
02575     d->previewInfo->setIconSet(*previewInfoViewIcon);
02576     d->previewInfo->setToggleButton(true);
02577     d->modeButtons->insert(d->previewInfo);
02578 
02579     d->previewContents = new QToolButton(this, "preview info view");
02580 #if defined(Q_WS_WIN) && !defined(Q_OS_TEMP)
02581     if ((qWinVersion() & Qt::WV_NT_based) > Qt::WV_NT)
02582 #else
02583     if (!qstrcmp(style()->className(), "QWindowsStyle"))
02584 #endif
02585     {
02586         d->goBack->setAutoRaise(true);
02587         d->cdToParent->setAutoRaise(true);
02588         d->newFolder->setAutoRaise(true);
02589         d->mcView->setAutoRaise(true);
02590         d->detailView->setAutoRaise(true);
02591         d->previewInfo->setAutoRaise(true);
02592         d->previewContents->setAutoRaise(true);
02593     }
02594     d->previewContents->setFocusPolicy(Qt::TabFocus);
02595 #ifndef QT_NO_TOOLTIP
02596     QToolTip::add(d->previewContents, tr("Preview File Contents"));
02597 #endif
02598     d->previewContents->setIconSet(*previewContentsViewIcon);
02599     d->previewContents->setToggleButton(true);
02600     d->modeButtons->insert(d->previewContents);
02601 
02602     connect(d->detailView, SIGNAL(clicked()),
02603              d->moreFiles, SLOT(cancelRename()));
02604     connect(d->detailView, SIGNAL(clicked()),
02605              files, SLOT(cancelRename()));
02606     connect(d->mcView, SIGNAL(clicked()),
02607              d->moreFiles, SLOT(cancelRename()));
02608     connect(d->mcView, SIGNAL(clicked()),
02609              files, SLOT(cancelRename()));
02610 
02611     d->stack->raiseWidget(d->moreFiles);
02612     d->mcView->setOn(true);
02613 
02614     QHBoxLayout *lay = new QHBoxLayout(this);
02615     lay->setMargin(6);
02616     d->leftLayout = new QHBoxLayout(lay, 5);
02617     d->topLevelLayout = new QVBoxLayout((QWidget*)0, 5);
02618     lay->addLayout(d->topLevelLayout, 1);
02619 
02620     QHBoxLayout * h;
02621 
02622     d->preview = new Q3WidgetStack(d->splitter, "qt_preview");
02623 
02624     d->infoPreviewWidget = new QWidget(d->preview, "qt_preview_info");
02625     d->contentsPreviewWidget = new QWidget(d->preview, "qt_preview_contents");
02626     d->infoPreviewer = d->contentsPreviewer = 0;
02627 
02628     h = new QHBoxLayout(0);
02629     d->buttonLayout = h;
02630     d->topLevelLayout->addLayout(h);
02631     h->addWidget(d->pathL);
02632     h->addSpacing(8);
02633     h->addWidget(d->paths);
02634     h->addSpacing(8);
02635     if (d->goBack)
02636         h->addWidget(d->goBack);
02637     h->addWidget(d->cdToParent);
02638     h->addSpacing(2);
02639     h->addWidget(d->newFolder);
02640     h->addSpacing(4);
02641     h->addWidget(d->mcView);
02642     h->addWidget(d->detailView);
02643     h->addWidget(d->previewInfo);
02644     h->addWidget(d->previewContents);
02645 
02646     d->topLevelLayout->addWidget(d->splitter);
02647 
02648     h = new QHBoxLayout();
02649     d->topLevelLayout->addLayout(h);
02650     h->addWidget(d->fileL);
02651     h->addWidget(nameEdit);
02652     h->addSpacing(15);
02653     h->addWidget(okB);
02654 
02655     h = new QHBoxLayout();
02656     d->topLevelLayout->addLayout(h);
02657     h->addWidget(d->typeL);
02658     h->addWidget(d->types);
02659     h->addSpacing(15);
02660     h->addWidget(cancelB);
02661 
02662     d->rightLayout = new QHBoxLayout(lay, 5);
02663     d->topLevelLayout->setStretchFactor(d->mcView, 1);
02664     d->topLevelLayout->setStretchFactor(files, 1);
02665 
02666     updateGeometries();
02667 
02668     if (d->goBack) {
02669         setTabOrder(d->paths, d->goBack);
02670         setTabOrder(d->goBack, d->cdToParent);
02671     } else {
02672         setTabOrder(d->paths, d->cdToParent);
02673     }
02674     setTabOrder(d->cdToParent, d->newFolder);
02675     setTabOrder(d->newFolder, d->mcView);
02676     setTabOrder(d->mcView, d->detailView);
02677     setTabOrder(d->detailView, d->moreFiles);
02678     setTabOrder(d->moreFiles, files);
02679     setTabOrder(files, nameEdit);
02680     setTabOrder(nameEdit, d->types);
02681     setTabOrder(d->types, okB);
02682     setTabOrder(okB, cancelB);
02683 
02684     d->rw = tr("Read-write");
02685     d->ro = tr("Read-only");
02686     d->wo = tr("Write-only");
02687     d->inaccessible = tr("Inaccessible");
02688 
02689     d->symLinkToFile = tr("Symlink to File");
02690     d->symLinkToDir = tr("Symlink to Directory");
02691     d->symLinkToSpecial = tr("Symlink to Special");
02692     d->file = tr("File");
02693     d->dir = tr("Dir");
02694     d->special = tr("Special");
02695 
02696     if (lastWidth == 0) {
02697         QRect screen = QApplication::desktop()->screenGeometry(pos());
02698         if (screen.width() < 1024 || screen.height() < 768) {
02699             resize(qMin(screen.width(), 420), qMin(screen.height(), 236));
02700         } else {
02701             QSize s = files->sizeHint();
02702             s = QSize(s.width() + 300, s.height() + 82);
02703 
02704             if (s.width() * 3 > screen.width() * 2)
02705                 s.setWidth(screen.width() * 2 / 3);
02706 
02707             if (s.height() * 3 > screen.height() * 2)
02708                 s.setHeight(screen.height() * 2 / 3);
02709             else if (s.height() * 3 < screen.height())
02710                 s.setHeight(screen.height() / 3);
02711 
02712             resize(s);
02713         }
02714         updateLastSize(this);
02715     } else {
02716         resize(lastWidth, lastHeight);
02717     }
02718 
02719     if (detailViewMode) {
02720         d->stack->raiseWidget(files);
02721         d->mcView->setOn(false);
02722         d->detailView->setOn(true);
02723     }
02724 
02725     d->preview->hide();
02726     nameEdit->setFocus();
02727 
02728     connect(nameEdit, SIGNAL(returnPressed()),
02729              this, SLOT(fileNameEditReturnPressed()));
02730 }
02731 
02736 void Q3FileDialog::fileNameEditReturnPressed()
02737 {
02738     d->oldUrl = d->url;
02739     if (!isDirectoryMode(d->mode)) {
02740         okClicked();
02741     } else {
02742         d->currentFileName.clear();
02743         if (nameEdit->text().isEmpty()) {
02744             emit fileSelected(selectedFile());
02745             accept();
02746         } else {
02747             QUrlInfo f;
02748             Q3FileDialogPrivate::File * c
02749                 = (Q3FileDialogPrivate::File *)files->currentItem();
02750             if (c && files->isSelected(c))
02751                 f = c->info;
02752             else
02753                 f = QUrlInfo(d->url.info(nameEdit->text().isEmpty() ? QString::fromLatin1(".") : nameEdit->text()));
02754             if (f.isDir()) {
02755                 setUrl(Q3UrlOperator(d->url,
02756                                       Q3FileDialogPrivate::encodeFileName(nameEdit->text() + "/")));
02757                 d->checkForFilter = true;
02758                 trySetSelection(true, d->url, true);
02759                 d->checkForFilter = false;
02760             }
02761         }
02762         nameEdit->setText(QString());
02763     }
02764 }
02765 
02771 void Q3FileDialog::updatePreviews(const Q3Url &u)
02772 {
02773     if (d->infoPreviewer)
02774         d->infoPreviewer->previewUrl(u);
02775     if (d->contentsPreviewer)
02776         d->contentsPreviewer->previewUrl(u);
02777 }
02778 
02784 void Q3FileDialog::changeMode(int id)
02785 {
02786     if (!d->infoPreview && !d->contentsPreview)
02787         return;
02788 
02789     QAbstractButton*btn = d->modeButtons->find(id);
02790     if (!btn)
02791         return;
02792 
02793     if (btn == d->previewContents && !d->contentsPreview)
02794         return;
02795     if (btn == d->previewInfo && !d->infoPreview)
02796         return;
02797 
02798     if (btn != d->previewContents && btn != d->previewInfo) {
02799         d->preview->hide();
02800     } else {
02801         if (files->currentItem())
02802             updatePreviews(Q3Url(d->url, files->currentItem()->text(0)));
02803         if (btn == d->previewInfo)
02804             d->preview->raiseWidget(d->infoPreviewWidget);
02805         else
02806             d->preview->raiseWidget(d->contentsPreviewWidget);
02807         d->preview->show();
02808     }
02809 }
02810 
02815 Q3FileDialog::~Q3FileDialog()
02816 {
02817     // since clear might call setContentsPos which would emit
02818     // a signal and thus cause a recompute of sizes...
02819     files->blockSignals(true);
02820     d->moreFiles->blockSignals(true);
02821     files->clear();
02822     d->moreFiles->clear();
02823     d->moreFiles->blockSignals(false);
02824     files->blockSignals(false);
02825 
02826 #ifndef QT_NO_CURSOR
02827     if (d->cursorOverride)
02828         QApplication::restoreOverrideCursor();
02829 #endif
02830 
02831     delete d;
02832     d = 0;
02833 }
02834 
02835 
02847 QString Q3FileDialog::selectedFile() const
02848 {
02849     QString s = d->currentFileName;
02850     // remove the protocol because we do not want to encode it...
02851     QString prot = Q3Url(s).protocol();
02852     if (!prot.isEmpty()) {
02853         prot += ":";
02854         s.remove(0, prot.length());
02855     }
02856     Q3Url u(prot + Q3FileDialogPrivate::encodeFileName(s));
02857     if (u.isLocalFile()) {
02858         QString s = u.toString();
02859         if (s.left(5) == "file:")
02860             s.remove((uint)0, 5);
02861         return s;
02862     }
02863     return d->currentFileName;
02864 }
02865 
02874 QString Q3FileDialog::selectedFilter() const
02875 {
02876     return d->types->currentText();
02877 }
02878 
02887 void Q3FileDialog::setSelectedFilter(int n)
02888 {
02889     d->types->setCurrentItem(n);
02890     QString f = d->types->currentText();
02891     QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
02892     int index = r.indexIn(f);
02893     if (index >= 0)
02894         f = r.cap(2);
02895     d->url.setNameFilter(f);
02896     rereadDir();
02897 }
02898 
02904 void Q3FileDialog::setSelectedFilter(const QString& mask)
02905 {
02906     int n;
02907 
02908     for (n = 0; n < d->types->count(); n++) {
02909         if (d->