diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:17:53 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:17:53 -0500 |
commit | dda8474928bd7276e1fad8fb7a601e7c83ff2bc2 (patch) | |
tree | 7f83910598b33b12730035f086df20b5a53ab99c /tqtinterface/qt4/src/dialogs/tqfiledialog.cpp | |
parent | 6260b6178868c03aab1644bf93b0ef043654bdb0 (diff) | |
download | experimental-dda8474928bd7276e1fad8fb7a601e7c83ff2bc2.tar.gz experimental-dda8474928bd7276e1fad8fb7a601e7c83ff2bc2.zip |
Added TQt4 HEAD
Diffstat (limited to 'tqtinterface/qt4/src/dialogs/tqfiledialog.cpp')
-rw-r--r-- | tqtinterface/qt4/src/dialogs/tqfiledialog.cpp | 6466 |
1 files changed, 6466 insertions, 0 deletions
diff --git a/tqtinterface/qt4/src/dialogs/tqfiledialog.cpp b/tqtinterface/qt4/src/dialogs/tqfiledialog.cpp new file mode 100644 index 0000000..f92e18e --- /dev/null +++ b/tqtinterface/qt4/src/dialogs/tqfiledialog.cpp @@ -0,0 +1,6466 @@ +/**************************************************************************** +** +** Implementation of TQFileDialog class +** +** Created : 950429 +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the dialogs module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqplatformdefs.h" + +// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED. +#if defined(connect) +# undef connect +#endif + +// POSIX Large File Support redefines truncate -> truncate64 +#if defined(truncate) +# undef truncate +#endif + +#include "tqfiledialog.h" + +#ifndef TQT_NO_FILEDIALOG + +#include "private/tqapplication_p.h" +#include "tqapplication.h" +#include "tqbitmap.h" +#include "tqbuttongroup.h" +#include "tqcheckbox.h" +#include "tqcleanuphandler.h" +#include "tqcombobox.h" +#include "tqcstring.h" +#include "tqcursor.h" +#include "tqdragobject.h" +#include "tqfile.h" +#include "tqguardedptr.h" +#include "tqhbox.h" +#include "tqheader.h" +#include "tqlabel.h" +#include "tqlayout.h" +#include "tqlibrary.h" +#include "tqlineedit.h" +#include "tqlistbox.h" +#include "tqlistview.h" +#include "tqmap.h" +#include "tqmessagebox.h" +#include "tqmime.h" +#include "tqnetworkprotocol.h" +#include "tqobjectlist.h" +#include "tqpainter.h" +#include "tqpopupmenu.h" +#include "tqprogressbar.h" +#include "tqptrvector.h" +#include "tqpushbutton.h" +#include "tqregexp.h" +#include "tqsemimodal.h" +#include "tqsplitter.h" +#include "tqstrlist.h" +#include "tqstyle.h" +#include "tqtimer.h" +#include "tqtoolbutton.h" +#include "tqtooltip.h" +#include "tqvbox.h" +#include "tqwidgetstack.h" + +#ifdef TQ_WS_WIN +#ifdef TQT_THREAD_SUPPORT +# include <private/tqmutexpool_p.h> +#endif // TQT_THREAD_SUPPORT +#endif // TQ_WS_WIN + +#if !defined(TQ_OS_TEMP) +#include <time.h> +#else +#include <shellapi.h> +#endif +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> + +#ifdef TQ_WS_MAC +#include "tqt_mac.h" +extern TQString qt_mac_precomposeFileName(const TQString &); // qglobal.cpp +#undef check +#endif + +/* 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 TQPixmap * openFolderIcon = 0; +static TQPixmap * closedFolderIcon = 0; +static TQPixmap * detailViewIcon = 0; +static TQPixmap * multiColumnListViewIcon = 0; +static TQPixmap * cdToParentIcon = 0; +static TQPixmap * newFolderIcon = 0; +static TQPixmap * fifteenTransparentPixels = 0; +static TQPixmap * symLinkDirIcon = 0; +static TQPixmap * symLinkFileIcon = 0; +static TQPixmap * fileIcon = 0; +static TQPixmap * startCopyIcon = 0; +static TQPixmap * endCopyIcon = 0; +static TQPixmap * previewContentsViewIcon = 0; +static TQPixmap * previewInfoViewIcon = 0; +static TQPixmap *goBackIcon = 0; +static TQFileIconProvider * fileIconProvider = 0; +static int lastWidth = 0; +static int lastHeight = 0; +static TQString * workingDirectory = 0; + +static bool bShowHiddenFiles = FALSE; +static int sortFilesBy = (int)TQDir::Name; +static bool sortAscending = TRUE; +static bool detailViewMode = FALSE; + +static TQCleanupHandler<TQPixmap> qfd_cleanup_pixmap; +static TQCleanupHandler<TQString> qfd_cleanup_string; + +static TQString toRootIfNotExists( const TQString &path ) +{ + if ( !path.isEmpty() ) + return path; + + const TQFileInfoList *drives = TQDir::drives(); + TQ_ASSERT( drives && !drives->isEmpty() ); + return drives->getFirst()->filePath(); +} + +static bool isDirectoryMode( int m ) +{ + return m == TQFileDialog::Directory || m == TQFileDialog::DirectoryOnly; +} + +static void updateLastSize( TQFileDialog *that ) +{ + int extWidth = 0; + int extHeight = 0; + if ( that->extension() && that->extension()->isVisible() ) { + if ( that->orientation() == Qt::Vertical ) + extHeight = that->extension()->height(); + else + extWidth = that->extension()->width(); + } + lastWidth = that->width() - extWidth; + lastHeight = that->height() - extHeight; +} + +// Don't remove the lines below! +// +// resolving the W methods manually is needed, because Windows 95 doesn't include +// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol +// when TQt calls getEsistingDirectory(), etc. +#if defined(TQ_WS_WIN) + +typedef UINT (WINAPI *PtrExtractIconEx)(LPCTSTR,int,HICON*,HICON*,UINT); +static PtrExtractIconEx ptrExtractIconEx = 0; + +static void resolveLibs() +{ +#ifndef TQ_OS_TEMP + static bool triedResolve = FALSE; + + if ( !triedResolve ) { +#ifdef TQT_THREAD_SUPPORT + // protect initialization + TQMutexLocker locker( tqt_global_mutexpool ? + tqt_global_mutexpool->get( &triedResolve ) : 0 ); + // check triedResolve again, since another thread may have already + // done the initialization + if ( triedResolve ) { + // another thread did initialize the security function pointers, + // so we shouldn't do it again. + return; + } +#endif + triedResolve = TRUE; + if ( qt_wintqunicode ) { + TQLibrary lib("shell32"); + lib.setAutoUnload( FALSE ); + ptrExtractIconEx = (PtrExtractIconEx) lib.resolve( "ExtractIconExW" ); + } + } +#endif +} +#ifdef TQ_OS_TEMP +#define PtrExtractIconEx ExtractIconEx +#endif + +class TQWindowsIconProvider : public TQFileIconProvider +{ +public: + TQWindowsIconProvider( TQObject *tqparent=0, const char *name=0 ); + ~TQWindowsIconProvider(); + + const TQPixmap * pixmap( const TQFileInfo &fi ); + +private: + TQPixmap defaultFolder; + TQPixmap defaultFile; + TQPixmap defaultExe; + TQPixmap pix; + int pixw, pixh; + TQMap< TQString, TQPixmap > cache; + +}; +#endif + +static void makeVariables() { + if ( !openFolderIcon ) { + workingDirectory = new TQString( ::toRootIfNotExists(TQDir::currentDirPath()) ); + qfd_cleanup_string.add( &workingDirectory ); + + openFolderIcon = new TQPixmap( (const char **)open_xpm); + qfd_cleanup_pixmap.add( &openFolderIcon ); + symLinkDirIcon = new TQPixmap( (const char **)link_dir_xpm); + qfd_cleanup_pixmap.add( &symLinkDirIcon ); + symLinkFileIcon = new TQPixmap( (const char **)link_file_xpm); + qfd_cleanup_pixmap.add( &symLinkFileIcon ); + fileIcon = new TQPixmap( (const char **)file_xpm); + qfd_cleanup_pixmap.add( &fileIcon ); + closedFolderIcon = new TQPixmap( (const char **)closed_xpm); + qfd_cleanup_pixmap.add( &closedFolderIcon ); + detailViewIcon = new TQPixmap( (const char **)detailedview_xpm); + qfd_cleanup_pixmap.add( &detailViewIcon ); + multiColumnListViewIcon = new TQPixmap( (const char **)mclistview_xpm); + qfd_cleanup_pixmap.add( &multiColumnListViewIcon ); + cdToParentIcon = new TQPixmap( (const char **)cdtoparent_xpm); + qfd_cleanup_pixmap.add( &cdToParentIcon ); + newFolderIcon = new TQPixmap( (const char **)newfolder_xpm); + qfd_cleanup_pixmap.add( &newFolderIcon ); + previewInfoViewIcon + = new TQPixmap( (const char **)previewinfoview_xpm ); + qfd_cleanup_pixmap.add( &previewInfoViewIcon ); + previewContentsViewIcon + = new TQPixmap( (const char **)previewcontentsview_xpm ); + qfd_cleanup_pixmap.add( &previewContentsViewIcon ); + startCopyIcon = new TQPixmap( (const char **)start_xpm ); + qfd_cleanup_pixmap.add( &startCopyIcon ); + endCopyIcon = new TQPixmap( (const char **)end_xpm ); + qfd_cleanup_pixmap.add( &endCopyIcon ); + goBackIcon = new TQPixmap( (const char **)back_xpm ); + qfd_cleanup_pixmap.add( &goBackIcon ); + fifteenTransparentPixels = new TQPixmap( closedFolderIcon->width(), 1 ); + qfd_cleanup_pixmap.add( &fifteenTransparentPixels ); + TQBitmap m( fifteenTransparentPixels->width(), 1 ); + m.fill( TQt::color0 ); + fifteenTransparentPixels->setMask( m ); + bShowHiddenFiles = FALSE; + sortFilesBy = (int)TQDir::Name; + detailViewMode = FALSE; +#if defined(TQ_WS_WIN) + if ( !fileIconProvider ) + fileIconProvider = new TQWindowsIconProvider( tqApp ); +#endif + } +} + +/****************************************************************** + * + * Definitions of view classes + * + ******************************************************************/ + +class TQRenameEdit : public TQLineEdit +{ + Q_OBJECT + TQ_OBJECT + +public: + TQRenameEdit( TQWidget *tqparent ) + : TQLineEdit( tqparent, "qt_rename_edit" ), doRenameAlreadyEmitted(FALSE) + { + connect( this, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotReturnPressed()) ); + } + +protected: + void keyPressEvent( TQKeyEvent *e ); + void focusOutEvent( TQFocusEvent *e ); + +Q_SIGNALS: + void cancelRename(); + void doRename(); + +private Q_SLOTS: + void slotReturnPressed(); + +private: + bool doRenameAlreadyEmitted; +}; + +class TQFileListBox : public TQListBox +{ + friend class TQFileDialog; + + Q_OBJECT + TQ_OBJECT + +private: + TQFileListBox( TQWidget *tqparent, TQFileDialog *d ); + + void clear(); + void show(); + void startRename( bool check = TRUE ); + void viewportMousePressEvent( TQMouseEvent *e ); + void viewportMouseReleaseEvent( TQMouseEvent *e ); + void viewportMouseDoubleClickEvent( TQMouseEvent *e ); + void viewportMouseMoveEvent( TQMouseEvent *e ); +#ifndef TQT_NO_DRAGANDDROP + void viewportDragEnterEvent( TQDragEnterEvent *e ); + void viewportDragMoveEvent( TQDragMoveEvent *e ); + void viewportDragLeaveEvent( TQDragLeaveEvent *e ); + void viewportDropEvent( TQDropEvent *e ); + bool acceptDrop( const TQPoint &pnt, TQWidget *source ); + void setCurrentDropItem( const TQPoint &pnt ); +#endif + void keyPressEvent( TQKeyEvent *e ); + +private Q_SLOTS: + void rename(); + void cancelRename(); + void doubleClickTimeout(); + void changeDirDuringDrag(); + void dragObjDestroyed(); + void contentsMoved( int, int ); + +private: + TQRenameEdit *lined; + TQFileDialog *filedialog; + bool renaming; + TQTimer* renameTimer; + TQListBoxItem *renameItem, *dragItem; + TQPoint pressPos, oldDragPos; + bool mousePressed; + int urls; + TQString startDragDir; + TQListBoxItem *currDropItem; + TQTimer *changeDirTimer; + bool firstMousePressEvent; + TQUrlOperator startDragUrl; + +}; + + +class TQFileDialogTQFileListView : public TQListView +{ + Q_OBJECT + TQ_OBJECT + +public: + TQFileDialogTQFileListView( TQWidget *tqparent, TQFileDialog *d ); + + void clear(); + void startRename( bool check = TRUE ); + void setSorting( int column, bool increasing = TRUE ); + + TQRenameEdit *lined; + bool renaming; + TQListViewItem *renameItem; + +private: + void viewportMousePressEvent( TQMouseEvent *e ); + void viewportMouseDoubleClickEvent( TQMouseEvent *e ); + void keyPressEvent( TQKeyEvent *e ); + void viewportMouseReleaseEvent( TQMouseEvent *e ); + void viewportMouseMoveEvent( TQMouseEvent *e ); +#ifndef TQT_NO_DRAGANDDROP + void viewportDragEnterEvent( TQDragEnterEvent *e ); + void viewportDragMoveEvent( TQDragMoveEvent *e ); + void viewportDragLeaveEvent( TQDragLeaveEvent *e ); + void viewportDropEvent( TQDropEvent *e ); + bool acceptDrop( const TQPoint &pnt, TQWidget *source ); + void setCurrentDropItem( const TQPoint &pnt ); +#endif + +private Q_SLOTS: + void rename(); + void cancelRename(); + void changeSortColumn2( int column ); + void doubleClickTimeout(); + void changeDirDuringDrag(); + void dragObjDestroyed(); + void contentsMoved( int, int ); + +private: + TQFileDialog *filedialog; + TQTimer* renameTimer; + TQPoint pressPos, oldDragPos; + bool mousePressed; + int urls; + TQString startDragDir; + TQListViewItem *currDropItem, *dragItem; + TQTimer *changeDirTimer; + bool firstMousePressEvent; + bool ascending; + int sortcolumn; + TQUrlOperator startDragUrl; + +}; + +/**************************************************************************** + * + * Classes for copy progress dialog + * + ****************************************************************************/ + +class TQFDProgressAnimation : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + +public: + TQFDProgressAnimation( TQWidget *tqparent ); + void start(); + +private Q_SLOTS: + void next(); + +protected: + void paintEvent( TQPaintEvent *e ); + +private: + int step; + TQTimer *timer; + +}; + +TQFDProgressAnimation::TQFDProgressAnimation( TQWidget *tqparent ) + : TQWidget( tqparent, "qt_progressanimation" ) +{ + setFixedSize( 300, 50 ); + step = -1; + next(); + timer = new TQTimer( this ); + connect( timer, TQT_SIGNAL( timeout() ), + this, TQT_SLOT( next() ) ); +} + +void TQFDProgressAnimation::start() +{ + timer->start( 150, FALSE ); +} + +void TQFDProgressAnimation::next() +{ + ++step; + if ( step > 10 ) + step = 0; + tqrepaint(); +} + +void TQFDProgressAnimation::paintEvent( TQPaintEvent * ) +{ + erase(); + + TQPainter 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 TQFDProgressDialog : public TQDialog +{ + Q_OBJECT + TQ_OBJECT + +public: + TQFDProgressDialog( TQWidget *tqparent, const TQString &fn, int steps ); + + void setReadProgress( int p ); + void setWriteProgress( int p ); + void setWriteLabel( const TQString &s ); + +Q_SIGNALS: + void cancelled(); + +private: + TQProgressBar *readBar; + TQProgressBar *writeBar; + TQLabel *writeLabel; + TQFDProgressAnimation *animation; + +}; + +TQFDProgressDialog::TQFDProgressDialog( TQWidget *tqparent, const TQString &fn, int steps ) + : TQDialog( tqparent, "", TRUE ) +{ +#ifndef TQT_NO_WIDGET_TOPEXTRA + setCaption( TQFileDialog::tr( "Copy or Move a File" ) ); +#endif + TQVBoxLayout *tqlayout = new TQVBoxLayout( this ); + tqlayout->setSpacing( 5 ); + tqlayout->setMargin( 5 ); + + animation = new TQFDProgressAnimation( this ); + tqlayout->addWidget( animation ); + + tqlayout->addWidget( new TQLabel( TQFileDialog::tr( "Read: %1" ).arg( fn ), + this, "qt_read_lbl" ) ); + readBar = new TQProgressBar( steps, this, "qt_readbar" ); + readBar->reset(); + readBar->setProgress( 0 ); + tqlayout->addWidget( readBar ); + writeLabel = new TQLabel( TQFileDialog::tr( "Write: %1" ).arg( TQString() ), + this, "qt_write_lbl" ); + tqlayout->addWidget( writeLabel ); + writeBar = new TQProgressBar( steps, this, "qt_writebar" ); + writeBar->reset(); + writeBar->setProgress( 0 ); + tqlayout->addWidget( writeBar ); + + TQPushButton *b = new TQPushButton( TQFileDialog::tr( "Cancel" ), this, + "qt_cancel_btn" ); + b->setFixedSize( b->tqsizeHint() ); + tqlayout->addWidget( b ); + connect( b, TQT_SIGNAL( clicked() ), + this, TQT_SIGNAL( cancelled() ) ); + + animation->start(); +} + +void TQFDProgressDialog::setReadProgress( int p ) +{ + readBar->setProgress( p ); +} + +void TQFDProgressDialog::setWriteProgress( int p ) +{ + writeBar->setProgress( p ); +} + +void TQFDProgressDialog::setWriteLabel( const TQString &s ) +{ + writeLabel->setText( TQFileDialog::tr( "Write: %1" ).arg( s ) ); +} + +/************************************************************************ + * + * Private TQFileDialog members + * + ************************************************************************/ + +class TQFileDialogPrivate { +public: + ~TQFileDialogPrivate(); + + TQStringList history; + + bool tqgeometryDirty; + TQComboBox * paths; + TQComboBox * types; + TQLabel * pathL; + TQLabel * fileL; + TQLabel * typeL; + + TQVBoxLayout * topLevelLayout; + TQHBoxLayout *buttonLayout, *leftLayout, *rightLayout; + TQPtrList<TQHBoxLayout> extraWidgetsLayouts; + TQPtrList<TQLabel> extraLabels; + TQPtrList<TQWidget> extraWidgets; + TQPtrList<TQWidget> extraButtons; + TQPtrList<TQButton> toolButtons; + + TQWidgetStack * stack; + + TQToolButton * cdToParent, *newFolder, * detailView, * mcView, + *previewInfo, *previewContents, *goBack; + TQButtonGroup * modeButtons; + + TQString currentFileName; + TQListViewItem *last; + + TQListBoxItem *lastEFSelected; + + struct File: public TQListViewItem { + File( TQFileDialogPrivate * dlgp, + const TQUrlInfo * fi, TQListViewItem * tqparent ) + : TQListViewItem( tqparent, dlgp->last ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE ) + { setup(); dlgp->last = this; } + File( TQFileDialogPrivate * dlgp, + const TQUrlInfo * fi, TQListView * tqparent ) + : TQListViewItem( tqparent, dlgp->last ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE ) + { setup(); dlgp->last = this; } + File( TQFileDialogPrivate * dlgp, + const TQUrlInfo * fi, TQListView * tqparent, TQListViewItem * after ) + : TQListViewItem( tqparent, after ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE ) + { setup(); if ( !nextSibling() ) dlgp->last = this; } + ~File(); + + TQString text( int column ) const; + const TQPixmap * pixmap( int ) const; + + TQUrlInfo info; + TQFileDialogPrivate * d; + TQListBoxItem *i; + bool hasMimePixmap; + }; + + class MCItem: public TQListBoxItem { + public: + MCItem( TQListBox *, TQListViewItem * item ); + MCItem( TQListBox *, TQListViewItem * item, TQListBoxItem *after ); + TQString text() const; + const TQPixmap *pixmap() const; + int height( const TQListBox * ) const; + int width( const TQListBox * ) const; + void paint( TQPainter * ); + TQListViewItem * i; + }; + + class UrlInfoList : public TQPtrList<TQUrlInfo> { + public: + UrlInfoList() { setAutoDelete( TRUE ); } + int compareItems( TQPtrCollection::Item n1, TQPtrCollection::Item n2 ) { + if ( !n1 || !n2 ) + return 0; + + TQUrlInfo *i1 = ( TQUrlInfo *)n1; + TQUrlInfo *i2 = ( TQUrlInfo *)n2; + + if ( i1->isDir() && !i2->isDir() ) + return -1; + if ( !i1->isDir() && i2->isDir() ) + return 1; + + if ( i1->name() == ".." ) + return -1; + if ( i2->name() == ".." ) + return 1; + + if ( sortFilesBy == TQDir::Name ) { +#if defined(TQ_OS_WIN32) + TQString name1 = i1->name().lower(); + TQString name2 = i2->name().lower(); + return name1.localeAwareCompare( name2 ); +#else + TQString name1 = i1->name(); + TQString name2 = i2->name(); + return name1.localeAwareCompare( name2 ); +#endif + } + if ( TQUrlInfo::equal( *i1, *i2, sortFilesBy ) ) + return 0; + else if ( TQUrlInfo::greaterThan( *i1, *i2, sortFilesBy ) ) + return 1; + else if ( TQUrlInfo::lessThan( *i1, *i2, sortFilesBy ) ) + return -1; + // can't happen... + return 0; + } + TQUrlInfo *operator[]( int i ) { + return at( i ); + } + }; + + UrlInfoList sortedList; + TQPtrList<File> pendingItems; + + TQFileListBox * moreFiles; + + TQFileDialog::Mode mode; + + TQString rw; + TQString ro; + TQString wo; + TQString inaccessible; + + TQString symLinkToFile; + TQString file; + TQString symLinkToDir; + TQString dir; + TQString symLinkToSpecial; + TQString special; + TQWidgetStack *preview; + bool infoPreview, contentsPreview; + TQSplitter *splitter; + TQUrlOperator url, oldUrl; + TQWidget *infoPreviewWidget, *contentsPreviewWidget; + TQFilePreview *infoPreviewer, *contentsPreviewer; + bool hadDotDot; + + bool ignoreNextKeyPress; + // ignores the next refresh operation in case the user forced a selection + bool ignoreNextRefresh; + TQFDProgressDialog *progressDia; + bool checkForFilter; + bool ignoreStop; + + TQTimer *mimeTypeTimer; + const TQNetworkOperation *currListChildren; + + // this is similar to TQUrl::encode but does encode "*" and + // doesn't encode whitespaces + static TQString encodeFileName( const TQString& fName ) { + + TQString newStr; + TQCString cName = fName.utf8(); + const TQCString sChars( +#ifdef TQ_WS_WIN + "#%" +#else + "<>#@\"&%$:,;?={}|^~[]\'`\\*" +#endif + ); + + int len = cName.length(); + if ( !len ) + return TQString::null; + for ( int i = 0; i < len ;++i ) { + uchar inCh = (uchar)cName[ i ]; + if ( inCh >= 128 || sChars.tqcontains(inCh) ) + { + newStr += TQChar( '%' ); + ushort c = inCh / 16; + c += c > 9 ? 'A' - 10 : '0'; + newStr += (char)c; + c = inCh % 16; + c += c > 9 ? 'A' - 10 : '0'; + newStr += (char)c; + } else { + newStr += (char)inCh; + } + } + return newStr; + } + + static bool fileExists( const TQUrlOperator &url, const TQString& name ) + { + TQUrl u( url, TQFileDialogPrivate::encodeFileName(name) ); + if ( u.isLocalFile() ) { + TQFileInfo f( u.path() ); + return f.exists(); + } else { + TQNetworkProtocol *p = TQNetworkProtocol::getNetworkProtocol( url.protocol() ); + if ( p && (p->supportedOperations()&TQNetworkProtocol::OpListChildren) ) { + TQUrlInfo ui( url, name ); + return ui.isValid(); + } + } + return TRUE; + } + +#ifndef TQ_NO_CURSOR + bool cursorOverride; // Remember if the cursor was overridden or not. +#endif +#ifdef TQ_WS_WIN + int oldPermissionLookup; +#endif +}; + +TQFileDialogPrivate::~TQFileDialogPrivate() +{ + delete modeButtons; +} + + + +/************************************************************************ + * + * Internal class TQRenameEdit + * + ************************************************************************/ + +void TQRenameEdit::keyPressEvent( TQKeyEvent *e ) +{ + if ( e->key() == Key_Escape ) + emit cancelRename(); + else + TQLineEdit::keyPressEvent( e ); + e->accept(); +} + +void TQRenameEdit::focusOutEvent( TQFocusEvent * ) +{ + if ( !doRenameAlreadyEmitted ) + emit doRename(); + else + doRenameAlreadyEmitted = FALSE; +} + +void TQRenameEdit::slotReturnPressed() +{ + doRenameAlreadyEmitted = TRUE; + emit doRename(); +} + +/************************************************************************ + * + * Internal class TQFileListBox + * + ************************************************************************/ + +TQFileListBox::TQFileListBox( TQWidget *tqparent, TQFileDialog *dlg ) + : TQListBox( tqparent, "filelistbox" ), filedialog( dlg ), + renaming( FALSE ), renameItem( 0 ), mousePressed( FALSE ), + firstMousePressEvent( TRUE ) +{ + changeDirTimer = new TQTimer( this ); + TQVBox *box = new TQVBox( viewport(), "qt_vbox" ); + box->setFrameStyle( TQFrame::Box | TQFrame::Plain ); + lined = new TQRenameEdit( box ); + lined->setFixedHeight( lined->tqsizeHint().height() ); + box->hide(); + box->setBackgroundMode( TQt::PaletteBase ); + renameTimer = new TQTimer( this ); + connect( lined, TQT_SIGNAL( doRename() ), + this, TQT_SLOT (rename() ) ); + connect( lined, TQT_SIGNAL( cancelRename() ), + this, TQT_SLOT( cancelRename() ) ); + connect( renameTimer, TQT_SIGNAL( timeout() ), + this, TQT_SLOT( doubleClickTimeout() ) ); + connect( changeDirTimer, TQT_SIGNAL( timeout() ), + this, TQT_SLOT( changeDirDuringDrag() ) ); + connect( this, TQT_SIGNAL( contentsMoving(int,int) ), + this, TQT_SLOT( contentsMoved(int,int) ) ); + viewport()->setAcceptDrops( TRUE ); + dragItem = 0; +} + +void TQFileListBox::show() +{ + setBackgroundMode( TQt::PaletteBase ); + viewport()->setBackgroundMode( TQt::PaletteBase ); + TQListBox::show(); +} + +void TQFileListBox::keyPressEvent( TQKeyEvent *e ) +{ + if ( ( e->key() == Qt::Key_Enter || + e->key() == Qt::Key_Return ) && + renaming ) + return; + + TQString keyPressed = TQT_TQSTRING(((TQKeyEvent *)e)->text()).lower(); + TQChar keyChar = keyPressed[0]; + bool handled = false; + if ( keyChar.isLetterOrNumber() ) { + TQListBoxItem * i = 0; + if ( currentItem() ) + i = item( currentItem() ); + else + i = firstItem(); + if ( i->next() ) + i = i->next(); + else + i = firstItem(); + while ( i != item( currentItem() ) ) { + TQString it = text( index( i ) ); + if ( it[0].lower() == keyChar ) { + clearSelection(); + setCurrentItem( i ); + handled = true; + e->accept(); + } else { + if ( i->next() ) + i = i->next(); + else + i = firstItem(); + } + } + } + cancelRename(); + if (!handled){ + TQListBox::keyPressEvent( e ); + } +} + +void TQFileListBox::viewportMousePressEvent( TQMouseEvent *e ) +{ + pressPos = e->pos(); + mousePressed = FALSE; + + bool didRename = renaming; + + cancelRename(); + if ( !hasFocus() && !viewport()->hasFocus() ) + setFocus(); + + if ( e->button() != Qt::LeftButton ) { + TQListBox::viewportMousePressEvent( e ); + firstMousePressEvent = FALSE; + return; + } + + int i = currentItem(); + bool wasSelected = FALSE; + if ( i != -1 ) + wasSelected = item( i )->isSelected(); + TQListBox::mousePressEvent( e ); + + TQFileDialogPrivate::MCItem *i1 = (TQFileDialogPrivate::MCItem*)item( currentItem() ); + if ( i1 ) + mousePressed = ( !( (TQFileDialogPrivate::File*)i1->i )->info.isDir() ) + || ( filedialog->mode() == TQFileDialog::Directory ) || ( filedialog->mode() == TQFileDialog::DirectoryOnly ); + + if ( itemAt( e->pos() ) != item( i ) ) { + firstMousePressEvent = FALSE; + return; + } + + if ( !firstMousePressEvent && !didRename && i == currentItem() && currentItem() != -1 && + wasSelected && TQUrlInfo( filedialog->d->url, "." ).isWritable() && item( currentItem() )->text() != ".." ) { + renameTimer->start( TQApplication::doubleClickInterval(), TRUE ); + renameItem = item( i ); + } + + firstMousePressEvent = FALSE; +} + +void TQFileListBox::viewportMouseReleaseEvent( TQMouseEvent *e ) +{ + dragItem = 0; + TQListBox::viewportMouseReleaseEvent( e ); + mousePressed = FALSE; +} + +void TQFileListBox::viewportMouseDoubleClickEvent( TQMouseEvent *e ) +{ + renameTimer->stop(); + TQListBox::viewportMouseDoubleClickEvent( e ); +} + +void TQFileListBox::viewportMouseMoveEvent( TQMouseEvent *e ) +{ + if ( !dragItem ) + dragItem = itemAt( e->pos() ); + renameTimer->stop(); +#ifndef TQT_NO_DRAGANDDROP + if ( ( pressPos - e->pos() ).manhattanLength() > TQApplication::startDragDistance() && mousePressed ) { + TQListBoxItem *item = dragItem; + dragItem = 0; + if ( item ) { + if ( !tqitemRect( item ).tqcontains( e->pos() ) ) + return; + TQUriDrag* drag = new TQUriDrag( viewport() ); + TQStringList files; + if ( filedialog->mode() == TQFileDialog::ExistingFiles ) + files = filedialog->selectedFiles(); + else + files = filedialog->selectedFile(); + drag->setFileNames( files ); + + if ( lined->parentWidget()->isVisible() ) + cancelRename(); + + connect( drag, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( dragObjDestroyed() ) ); + drag->drag(); + + mousePressed = FALSE; + } + } else +#endif + { + TQListBox::viewportMouseMoveEvent( e ); + } + +} + +void TQFileListBox::dragObjDestroyed() +{ +#ifndef TQT_NO_DRAGANDDROP + //####### + //filedialog->rereadDir(); +#endif +} + +#ifndef TQT_NO_DRAGANDDROP +void TQFileListBox::viewportDragEnterEvent( TQDragEnterEvent *e ) +{ + startDragUrl = filedialog->d->url; + startDragDir = filedialog->dirPath(); + currDropItem = 0; + + if ( !TQUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + TQStringList l; + TQUriDrag::decodeLocalFiles( e, l ); + urls = (int)l.count(); + + if ( acceptDrop( e->pos(), e->source() ) ) { + e->accept(); + setCurrentDropItem( e->pos() ); + } else { + e->ignore(); + setCurrentDropItem( TQPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void TQFileListBox::viewportDragMoveEvent( TQDragMoveEvent *e ) +{ + if ( acceptDrop( e->pos(), e->source() ) ) { + switch ( e->action() ) { + case TQDropEvent::Copy: + e->acceptAction(); + break; + case TQDropEvent::Move: + e->acceptAction(); + break; + case TQDropEvent::Link: + break; + default: + break; + } + if ( oldDragPos != e->pos() ) + setCurrentDropItem( e->pos() ); + } else { + changeDirTimer->stop(); + e->ignore(); + setCurrentDropItem( TQPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void TQFileListBox::viewportDragLeaveEvent( TQDragLeaveEvent * ) +{ + changeDirTimer->stop(); + setCurrentDropItem( TQPoint( -1, -1 ) ); +//######## +// if ( startDragDir != filedialog->d->url ) +// filedialog->setUrl( startDragUrl ); +} + +void TQFileListBox::viewportDropEvent( TQDropEvent *e ) +{ + changeDirTimer->stop(); + + if ( !TQUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + uint i; + TQStrList l; + TQUriDrag::decode( e, l ); + + bool move = e->action() == TQDropEvent::Move; +// bool supportAction = move || e->action() == TQDropEvent::Copy; + + TQUrlOperator dest; + if ( currDropItem ) + dest = TQUrlOperator( filedialog->d->url, TQFileDialogPrivate::encodeFileName( currDropItem->text() ) ); + else + dest = filedialog->d->url; + TQStringList lst; + for ( i = 0; i < l.count(); ++i ) { + lst << l.at( i ); + } + + // make sure that we can write to the destination before performing the action + bool exists = false; + TQString name = (currDropItem ? TQFileDialogPrivate::encodeFileName(currDropItem->text()) : TQString(".")); + TQUrlInfo info(filedialog->d->url, name); + for ( i = 0; i < lst.count(); ++i ) { + int slash = lst[i].tqfindRev('/'); + TQString filename = lst[i].right(lst[i].length() - slash - 1); + exists = exists || TQFileDialogPrivate::fileExists( dest, filename); + } + if (info.isWritable() && !exists) + filedialog->d->url.copy( lst, dest, move ); + + // ##### what is supportAction for? + e->acceptAction(); + currDropItem = 0; +} + +bool TQFileListBox::acceptDrop( const TQPoint &pnt, TQWidget *source ) +{ + TQListBoxItem *item = itemAt( pnt ); + if ( !item || (item && !tqitemRect( item ).tqcontains( pnt )) ) { + if ( source == viewport() && startDragDir == filedialog->dirPath() ) + return FALSE; + return TRUE; + } + + TQUrlInfo fi( filedialog->d->url, item->text() ); + + if ( fi.isDir() && tqitemRect( item ).tqcontains( pnt ) ) + return TRUE; + return FALSE; +} + +void TQFileListBox::setCurrentDropItem( const TQPoint &pnt ) +{ + changeDirTimer->stop(); + + TQListBoxItem *item = 0; + if ( pnt != TQPoint( -1, -1 ) ) + item = itemAt( pnt ); + if ( item && !TQUrlInfo( filedialog->d->url, item->text() ).isDir() ) + item = 0; + if ( item && !tqitemRect( item ).tqcontains( pnt ) ) + item = 0; + + currDropItem = item; + if ( currDropItem ) + setCurrentItem( currDropItem ); + changeDirTimer->start( 750 ); +} +#endif // TQT_NO_DRAGANDDROP + +void TQFileListBox::changeDirDuringDrag() +{ +#ifndef TQT_NO_DRAGANDDROP + if ( !currDropItem ) + return; + changeDirTimer->stop(); + TQUrl u( filedialog->d->url, TQFileDialogPrivate::encodeFileName(currDropItem->text()) ); + filedialog->setDir( u ); + currDropItem = 0; +#endif +} + +void TQFileListBox::doubleClickTimeout() +{ + startRename(); + renameTimer->stop(); +} + +void TQFileListBox::startRename( bool check ) +{ + if ( check && ( !renameItem || renameItem != item( currentItem() ) ) ) + return; + + int i = currentItem(); + setSelected( i, TRUE ); + TQRect r = tqitemRect( 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 = TQMAX( 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 TQFileListBox::clear() +{ + cancelRename(); + TQListBox::clear(); +} + +void TQFileListBox::rename() +{ + if ( !lined->text().isEmpty() ) { + TQString file = currentText(); + + if ( lined->text() != file ) + filedialog->d->url.rename( file, lined->text() ); + } + cancelRename(); +} + +void TQFileListBox::cancelRename() +{ + renameItem = 0; + lined->parentWidget()->hide(); + viewport()->setFocusProxy( this ); + renaming = FALSE; + updateItem( currentItem() ); + if ( lined->hasFocus() ) + viewport()->setFocus(); +} + +void TQFileListBox::contentsMoved( int, int ) +{ + changeDirTimer->stop(); +#ifndef TQT_NO_DRAGANDDROP + setCurrentDropItem( TQPoint( -1, -1 ) ); +#endif +} + +/************************************************************************ + * + * Internal class TQFileListView + * + ************************************************************************/ + +TQFileDialogTQFileListView::TQFileDialogTQFileListView( TQWidget *tqparent, TQFileDialog *dlg ) + : TQListView( tqparent, "qt_filedlg_listview" ), renaming( FALSE ), renameItem( 0 ), + filedialog( dlg ), mousePressed( FALSE ), + firstMousePressEvent( TRUE ) +{ + changeDirTimer = new TQTimer( this ); + TQVBox *box = new TQVBox( viewport(), "qt_vbox" ); + box->setFrameStyle( TQFrame::Box | TQFrame::Plain ); + lined = new TQRenameEdit( box ); + lined->setFixedHeight( lined->tqsizeHint().height() ); + box->hide(); + box->setBackgroundMode( TQt::PaletteBase ); + renameTimer = new TQTimer( this ); + connect( lined, TQT_SIGNAL( doRename() ), + this, TQT_SLOT (rename() ) ); + connect( lined, TQT_SIGNAL( cancelRename() ), + this, TQT_SLOT( cancelRename() ) ); + header()->setMovingEnabled( FALSE ); + connect( renameTimer, TQT_SIGNAL( timeout() ), + this, TQT_SLOT( doubleClickTimeout() ) ); + connect( changeDirTimer, TQT_SIGNAL( timeout() ), + this, TQT_SLOT( changeDirDuringDrag() ) ); + disconnect( header(), TQT_SIGNAL( sectionClicked(int) ), + this, TQT_SLOT( changeSortColumn(int) ) ); + connect( header(), TQT_SIGNAL( sectionClicked(int) ), + this, TQT_SLOT( changeSortColumn2(int) ) ); + connect( this, TQT_SIGNAL( contentsMoving(int,int) ), + this, TQT_SLOT( contentsMoved(int,int) ) ); + + viewport()->setAcceptDrops( TRUE ); + sortcolumn = 0; + ascending = TRUE; + dragItem = 0; +} + +void TQFileDialogTQFileListView::setSorting( int column, bool increasing ) +{ + if ( column == -1 ) { + TQListView::setSorting( column, increasing ); + return; + } + + sortAscending = ascending = increasing; + sortcolumn = column; + switch ( column ) { + case 0: + sortFilesBy = TQDir::Name; + break; + case 1: + sortFilesBy = TQDir::Size; + break; + case 3: + sortFilesBy = TQDir::Time; + break; + default: + sortFilesBy = TQDir::Name; // #### ??? + break; + } + + filedialog->resortDir(); +} + +void TQFileDialogTQFileListView::changeSortColumn2( int column ) +{ + int lcol = header()->mapToLogical( column ); + setSorting( lcol, sortcolumn == lcol ? !ascending : TRUE ); +} + +void TQFileDialogTQFileListView::keyPressEvent( TQKeyEvent *e ) +{ + if ( ( e->key() == Qt::Key_Enter || + e->key() == Qt::Key_Return ) && + renaming ) + return; + + TQString keyPressed = TQT_TQSTRING(e->text()).lower(); + TQChar keyChar = keyPressed[0]; + if ( keyChar.isLetterOrNumber() ) { + TQListViewItem * i = 0; + if ( currentItem() ) + i = currentItem(); + else + i = firstChild(); + if ( i->nextSibling() ) + i = i->nextSibling(); + else + i = firstChild(); + while ( i != currentItem() ) { + TQString it = i->text(0); + if ( it[0].lower() == keyChar ) { + clearSelection(); + ensureItemVisible( i ); + setCurrentItem( i ); + } else { + if ( i->nextSibling() ) + i = i->nextSibling(); + else + i = firstChild(); + } + } + return; + } + + cancelRename(); + TQListView::keyPressEvent( e ); +} + +void TQFileDialogTQFileListView::viewportMousePressEvent( TQMouseEvent *e ) +{ + pressPos = e->pos(); + mousePressed = FALSE; + + bool didRename = renaming; + cancelRename(); + if ( !hasFocus() && !viewport()->hasFocus() ) + setFocus(); + + if ( e->button() != Qt::LeftButton ) { + TQListView::viewportMousePressEvent( e ); + firstMousePressEvent = FALSE; + return; + } + + TQListViewItem *i = currentItem(); + TQListView::viewportMousePressEvent( e ); + + TQFileDialogPrivate::File *i1 = (TQFileDialogPrivate::File*)currentItem(); + if ( i1 ) + mousePressed = !i1->info.isDir() || ( filedialog->mode() == TQFileDialog::Directory ) || ( filedialog->mode() == TQFileDialog::DirectoryOnly ); + + + if ( itemAt( e->pos() ) != i || + e->x() + contentsX() > columnWidth( 0 ) ) { + firstMousePressEvent = FALSE; + return; + } + + if ( !firstMousePressEvent && !didRename && i == currentItem() && currentItem() && + TQUrlInfo( filedialog->d->url, "." ).isWritable() && currentItem()->text( 0 ) != ".." ) { + renameTimer->start( TQApplication::doubleClickInterval(), TRUE ); + renameItem = currentItem(); + } + + firstMousePressEvent = FALSE; +} + +void TQFileDialogTQFileListView::viewportMouseDoubleClickEvent( TQMouseEvent *e ) +{ + renameTimer->stop(); + TQListView::viewportMouseDoubleClickEvent( e ); +} + +void TQFileDialogTQFileListView::viewportMouseReleaseEvent( TQMouseEvent *e ) +{ + TQListView::viewportMouseReleaseEvent( e ); + mousePressed = FALSE; + dragItem = 0; +} + +void TQFileDialogTQFileListView::viewportMouseMoveEvent( TQMouseEvent *e ) +{ + renameTimer->stop(); + if ( !dragItem ) + dragItem = itemAt( e->pos() ); +#ifndef TQT_NO_DRAGANDDROP + if ( ( pressPos - e->pos() ).manhattanLength() > TQApplication::startDragDistance() && mousePressed ) { + TQListViewItem *item = dragItem; + dragItem = 0; + if ( item ) { + TQUriDrag* drag = new TQUriDrag( viewport() ); + TQStringList files; + if ( filedialog->mode() == TQFileDialog::ExistingFiles ) + files = filedialog->selectedFiles(); + else + files = filedialog->selectedFile(); + drag->setFileNames( files ); + + if ( lined->isVisible() ) + cancelRename(); + + connect( drag, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( dragObjDestroyed() ) ); + drag->drag(); + + mousePressed = FALSE; + } + } +#endif +} + +void TQFileDialogTQFileListView::dragObjDestroyed() +{ +#ifndef TQT_NO_DRAGANDDROP + //###### + //filedialog->rereadDir(); +#endif +} + +#ifndef TQT_NO_DRAGANDDROP +void TQFileDialogTQFileListView::viewportDragEnterEvent( TQDragEnterEvent *e ) +{ + startDragUrl = filedialog->d->url; + startDragDir = filedialog->dirPath(); + currDropItem = 0; + + if ( !TQUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + TQStringList l; + TQUriDrag::decodeLocalFiles( e, l ); + urls = (int)l.count(); + + if ( acceptDrop( e->pos(), e->source() ) ) { + e->accept(); + setCurrentDropItem( e->pos() ); + } else { + e->ignore(); + setCurrentDropItem( TQPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void TQFileDialogTQFileListView::viewportDragMoveEvent( TQDragMoveEvent *e ) +{ + if ( acceptDrop( e->pos(), e->source() ) ) { + if ( oldDragPos != e->pos() ) + setCurrentDropItem( e->pos() ); + switch ( e->action() ) { + case TQDropEvent::Copy: + e->acceptAction(); + break; + case TQDropEvent::Move: + e->acceptAction(); + break; + case TQDropEvent::Link: + break; + default: + break; + } + } else { + changeDirTimer->stop(); + e->ignore(); + setCurrentDropItem( TQPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void TQFileDialogTQFileListView::viewportDragLeaveEvent( TQDragLeaveEvent * ) +{ + changeDirTimer->stop(); + setCurrentDropItem( TQPoint( -1, -1 ) ); +//######## +// if ( startDragDir != filedialog->d->url ) +// filedialog->setUrl( startDragUrl ); +} + +void TQFileDialogTQFileListView::viewportDropEvent( TQDropEvent *e ) +{ + changeDirTimer->stop(); + + if ( !TQUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + TQStringList l; + TQUriDrag::decodeToUnicodeUris( e, l ); + + bool move = e->action() == TQDropEvent::Move; +// bool supportAction = move || e->action() == TQDropEvent::Copy; + + TQUrlOperator dest; + if ( currDropItem ) + dest = TQUrlOperator( filedialog->d->url, TQFileDialogPrivate::encodeFileName( currDropItem->text( 0 ) ) ); + else + dest = filedialog->d->url; + + // make sure that we can write to the destination before performing the action + bool exists = false; + TQString name = (currDropItem ? TQFileDialogPrivate::encodeFileName(currDropItem->text(0)) : TQString(".")); + TQUrlInfo info(filedialog->d->url, name); + for (uint i = 0; i < l.count(); ++i) { + int slash = l[i].tqfindRev('/'); + TQString filename = l[i].right(l[i].length() - slash - 1); + exists = exists || TQFileDialogPrivate::fileExists(dest, filename); + } + if (info.isWritable() && !exists) + filedialog->d->url.copy( l, dest, move ); + + // ##### what is supportAction for? + e->acceptAction(); + currDropItem = 0; +} + +bool TQFileDialogTQFileListView::acceptDrop( const TQPoint &pnt, TQWidget *source ) +{ + TQListViewItem *item = itemAt( pnt ); + if ( !item || (item && !tqitemRect( item ).tqcontains( pnt )) ) { + if ( source == viewport() && startDragDir == filedialog->dirPath() ) + return FALSE; + return TRUE; + } + + TQUrlInfo fi( filedialog->d->url, item->text( 0 ) ); + + if ( fi.isDir() && tqitemRect( item ).tqcontains( pnt ) ) + return TRUE; + return FALSE; +} + +void TQFileDialogTQFileListView::setCurrentDropItem( const TQPoint &pnt ) +{ + changeDirTimer->stop(); + + TQListViewItem *item = itemAt( pnt ); + if ( pnt == TQPoint( -1, -1 ) ) + item = 0; + if ( item && !TQUrlInfo( filedialog->d->url, item->text( 0 ) ).isDir() ) + item = 0; + + if ( item && !tqitemRect( item ).tqcontains( pnt ) ) + item = 0; + + currDropItem = item; + + if ( currDropItem ) + setCurrentItem( currDropItem ); + + changeDirTimer->start( 750 ); +} +#endif // TQT_NO_DRAGANDDROP + +void TQFileDialogTQFileListView::changeDirDuringDrag() +{ +#ifndef TQT_NO_DRAGANDDROP + if ( !currDropItem ) + return; + changeDirTimer->stop(); + TQUrl u( filedialog->d->url, TQFileDialogPrivate::encodeFileName(currDropItem->text( 0 ) ) ); + filedialog->setDir( u ); + currDropItem = 0; +#endif // TQT_NO_DRAGANDDROP +} + + +void TQFileDialogTQFileListView::doubleClickTimeout() +{ + startRename(); + renameTimer->stop(); +} + +void TQFileDialogTQFileListView::startRename( bool check ) +{ + if ( check && ( !renameItem || renameItem != currentItem() ) ) + return; + + TQListViewItem *i = currentItem(); + setSelected( i, TRUE ); + + TQRect r = tqitemRect( 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 = TQMAX( 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 TQFileDialogTQFileListView::clear() +{ + cancelRename(); + TQListView::clear(); +} + +void TQFileDialogTQFileListView::rename() +{ + if ( !lined->text().isEmpty() ) { + TQString file = currentItem()->text( 0 ); + + if ( lined->text() != file ) + filedialog->d->url.rename( file, lined->text() ); + } + cancelRename(); +} + +void TQFileDialogTQFileListView::cancelRename() +{ + renameItem = 0; + lined->parentWidget()->hide(); + viewport()->setFocusProxy( this ); + renaming = FALSE; + if ( currentItem() ) + currentItem()->tqrepaint(); + if ( lined->hasFocus() ) + viewport()->setFocus(); +} + +void TQFileDialogTQFileListView::contentsMoved( int, int ) +{ + changeDirTimer->stop(); +#ifndef TQT_NO_DRAGANDDROP + setCurrentDropItem( TQPoint( -1, -1 ) ); +#endif +} + + +TQFileDialogPrivate::File::~File() +{ + if ( d->pendingItems.tqfindRef( this ) ) + d->pendingItems.removeRef( this ); +} + +TQString TQFileDialogPrivate::File::text( int column ) const +{ + makeVariables(); + + switch( column ) { + case 0: + return info.name(); + case 1: + if ( info.isFile() ) { +#if (TQT_VERSION-0 >= 0x040000) +#error "clean up Large File Support" +#elif defined(TQT_ABI_QT4) + TQIODevice::Offset size = info.size(); +#else + uint size = info.size(); +#endif +#if defined(TQT_LARGEFILE_SUPPORT) && defined(TQ_OS_UNIX) + // ### the following code should not be needed as soon + // ### as TQUrlInfo::size() can return 64-bit + if ( size > INT_MAX ) { + struct stat buffer; + if ( ::stat( TQFile::encodeName(info.name()), &buffer ) == 0 ) { + TQ_ULLONG size64 = (TQ_ULLONG)buffer.st_size; + return TQString::number(size64); + } + } +#endif + return TQString::number(size); + } else { + return TQString::tqfromLatin1(""); + } + 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 TQString::tqfromLatin1("<--->"); +} + +const TQPixmap * TQFileDialogPrivate::File::pixmap( int column ) const +{ + if ( column ) { + return 0; + } else if ( TQListViewItem::pixmap( column ) ) { + return TQListViewItem::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; + } +} + +TQFileDialogPrivate::MCItem::MCItem( TQListBox * lb, TQListViewItem * item ) + : TQListBoxItem() +{ + i = item; + if ( lb ) + lb->insertItem( this ); +} + +TQFileDialogPrivate::MCItem::MCItem( TQListBox * lb, TQListViewItem * item, TQListBoxItem *after ) + : TQListBoxItem() +{ + i = item; + if ( lb ) + lb->insertItem( this, after ); +} + +TQString TQFileDialogPrivate::MCItem::text() const +{ + return i->text( 0 ); +} + + +const TQPixmap *TQFileDialogPrivate::MCItem::pixmap() const +{ + return i->pixmap( 0 ); +} + + +int TQFileDialogPrivate::MCItem::height( const TQListBox * lb ) const +{ + int hf = lb->fontMetrics().height(); + int hp = pixmap() ? pixmap()->height() : 0; + return TQMAX(hf, hp) + 2; +} + + +int TQFileDialogPrivate::MCItem::width( const TQListBox * lb ) const +{ + TQFontMetrics 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 TQFileDialogPrivate::MCItem::paint( TQPainter * ptr ) +{ + TQFontMetrics fm = ptr->fontMetrics(); + + int h; + + if ( pixmap() ) + h = TQMAX( fm.height(), pixmap()->height()) + 2; + else + h = fm.height() + 2; + + const TQPixmap * pm = pixmap(); + if ( pm ) + ptr->drawPixmap( 2, 1, *pm ); + + ptr->drawText( pm ? pm->width() + 4 : 22, h - fm.descent() - 2, + text() ); +} + +static TQStringList makeFiltersList( const TQString &filter ) +{ + if ( filter.isEmpty() ) + return TQStringList(); + + int i = filter.tqfind( ";;", 0 ); + TQString sep( ";;" ); + if ( i == -1 ) { + if ( filter.tqfind( "\n", 0 ) != -1 ) { + sep = "\n"; + i = filter.tqfind( sep, 0 ); + } + } + + return TQStringList::split( sep, filter ); +} + +/*! + \class TQFileDialog tqfiledialog.h + \brief The TQFileDialog class provides dialogs that allow users to select files or directories. + \ingroup dialogs + \mainclass + + The TQFileDialog 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 TQFileDialog 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. + + \code + TQString s = TQFileDialog::getOpenFileName( + "/home", + "Images (*.png *.xpm *.jpg)", + this, + "open file dialog", + "Choose a file" ); + \endcode + + In the above example, a modal TQFileDialog is created using a static + function. The startup directory is set to "/home". The file filter + is set to "Images (*.png *.xpm *.jpg)". The tqparent 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 semi-colons, e.g. + \code + "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + \endcode + + You can create your own TQFileDialog without using the static + functions. By calling setMode(), you can set what can be returned by + the TQFileDialog. + + \code + TQFileDialog* fd = new TQFileDialog( this, "file dialog", TRUE ); + fd->setMode( TQFileDialog::AnyFile ); + \endcode + + In the above example, the mode of the file dialog is set to \c + 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 \c ExistingFile if the user must select an + existing file or \c Directory if only a directory may be selected. + (See the \l TQFileDialog::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. + + \code + fd->setFilter( "Images (*.png *.xpm *.jpg)" ); + \endcode + + 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 TQFileDialog. 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, TQFileDialog::List which simply + lists file and directory names and TQFileDialog::Detail which + displays additional information alongside each name, e.g. file size, + modification date, etc. Set the mode with setViewMode(). + + \code + fd->setViewMode( TQFileDialog::Detail ); + \endcode + + The last important function you will need to use when creating your + own file dialog is selectedFile(). + + \code + TQString fileName; + if ( fd->exec() == TQDialog::Accepted ) + fileName = fd->selectedFile(); + \endcode + + 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 \c ExistingFiles mode then you will need to use + selectedFiles() which will return the selected files in a TQStringList. + + 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 + TQFileDialogs: \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 TQFileDialog so + that the user can see either the contents of the file, or information + about the file. + + \code + class Preview : public TQLabel, public TQFilePreview + { + public: + Preview( TQWidget *tqparent=0 ) : TQLabel( tqparent ) {} + + void previewUrl( const TQUrl &u ) + { + TQString path = u.path(); + TQPixmap pix( path ); + if ( pix.isNull() ) + setText( "This is not a pixmap" ); + else + setPixmap( pix ); + } + }; + \endcode + + In the above snippet, we create a preview widget which inherits from + TQLabel and TQFilePreview. File preview widgets \e must inherit from + TQFilePreview. + + Inside the class we reimplement TQFilePreview::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: + + \code + Preview* p = new Preview; + + TQFileDialog* fd = new TQFileDialog( this ); + fd->setContentsPreviewEnabled( TRUE ); + fd->setContentsPreview( p, p ); + fd->setPreviewMode( TQFileDialog::Contents ); + fd->show(); + \endcode + + 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 TQFilePreview widget see + \l{TQFilePreview}. + + <img src=qfiledlg-m.png> <img src=qfiledlg-w.png> + +*/ + + +/*! \enum TQFileDialog::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 TQFileDialog::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 TQFileDialog::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 TQFileDialog::detailViewSelectionChanged() + \internal +*/ + +/*! + \fn void TQFileDialog::listBoxSelectionChanged() + \internal +*/ + +extern const char qt_file_dialog_filter_reg_exp[] = + "([a-zA-Z0-9 ]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$"; + +/*! + Constructs a file dialog called \a name, with the tqparent, \a tqparent. + If \a modal is TRUE then the file dialog is modal; otherwise it is + modeless. +*/ + +TQFileDialog::TQFileDialog( TQWidget *tqparent, const char *name, bool modal ) + : TQDialog( tqparent, name, modal, + (modal ? + (WFlags)(WStyle_Customize | TQt::WStyle_DialogBorder | TQt::WStyle_Title | TQt::WStyle_SysMenu) : (WFlags)0) ) +{ + init(); + d->mode = ExistingFile; + d->types->insertItem( tqtr( "All Files (*)" ) ); + d->cursorOverride = FALSE; + emit dirEntered( d->url.dirPath() ); + rereadDir(); +} + + +/*! + Constructs a file dialog called \a name with the tqparent, \a tqparent. + 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. + +*/ + +TQFileDialog::TQFileDialog( const TQString& dirName, const TQString & filter, + TQWidget *tqparent, const char *name, bool modal ) + : TQDialog( tqparent, name, modal, + (modal ? + (WFlags)(WStyle_Customize | TQt::WStyle_DialogBorder | TQt::WStyle_Title | TQt::WStyle_SysMenu) : (WFlags)0) ) +{ + init(); + d->mode = ExistingFile; + rereadDir(); + TQUrlOperator u( dirName ); + if ( !dirName.isEmpty() && ( !u.isLocalFile() || TQDir( dirName ).exists() ) ) + setSelection( dirName ); + else if ( workingDirectory && !workingDirectory->isEmpty() ) + setDir( *workingDirectory ); + + if ( !filter.isEmpty() ) { + setFilters( filter ); + if ( !dirName.isEmpty() ) { + int dotpos = dirName.tqfind( TQChar('.'), 0, FALSE ); + if ( dotpos != -1 ) { + for ( int b=0 ; b<d->types->count() ; b++ ) { + if ( d->types->text(b).tqcontains( dirName.right( dirName.length() - dotpos ) ) ) { + d->types->setCurrentItem( b ); + setFilter( d->types->text( b ) ); + return; + } + } + } + } + } else { + d->types->insertItem( tqtr( "All Files (*)" ) ); + } +} + + +#if defined(TQ_WS_WIN) +extern int qt_ntfs_permission_lookup; +#endif + +/*! + \internal + Initializes the file dialog. +*/ + +void TQFileDialog::init() +{ + setSizeGripEnabled( TRUE ); + d = new TQFileDialogPrivate(); + 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->pendingItems.setAutoDelete( FALSE ); + d->mimeTypeTimer = new TQTimer( this ); + d->cursorOverride = FALSE; +#if defined(TQ_WS_WIN) + d->oldPermissionLookup = qt_ntfs_permission_lookup; +#endif + connect( d->mimeTypeTimer, TQT_SIGNAL( timeout() ), + this, TQT_SLOT( doMimeTypeLookup() ) ); + + d->url = TQUrlOperator( ::toRootIfNotExists( TQDir::currentDirPath() ) ); + d->oldUrl = d->url; + d->currListChildren = 0; + + connect( &d->url, TQT_SIGNAL( start(TQNetworkOperation*) ), + this, TQT_SLOT( urlStart(TQNetworkOperation*) ) ); + connect( &d->url, TQT_SIGNAL( finished(TQNetworkOperation*) ), + this, TQT_SLOT( urlFinished(TQNetworkOperation*) ) ); + connect( &d->url, TQT_SIGNAL( newChildren(const TQValueList<TQUrlInfo>&,TQNetworkOperation*) ), + this, TQT_SLOT( insertEntry(const TQValueList<TQUrlInfo>&,TQNetworkOperation*) ) ); + connect( &d->url, TQT_SIGNAL( removed(TQNetworkOperation*) ), + this, TQT_SLOT( removeEntry(TQNetworkOperation*) ) ); + connect( &d->url, TQT_SIGNAL( createdDirectory(const TQUrlInfo&,TQNetworkOperation*) ), + this, TQT_SLOT( createdDirectory(const TQUrlInfo&,TQNetworkOperation*) ) ); + connect( &d->url, TQT_SIGNAL( itemChanged(TQNetworkOperation*) ), + this, TQT_SLOT( itemChanged(TQNetworkOperation*) ) ); + connect( &d->url, TQT_SIGNAL( dataTransferProgress(int,int,TQNetworkOperation*) ), + this, TQT_SLOT( dataTransferProgress(int,int,TQNetworkOperation*) ) ); + + nameEdit = new TQLineEdit( this, "name/filter editor" ); + nameEdit->setMaxLength( 255 ); //_POSIX_MAX_PATH + connect( nameEdit, TQT_SIGNAL(textChanged(const TQString&)), + this, TQT_SLOT(fileNameEditDone()) ); + nameEdit->installEventFilter( this ); + + d->splitter = new TQSplitter( this, "qt_splitter" ); + + d->stack = new TQWidgetStack( d->splitter, "files and more files" ); + + d->splitter->tqsetSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding ) ); + + files = new TQFileDialogTQFileListView( d->stack, this ); + TQFontMetrics 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, TQT_SIGNAL( selectionChanged() ), + this, TQT_SLOT( detailViewSelectionChanged() ) ); + connect( files, TQT_SIGNAL(currentChanged(TQListViewItem*)), + this, TQT_SLOT(updateFileNameEdit(TQListViewItem*)) ); + connect( files, TQT_SIGNAL(doubleClicked(TQListViewItem*)), + this, TQT_SLOT(selectDirectoryOrFile(TQListViewItem*)) ); + connect( files, TQT_SIGNAL(returnPressed(TQListViewItem*)), + this, TQT_SLOT(selectDirectoryOrFile(TQListViewItem*)) ); + connect( files, TQT_SIGNAL(rightButtonPressed(TQListViewItem*,const TQPoint&,int)), + this, TQT_SLOT(popupContextMenu(TQListViewItem*,const TQPoint&,int)) ); + + files->installEventFilter( this ); + files->viewport()->installEventFilter( this ); + + d->moreFiles = new TQFileListBox( d->stack, this ); + d->moreFiles->setRowMode( TQListBox::FitToHeight ); + d->moreFiles->setVariableWidth( TRUE ); + + connect( d->moreFiles, TQT_SIGNAL(selected(TQListBoxItem*)), + this, TQT_SLOT(selectDirectoryOrFile(TQListBoxItem*)) ); + connect( d->moreFiles, TQT_SIGNAL( selectionChanged() ), + this, TQT_SLOT( listBoxSelectionChanged() ) ); + connect( d->moreFiles, TQT_SIGNAL(highlighted(TQListBoxItem*)), + this, TQT_SLOT(updateFileNameEdit(TQListBoxItem*)) ); + connect( d->moreFiles, TQT_SIGNAL( rightButtonPressed(TQListBoxItem*,const TQPoint&) ), + this, TQT_SLOT( popupContextMenu(TQListBoxItem*,const TQPoint&) ) ); + + d->moreFiles->installEventFilter( this ); + d->moreFiles->viewport()->installEventFilter( this ); + + okB = new TQPushButton( tr("&OK"), this, "OK" ); //### Or "Save (see other "OK") + okB->setDefault( TRUE ); + okB->setEnabled( FALSE ); + connect( okB, TQT_SIGNAL(clicked()), this, TQT_SLOT(okClicked()) ); + cancelB = new TQPushButton( tr("Cancel") , this, "Cancel" ); + connect( cancelB, TQT_SIGNAL(clicked()), this, TQT_SLOT(cancelClicked()) ); + + d->paths = new TQComboBox( TRUE, this, "directory history/editor" ); + d->paths->setDuplicatesEnabled( FALSE ); + d->paths->setInsertionPolicy( TQComboBox::NoInsertion ); + const TQFileInfoList * rootDrives = TQDir::drives(); + TQFileInfoListIterator it( *rootDrives ); + TQFileInfo *fi; + makeVariables(); + + while ( (fi = it.current()) != 0 ) { + ++it; + d->paths->insertItem( *openFolderIcon, fi->absFilePath() ); + } + + if ( !!TQDir::homeDirPath() ) { + if ( !d->paths->listBox()->tqfindItem( TQDir::homeDirPath() ) ) + d->paths->insertItem( *openFolderIcon, TQDir::homeDirPath() ); + } + + connect( d->paths, TQT_SIGNAL(activated(const TQString&)), + this, TQT_SLOT(setDir(const TQString&)) ); + + d->paths->installEventFilter( this ); + TQObjectList *ol = d->paths->queryList( "TQLineEdit" ); + if ( ol && ol->first() ) + ( (TQLineEdit*)ol->first() )->installEventFilter( this ); + delete ol; + + d->tqgeometryDirty = TRUE; + d->types = new TQComboBox( TRUE, this, "file types" ); + d->types->setDuplicatesEnabled( FALSE ); + d->types->setEditable( FALSE ); + connect( d->types, TQT_SIGNAL(activated(const TQString&)), + this, TQT_SLOT(setFilter(const TQString&)) ); + connect( d->types, TQT_SIGNAL(activated(const TQString&)), + this, TQT_SIGNAL(filterSelected(const TQString&)) ); + + d->pathL = new TQLabel( d->paths, tr("Look &in:"), this, "qt_looin_lbl" ); + d->fileL = new TQLabel( nameEdit, tr("File &name:"), this, "qt_filename_lbl" ); + d->typeL = new TQLabel( d->types, tr("File &type:"), this, "qt_filetype_lbl" ); + + d->goBack = new TQToolButton( this, "go back" ); + d->goBack->setEnabled( FALSE ); + d->goBack->setFocusPolicy( Qt::TabFocus ); + connect( d->goBack, TQT_SIGNAL( clicked() ), this, TQT_SLOT( goBack() ) ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::add( d->goBack, tr( "Back" ) ); +#endif + d->goBack->setIconSet( *goBackIcon ); + + d->cdToParent = new TQToolButton( this, "cd to tqparent" ); + d->cdToParent->setFocusPolicy( Qt::TabFocus ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::add( d->cdToParent, tr( "One directory up" ) ); +#endif + d->cdToParent->setIconSet( *cdToParentIcon ); + connect( d->cdToParent, TQT_SIGNAL(clicked()), + this, TQT_SLOT(cdUpClicked()) ); + + d->newFolder = new TQToolButton( this, "new folder" ); + d->newFolder->setFocusPolicy( Qt::TabFocus ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::add( d->newFolder, tr( "Create New Folder" ) ); +#endif + d->newFolder->setIconSet( *newFolderIcon ); + connect( d->newFolder, TQT_SIGNAL(clicked()), + this, TQT_SLOT(newFolderClicked()) ); + + d->modeButtons = new TQButtonGroup( 0, "invisible group" ); + connect( d->modeButtons, TQT_SIGNAL(destroyed()), + this, TQT_SLOT(modeButtonsDestroyed()) ); + d->modeButtons->setExclusive( TRUE ); + connect( d->modeButtons, TQT_SIGNAL(clicked(int)), + d->stack, TQT_SLOT(raiseWidget(int)) ); + connect( d->modeButtons, TQT_SIGNAL(clicked(int)), + this, TQT_SLOT(changeMode(int)) ); + + d->mcView = new TQToolButton( this, "mclistbox view" ); + d->mcView->setFocusPolicy( Qt::TabFocus ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::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 TQToolButton( this, "list view" ); + d->detailView->setFocusPolicy( Qt::TabFocus ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::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 TQToolButton( this, "preview info view" ); + d->previewInfo->setFocusPolicy( Qt::TabFocus ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::add( d->previewInfo, tr( "Preview File Info" ) ); +#endif + d->previewInfo->setIconSet( *previewInfoViewIcon ); + d->previewInfo->setToggleButton( TRUE ); + d->modeButtons->insert( d->previewInfo ); + + d->previewContents = new TQToolButton( this, "preview info view" ); +#if defined(TQ_WS_WIN) && !defined(TQ_OS_TEMP) + if ( (qt_winver & WV_NT_based) > TQt::WV_NT ) +#else + if ( !qstrcmp(tqstyle().className(), "TQWindowsStyle") ) +#endif + { + d->goBack->setAutoRaise( TRUE ); + d->cdToParent->setAutoRaise( TRUE ); + d->newFolder->setAutoRaise( TRUE ); + d->mcView->setAutoRaise( TRUE ); + d->detailView->setAutoRaise( TRUE ); + d->previewInfo->setAutoRaise( TRUE ); + d->previewContents->setAutoRaise( TRUE ); + } + d->previewContents->setFocusPolicy( Qt::TabFocus ); +#ifndef TQT_NO_TOOLTIP + TQToolTip::add( d->previewContents, tr( "Preview File Contents" ) ); +#endif + d->previewContents->setIconSet( *previewContentsViewIcon ); + d->previewContents->setToggleButton( TRUE ); + d->modeButtons->insert( d->previewContents ); + + connect( d->detailView, TQT_SIGNAL( clicked() ), + d->moreFiles, TQT_SLOT( cancelRename() ) ); + connect( d->detailView, TQT_SIGNAL( clicked() ), + files, TQT_SLOT( cancelRename() ) ); + connect( d->mcView, TQT_SIGNAL( clicked() ), + d->moreFiles, TQT_SLOT( cancelRename() ) ); + connect( d->mcView, TQT_SIGNAL( clicked() ), + files, TQT_SLOT( cancelRename() ) ); + + d->stack->raiseWidget( d->moreFiles ); + d->mcView->setOn( TRUE ); + + TQHBoxLayout *lay = new TQHBoxLayout( this ); + lay->setMargin( 6 ); + d->leftLayout = new TQHBoxLayout( lay, 5 ); + d->topLevelLayout = new TQVBoxLayout( (TQWidget*)0, 5 ); + lay->addLayout( d->topLevelLayout, 1 ); + d->extraWidgetsLayouts.setAutoDelete( FALSE ); + d->extraLabels.setAutoDelete( FALSE ); + d->extraWidgets.setAutoDelete( FALSE ); + d->extraButtons.setAutoDelete( FALSE ); + d->toolButtons.setAutoDelete( FALSE ); + + TQHBoxLayout * h; + + d->preview = new TQWidgetStack( d->splitter, "qt_preview" ); + + d->infoPreviewWidget = new TQWidget( d->preview, "qt_preview_info" ); + d->contentsPreviewWidget = new TQWidget( d->preview, "qt_preview_contents" ); + d->infoPreviewer = d->contentsPreviewer = 0; + + h = new TQHBoxLayout( 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 TQHBoxLayout(); + d->topLevelLayout->addLayout( h ); + h->addWidget( d->fileL ); + h->addWidget( nameEdit ); + h->addSpacing( 15 ); + h->addWidget( okB ); + + h = new TQHBoxLayout(); + d->topLevelLayout->addLayout( h ); + h->addWidget( d->typeL ); + h->addWidget( d->types ); + h->addSpacing( 15 ); + h->addWidget( cancelB ); + + d->rightLayout = new TQHBoxLayout( 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 ) { + TQRect screen = TQApplication::desktop()->screenGeometry( pos() ); + if ( screen.width() < 1024 || screen.height() < 768 ) { + resize( TQMIN(screen.width(), 420), TQMIN(screen.height(), 236) ); + } else { + TQSize s = files->tqsizeHint(); + s = TQSize( 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, TQT_SIGNAL( returnPressed() ), + this, TQT_SLOT( fileNameEditReturnPressed() ) ); +} + +/*! + \internal +*/ + +void TQFileDialog::fileNameEditReturnPressed() +{ + d->oldUrl = d->url; + if ( !isDirectoryMode( d->mode ) ) { + okClicked(); + } else { + d->currentFileName = TQString::null; + if ( nameEdit->text().isEmpty() ) { + emit fileSelected( selectedFile() ); + accept(); + } else { + TQUrlInfo f; + TQFileDialogPrivate::File * c + = (TQFileDialogPrivate::File *)files->currentItem(); + if ( c && files->isSelected(c) ) + f = c->info; + else + f = TQUrlInfo( d->url, nameEdit->text() ); + if ( f.isDir() ) { + setUrl( TQUrlOperator( d->url, + TQFileDialogPrivate::encodeFileName(nameEdit->text() + "/" ) ) ); + d->checkForFilter = TRUE; + trySetSelection( TRUE, d->url, TRUE ); + d->checkForFilter = FALSE; + } + } + nameEdit->setText( TQString::null ); + } +} + +/*! + \internal + Update the info and content preview widgets to display \a u. +*/ + +void TQFileDialog::updatePreviews( const TQUrl &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 TQFileDialog::changeMode( int id ) +{ + if ( !d->infoPreview && !d->contentsPreview ) + return; + + TQButton *btn = (TQButton*)d->modeButtons->tqfind( 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( TQUrl( 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. +*/ + +TQFileDialog::~TQFileDialog() +{ + // 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 TQT_NO_CURSOR + if ( d->cursorOverride ) + TQApplication::restoreOverrideCursor(); +#endif + + delete d; + d = 0; +} + + +/*! + \property TQFileDialog::selectedFile + + \brief the name of the selected file + + If a file was selected selectedFile tqcontains the file's name including + its absolute path; otherwise selectedFile is empty. + + \sa TQString::isEmpty(), selectedFiles, selectedFilter +*/ + +TQString TQFileDialog::selectedFile() const +{ + TQString s = d->currentFileName; + // remove the protocol because we do not want to encode it... + TQString prot = TQUrl( s ).protocol(); + if ( !prot.isEmpty() ) { + prot += ":"; + s.remove( 0, prot.length() ); + } + TQUrl u( prot + TQFileDialogPrivate::encodeFileName( s ) ); + if ( u.isLocalFile() ) { + TQString s = u.toString(); + if ( s.left( 5 ) == "file:" ) + s.remove( (uint)0, 5 ); + return s; + } + return d->currentFileName; +} + +/*! + \property TQFileDialog::selectedFilter + + \brief the filter which the user has selected in the file dialog + + \sa filterSelected(), selectedFiles, selectedFile +*/ + +TQString TQFileDialog::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 TQFileDialog::setSelectedFilter( int n ) +{ + d->types->setCurrentItem( n ); + TQString f = d->types->currentText(); + TQRegExp r( TQString::tqfromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( 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 tqcontains the text \a tqmask. +*/ + +void TQFileDialog::setSelectedFilter( const TQString& tqmask ) +{ + int n; + + for ( n = 0; n < d->types->count(); n++ ) { + if ( d->types->text( n ).tqcontains( tqmask, FALSE ) ) { + d->types->setCurrentItem( n ); + TQString f = tqmask; + TQRegExp r( TQString::tqfromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( f ); + if ( index >= 0 ) + f = r.cap( 2 ); + d->url.setNameFilter( f ); + rereadDir(); + return; + } + } +} + +/*! + \property TQFileDialog::selectedFiles + + \brief the list of selected files + + If one or more files are selected, selectedFiles tqcontains 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 + \c ExistingFile, \c Directory or \c DirectoryOnly. + + Note that if you want to iterate over the list, you should + iterate over a copy, e.g. + \code + TQStringList list = myFileDialog.selectedFiles(); + TQStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + + \sa selectedFile, selectedFilter, TQValueList::empty() +*/ + +TQStringList TQFileDialog::selectedFiles() const +{ + TQStringList lst; + + if ( mode() == ExistingFiles ) { + TQStringList selectedLst; + TQString selectedFiles = nameEdit->text(); + if (selectedFiles.tqfindRev('\"') == -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.tqfindRev( '\"' ) ); + selectedLst = selectedLst.split( TQString("\" "), selectedFiles ); + } + for ( TQStringList::Iterator it = selectedLst.begin(); it != selectedLst.end(); ++it ) { + TQUrl u; + if ( (*it)[0] == '\"' ) { + u = TQUrl( d->url, TQFileDialogPrivate::encodeFileName( (*it).mid(1) ) ); + } else { + u = TQUrl( d->url, TQFileDialogPrivate::encodeFileName( (*it) ) ); + } + if ( u.isLocalFile() ) { + TQString s = u.toString(); + if ( s.left( 5 ) == "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 TQFileDialog. + \endomit +*/ + +void TQFileDialog::setSelection( const TQString & filename ) +{ + d->oldUrl = d->url; + TQString nf = d->url.nameFilter(); + if ( TQUrl::isRelativeUrl( filename ) ) + d->url = TQUrlOperator( d->url, TQFileDialogPrivate::encodeFileName( filename ) ); + else + d->url = TQUrlOperator( filename ); + d->url.setNameFilter( nf ); + d->checkForFilter = TRUE; + bool isDirOk; + bool isDir = d->url.isDir( &isDirOk ); + if ( !isDirOk ) + isDir = d->url.path().right( 1 ) == "/"; + if ( !isDir ) { + TQUrlOperator 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 ) != "/" ) { + TQString p = d->url.path(); + p += "/"; + d->url.setPath( p ); + } + trySetSelection( TRUE, d->url, FALSE ); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + nameEdit->setText( TQString::tqfromLatin1("") ); + } + d->checkForFilter = FALSE; +} + +/*! + \property TQFileDialog::dirPath + + \brief the file dialog's working directory + + \sa dir(), setDir() +*/ + +TQString TQFileDialog::dirPath() const +{ + return d->url.dirPath(); +} + + +/*! + + Sets the filter used in the file dialog to \a newFilter. + + If \a newFilter tqcontains a pair of parentheses containing one or more + of <em><b>anything*something</b></em> separated by spaces or by + semi-colons then only the text contained in the parentheses is used as + the filter. This means that these calls are all equivalent: + + \code + fd->setFilter( "All C++ files (*.cpp *.cc *.C *.cxx *.c++)" ); + fd->setFilter( "*.cpp *.cc *.C *.cxx *.c++" ); + fd->setFilter( "All C++ files (*.cpp;*.cc;*.C;*.cxx;*.c++)" ); + fd->setFilter( "*.cpp;*.cc;*.C;*.cxx;*.c++" ); + \endcode + + \sa setFilters() +*/ + +void TQFileDialog::setFilter( const TQString & newFilter ) +{ + if ( newFilter.isEmpty() ) + return; + TQString f = newFilter; + TQRegExp r( TQString::tqfromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( 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 TQFileDialog::setDir( const TQString & pathstr ) +{ + TQString dr = pathstr; + if ( dr.isEmpty() ) + return; + +#if defined(TQ_OS_UNIX) + if ( dr.length() && dr[0] == '~' ) { + int i = 0; + while( i < (int)dr.length() && dr[i] != '/' ) + i++; + TQCString user; + if ( i == 1 ) { +#if defined(TQT_THREAD_SUPPORT) && 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.isNull() ) +#endif + user = getenv( "LOGNAME" ); + } else + user = TQT_TQSTRING(dr.mid( 1, i-1 )).local8Bit(); + dr = dr.mid( i, dr.length() ); + struct passwd *pw; +#if defined(TQT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(TQ_OS_FREEBSD) && !defined(TQ_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( TQString::fromLocal8Bit(pw->pw_dir) ); + } +#endif + + setUrl( dr ); +} + +/*! + Returns the current directory shown in the file dialog. + + The ownership of the TQDir pointer is transferred to the caller, so + it must be deleted by the caller when no longer required. + + \sa setDir() +*/ + +const TQDir *TQFileDialog::dir() const +{ + if ( d->url.isLocalFile() ) + return new TQDir( d->url.path() ); + else + return 0; +} + +/*! + Sets the file dialog's working directory to \a dir. + \sa dir() +*/ + +void TQFileDialog::setDir( const TQDir &dir ) +{ + d->oldUrl = d->url; + TQString nf( d->url.nameFilter() ); + d->url = dir.canonicalPath(); + d->url.setNameFilter( nf ); + TQUrlInfo i( d->url, nameEdit->text() ); + d->checkForFilter = TRUE; + trySetSelection( i.isDir(), TQUrlOperator( d->url, TQFileDialogPrivate::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 TQFileDialog::setUrl( const TQUrlOperator &url ) +{ + d->oldUrl = d->url; + TQString nf = d->url.nameFilter(); + + TQString operatorPath = url.toString( FALSE, FALSE ); + if ( TQUrl::isRelativeUrl( operatorPath ) ) { + d->url = TQUrl( d->url, operatorPath ); + } else { + d->url = url; + } + d->url.setNameFilter( nf ); + + d->checkForFilter = TRUE; + if ( !d->url.isDir() ) { + TQUrlOperator u = d->url; + d->url.setPath( d->url.dirPath() ); + trySetSelection( FALSE, u, FALSE ); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + TQString fn = u.fileName(); + nameEdit->setText( fn ); + } else { + trySetSelection( TRUE, d->url, FALSE ); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + } + d->checkForFilter = FALSE; +} + +/*! + \property TQFileDialog::showHiddenFiles + + \brief whether hidden files are shown in the file dialog + + The default is FALSE, i.e. don't show hidden files. +*/ + +void TQFileDialog::setShowHiddenFiles( bool s ) +{ + if ( s == bShowHiddenFiles ) + return; + + bShowHiddenFiles = s; + rereadDir(); +} + +bool TQFileDialog::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 TQFileDialog::rereadDir() +{ +#ifndef TQT_NO_CURSOR + if ( !d->cursorOverride ) { + TQApplication::setOverrideCursor( TQCursor( TQt::WaitCursor ) ); + d->cursorOverride = TRUE; + } +#endif + d->pendingItems.clear(); + if ( d->mimeTypeTimer->isActive() ) + d->mimeTypeTimer->stop(); + d->currListChildren = d->url.listChildren(); +#ifndef TQT_NO_CURSOR + if ( d->cursorOverride ) { + TQApplication::restoreOverrideCursor(); + d->cursorOverride = FALSE; + } +#endif +} + + +/*! + \fn void TQFileDialog::fileHighlighted( const TQString& ) + + This signal is emitted when the user highlights a file, i.e. makes + it the current file. + + \sa fileSelected(), filesSelected() +*/ + +/*! + \fn void TQFileDialog::fileSelected( const TQString& ) + + This signal is emitted when the user selects a file. + + \sa filesSelected(), fileHighlighted(), selectedFile() +*/ + +/*! + \fn void TQFileDialog::filesSelected( const TQStringList& ) + + This signal is emitted when the user selects one or more files in \e + ExistingFiles mode. + + \sa fileSelected(), fileHighlighted(), selectedFiles() +*/ + +/*! + \fn void TQFileDialog::dirEntered( const TQString& ) + + This signal is emitted when the user enters a directory. + + \sa dir() +*/ + +/*! + \fn void TQFileDialog::filterSelected( const TQString& ) + + This signal is emitted when the user selects a filter. + + \sa selectedFilter() +*/ + +extern bool qt_resolve_symlinks; // defined in qapplication.cpp +bool TQ_EXPORT qt_use_native_dialogs = TRUE; + +/*! + 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. + + \code + TQString s = TQFileDialog::getOpenFileName( + "/home", + "Images (*.png *.xpm *.jpg)", + this, + "open file dialog", + "Choose a file to open" ); + \endcode + + The function creates a modal file dialog called \a name, with + tqparent, \a tqparent. If a tqparent is not 0, the dialog will be shown + centered over the tqparent. + + 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 TQString::null. + + 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 TQFileDialog, 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 + TQTimers and if tqparent is not 0 then it will position the dialog just under + the tqparent's titlebar). + + 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() +*/ + +TQString TQFileDialog::getOpenFileName( const TQString & startWith, + const TQString& filter, + TQWidget *tqparent, const char* name, + const TQString& caption, + TQString *selectedFilter, + bool resolveSymlinks ) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + TQStringList filters; + if ( !filter.isEmpty() ) + filters = makeFiltersList( filter ); + + makeVariables(); + TQString 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() ) { + TQUrlOperator u( TQFileDialogPrivate::encodeFileName( startWith ) ); + if ( u.isLocalFile() && TQFileInfo( u.path() ).isDir() ) { + *workingDirectory = startWith; + } else { + if ( u.isLocalFile() ) { + TQFileInfo fi( u.dirPath() ); + if ( fi.exists() ) { + *workingDirectory = u.dirPath(); + initialSelection = u.fileName(); + } + } else { + *workingDirectory = u.toString(); + initialSelection = TQString::null;//u.fileName(); + } + } + } + + if ( workingDirectory->isNull() ) + *workingDirectory = ::toRootIfNotExists( TQDir::currentDirPath() ); + +#if defined(TQ_WS_WIN) + if ( qt_use_native_dialogs && tqApp->tqstyle().tqstyleHint( TQStyle::SH_GUIStyle ) == WindowsStyle ) + return winGetOpenFileName( initialSelection, filter, workingDirectory, + tqparent, name, caption, selectedFilter ); +#elif defined(TQ_WS_MAC) + if (qt_use_native_dialogs && (tqApp->tqstyle().inherits(TQMAC_DEFAULT_STYLE) + || tqApp->tqstyle().inherits("TQMacStyle"))) + return qt_mac_precomposeFileName(macGetOpenFileNames(filter, + startWith.isEmpty() ? 0 : workingDirectory, + tqparent, name, caption, selectedFilter, FALSE).first()); +#endif + + TQFileDialog *dlg = new TQFileDialog( *workingDirectory, TQString::null, tqparent, name ? name : "qt_filedlg_gofn", TRUE ); + + TQ_CHECK_PTR( dlg ); +#ifndef TQT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( TQFileDialog::tr( "Open" ) ); +#endif + + dlg->setFilters( filters ); + if ( selectedFilter ) + dlg->setFilter( *selectedFilter ); + dlg->setMode( TQFileDialog::ExistingFile ); + TQString result; + if ( !initialSelection.isEmpty() ) + dlg->setSelection( initialSelection ); + if ( dlg->exec() == TQDialog::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 tqparent, \a tqparent. + If a tqparent is not 0, the dialog will be shown centered over the + tqparent. + + \code + TQString s = TQFileDialog::getSaveFileName( + "/home", + "Images (*.png *.xpm *.jpg)", + this, + "save file dialog", + "Choose a filename to save under" ); + \endcode + + 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 TQString::null. + + 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 TQFileDialog, 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 + TQTimers and if tqparent is not 0 then it will position the dialog just under + the tqparent's titlebar. + + 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() +*/ + +TQString TQFileDialog::getSaveFileName( const TQString & startWith, + const TQString& filter, + TQWidget *tqparent, const char* name, + const TQString& caption, + TQString *selectedFilter, + bool resolveSymlinks) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + TQStringList filters; + if ( !filter.isEmpty() ) + filters = makeFiltersList( filter ); + + makeVariables(); + TQString initialSelection; + if ( !startWith.isEmpty() ) { + TQUrlOperator u( TQFileDialogPrivate::encodeFileName( startWith ) ); + if ( u.isLocalFile() && TQFileInfo( u.path() ).isDir() ) { + *workingDirectory = startWith; + } else { + if ( u.isLocalFile() ) { + TQFileInfo fi( u.dirPath() ); + if ( fi.exists() ) { + *workingDirectory = u.dirPath(); + initialSelection = u.fileName(); + } + } else { + *workingDirectory = u.toString(); + initialSelection = TQString::null;//u.fileName(); + } + } + } + + if ( workingDirectory->isNull() ) + *workingDirectory = ::toRootIfNotExists( TQDir::currentDirPath() ); + +#if defined(TQ_WS_WIN) + if ( qt_use_native_dialogs && tqApp->tqstyle().tqstyleHint( TQStyle::SH_GUIStyle ) == WindowsStyle ) + return winGetSaveFileName( initialSelection, filter, workingDirectory, + tqparent, name, caption, selectedFilter ); +#elif defined(TQ_WS_MAC) + if (qt_use_native_dialogs && (tqApp->tqstyle().inherits(TQMAC_DEFAULT_STYLE) + || tqApp->tqstyle().inherits("TQMacStyle"))) + return qt_mac_precomposeFileName(macGetSaveFileName(initialSelection, filter, + startWith.isEmpty() ? 0 : workingDirectory, tqparent, name, + caption, selectedFilter)); +#endif + + TQFileDialog *dlg = new TQFileDialog( *workingDirectory, TQString::null, tqparent, name ? name : "qt_filedlg_gsfn", TRUE ); + + TQ_CHECK_PTR( dlg ); +#ifndef TQT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( TQFileDialog::tr( "Save As" ) ); +#endif + + TQString result; + dlg->setFilters( filters ); + if ( selectedFilter ) + dlg->setFilter( *selectedFilter ); + dlg->setMode( TQFileDialog::AnyFile ); + if ( !initialSelection.isEmpty() ) + dlg->setSelection( initialSelection ); + if ( dlg->exec() == TQDialog::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 TQFileDialog::okClicked() +{ + TQString fn( nameEdit->text() ); + +#if defined(TQ_WS_WIN) + TQFileInfo fi( d->url.path() + fn ); + if ( fi.isSymLink() ) { + nameEdit->setText( fi.readLink() ); + } +#endif + + if ( fn.tqcontains("*") ) { + addFilter( fn ); + nameEdit->blockSignals( TRUE ); + nameEdit->setText( TQString::tqfromLatin1("") ); + nameEdit->blockSignals( FALSE ); + return; + } + + *workingDirectory = d->url; + detailViewMode = files->isVisible(); + updateLastSize(this); + + if ( isDirectoryMode( d->mode ) ) { + TQUrlInfo f( d->url, nameEdit->text() ); + if ( f.isDir() ) { + d->currentFileName = d->url; + if ( d->currentFileName.right(1) != "/" ) + d->currentFileName += '/'; + if ( f.name() != "." ) + 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() ) { + TQStringList sf = selectedFiles(); + bool isdir = FALSE; + if ( sf.count() == 1 ) { + TQUrlOperator u( d->url, sf[0] ); + bool ok; + isdir = u.isDir(&ok) && ok; + } + if ( !isdir ) { + emit filesSelected( sf ); + accept(); + return; + } + } + } + + if ( mode() == AnyFile ) { + TQUrlOperator u( d->url, TQFileDialogPrivate::encodeFileName(nameEdit->text()) ); + if ( !u.isDir() ) { + d->currentFileName = u; + emit fileSelected( selectedFile() ); + accept(); + return; + } + } + + if ( mode() == ExistingFile ) { + if ( !TQFileDialogPrivate::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.tqcontains( "*" ) ) { + emit fileSelected( selectedFile() ); + accept(); + } else { + TQUrlInfo f; + TQFileDialogPrivate::File * c + = (TQFileDialogPrivate::File *)files->currentItem(); + TQFileDialogPrivate::MCItem * m + = (TQFileDialogPrivate::MCItem *)d->moreFiles->item( d->moreFiles->currentItem() ); + if ( (c && files->isVisible() && files->hasFocus()) || + (m && d->moreFiles->isVisible() && d->moreFiles->hasFocus()) ) { + if ( c && files->isVisible() ) + f = c->info; + else + f = ( (TQFileDialogPrivate::File*)m->i )->info; + } else { + f = TQUrlInfo( d->url, nameEdit->text() ); + } + if ( f.isDir() ) { + setUrl( TQUrlOperator( d->url, TQFileDialogPrivate::encodeFileName(f.name() + "/" ) ) ); + d->checkForFilter = TRUE; + trySetSelection( TRUE, d->url, TRUE ); + d->checkForFilter = FALSE; + } else { + if ( !nameEdit->text().tqcontains( "/" ) && + !nameEdit->text().tqcontains( "\\" ) +#if defined(TQ_OS_WIN32) + && nameEdit->text()[ 1 ] != ':' +#endif + ) + addFilter( nameEdit->text() ); + else if ( nameEdit->text()[ 0 ] == '/' || + nameEdit->text()[ 0 ] == '\\' +#if defined(TQ_OS_WIN32) + || nameEdit->text()[ 1 ] == ':' +#endif + ) + setDir( nameEdit->text() ); + else if ( nameEdit->text().left( 3 ) == "../" || nameEdit->text().left( 3 ) == "..\\" ) + setDir( TQUrl( d->url.toString(), TQFileDialogPrivate::encodeFileName(nameEdit->text() ) ).toString() ); + } + nameEdit->setText( "" ); + } +} + +/*! + \internal + Activated when the "Filter" button is clicked. +*/ + +void TQFileDialog::filterClicked() +{ + // unused +} + +/*! + \internal + Activated when the "Cancel" button is clicked. +*/ + +void TQFileDialog::cancelClicked() +{ + *workingDirectory = d->url; + detailViewMode = files->isVisible(); + updateLastSize(this); + reject(); +} + + +/*!\reimp +*/ + +void TQFileDialog::resizeEvent( TQResizeEvent * e ) +{ + TQDialog::resizeEvent( e ); + updateGeometries(); +} + +/* + \internal + The only correct way to try to set currentFileName +*/ +bool TQFileDialog::trySetSelection( bool isDir, const TQUrlOperator &u, bool updatelined ) +{ + if ( !isDir && !u.path().isEmpty() && u.path().right( 1 ) == "/" ) + isDir = TRUE; + if ( u.fileName().tqcontains( "*") && d->checkForFilter ) { + TQString fn( u.fileName() ); + if ( fn.tqcontains( "*" ) ) { + addFilter( fn ); + d->currentFileName = TQString::null; + d->url.setFileName( TQString::null ); + nameEdit->setText( TQString::tqfromLatin1("") ); + return FALSE; + } + } + + if ( d->preview && d->preview->isVisible() ) + updatePreviews( u ); + + TQString old = d->currentFileName; + + if ( isDirectoryMode( mode() ) ) { + if ( isDir ) + d->currentFileName = u; + else + d->currentFileName = TQString::null; + } else if ( !isDir && mode() == ExistingFiles ) { + d->currentFileName = u; + } else if ( !isDir || ( mode() == AnyFile && !isDir ) ) { + d->currentFileName = u; + } else { + d->currentFileName = TQString::null; + } + 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() != ".." ) { + TQString fn = u.fileName(); + nameEdit->setText( fn ); + } else { + nameEdit->setText(""); + } + } else + nameEdit->setText( TQString::tqfromLatin1("") ); + } + + 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 TQFileDialog::updateGeometries() +{ + if ( !d || !d->tqgeometryDirty ) + return; + + d->tqgeometryDirty = FALSE; + + TQSize r, t; + + // we really should have a TQSize::unite() +#define RM r.setWidth( TQMAX(r.width(),t.width()) ); \ +r.setHeight( TQMAX(r.height(),t.height()) ) + + // labels first + r = d->pathL->tqsizeHint(); + t = d->fileL->tqsizeHint(); + RM; + t = d->typeL->tqsizeHint(); + RM; + d->pathL->setFixedSize( d->pathL->tqsizeHint() ); + d->fileL->setFixedSize( r ); + d->typeL->setFixedSize( r ); + + // single-line input areas + r = d->paths->tqsizeHint(); + t = nameEdit->tqsizeHint(); + RM; + t = d->types->tqsizeHint(); + RM; + r.setWidth( t.width() * 2 / 3 ); + t.setWidth( TQWIDGETSIZE_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 = TQSize( 0, d->paths->tqminimumSize().height() ); + t = TQSize( 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 ); + + TQButton *b = 0; + if ( !d->toolButtons.isEmpty() ) { + for ( b = d->toolButtons.first(); b; b = d->toolButtons.next() ) + b->setFixedSize( b->tqsizeHint().width(), r.height() ); + } + + if ( d->infoPreview ) { + d->previewInfo->show(); + d->previewInfo->setFixedSize( r ); + } else { + d->previewInfo->hide(); + d->previewInfo->setFixedSize( TQSize( 0, 0 ) ); + } + + if ( d->contentsPreview ) { + d->previewContents->show(); + d->previewContents->setFixedSize( r ); + } else { + d->previewContents->hide(); + d->previewContents->setFixedSize( TQSize( 0, 0 ) ); + } + + // open/save, cancel + r = TQSize( 75, 20 ); + t = okB->tqsizeHint(); + RM; + t = cancelB->tqsizeHint(); + 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 TQFileDialog::updateFileNameEdit( TQListViewItem * newItem ) +{ + if ( !newItem ) + return; + + if ( mode() == ExistingFiles ) { + detailViewSelectionChanged(); + TQUrl u( d->url, TQFileDialogPrivate::encodeFileName( ((TQFileDialogPrivate::File*)files->currentItem())->info.name() ) ); + TQFileInfo fi( u.toString( FALSE, FALSE ) ); + if ( !fi.isDir() ) + emit fileHighlighted( u.toString( FALSE, FALSE ) ); + } else if ( files->isSelected( newItem ) ) { + TQFileDialogPrivate::File * i = (TQFileDialogPrivate::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 + TQString encFile = TQFileDialogPrivate::encodeFileName( newItem->text( 0 ) ); + trySetSelection( i->info.isDir(), TQUrlOperator( d->url, encFile ), TRUE ); + } +} + +void TQFileDialog::detailViewSelectionChanged() +{ + if ( d->mode != ExistingFiles ) + return; + + nameEdit->clear(); + TQString str; + TQListViewItem * i = files->firstChild(); + d->moreFiles->blockSignals( TRUE ); + while( i ) { + if ( d->moreFiles && isVisible() ) { + TQFileDialogPrivate::File *f = (TQFileDialogPrivate::File *)i; + if ( f->i && f->i->isSelected() != i->isSelected() ) + d->moreFiles->setSelected( f->i, i->isSelected() ); + } + if ( i->isSelected() && !( (TQFileDialogPrivate::File *)i )->info.isDir() ) + str += TQString( "\"%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() ) { + TQUrl u = TQUrl( d->url, TQFileDialogPrivate::encodeFileName( ((TQFileDialogPrivate::File*)files->currentItem())->info.name() ) ); + updatePreviews( u ); + } +} + +void TQFileDialog::listBoxSelectionChanged() +{ + if ( d->mode != ExistingFiles ) + return; + + if ( d->ignoreNextRefresh ) { + d->ignoreNextRefresh = FALSE; + return; + } + + nameEdit->clear(); + TQString str; + TQListBoxItem * i = d->moreFiles->item( 0 ); + TQListBoxItem * j = 0; + int index = 0; + files->blockSignals( TRUE ); + while( i ) { + TQFileDialogPrivate::MCItem *mcitem = (TQFileDialogPrivate::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 TQListBox 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(TQListViewItem) 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 ) { + TQUrl u( d->url, TQFileDialogPrivate::encodeFileName( ((TQFileDialogPrivate::File*)(mcitem)->i)->info.name()) ); + d->lastEFSelected = i; + emit fileHighlighted( u.toString(FALSE, FALSE) ); + } + } + } + if ( d->moreFiles->isSelected( i ) + && !( (TQFileDialogPrivate::File*)(mcitem)->i )->info.isDir() ) { + str += TQString( "\"%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 ) { + TQUrl u = TQUrl( d->url, + TQFileDialogPrivate::encodeFileName( ( (TQFileDialogPrivate::File*)( (TQFileDialogPrivate::MCItem*)j )->i )->info.name() ) ); + updatePreviews( u ); + } +} + +/*! \overload */ + +void TQFileDialog::updateFileNameEdit( TQListBoxItem * newItem ) +{ + if ( !newItem ) + return; + TQFileDialogPrivate::MCItem * i = (TQFileDialogPrivate::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 TQFileDialog::fileNameEditDone() +{ + TQUrlInfo f( d->url, nameEdit->text() ); + if ( mode() != TQFileDialog::ExistingFiles ) { + TQUrlOperator u( d->url, TQFileDialogPrivate::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 TQFileDialog::selectDirectoryOrFile( TQListViewItem * newItem ) +{ + + *workingDirectory = d->url; + detailViewMode = files->isVisible(); + updateLastSize(this); + + if ( !newItem ) + return; + + if ( d->url.isLocalFile() ) { + TQFileInfo fi( d->url.path() + newItem->text(0) ); +#if defined(TQ_WS_WIN) + if ( fi.isSymLink() ) { + nameEdit->setText( fi.readLink() ); + okClicked(); + return; + } +#endif + } + + TQFileDialogPrivate::File * i = (TQFileDialogPrivate::File *)newItem; + + TQString oldName = nameEdit->text(); + if ( i->info.isDir() ) { + setUrl( TQUrlOperator( d->url, TQFileDialogPrivate::encodeFileName( i->info.name() ) + "/" ) ); + if ( isDirectoryMode( mode() ) ) { + TQUrlInfo f ( d->url, TQString::tqfromLatin1( "." ) ); + trySetSelection( f.isDir(), d->url, TRUE ); + } + } else if ( newItem->isSelectable() && + trySetSelection( i->info.isDir(), TQUrlOperator( d->url, TQFileDialogPrivate::encodeFileName( i->info.name() ) ), TRUE ) ) { + if ( !isDirectoryMode( mode() ) ) { + if ( mode() == ExistingFile ) { + if ( TQFileDialogPrivate::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 TQFileDialog::selectDirectoryOrFile( TQListBoxItem * newItem ) +{ + if ( !newItem ) + return; + + TQFileDialogPrivate::MCItem * i = (TQFileDialogPrivate::MCItem *)newItem; + if ( i->i ) { + i->i->listView()->setSelected( i->i, i->isSelected() ); + selectDirectoryOrFile( i->i ); + } +} + + +void TQFileDialog::popupContextMenu( TQListViewItem *item, const TQPoint &p, + int ) +{ + if ( item ) { + files->setCurrentItem( item ); + files->setSelected( item, TRUE ); + } + + PopupAction action; + popupContextMenu( item ? item->text( 0 ) : TQString::null, 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 ) : TQString::null ); + else if ( action == PA_Reload ) + rereadDir(); + else if ( action == PA_Hidden ) { + bShowHiddenFiles = !bShowHiddenFiles; + rereadDir(); + } else if ( action == PA_SortName ) { + sortFilesBy = (int)TQDir::Name; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortSize ) { + sortFilesBy = (int)TQDir::Size; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortDate ) { + sortFilesBy = (int)TQDir::Time; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortUnsorted ) { + sortFilesBy = (int)TQDir::Unsorted; + sortAscending = TRUE; + resortDir(); + } + +} + +void TQFileDialog::popupContextMenu( TQListBoxItem *item, const TQPoint & p ) +{ + PopupAction action; + popupContextMenu( item ? item->text() : TQString::null, 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)TQDir::Name; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortSize ) { + sortFilesBy = (int)TQDir::Size; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortDate ) { + sortFilesBy = (int)TQDir::Time; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortUnsorted ) { + sortFilesBy = (int)TQDir::Unsorted; + sortAscending = TRUE; + resortDir(); + } +} + +void TQFileDialog::popupContextMenu( const TQString &filename, bool, + PopupAction &action, const TQPoint &p ) +{ + action = PA_Cancel; + + bool glob = filename.isEmpty(); + + TQPopupMenu m( 0, "file dialog context menu" ); + m.setCheckable( TRUE ); + + if ( !glob ) { + TQString okt; + if ( TQUrlInfo( d->url, 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() || !TQUrlInfo( d->url, filename ).isWritable() || + filename == ".." ) { + if ( filename.isEmpty() || !TQUrlInfo( d->url, filename ).isReadable() ) + m.setItemEnabled( ok, FALSE ); + m.setItemEnabled( rename, FALSE ); + m.setItemEnabled( del, FALSE ); + } + + m.move( p ); + int res = m.exec(); + + 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" ) ); + + TQPopupMenu 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)TQDir::Name ) + m2.setItemChecked( sname, TRUE ); + else if ( sortFilesBy == (int)TQDir::Size ) + m2.setItemChecked( ssize, TRUE ); +// else if ( sortFilesBy == 0x16 ) +// m2.setItemChecked( stype, TRUE ); + else if ( sortFilesBy == (int)TQDir::Time ) + m2.setItemChecked( sdate, TRUE ); + else if ( sortFilesBy == (int)TQDir::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(); + + 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 TQFileDialog::deleteFile( const TQString &filename ) +{ + if ( filename.isEmpty() ) + return; + + TQUrlInfo fi( d->url, TQFileDialogPrivate::encodeFileName( filename ) ); + TQString t = tr( "the file" ); + if ( fi.isDir() ) + t = tr( "the directory" ); + if ( fi.isSymLink() ) + t = tr( "the symlink" ); + + if ( TQMessageBox::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" ), TQString::null, 1 ) == 0 ) + d->url.remove( TQFileDialogPrivate::encodeFileName( filename ) ); + +} + +void TQFileDialog::fileSelected( int ) +{ + // unused +} + +void TQFileDialog::fileHighlighted( int ) +{ + // unused +} + +void TQFileDialog::dirSelected( int ) +{ + // unused +} + +void TQFileDialog::pathSelected( int ) +{ + // unused +} + + +void TQFileDialog::cdUpClicked() +{ + TQString oldName = nameEdit->text(); + setUrl( TQUrlOperator( d->url, ".." ) ); + if ( !oldName.isEmpty() ) + nameEdit->setText( oldName ); +} + +void TQFileDialog::newFolderClicked() +{ + TQString foldername( tr( "New Folder 1" ) ); + int i = 0; + TQStringList lst; + TQListViewItemIterator it( files ); + for ( ; it.current(); ++it ) + if ( it.current()->text( 0 ).tqcontains( tr( "New Folder" ) ) ) + lst.append( it.current()->text( 0 ) ); + + if ( !lst.count() == 0 ) + while ( lst.tqcontains( foldername ) ) + foldername = tr( "New Folder %1" ).arg( ++i ); + + d->url.mkdir( foldername ); +} + +void TQFileDialog::createdDirectory( const TQUrlInfo &info, TQNetworkOperation * ) +{ + 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 { + TQListViewItem *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. + + \code + TQString s = TQFileDialog::getExistingDirectory( + "/home", + this, + "get existing directory", + "Choose a directory", + TRUE ); + \endcode + + This function creates a modal file dialog called \a name, with + tqparent, \a tqparent. If tqparent is not 0, the dialog will be shown + centered over the tqparent. + + The dialog's working directory is set to \a dir, and the caption is + set to \a caption. Either of these may be TQString::null in which case + the current directory and a default caption will be used respectively. + + Note on Windows that if \a dir is TQString::null then the dialog's working + directory will be set to the user's My Documents directory. + + 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. + + Under Windows and Mac OS X, this static function will use the native + file dialog and not a TQFileDialog, 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 + TQTimers and if tqparent is not 0 then it will position the dialog just under + the tqparent's titlebar). + + \sa getOpenFileName(), getOpenFileNames(), getSaveFileName() +*/ + +TQString TQFileDialog::getExistingDirectory( const TQString & dir, + TQWidget *tqparent, + const char* name, + const TQString& caption, + bool dirOnly, + bool resolveSymlinks) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + makeVariables(); + TQString wd; + if ( workingDirectory ) + wd = *workingDirectory; + +#if defined(TQ_WS_WIN) + TQString initialDir; + if ( !dir.isEmpty() ) { + TQUrlOperator u( dir ); + if ( TQFileInfo( u.path() ).isDir() ) + initialDir = dir; + } else + initialDir = TQString::null; + if ( qt_use_native_dialogs && tqApp->tqstyle().tqstyleHint( TQStyle::SH_GUIStyle ) == WindowsStyle && dirOnly ) + return winGetExistingDirectory( initialDir, tqparent, name, caption ); +#endif +#if defined(TQ_WS_MAC) + TQString *initialDir = 0; + if (!dir.isEmpty()) { + TQUrlOperator u(dir); + if (TQFileInfo(u.path()).isDir()) + initialDir = (TQString *)&dir; + } + if( qt_use_native_dialogs && (tqApp->tqstyle().inherits(TQMAC_DEFAULT_STYLE) + || tqApp->tqstyle().inherits("TQMacStyle"))) + return qt_mac_precomposeFileName(macGetOpenFileNames("", initialDir, tqparent, name, + caption, 0, FALSE, TRUE).first()); +#endif + + TQFileDialog *dlg = new TQFileDialog( tqparent, name ? name : "qt_filedlg_ged", TRUE ); + + TQ_CHECK_PTR( dlg ); +#ifndef TQT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( TQFileDialog::tqtr("Find Directory") ); +#endif + + dlg->setMode( dirOnly ? DirectoryOnly : Directory ); + + dlg->d->types->clear(); + dlg->d->types->insertItem( TQFileDialog::tqtr("Directories") ); + dlg->d->types->setEnabled( FALSE ); + + TQString dir_( dir ); + dir_ = dir_.simplifyWhiteSpace(); + if ( dir_.isEmpty() && !wd.isEmpty() ) + dir_ = wd; + TQUrlOperator u( dir_ ); + if ( u.isLocalFile() ) { + if ( !dir_.isEmpty() ) { + TQFileInfo f( u.path() ); + if ( f.exists() ) + if ( f.isDir() ) { + dlg->setDir( dir_ ); + wd = dir_; + } + } else if ( !wd.isEmpty() ) { + TQUrl tempUrl( wd ); + TQFileInfo f( tempUrl.path() ); + if ( f.isDir() ) { + dlg->setDir( wd ); + } + } else { + TQString theDir = dir_; + if ( theDir.isEmpty() ) { + theDir = ::toRootIfNotExists( TQDir::currentDirPath() ); + } if ( !theDir.isEmpty() ) { + TQUrl tempUrl( theDir ); + TQFileInfo f( tempUrl.path() ); + if ( f.isDir() ) { + wd = theDir; + dlg->setDir( theDir ); + } + } + } + } else { + dlg->setUrl( dir_ ); + } + + TQString result; + dlg->setSelection( dlg->d->url.toString() ); + + if ( dlg->exec() == TQDialog::Accepted ) { + result = dlg->selectedFile(); + wd = result; + } + delete dlg; + + if ( !result.isEmpty() && result.right( 1 ) != "/" ) + result += "/"; + + qt_resolve_symlinks = save_qt_resolve_symlinks; + + return result; +} + + +/*! + \property TQFileDialog::mode + \brief the file dialog's mode + + The default mode is \c ExistingFile. +*/ + +void TQFileDialog::setMode( Mode newMode ) +{ + if ( d->mode != newMode ) { + d->mode = newMode; + TQString sel = d->currentFileName; + int maxnamelen = 255; // _POSIX_MAX_PATH + if ( isDirectoryMode( newMode ) ) { + files->setSelectionMode( TQListView::Single ); + d->moreFiles->setSelectionMode( TQListBox::Single ); + if ( sel.isNull() ) + sel = TQString::tqfromLatin1("."); + d->types->setEnabled( FALSE ); + } else if ( newMode == ExistingFiles ) { + maxnamelen = INT_MAX; + files->setSelectionMode( TQListView::Extended ); + d->moreFiles->setSelectionMode( TQListBox::Extended ); + d->types->setEnabled( TRUE ); + } else { + files->setSelectionMode( TQListView::Single ); + d->moreFiles->setSelectionMode( TQListBox::Single ); + d->types->setEnabled( TRUE ); + } + nameEdit->setMaxLength(maxnamelen); + rereadDir(); + TQUrlInfo f( d->url, "." ); + trySetSelection( f.isDir(), d->url, FALSE ); + } + + TQString 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() == "Directories" ) { + changeFilters = TRUE; + } + } + } + else if ( mode() == Directory || mode() == DirectoryOnly ) { + okt = tr("&OK"); + d->fileL->setText( tr("Directory:") ); + d->types->clear(); + d->types->insertItem( tqtr("Directories") ); + } + else { + okt = tr("&Open"); + d->fileL->setText( tqtr("File &name:") ); + if ( d->types->count() == 1 ) { + d->types->setCurrentItem( 0 ); + if ( d->types->currentText() == "Directories" ) { + changeFilters = TRUE; + } + } + } + + if ( changeFilters ) { + d->types->clear(); + d->types->insertItem( tqtr("All Files (*)") ); + } + + okB->setText( okt ); +} + +TQFileDialog::Mode TQFileDialog::mode() const +{ + return d->mode; +} + +/*! \reimp +*/ + +void TQFileDialog::done( int i ) +{ + if ( i == TQDialog::Accepted && (d->mode == ExistingFile || d->mode == ExistingFiles) ) { + TQStringList selection = selectedFiles(); + for ( uint f = 0; f < selection.count(); f++ ) { + TQString file = selection[f]; + if ( file.isNull() ) + continue; + if ( d->url.isLocalFile() && !TQFile::exists( file ) ) { + TQMessageBox::information( this, tr("Error"), + tr("%1\nFile not found.\nCheck path and filename.").arg( file ) ); + return; + } + } + } + TQDialog::done( i ); +} + +/*! + \property TQFileDialog::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 TQFileDialog::ViewMode +*/ + + +TQFileDialog::ViewMode TQFileDialog::viewMode() const +{ + if ( detailViewMode ) + return Detail; + else + return List; +} + +void TQFileDialog::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 TQFileDialog::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 TQFileDialog::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 ) ); + } +} +TQFileDialog::PreviewMode TQFileDialog::previewMode() const +{ + if ( d->infoPreview && d->infoPreviewWidget->isVisible() ) + return Info; + else if ( d->contentsPreview && d->contentsPreviewWidget->isVisible() ) + return Contents; + + return NoPreview; +} + + +/*! + Adds the specified widgets to the bottom of the file dialog. The + label \a l is placed underneath the "file name" and the "file types" + labels. The widget \a w is placed underneath the file types combobox. + The button \a b is placed underneath the Cancel pushbutton. + + \code + MyFileDialog::MyFileDialog( TQWidget* tqparent, const char* name ) : + TQFileDialog( tqparent, name ) + { + TQLabel* label = new TQLabel( "Added widgets", this ); + TQLineEdit* lineedit = new TQLineEdit( this ); + TQPushButton* pushbutton = new TQPushButton( this ); + + addWidgets( label, lineedit, pushbutton ); + } + \endcode + + 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 TQFileDialog::addWidgets( TQLabel * l, TQWidget * w, TQPushButton * b ) +{ + if ( !l && !w && !b ) + return; + + d->tqgeometryDirty = TRUE; + + TQHBoxLayout *lay = new TQHBoxLayout(); + d->extraWidgetsLayouts.append( lay ); + d->topLevelLayout->addLayout( lay ); + + if ( !l ) + l = new TQLabel( this, "qt_intern_lbl" ); + d->extraLabels.append( l ); + lay->addWidget( l ); + + if ( !w ) + w = new TQWidget( this, "qt_intern_widget" ); + d->extraWidgets.append( w ); + lay->addWidget( w ); + lay->addSpacing( 15 ); + + if ( b ) { + d->extraButtons.append( b ); + lay->addWidget( b ); + } else { + TQWidget *wid = new TQWidget( 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 TQFileDialog::addToolButton( TQButton *b, bool separator ) +{ + if ( !b || !d->buttonLayout ) + return; + + d->tqgeometryDirty = 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 TQFileDialog::addLeftWidget( TQWidget *w ) +{ + if ( !w ) + return; + d->tqgeometryDirty = 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 TQFileDialog::addRightWidget( TQWidget *w ) +{ + if ( !w ) + return; + d->tqgeometryDirty = TRUE; + + d->rightLayout->addSpacing( 5 ); + d->rightLayout->addWidget( w ); + + updateGeometries(); +} + +/*! \reimp */ + +void TQFileDialog::keyPressEvent( TQKeyEvent * 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 == TQUrl(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 + TQUrlInfo i( d->url, nameEdit->text() ); + if ( i.isDir() ) { + nameEdit->setText( TQString::tqfromLatin1("") ); + setDir( TQUrlOperator( d->url, TQFileDialogPrivate::encodeFileName(i.name()) ) ); + } + ke->accept(); + } else if ( mode() == ExistingFiles ) { + TQUrlInfo i( d->url, nameEdit->text() ); + if ( i.isFile() ) { + TQListViewItem * 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() == Key_Escape ) { + ke->ignore(); + } + + d->ignoreNextKeyPress = FALSE; + + if ( !ke->isAccepted() ) { + TQDialog::keyPressEvent( ke ); + } +} + + +/*! \class TQFileIconProvider tqfiledialog.h + + \brief The TQFileIconProvider class provides icons for TQFileDialog to + use. + + \ingroup misc + + By default TQFileIconProvider is not used, but any application or + library can subclass it, reimplement pixmap() to return a suitable + icon, and make all TQFileDialog objects use it by calling the static + function TQFileDialog::setIconProvider(). + + It is advisable to make all the icons that TQFileIconProvider returns be + the same size or at least the same width. This makes the list view + look much better. + + \sa TQFileDialog +*/ + + +/*! Constructs an empty file icon provider called \a name, with the + tqparent \a tqparent. +*/ + +TQFileIconProvider::TQFileIconProvider( TQObject * tqparent, const char* name ) + : TQObject( tqparent, 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, TQFileDialog 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 TQPixmap * TQFileIconProvider::pixmap( const TQFileInfo & 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 TQFileIconProvider used by the file dialog to \a provider. + + The default is that there is no TQFileIconProvider and TQFileDialog + just draws a folder icon next to each directory and nothing next + to files. + + \sa TQFileIconProvider, iconProvider() +*/ + +void TQFileDialog::setIconProvider( TQFileIconProvider * 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(), TQFileIconProvider +*/ + +TQFileIconProvider * TQFileDialog::iconProvider() +{ + return fileIconProvider; +} + + +#if defined(TQ_WS_WIN) + +// ### FIXME: this code is duplicated in qdns.cpp +static TQString getWindowsRegString( HKEY key, const TQString &subKey ) +{ + TQString s; + TQT_WA( { + char buf[1024]; + DWORD bsz = sizeof(buf); + int r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz ); + if ( r == ERROR_SUCCESS ) { + s = TQString::fromUcs2( (unsigned short *)buf ); + } else if ( r == ERROR_MORE_DATA ) { + char *ptr = new char[bsz+1]; + r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz ); + if ( r == ERROR_SUCCESS ) + s = ptr; + delete [] ptr; + } + } , { + char buf[512]; + DWORD bsz = sizeof(buf); + int r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz ); + if ( r == ERROR_SUCCESS ) { + s = buf; + } else if ( r == ERROR_MORE_DATA ) { + char *ptr = new char[bsz+1]; + r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz ); + if ( r == ERROR_SUCCESS ) + s = ptr; + delete [] ptr; + } + } ); + return s; +} + +static void initPixmap( TQPixmap &pm ) +{ + pm.fill( TQt::white ); +} + + +TQWindowsIconProvider::TQWindowsIconProvider( TQObject *tqparent, const char *name ) + : TQFileIconProvider( tqparent, name ) +{ + pixw = GetSystemMetrics( SM_CXSMICON ); + pixh = GetSystemMetrics( SM_CYSMICON ); + + HKEY k; + HICON si; + int r; + TQString s; + UINT res = 0; + + // ---------- get default folder pixmap + const wchar_t iconFolder[] = L"folder\\DefaultIcon"; // workaround for Borland + TQT_WA( { + r = RegOpenKeyEx( HKEY_CLASSES_ROOT, + iconFolder, + 0, KEY_READ, &k ); + } , { + r = RegOpenKeyExA( HKEY_CLASSES_ROOT, + "folder\\DefaultIcon", + 0, KEY_READ, &k ); + } ); + resolveLibs(); + if ( r == ERROR_SUCCESS ) { + s = getWindowsRegString( k, TQString::null ); + RegCloseKey( k ); + + TQStringList lst = TQStringList::split( ",", s ); + + if (lst.count() >= 2) { // don't just assume that lst has two entries +#ifndef TQ_OS_TEMP + TQT_WA( { + res = ptrExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(), + lst[ 1 ].simplifyWhiteSpace().toInt(), + 0, &si, 1 ); + } , { + res = ExtractIconExA( lst[ 0 ].simplifyWhiteSpace().local8Bit(), + lst[ 1 ].simplifyWhiteSpace().toInt(), + 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(), + lst[ 1 ].simplifyWhiteSpace().toInt(), + 0, &si, 1 ); +#endif + } + if ( res ) { + defaultFolder.resize( pixw, pixh ); + initPixmap( defaultFolder ); + TQPainter p( &defaultFolder ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + defaultFolder.setMask( defaultFolder.createHeuristicMask() ); + *closedFolderIcon = defaultFolder; + DestroyIcon( si ); + } else { + defaultFolder = *closedFolderIcon; + } + } else { + RegCloseKey( k ); + } + + //------------------------------- get default file pixmap +#ifndef TQ_OS_TEMP + TQT_WA( { + res = ptrExtractIconEx( L"shell32.dll", + 0, 0, &si, 1 ); + } , { + res = ExtractIconExA( "shell32.dll", + 0, 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( L"shell32.dll", + 0, 0, &si, 1 ); +#endif + + if ( res ) { + defaultFile.resize( pixw, pixh ); + initPixmap( defaultFile ); + TQPainter p( &defaultFile ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + defaultFile.setMask( defaultFile.createHeuristicMask() ); + *fileIcon = defaultFile; + DestroyIcon( si ); + } else { + defaultFile = *fileIcon; + } + + //------------------------------- get default exe pixmap +#ifndef TQ_OS_TEMP + TQT_WA( { + res = ptrExtractIconEx( L"shell32.dll", + 2, 0, &si, 1 ); + } , { + res = ExtractIconExA( "shell32.dll", + 2, 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( L"ceshell.dll", + 10, 0, &si, 1 ); +#endif + + if ( res ) { + defaultExe.resize( pixw, pixh ); + initPixmap( defaultExe ); + TQPainter p( &defaultExe ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + defaultExe.setMask( defaultExe.createHeuristicMask() ); + DestroyIcon( si ); + } else { + defaultExe = *fileIcon; + } +} + +TQWindowsIconProvider::~TQWindowsIconProvider() +{ + if ( this == fileIconProvider ) + fileIconProvider = 0; +} + +const TQPixmap * TQWindowsIconProvider::pixmap( const TQFileInfo &fi ) +{ + if (fi.isSymLink()) { + TQString real = fi.readLink(); + if (!real.isEmpty()) + return pixmap(TQFileInfo(real)); + } + + TQString ext = fi.extension( FALSE ).upper(); + TQString key = ext; + ext.prepend( "." ); + TQMap< TQString, TQPixmap >::Iterator it; + + if ( fi.isDir() ) { + return &defaultFolder; + } else if ( ext != ".EXE" ) { + it = cache.tqfind( key ); + if ( it != cache.end() ) + return &( *it ); + + HKEY k, k2; + int r; + TQT_WA( { + r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)ext.ucs2(), + 0, KEY_READ, &k ); + } , { + r = RegOpenKeyExA( HKEY_CLASSES_ROOT, ext.local8Bit(), + 0, KEY_READ, &k ); + } ); + TQString s; + if ( r == ERROR_SUCCESS ) { + s = getWindowsRegString( k, TQString::null ); + } else { + cache[ key ] = defaultFile; + RegCloseKey( k ); + return &defaultFile; + } + RegCloseKey( k ); + + TQT_WA( { + r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)TQString( s + "\\DefaultIcon" ).ucs2(), + 0, KEY_READ, &k2 ); + } , { + r = RegOpenKeyExA( HKEY_CLASSES_ROOT, TQString( s + "\\DefaultIcon" ).local8Bit() , + 0, KEY_READ, &k2 ); + } ); + if ( r == ERROR_SUCCESS ) { + s = getWindowsRegString( k2, TQString::null ); + } else { + cache[ key ] = defaultFile; + RegCloseKey( k2 ); + return &defaultFile; + } + RegCloseKey( k2 ); + + TQStringList lst = TQStringList::split( ",", s ); + + HICON si; + UINT res = 0; + if (lst.count() >= 2) { // don't just assume that lst has two entries + TQString filepath = lst[ 0 ].stripWhiteSpace(); + if ( !filepath.isEmpty() ) { + if ( filepath.tqfind("%1") != -1 ) { + filepath = filepath.arg( fi.filePath() ); + if ( ext == ".DLL" ) { + pix = defaultFile; + return &pix; + } + } + if ( filepath[0] == '"' && filepath[(int)filepath.length()-1] == '"' ) + filepath = filepath.mid( 1, filepath.length()-2 ); + + resolveLibs(); +#ifndef TQ_OS_TEMP + TQT_WA( { + res = ptrExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(), + 0, &si, 1 ); + } , { + res = ExtractIconExA( filepath.local8Bit(), lst[ 1 ].stripWhiteSpace().toInt(), + 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(), + 0, &si, 1 ); +#endif + } + } + + if ( res ) { + pix.resize( pixw, pixh ); + initPixmap( pix ); + TQPainter p( &pix ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + pix.setMask( pix.createHeuristicMask() ); + DestroyIcon( si ); + } else { + pix = defaultFile; + } + + cache[ key ] = pix; + return &pix; + } else { + HICON si; + UINT res = 0; + if ( !fi.absFilePath().isEmpty() ) { +#ifndef TQ_OS_TEMP + TQT_WA( { + res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1, + 0, 0, 1 ); + } , { + res = ExtractIconExA( fi.absFilePath().local8Bit(), -1, + 0, 0, 1 ); + } ); + + if ( res ) { + TQT_WA( { + res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1, + 0, &si, 1 ); + } , { + res = ExtractIconExA( fi.absFilePath().local8Bit(), res - 1, + 0, &si, 1 ); + } ); + } +#else + res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1, + 0, 0, 1 ); + if ( res ) + res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1, + 0, &si, 1 ); +#endif + + } + + if ( res ) { + pix.resize( pixw, pixh ); + initPixmap( pix ); + TQPainter p( &pix ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + pix.setMask( pix.createHeuristicMask() ); + DestroyIcon( si ); + } else { + pix = defaultExe; + } + + return &pix; + } + + // can't happen! + return 0; +} +#endif + + + +/*! + \reimp +*/ +bool TQFileDialog::eventFilter( TQObject * o, TQEvent * e ) +{ + if ( e->type() == TQEvent::KeyPress && ( (TQKeyEvent*)e )->key() == Qt::Key_F5 ) { + rereadDir(); + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && ( (TQKeyEvent*)e )->key() == Qt::Key_F2 && + ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files->viewport()) ) ) { + if ( files->isVisible() && files->currentItem() ) { + if ( TQUrlInfo( d->url, "." ).isWritable() && files->currentItem()->text( 0 ) != ".." ) { + files->renameItem = files->currentItem(); + files->startRename( TRUE ); + } + } + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && ( (TQKeyEvent*)e )->key() == Qt::Key_F2 && + ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles->viewport()) ) ) { + if ( d->moreFiles->isVisible() && d->moreFiles->currentItem() != -1 ) { + if ( TQUrlInfo( d->url, "." ).isWritable() && + d->moreFiles->item( d->moreFiles->currentItem() )->text() != ".." ) { + d->moreFiles->renameItem = d->moreFiles->item( d->moreFiles->currentItem() ); + d->moreFiles->startRename( TRUE ); + } + } + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && d->moreFiles->renaming ) { + d->moreFiles->lined->setFocus(); + TQApplication::sendEvent( d->moreFiles->lined, e ); + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && files->renaming ) { + files->lined->setFocus(); + TQApplication::sendEvent( files->lined, e ); + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && + ((TQKeyEvent *)e)->key() == Qt::Key_Backspace && + ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files) || + TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles) || + TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files->viewport()) || + TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles->viewport()) ) ) { + cdUpClicked(); + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && + ((TQKeyEvent *)e)->key() == Qt::Key_Delete && + ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files) || + TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files->viewport()) ) ) { + if ( files->currentItem() ) + deleteFile( files->currentItem()->text( 0 ) ); + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == TQEvent::KeyPress && + ((TQKeyEvent *)e)->key() == Qt::Key_Delete && + ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles) || + TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles->viewport()) ) ) { + int c = d->moreFiles->currentItem(); + if ( c >= 0 ) + deleteFile( d->moreFiles->item( c )->text() ); + ((TQKeyEvent *)e)->accept(); + return TRUE; + } else if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files) && e->type() == TQEvent::FocusOut && files->currentItem() ) { + } else if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(files) && e->type() == TQEvent::KeyPress ) { + TQTimer::singleShot( 0, this, TQT_SLOT(fixupNameEdit()) ); + } else if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(nameEdit) && e->type() == TQEvent::KeyPress && d->mode != AnyFile ) { + if ( ( nameEdit->cursorPosition() == (int)nameEdit->text().length() || nameEdit->hasSelectedText() ) && + isprint(((TQKeyEvent *)e)->ascii()) ) { +#if defined(TQ_WS_WIN) + TQString nt( nameEdit->text().lower() ); +#else + TQString nt( nameEdit->text() ); +#endif + nt.truncate( nameEdit->cursorPosition() ); + nt += (char)(((TQKeyEvent *)e)->ascii()); + TQListViewItem * i = files->firstChild(); +#if defined(TQ_WS_WIN) + while( i && i->text( 0 ).left(nt.length()).lower() != 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 ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(nameEdit) && e->type() == TQEvent::FocusIn ) { + fileNameEditDone(); + } else if ( d->moreFiles->renaming && TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(d->moreFiles->lined) && e->type() == TQEvent::FocusIn ) { + d->moreFiles->lined->setFocus(); + return TRUE; + } else if ( files->renaming && TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(files->lined) && e->type() == TQEvent::FocusIn ) { + files->lined->setFocus(); + return TRUE; + } else if ( ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles->viewport()) ) && + e->type() == TQEvent::FocusIn ) { + if ( (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles->viewport()) && !d->moreFiles->viewport()->hasFocus()) || + (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(d->moreFiles) && !d->moreFiles->hasFocus()) ) + ((TQWidget*)o)->setFocus(); + return FALSE; + } + + return TQDialog::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 semi-colons). + + \code + TQString types("Image files (*.png *.xpm *.jpg);;" + "Text files (*.txt);;" + "Any files (*)"); + TQFileDialog fd = new TQFileDialog( this ); + fd->setFilters( types ); + fd->show(); + \endcode + +*/ + +void TQFileDialog::setFilters( const TQString &filters ) +{ + TQStringList lst = makeFiltersList( filters ); + setFilters( lst ); +} + +/*! + \overload + + \a types must be a null-terminated list of strings. + +*/ + +void TQFileDialog::setFilters( const char ** types ) +{ + if ( !types || !*types ) + return; + + d->types->clear(); + while( types && *types ) { + d->types->insertItem( TQString::tqfromLatin1(*types) ); + types++; + } + d->types->setCurrentItem( 0 ); + setFilter( d->types->text( 0 ) ); +} + + +/*! \overload void TQFileDialog::setFilters( const TQStringList & ) +*/ + +void TQFileDialog::setFilters( const TQStringList & types ) +{ + if ( types.count() < 1 ) + return; + + d->types->clear(); + for ( TQStringList::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. + + \code + TQFileDialog* fd = new TQFileDialog( this ); + fd->addFilter( "Images (*.png *.jpg *.xpm)" ); + fd->show(); + \endcode + + 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 TQFileDialog::addFilter( const TQString &filter ) +{ + if ( filter.isEmpty() ) + return; + TQString f = filter; + TQRegExp r( TQString::tqfromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( f ); + if ( index >= 0 ) + f = r.cap( 2 ); + for ( int i = 0; i < d->types->count(); ++i ) { + TQString f2( d->types->text( i ) ); + int index = r.search( 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 TQFileDialog::modeButtonsDestroyed() +{ + if ( d ) + d->modeButtons = 0; +} + + +/*! + This is a convenience static function that will return one or more + existing files selected by the user. + + \code + TQStringList files = TQFileDialog::getOpenFileNames( + "Images (*.png *.xpm *.jpg)", + "/home", + this, + "open files dialog", + "Select one or more files to open" ); + \endcode + + This function creates a modal file dialog called \a name, with + tqparent \a tqparent. If \a tqparent is not 0, the dialog will be shown + centered over the tqparent. + + 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 TQString::null. + + 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 TQFileDialog, 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 + TQTimers and if tqparent is not 0 then it will position the dialog just under + the tqparent's titlebar). + + 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. + \code + TQStringList list = files; + TQStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + + \sa getOpenFileName(), getSaveFileName(), getExistingDirectory() +*/ + +TQStringList TQFileDialog::getOpenFileNames( const TQString & filter, + const TQString& dir, + TQWidget *tqparent, + const char* name, + const TQString& caption, + TQString *selectedFilter, + bool resolveSymlinks ) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + TQStringList filters; + if ( !filter.isEmpty() ) + filters = makeFiltersList( filter ); + + makeVariables(); + + if ( workingDirectory->isNull() ) + *workingDirectory = ::toRootIfNotExists( TQDir::currentDirPath() ); + + if ( !dir.isEmpty() ) { + // #### works only correct for local files + TQUrlOperator u( TQFileDialogPrivate::encodeFileName(dir) ); + if ( u.isLocalFile() && TQFileInfo( u.path() ).isDir() ) { + *workingDirectory = dir; + } else { + *workingDirectory = u.toString(); + } + } + +#if defined(TQ_WS_WIN) + if ( qt_use_native_dialogs && tqApp->tqstyle().tqstyleHint( TQStyle::SH_GUIStyle ) == WindowsStyle ) + return winGetOpenFileNames( filter, workingDirectory, tqparent, name, caption, selectedFilter ); +#elif defined(TQ_WS_MAC) + if (qt_use_native_dialogs && (tqApp->tqstyle().inherits(TQMAC_DEFAULT_STYLE) + || tqApp->tqstyle().inherits("TQMacStyle"))) { + TQStringList sl = macGetOpenFileNames(filter, dir.isEmpty() ? 0 : workingDirectory, tqparent, + name, caption, selectedFilter); + TQStringList::iterator it = sl.begin(); + while (it != sl.end()) { + *it = qt_mac_precomposeFileName(*it); + ++it; + } + return sl; + } +#endif + + TQFileDialog *dlg = new TQFileDialog( *workingDirectory, TQString::null, tqparent, name ? name : "qt_filedlg_gofns", TRUE ); + + TQ_CHECK_PTR( dlg ); +#ifndef TQT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( TQFileDialog::tr("Open") ); +#endif + + dlg->setFilters( filters ); + if ( selectedFilter ) + dlg->setFilter( *selectedFilter ); + dlg->setMode( TQFileDialog::ExistingFiles ); + TQString result; + TQStringList lst; + if ( dlg->exec() == TQDialog::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 TQListView. */ + +void TQFileDialog::fixupNameEdit() +{ + if ( files->currentItem() ) { + if ( ( (TQFileDialogPrivate::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() +*/ + +TQUrl TQFileDialog::url() const +{ + return d->url; +} + +static bool isRoot( const TQUrl &u ) +{ +#if defined(TQ_OS_MAC9) + TQString p = TQDir::convertSeparators(u.path()); + if(p.tqcontains(':') == 1) + return TRUE; +#elif defined(TQ_OS_UNIX) + if ( u.path() == "/" ) + return TRUE; +#elif defined(TQ_OS_WIN32) + TQString p = u.path(); + if ( p.length() == 3 && + p.right( 2 ) == ":/" ) + return TRUE; + if ( p[ 0 ] == '/' && p[ 1 ] == '/' ) { + int slashes = p.tqcontains( '/' ); + if ( slashes <= 3 ) + return TRUE; + if ( slashes == 4 && p[ (int)p.length() - 1 ] == '/' ) + return TRUE; + } +#else +#if defined(TQ_CC_GNU) +#warning "case not covered.." +#endif +#endif + + if ( !u.isLocalFile() && u.path() == "/" ) + return TRUE; + + return FALSE; +} + +void TQFileDialog::urlStart( TQNetworkOperation *op ) +{ + if ( !op ) + return; + +#if defined(TQ_WS_WIN) + qt_ntfs_permission_lookup--; +#endif + if ( op->operation() == TQNetworkProtocol::OpListChildren ) { +#ifndef TQT_NO_CURSOR + if ( !d->cursorOverride ) { + TQApplication::setOverrideCursor( TQCursor( TQt::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 ); + + TQString s = d->url.toString( FALSE, FALSE ); + bool found = FALSE; + for ( int i = 0; i < d->paths->count(); ++i ) { +#if defined(TQ_WS_WIN) + if ( d->paths->text( i ).lower() == s.lower() ) { +#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.last() != d->url.toString() ) { + d->history.append( d->url.toString() ); + if ( d->history.count() > 1 ) + d->goBack->setEnabled( TRUE ); + } + } +} + +void TQFileDialog::urlFinished( TQNetworkOperation *op ) +{ + if ( !op ) + return; + +#ifndef TQT_NO_CURSOR + if ( op->operation() == TQNetworkProtocol::OpListChildren && + d->cursorOverride ) { + TQApplication::restoreOverrideCursor(); + d->cursorOverride = FALSE; + } +#endif + + if ( op->state() == TQNetworkProtocol::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(); + TQMessageBox::critical( this, tr( "Error" ), op->protocolDetail() ); + + if ( ecode == TQNetworkProtocol::ErrListChildren || ecode == TQNetworkProtocol::ErrParse || + ecode == TQNetworkProtocol::ErrUnknownProtocol || ecode == TQNetworkProtocol::ErrLoginIncorrect || + ecode == TQNetworkProtocol::ErrValid || ecode == TQNetworkProtocol::ErrHostNotFound || + ecode == TQNetworkProtocol::ErrFileNotExisting ) { + if (!(d->url == d->oldUrl)) { + d->url = d->oldUrl; + rereadDir(); + } + } else { + // another error happened, no need to go back to last dir + } + } else if ( op->operation() == TQNetworkProtocol::OpListChildren && + op == d->currListChildren ) { + if ( !d->hadDotDot && !isRoot( d->url ) ) { + bool ok = TRUE; +#if defined(TQ_WS_WIN) + if ( d->url.path().left( 2 ) == "//" ) + ok = FALSE; +#endif + if ( ok ) { + TQUrlInfo ui( d->url, ".." ); + ui.setName( ".." ); + ui.setDir( TRUE ); + ui.setFile( FALSE ); + ui.setSymLink( FALSE ); + ui.setSize( 0 ); + TQValueList<TQUrlInfo> lst; + lst << ui; + insertEntry( lst, 0 ); + } + } + resortDir(); + } else if ( op->operation() == TQNetworkProtocol::OpGet ) { + } else if ( op->operation() == TQNetworkProtocol::OpPut ) { + rereadDir(); + if ( d->progressDia ) { + d->ignoreStop = TRUE; + d->progressDia->close(); + } + delete d->progressDia; + d->progressDia = 0; + } + +#if defined(TQ_WS_WIN) + if (d->oldPermissionLookup != qt_ntfs_permission_lookup) + qt_ntfs_permission_lookup++; +#endif +} + +void TQFileDialog::dataTransferProgress( int bytesDone, int bytesTotal, TQNetworkOperation *op ) +{ + if ( !op ) + return; + + TQString label; + TQUrl u( op->arg( 0 ) ); + if ( u.isLocalFile() ) { + label = u.path(); + } else { + label = TQString( "%1 (on %2)" ); + label = label.arg( u.path() ).arg( u.host() ); + } + + if ( !d->progressDia ) { + if ( bytesDone < bytesTotal) { + d->ignoreStop = FALSE; + d->progressDia = new TQFDProgressDialog( this, label, bytesTotal ); + connect( d->progressDia, TQT_SIGNAL( cancelled() ), + this, TQT_SLOT( stopCopy() ) ); + d->progressDia->show(); + } else + return; + } + + if ( d->progressDia ) { + if ( op->operation() == TQNetworkProtocol::OpGet ) { + if ( d->progressDia ) { + d->progressDia->setReadProgress( bytesDone ); + } + } else if ( op->operation() == TQNetworkProtocol::OpPut ) { + if ( d->progressDia ) { + d->progressDia->setWriteLabel( label ); + d->progressDia->setWriteProgress( bytesDone ); + } + } else { + return; + } + } +} + +void TQFileDialog::insertEntry( const TQValueList<TQUrlInfo> &lst, TQNetworkOperation *op ) +{ + if ( op && op->operation() == TQNetworkProtocol::OpListChildren && + op != d->currListChildren ) + return; + TQValueList<TQUrlInfo>::ConstIterator it = lst.begin(); + for ( ; it != lst.end(); ++it ) { + const TQUrlInfo &inf = *it; + if ( d->mode == DirectoryOnly && !inf.isDir() ) + continue; + if ( inf.name() == ".." ) { + d->hadDotDot = TRUE; + if ( isRoot( d->url ) ) + continue; +#if defined(TQ_WS_WIN) + if ( d->url.path().left( 2 ) == "//" ) + continue; +#endif + } else if ( inf.name() == "." ) + continue; + +#if defined(TQ_WS_WIN) + // Workaround a Windows bug, '..' is apparantly hidden in directories + // that are one level away from root + if ( !bShowHiddenFiles && inf.name() != ".." ) { + if ( d->url.isLocalFile() ) { + TQString file = d->url.path(); + if ( !file.endsWith( "/" ) ) + file.append( "/" ); + file += inf.name(); + TQT_WA( { + if ( GetFileAttributesW( (TCHAR*)file.ucs2() ) & FILE_ATTRIBUTE_HIDDEN ) + continue; + } , { + if ( GetFileAttributesA( file.local8Bit() ) & FILE_ATTRIBUTE_HIDDEN ) + continue; + } ); + } else { + if ( inf.name() != ".." && inf.name()[0] == TQChar('.') ) + continue; + } + } +#else + if ( !bShowHiddenFiles && inf.name() != ".." ) { + if ( inf.name()[ 0 ] == TQChar( '.' ) ) + continue; + } +#endif + if ( !d->url.isLocalFile() ) { + TQFileDialogPrivate::File * i = 0; + TQFileDialogPrivate::MCItem *i2 = 0; + i = new TQFileDialogPrivate::File( d, &inf, files ); + i2 = new TQFileDialogPrivate::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 TQUrlInfo( inf ) ); + } +} + +void TQFileDialog::removeEntry( TQNetworkOperation *op ) +{ + if ( !op ) + return; + + TQUrlInfo *i = 0; + TQListViewItemIterator it( files ); + bool ok1 = FALSE, ok2 = FALSE; + for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) { + TQString encName = TQFileDialogPrivate::encodeFileName( + ( (TQFileDialogPrivate::File*)it.current() )->info.name() ); + if ( encName == op->arg( 0 ) ) { + d->pendingItems.removeRef( (TQFileDialogPrivate::File*)it.current() ); + delete ( (TQFileDialogPrivate::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 TQFileDialog::itemChanged( TQNetworkOperation *op ) +{ + if ( !op ) + return; + + TQUrlInfo *i = 0; + TQListViewItemIterator it1( files ); + bool ok1 = FALSE, ok2 = FALSE; + // first check whether the new file tqreplaces an existing file. + for ( i = d->sortedList.first(); it1.current(); ++it1, i = d->sortedList.next() ) { + if ( ( (TQFileDialogPrivate::File*)it1.current() )->info.name() == op->arg( 1 ) ) { + delete ( (TQFileDialogPrivate::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; + TQListViewItemIterator it( files ); + ok1 = FALSE; + ok2 = FALSE; + for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) { + if ( ( (TQFileDialogPrivate::File*)it.current() )->info.name() == op->arg( 0 ) ) { + ( (TQFileDialogPrivate::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 TQFileDialog::infoPreview + + \brief whether the file dialog can provide preview information about + the currently selected file + + The default is FALSE. +*/ +bool TQFileDialog::isInfoPreviewEnabled() const +{ + return d->infoPreview; +} + +void TQFileDialog::setInfoPreviewEnabled( bool info ) +{ + if ( info == d->infoPreview ) + return; + d->tqgeometryDirty = TRUE; + d->infoPreview = info; + updateGeometries(); +} + + +/*! + \property TQFileDialog::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 TQFileDialog::isContentsPreviewEnabled() const +{ + return d->contentsPreview; +} + +void TQFileDialog::setContentsPreviewEnabled( bool contents ) +{ + if ( contents == d->contentsPreview ) + return; + d->tqgeometryDirty = 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 + TQFilePreview \a preview. + + Normally you would create a preview widget that derives from both TQWidget and + TQFilePreview, so you should pass the same widget twice. If you + don't, you must remember to delete the preview object in order to + avoid memory leaks. + + \code + class Preview : public TQLabel, public TQFilePreview + { + public: + Preview( TQWidget *tqparent=0 ) : TQLabel( tqparent ) {} + + void previewUrl( const TQUrl &u ) + { + TQString path = u.path(); + TQPixmap pix( path ); + if ( pix.isNull() ) + setText( "This is not a pixmap" ); + else + setText( "This is a pixmap" ); + } + }; + + //... + + int main( int argc, char** argv ) + { + Preview* p = new Preview; + + TQFileDialog* fd = new TQFileDialog( this ); + fd->setInfoPreviewEnabled( TRUE ); + fd->setInfoPreview( p, p ); + fd->setPreviewMode( TQFileDialog::Info ); + fd->show(); + } + + \endcode + + \sa setContentsPreview(), setInfoPreviewEnabled(), setPreviewMode() + +*/ + +void TQFileDialog::setInfoPreview( TQWidget *w, TQFilePreview *preview ) +{ + if ( !w || !preview ) + return; + + if ( d->infoPreviewWidget ) { + d->preview->removeWidget( d->infoPreviewWidget ); + delete d->infoPreviewWidget; + } + d->infoPreviewWidget = w; + d->infoPreviewer = preview; + w->reparent( d->preview, 0, TQPoint( 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 + TQFilePreview \a preview. + + Normally you would create a preview widget that derives from both TQWidget and + TQFilePreview, so you should pass the same widget twice. If you + don't, you must remember to delete the preview object in order to + avoid memory leaks. + + \code + class Preview : public TQLabel, public TQFilePreview + { + public: + Preview( TQWidget *tqparent=0 ) : TQLabel( tqparent ) {} + + void previewUrl( const TQUrl &u ) + { + TQString path = u.path(); + TQPixmap pix( path ); + if ( pix.isNull() ) + setText( "This is not a pixmap" ); + else + setPixmap( pix ); + } + }; + + //... + + int main( int argc, char** argv ) + { + Preview* p = new Preview; + + TQFileDialog* fd = new TQFileDialog( this ); + fd->setContentsPreviewEnabled( TRUE ); + fd->setContentsPreview( p, p ); + fd->setPreviewMode( TQFileDialog::Contents ); + fd->show(); + } + \endcode + + \sa setContentsPreviewEnabled(), setInfoPreview(), setPreviewMode() +*/ + +void TQFileDialog::setContentsPreview( TQWidget *w, TQFilePreview *preview ) +{ + if ( !w || !preview ) + return; + + if ( d->contentsPreviewWidget ) { + d->preview->removeWidget( d->contentsPreviewWidget ); + delete d->contentsPreviewWidget; + } + d->contentsPreviewWidget = w; + d->contentsPreviewer = preview; + w->reparent( d->preview, 0, TQPoint( 0, 0 ) ); +} + +/*! + Re-sorts the displayed directory. + + \sa rereadDir() +*/ + +void TQFileDialog::resortDir() +{ + d->mimeTypeTimer->stop(); + d->pendingItems.clear(); + + TQFileDialogPrivate::File *item = 0; + TQFileDialogPrivate::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 ); + } + + TQUrlInfo *i = sortAscending ? d->sortedList.first() : d->sortedList.last(); + for ( ; i; i = sortAscending ? d->sortedList.next() : d->sortedList.prev() ) { + item = new TQFileDialogPrivate::File( d, i, files ); + item2 = new TQFileDialogPrivate::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 TQFileIconProvider only support TQFileInfo and no + // TQUrlInfo it can be only used for local files at the moment. In + // 3.0 we have to change the API of TQFileIconProvider to work on + // TQUrlInfo 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 TQFileDialog::stopCopy() +{ + if ( d->ignoreStop ) + return; + + d->url.blockSignals( TRUE ); + d->url.stop(); + if ( d->progressDia ) { + d->ignoreStop = TRUE; + TQTimer::singleShot( 100, this, TQT_SLOT( removeProgressDia() ) ); + } + d->url.blockSignals( FALSE ); +} + +/*! + \internal +*/ + +void TQFileDialog::removeProgressDia() +{ + if ( d->progressDia ) + delete d->progressDia; + d->progressDia = 0; +} + +/*! + \internal +*/ + +void TQFileDialog::doMimeTypeLookup() +{ + if ( !iconProvider() ) { + d->pendingItems.clear(); + d->mimeTypeTimer->stop(); + return; + } + + d->mimeTypeTimer->stop(); + if ( d->pendingItems.count() == 0 ) { + return; + } + + TQRect r; + TQFileDialogPrivate::File *item = d->pendingItems.first(); + if ( item ) { + TQFileInfo fi; + if ( d->url.isLocalFile() ) { + fi.setFile( TQUrl( d->url.path(), TQFileDialogPrivate::encodeFileName( item->info.name() ) ).path( FALSE ) ); + } else + fi.setFile( item->info.name() ); // ##### + const TQPixmap *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! + TQGuardedPtr<TQFileDialog> that( this ); // this may be deleted by an event handler + tqApp->processEvents(); + if ( that.isNull() ) + return; + files->setUpdatesEnabled( FALSE ); + files->viewport()->setUpdatesEnabled( FALSE ); + if ( item != d->pendingItems.first() ) + return; + item->setPixmap( 0, *p ); + tqApp->processEvents(); + if ( that.isNull() ) + return; + files->setUpdatesEnabled( TRUE ); + files->viewport()->setUpdatesEnabled( TRUE ); + + if ( files->isVisible() ) { + TQRect ir( files->tqitemRect( item ) ); + if ( ir != TQRect( 0, 0, -1, -1 ) ) { + r = r.unite( ir ); + } + } else { + TQRect ir( d->moreFiles->tqitemRect( item->i ) ); + if ( ir != TQRect( 0, 0, -1, -1 ) ) { + r = r.unite( ir ); + } + } + } + if ( d->pendingItems.count() ) + d->pendingItems.removeFirst(); + } + + if ( d->moreFiles->isVisible() ) { + d->moreFiles->viewport()->tqrepaint( r, FALSE ); + } else { + files->viewport()->tqrepaint( r, FALSE ); + } + + 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 TQFileDialog::selectAll( bool b ) +{ + if ( d->mode != ExistingFiles ) + return; + d->moreFiles->selectAll( b ); + files->selectAll( b ); +} + +void TQFileDialog::goBack() +{ + if ( !d->goBack || !d->goBack->isEnabled() ) + return; + d->history.remove( d->history.last() ); + if ( d->history.count() < 2 ) + d->goBack->setEnabled( FALSE ); + setUrl( d->history.last() ); +} + +// a class with wonderfully inflexible flexibility. why doesn't it +// just subclass TQWidget in the first place? 'you have to derive your +// preview widget from TQWidget and from this class' indeed. + +/*! + \class TQFilePreview tqfiledialog.h + \ingroup misc + \brief The TQFilePreview class provides file previewing in TQFileDialog. + + This class is an abstract base class which is used to implement + widgets that can display a preview of a file in a TQFileDialog. + + You must derive the preview widget from both TQWidget 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 TQFileDialog::setPreviewMode(), TQFileDialog::setContentsPreview(), + TQFileDialog::setInfoPreview(), TQFileDialog::setInfoPreviewEnabled(), + TQFileDialog::setContentsPreviewEnabled(). + + For an example of a preview widget see qt/examples/qdir/qdir.cpp. +*/ + +/*! + Constructs the TQFilePreview. +*/ + +TQFilePreview::TQFilePreview() +{ +} + +/*! + \fn void TQFilePreview::previewUrl( const TQUrl &url ) + + This function is called by TQFileDialog if a preview + for the \a url should be shown. Reimplement this + function to provide file previewing. +*/ + + +#include "tqfiledialog.tqmoc" + +#endif |