source: vendor/trolltech/current/src/dialogs/qfiledialog.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 173.7 KB
Line 
1/****************************************************************************
2** $Id: qfiledialog.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QFileDialog class
5**
6** Created : 950429
7**
8** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
9**
10** This file is part of the dialogs module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qplatformdefs.h"
39
40// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
41#if defined(connect)
42# undef connect
43#endif
44
45// POSIX Large File Support redefines truncate -> truncate64
46#if defined(truncate)
47# undef truncate
48#endif
49
50#include "qfiledialog.h"
51
52#ifndef QT_NO_FILEDIALOG
53
54#include "private/qapplication_p.h"
55#include "qapplication.h"
56#include "qbitmap.h"
57#include "qbuttongroup.h"
58#include "qcheckbox.h"
59#include "qcleanuphandler.h"
60#include "qcombobox.h"
61#include "qcstring.h"
62#include "qcursor.h"
63#include "qdragobject.h"
64#include "qfile.h"
65#include "qguardedptr.h"
66#include "qhbox.h"
67#include "qheader.h"
68#include "qlabel.h"
69#include "qlayout.h"
70#include "qlibrary.h"
71#include "qlineedit.h"
72#include "qlistbox.h"
73#include "qlistview.h"
74#include "qmap.h"
75#include "qmessagebox.h"
76#include "qmime.h"
77#include "qnetworkprotocol.h"
78#include "qobjectlist.h"
79#include "qpainter.h"
80#include "qpopupmenu.h"
81#include "qprogressbar.h"
82#include "qptrvector.h"
83#include "qpushbutton.h"
84#include "qregexp.h"
85#include "qsemimodal.h"
86#include "qsplitter.h"
87#include "qstrlist.h"
88#include "qstyle.h"
89#include "qtimer.h"
90#include "qtoolbutton.h"
91#include "qtooltip.h"
92#include "qvbox.h"
93#include "qwidgetstack.h"
94
95#ifdef Q_WS_WIN
96#ifdef QT_THREAD_SUPPORT
97# include <private/qmutexpool_p.h>
98#endif // QT_THREAD_SUPPORT
99#endif // Q_WS_WIN
100
101#if !defined(Q_OS_TEMP)
102#include <time.h>
103#else
104#include <shellapi.h>
105#endif
106#include <stdlib.h>
107#include <limits.h>
108#include <ctype.h>
109
110#ifdef Q_WS_MAC
111#include "qt_mac.h"
112#undef check
113#endif
114
115/* XPM */
116static const char * const start_xpm[]={
117 "16 15 8 1",
118 "a c #cec6bd",
119 "# c #000000",
120 "e c #ffff00",
121 "b c #999999",
122 "f c #cccccc",
123 "d c #dcdcdc",
124 "c c #ffffff",
125 ". c None",
126 ".....######aaaaa",
127 "...bb#cccc##aaaa",
128 "..bcc#cccc#d#aaa",
129 ".bcef#cccc#dd#aa",
130 ".bcfe#cccc#####a",
131 ".bcef#ccccccccc#",
132 "bbbbbbbbbbbbccc#",
133 "bccccccccccbbcc#",
134 "bcefefefefee#bc#",
135 ".bcefefefefef#c#",
136 ".bcfefefefefe#c#",
137 "..bcfefefefeeb##",
138 "..bbbbbbbbbbbbb#",
139 "...#############",
140 "................"};
141
142/* XPM */
143static const char * const end_xpm[]={
144 "16 15 9 1",
145 "d c #a0a0a0",
146 "c c #c3c3c3",
147 "# c #cec6bd",
148 ". c #000000",
149 "f c #ffff00",
150 "e c #999999",
151 "g c #cccccc",
152 "b c #ffffff",
153 "a c None",
154 "......####aaaaaa",
155 ".bbbb..###aaaaaa",
156 ".bbbb.c.##aaaaaa",
157 ".bbbb....ddeeeea",
158 ".bbbbbbb.bbbbbe.",
159 ".bbbbbbb.bcfgfe.",
160 "eeeeeeeeeeeeefe.",
161 "ebbbbbbbbbbeege.",
162 "ebfgfgfgfgff.ee.",
163 "aebfgfgfgfgfg.e.",
164 "aebgfgfgfgfgf.e.",
165 "aaebgfgfgfgffe..",
166 "aaeeeeeeeeeeeee.",
167 "aaa.............",
168 "aaaaaaaaaaaaaaaa"};
169
170/* XPM */
171static const char* const open_xpm[]={
172 "16 16 6 1",
173 ". c None",
174 "b c #ffff00",
175 "d c #000000",
176 "* c #999999",
177 "c c #cccccc",
178 "a c #ffffff",
179 "................",
180 "................",
181 "...*****........",
182 "..*aaaaa*.......",
183 ".*abcbcba******.",
184 ".*acbcbcaaaaaa*d",
185 ".*abcbcbcbcbcb*d",
186 "*************b*d",
187 "*aaaaaaaaaa**c*d",
188 "*abcbcbcbcbbd**d",
189 ".*abcbcbcbcbcd*d",
190 ".*acbcbcbcbcbd*d",
191 "..*acbcbcbcbb*dd",
192 "..*************d",
193 "...ddddddddddddd",
194 "................"};
195
196/* XPM */
197static const char * const link_dir_xpm[]={
198 "16 16 10 1",
199 "h c #808080",
200 "g c #a0a0a0",
201 "d c #000000",
202 "b c #ffff00",
203 "f c #303030",
204 "# c #999999",
205 "a c #cccccc",
206 "e c #585858",
207 "c c #ffffff",
208 ". c None",
209 "................",
210 "................",
211 "..#####.........",
212 ".#ababa#........",
213 "#abababa######..",
214 "#cccccccccccc#d.",
215 "#cbababababab#d.",
216 "#cabababababa#d.",
217 "#cbababdddddddd.",
218 "#cababadccccccd.",
219 "#cbababdcececcd.",
220 "#cababadcefdfcd.",
221 "#cbababdccgdhcd.",
222 "#######dccchccd.",
223 ".dddddddddddddd.",
224 "................"};
225
226/* XPM */
227static const char * const link_file_xpm[]={
228 "16 16 10 1",
229 "h c #808080",
230 "g c #a0a0a0",
231 "d c #c3c3c3",
232 ". c #7f7f7f",
233 "c c #000000",
234 "b c #bfbfbf",
235 "f c #303030",
236 "e c #585858",
237 "a c #ffffff",
238 "# c None",
239 "################",
240 "..........######",
241 ".aaaaaaaab.#####",
242 ".aaaaaaaaba.####",
243 ".aaaaaaaacccc###",
244 ".aaaaaaaaaabc###",
245 ".aaaaaaaaaabc###",
246 ".aaaaaaaaaadc###",
247 ".aaaaaaaaaadc###",
248 ".aaaacccccccc###",
249 ".aaaacaaaaaac###",
250 ".aaaacaeaeaac###",
251 ".aaaacaefcfac###",
252 ".aaaacaagchac###",
253 ".ddddcaaahaac###",
254 "ccccccccccccc###"};
255
256/* XPM */
257static const char* const file_xpm[]={
258 "16 16 5 1",
259 ". c #7f7f7f",
260 "# c None",
261 "c c #000000",
262 "b c #bfbfbf",
263 "a c #ffffff",
264 "################",
265 "..........######",
266 ".aaaaaaaab.#####",
267 ".aaaaaaaaba.####",
268 ".aaaaaaaacccc###",
269 ".aaaaaaaaaabc###",
270 ".aaaaaaaaaabc###",
271 ".aaaaaaaaaabc###",
272 ".aaaaaaaaaabc###",
273 ".aaaaaaaaaabc###",
274 ".aaaaaaaaaabc###",
275 ".aaaaaaaaaabc###",
276 ".aaaaaaaaaabc###",
277 ".aaaaaaaaaabc###",
278 ".bbbbbbbbbbbc###",
279 "ccccccccccccc###"};
280
281/* XPM */
282static const char * const closed_xpm[]={
283 "16 16 6 1",
284 ". c None",
285 "b c #ffff00",
286 "d c #000000",
287 "* c #999999",
288 "a c #cccccc",
289 "c c #ffffff",
290 "................",
291 "................",
292 "..*****.........",
293 ".*ababa*........",
294 "*abababa******..",
295 "*cccccccccccc*d.",
296 "*cbababababab*d.",
297 "*cabababababa*d.",
298 "*cbababababab*d.",
299 "*cabababababa*d.",
300 "*cbababababab*d.",
301 "*cabababababa*d.",
302 "*cbababababab*d.",
303 "**************d.",
304 ".dddddddddddddd.",
305 "................"};
306
307
308/* XPM */
309static const char* const cdtoparent_xpm[]={
310 "15 13 3 1",
311 ". c None",
312 "* c #000000",
313 "a c #ffff99",
314 "..*****........",
315 ".*aaaaa*.......",
316 "***************",
317 "*aaaaaaaaaaaaa*",
318 "*aaaa*aaaaaaaa*",
319 "*aaa***aaaaaaa*",
320 "*aa*****aaaaaa*",
321 "*aaaa*aaaaaaaa*",
322 "*aaaa*aaaaaaaa*",
323 "*aaaa******aaa*",
324 "*aaaaaaaaaaaaa*",
325 "*aaaaaaaaaaaaa*",
326 "***************"};
327
328
329/* XPM */
330static const char* const newfolder_xpm[] = {
331 "15 14 4 1",
332 " c None",
333 ". c #000000",
334 "+ c #FFFF00",
335 "@ c #FFFFFF",
336 " . ",
337 " ",
338 " . ",
339 " . . ",
340 " .... . . . ",
341 " .+@+@. . . ",
342 ".......... . .",
343 ".@+@+@+@+@.. ",
344 ".+@+@+@+@+. . ",
345 ".@+@+@+@+@. . ",
346 ".+@+@+@+@+. ",
347 ".@+@+@+@+@. ",
348 ".+@+@+@+@+. ",
349 "........... "};
350
351/* XPM */
352static const char* const detailedview_xpm[]={
353 "14 11 3 1",
354 ". c None",
355 "* c #000000",
356 "a c #000099",
357 ".****.***.***.",
358 "..............",
359 "aaaaaaaaaaaaaa",
360 "..............",
361 ".****.***.***.",
362 "..............",
363 ".****.***.***.",
364 "..............",
365 ".****.***.***.",
366 "..............",
367 ".****.***.***."};
368
369/* XPM */
370static const char* const previewinfoview_xpm[]={
371 "13 13 4 1",
372 ". c #00007f",
373 "a c black",
374 "# c #cec6bd",
375 "b c #000000",
376 "..#####aaaaaa",
377 ".#.#bb#a#####",
378 "...####a#bbb#",
379 "#######a#####",
380 "#######a#bb##",
381 "..#####a#####",
382 ".#.#bb#a#bbb#",
383 "...####a#####",
384 "#######a#bb##",
385 "#######a#####",
386 "..#####a#bbb#",
387 ".#.#bb#a#####",
388 "...####aaaaaa"};
389
390/* XPM */
391static const char* const previewcontentsview_xpm[]={
392 "14 13 5 1",
393 ". c #00007f",
394 "a c black",
395 "c c #7f007f",
396 "# c #cec6bd",
397 "b c #000000",
398 "..#####aaaaaaa",
399 ".#.#bb#a#####a",
400 "...####a#ccc#a",
401 "#######a#ccc#a",
402 "#######a#####a",
403 "..#####a#bbb#a",
404 ".#.#bb#a#####a",
405 "...####a#bbb#a",
406 "#######a#####a",
407 "#######a#bbb#a",
408 "..#####a#####a",
409 ".#.#bb#a#####a",
410 "...####aaaaaaa"};
411
412/* XPM */
413static const char* const mclistview_xpm[]={
414 "15 11 4 1",
415 "* c None",
416 "b c #000000",
417 ". c #000099",
418 "a c #ffffff",
419 "...*****...****",
420 ".a.*bbb*.a.*bbb",
421 "...*****...****",
422 "***************",
423 "...*****...****",
424 ".a.*bbb*.a.*bbb",
425 "...*****...****",
426 "***************",
427 "...*****...****",
428 ".a.*bbb*.a.*bbb",
429 "...*****...****"};
430
431/* XPM */
432static const char * const back_xpm [] = {
433 "13 11 3 1",
434 "a c #00ffff",
435 "# c #000000",
436 ". c None",
437 ".....#.......",
438 "....##.......",
439 "...#a#.......",
440 "..#aa########",
441 ".#aaaaaaaaaa#",
442 "#aaaaaaaaaaa#",
443 ".#aaaaaaaaaa#",
444 "..#aa########",
445 "...#a#.......",
446 "....##.......",
447 ".....#......."};
448
449static QPixmap * openFolderIcon = 0;
450static QPixmap * closedFolderIcon = 0;
451static QPixmap * detailViewIcon = 0;
452static QPixmap * multiColumnListViewIcon = 0;
453static QPixmap * cdToParentIcon = 0;
454static QPixmap * newFolderIcon = 0;
455static QPixmap * fifteenTransparentPixels = 0;
456static QPixmap * symLinkDirIcon = 0;
457static QPixmap * symLinkFileIcon = 0;
458static QPixmap * fileIcon = 0;
459static QPixmap * startCopyIcon = 0;
460static QPixmap * endCopyIcon = 0;
461static QPixmap * previewContentsViewIcon = 0;
462static QPixmap * previewInfoViewIcon = 0;
463static QPixmap *goBackIcon = 0;
464static QFileIconProvider * fileIconProvider = 0;
465static int lastWidth = 0;
466static int lastHeight = 0;
467static QString * workingDirectory = 0;
468
469static bool bShowHiddenFiles = FALSE;
470static int sortFilesBy = (int)QDir::Name;
471static bool sortAscending = TRUE;
472static bool detailViewMode = FALSE;
473
474static QCleanupHandler<QPixmap> qfd_cleanup_pixmap;
475static QCleanupHandler<QString> qfd_cleanup_string;
476
477static bool isDirectoryMode( int m )
478{
479 return m == QFileDialog::Directory || m == QFileDialog::DirectoryOnly;
480}
481
482static void updateLastSize( QFileDialog *that )
483{
484 int extWidth = 0;
485 int extHeight = 0;
486 if ( that->extension() && that->extension()->isVisible() ) {
487 if ( that->orientation() == Qt::Vertical )
488 extHeight = that->extension()->height();
489 else
490 extWidth = that->extension()->width();
491 }
492 lastWidth = that->width() - extWidth;
493 lastHeight = that->height() - extHeight;
494}
495
496// Don't remove the lines below!
497//
498// resolving the W methods manually is needed, because Windows 95 doesn't include
499// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol
500// when Qt calls getEsistingDirectory(), etc.
501#if defined(Q_WS_WIN)
502
503typedef UINT (WINAPI *PtrExtractIconEx)(LPCTSTR,int,HICON*,HICON*,UINT);
504static PtrExtractIconEx ptrExtractIconEx = 0;
505
506static void resolveLibs()
507{
508#ifndef Q_OS_TEMP
509 static bool triedResolve = FALSE;
510
511 if ( !triedResolve ) {
512#ifdef QT_THREAD_SUPPORT
513 // protect initialization
514 QMutexLocker locker( qt_global_mutexpool ?
515 qt_global_mutexpool->get( &triedResolve ) : 0 );
516 // check triedResolve again, since another thread may have already
517 // done the initialization
518 if ( triedResolve ) {
519 // another thread did initialize the security function pointers,
520 // so we shouldn't do it again.
521 return;
522 }
523#endif
524 triedResolve = TRUE;
525 if ( qt_winunicode ) {
526 QLibrary lib("shell32");
527 lib.setAutoUnload( FALSE );
528 ptrExtractIconEx = (PtrExtractIconEx) lib.resolve( "ExtractIconExW" );
529 }
530 }
531#endif
532}
533#ifdef Q_OS_TEMP
534#define PtrExtractIconEx ExtractIconEx
535#endif
536
537class QWindowsIconProvider : public QFileIconProvider
538{
539public:
540 QWindowsIconProvider( QObject *parent=0, const char *name=0 );
541 ~QWindowsIconProvider();
542
543 const QPixmap * pixmap( const QFileInfo &fi );
544
545private:
546 QPixmap defaultFolder;
547 QPixmap defaultFile;
548 QPixmap defaultExe;
549 QPixmap pix;
550 int pixw, pixh;
551 QMap< QString, QPixmap > cache;
552
553};
554#endif
555
556static void makeVariables() {
557 if ( !openFolderIcon ) {
558 workingDirectory = new QString( QDir::currentDirPath() );
559 qfd_cleanup_string.add( &workingDirectory );
560
561 openFolderIcon = new QPixmap( (const char **)open_xpm);
562 qfd_cleanup_pixmap.add( &openFolderIcon );
563 symLinkDirIcon = new QPixmap( (const char **)link_dir_xpm);
564 qfd_cleanup_pixmap.add( &symLinkDirIcon );
565 symLinkFileIcon = new QPixmap( (const char **)link_file_xpm);
566 qfd_cleanup_pixmap.add( &symLinkFileIcon );
567 fileIcon = new QPixmap( (const char **)file_xpm);
568 qfd_cleanup_pixmap.add( &fileIcon );
569 closedFolderIcon = new QPixmap( (const char **)closed_xpm);
570 qfd_cleanup_pixmap.add( &closedFolderIcon );
571 detailViewIcon = new QPixmap( (const char **)detailedview_xpm);
572 qfd_cleanup_pixmap.add( &detailViewIcon );
573 multiColumnListViewIcon = new QPixmap( (const char **)mclistview_xpm);
574 qfd_cleanup_pixmap.add( &multiColumnListViewIcon );
575 cdToParentIcon = new QPixmap( (const char **)cdtoparent_xpm);
576 qfd_cleanup_pixmap.add( &cdToParentIcon );
577 newFolderIcon = new QPixmap( (const char **)newfolder_xpm);
578 qfd_cleanup_pixmap.add( &newFolderIcon );
579 previewInfoViewIcon
580 = new QPixmap( (const char **)previewinfoview_xpm );
581 qfd_cleanup_pixmap.add( &previewInfoViewIcon );
582 previewContentsViewIcon
583 = new QPixmap( (const char **)previewcontentsview_xpm );
584 qfd_cleanup_pixmap.add( &previewContentsViewIcon );
585 startCopyIcon = new QPixmap( (const char **)start_xpm );
586 qfd_cleanup_pixmap.add( &startCopyIcon );
587 endCopyIcon = new QPixmap( (const char **)end_xpm );
588 qfd_cleanup_pixmap.add( &endCopyIcon );
589 goBackIcon = new QPixmap( (const char **)back_xpm );
590 qfd_cleanup_pixmap.add( &goBackIcon );
591 fifteenTransparentPixels = new QPixmap( closedFolderIcon->width(), 1 );
592 qfd_cleanup_pixmap.add( &fifteenTransparentPixels );
593 QBitmap m( fifteenTransparentPixels->width(), 1 );
594 m.fill( Qt::color0 );
595 fifteenTransparentPixels->setMask( m );
596 bShowHiddenFiles = FALSE;
597 sortFilesBy = (int)QDir::Name;
598 detailViewMode = FALSE;
599#if defined(Q_WS_WIN)
600 if ( !fileIconProvider )
601 fileIconProvider = new QWindowsIconProvider( qApp );
602#endif
603 }
604}
605
606/******************************************************************
607 *
608 * Definitions of view classes
609 *
610 ******************************************************************/
611
612class QRenameEdit : public QLineEdit
613{
614 Q_OBJECT
615
616public:
617 QRenameEdit( QWidget *parent )
618 : QLineEdit( parent, "qt_rename_edit" ), doRenameAlreadyEmitted(FALSE)
619 {
620 connect( this, SIGNAL(returnPressed()), SLOT(slotReturnPressed()) );
621 }
622
623protected:
624 void keyPressEvent( QKeyEvent *e );
625 void focusOutEvent( QFocusEvent *e );
626
627signals:
628 void cancelRename();
629 void doRename();
630
631private slots:
632 void slotReturnPressed();
633
634private:
635 bool doRenameAlreadyEmitted;
636};
637
638class QFileListBox : public QListBox
639{
640 friend class QFileDialog;
641
642 Q_OBJECT
643
644private:
645 QFileListBox( QWidget *parent, QFileDialog *d );
646
647 void clear();
648 void show();
649 void startRename( bool check = TRUE );
650 void viewportMousePressEvent( QMouseEvent *e );
651 void viewportMouseReleaseEvent( QMouseEvent *e );
652 void viewportMouseDoubleClickEvent( QMouseEvent *e );
653 void viewportMouseMoveEvent( QMouseEvent *e );
654#ifndef QT_NO_DRAGANDDROP
655 void viewportDragEnterEvent( QDragEnterEvent *e );
656 void viewportDragMoveEvent( QDragMoveEvent *e );
657 void viewportDragLeaveEvent( QDragLeaveEvent *e );
658 void viewportDropEvent( QDropEvent *e );
659 bool acceptDrop( const QPoint &pnt, QWidget *source );
660 void setCurrentDropItem( const QPoint &pnt );
661#endif
662 void keyPressEvent( QKeyEvent *e );
663
664private slots:
665 void rename();
666 void cancelRename();
667 void doubleClickTimeout();
668 void changeDirDuringDrag();
669 void dragObjDestroyed();
670 void contentsMoved( int, int );
671
672private:
673 QRenameEdit *lined;
674 QFileDialog *filedialog;
675 bool renaming;
676 QTimer* renameTimer;
677 QListBoxItem *renameItem, *dragItem;
678 QPoint pressPos, oldDragPos;
679 bool mousePressed;
680 int urls;
681 QString startDragDir;
682 QListBoxItem *currDropItem;
683 QTimer *changeDirTimer;
684 bool firstMousePressEvent;
685 QUrlOperator startDragUrl;
686
687};
688
689
690class QFileDialogQFileListView : public QListView
691{
692 Q_OBJECT
693
694public:
695 QFileDialogQFileListView( QWidget *parent, QFileDialog *d );
696
697 void clear();
698 void startRename( bool check = TRUE );
699 void setSorting( int column, bool increasing = TRUE );
700
701 QRenameEdit *lined;
702 bool renaming;
703 QListViewItem *renameItem;
704
705private:
706 void viewportMousePressEvent( QMouseEvent *e );
707 void viewportMouseDoubleClickEvent( QMouseEvent *e );
708 void keyPressEvent( QKeyEvent *e );
709 void viewportMouseReleaseEvent( QMouseEvent *e );
710 void viewportMouseMoveEvent( QMouseEvent *e );
711#ifndef QT_NO_DRAGANDDROP
712 void viewportDragEnterEvent( QDragEnterEvent *e );
713 void viewportDragMoveEvent( QDragMoveEvent *e );
714 void viewportDragLeaveEvent( QDragLeaveEvent *e );
715 void viewportDropEvent( QDropEvent *e );
716 bool acceptDrop( const QPoint &pnt, QWidget *source );
717 void setCurrentDropItem( const QPoint &pnt );
718#endif
719
720private slots:
721 void rename();
722 void cancelRename();
723 void changeSortColumn2( int column );
724 void doubleClickTimeout();
725 void changeDirDuringDrag();
726 void dragObjDestroyed();
727 void contentsMoved( int, int );
728
729private:
730 QFileDialog *filedialog;
731 QTimer* renameTimer;
732 QPoint pressPos, oldDragPos;
733 bool mousePressed;
734 int urls;
735 QString startDragDir;
736 QListViewItem *currDropItem, *dragItem;
737 QTimer *changeDirTimer;
738 bool firstMousePressEvent;
739 bool ascending;
740 int sortcolumn;
741 QUrlOperator startDragUrl;
742
743};
744
745/****************************************************************************
746 *
747 * Classes for copy progress dialog
748 *
749 ****************************************************************************/
750
751class QFDProgressAnimation : public QWidget
752{
753 Q_OBJECT
754
755public:
756 QFDProgressAnimation( QWidget *parent );
757 void start();
758
759private slots:
760 void next();
761
762protected:
763 void paintEvent( QPaintEvent *e );
764
765private:
766 int step;
767 QTimer *timer;
768
769};
770
771QFDProgressAnimation::QFDProgressAnimation( QWidget *parent )
772 : QWidget( parent, "qt_progressanimation" )
773{
774 setFixedSize( 300, 50 );
775 step = -1;
776 next();
777 timer = new QTimer( this );
778 connect( timer, SIGNAL( timeout() ),
779 this, SLOT( next() ) );
780}
781
782void QFDProgressAnimation::start()
783{
784 timer->start( 150, FALSE );
785}
786
787void QFDProgressAnimation::next()
788{
789 ++step;
790 if ( step > 10 )
791 step = 0;
792 repaint();
793}
794
795void QFDProgressAnimation::paintEvent( QPaintEvent * )
796{
797 erase();
798
799 QPainter p;
800 p.begin( this );
801 if ( step == 0 ) {
802 p.drawPixmap( 5, ( height() - startCopyIcon->height() ) / 2,
803 *startCopyIcon );
804 p.drawPixmap( width() - 5 - openFolderIcon->width(),
805 ( height() - openFolderIcon->height() ) / 2 , *openFolderIcon );
806 } else if ( step == 10 ) {
807 p.drawPixmap( 5, ( height() - openFolderIcon->height() ) / 2,
808 *openFolderIcon );
809 p.drawPixmap( width() - 5 - endCopyIcon->width(),
810 ( height() - endCopyIcon->height() ) / 2 , *endCopyIcon );
811 } else {
812 p.drawPixmap( 5, ( height() - openFolderIcon->height() ) / 2,
813 *openFolderIcon );
814 p.drawPixmap( width() - 5 - openFolderIcon->width(),
815 ( height() - openFolderIcon->height() ) / 2 , *openFolderIcon );
816 int x = 10 + openFolderIcon->width();
817 int w = width() - 2 * x;
818 int s = w / 9;
819 p.drawPixmap( x + s * step, ( height() - fileIcon->height() ) / 2 - fileIcon->height(),
820 *fileIcon );
821 }
822}
823
824
825class QFDProgressDialog : public QDialog
826{
827 Q_OBJECT
828
829public:
830 QFDProgressDialog( QWidget *parent, const QString &fn, int steps );
831
832 void setReadProgress( int p );
833 void setWriteProgress( int p );
834 void setWriteLabel( const QString &s );
835
836signals:
837 void cancelled();
838
839private:
840 QProgressBar *readBar;
841 QProgressBar *writeBar;
842 QLabel *writeLabel;
843 QFDProgressAnimation *animation;
844
845};
846
847QFDProgressDialog::QFDProgressDialog( QWidget *parent, const QString &fn, int steps )
848 : QDialog( parent, "", TRUE )
849{
850#ifndef QT_NO_WIDGET_TOPEXTRA
851 setCaption( QFileDialog::tr( "Copy or Move a File" ) );
852#endif
853 QVBoxLayout *layout = new QVBoxLayout( this );
854 layout->setSpacing( 5 );
855 layout->setMargin( 5 );
856
857 animation = new QFDProgressAnimation( this );
858 layout->addWidget( animation );
859
860 layout->addWidget( new QLabel( QFileDialog::tr( "Read: %1" ).arg( fn ),
861 this, "qt_read_lbl" ) );
862 readBar = new QProgressBar( steps, this, "qt_readbar" );
863 readBar->reset();
864 readBar->setProgress( 0 );
865 layout->addWidget( readBar );
866 writeLabel = new QLabel( QFileDialog::tr( "Write: %1" ).arg( QString::null ),
867 this, "qt_write_lbl" );
868 layout->addWidget( writeLabel );
869 writeBar = new QProgressBar( steps, this, "qt_writebar" );
870 writeBar->reset();
871 writeBar->setProgress( 0 );
872 layout->addWidget( writeBar );
873
874 QPushButton *b = new QPushButton( QFileDialog::tr( "Cancel" ), this,
875 "qt_cancel_btn" );
876 b->setFixedSize( b->sizeHint() );
877 layout->addWidget( b );
878 connect( b, SIGNAL( clicked() ),
879 this, SIGNAL( cancelled() ) );
880
881 animation->start();
882}
883
884void QFDProgressDialog::setReadProgress( int p )
885{
886 readBar->setProgress( p );
887}
888
889void QFDProgressDialog::setWriteProgress( int p )
890{
891 writeBar->setProgress( p );
892}
893
894void QFDProgressDialog::setWriteLabel( const QString &s )
895{
896 writeLabel->setText( QFileDialog::tr( "Write: %1" ).arg( s ) );
897}
898
899/************************************************************************
900 *
901 * Private QFileDialog members
902 *
903 ************************************************************************/
904
905class QFileDialogPrivate {
906public:
907 ~QFileDialogPrivate();
908
909 QStringList history;
910
911 bool geometryDirty;
912 QComboBox * paths;
913 QComboBox * types;
914 QLabel * pathL;
915 QLabel * fileL;
916 QLabel * typeL;
917
918 QVBoxLayout * topLevelLayout;
919 QHBoxLayout *buttonLayout, *leftLayout, *rightLayout;
920 QPtrList<QHBoxLayout> extraWidgetsLayouts;
921 QPtrList<QLabel> extraLabels;
922 QPtrList<QWidget> extraWidgets;
923 QPtrList<QWidget> extraButtons;
924 QPtrList<QButton> toolButtons;
925
926 QWidgetStack * stack;
927
928 QToolButton * cdToParent, *newFolder, * detailView, * mcView,
929 *previewInfo, *previewContents, *goBack;
930 QButtonGroup * modeButtons;
931
932 QString currentFileName;
933 QListViewItem *last;
934
935 QListBoxItem *lastEFSelected;
936
937 struct File: public QListViewItem {
938 File( QFileDialogPrivate * dlgp,
939 const QUrlInfo * fi, QListViewItem * parent )
940 : QListViewItem( parent, dlgp->last ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE )
941 { setup(); dlgp->last = this; }
942 File( QFileDialogPrivate * dlgp,
943 const QUrlInfo * fi, QListView * parent )
944 : QListViewItem( parent, dlgp->last ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE )
945 { setup(); dlgp->last = this; }
946 File( QFileDialogPrivate * dlgp,
947 const QUrlInfo * fi, QListView * parent, QListViewItem * after )
948 : QListViewItem( parent, after ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE )
949 { setup(); if ( !nextSibling() ) dlgp->last = this; }
950 ~File();
951
952 QString text( int column ) const;
953 const QPixmap * pixmap( int ) const;
954
955 QUrlInfo info;
956 QFileDialogPrivate * d;
957 QListBoxItem *i;
958 bool hasMimePixmap;
959 };
960
961 class MCItem: public QListBoxItem {
962 public:
963 MCItem( QListBox *, QListViewItem * item );
964 MCItem( QListBox *, QListViewItem * item, QListBoxItem *after );
965 QString text() const;
966 const QPixmap *pixmap() const;
967 int height( const QListBox * ) const;
968 int width( const QListBox * ) const;
969 void paint( QPainter * );
970 QListViewItem * i;
971 };
972
973 class UrlInfoList : public QPtrList<QUrlInfo> {
974 public:
975 UrlInfoList() { setAutoDelete( TRUE ); }
976 int compareItems( QPtrCollection::Item n1, QPtrCollection::Item n2 ) {
977 if ( !n1 || !n2 )
978 return 0;
979
980 QUrlInfo *i1 = ( QUrlInfo *)n1;
981 QUrlInfo *i2 = ( QUrlInfo *)n2;
982
983 if ( i1->isDir() && !i2->isDir() )
984 return -1;
985 if ( !i1->isDir() && i2->isDir() )
986 return 1;
987
988 if ( i1->name() == ".." )
989 return -1;
990 if ( i2->name() == ".." )
991 return 1;
992
993#if defined(Q_OS_WIN32)
994 if ( sortFilesBy == QDir::Name ) {
995 QString name1 = i1->name().lower();
996 QString name2 = i2->name().lower();
997 return name1.compare( name2 );
998 }
999#endif
1000 if ( QUrlInfo::equal( *i1, *i2, sortFilesBy ) )
1001 return 0;
1002 else if ( QUrlInfo::greaterThan( *i1, *i2, sortFilesBy ) )
1003 return 1;
1004 else if ( QUrlInfo::lessThan( *i1, *i2, sortFilesBy ) )
1005 return -1;
1006 // can't happen...
1007 return 0;
1008 }
1009 QUrlInfo *operator[]( int i ) {
1010 return at( i );
1011 }
1012 };
1013
1014 UrlInfoList sortedList;
1015 QPtrList<File> pendingItems;
1016
1017 QFileListBox * moreFiles;
1018
1019 QFileDialog::Mode mode;
1020
1021 QString rw;
1022 QString ro;
1023 QString wo;
1024 QString inaccessible;
1025
1026 QString symLinkToFile;
1027 QString file;
1028 QString symLinkToDir;
1029 QString dir;
1030 QString symLinkToSpecial;
1031 QString special;
1032 QWidgetStack *preview;
1033 bool infoPreview, contentsPreview;
1034 QSplitter *splitter;
1035 QUrlOperator url, oldUrl;
1036 QWidget *infoPreviewWidget, *contentsPreviewWidget;
1037 QFilePreview *infoPreviewer, *contentsPreviewer;
1038 bool hadDotDot;
1039
1040 bool ignoreNextKeyPress;
1041 // ignores the next refresh operation in case the user forced a selection
1042 bool ignoreNextRefresh;
1043 QFDProgressDialog *progressDia;
1044 bool checkForFilter;
1045 bool ignoreStop;
1046
1047 QTimer *mimeTypeTimer;
1048 const QNetworkOperation *currListChildren;
1049
1050 // this is similar to QUrl::encode but does encode "*" and
1051 // doesn't encode whitespaces
1052 static QString encodeFileName( const QString& fName ) {
1053
1054 QString newStr;
1055 QCString cName = fName.utf8();
1056 const QCString sChars(
1057#ifdef Q_WS_WIN
1058 "#%"
1059#else
1060 "<>#@\"&%$:,;?={}|^~[]\'`\\*"
1061#endif
1062 );
1063
1064 int len = cName.length();
1065 if ( !len )
1066 return QString::null;
1067 for ( int i = 0; i < len ;++i ) {
1068 uchar inCh = (uchar)cName[ i ];
1069 if ( inCh >= 128 || sChars.contains(inCh) )
1070 {
1071 newStr += QChar( '%' );
1072 ushort c = inCh / 16;
1073 c += c > 9 ? 'A' - 10 : '0';
1074 newStr += (char)c;
1075 c = inCh % 16;
1076 c += c > 9 ? 'A' - 10 : '0';
1077 newStr += (char)c;
1078 } else {
1079 newStr += (char)inCh;
1080 }
1081 }
1082 return newStr;
1083 }
1084
1085 static bool fileExists( const QUrlOperator &url, const QString& name )
1086 {
1087 QUrl u( url, QFileDialogPrivate::encodeFileName(name) );
1088 if ( u.isLocalFile() ) {
1089 QFileInfo f( u.path() );
1090 return f.exists();
1091 } else {
1092 QNetworkProtocol *p = QNetworkProtocol::getNetworkProtocol( url.protocol() );
1093 if ( p && (p->supportedOperations()&QNetworkProtocol::OpListChildren) ) {
1094 QUrlInfo ui( url, name );
1095 return ui.isValid();
1096 }
1097 }
1098 return TRUE;
1099 }
1100
1101#ifndef Q_NO_CURSOR
1102 bool cursorOverride; // Remember if the cursor was overridden or not.
1103#endif
1104};
1105
1106QFileDialogPrivate::~QFileDialogPrivate()
1107{
1108 delete modeButtons;
1109}
1110
1111
1112
1113/************************************************************************
1114 *
1115 * Internal class QRenameEdit
1116 *
1117 ************************************************************************/
1118
1119void QRenameEdit::keyPressEvent( QKeyEvent *e )
1120{
1121 if ( e->key() == Key_Escape )
1122 emit cancelRename();
1123 else
1124 QLineEdit::keyPressEvent( e );
1125 e->accept();
1126}
1127
1128void QRenameEdit::focusOutEvent( QFocusEvent * )
1129{
1130 if ( !doRenameAlreadyEmitted )
1131 emit doRename();
1132 else
1133 doRenameAlreadyEmitted = FALSE;
1134}
1135
1136void QRenameEdit::slotReturnPressed()
1137{
1138 doRenameAlreadyEmitted = TRUE;
1139 emit doRename();
1140}
1141
1142/************************************************************************
1143 *
1144 * Internal class QFileListBox
1145 *
1146 ************************************************************************/
1147
1148QFileListBox::QFileListBox( QWidget *parent, QFileDialog *dlg )
1149 : QListBox( parent, "filelistbox" ), filedialog( dlg ),
1150 renaming( FALSE ), renameItem( 0 ), mousePressed( FALSE ),
1151 firstMousePressEvent( TRUE )
1152{
1153 changeDirTimer = new QTimer( this );
1154 QVBox *box = new QVBox( viewport(), "qt_vbox" );
1155 box->setFrameStyle( QFrame::Box | QFrame::Plain );
1156 lined = new QRenameEdit( box );
1157 lined->setFixedHeight( lined->sizeHint().height() );
1158 box->hide();
1159 box->setBackgroundMode( PaletteBase );
1160 renameTimer = new QTimer( this );
1161 connect( lined, SIGNAL( doRename() ),
1162 this, SLOT (rename() ) );
1163 connect( lined, SIGNAL( cancelRename() ),
1164 this, SLOT( cancelRename() ) );
1165 connect( renameTimer, SIGNAL( timeout() ),
1166 this, SLOT( doubleClickTimeout() ) );
1167 connect( changeDirTimer, SIGNAL( timeout() ),
1168 this, SLOT( changeDirDuringDrag() ) );
1169 connect( this, SIGNAL( contentsMoving(int,int) ),
1170 this, SLOT( contentsMoved(int,int) ) );
1171 viewport()->setAcceptDrops( TRUE );
1172 dragItem = 0;
1173}
1174
1175void QFileListBox::show()
1176{
1177 setBackgroundMode( PaletteBase );
1178 viewport()->setBackgroundMode( PaletteBase );
1179 QListBox::show();
1180}
1181
1182void QFileListBox::keyPressEvent( QKeyEvent *e )
1183{
1184 if ( ( e->key() == Key_Enter ||
1185 e->key() == Key_Return ) &&
1186 renaming )
1187 return;
1188
1189 QString keyPressed = ((QKeyEvent *)e)->text().lower();
1190 QChar keyChar = keyPressed[0];
1191 if ( keyChar.isLetterOrNumber() ) {
1192 QListBoxItem * i = 0;
1193 if ( currentItem() )
1194 i = item( currentItem() );
1195 else
1196 i = firstItem();
1197 if ( i->next() )
1198 i = i->next();
1199 else
1200 i = firstItem();
1201 while ( i != item( currentItem() ) ) {
1202 QString it = text( index( i ) );
1203 if ( it[0].lower() == keyChar ) {
1204 clearSelection();
1205 setCurrentItem( i );
1206 } else {
1207 if ( i->next() )
1208 i = i->next();
1209 else
1210 i = firstItem();
1211 }
1212 }
1213 }
1214 cancelRename();
1215 QListBox::keyPressEvent( e );
1216}
1217
1218void QFileListBox::viewportMousePressEvent( QMouseEvent *e )
1219{
1220 pressPos = e->pos();
1221 mousePressed = FALSE;
1222
1223 bool didRename = renaming;
1224
1225 cancelRename();
1226 if ( !hasFocus() && !viewport()->hasFocus() )
1227 setFocus();
1228
1229 if ( e->button() != LeftButton ) {
1230 QListBox::viewportMousePressEvent( e );
1231 firstMousePressEvent = FALSE;
1232 return;
1233 }
1234
1235 int i = currentItem();
1236 bool wasSelected = FALSE;
1237 if ( i != -1 )
1238 wasSelected = item( i )->isSelected();
1239 QListBox::mousePressEvent( e );
1240
1241 QFileDialogPrivate::MCItem *i1 = (QFileDialogPrivate::MCItem*)item( currentItem() );
1242 if ( i1 )
1243 mousePressed = ( !( (QFileDialogPrivate::File*)i1->i )->info.isDir() )
1244 || ( filedialog->mode() == QFileDialog::Directory ) || ( filedialog->mode() == QFileDialog::DirectoryOnly );
1245
1246 if ( itemAt( e->pos() ) != item( i ) ) {
1247 firstMousePressEvent = FALSE;
1248 return;
1249 }
1250
1251 if ( !firstMousePressEvent && !didRename && i == currentItem() && currentItem() != -1 &&
1252 wasSelected && QUrlInfo( filedialog->d->url, "." ).isWritable() && item( currentItem() )->text() != ".." ) {
1253 renameTimer->start( QApplication::doubleClickInterval(), TRUE );
1254 renameItem = item( i );
1255 }
1256
1257 firstMousePressEvent = FALSE;
1258}
1259
1260void QFileListBox::viewportMouseReleaseEvent( QMouseEvent *e )
1261{
1262 dragItem = 0;
1263 QListBox::viewportMouseReleaseEvent( e );
1264 mousePressed = FALSE;
1265}
1266
1267void QFileListBox::viewportMouseDoubleClickEvent( QMouseEvent *e )
1268{
1269 renameTimer->stop();
1270 QListBox::viewportMouseDoubleClickEvent( e );
1271}
1272
1273void QFileListBox::viewportMouseMoveEvent( QMouseEvent *e )
1274{
1275 if ( !dragItem )
1276 dragItem = itemAt( e->pos() );
1277 renameTimer->stop();
1278#ifndef QT_NO_DRAGANDDROP
1279 if ( ( pressPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() && mousePressed ) {
1280 QListBoxItem *item = dragItem;
1281 dragItem = 0;
1282 if ( item ) {
1283 if ( !itemRect( item ).contains( e->pos() ) )
1284 return;
1285 QUriDrag* drag = new QUriDrag( viewport() );
1286 QStringList files;
1287 if ( filedialog->mode() == QFileDialog::ExistingFiles )
1288 files = filedialog->selectedFiles();
1289 else
1290 files = filedialog->selectedFile();
1291 drag->setFileNames( files );
1292
1293 if ( lined->parentWidget()->isVisible() )
1294 cancelRename();
1295
1296 connect( drag, SIGNAL( destroyed() ),
1297 this, SLOT( dragObjDestroyed() ) );
1298 drag->drag();
1299
1300 mousePressed = FALSE;
1301 }
1302 } else
1303#endif
1304 {
1305 QListBox::viewportMouseMoveEvent( e );
1306 }
1307
1308}
1309
1310void QFileListBox::dragObjDestroyed()
1311{
1312#ifndef QT_NO_DRAGANDDROP
1313 //#######
1314 //filedialog->rereadDir();
1315#endif
1316}
1317
1318#ifndef QT_NO_DRAGANDDROP
1319void QFileListBox::viewportDragEnterEvent( QDragEnterEvent *e )
1320{
1321 startDragUrl = filedialog->d->url;
1322 startDragDir = filedialog->dirPath();
1323 currDropItem = 0;
1324
1325 if ( !QUriDrag::canDecode( e ) ) {
1326 e->ignore();
1327 return;
1328 }
1329
1330 QStringList l;
1331 QUriDrag::decodeLocalFiles( e, l );
1332 urls = (int)l.count();
1333
1334 if ( acceptDrop( e->pos(), e->source() ) ) {
1335 e->accept();
1336 setCurrentDropItem( e->pos() );
1337 } else {
1338 e->ignore();
1339 setCurrentDropItem( QPoint( -1, -1 ) );
1340 }
1341
1342 oldDragPos = e->pos();
1343}
1344
1345void QFileListBox::viewportDragMoveEvent( QDragMoveEvent *e )
1346{
1347 if ( acceptDrop( e->pos(), e->source() ) ) {
1348 switch ( e->action() ) {
1349 case QDropEvent::Copy:
1350 e->acceptAction();
1351 break;
1352 case QDropEvent::Move:
1353 e->acceptAction();
1354 break;
1355 case QDropEvent::Link:
1356 break;
1357 default:
1358 break;
1359 }
1360 if ( oldDragPos != e->pos() )
1361 setCurrentDropItem( e->pos() );
1362 } else {
1363 changeDirTimer->stop();
1364 e->ignore();
1365 setCurrentDropItem( QPoint( -1, -1 ) );
1366 }
1367
1368 oldDragPos = e->pos();
1369}
1370
1371void QFileListBox::viewportDragLeaveEvent( QDragLeaveEvent * )
1372{
1373 changeDirTimer->stop();
1374 setCurrentDropItem( QPoint( -1, -1 ) );
1375//########
1376// if ( startDragDir != filedialog->d->url )
1377// filedialog->setUrl( startDragUrl );
1378}
1379
1380void QFileListBox::viewportDropEvent( QDropEvent *e )
1381{
1382 changeDirTimer->stop();
1383
1384 if ( !QUriDrag::canDecode( e ) ) {
1385 e->ignore();
1386 return;
1387 }
1388
1389 QStrList l;
1390 QUriDrag::decode( e, l );
1391
1392 bool move = e->action() == QDropEvent::Move;
1393// bool supportAction = move || e->action() == QDropEvent::Copy;
1394
1395 QUrlOperator dest;
1396 if ( currDropItem )
1397 dest = QUrlOperator( filedialog->d->url, QFileDialogPrivate::encodeFileName( currDropItem->text() ) );
1398 else
1399 dest = filedialog->d->url;
1400 QStringList lst;
1401 for ( uint i = 0; i < l.count(); ++i ) {
1402 lst << l.at( i );
1403 }
1404
1405 filedialog->d->url.copy( lst, dest, move );
1406
1407 // ##### what is supportAction for?
1408 e->acceptAction();
1409 currDropItem = 0;
1410}
1411
1412bool QFileListBox::acceptDrop( const QPoint &pnt, QWidget *source )
1413{
1414 QListBoxItem *item = itemAt( pnt );
1415 if ( !item || item && !itemRect( item ).contains( pnt ) ) {
1416 if ( source == viewport() && startDragDir == filedialog->dirPath() )
1417 return FALSE;
1418 return TRUE;
1419 }
1420
1421 QUrlInfo fi( filedialog->d->url, item->text() );
1422
1423 if ( fi.isDir() && itemRect( item ).contains( pnt ) )
1424 return TRUE;
1425 return FALSE;
1426}
1427
1428void QFileListBox::setCurrentDropItem( const QPoint &pnt )
1429{
1430 changeDirTimer->stop();
1431
1432 QListBoxItem *item = 0;
1433 if ( pnt != QPoint( -1, -1 ) )
1434 item = itemAt( pnt );
1435 if ( item && !QUrlInfo( filedialog->d->url, item->text() ).isDir() )
1436 item = 0;
1437 if ( item && !itemRect( item ).contains( pnt ) )
1438 item = 0;
1439
1440 currDropItem = item;
1441 if ( currDropItem )
1442 setCurrentItem( currDropItem );
1443 changeDirTimer->start( 750 );
1444}
1445#endif // QT_NO_DRAGANDDROP
1446
1447void QFileListBox::changeDirDuringDrag()
1448{
1449#ifndef QT_NO_DRAGANDDROP
1450 if ( !currDropItem )
1451 return;
1452 changeDirTimer->stop();
1453 QUrl u( filedialog->d->url, QFileDialogPrivate::encodeFileName(currDropItem->text()) );
1454 filedialog->setDir( u );
1455 currDropItem = 0;
1456#endif
1457}
1458
1459void QFileListBox::doubleClickTimeout()
1460{
1461 startRename();
1462 renameTimer->stop();
1463}
1464
1465void QFileListBox::startRename( bool check )
1466{
1467 if ( check && ( !renameItem || renameItem != item( currentItem() ) ) )
1468 return;
1469
1470 int i = currentItem();
1471 setSelected( i, TRUE );
1472 QRect r = itemRect( item( i ) );
1473 int bdr = item( i )->pixmap() ?
1474 item( i )->pixmap()->width() : 16;
1475 int x = r.x() + bdr;
1476 int y = r.y();
1477 int w = item( i )->width( this ) - bdr;
1478 int h = QMAX( lined->height() + 2, r.height() );
1479 y = y + r.height() / 2 - h / 2;
1480
1481 lined->parentWidget()->setGeometry( x, y, w + 6, h );
1482 lined->setFocus();
1483 lined->setText( item( i )->text() );
1484 lined->selectAll();
1485 lined->setFrame( FALSE );
1486 lined->parentWidget()->show();
1487 viewport()->setFocusProxy( lined );
1488 renaming = TRUE;
1489}
1490
1491void QFileListBox::clear()
1492{
1493 cancelRename();
1494 QListBox::clear();
1495}
1496
1497void QFileListBox::rename()
1498{
1499 if ( !lined->text().isEmpty() ) {
1500 QString file = currentText();
1501
1502 if ( lined->text() != file )
1503 filedialog->d->url.rename( file, lined->text() );
1504 }
1505 cancelRename();
1506}
1507
1508void QFileListBox::cancelRename()
1509{
1510 renameItem = 0;
1511 lined->parentWidget()->hide();
1512 viewport()->setFocusProxy( this );
1513 renaming = FALSE;
1514 updateItem( currentItem() );
1515 if ( lined->hasFocus() )
1516 viewport()->setFocus();
1517}
1518
1519void QFileListBox::contentsMoved( int, int )
1520{
1521 changeDirTimer->stop();
1522#ifndef QT_NO_DRAGANDDROP
1523 setCurrentDropItem( QPoint( -1, -1 ) );
1524#endif
1525}
1526
1527/************************************************************************
1528 *
1529 * Internal class QFileListView
1530 *
1531 ************************************************************************/
1532
1533QFileDialogQFileListView::QFileDialogQFileListView( QWidget *parent, QFileDialog *dlg )
1534 : QListView( parent, "qt_filedlg_listview" ), renaming( FALSE ), renameItem( 0 ),
1535 filedialog( dlg ), mousePressed( FALSE ),
1536 firstMousePressEvent( TRUE )
1537{
1538 changeDirTimer = new QTimer( this );
1539 QVBox *box = new QVBox( viewport(), "qt_vbox" );
1540 box->setFrameStyle( QFrame::Box | QFrame::Plain );
1541 lined = new QRenameEdit( box );
1542 lined->setFixedHeight( lined->sizeHint().height() );
1543 box->hide();
1544 box->setBackgroundMode( PaletteBase );
1545 renameTimer = new QTimer( this );
1546 connect( lined, SIGNAL( doRename() ),
1547 this, SLOT (rename() ) );
1548 connect( lined, SIGNAL( cancelRename() ),
1549 this, SLOT( cancelRename() ) );
1550 header()->setMovingEnabled( FALSE );
1551 connect( renameTimer, SIGNAL( timeout() ),
1552 this, SLOT( doubleClickTimeout() ) );
1553 connect( changeDirTimer, SIGNAL( timeout() ),
1554 this, SLOT( changeDirDuringDrag() ) );
1555 disconnect( header(), SIGNAL( sectionClicked(int) ),
1556 this, SLOT( changeSortColumn(int) ) );
1557 connect( header(), SIGNAL( sectionClicked(int) ),
1558 this, SLOT( changeSortColumn2(int) ) );
1559 connect( this, SIGNAL( contentsMoving(int,int) ),
1560 this, SLOT( contentsMoved(int,int) ) );
1561
1562 viewport()->setAcceptDrops( TRUE );
1563 sortcolumn = 0;
1564 ascending = TRUE;
1565 dragItem = 0;
1566}
1567
1568void QFileDialogQFileListView::setSorting( int column, bool increasing )
1569{
1570 if ( column == -1 ) {
1571 QListView::setSorting( column, increasing );
1572 return;
1573 }
1574
1575 sortAscending = ascending = increasing;
1576 sortcolumn = column;
1577 switch ( column ) {
1578 case 0:
1579 sortFilesBy = QDir::Name;
1580 break;
1581 case 1:
1582 sortFilesBy = QDir::Size;
1583 break;
1584 case 3:
1585 sortFilesBy = QDir::Time;
1586 break;
1587 default:
1588 sortFilesBy = QDir::Name; // #### ???
1589 break;
1590 }
1591
1592 filedialog->resortDir();
1593}
1594
1595void QFileDialogQFileListView::changeSortColumn2( int column )
1596{
1597 int lcol = header()->mapToLogical( column );
1598 setSorting( lcol, sortcolumn == lcol ? !ascending : TRUE );
1599}
1600
1601void QFileDialogQFileListView::keyPressEvent( QKeyEvent *e )
1602{
1603 if ( ( e->key() == Key_Enter ||
1604 e->key() == Key_Return ) &&
1605 renaming )
1606 return;
1607
1608 QString keyPressed = e->text().lower();
1609 QChar keyChar = keyPressed[0];
1610 if ( keyChar.isLetterOrNumber() ) {
1611 QListViewItem * i = 0;
1612 if ( currentItem() )
1613 i = currentItem();
1614 else
1615 i = firstChild();
1616 if ( i->nextSibling() )
1617 i = i->nextSibling();
1618 else
1619 i = firstChild();
1620 while ( i != currentItem() ) {
1621 QString it = i->text(0);
1622 if ( it[0].lower() == keyChar ) {
1623 clearSelection();
1624 ensureItemVisible( i );
1625 setCurrentItem( i );
1626 } else {
1627 if ( i->nextSibling() )
1628 i = i->nextSibling();
1629 else
1630 i = firstChild();
1631 }
1632 }
1633 return;
1634 }
1635
1636 cancelRename();
1637 QListView::keyPressEvent( e );
1638}
1639
1640void QFileDialogQFileListView::viewportMousePressEvent( QMouseEvent *e )
1641{
1642 pressPos = e->pos();
1643 mousePressed = FALSE;
1644
1645 bool didRename = renaming;
1646 cancelRename();
1647 if ( !hasFocus() && !viewport()->hasFocus() )
1648 setFocus();
1649
1650 if ( e->button() != LeftButton ) {
1651 QListView::viewportMousePressEvent( e );
1652 firstMousePressEvent = FALSE;
1653 return;
1654 }
1655
1656 QListViewItem *i = currentItem();
1657 QListView::viewportMousePressEvent( e );
1658
1659 QFileDialogPrivate::File *i1 = (QFileDialogPrivate::File*)currentItem();
1660 if ( i1 )
1661 mousePressed = !i1->info.isDir() || ( filedialog->mode() == QFileDialog::Directory ) || ( filedialog->mode() == QFileDialog::DirectoryOnly );
1662
1663
1664 if ( itemAt( e->pos() ) != i ||
1665 e->x() + contentsX() > columnWidth( 0 ) ) {
1666 firstMousePressEvent = FALSE;
1667 return;
1668 }
1669
1670 if ( !firstMousePressEvent && !didRename && i == currentItem() && currentItem() &&
1671 QUrlInfo( filedialog->d->url, "." ).isWritable() && currentItem()->text( 0 ) != ".." ) {
1672 renameTimer->start( QApplication::doubleClickInterval(), TRUE );
1673 renameItem = currentItem();
1674 }
1675
1676 firstMousePressEvent = FALSE;
1677}
1678
1679void QFileDialogQFileListView::viewportMouseDoubleClickEvent( QMouseEvent *e )
1680{
1681 renameTimer->stop();
1682 QListView::viewportMouseDoubleClickEvent( e );
1683}
1684
1685void QFileDialogQFileListView::viewportMouseReleaseEvent( QMouseEvent *e )
1686{
1687 QListView::viewportMouseReleaseEvent( e );
1688 mousePressed = FALSE;
1689 dragItem = 0;
1690}
1691
1692void QFileDialogQFileListView::viewportMouseMoveEvent( QMouseEvent *e )
1693{
1694 renameTimer->stop();
1695 if ( !dragItem )
1696 dragItem = itemAt( e->pos() );
1697#ifndef QT_NO_DRAGANDDROP
1698 if ( ( pressPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() && mousePressed ) {
1699 QListViewItem *item = dragItem;
1700 dragItem = 0;
1701 if ( item ) {
1702 QUriDrag* drag = new QUriDrag( viewport() );
1703 QStringList files;
1704 if ( filedialog->mode() == QFileDialog::ExistingFiles )
1705 files = filedialog->selectedFiles();
1706 else
1707 files = filedialog->selectedFile();
1708 drag->setFileNames( files );
1709
1710 if ( lined->isVisible() )
1711 cancelRename();
1712
1713 connect( drag, SIGNAL( destroyed() ),
1714 this, SLOT( dragObjDestroyed() ) );
1715 drag->drag();
1716
1717 mousePressed = FALSE;
1718 }
1719 }
1720#endif
1721}
1722
1723void QFileDialogQFileListView::dragObjDestroyed()
1724{
1725#ifndef QT_NO_DRAGANDDROP
1726 //######
1727 //filedialog->rereadDir();
1728#endif
1729}
1730
1731#ifndef QT_NO_DRAGANDDROP
1732void QFileDialogQFileListView::viewportDragEnterEvent( QDragEnterEvent *e )
1733{
1734 startDragUrl = filedialog->d->url;
1735 startDragDir = filedialog->dirPath();
1736 currDropItem = 0;
1737
1738 if ( !QUriDrag::canDecode( e ) ) {
1739 e->ignore();
1740 return;
1741 }
1742
1743 QStringList l;
1744 QUriDrag::decodeLocalFiles( e, l );
1745 urls = (int)l.count();
1746
1747 if ( acceptDrop( e->pos(), e->source() ) ) {
1748 e->accept();
1749 setCurrentDropItem( e->pos() );
1750 } else {
1751 e->ignore();
1752 setCurrentDropItem( QPoint( -1, -1 ) );
1753 }
1754
1755 oldDragPos = e->pos();
1756}
1757
1758void QFileDialogQFileListView::viewportDragMoveEvent( QDragMoveEvent *e )
1759{
1760 if ( acceptDrop( e->pos(), e->source() ) ) {
1761 if ( oldDragPos != e->pos() )
1762 setCurrentDropItem( e->pos() );
1763 switch ( e->action() ) {
1764 case QDropEvent::Copy:
1765 e->acceptAction();
1766 break;
1767 case QDropEvent::Move:
1768 e->acceptAction();
1769 break;
1770 case QDropEvent::Link:
1771 break;
1772 default:
1773 break;
1774 }
1775 } else {
1776 changeDirTimer->stop();
1777 e->ignore();
1778 setCurrentDropItem( QPoint( -1, -1 ) );
1779 }
1780
1781 oldDragPos = e->pos();
1782}
1783
1784void QFileDialogQFileListView::viewportDragLeaveEvent( QDragLeaveEvent * )
1785{
1786 changeDirTimer->stop();
1787 setCurrentDropItem( QPoint( -1, -1 ) );
1788//########
1789// if ( startDragDir != filedialog->d->url )
1790// filedialog->setUrl( startDragUrl );
1791}
1792
1793void QFileDialogQFileListView::viewportDropEvent( QDropEvent *e )
1794{
1795 changeDirTimer->stop();
1796
1797 if ( !QUriDrag::canDecode( e ) ) {
1798 e->ignore();
1799 return;
1800 }
1801
1802 QStringList l;
1803 QUriDrag::decodeToUnicodeUris( e, l );
1804
1805 bool move = e->action() == QDropEvent::Move;
1806// bool supportAction = move || e->action() == QDropEvent::Copy;
1807
1808 QUrlOperator dest;
1809 if ( currDropItem )
1810 dest = QUrlOperator( filedialog->d->url, QFileDialogPrivate::encodeFileName( currDropItem->text( 0 ) ) );
1811 else
1812 dest = filedialog->d->url;
1813 filedialog->d->url.copy( l, dest, move );
1814
1815 // ##### what is supportAction for?
1816 e->acceptAction();
1817 currDropItem = 0;
1818}
1819
1820bool QFileDialogQFileListView::acceptDrop( const QPoint &pnt, QWidget *source )
1821{
1822 QListViewItem *item = itemAt( pnt );
1823 if ( !item || item && !itemRect( item ).contains( pnt ) ) {
1824 if ( source == viewport() && startDragDir == filedialog->dirPath() )
1825 return FALSE;
1826 return TRUE;
1827 }
1828
1829 QUrlInfo fi( filedialog->d->url, item->text( 0 ) );
1830
1831 if ( fi.isDir() && itemRect( item ).contains( pnt ) )
1832 return TRUE;
1833 return FALSE;
1834}
1835
1836void QFileDialogQFileListView::setCurrentDropItem( const QPoint &pnt )
1837{
1838 changeDirTimer->stop();
1839
1840 QListViewItem *item = itemAt( pnt );
1841 if ( pnt == QPoint( -1, -1 ) )
1842 item = 0;
1843 if ( item && !QUrlInfo( filedialog->d->url, item->text( 0 ) ).isDir() )
1844 item = 0;
1845
1846 if ( item && !itemRect( item ).contains( pnt ) )
1847 item = 0;
1848
1849 currDropItem = item;
1850
1851 if ( currDropItem )
1852 setCurrentItem( currDropItem );
1853
1854 changeDirTimer->start( 750 );
1855}
1856#endif // QT_NO_DRAGANDDROP
1857
1858void QFileDialogQFileListView::changeDirDuringDrag()
1859{
1860#ifndef QT_NO_DRAGANDDROP
1861 if ( !currDropItem )
1862 return;
1863 changeDirTimer->stop();
1864 QUrl u( filedialog->d->url, QFileDialogPrivate::encodeFileName(currDropItem->text( 0 ) ) );
1865 filedialog->setDir( u );
1866 currDropItem = 0;
1867#endif // QT_NO_DRAGANDDROP
1868}
1869
1870
1871void QFileDialogQFileListView::doubleClickTimeout()
1872{
1873 startRename();
1874 renameTimer->stop();
1875}
1876
1877void QFileDialogQFileListView::startRename( bool check )
1878{
1879 if ( check && ( !renameItem || renameItem != currentItem() ) )
1880 return;
1881
1882 QListViewItem *i = currentItem();
1883 setSelected( i, TRUE );
1884
1885 QRect r = itemRect( i );
1886 int bdr = i->pixmap( 0 ) ?
1887 i->pixmap( 0 )->width() : 16;
1888 int x = r.x() + bdr;
1889 int y = r.y();
1890 int w = columnWidth( 0 ) - bdr;
1891 int h = QMAX( lined->height() + 2, r.height() );
1892 y = y + r.height() / 2 - h / 2;
1893
1894 lined->parentWidget()->setGeometry( x, y, w + 6, h );
1895 lined->setFocus();
1896 lined->setText( i->text( 0 ) );
1897 lined->selectAll();
1898 lined->setFrame( FALSE );
1899 lined->parentWidget()->show();
1900 viewport()->setFocusProxy( lined );
1901 renaming = TRUE;
1902}
1903
1904void QFileDialogQFileListView::clear()
1905{
1906 cancelRename();
1907 QListView::clear();
1908}
1909
1910void QFileDialogQFileListView::rename()
1911{
1912 if ( !lined->text().isEmpty() ) {
1913 QString file = currentItem()->text( 0 );
1914
1915 if ( lined->text() != file )
1916 filedialog->d->url.rename( file, lined->text() );
1917 }
1918 cancelRename();
1919}
1920
1921void QFileDialogQFileListView::cancelRename()
1922{
1923 renameItem = 0;
1924 lined->parentWidget()->hide();
1925 viewport()->setFocusProxy( this );
1926 renaming = FALSE;
1927 if ( currentItem() )
1928 currentItem()->repaint();
1929 if ( lined->hasFocus() )
1930 viewport()->setFocus();
1931}
1932
1933void QFileDialogQFileListView::contentsMoved( int, int )
1934{
1935 changeDirTimer->stop();
1936#ifndef QT_NO_DRAGANDDROP
1937 setCurrentDropItem( QPoint( -1, -1 ) );
1938#endif
1939}
1940
1941
1942QFileDialogPrivate::File::~File()
1943{
1944 if ( d->pendingItems.findRef( this ) )
1945 d->pendingItems.removeRef( this );
1946}
1947
1948QString QFileDialogPrivate::File::text( int column ) const
1949{
1950 makeVariables();
1951
1952 switch( column ) {
1953 case 0:
1954 return info.name();
1955 case 1:
1956 if ( info.isFile() ) {
1957#if (QT_VERSION-0 >= 0x040000)
1958#error "clean up Large File Support"
1959#elif defined(QT_ABI_QT4)
1960 QIODevice::Offset size = info.size();
1961#else
1962 uint size = info.size();
1963#endif
1964#if defined(QT_LARGEFILE_SUPPORT) && defined(Q_OS_UNIX)
1965 // ### the following code should not be needed as soon
1966 // ### as QUrlInfo::size() can return 64-bit
1967 if ( size > INT_MAX ) {
1968 struct stat buffer;
1969 if ( ::stat( QFile::encodeName(info.name()), &buffer ) == 0 ) {
1970 Q_ULLONG size64 = (Q_ULLONG)buffer.st_size;
1971 return QString::number(size64);
1972 }
1973 }
1974#endif
1975 return QString::number(size);
1976 } else {
1977 return QString::fromLatin1("");
1978 }
1979 case 2:
1980 if ( info.isFile() && info.isSymLink() ) {
1981 return d->symLinkToFile;
1982 } else if ( info.isFile() ) {
1983 return d->file;
1984 } else if ( info.isDir() && info.isSymLink() ) {
1985 return d->symLinkToDir;
1986 } else if ( info.isDir() ) {
1987 return d->dir;
1988 } else if ( info.isSymLink() ) {
1989 return d->symLinkToSpecial;
1990 } else {
1991 return d->special;
1992 }
1993 case 3: {
1994 return info.lastModified().toString( Qt::LocalDate );
1995 }
1996 case 4:
1997 if ( info.isReadable() )
1998 return info.isWritable() ? d->rw : d->ro;
1999 else
2000 return info.isWritable() ? d->wo : d->inaccessible;
2001 }
2002
2003 return QString::fromLatin1("<--->");
2004}
2005
2006const QPixmap * QFileDialogPrivate::File::pixmap( int column ) const
2007{
2008 if ( column ) {
2009 return 0;
2010 } else if ( QListViewItem::pixmap( column ) ) {
2011 return QListViewItem::pixmap( column );
2012 } else if ( info.isSymLink() ) {
2013 if ( info.isFile() )
2014 return symLinkFileIcon;
2015 else
2016 return symLinkDirIcon;
2017 } else if ( info.isDir() ) {
2018 return closedFolderIcon;
2019 } else if ( info.isFile() ) {
2020 return fileIcon;
2021 } else {
2022 return fifteenTransparentPixels;
2023 }
2024}
2025
2026QFileDialogPrivate::MCItem::MCItem( QListBox * lb, QListViewItem * item )
2027 : QListBoxItem()
2028{
2029 i = item;
2030 if ( lb )
2031 lb->insertItem( this );
2032}
2033
2034QFileDialogPrivate::MCItem::MCItem( QListBox * lb, QListViewItem * item, QListBoxItem *after )
2035 : QListBoxItem()
2036{
2037 i = item;
2038 if ( lb )
2039 lb->insertItem( this, after );
2040}
2041
2042QString QFileDialogPrivate::MCItem::text() const
2043{
2044 return i->text( 0 );
2045}
2046
2047
2048const QPixmap *QFileDialogPrivate::MCItem::pixmap() const
2049{
2050 return i->pixmap( 0 );
2051}
2052
2053
2054int QFileDialogPrivate::MCItem::height( const QListBox * lb ) const
2055{
2056 int hf = lb->fontMetrics().height();
2057 int hp = pixmap() ? pixmap()->height() : 0;
2058 return QMAX(hf, hp) + 2;
2059}
2060
2061
2062int QFileDialogPrivate::MCItem::width( const QListBox * lb ) const
2063{
2064 QFontMetrics fm = lb->fontMetrics();
2065 int w = 2;
2066 if ( pixmap() )
2067 w += pixmap()->width() + 4;
2068 else
2069 w += 18;
2070 w += fm.width( text() );
2071 w += -fm.minLeftBearing();
2072 w += -fm.minRightBearing();
2073 w += 6;
2074 return w;
2075}
2076
2077
2078void QFileDialogPrivate::MCItem::paint( QPainter * ptr )
2079{
2080 QFontMetrics fm = ptr->fontMetrics();
2081
2082 int h;
2083
2084 if ( pixmap() )
2085 h = QMAX( fm.height(), pixmap()->height()) + 2;
2086 else
2087 h = fm.height() + 2;
2088
2089 const QPixmap * pm = pixmap();
2090 if ( pm )
2091 ptr->drawPixmap( 2, 1, *pm );
2092
2093 ptr->drawText( pm ? pm->width() + 4 : 22, h - fm.descent() - 2,
2094 text() );
2095}
2096
2097static QStringList makeFiltersList( const QString &filter )
2098{
2099 if ( filter.isEmpty() )
2100 return QStringList();
2101
2102 int i = filter.find( ";;", 0 );
2103 QString sep( ";;" );
2104 if ( i == -1 ) {
2105 if ( filter.find( "\n", 0 ) != -1 ) {
2106 sep = "\n";
2107 i = filter.find( sep, 0 );
2108 }
2109 }
2110
2111 return QStringList::split( sep, filter );
2112}
2113
2114/*!
2115 \class QFileDialog qfiledialog.h
2116 \brief The QFileDialog class provides dialogs that allow users to select files or directories.
2117 \ingroup dialogs
2118 \mainclass
2119
2120 The QFileDialog class enables a user to traverse their file system in
2121 order to select one or many files or a directory.
2122
2123 The easiest way to create a QFileDialog is to use the static
2124 functions. On Windows, these static functions will call the native
2125 Windows file dialog and on Mac OS X, these static function will call
2126 the native Mac OS X file dialog.
2127
2128 \code
2129 QString s = QFileDialog::getOpenFileName(
2130 "/home",
2131 "Images (*.png *.xpm *.jpg)",
2132 this,
2133 "open file dialog"
2134 "Choose a file" );
2135 \endcode
2136
2137 In the above example, a modal QFileDialog is created using a static
2138 function. The startup directory is set to "/home". The file filter
2139 is set to "Images (*.png *.xpm *.jpg)". The parent of the file dialog
2140 is set to \e this and it is given the identification name - "open file
2141 dialog". The caption at the top of file dialog is set to "Choose a
2142 file". If you want to use multiple filters, separate each one with
2143 \e two semi-colons, e.g.
2144 \code
2145 "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
2146 \endcode
2147
2148 You can create your own QFileDialog without using the static
2149 functions. By calling setMode(), you can set what can be returned by
2150 the QFileDialog.
2151
2152 \code
2153 QFileDialog* fd = new QFileDialog( this, "file dialog", TRUE );
2154 fd->setMode( QFileDialog::AnyFile );
2155 \endcode
2156
2157 In the above example, the mode of the file dialog is set to \c
2158 AnyFile, meaning that the user can select any file, or even specify a
2159 file that doesn't exist. This mode is useful for creating a "File Save
2160 As" file dialog. Use \c ExistingFile if the user must select an
2161 existing file or \c Directory if only a directory may be selected.
2162 (See the \l QFileDialog::Mode enum for the complete list of modes.)
2163
2164 You can retrieve the dialog's mode with mode(). Use setFilter() to set
2165 the dialog's file filter, e.g.
2166
2167 \code
2168 fd->setFilter( "Images (*.png *.xpm *.jpg)" );
2169 \endcode
2170
2171 In the above example, the filter is set to "Images (*.png *.xpm
2172 *.jpg)", this means that only files with the extension \c png, \c xpm
2173 or \c jpg will be shown in the QFileDialog. You can apply
2174 several filters by using setFilters() and add additional filters with
2175 addFilter(). Use setSelectedFilter() to select one of the filters
2176 you've given as the file dialog's default filter. Whenever the user
2177 changes the filter the filterSelected() signal is emitted.
2178
2179 The file dialog has two view modes, QFileDialog::List which simply
2180 lists file and directory names and QFileDialog::Detail which
2181 displays additional information alongside each name, e.g. file size,
2182 modification date, etc. Set the mode with setViewMode().
2183
2184 \code
2185 fd->setViewMode( QFileDialog::Detail );
2186 \endcode
2187
2188 The last important function you will need to use when creating your
2189 own file dialog is selectedFile().
2190
2191 \code
2192 QString fileName;
2193 if ( fd->exec() == QDialog::Accepted )
2194 fileName = fd->selectedFile();
2195 \endcode
2196
2197 In the above example, a modal file dialog is created and shown. If
2198 the user clicked OK, then the file they selected is put in \c
2199 fileName.
2200
2201 If you are using the \c ExistingFiles mode then you will need to use
2202 selectedFiles() which will return the selected files in a QStringList.
2203
2204 The dialog's working directory can be set with setDir(). The display
2205 of hidden files is controlled with setShowHiddenFiles(). The dialog
2206 can be forced to re-read the directory with rereadDir() and re-sort
2207 the directory with resortDir(). All the files in the current directory
2208 can be selected with selectAll().
2209
2210 \section1 Creating and using preview widgets
2211
2212 There are two kinds of preview widgets that can be used with
2213 QFileDialogs: \e content preview widgets and \e information preview
2214 widgets. They are created and used in the same way except that the
2215 function names differ, e.g. setContentsPreview() and setInfoPreview().
2216
2217 A preview widget is a widget that is placed inside a QFileDialog so
2218 that the user can see either the contents of the file, or information
2219 about the file.
2220
2221 \code
2222 class Preview : public QLabel, public QFilePreview
2223 {
2224 public:
2225 Preview( QWidget *parent=0 ) : QLabel( parent ) {}
2226
2227 void previewUrl( const QUrl &u )
2228 {
2229 QString path = u.path();
2230 QPixmap pix( path );
2231 if ( pix.isNull() )
2232 setText( "This is not a pixmap" );
2233 else
2234 setPixmap( pix );
2235 }
2236 };
2237 \endcode
2238
2239 In the above snippet, we create a preview widget which inherits from
2240 QLabel and QFilePreview. File preview widgets \e must inherit from
2241 QFilePreview.
2242
2243 Inside the class we reimplement QFilePreview::previewUrl(), this is
2244 where we determine what happens when a file is selected. In the
2245 above example we only show a preview of the file if it is a valid
2246 pixmap. Here's how to make a file dialog use a preview widget:
2247
2248 \code
2249 Preview* p = new Preview;
2250
2251 QFileDialog* fd = new QFileDialog( this );
2252 fd->setContentsPreviewEnabled( TRUE );
2253 fd->setContentsPreview( p, p );
2254 fd->setPreviewMode( QFileDialog::Contents );
2255 fd->show();
2256 \endcode
2257
2258 The first line creates an instance of our preview widget. We then
2259 create our file dialog and call setContentsPreviewEnabled( TRUE ),
2260 this tell the file dialog to preview the contents of the currently
2261 selected file. We then call setContentsPreview() -- note that we pass
2262 the same preview widget twice. Finally, before showing the file
2263 dialog, we call setPreviewMode() setting the mode to \e Contents which
2264 will show the contents preview of the file that the user has selected.
2265
2266 If you create another preview widget that is used for displaying
2267 information about a file, create it in the same way as the contents
2268 preview widget and call setInfoPreviewEnabled(), and
2269 setInfoPreview(). Then the user will be able to switch between the
2270 two preview modes.
2271
2272 For more information about creating a QFilePreview widget see
2273 \l{QFilePreview}.
2274
2275 <img src=qfiledlg-m.png> <img src=qfiledlg-w.png>
2276
2277*/
2278
2279
2280/*! \enum QFileDialog::Mode
2281
2282 This enum is used to indicate what the user may select in the file
2283 dialog, i.e. what the dialog will return if the user clicks OK.
2284
2285 \value AnyFile The name of a file, whether it exists or not.
2286 \value ExistingFile The name of a single existing file.
2287 \value Directory The name of a directory. Both files and directories
2288 are displayed.
2289 \value DirectoryOnly The name of a directory. The file dialog will only display directories.
2290 \value ExistingFiles The names of zero or more existing files.
2291
2292 See setMode().
2293*/
2294
2295/*!
2296 \enum QFileDialog::ViewMode
2297
2298 This enum describes the view mode of the file dialog, i.e. what
2299 information about each file will be displayed.
2300
2301 \value List Display file and directory names with icons.
2302 \value Detail Display file and directory names with icons plus
2303 additional information, such as file size and modification date.
2304
2305 See setViewMode().
2306*/
2307
2308/*!
2309 \enum QFileDialog::PreviewMode
2310
2311 This enum describes the preview mode of the file dialog.
2312
2313 \value NoPreview No preview is shown at all.
2314 \value Contents Show a preview of the contents of the current file
2315 using the contents preview widget.
2316 \value Info Show information about the current file using the
2317 info preview widget.
2318
2319 See setPreviewMode(), setContentsPreview() and setInfoPreview().
2320*/
2321
2322/*!
2323 \fn void QFileDialog::detailViewSelectionChanged()
2324 \internal
2325*/
2326
2327/*!
2328 \fn void QFileDialog::listBoxSelectionChanged()
2329 \internal
2330*/
2331
2332extern const char qt_file_dialog_filter_reg_exp[] =
2333 "([a-zA-Z0-9 ]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$";
2334
2335/*!
2336 Constructs a file dialog called \a name, with the parent, \a parent.
2337 If \a modal is TRUE then the file dialog is modal; otherwise it is
2338 modeless.
2339*/
2340
2341QFileDialog::QFileDialog( QWidget *parent, const char *name, bool modal )
2342 : QDialog( parent, name, modal,
2343 (modal ?
2344 (WStyle_Customize | WStyle_DialogBorder | WStyle_Title | WStyle_SysMenu) : 0) )
2345{
2346 init();
2347 d->mode = ExistingFile;
2348 d->types->insertItem( tr( "All Files (*)" ) );
2349 d->cursorOverride = FALSE;
2350 emit dirEntered( d->url.dirPath() );
2351 rereadDir();
2352}
2353
2354
2355/*!
2356 Constructs a file dialog called \a name with the parent, \a parent.
2357 If \a modal is TRUE then the file dialog is modal; otherwise it is
2358 modeless.
2359
2360 If \a dirName is specified then it will be used as the dialog's
2361 working directory, i.e. it will be the directory that is shown when
2362 the dialog appears. If \a filter is specified it will be used as the
2363 dialog's file filter.
2364
2365*/
2366
2367QFileDialog::QFileDialog( const QString& dirName, const QString & filter,
2368 QWidget *parent, const char *name, bool modal )
2369 : QDialog( parent, name, modal,
2370 (modal ?
2371 (WStyle_Customize | WStyle_DialogBorder | WStyle_Title | WStyle_SysMenu) : 0) )
2372{
2373 init();
2374 d->mode = ExistingFile;
2375 rereadDir();
2376 QUrlOperator u( dirName );
2377 if ( !dirName.isEmpty() && ( !u.isLocalFile() || QDir( dirName ).exists() ) )
2378 setSelection( dirName );
2379 else if ( workingDirectory && !workingDirectory->isEmpty() )
2380 setDir( *workingDirectory );
2381
2382 if ( !filter.isEmpty() ) {
2383 setFilters( filter );
2384 if ( !dirName.isEmpty() ) {
2385 int dotpos = dirName.find( QChar('.'), 0, FALSE );
2386 if ( dotpos != -1 ) {
2387 for ( int b=0 ; b<d->types->count() ; b++ ) {
2388 if ( d->types->text(b).contains( dirName.right( dirName.length() - dotpos ) ) ) {
2389 d->types->setCurrentItem( b );
2390 setFilter( d->types->text( b ) );
2391 return;
2392 }
2393 }
2394 }
2395 }
2396 } else {
2397 d->types->insertItem( tr( "All Files (*)" ) );
2398 }
2399}
2400
2401
2402/*!
2403 \internal
2404 Initializes the file dialog.
2405*/
2406
2407void QFileDialog::init()
2408{
2409 setSizeGripEnabled( TRUE );
2410 d = new QFileDialogPrivate();
2411 d->mode = AnyFile;
2412 d->last = 0;
2413 d->lastEFSelected = 0;
2414 d->moreFiles = 0;
2415 d->infoPreview = FALSE;
2416 d->contentsPreview = FALSE;
2417 d->hadDotDot = FALSE;
2418 d->ignoreNextKeyPress = FALSE;
2419 d->progressDia = 0;
2420 d->checkForFilter = FALSE;
2421 d->ignoreNextRefresh = FALSE;
2422 d->ignoreStop = FALSE;
2423 d->pendingItems.setAutoDelete( FALSE );
2424 d->mimeTypeTimer = new QTimer( this );
2425 d->cursorOverride = FALSE;
2426 connect( d->mimeTypeTimer, SIGNAL( timeout() ),
2427 this, SLOT( doMimeTypeLookup() ) );
2428
2429 d->url = QUrlOperator( QDir::currentDirPath() );
2430 d->oldUrl = d->url;
2431 d->currListChildren = 0;
2432
2433 connect( &d->url, SIGNAL( start(QNetworkOperation*) ),
2434 this, SLOT( urlStart(QNetworkOperation*) ) );
2435 connect( &d->url, SIGNAL( finished(QNetworkOperation*) ),
2436 this, SLOT( urlFinished(QNetworkOperation*) ) );
2437 connect( &d->url, SIGNAL( newChildren(const QValueList<QUrlInfo>&,QNetworkOperation*) ),
2438 this, SLOT( insertEntry(const QValueList<QUrlInfo>&,QNetworkOperation*) ) );
2439 connect( &d->url, SIGNAL( removed(QNetworkOperation*) ),
2440 this, SLOT( removeEntry(QNetworkOperation*) ) );
2441 connect( &d->url, SIGNAL( createdDirectory(const QUrlInfo&,QNetworkOperation*) ),
2442 this, SLOT( createdDirectory(const QUrlInfo&,QNetworkOperation*) ) );
2443 connect( &d->url, SIGNAL( itemChanged(QNetworkOperation*) ),
2444 this, SLOT( itemChanged(QNetworkOperation*) ) );
2445 connect( &d->url, SIGNAL( dataTransferProgress(int,int,QNetworkOperation*) ),
2446 this, SLOT( dataTransferProgress(int,int,QNetworkOperation*) ) );
2447
2448 nameEdit = new QLineEdit( this, "name/filter editor" );
2449 nameEdit->setMaxLength( 255 ); //_POSIX_MAX_PATH
2450 connect( nameEdit, SIGNAL(textChanged(const QString&)),
2451 this, SLOT(fileNameEditDone()) );
2452 nameEdit->installEventFilter( this );
2453
2454 d->splitter = new QSplitter( this, "qt_splitter" );
2455
2456 d->stack = new QWidgetStack( d->splitter, "files and more files" );
2457
2458 d->splitter->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
2459
2460 files = new QFileDialogQFileListView( d->stack, this );
2461 QFontMetrics fm = fontMetrics();
2462 files->addColumn( tr("Name") );
2463 files->addColumn( tr("Size") );
2464 files->setColumnAlignment( 1, AlignRight );
2465 files->addColumn( tr("Type") );
2466 files->addColumn( tr("Date") );
2467 files->addColumn( tr("Attributes") );
2468 files->header()->setStretchEnabled( TRUE, 0 );
2469
2470 files->setMinimumSize( 50, 25 + 2*fm.lineSpacing() );
2471
2472 connect( files, SIGNAL( selectionChanged() ),
2473 this, SLOT( detailViewSelectionChanged() ) );
2474 connect( files, SIGNAL(currentChanged(QListViewItem*)),
2475 this, SLOT(updateFileNameEdit(QListViewItem*)) );
2476 connect( files, SIGNAL(doubleClicked(QListViewItem*)),
2477 this, SLOT(selectDirectoryOrFile(QListViewItem*)) );
2478 connect( files, SIGNAL(returnPressed(QListViewItem*)),
2479 this, SLOT(selectDirectoryOrFile(QListViewItem*)) );
2480 connect( files, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint&,int)),
2481 this, SLOT(popupContextMenu(QListViewItem*,const QPoint&,int)) );
2482
2483 files->installEventFilter( this );
2484 files->viewport()->installEventFilter( this );
2485
2486 d->moreFiles = new QFileListBox( d->stack, this );
2487 d->moreFiles->setRowMode( QListBox::FitToHeight );
2488 d->moreFiles->setVariableWidth( TRUE );
2489
2490 connect( d->moreFiles, SIGNAL(selected(QListBoxItem*)),
2491 this, SLOT(selectDirectoryOrFile(QListBoxItem*)) );
2492 connect( d->moreFiles, SIGNAL( selectionChanged() ),
2493 this, SLOT( listBoxSelectionChanged() ) );
2494 connect( d->moreFiles, SIGNAL(highlighted(QListBoxItem*)),
2495 this, SLOT(updateFileNameEdit(QListBoxItem*)) );
2496 connect( d->moreFiles, SIGNAL( rightButtonPressed(QListBoxItem*,const QPoint&) ),
2497 this, SLOT( popupContextMenu(QListBoxItem*,const QPoint&) ) );
2498
2499 d->moreFiles->installEventFilter( this );
2500 d->moreFiles->viewport()->installEventFilter( this );
2501
2502 okB = new QPushButton( tr("&OK"), this, "OK" ); //### Or "Save (see other "OK")
2503 okB->setDefault( TRUE );
2504 okB->setEnabled( FALSE );
2505 connect( okB, SIGNAL(clicked()), this, SLOT(okClicked()) );
2506 cancelB = new QPushButton( tr("Cancel") , this, "Cancel" );
2507 connect( cancelB, SIGNAL(clicked()), this, SLOT(cancelClicked()) );
2508
2509 d->paths = new QComboBox( TRUE, this, "directory history/editor" );
2510 d->paths->setDuplicatesEnabled( FALSE );
2511 d->paths->setInsertionPolicy( QComboBox::NoInsertion );
2512 const QFileInfoList * rootDrives = QDir::drives();
2513 QFileInfoListIterator it( *rootDrives );
2514 QFileInfo *fi;
2515 makeVariables();
2516
2517 while ( (fi = it.current()) != 0 ) {
2518 ++it;
2519 d->paths->insertItem( *openFolderIcon, fi->absFilePath() );
2520 }
2521
2522 if ( !!QDir::homeDirPath() ) {
2523 if ( !d->paths->listBox()->findItem( QDir::homeDirPath() ) )
2524 d->paths->insertItem( *openFolderIcon, QDir::homeDirPath() );
2525 }
2526
2527 connect( d->paths, SIGNAL(activated(const QString&)),
2528 this, SLOT(setDir(const QString&)) );
2529
2530 d->paths->installEventFilter( this );
2531 QObjectList *ol = d->paths->queryList( "QLineEdit" );
2532 if ( ol && ol->first() )
2533 ( (QLineEdit*)ol->first() )->installEventFilter( this );
2534 delete ol;
2535
2536 d->geometryDirty = TRUE;
2537 d->types = new QComboBox( TRUE, this, "file types" );
2538 d->types->setDuplicatesEnabled( FALSE );
2539 d->types->setEditable( FALSE );
2540 connect( d->types, SIGNAL(activated(const QString&)),
2541 this, SLOT(setFilter(const QString&)) );
2542 connect( d->types, SIGNAL(activated(const QString&)),
2543 this, SIGNAL(filterSelected(const QString&)) );
2544
2545 d->pathL = new QLabel( d->paths, tr("Look &in:"), this, "qt_looin_lbl" );
2546 d->fileL = new QLabel( nameEdit, tr("File &name:"), this, "qt_filename_lbl" );
2547 d->typeL = new QLabel( d->types, tr("File &type:"), this, "qt_filetype_lbl" );
2548
2549 d->goBack = new QToolButton( this, "go back" );
2550 d->goBack->setEnabled( FALSE );
2551 d->goBack->setFocusPolicy( TabFocus );
2552 connect( d->goBack, SIGNAL( clicked() ), this, SLOT( goBack() ) );
2553#ifndef QT_NO_TOOLTIP
2554 QToolTip::add( d->goBack, tr( "Back" ) );
2555#endif
2556 d->goBack->setIconSet( *goBackIcon );
2557
2558 d->cdToParent = new QToolButton( this, "cd to parent" );
2559 d->cdToParent->setFocusPolicy( TabFocus );
2560#ifndef QT_NO_TOOLTIP
2561 QToolTip::add( d->cdToParent, tr( "One directory up" ) );
2562#endif
2563 d->cdToParent->setIconSet( *cdToParentIcon );
2564 connect( d->cdToParent, SIGNAL(clicked()),
2565 this, SLOT(cdUpClicked()) );
2566
2567 d->newFolder = new QToolButton( this, "new folder" );
2568 d->newFolder->setFocusPolicy( TabFocus );
2569#ifndef QT_NO_TOOLTIP
2570 QToolTip::add( d->newFolder, tr( "Create New Folder" ) );
2571#endif
2572 d->newFolder->setIconSet( *newFolderIcon );
2573 connect( d->newFolder, SIGNAL(clicked()),
2574 this, SLOT(newFolderClicked()) );
2575
2576 d->modeButtons = new QButtonGroup( 0, "invisible group" );
2577 connect( d->modeButtons, SIGNAL(destroyed()),
2578 this, SLOT(modeButtonsDestroyed()) );
2579 d->modeButtons->setExclusive( TRUE );
2580 connect( d->modeButtons, SIGNAL(clicked(int)),
2581 d->stack, SLOT(raiseWidget(int)) );
2582 connect( d->modeButtons, SIGNAL(clicked(int)),
2583 this, SLOT(changeMode(int)) );
2584
2585 d->mcView = new QToolButton( this, "mclistbox view" );
2586 d->mcView->setFocusPolicy( TabFocus );
2587#ifndef QT_NO_TOOLTIP
2588 QToolTip::add( d->mcView, tr( "List View" ) );
2589#endif
2590 d->mcView->setIconSet( *multiColumnListViewIcon );
2591 d->mcView->setToggleButton( TRUE );
2592 d->stack->addWidget( d->moreFiles, d->modeButtons->insert( d->mcView ) );
2593 d->detailView = new QToolButton( this, "list view" );
2594 d->detailView->setFocusPolicy( TabFocus );
2595#ifndef QT_NO_TOOLTIP
2596 QToolTip::add( d->detailView, tr( "Detail View" ) );
2597#endif
2598 d->detailView->setIconSet( *detailViewIcon );
2599 d->detailView->setToggleButton( TRUE );
2600 d->stack->addWidget( files, d->modeButtons->insert( d->detailView ) );
2601
2602 d->previewInfo = new QToolButton( this, "preview info view" );
2603 d->previewInfo->setFocusPolicy( TabFocus );
2604#ifndef QT_NO_TOOLTIP
2605 QToolTip::add( d->previewInfo, tr( "Preview File Info" ) );
2606#endif
2607 d->previewInfo->setIconSet( *previewInfoViewIcon );
2608 d->previewInfo->setToggleButton( TRUE );
2609 d->modeButtons->insert( d->previewInfo );
2610
2611 d->previewContents = new QToolButton( this, "preview info view" );
2612#if defined(Q_WS_WIN) && !defined(Q_OS_TEMP)
2613 if ( (qt_winver & WV_NT_based) > Qt::WV_NT )
2614#else
2615 if ( !qstrcmp(style().className(), "QWindowsStyle") )
2616#endif
2617 {
2618 d->goBack->setAutoRaise( TRUE );
2619 d->cdToParent->setAutoRaise( TRUE );
2620 d->newFolder->setAutoRaise( TRUE );
2621 d->mcView->setAutoRaise( TRUE );
2622 d->detailView->setAutoRaise( TRUE );
2623 d->previewInfo->setAutoRaise( TRUE );
2624 d->previewContents->setAutoRaise( TRUE );
2625 }
2626 d->previewContents->setFocusPolicy( TabFocus );
2627#ifndef QT_NO_TOOLTIP
2628 QToolTip::add( d->previewContents, tr( "Preview File Contents" ) );
2629#endif
2630 d->previewContents->setIconSet( *previewContentsViewIcon );
2631 d->previewContents->setToggleButton( TRUE );
2632 d->modeButtons->insert( d->previewContents );
2633
2634 connect( d->detailView, SIGNAL( clicked() ),
2635 d->moreFiles, SLOT( cancelRename() ) );
2636 connect( d->detailView, SIGNAL( clicked() ),
2637 files, SLOT( cancelRename() ) );
2638 connect( d->mcView, SIGNAL( clicked() ),
2639 d->moreFiles, SLOT( cancelRename() ) );
2640 connect( d->mcView, SIGNAL( clicked() ),
2641 files, SLOT( cancelRename() ) );
2642
2643 d->stack->raiseWidget( d->moreFiles );
2644 d->mcView->setOn( TRUE );
2645
2646 QHBoxLayout *lay = new QHBoxLayout( this );
2647 lay->setMargin( 6 );
2648 d->leftLayout = new QHBoxLayout( lay, 5 );
2649 d->topLevelLayout = new QVBoxLayout( (QWidget*)0, 5 );
2650 lay->addLayout( d->topLevelLayout, 1 );
2651 d->extraWidgetsLayouts.setAutoDelete( FALSE );
2652 d->extraLabels.setAutoDelete( FALSE );
2653 d->extraWidgets.setAutoDelete( FALSE );
2654 d->extraButtons.setAutoDelete( FALSE );
2655 d->toolButtons.setAutoDelete( FALSE );
2656
2657 QHBoxLayout * h;
2658
2659 d->preview = new QWidgetStack( d->splitter, "qt_preview" );
2660
2661 d->infoPreviewWidget = new QWidget( d->preview, "qt_preview_info" );
2662 d->contentsPreviewWidget = new QWidget( d->preview, "qt_preview_contents" );
2663 d->infoPreviewer = d->contentsPreviewer = 0;
2664
2665 h = new QHBoxLayout( 0 );
2666 d->buttonLayout = h;
2667 d->topLevelLayout->addLayout( h );
2668 h->addWidget( d->pathL );
2669 h->addSpacing( 8 );
2670 h->addWidget( d->paths );
2671 h->addSpacing( 8 );
2672 if ( d->goBack )
2673 h->addWidget( d->goBack );
2674 h->addWidget( d->cdToParent );
2675 h->addSpacing( 2 );
2676 h->addWidget( d->newFolder );
2677 h->addSpacing( 4 );
2678 h->addWidget( d->mcView );
2679 h->addWidget( d->detailView );
2680 h->addWidget( d->previewInfo );
2681 h->addWidget( d->previewContents );
2682
2683 d->topLevelLayout->addWidget( d->splitter );
2684
2685 h = new QHBoxLayout();
2686 d->topLevelLayout->addLayout( h );
2687 h->addWidget( d->fileL );
2688 h->addWidget( nameEdit );
2689 h->addSpacing( 15 );
2690 h->addWidget( okB );
2691
2692 h = new QHBoxLayout();
2693 d->topLevelLayout->addLayout( h );
2694 h->addWidget( d->typeL );
2695 h->addWidget( d->types );
2696 h->addSpacing( 15 );
2697 h->addWidget( cancelB );
2698
2699 d->rightLayout = new QHBoxLayout( lay, 5 );
2700 d->topLevelLayout->setStretchFactor( d->mcView, 1 );
2701 d->topLevelLayout->setStretchFactor( files, 1 );
2702
2703 updateGeometries();
2704
2705 if ( d->goBack ) {
2706 setTabOrder( d->paths, d->goBack );
2707 setTabOrder( d->goBack, d->cdToParent );
2708 } else {
2709 setTabOrder( d->paths, d->cdToParent );
2710 }
2711 setTabOrder( d->cdToParent, d->newFolder );
2712 setTabOrder( d->newFolder, d->mcView );
2713 setTabOrder( d->mcView, d->detailView );
2714 setTabOrder( d->detailView, d->moreFiles );
2715 setTabOrder( d->moreFiles, files );
2716 setTabOrder( files, nameEdit );
2717 setTabOrder( nameEdit, d->types );
2718 setTabOrder( d->types, okB );
2719 setTabOrder( okB, cancelB );
2720
2721 d->rw = tr( "Read-write" );
2722 d->ro = tr( "Read-only" );
2723 d->wo = tr( "Write-only" );
2724 d->inaccessible = tr( "Inaccessible" );
2725
2726 d->symLinkToFile = tr( "Symlink to File" );
2727 d->symLinkToDir = tr( "Symlink to Directory" );
2728 d->symLinkToSpecial = tr( "Symlink to Special" );
2729 d->file = tr( "File" );
2730 d->dir = tr( "Dir" );
2731 d->special = tr( "Special" );
2732
2733 if ( lastWidth == 0 ) {
2734 QRect screen = QApplication::desktop()->screenGeometry( pos() );
2735 if ( screen.width() < 1024 || screen.height() < 768 ) {
2736 resize( QMIN(screen.width(), 420), QMIN(screen.height(), 236) );
2737 } else {
2738 QSize s = files->sizeHint();
2739 s = QSize( s.width() + 300, s.height() + 82 );
2740
2741 if ( s.width() * 3 > screen.width() * 2 )
2742 s.setWidth( screen.width() * 2 / 3 );
2743
2744 if ( s.height() * 3 > screen.height() * 2 )
2745 s.setHeight( screen.height() * 2 / 3 );
2746 else if ( s.height() * 3 < screen.height() )
2747 s.setHeight( screen.height() / 3 );
2748
2749 resize( s );
2750 }
2751 updateLastSize(this);
2752 } else {
2753 resize( lastWidth, lastHeight );
2754 }
2755
2756 if ( detailViewMode ) {
2757 d->stack->raiseWidget( files );
2758 d->mcView->setOn( FALSE );
2759 d->detailView->setOn( TRUE );
2760 }
2761
2762 d->preview->hide();
2763 nameEdit->setFocus();
2764
2765 connect( nameEdit, SIGNAL( returnPressed() ),
2766 this, SLOT( fileNameEditReturnPressed() ) );
2767}
2768
2769/*!
2770 \internal
2771*/
2772
2773void QFileDialog::fileNameEditReturnPressed()
2774{
2775 d->oldUrl = d->url;
2776 if ( !isDirectoryMode( d->mode ) ) {
2777 okClicked();
2778 } else {
2779 d->currentFileName = QString::null;
2780 if ( nameEdit->text().isEmpty() ) {
2781 emit fileSelected( selectedFile() );
2782 accept();
2783 } else {
2784 QUrlInfo f;
2785 QFileDialogPrivate::File * c
2786 = (QFileDialogPrivate::File *)files->currentItem();
2787 if ( c && files->isSelected(c) )
2788 f = c->info;
2789 else
2790 f = QUrlInfo( d->url, nameEdit->text() );
2791 if ( f.isDir() ) {
2792 setUrl( QUrlOperator( d->url,
2793 QFileDialogPrivate::encodeFileName(nameEdit->text() + "/" ) ) );
2794 d->checkForFilter = TRUE;
2795 trySetSelection( TRUE, d->url, TRUE );
2796 d->checkForFilter = FALSE;
2797 }
2798 }
2799 nameEdit->setText( QString::null );
2800 }
2801}
2802
2803/*!
2804 \internal
2805 Update the info and content preview widgets to display \a u.
2806*/
2807
2808void QFileDialog::updatePreviews( const QUrl &u )
2809{
2810 if ( d->infoPreviewer )
2811 d->infoPreviewer->previewUrl( u );
2812 if ( d->contentsPreviewer )
2813 d->contentsPreviewer->previewUrl( u );
2814}
2815
2816/*!
2817 \internal
2818 Changes the preview mode to the mode specified at \a id.
2819*/
2820
2821void QFileDialog::changeMode( int id )
2822{
2823 if ( !d->infoPreview && !d->contentsPreview )
2824 return;
2825
2826 QButton *btn = (QButton*)d->modeButtons->find( id );
2827 if ( !btn )
2828 return;
2829
2830 if ( btn == d->previewContents && !d->contentsPreview )
2831 return;
2832 if ( btn == d->previewInfo && !d->infoPreview )
2833 return;
2834
2835 if ( btn != d->previewContents && btn != d->previewInfo ) {
2836 d->preview->hide();
2837 } else {
2838 if ( files->currentItem() )
2839 updatePreviews( QUrl( d->url, files->currentItem()->text( 0 ) ) );
2840 if ( btn == d->previewInfo )
2841 d->preview->raiseWidget( d->infoPreviewWidget );
2842 else
2843 d->preview->raiseWidget( d->contentsPreviewWidget );
2844 d->preview->show();
2845 }
2846}
2847
2848/*!
2849 Destroys the file dialog.
2850*/
2851
2852QFileDialog::~QFileDialog()
2853{
2854 // since clear might call setContentsPos which would emit
2855 // a signal and thus cause a recompute of sizes...
2856 files->blockSignals( TRUE );
2857 d->moreFiles->blockSignals( TRUE );
2858 files->clear();
2859 d->moreFiles->clear();
2860 d->moreFiles->blockSignals( FALSE );
2861 files->blockSignals( FALSE );
2862
2863#ifndef QT_NO_CURSOR
2864 if ( d->cursorOverride )
2865 QApplication::restoreOverrideCursor();
2866#endif
2867
2868 delete d;
2869 d = 0;
2870}
2871
2872
2873/*!
2874 \property QFileDialog::selectedFile
2875
2876 \brief the name of the selected file
2877
2878 If a file was selected selectedFile contains the file's name including
2879 its absolute path; otherwise selectedFile is empty.
2880
2881 \sa QString::isEmpty(), selectedFiles, selectedFilter
2882*/
2883
2884QString QFileDialog::selectedFile() const
2885{
2886 QString s = d->currentFileName;
2887 // remove the protocol because we do not want to encode it...
2888 QString prot = QUrl( s ).protocol();
2889 if ( !prot.isEmpty() ) {
2890 prot += ":";
2891 s.remove( 0, prot.length() );
2892 }
2893 QUrl u( prot + QFileDialogPrivate::encodeFileName( s ) );
2894 if ( u.isLocalFile() ) {
2895 QString s = u.toString();
2896 if ( s.left( 5 ) == "file:" )
2897 s.remove( (uint)0, 5 );
2898 return s;
2899 }
2900 return d->currentFileName;
2901}
2902
2903/*!
2904 \property QFileDialog::selectedFilter
2905
2906 \brief the filter which the user has selected in the file dialog
2907
2908 \sa filterSelected(), selectedFiles, selectedFile
2909*/
2910
2911QString QFileDialog::selectedFilter() const
2912{
2913 return d->types->currentText();
2914}
2915
2916/*! \overload
2917
2918 Sets the current filter selected in the file dialog to the
2919 \a{n}-th filter in the filter list.
2920
2921 \sa filterSelected(), selectedFilter(), selectedFiles(), selectedFile()
2922*/
2923
2924void QFileDialog::setSelectedFilter( int n )
2925{
2926 d->types->setCurrentItem( n );
2927 QString f = d->types->currentText();
2928 QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) );
2929 int index = r.search( f );
2930 if ( index >= 0 )
2931 f = r.cap( 2 );
2932 d->url.setNameFilter( f );
2933 rereadDir();
2934}
2935
2936/*!
2937 Sets the current filter selected in the file dialog to the first
2938 one that contains the text \a mask.
2939*/
2940
2941void QFileDialog::setSelectedFilter( const QString& mask )
2942{
2943 int n;
2944
2945 for ( n = 0; n < d->types->count(); n++ ) {
2946 if ( d->types->text( n ).contains( mask, FALSE ) ) {
2947 d->types->setCurrentItem( n );
2948 QString f = mask;
2949 QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) );
2950 int index = r.search( f );
2951 if ( index >= 0 )
2952 f = r.cap( 2 );
2953 d->url.setNameFilter( f );
2954 rereadDir();
2955 return;
2956 }
2957 }
2958}
2959
2960/*!
2961 \property QFileDialog::selectedFiles
2962
2963 \brief the list of selected files
2964
2965 If one or more files are selected, selectedFiles contains their
2966 names including their absolute paths. If no files are selected or
2967 the mode isn't ExistingFiles selectedFiles is an empty list.
2968
2969 It is more convenient to use selectedFile() if the mode is
2970 \c ExistingFile, \c Directory or \c DirectoryOnly.
2971
2972 Note that if you want to iterate over the list, you should
2973 iterate over a copy, e.g.
2974 \code
2975 QStringList list = myFileDialog.selectedFiles();
2976 QStringList::Iterator it = list.begin();
2977 while( it != list.end() ) {
2978 myProcessing( *it );
2979 ++it;
2980 }
2981 \endcode
2982
2983 \sa selectedFile, selectedFilter, QValueList::empty()
2984*/
2985
2986QStringList QFileDialog::selectedFiles() const
2987{
2988 QStringList lst;
2989
2990 if ( mode() == ExistingFiles ) {
2991 QStringList selectedLst;
2992 QString selectedFiles = nameEdit->text();
2993 selectedFiles.truncate( selectedFiles.findRev( '\"' ) );
2994 selectedLst = selectedLst.split( QString("\" "), selectedFiles );
2995 for ( QStringList::Iterator it = selectedLst.begin(); it != selectedLst.end(); ++it ) {
2996 QUrl u;
2997 if ( (*it)[0] == '\"' ) {
2998 u = QUrl( d->url, QFileDialogPrivate::encodeFileName( (*it).mid(1) ) );
2999 } else {
3000 u = QUrl( d->url, QFileDialogPrivate::encodeFileName( (*it) ) );
3001 }
3002 if ( u.isLocalFile() ) {
3003 QString s = u.toString();
3004 if ( s.left( 5 ) == "file:" )
3005 s.remove( (uint)0, 5 );
3006 lst << s;
3007 } else {
3008 lst << u.toString();
3009 }
3010 }
3011 }
3012
3013 return lst;
3014}
3015
3016/*!
3017 Sets the default selection to \a filename. If \a filename is
3018 absolute, setDir() is also called to set the file dialog's working
3019 directory to the filename's directory.
3020
3021 \omit
3022 Only for external use. Not useful inside QFileDialog.
3023 \endomit
3024*/
3025
3026void QFileDialog::setSelection( const QString & filename )
3027{
3028 d->oldUrl = d->url;
3029 QString nf = d->url.nameFilter();
3030 if ( QUrl::isRelativeUrl( filename ) )
3031 d->url = QUrlOperator( d->url, QFileDialogPrivate::encodeFileName( filename ) );
3032 else
3033 d->url = QUrlOperator( filename );
3034 d->url.setNameFilter( nf );
3035 d->checkForFilter = TRUE;
3036 bool isDirOk;
3037 bool isDir = d->url.isDir( &isDirOk );
3038 if ( !isDirOk )
3039 isDir = d->url.path().right( 1 ) == "/";
3040 if ( !isDir ) {
3041 QUrlOperator u( d->url );
3042 d->url.setPath( d->url.dirPath() );
3043 trySetSelection( FALSE, u, TRUE );
3044 d->ignoreNextRefresh = TRUE;
3045 nameEdit->selectAll();
3046 rereadDir();
3047 emit dirEntered( d->url.dirPath() );
3048 } else {
3049 if ( !d->url.path().isEmpty() &&
3050 d->url.path().right( 1 ) != "/" ) {
3051 QString p = d->url.path();
3052 p += "/";
3053 d->url.setPath( p );
3054 }
3055 trySetSelection( TRUE, d->url, FALSE );
3056 rereadDir();
3057 emit dirEntered( d->url.dirPath() );
3058 nameEdit->setText( QString::fromLatin1("") );
3059 }
3060 d->checkForFilter = FALSE;
3061}
3062
3063/*!
3064 \property QFileDialog::dirPath
3065
3066 \brief the file dialog's working directory
3067
3068 \sa dir(), setDir()
3069*/
3070
3071QString QFileDialog::dirPath() const
3072{
3073 return d->url.dirPath();
3074}
3075
3076
3077/*!
3078
3079 Sets the filter used in the file dialog to \a newFilter.
3080
3081 If \a newFilter contains a pair of parentheses containing one or more
3082 of <em><b>anything*something</b></em> separated by spaces or by
3083 semi-colons then only the text contained in the parentheses is used as
3084 the filter. This means that these calls are all equivalent:
3085
3086 \code
3087 fd->setFilter( "All C++ files (*.cpp *.cc *.C *.cxx *.c++)" );
3088 fd->setFilter( "*.cpp *.cc *.C *.cxx *.c++" );
3089 fd->setFilter( "All C++ files (*.cpp;*.cc;*.C;*.cxx;*.c++)" );
3090 fd->setFilter( "*.cpp;*.cc;*.C;*.cxx;*.c++" );
3091 \endcode
3092
3093 \sa setFilters()
3094*/
3095
3096void QFileDialog::setFilter( const QString & newFilter )
3097{
3098 if ( newFilter.isEmpty() )
3099 return;
3100 QString f = newFilter;
3101 QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) );
3102 int index = r.search( f );
3103 if ( index >= 0 )
3104 f = r.cap( 2 );
3105 d->url.setNameFilter( f );
3106 if ( d->types->count() == 1 ) {
3107 d->types->clear();
3108 d->types->insertItem( newFilter );
3109 } else {
3110 for ( int i = 0; i < d->types->count(); ++i ) {
3111 if ( d->types->text( i ).left( newFilter.length() ) == newFilter ||
3112 d->types->text( i ).left( f.length() ) == f ) {
3113 d->types->setCurrentItem( i );
3114 break;
3115 }
3116 }
3117 }
3118 rereadDir();
3119}
3120
3121
3122/*! \overload
3123 Sets the file dialog's working directory to \a pathstr.
3124
3125 \sa dir()
3126*/
3127
3128void QFileDialog::setDir( const QString & pathstr )
3129{
3130 QString dr = pathstr;
3131 if ( dr.isEmpty() )
3132 return;
3133
3134#if defined(Q_OS_UNIX)
3135 if ( dr.length() && dr[0] == '~' ) {
3136 int i = 0;
3137 while( i < (int)dr.length() && dr[i] != '/' )
3138 i++;
3139 QCString user;
3140 if ( i == 1 ) {
3141#if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
3142
3143# ifndef _POSIX_LOGIN_NAME_MAX
3144# define _POSIX_LOGIN_NAME_MAX 9
3145# endif
3146
3147 char name[_POSIX_LOGIN_NAME_MAX];
3148 if ( ::getlogin_r( name, _POSIX_LOGIN_NAME_MAX ) == 0 )
3149 user = name;
3150 else
3151#else
3152 user = ::getlogin();
3153 if ( !user )
3154#endif
3155 user = getenv( "LOGNAME" );
3156 } else
3157 user = dr.mid( 1, i-1 ).local8Bit();
3158 dr = dr.mid( i, dr.length() );
3159 struct passwd *pw;
3160#if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_FREEBSD)
3161 struct passwd mt_pw;
3162 char buffer[2048];
3163 if ( ::getpwnam_r( user, &mt_pw, buffer, 2048, &pw ) == 0 && pw == &mt_pw )
3164#else
3165 pw = ::getpwnam( user );
3166 if ( pw )
3167#endif
3168 dr.prepend( QString::fromLocal8Bit(pw->pw_dir) );
3169 }
3170#endif
3171
3172 setUrl( dr );
3173}
3174
3175/*!
3176 Returns the current directory shown in the file dialog.
3177
3178 The ownership of the QDir pointer is transferred to the caller, so
3179 it must be deleted by the caller when no longer required.
3180
3181 \sa setDir()
3182*/
3183
3184const QDir *QFileDialog::dir() const
3185{
3186 if ( d->url.isLocalFile() )
3187 return new QDir( d->url.path() );
3188 else
3189 return 0;
3190}
3191
3192/*!
3193 Sets the file dialog's working directory to \a dir.
3194 \sa dir()
3195*/
3196
3197void QFileDialog::setDir( const QDir &dir )
3198{
3199 d->oldUrl = d->url;
3200 QString nf( d->url.nameFilter() );
3201 d->url = dir.canonicalPath();
3202 d->url.setNameFilter( nf );
3203 QUrlInfo i( d->url, nameEdit->text() );
3204 d->checkForFilter = TRUE;
3205 trySetSelection( i.isDir(), QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(nameEdit->text() ) ), FALSE );
3206 d->checkForFilter = FALSE;
3207 rereadDir();
3208 emit dirEntered( d->url.path() );
3209}
3210
3211/*!
3212 Sets the file dialog's working directory to the directory specified at \a url.
3213
3214 \sa url()
3215*/
3216
3217void QFileDialog::setUrl( const QUrlOperator &url )
3218{
3219 d->oldUrl = d->url;
3220 QString nf = d->url.nameFilter();
3221
3222 QString operatorPath = url.toString( FALSE, FALSE );
3223 if ( QUrl::isRelativeUrl( operatorPath ) ) {
3224 d->url = QUrl( d->url, operatorPath );
3225 } else {
3226 d->url = url;
3227 }
3228 d->url.setNameFilter( nf );
3229
3230 d->checkForFilter = TRUE;
3231 if ( !d->url.isDir() ) {
3232 QUrlOperator u = d->url;
3233 d->url.setPath( d->url.dirPath() );
3234 trySetSelection( FALSE, u, FALSE );
3235 rereadDir();
3236 emit dirEntered( d->url.dirPath() );
3237 QString fn = u.fileName();
3238 nameEdit->setText( fn );
3239 } else {
3240 trySetSelection( TRUE, d->url, FALSE );
3241 rereadDir();
3242 emit dirEntered( d->url.dirPath() );
3243 }
3244 d->checkForFilter = FALSE;
3245}
3246
3247/*!
3248 \property QFileDialog::showHiddenFiles
3249
3250 \brief whether hidden files are shown in the file dialog
3251
3252 The default is FALSE, i.e. don't show hidden files.
3253*/
3254
3255void QFileDialog::setShowHiddenFiles( bool s )
3256{
3257 if ( s == bShowHiddenFiles )
3258 return;
3259
3260 bShowHiddenFiles = s;
3261 rereadDir();
3262}
3263
3264bool QFileDialog::showHiddenFiles() const
3265{
3266 return bShowHiddenFiles;
3267}
3268
3269/*!
3270 Rereads the current directory shown in the file dialog.
3271
3272 The only time you will need to call this function is if the contents of
3273 the directory change and you wish to refresh the file dialog to reflect
3274 the change.
3275
3276 \sa resortDir()
3277*/
3278
3279void QFileDialog::rereadDir()
3280{
3281#ifndef QT_NO_CURSOR
3282 if ( !d->cursorOverride ) {
3283 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3284 d->cursorOverride = TRUE;
3285 }
3286#endif
3287 d->pendingItems.clear();
3288 if ( d->mimeTypeTimer->isActive() )
3289 d->mimeTypeTimer->stop();
3290 d->currListChildren = d->url.listChildren();
3291#ifndef QT_NO_CURSOR
3292 if ( d->cursorOverride ) {
3293 QApplication::restoreOverrideCursor();
3294 d->cursorOverride = FALSE;
3295 }
3296#endif
3297}
3298
3299
3300/*!
3301 \fn void QFileDialog::fileHighlighted( const QString& )
3302
3303 This signal is emitted when the user highlights a file, i.e. makes
3304 it the current file.
3305
3306 \sa fileSelected(), filesSelected()
3307*/
3308
3309/*!
3310 \fn void QFileDialog::fileSelected( const QString& )
3311
3312 This signal is emitted when the user selects a file.
3313
3314 \sa filesSelected(), fileHighlighted(), selectedFile()
3315*/
3316
3317/*!
3318 \fn void QFileDialog::filesSelected( const QStringList& )
3319
3320 This signal is emitted when the user selects one or more files in \e
3321 ExistingFiles mode.
3322
3323 \sa fileSelected(), fileHighlighted(), selectedFiles()
3324*/
3325
3326/*!
3327 \fn void QFileDialog::dirEntered( const QString& )
3328
3329 This signal is emitted when the user enters a directory.
3330
3331 \sa dir()
3332*/
3333
3334/*!
3335 \fn void QFileDialog::filterSelected( const QString& )
3336
3337 This signal is emitted when the user selects a filter.
3338
3339 \sa selectedFilter()
3340*/
3341
3342extern bool qt_resolve_symlinks; // defined in qapplication.cpp
3343bool Q_EXPORT qt_use_native_dialogs = TRUE;
3344
3345/*!
3346 This is a convenience static function that returns an existing file
3347 selected by the user. If the user pressed Cancel, it returns a null
3348 string.
3349
3350 \code
3351 QString s = QFileDialog::getOpenFileName(
3352 "/home",
3353 "Images (*.png *.xpm *.jpg)",
3354 this,
3355 "open file dialog",
3356 "Choose a file to open" );
3357 \endcode
3358
3359 The function creates a modal file dialog called \a name, with
3360 parent, \a parent. If a parent is not 0, the dialog will be shown
3361 centered over the parent.
3362
3363 The file dialog's working directory will be set to \a startWith. If \a
3364 startWith includes a file name, the file will be selected. The filter
3365 is set to \a filter so that only those files which match the filter
3366 are shown. The filter selected is set to \a selectedFilter. The parameters
3367 \a startWith, \a selectedFilter and \a filter may be QString::null.
3368
3369 The dialog's caption is set to \a caption. If \a caption is not
3370 specified then a default caption will be used.
3371
3372 Under Windows and Mac OS X, this static function will use the native
3373 file dialog and not a QFileDialog, unless the style of the application
3374 is set to something other than the native style (Note that on Windows the
3375 dialog will spin a blocking modal event loop that will not dispatch any
3376 QTimers and if parent is not 0 then it will position the dialog just under
3377 the parent's titlebar).
3378
3379 Under Unix/X11, the normal behavior of the file dialog is to resolve
3380 and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
3381 the file dialog will change to /var/tmp after entering /usr/tmp.
3382 If \a resolveSymlinks is FALSE, the file dialog will treat
3383 symlinks as regular directories.
3384
3385 \sa getOpenFileNames(), getSaveFileName(), getExistingDirectory()
3386*/
3387
3388QString QFileDialog::getOpenFileName( const QString & startWith,
3389 const QString& filter,
3390 QWidget *parent, const char* name,
3391 const QString& caption,
3392 QString *selectedFilter,
3393 bool resolveSymlinks )
3394{
3395 bool save_qt_resolve_symlinks = qt_resolve_symlinks;
3396 qt_resolve_symlinks = resolveSymlinks;
3397
3398 QStringList filters;
3399 if ( !filter.isEmpty() )
3400 filters = makeFiltersList( filter );
3401
3402 makeVariables();
3403 QString initialSelection;
3404 //### Problem with the logic here: If a startWith is given and a file
3405 // with that name exists in D->URL, the box will be opened at D->URL instead of
3406 // the last directory used ('workingDirectory').
3407 //
3408 // hm... isn't that problem exactly the documented behaviour? the
3409 // documented behaviour sounds meaningful.
3410 if ( !startWith.isEmpty() ) {
3411 QUrlOperator u( QFileDialogPrivate::encodeFileName( startWith ) );
3412 if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) {
3413 *workingDirectory = startWith;
3414 } else {
3415 if ( u.isLocalFile() ) {
3416 QFileInfo fi( u.dirPath() );
3417 if ( fi.exists() ) {
3418 *workingDirectory = u.dirPath();
3419 initialSelection = u.fileName();
3420 }
3421 } else {
3422 *workingDirectory = u.toString();
3423 initialSelection = QString::null;//u.fileName();
3424 }
3425 }
3426 }
3427
3428 if ( workingDirectory->isNull() )
3429 *workingDirectory = QDir::currentDirPath();
3430
3431#if defined(Q_WS_WIN)
3432 if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle )
3433 return winGetOpenFileName( initialSelection, filter, workingDirectory,
3434 parent, name, caption, selectedFilter );
3435#elif defined(Q_WS_MAC)
3436 if( qt_use_native_dialogs && ( qApp->style().inherits(QMAC_DEFAULT_STYLE) || qApp->style().inherits("QMacStyle") ) )
3437 return macGetOpenFileNames(filter, workingDirectory, parent, name, caption, selectedFilter, FALSE).first();
3438#endif
3439
3440 QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gofn", TRUE );
3441
3442 Q_CHECK_PTR( dlg );
3443#ifndef QT_NO_WIDGET_TOPEXTRA
3444 if ( !caption.isNull() )
3445 dlg->setCaption( caption );
3446 else
3447 dlg->setCaption( QFileDialog::tr( "Open" ) );
3448#endif
3449
3450 dlg->setFilters( filters );
3451 if ( selectedFilter )
3452 dlg->setFilter( *selectedFilter );
3453 dlg->setMode( QFileDialog::ExistingFile );
3454 QString result;
3455 if ( !initialSelection.isEmpty() )
3456 dlg->setSelection( initialSelection );
3457 if ( dlg->exec() == QDialog::Accepted ) {
3458 result = dlg->selectedFile();
3459 *workingDirectory = dlg->d->url;
3460 if ( selectedFilter )
3461 *selectedFilter = dlg->selectedFilter();
3462 }
3463 delete dlg;
3464
3465 qt_resolve_symlinks = save_qt_resolve_symlinks;
3466
3467 return result;
3468}
3469
3470/*!
3471 This is a convenience static function that will return a file name
3472 selected by the user. The file does not have to exist.
3473
3474 It creates a modal file dialog called \a name, with parent, \a parent.
3475 If a parent is not 0, the dialog will be shown centered over the
3476 parent.
3477
3478 \code
3479 QString s = QFileDialog::getSaveFileName(
3480 "/home",
3481 "Images (*.png *.xpm *.jpg)",
3482 this,
3483 "save file dialog"
3484 "Choose a filename to save under" );
3485 \endcode
3486
3487 The file dialog's working directory will be set to \a startWith. If \a
3488 startWith includes a file name, the file will be selected. The filter
3489 is set to \a filter so that only those files which match the filter
3490 are shown. The filter selected is set to \a selectedFilter. The parameters
3491 \a startWith, \a selectedFilter and \a filter may be QString::null.
3492
3493 The dialog's caption is set to \a caption. If \a caption is not
3494 specified then a default caption will be used.
3495
3496 Under Windows and Mac OS X, this static function will use the native
3497 file dialog and not a QFileDialog, unless the style of the application
3498 is set to something other than the native style. (Note that on Windows the
3499 dialog will spin a blocking modal event loop that will not dispatch any
3500 QTimers and if parent is not 0 then it will position the dialog just under
3501 the parent's titlebar. And on the Mac the filter argument is ignored).
3502
3503 Under Unix/X11, the normal behavior of the file dialog is to resolve
3504 and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
3505 the file dialog will change to /var/tmp after entering /usr/tmp.
3506 If \a resolveSymlinks is FALSE, the file dialog will treat
3507 symlinks as regular directories.
3508
3509 \sa getOpenFileName(), getOpenFileNames(), getExistingDirectory()
3510*/
3511
3512QString QFileDialog::getSaveFileName( const QString & startWith,
3513 const QString& filter,
3514 QWidget *parent, const char* name,
3515 const QString& caption,
3516 QString *selectedFilter,
3517 bool resolveSymlinks)
3518{
3519 bool save_qt_resolve_symlinks = qt_resolve_symlinks;
3520 qt_resolve_symlinks = resolveSymlinks;
3521
3522 QStringList filters;
3523 if ( !filter.isEmpty() )
3524 filters = makeFiltersList( filter );
3525
3526 makeVariables();
3527 QString initialSelection;
3528 if ( !startWith.isEmpty() ) {
3529 QUrlOperator u( QFileDialogPrivate::encodeFileName( startWith ) );
3530 if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) {
3531 *workingDirectory = startWith;
3532 } else {
3533 if ( u.isLocalFile() ) {
3534 QFileInfo fi( u.dirPath() );
3535 if ( fi.exists() ) {
3536 *workingDirectory = u.dirPath();
3537 initialSelection = u.fileName();
3538 }
3539 } else {
3540 *workingDirectory = u.toString();
3541 initialSelection = QString::null;//u.fileName();
3542 }
3543 }
3544 }
3545
3546 if ( workingDirectory->isNull() )
3547 *workingDirectory = QDir::currentDirPath();
3548
3549#if defined(Q_WS_WIN)
3550 if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle )
3551 return winGetSaveFileName( initialSelection, filter, workingDirectory,
3552 parent, name, caption, selectedFilter );
3553#elif defined(Q_WS_MAC)
3554 if( qt_use_native_dialogs && ( qApp->style().inherits(QMAC_DEFAULT_STYLE) || qApp->style().inherits("QMacStyle") ) )
3555 return macGetSaveFileName( initialSelection.isNull() ? startWith : initialSelection, filter, workingDirectory,
3556 parent, name, caption, selectedFilter );
3557#endif
3558
3559 QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gsfn", TRUE );
3560
3561 Q_CHECK_PTR( dlg );
3562#ifndef QT_NO_WIDGET_TOPEXTRA
3563 if ( !caption.isNull() )
3564 dlg->setCaption( caption );
3565 else
3566 dlg->setCaption( QFileDialog::tr( "Save As" ) );
3567#endif
3568
3569 QString result;
3570 dlg->setFilters( filters );
3571 if ( selectedFilter )
3572 dlg->setFilter( *selectedFilter );
3573 dlg->setMode( QFileDialog::AnyFile );
3574 if ( !initialSelection.isEmpty() )
3575 dlg->setSelection( initialSelection );
3576 if ( dlg->exec() == QDialog::Accepted ) {
3577 result = dlg->selectedFile();
3578 *workingDirectory = dlg->d->url;
3579 if ( selectedFilter )
3580 *selectedFilter = dlg->selectedFilter();
3581 }
3582 delete dlg;
3583
3584 qt_resolve_symlinks = save_qt_resolve_symlinks;
3585
3586 return result;
3587}
3588
3589/*!
3590 \internal
3591 Activated when the "OK" button is clicked.
3592*/
3593
3594void QFileDialog::okClicked()
3595{
3596 QString fn( nameEdit->text() );
3597
3598#if defined(Q_WS_WIN)
3599 QFileInfo fi( d->url.path() + fn );
3600 if ( fi.isSymLink() ) {
3601 nameEdit->setText( fi.readLink() );
3602 }
3603#endif
3604
3605 if ( fn.contains("*") ) {
3606 addFilter( fn );
3607 nameEdit->blockSignals( TRUE );
3608 nameEdit->setText( QString::fromLatin1("") );
3609 nameEdit->blockSignals( FALSE );
3610 return;
3611 }
3612
3613 *workingDirectory = d->url;
3614 detailViewMode = files->isVisible();
3615 updateLastSize(this);
3616
3617 if ( isDirectoryMode( d->mode ) ) {
3618 QUrlInfo f( d->url, nameEdit->text() );
3619 if ( f.isDir() ) {
3620 d->currentFileName = d->url;
3621 if ( d->currentFileName.right(1) != "/" )
3622 d->currentFileName += '/';
3623 if ( f.name() != "." )
3624 d->currentFileName += f.name();
3625 accept();
3626 return;
3627 }
3628 // Since it's not a directory and we clicked ok, we
3629 // don't really want to do anything else
3630 return;
3631 }
3632
3633 // if we're in multi-selection mode and something is selected,
3634 // accept it and be done.
3635 if ( mode() == ExistingFiles ) {
3636 if ( ! nameEdit->text().isEmpty() ) {
3637 QStringList sf = selectedFiles();
3638 bool isdir = FALSE;
3639 if ( sf.count() == 1 ) {
3640 QUrlOperator u( d->url, sf[0] );
3641 bool ok;
3642 isdir = u.isDir(&ok) && ok;
3643 }
3644 if ( !isdir ) {
3645 emit filesSelected( sf );
3646 accept();
3647 return;
3648 }
3649 }
3650 }
3651
3652 if ( mode() == AnyFile ) {
3653 QUrlOperator u( d->url, QFileDialogPrivate::encodeFileName(nameEdit->text()) );
3654 if ( !u.isDir() ) {
3655 d->currentFileName = u;
3656 emit fileSelected( selectedFile() );
3657 accept();
3658 return;
3659 }
3660 }
3661
3662 if ( mode() == ExistingFile ) {
3663 if ( !QFileDialogPrivate::fileExists( d->url, nameEdit->text() ) )
3664 return;
3665 }
3666
3667 // If selection is valid, return it, else try
3668 // using selection as a directory to change to.
3669 if ( !d->currentFileName.isNull() && !d->currentFileName.contains( "*" ) ) {
3670 emit fileSelected( selectedFile() );
3671 accept();
3672 } else {
3673 QUrlInfo f;
3674 QFileDialogPrivate::File * c
3675 = (QFileDialogPrivate::File *)files->currentItem();
3676 QFileDialogPrivate::MCItem * m
3677 = (QFileDialogPrivate::MCItem *)d->moreFiles->item( d->moreFiles->currentItem() );
3678 if ( c && files->isVisible() && files->hasFocus() ||
3679 m && d->moreFiles->isVisible() && d->moreFiles->hasFocus() ) {
3680 if ( c && files->isVisible() )
3681 f = c->info;
3682 else
3683 f = ( (QFileDialogPrivate::File*)m->i )->info;
3684 } else {
3685 f = QUrlInfo( d->url, nameEdit->text() );
3686 }
3687 if ( f.isDir() ) {
3688 setUrl( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(f.name() + "/" ) ) );
3689 d->checkForFilter = TRUE;
3690 trySetSelection( TRUE, d->url, TRUE );
3691 d->checkForFilter = FALSE;
3692 } else {
3693 if ( !nameEdit->text().contains( "/" ) &&
3694 !nameEdit->text().contains( "\\" )
3695#if defined(Q_OS_WIN32)
3696 && nameEdit->text()[ 1 ] != ':'
3697#endif
3698 )
3699 addFilter( nameEdit->text() );
3700 else if ( nameEdit->text()[ 0 ] == '/' ||
3701 nameEdit->text()[ 0 ] == '\\'
3702#if defined(Q_OS_WIN32)
3703 || nameEdit->text()[ 1 ] == ':'
3704#endif
3705 )
3706 setDir( nameEdit->text() );
3707 else if ( nameEdit->text().left( 3 ) == "../" || nameEdit->text().left( 3 ) == "..\\" )
3708 setDir( QUrl( d->url.toString(), QFileDialogPrivate::encodeFileName(nameEdit->text() ) ).toString() );
3709 }
3710 nameEdit->setText( "" );
3711 }
3712}
3713
3714/*!
3715 \internal
3716 Activated when the "Filter" button is clicked.
3717*/
3718
3719void QFileDialog::filterClicked()
3720{
3721 // unused
3722}
3723
3724/*!
3725 \internal
3726 Activated when the "Cancel" button is clicked.
3727*/
3728
3729void QFileDialog::cancelClicked()
3730{
3731 *workingDirectory = d->url;
3732 detailViewMode = files->isVisible();
3733 updateLastSize(this);
3734 reject();
3735}
3736
3737
3738/*!\reimp
3739*/
3740
3741void QFileDialog::resizeEvent( QResizeEvent * e )
3742{
3743 QDialog::resizeEvent( e );
3744 updateGeometries();
3745}
3746
3747/*
3748 \internal
3749 The only correct way to try to set currentFileName
3750*/
3751bool QFileDialog::trySetSelection( bool isDir, const QUrlOperator &u, bool updatelined )
3752{
3753 if ( !isDir && !u.path().isEmpty() && u.path().right( 1 ) == "/" )
3754 isDir = TRUE;
3755 if ( u.fileName().contains( "*") && d->checkForFilter ) {
3756 QString fn( u.fileName() );
3757 if ( fn.contains( "*" ) ) {
3758 addFilter( fn );
3759 d->currentFileName = QString::null;
3760 d->url.setFileName( QString::null );
3761 nameEdit->setText( QString::fromLatin1("") );
3762 return FALSE;
3763 }
3764 }
3765
3766 if ( isDir && d->preview && d->preview->isVisible() )
3767 updatePreviews( u );
3768
3769 QString old = d->currentFileName;
3770
3771 if ( isDirectoryMode( mode() ) ) {
3772 if ( isDir )
3773 d->currentFileName = u;
3774 else
3775 d->currentFileName = QString::null;
3776 } else if ( !isDir && mode() == ExistingFiles ) {
3777 d->currentFileName = u;
3778 } else if ( !isDir || ( mode() == AnyFile && !isDir ) ) {
3779 d->currentFileName = u;
3780 } else {
3781 d->currentFileName = QString::null;
3782 }
3783 if ( updatelined && !d->currentFileName.isEmpty() ) {
3784 // If the selection is valid, or if its a directory, allow OK.
3785 if ( !d->currentFileName.isNull() || isDir ) {
3786 if ( u.fileName() != ".." ) {
3787 QString fn = u.fileName();
3788 nameEdit->setText( fn );
3789 } else {
3790 nameEdit->setText("");
3791 }
3792 } else
3793 nameEdit->setText( QString::fromLatin1("") );
3794 }
3795
3796 if ( !d->currentFileName.isNull() || isDir ) {
3797 okB->setEnabled( TRUE );
3798 } else if ( !isDirectoryMode( d->mode ) ) {
3799 okB->setEnabled( FALSE );
3800 }
3801
3802 if ( d->currentFileName.length() && old != d->currentFileName )
3803 emit fileHighlighted( selectedFile() );
3804
3805 return !d->currentFileName.isNull();
3806}
3807
3808
3809/*! Make sure the minimum and maximum sizes of everything are sane.
3810*/
3811
3812void QFileDialog::updateGeometries()
3813{
3814 if ( !d || !d->geometryDirty )
3815 return;
3816
3817 d->geometryDirty = FALSE;
3818
3819 QSize r, t;
3820
3821 // we really should have a QSize::unite()
3822#define RM r.setWidth( QMAX(r.width(),t.width()) ); \
3823r.setHeight( QMAX(r.height(),t.height()) )
3824
3825 // labels first
3826 r = d->pathL->sizeHint();
3827 t = d->fileL->sizeHint();
3828 RM;
3829 t = d->typeL->sizeHint();
3830 RM;
3831 d->pathL->setFixedSize( d->pathL->sizeHint() );
3832 d->fileL->setFixedSize( r );
3833 d->typeL->setFixedSize( r );
3834
3835 // single-line input areas
3836 r = d->paths->sizeHint();
3837 t = nameEdit->sizeHint();
3838 RM;
3839 t = d->types->sizeHint();
3840 RM;
3841 r.setWidth( t.width() * 2 / 3 );
3842 t.setWidth( QWIDGETSIZE_MAX );
3843 t.setHeight( r.height() );
3844 d->paths->setMinimumSize( r );
3845 d->paths->setMaximumSize( t );
3846 nameEdit->setMinimumSize( r );
3847 nameEdit->setMaximumSize( t );
3848 d->types->setMinimumSize( r );
3849 d->types->setMaximumSize( t );
3850
3851 // buttons on top row
3852 r = QSize( 0, d->paths->minimumSize().height() );
3853 t = QSize( 21, 20 );
3854 RM;
3855 if ( r.height()+1 > r.width() )
3856 r.setWidth( r.height()+1 );
3857 if ( d->goBack )
3858 d->goBack->setFixedSize( r );
3859 d->cdToParent->setFixedSize( r );
3860 d->newFolder->setFixedSize( r );
3861 d->mcView->setFixedSize( r );
3862 d->detailView->setFixedSize( r );
3863
3864 QButton *b = 0;
3865 if ( !d->toolButtons.isEmpty() ) {
3866 for ( b = d->toolButtons.first(); b; b = d->toolButtons.next() )
3867 b->setFixedSize( b->sizeHint().width(), r.height() );
3868 }
3869
3870 if ( d->infoPreview ) {
3871 d->previewInfo->show();
3872 d->previewInfo->setFixedSize( r );
3873 } else {
3874 d->previewInfo->hide();
3875 d->previewInfo->setFixedSize( QSize( 0, 0 ) );
3876 }
3877
3878 if ( d->contentsPreview ) {
3879 d->previewContents->show();
3880 d->previewContents->setFixedSize( r );
3881 } else {
3882 d->previewContents->hide();
3883 d->previewContents->setFixedSize( QSize( 0, 0 ) );
3884 }
3885
3886 // open/save, cancel
3887 r = QSize( 75, 20 );
3888 t = okB->sizeHint();
3889 RM;
3890 t = cancelB->sizeHint();
3891 RM;
3892
3893 okB->setFixedSize( r );
3894 cancelB->setFixedSize( r );
3895
3896 d->topLevelLayout->activate();
3897
3898#undef RM
3899}
3900
3901
3902/*! Updates the file name edit box to \a newItem in the file dialog
3903 when the cursor moves in the listview.
3904*/
3905
3906void QFileDialog::updateFileNameEdit( QListViewItem * newItem )
3907{
3908 if ( !newItem )
3909 return;
3910
3911 if ( mode() == ExistingFiles ) {
3912 detailViewSelectionChanged();
3913 QUrl u( d->url, QFileDialogPrivate::encodeFileName( ((QFileDialogPrivate::File*)files->currentItem())->info.name() ) );
3914 QFileInfo fi( u.toString( FALSE, FALSE ) );
3915 if ( !fi.isDir() )
3916 emit fileHighlighted( u.toString( FALSE, FALSE ) );
3917 } else if ( files->isSelected( newItem ) ) {
3918 QFileDialogPrivate::File * i = (QFileDialogPrivate::File *)newItem;
3919 if ( i && i->i && !i->i->isSelected() ) {
3920 d->moreFiles->blockSignals( TRUE );
3921 d->moreFiles->setSelected( i->i, TRUE );
3922 d->moreFiles->blockSignals( FALSE );
3923 }
3924 // Encode the filename in case it had any special characters in it
3925 QString encFile = QFileDialogPrivate::encodeFileName( newItem->text( 0 ) );
3926 trySetSelection( i->info.isDir(), QUrlOperator( d->url, encFile ), TRUE );
3927 }
3928}
3929
3930void QFileDialog::detailViewSelectionChanged()
3931{
3932 if ( d->mode != ExistingFiles )
3933 return;
3934
3935 nameEdit->clear();
3936 QString str;
3937 QListViewItem * i = files->firstChild();
3938 d->moreFiles->blockSignals( TRUE );
3939 while( i ) {
3940 if ( d->moreFiles && isVisible() ) {
3941 QFileDialogPrivate::File *f = (QFileDialogPrivate::File *)i;
3942 if ( f->i && f->i->isSelected() != i->isSelected() )
3943 d->moreFiles->setSelected( f->i, i->isSelected() );
3944 }
3945 if ( i->isSelected() && !( (QFileDialogPrivate::File *)i )->info.isDir() )
3946 str += QString( "\"%1\" " ).arg( i->text( 0 ) );
3947 i = i->nextSibling();
3948 }
3949 d->moreFiles->blockSignals( FALSE );
3950 nameEdit->setText( str );
3951 nameEdit->setCursorPosition( str.length() );
3952 okB->setEnabled( TRUE );
3953 if ( d->preview && d->preview->isVisible() && files->currentItem() ) {
3954 QUrl u = QUrl( d->url, QFileDialogPrivate::encodeFileName( ((QFileDialogPrivate::File*)files->currentItem())->info.name() ) );
3955 updatePreviews( u );
3956 }
3957}
3958
3959void QFileDialog::listBoxSelectionChanged()
3960{
3961 if ( d->mode != ExistingFiles )
3962 return;
3963
3964 if ( d->ignoreNextRefresh ) {
3965 d->ignoreNextRefresh = FALSE;
3966 return;
3967 }
3968
3969 nameEdit->clear();
3970 QString str;
3971 QListBoxItem * i = d->moreFiles->item( 0 );
3972 QListBoxItem * j = 0;
3973 int index = 0;
3974 files->blockSignals( TRUE );
3975 while( i ) {
3976 QFileDialogPrivate::MCItem *mcitem = (QFileDialogPrivate::MCItem *)i;
3977 if ( files && isVisible() ) {
3978 if ( mcitem->i->isSelected() != mcitem->isSelected() ) {
3979 files->setSelected( mcitem->i, mcitem->isSelected() );
3980
3981 // What happens here is that we want to emit signal highlighted for
3982 // newly added items. But QListBox apparently emits selectionChanged even
3983 // when a user clicks on the same item twice. So, basically emulate the behaivor
3984 // we have in the "Details" view which only emits highlighted the first time we
3985 // click on the item. Perhaps at some point we should have a call to
3986 // updateFileNameEdit(QListViewItem) which also emits fileHighlighted() for
3987 // ExistingFiles. For better or for worse, this clones the behaivor of the
3988 // "Details" view quite well.
3989 if ( mcitem->isSelected() && i != d->lastEFSelected ) {
3990 QUrl u( d->url, QFileDialogPrivate::encodeFileName( ((QFileDialogPrivate::File*)(mcitem)->i)->info.name()) );
3991 d->lastEFSelected = i;
3992 emit fileHighlighted( u.toString(FALSE, FALSE) );
3993 }
3994 }
3995 }
3996 if ( d->moreFiles->isSelected( i )
3997 && !( (QFileDialogPrivate::File*)(mcitem)->i )->info.isDir() ) {
3998 str += QString( "\"%1\" " ).arg( i->text() );
3999 if ( j == 0 )
4000 j = i;
4001 }
4002 i = d->moreFiles->item( ++index );
4003 }
4004
4005 files->blockSignals( FALSE );
4006 nameEdit->setText( str );
4007 nameEdit->setCursorPosition( str.length() );
4008 okB->setEnabled( TRUE );
4009 if ( d->preview && d->preview->isVisible() && j ) {
4010 QUrl u = QUrl( d->url,
4011 QFileDialogPrivate::encodeFileName( ( (QFileDialogPrivate::File*)( (QFileDialogPrivate::MCItem*)j )->i )->info.name() ) );
4012 updatePreviews( u );
4013 }
4014}
4015
4016/*! \overload */
4017
4018void QFileDialog::updateFileNameEdit( QListBoxItem * newItem )
4019{
4020 if ( !newItem )
4021 return;
4022 QFileDialogPrivate::MCItem * i = (QFileDialogPrivate::MCItem *)newItem;
4023 if ( i->i ) {
4024 i->i->listView()->setSelected( i->i, i->isSelected() );
4025 updateFileNameEdit( i->i );
4026 }
4027}
4028
4029
4030/*! Updates the dialog when the file name edit changes. */
4031
4032void QFileDialog::fileNameEditDone()
4033{
4034 QUrlInfo f( d->url, nameEdit->text() );
4035 if ( mode() != QFileDialog::ExistingFiles ) {
4036 QUrlOperator u( d->url, QFileDialogPrivate::encodeFileName( nameEdit->text() ) );
4037 trySetSelection( f.isDir(), u, FALSE );
4038 if ( d->preview && d->preview->isVisible() )
4039 updatePreviews( u );
4040 }
4041}
4042
4043
4044
4045/*! This private slot reacts to double-clicks in the list view. The item that
4046was double-clicked is specified in \a newItem */
4047
4048void QFileDialog::selectDirectoryOrFile( QListViewItem * newItem )
4049{
4050
4051 *workingDirectory = d->url;
4052 detailViewMode = files->isVisible();
4053 updateLastSize(this);
4054
4055 if ( !newItem )
4056 return;
4057
4058 if ( d->url.isLocalFile() ) {
4059 QFileInfo fi( d->url.path() + newItem->text(0) );
4060#if defined(Q_WS_WIN)
4061 if ( fi.isSymLink() ) {
4062 nameEdit->setText( fi.readLink() );
4063 okClicked();
4064 return;
4065 }
4066#endif
4067 }
4068
4069 QFileDialogPrivate::File * i = (QFileDialogPrivate::File *)newItem;
4070
4071 QString oldName = nameEdit->text();
4072 if ( i->info.isDir() ) {
4073 setUrl( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName( i->info.name() ) + "/" ) );
4074 if ( isDirectoryMode( mode() ) ) {
4075 QUrlInfo f ( d->url, QString::fromLatin1( "." ) );
4076 trySetSelection( f.isDir(), d->url, TRUE );
4077 }
4078 } else if ( newItem->isSelectable() &&
4079 trySetSelection( i->info.isDir(), QUrlOperator( d->url, QFileDialogPrivate::encodeFileName( i->info.name() ) ), TRUE ) ) {
4080 if ( !isDirectoryMode( mode() ) ) {
4081 if ( mode() == ExistingFile ) {
4082 if ( QFileDialogPrivate::fileExists( d->url, nameEdit->text() ) ) {
4083 emit fileSelected( selectedFile() );
4084 accept();
4085 }
4086 } else {
4087 emit fileSelected( selectedFile() );
4088 accept();
4089 }
4090 }
4091 } else if ( isDirectoryMode( d->mode ) ) {
4092 d->currentFileName = d->url;
4093 accept();
4094 }
4095 if ( !oldName.isEmpty() && !isDirectoryMode( mode() ) )
4096 nameEdit->setText( oldName );
4097}
4098
4099
4100void QFileDialog::selectDirectoryOrFile( QListBoxItem * newItem )
4101{
4102 if ( !newItem )
4103 return;
4104
4105 QFileDialogPrivate::MCItem * i = (QFileDialogPrivate::MCItem *)newItem;
4106 if ( i->i ) {
4107 i->i->listView()->setSelected( i->i, i->isSelected() );
4108 selectDirectoryOrFile( i->i );
4109 }
4110}
4111
4112
4113void QFileDialog::popupContextMenu( QListViewItem *item, const QPoint &p,
4114 int )
4115{
4116 if ( item ) {
4117 files->setCurrentItem( item );
4118 files->setSelected( item, TRUE );
4119 }
4120
4121 PopupAction action;
4122 popupContextMenu( item ? item->text( 0 ) : QString::null, TRUE, action, p );
4123
4124 if ( action == PA_Open )
4125 selectDirectoryOrFile( item );
4126 else if ( action == PA_Rename )
4127 files->startRename( FALSE );
4128 else if ( action == PA_Delete )
4129 deleteFile( item ? item->text( 0 ) : QString::null );
4130 else if ( action == PA_Reload )
4131 rereadDir();
4132 else if ( action == PA_Hidden ) {
4133 bShowHiddenFiles = !bShowHiddenFiles;
4134 rereadDir();
4135 } else if ( action == PA_SortName ) {
4136 sortFilesBy = (int)QDir::Name;
4137 sortAscending = TRUE;
4138 resortDir();
4139 } else if ( action == PA_SortSize ) {
4140 sortFilesBy = (int)QDir::Size;
4141 sortAscending = TRUE;
4142 resortDir();
4143 } else if ( action == PA_SortDate ) {
4144 sortFilesBy = (int)QDir::Time;
4145 sortAscending = TRUE;
4146 resortDir();
4147 } else if ( action == PA_SortUnsorted ) {
4148 sortFilesBy = (int)QDir::Unsorted;
4149 sortAscending = TRUE;
4150 resortDir();
4151 }
4152
4153}
4154
4155void QFileDialog::popupContextMenu( QListBoxItem *item, const QPoint & p )
4156{
4157 PopupAction action;
4158 popupContextMenu( item ? item->text() : QString::null, FALSE, action, p );
4159
4160 if ( action == PA_Open )
4161 selectDirectoryOrFile( item );
4162 else if ( action == PA_Rename )
4163 d->moreFiles->startRename( FALSE );
4164 else if ( action == PA_Delete )
4165 deleteFile( item->text() );
4166 else if ( action == PA_Reload )
4167 rereadDir();
4168 else if ( action == PA_Hidden ) {
4169 bShowHiddenFiles = !bShowHiddenFiles;
4170 rereadDir();
4171 } else if ( action == PA_SortName ) {
4172 sortFilesBy = (int)QDir::Name;
4173 sortAscending = TRUE;
4174 resortDir();
4175 } else if ( action == PA_SortSize ) {
4176 sortFilesBy = (int)QDir::Size;
4177 sortAscending = TRUE;
4178 resortDir();
4179 } else if ( action == PA_SortDate ) {
4180 sortFilesBy = (int)QDir::Time;
4181 sortAscending = TRUE;
4182 resortDir();
4183 } else if ( action == PA_SortUnsorted ) {
4184 sortFilesBy = (int)QDir::Unsorted;
4185 sortAscending = TRUE;
4186 resortDir();
4187 }
4188}
4189
4190void QFileDialog::popupContextMenu( const QString &filename, bool,
4191 PopupAction &action, const QPoint &p )
4192{
4193 action = PA_Cancel;
4194
4195 bool glob = filename.isEmpty();
4196
4197 QPopupMenu m( 0, "file dialog context menu" );
4198 m.setCheckable( TRUE );
4199
4200 if ( !glob ) {
4201 QString okt;
4202 if ( QUrlInfo( d->url, filename ).isDir() ) {
4203 okt = tr( "&Open" );
4204 } else {
4205 if ( mode() == AnyFile )
4206 okt = tr( "&Save" );
4207 else
4208 okt = tr( "&Open" );
4209 }
4210 int ok = m.insertItem( okt );
4211
4212 m.insertSeparator();
4213 int rename = m.insertItem( tr( "&Rename" ) );
4214 int del = m.insertItem( tr( "&Delete" ) );
4215
4216 if ( filename.isEmpty() || !QUrlInfo( d->url, filename ).isWritable() ||
4217 filename == ".." ) {
4218 if ( filename.isEmpty() || !QUrlInfo( d->url, filename ).isReadable() )
4219 m.setItemEnabled( ok, FALSE );
4220 m.setItemEnabled( rename, FALSE );
4221 m.setItemEnabled( del, FALSE );
4222 }
4223
4224 m.move( p );
4225 int res = m.exec();
4226
4227 if ( res == ok )
4228 action = PA_Open;
4229 else if ( res == rename )
4230 action = PA_Rename;
4231 else if ( res == del )
4232 action = PA_Delete;
4233 } else {
4234 int reload = m.insertItem( tr( "R&eload" ) );
4235
4236 QPopupMenu m2( 0, "sort menu" );
4237
4238 int sname = m2.insertItem( tr( "Sort by &Name" ) );
4239 //int stype = m2.insertItem( tr( "Sort by &Type" ) );
4240 int ssize = m2.insertItem( tr( "Sort by &Size" ) );
4241 int sdate = m2.insertItem( tr( "Sort by &Date" ) );
4242 m2.insertSeparator();
4243 int sunsorted = m2.insertItem( tr( "&Unsorted" ) );
4244
4245 //m2.setItemEnabled( stype, FALSE );
4246
4247 if ( sortFilesBy == (int)QDir::Name )
4248 m2.setItemChecked( sname, TRUE );
4249 else if ( sortFilesBy == (int)QDir::Size )
4250 m2.setItemChecked( ssize, TRUE );
4251// else if ( sortFilesBy == 0x16 )
4252// m2.setItemChecked( stype, TRUE );
4253 else if ( sortFilesBy == (int)QDir::Time )
4254 m2.setItemChecked( sdate, TRUE );
4255 else if ( sortFilesBy == (int)QDir::Unsorted )
4256 m2.setItemChecked( sunsorted, TRUE );
4257
4258 m.insertItem( tr( "Sort" ), &m2 );
4259
4260 m.insertSeparator();
4261
4262 int hidden = m.insertItem( tr( "Show &hidden files" ) );
4263 m.setItemChecked( hidden, bShowHiddenFiles );
4264
4265 m.move( p );
4266 int res = m.exec();
4267
4268 if ( res == reload )
4269 action = PA_Reload;
4270 else if ( res == hidden )
4271 action = PA_Hidden;
4272 else if ( res == sname )
4273 action = PA_SortName;
4274// else if ( res == stype )
4275// action = PA_SortType;
4276 else if ( res == sdate )
4277 action = PA_SortDate;
4278 else if ( res == ssize )
4279 action = PA_SortSize;
4280 else if ( res == sunsorted )
4281 action = PA_SortUnsorted;
4282 }
4283
4284}
4285
4286void QFileDialog::deleteFile( const QString &filename )
4287{
4288 if ( filename.isEmpty() )
4289 return;
4290
4291 QUrlInfo fi( d->url, QFileDialogPrivate::encodeFileName( filename ) );
4292 QString t = tr( "the file" );
4293 if ( fi.isDir() )
4294 t = tr( "the directory" );
4295 if ( fi.isSymLink() )
4296 t = tr( "the symlink" );
4297
4298 if ( QMessageBox::warning( this,
4299 tr( "Delete %1" ).arg( t ),
4300 tr( "<qt>Are you sure you wish to delete %1 \"%2\"?</qt>" )
4301 .arg( t ).arg(filename),
4302 tr( "&Yes" ), tr( "&No" ), QString::null, 1 ) == 0 )
4303 d->url.remove( QFileDialogPrivate::encodeFileName( filename ) );
4304
4305}
4306
4307void QFileDialog::fileSelected( int )
4308{
4309 // unused
4310}
4311
4312void QFileDialog::fileHighlighted( int )
4313{
4314 // unused
4315}
4316
4317void QFileDialog::dirSelected( int )
4318{
4319 // unused
4320}
4321
4322void QFileDialog::pathSelected( int )
4323{
4324 // unused
4325}
4326
4327
4328void QFileDialog::cdUpClicked()
4329{
4330 QString oldName = nameEdit->text();
4331 setUrl( QUrlOperator( d->url, ".." ) );
4332 if ( !oldName.isEmpty() )
4333 nameEdit->setText( oldName );
4334}
4335
4336void QFileDialog::newFolderClicked()
4337{
4338 QString foldername( tr( "New Folder 1" ) );
4339 int i = 0;
4340 QStringList lst;
4341 QListViewItemIterator it( files );
4342 for ( ; it.current(); ++it )
4343 if ( it.current()->text( 0 ).contains( tr( "New Folder" ) ) )
4344 lst.append( it.current()->text( 0 ) );
4345
4346 if ( !lst.count() == 0 )
4347 while ( lst.contains( foldername ) )
4348 foldername = tr( "New Folder %1" ).arg( ++i );
4349
4350 d->url.mkdir( foldername );
4351}
4352
4353void QFileDialog::createdDirectory( const QUrlInfo &info, QNetworkOperation * )
4354{
4355 resortDir();
4356 if ( d->moreFiles->isVisible() ) {
4357 for ( uint i = 0; i < d->moreFiles->count(); ++i ) {
4358 if ( d->moreFiles->text( i ) == info.name() ) {
4359 d->moreFiles->setCurrentItem( i );
4360 d->moreFiles->startRename( FALSE );
4361 break;
4362 }
4363 }
4364 } else {
4365 QListViewItem *item = files->firstChild();
4366 while ( item ) {
4367 if ( item->text( 0 ) == info.name() ) {
4368 files->setSelected( item, TRUE );
4369 files->setCurrentItem( item );
4370 files->startRename( FALSE );
4371 break;
4372 }
4373 item = item->nextSibling();
4374 }
4375 }
4376}
4377
4378
4379/*!
4380 This is a convenience static function that will return an existing directory
4381 selected by the user.
4382
4383 \code
4384 QString s = QFileDialog::getExistingDirectory(
4385 "/home",
4386 this,
4387 "get existing directory",
4388 "Choose a directory",
4389 TRUE );
4390 \endcode
4391
4392 This function creates a modal file dialog called \a name, with
4393 parent, \a parent. If parent is not 0, the dialog will be shown
4394 centered over the parent.
4395
4396 The dialog's working directory is set to \a dir, and the caption is
4397 set to \a caption. Either of these may be QString::null in which case
4398 the current directory and a default caption will be used respectively.
4399
4400 If \a dirOnly is TRUE, then only directories will be shown in
4401 the file dialog; otherwise both directories and files will be shown.
4402
4403 Under Unix/X11, the normal behavior of the file dialog is to resolve
4404 and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
4405 the file dialog will change to /var/tmp after entering /usr/tmp.
4406 If \a resolveSymlinks is FALSE, the file dialog will treat
4407 symlinks as regular directories.
4408
4409 Note that on Windows the dialog will spin a blocking modal event loop
4410 that will not dispatch any QTimers and if parent is not 0 then it will
4411 position the dialog just under the parent's titlebar.
4412
4413 \sa getOpenFileName(), getOpenFileNames(), getSaveFileName()
4414*/
4415
4416QString QFileDialog::getExistingDirectory( const QString & dir,
4417 QWidget *parent,
4418 const char* name,
4419 const QString& caption,
4420 bool dirOnly,
4421 bool resolveSymlinks)
4422{
4423 bool save_qt_resolve_symlinks = qt_resolve_symlinks;
4424 qt_resolve_symlinks = resolveSymlinks;
4425
4426 makeVariables();
4427 QString wd;
4428 if ( workingDirectory )
4429 wd = *workingDirectory;
4430
4431#if defined(Q_WS_WIN)
4432 QString initialDir;
4433 if ( !dir.isEmpty() ) {
4434 QUrlOperator u( dir );
4435 if ( QFileInfo( u.path() ).isDir() )
4436 initialDir = dir;
4437 } else
4438 initialDir = QString::null;
4439 if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle && dirOnly )
4440 return winGetExistingDirectory( initialDir, parent, name, caption );
4441#endif
4442#if defined(Q_WS_MAC)
4443 if( qt_use_native_dialogs && ( qApp->style().inherits(QMAC_DEFAULT_STYLE) || qApp->style().inherits("QMacStyle") ) )
4444 return macGetOpenFileNames("", 0, parent, name, caption, NULL, FALSE, TRUE).first();
4445#endif
4446
4447 QFileDialog *dlg = new QFileDialog( parent, name ? name : "qt_filedlg_ged", TRUE );
4448
4449 Q_CHECK_PTR( dlg );
4450#ifndef QT_NO_WIDGET_TOPEXTRA
4451 if ( !caption.isNull() )
4452 dlg->setCaption( caption );
4453 else
4454 dlg->setCaption( QFileDialog::tr("Find Directory") );
4455#endif
4456
4457 dlg->setMode( dirOnly ? DirectoryOnly : Directory );
4458
4459 dlg->d->types->clear();
4460 dlg->d->types->insertItem( QFileDialog::tr("Directories") );
4461 dlg->d->types->setEnabled( FALSE );
4462
4463 QString dir_( dir );
4464 dir_ = dir_.simplifyWhiteSpace();
4465 if ( dir_.isEmpty() && !wd.isEmpty() )
4466 dir_ = wd;
4467 QUrlOperator u( dir_ );
4468 if ( u.isLocalFile() ) {
4469 if ( !dir_.isEmpty() ) {
4470 QFileInfo f( u.path() );
4471 if ( f.exists() )
4472 if ( f.isDir() ) {
4473 dlg->setDir( dir_ );
4474 wd = dir_;
4475 }
4476 } else if ( !wd.isEmpty() ) {
4477 QUrl tempUrl( wd );
4478 QFileInfo f( tempUrl.path() );
4479 if ( f.isDir() ) {
4480 dlg->setDir( wd );
4481 }
4482 } else {
4483 QString theDir = dir_;
4484 if ( theDir.isEmpty() ) {
4485 theDir = QDir::currentDirPath();
4486 } if ( !theDir.isEmpty() ) {
4487 QUrl tempUrl( theDir );
4488 QFileInfo f( tempUrl.path() );
4489 if ( f.isDir() ) {
4490 wd = theDir;
4491 dlg->setDir( theDir );
4492 }
4493 }
4494 }
4495 } else {
4496 dlg->setUrl( dir_ );
4497 }
4498
4499 QString result;
4500 dlg->setSelection( dlg->d->url.toString() );
4501
4502 if ( dlg->exec() == QDialog::Accepted ) {
4503 result = dlg->selectedFile();
4504 wd = result;
4505 }
4506 delete dlg;
4507
4508 if ( !result.isEmpty() && result.right( 1 ) != "/" )
4509 result += "/";
4510
4511 qt_resolve_symlinks = save_qt_resolve_symlinks;
4512
4513 return result;
4514}
4515
4516
4517/*!
4518 \property QFileDialog::mode
4519 \brief the file dialog's mode
4520
4521 The default mode is \c ExistingFile.
4522*/
4523
4524void QFileDialog::setMode( Mode newMode )
4525{
4526 if ( d->mode != newMode ) {
4527 d->mode = newMode;
4528 QString sel = d->currentFileName;
4529 int maxnamelen = 255; // _POSIX_MAX_PATH
4530 if ( isDirectoryMode( newMode ) ) {
4531 files->setSelectionMode( QListView::Single );
4532 d->moreFiles->setSelectionMode( QListBox::Single );
4533 if ( sel.isNull() )
4534 sel = QString::fromLatin1(".");
4535 d->types->setEnabled( FALSE );
4536 } else if ( newMode == ExistingFiles ) {
4537 maxnamelen = INT_MAX;
4538 files->setSelectionMode( QListView::Extended );
4539 d->moreFiles->setSelectionMode( QListBox::Extended );
4540 d->types->setEnabled( TRUE );
4541 } else {
4542 files->setSelectionMode( QListView::Single );
4543 d->moreFiles->setSelectionMode( QListBox::Single );
4544 d->types->setEnabled( TRUE );
4545 }
4546 nameEdit->setMaxLength(maxnamelen);
4547 rereadDir();
4548 QUrlInfo f( d->url, "." );
4549 trySetSelection( f.isDir(), d->url, FALSE );
4550 }
4551
4552 QString okt;
4553 bool changeFilters = FALSE;
4554 if ( mode() == AnyFile ) {
4555 okt = tr("&Save");
4556 d->fileL->setText( tr("File &name:") );
4557 if ( d->types->count() == 1 ) {
4558 d->types->setCurrentItem( 0 );
4559 if ( d->types->currentText() == "Directories" ) {
4560 changeFilters = TRUE;
4561 }
4562 }
4563 }
4564 else if ( mode() == Directory || mode() == DirectoryOnly ) {
4565 okt = tr("&OK");
4566 d->fileL->setText( tr("Directory:") );
4567 d->types->clear();
4568 d->types->insertItem( tr("Directories") );
4569 }
4570 else {
4571 okt = tr("&Open");
4572 d->fileL->setText( tr("File &name:") );
4573 if ( d->types->count() == 1 ) {
4574 d->types->setCurrentItem( 0 );
4575 if ( d->types->currentText() == "Directories" ) {
4576 changeFilters = TRUE;
4577 }
4578 }
4579 }
4580
4581 if ( changeFilters ) {
4582 d->types->clear();
4583 d->types->insertItem( tr("All Files (*)") );
4584 }
4585
4586 okB->setText( okt );
4587}
4588
4589QFileDialog::Mode QFileDialog::mode() const
4590{
4591 return d->mode;
4592}
4593
4594/*! \reimp
4595*/
4596
4597void QFileDialog::done( int i )
4598{
4599 if ( i == QDialog::Accepted && (d->mode == ExistingFile || d->mode == ExistingFiles) ) {
4600 QStringList selection = selectedFiles();
4601 for ( uint f = 0; f < selection.count(); f++ ) {
4602 QString file = selection[f];
4603 if ( file.isNull() )
4604 continue;
4605 if ( d->url.isLocalFile() && !QFile::exists( file ) ) {
4606 QMessageBox::information( this, tr("Error"),
4607 tr("%1\nFile not found.\nCheck path and filename.").arg( file ) );
4608 return;
4609 }
4610 }
4611 }
4612 QDialog::done( i );
4613}
4614
4615/*!
4616 \property QFileDialog::viewMode
4617
4618 \brief the file dialog's view mode
4619
4620 If you set the view mode to be \e Detail (the default), then you
4621 will see the file's details, such as the size of the file and the
4622 date the file was last modified in addition to the file's name.
4623
4624 If you set the view mode to be \e List, then you will just
4625 see a list of the files and folders.
4626
4627 See \l QFileDialog::ViewMode
4628*/
4629
4630
4631QFileDialog::ViewMode QFileDialog::viewMode() const
4632{
4633 if ( detailViewMode )
4634 return Detail;
4635 else
4636 return List;
4637}
4638
4639void QFileDialog::setViewMode( ViewMode m )
4640{
4641 if ( m == Detail ) {
4642 detailViewMode = TRUE;
4643 d->stack->raiseWidget( files );
4644 d->detailView->setOn( TRUE );
4645 d->mcView->setOn( FALSE );
4646 } else if ( m == List ) {
4647 detailViewMode = FALSE;
4648 d->stack->raiseWidget( d->moreFiles );
4649 d->detailView->setOn( FALSE );
4650 d->mcView->setOn( TRUE );
4651 }
4652}
4653
4654
4655/*!
4656 \property QFileDialog::previewMode
4657
4658 \brief the preview mode for the file dialog
4659
4660 If you set the mode to be a mode other than \e NoPreview, you must
4661 use setInfoPreview() or setContentsPreview() to set the dialog's
4662 preview widget to your preview widget and enable the preview
4663 widget(s) with setInfoPreviewEnabled() or
4664 setContentsPreviewEnabled().
4665
4666 \sa infoPreview, contentsPreview, viewMode
4667*/
4668
4669void QFileDialog::setPreviewMode( PreviewMode m )
4670{
4671 if ( m == NoPreview ) {
4672 d->previewInfo->setOn( FALSE );
4673 d->previewContents->setOn( FALSE );
4674 } else if ( m == Info && d->infoPreview ) {
4675 d->previewInfo->setOn( TRUE );
4676 d->previewContents->setOn( FALSE );
4677 changeMode( d->modeButtons->id( d->previewInfo ) );
4678 } else if ( m == Contents && d->contentsPreview ) {
4679 d->previewInfo->setOn( FALSE );
4680 d->previewContents->setOn( TRUE );
4681 changeMode( d->modeButtons->id( d->previewContents ) );
4682 }
4683}
4684QFileDialog::PreviewMode QFileDialog::previewMode() const
4685{
4686 if ( d->infoPreview && d->infoPreviewWidget->isVisible() )
4687 return Info;
4688 else if ( d->contentsPreview && d->contentsPreviewWidget->isVisible() )
4689 return Contents;
4690
4691 return NoPreview;
4692}
4693
4694
4695/*!
4696 Adds the specified widgets to the bottom of the file dialog. The
4697 label \a l is placed underneath the "file name" and the "file types"
4698 labels. The widget \a w is placed underneath the file types combobox.
4699 The button \a b is placed underneath the Cancel pushbutton.
4700
4701 \code
4702 MyFileDialog::MyFileDialog( QWidget* parent, const char* name ) :
4703 QFileDialog( parent, name )
4704 {
4705 QLabel* label = new QLabel( "Added widgets", this );
4706 QLineEdit* lineedit = new QLineEdit( this );
4707 QPushButton* pushbutton = new QPushButton( this );
4708
4709 addWidgets( label, lineedit, pushbutton );
4710 }
4711 \endcode
4712
4713 If you don't want to have one of the widgets added, pass 0 in that
4714 widget's position.
4715
4716 Every time you call this function, a new row of widgets will be added
4717 to the bottom of the file dialog.
4718
4719 \sa addToolButton(), addLeftWidget(), addRightWidget()
4720*/
4721
4722void QFileDialog::addWidgets( QLabel * l, QWidget * w, QPushButton * b )
4723{
4724 if ( !l && !w && !b )
4725 return;
4726
4727 d->geometryDirty = TRUE;
4728
4729 QHBoxLayout *lay = new QHBoxLayout();
4730 d->extraWidgetsLayouts.append( lay );
4731 d->topLevelLayout->addLayout( lay );
4732
4733 if ( !l )
4734 l = new QLabel( this, "qt_intern_lbl" );
4735 d->extraLabels.append( l );
4736 lay->addWidget( l );
4737
4738 if ( !w )
4739 w = new QWidget( this, "qt_intern_widget" );
4740 d->extraWidgets.append( w );
4741 lay->addWidget( w );
4742 lay->addSpacing( 15 );
4743
4744 if ( b ) {
4745 d->extraButtons.append( b );
4746 lay->addWidget( b );
4747 } else {
4748 QWidget *wid = new QWidget( this, "qt_extrabuttons_widget" );
4749 d->extraButtons.append( wid );
4750 lay->addWidget( wid );
4751 }
4752
4753 updateGeometries();
4754}
4755
4756/*!
4757 Adds the tool button \a b to the row of tool buttons at the top of the
4758 file dialog. The button is appended to the right of
4759 this row. If \a separator is TRUE, a small space is inserted between the
4760 last button of the row and the new button \a b.
4761
4762 \sa addWidgets(), addLeftWidget(), addRightWidget()
4763*/
4764
4765void QFileDialog::addToolButton( QButton *b, bool separator )
4766{
4767 if ( !b || !d->buttonLayout )
4768 return;
4769
4770 d->geometryDirty = TRUE;
4771
4772 d->toolButtons.append( b );
4773 if ( separator )
4774 d->buttonLayout->addSpacing( 8 );
4775 d->buttonLayout->addWidget( b );
4776
4777 updateGeometries();
4778}
4779
4780/*!
4781 Adds the widget \a w to the left-hand side of the file dialog.
4782
4783 \sa addRightWidget(), addWidgets(), addToolButton()
4784*/
4785
4786void QFileDialog::addLeftWidget( QWidget *w )
4787{
4788 if ( !w )
4789 return;
4790 d->geometryDirty = TRUE;
4791
4792 d->leftLayout->addWidget( w );
4793 d->leftLayout->addSpacing( 5 );
4794
4795 updateGeometries();
4796}
4797
4798/*!
4799 Adds the widget \a w to the right-hand side of the file dialog.
4800
4801 \sa addLeftWidget(), addWidgets(), addToolButton()
4802*/
4803
4804void QFileDialog::addRightWidget( QWidget *w )
4805{
4806 if ( !w )
4807 return;
4808 d->geometryDirty = TRUE;
4809
4810 d->rightLayout->addSpacing( 5 );
4811 d->rightLayout->addWidget( w );
4812
4813 updateGeometries();
4814}
4815
4816/*! \reimp */
4817
4818void QFileDialog::keyPressEvent( QKeyEvent * ke )
4819{
4820 if ( !d->ignoreNextKeyPress &&
4821 ke && ( ke->key() == Key_Enter ||
4822 ke->key() == Key_Return ) ) {
4823 ke->ignore();
4824 if ( d->paths->hasFocus() ) {
4825 ke->accept();
4826 if ( d->url == QUrl(d->paths->currentText()) )
4827 nameEdit->setFocus();
4828 } else if ( d->types->hasFocus() ) {
4829 ke->accept();
4830 // ### is there a suitable condition for this? only valid
4831 // wildcards?
4832 nameEdit->setFocus();
4833 } else if ( nameEdit->hasFocus() ) {
4834 if ( d->currentFileName.isNull() ) {
4835 // maybe change directory
4836 QUrlInfo i( d->url, nameEdit->text() );
4837 if ( i.isDir() ) {
4838 nameEdit->setText( QString::fromLatin1("") );
4839 setDir( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(i.name()) ) );
4840 }
4841 ke->accept();
4842 } else if ( mode() == ExistingFiles ) {
4843 QUrlInfo i( d->url, nameEdit->text() );
4844 if ( i.isFile() ) {
4845 QListViewItem * i = files->firstChild();
4846 while ( i && nameEdit->text() != i->text( 0 ) )
4847 i = i->nextSibling();
4848 if ( i )
4849 files->setSelected( i, TRUE );
4850 else
4851 ke->accept(); // strangely, means to ignore that event
4852 }
4853 }
4854 } else if ( files->hasFocus() || d->moreFiles->hasFocus() ) {
4855 ke->accept();
4856 }
4857 } else if ( ke->key() == Key_Escape ) {
4858 ke->ignore();
4859 }
4860
4861 d->ignoreNextKeyPress = FALSE;
4862
4863 if ( !ke->isAccepted() ) {
4864 QDialog::keyPressEvent( ke );
4865 }
4866}
4867
4868
4869/*! \class QFileIconProvider qfiledialog.h
4870
4871 \brief The QFileIconProvider class provides icons for QFileDialog to
4872 use.
4873
4874 \ingroup misc
4875
4876 By default QFileIconProvider is not used, but any application or
4877 library can subclass it, reimplement pixmap() to return a suitable
4878 icon, and make all QFileDialog objects use it by calling the static
4879 function QFileDialog::setIconProvider().
4880
4881 It is advisable to make all the icons that QFileIconProvider returns be
4882 the same size or at least the same width. This makes the list view
4883 look much better.
4884
4885 \sa QFileDialog
4886*/
4887
4888
4889/*! Constructs an empty file icon provider called \a name, with the
4890 parent \a parent.
4891*/
4892
4893QFileIconProvider::QFileIconProvider( QObject * parent, const char* name )
4894 : QObject( parent, name )
4895{
4896 // nothing necessary
4897}
4898
4899
4900/*!
4901 Returns a pointer to a pixmap that should be used to
4902 signify the file with the information \a info.
4903
4904 If pixmap() returns 0, QFileDialog draws the default pixmap.
4905
4906 The default implementation returns particular icons for files, directories,
4907 link-files and link-directories. It returns a blank "icon" for other types.
4908
4909 If you return a pixmap here, it should measure 16x16 pixels.
4910*/
4911
4912const QPixmap * QFileIconProvider::pixmap( const QFileInfo & info )
4913{
4914 if ( info.isSymLink() ) {
4915 if ( info.isFile() )
4916 return symLinkFileIcon;
4917 else
4918 return symLinkDirIcon;
4919 } else if ( info.isDir() ) {
4920 return closedFolderIcon;
4921 } else if ( info.isFile() ) {
4922 return fileIcon;
4923 } else {
4924 return fifteenTransparentPixels;
4925 }
4926}
4927
4928/*!
4929 Sets the QFileIconProvider used by the file dialog to \a provider.
4930
4931 The default is that there is no QFileIconProvider and QFileDialog
4932 just draws a folder icon next to each directory and nothing next
4933 to files.
4934
4935 \sa QFileIconProvider, iconProvider()
4936*/
4937
4938void QFileDialog::setIconProvider( QFileIconProvider * provider )
4939{
4940 fileIconProvider = provider;
4941}
4942
4943
4944/*!
4945 Returns a pointer to the icon provider currently set on the file dialog.
4946 By default there is no icon provider, and this function returns 0.
4947
4948 \sa setIconProvider(), QFileIconProvider
4949*/
4950
4951QFileIconProvider * QFileDialog::iconProvider()
4952{
4953 return fileIconProvider;
4954}
4955
4956
4957#if defined(Q_WS_WIN)
4958
4959// ### FIXME: this code is duplicated in qdns.cpp
4960static QString getWindowsRegString( HKEY key, const QString &subKey )
4961{
4962 QString s;
4963 QT_WA( {
4964 char buf[1024];
4965 DWORD bsz = sizeof(buf);
4966 int r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz );
4967 if ( r == ERROR_SUCCESS ) {
4968 s = QString::fromUcs2( (unsigned short *)buf );
4969 } else if ( r == ERROR_MORE_DATA ) {
4970 char *ptr = new char[bsz+1];
4971 r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz );
4972 if ( r == ERROR_SUCCESS )
4973 s = ptr;
4974 delete [] ptr;
4975 }
4976 } , {
4977 char buf[512];
4978 DWORD bsz = sizeof(buf);
4979 int r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz );
4980 if ( r == ERROR_SUCCESS ) {
4981 s = buf;
4982 } else if ( r == ERROR_MORE_DATA ) {
4983 char *ptr = new char[bsz+1];
4984 r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz );
4985 if ( r == ERROR_SUCCESS )
4986 s = ptr;
4987 delete [] ptr;
4988 }
4989 } );
4990 return s;
4991}
4992
4993static void initPixmap( QPixmap &pm )
4994{
4995 pm.fill( Qt::white );
4996}
4997
4998
4999QWindowsIconProvider::QWindowsIconProvider( QObject *parent, const char *name )
5000 : QFileIconProvider( parent, name )
5001{
5002 pixw = GetSystemMetrics( SM_CXSMICON );
5003 pixh = GetSystemMetrics( SM_CYSMICON );
5004
5005 HKEY k;
5006 HICON si;
5007 int r;
5008 QString s;
5009 UINT res;
5010
5011 // ---------- get default folder pixmap
5012 const wchar_t iconFolder[] = L"folder\\DefaultIcon"; // workaround for Borland
5013 QT_WA( {
5014 r = RegOpenKeyEx( HKEY_CLASSES_ROOT,
5015 iconFolder,
5016 0, KEY_READ, &k );
5017 } , {
5018 r = RegOpenKeyExA( HKEY_CLASSES_ROOT,
5019 "folder\\DefaultIcon",
5020 0, KEY_READ, &k );
5021 } );
5022 resolveLibs();
5023 if ( r == ERROR_SUCCESS ) {
5024 s = getWindowsRegString( k, QString::null );
5025 RegCloseKey( k );
5026
5027 QStringList lst = QStringList::split( ",", s );
5028
5029#ifndef Q_OS_TEMP
5030 QT_WA( {
5031 res = ptrExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(),
5032 lst[ 1 ].simplifyWhiteSpace().toInt(),
5033 0, &si, 1 );
5034 } , {
5035 res = ExtractIconExA( lst[ 0 ].simplifyWhiteSpace().local8Bit(),
5036 lst[ 1 ].simplifyWhiteSpace().toInt(),
5037 0, &si, 1 );
5038 } );
5039#else
5040 res = (UINT)ExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(),
5041 lst[ 1 ].simplifyWhiteSpace().toInt(),
5042 0, &si, 1 );
5043#endif
5044
5045 if ( res ) {
5046 defaultFolder.resize( pixw, pixh );
5047 initPixmap( defaultFolder );
5048 QPainter p( &defaultFolder );
5049 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5050 p.end();
5051 defaultFolder.setMask( defaultFolder.createHeuristicMask() );
5052 *closedFolderIcon = defaultFolder;
5053 DestroyIcon( si );
5054 } else {
5055 defaultFolder = *closedFolderIcon;
5056 }
5057 } else {
5058 RegCloseKey( k );
5059 }
5060
5061 //------------------------------- get default file pixmap
5062#ifndef Q_OS_TEMP
5063 QT_WA( {
5064 res = ptrExtractIconEx( L"shell32.dll",
5065 0, 0, &si, 1 );
5066 } , {
5067 res = ExtractIconExA( "shell32.dll",
5068 0, 0, &si, 1 );
5069 } );
5070#else
5071 res = (UINT)ExtractIconEx( L"shell32.dll",
5072 0, 0, &si, 1 );
5073#endif
5074
5075 if ( res ) {
5076 defaultFile.resize( pixw, pixh );
5077 initPixmap( defaultFile );
5078 QPainter p( &defaultFile );
5079 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5080 p.end();
5081 defaultFile.setMask( defaultFile.createHeuristicMask() );
5082 *fileIcon = defaultFile;
5083 DestroyIcon( si );
5084 } else {
5085 defaultFile = *fileIcon;
5086 }
5087
5088 //------------------------------- get default exe pixmap
5089#ifndef Q_OS_TEMP
5090 QT_WA( {
5091 res = ptrExtractIconEx( L"shell32.dll",
5092 2, 0, &si, 1 );
5093 } , {
5094 res = ExtractIconExA( "shell32.dll",
5095 2, 0, &si, 1 );
5096 } );
5097#else
5098 res = (UINT)ExtractIconEx( L"ceshell.dll",
5099 10, 0, &si, 1 );
5100#endif
5101
5102 if ( res ) {
5103 defaultExe.resize( pixw, pixh );
5104 initPixmap( defaultExe );
5105 QPainter p( &defaultExe );
5106 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5107 p.end();
5108 defaultExe.setMask( defaultExe.createHeuristicMask() );
5109 DestroyIcon( si );
5110 } else {
5111 defaultExe = *fileIcon;
5112 }
5113}
5114
5115QWindowsIconProvider::~QWindowsIconProvider()
5116{
5117 if ( this == fileIconProvider )
5118 fileIconProvider = 0;
5119}
5120
5121const QPixmap * QWindowsIconProvider::pixmap( const QFileInfo &fi )
5122{
5123 QString ext = fi.extension( FALSE ).upper();
5124 QString key = ext;
5125 ext.prepend( "." );
5126 QMap< QString, QPixmap >::Iterator it;
5127
5128 if ( fi.isDir() ) {
5129 return &defaultFolder;
5130 } else if ( ext.lower() != ".exe" ) {
5131 it = cache.find( key );
5132 if ( it != cache.end() )
5133 return &( *it );
5134
5135 HKEY k, k2;
5136 int r;
5137 QT_WA( {
5138 r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)ext.ucs2(),
5139 0, KEY_READ, &k );
5140 } , {
5141 r = RegOpenKeyExA( HKEY_CLASSES_ROOT, ext.local8Bit(),
5142 0, KEY_READ, &k );
5143 } );
5144 QString s;
5145 if ( r == ERROR_SUCCESS ) {
5146 s = getWindowsRegString( k, QString::null );
5147 } else {
5148 cache[ key ] = defaultFile;
5149 RegCloseKey( k );
5150 return &defaultFile;
5151 }
5152 RegCloseKey( k );
5153
5154 QT_WA( {
5155 r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)QString( s + "\\DefaultIcon" ).ucs2(),
5156 0, KEY_READ, &k2 );
5157 } , {
5158 r = RegOpenKeyExA( HKEY_CLASSES_ROOT, QString( s + "\\DefaultIcon" ).local8Bit() ,
5159 0, KEY_READ, &k2 );
5160 } );
5161 if ( r == ERROR_SUCCESS ) {
5162 s = getWindowsRegString( k2, QString::null );
5163 } else {
5164 cache[ key ] = defaultFile;
5165 RegCloseKey( k2 );
5166 return &defaultFile;
5167 }
5168 RegCloseKey( k2 );
5169
5170 QStringList lst = QStringList::split( ",", s );
5171
5172 HICON si;
5173 UINT res = 0;
5174 QString filepath = lst[ 0 ].stripWhiteSpace();
5175 if ( !filepath.isEmpty() ) {
5176 if ( filepath.find("%1") != -1 ) {
5177 filepath = filepath.arg( fi.filePath() );
5178 if ( ext.lower() == ".dll" ) {
5179 pix = defaultFile;
5180 return &pix;
5181 }
5182 }
5183 if ( filepath[0] == '"' && filepath[(int)filepath.length()-1] == '"' )
5184 filepath = filepath.mid( 1, filepath.length()-2 );
5185
5186 resolveLibs();
5187#ifndef Q_OS_TEMP
5188 QT_WA( {
5189 res = ptrExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(),
5190 0, &si, 1 );
5191 } , {
5192 res = ExtractIconExA( filepath.local8Bit(), lst[ 1 ].stripWhiteSpace().toInt(),
5193 0, &si, 1 );
5194 } );
5195#else
5196 res = (UINT)ExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(),
5197 0, &si, 1 );
5198#endif
5199 }
5200
5201 if ( res ) {
5202 pix.resize( pixw, pixh );
5203 initPixmap( pix );
5204 QPainter p( &pix );
5205 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5206 p.end();
5207 pix.setMask( pix.createHeuristicMask() );
5208 DestroyIcon( si );
5209 } else {
5210 pix = defaultFile;
5211 }
5212
5213 cache[ key ] = pix;
5214 return &pix;
5215 } else {
5216 HICON si;
5217 UINT res = 0;
5218 if ( !fi.absFilePath().isEmpty() ) {
5219#ifndef Q_OS_TEMP
5220 QT_WA( {
5221 res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1,
5222 0, 0, 1 );
5223 } , {
5224 res = ExtractIconExA( fi.absFilePath().local8Bit(), -1,
5225 0, 0, 1 );
5226 } );
5227
5228 if ( res ) {
5229 QT_WA( {
5230 res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1,
5231 0, &si, 1 );
5232 } , {
5233 res = ExtractIconExA( fi.absFilePath().local8Bit(), res - 1,
5234 0, &si, 1 );
5235 } );
5236 }
5237#else
5238 res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1,
5239 0, 0, 1 );
5240 if ( res )
5241 res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1,
5242 0, &si, 1 );
5243#endif
5244
5245 }
5246
5247 if ( res ) {
5248 pix.resize( pixw, pixh );
5249 initPixmap( pix );
5250 QPainter p( &pix );
5251 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5252 p.end();
5253 pix.setMask( pix.createHeuristicMask() );
5254 DestroyIcon( si );
5255 } else {
5256 pix = defaultExe;
5257 }
5258
5259 return &pix;
5260 }
5261
5262 // can't happen!
5263 return 0;
5264}
5265#endif
5266
5267
5268
5269/*!
5270 \reimp
5271*/
5272bool QFileDialog::eventFilter( QObject * o, QEvent * e )
5273{
5274 if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F5 ) {
5275 rereadDir();
5276 ((QKeyEvent *)e)->accept();
5277 return TRUE;
5278 } else if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F2 &&
5279 ( o == files || o == files->viewport() ) ) {
5280 if ( files->isVisible() && files->currentItem() ) {
5281 if ( QUrlInfo( d->url, "." ).isWritable() && files->currentItem()->text( 0 ) != ".." ) {
5282 files->renameItem = files->currentItem();
5283 files->startRename( TRUE );
5284 }
5285 }
5286 ((QKeyEvent *)e)->accept();
5287 return TRUE;
5288 } else if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F2 &&
5289 ( o == d->moreFiles || o == d->moreFiles->viewport() ) ) {
5290 if ( d->moreFiles->isVisible() && d->moreFiles->currentItem() != -1 ) {
5291 if ( QUrlInfo( d->url, "." ).isWritable() &&
5292 d->moreFiles->item( d->moreFiles->currentItem() )->text() != ".." ) {
5293 d->moreFiles->renameItem = d->moreFiles->item( d->moreFiles->currentItem() );
5294 d->moreFiles->startRename( TRUE );
5295 }
5296 }
5297 ((QKeyEvent *)e)->accept();
5298 return TRUE;
5299 } else if ( e->type() == QEvent::KeyPress && d->moreFiles->renaming ) {
5300 d->moreFiles->lined->setFocus();
5301 QApplication::sendEvent( d->moreFiles->lined, e );
5302 ((QKeyEvent *)e)->accept();
5303 return TRUE;
5304 } else if ( e->type() == QEvent::KeyPress && files->renaming ) {
5305 files->lined->setFocus();
5306 QApplication::sendEvent( files->lined, e );
5307 ((QKeyEvent *)e)->accept();
5308 return TRUE;
5309 } else if ( e->type() == QEvent::KeyPress &&
5310 ((QKeyEvent *)e)->key() == Key_Backspace &&
5311 ( o == files ||
5312 o == d->moreFiles ||
5313 o == files->viewport() ||
5314 o == d->moreFiles->viewport() ) ) {
5315 cdUpClicked();
5316 ((QKeyEvent *)e)->accept();
5317 return TRUE;
5318 } else if ( e->type() == QEvent::KeyPress &&
5319 ((QKeyEvent *)e)->key() == Key_Delete &&
5320 ( o == files ||
5321 o == files->viewport() ) ) {
5322 if ( files->currentItem() )
5323 deleteFile( files->currentItem()->text( 0 ) );
5324 ((QKeyEvent *)e)->accept();
5325 return TRUE;
5326 } else if ( e->type() == QEvent::KeyPress &&
5327 ((QKeyEvent *)e)->key() == Key_Delete &&
5328 ( o == d->moreFiles ||
5329 o == d->moreFiles->viewport() ) ) {
5330 int c = d->moreFiles->currentItem();
5331 if ( c >= 0 )
5332 deleteFile( d->moreFiles->item( c )->text() );
5333 ((QKeyEvent *)e)->accept();
5334 return TRUE;
5335 } else if ( o == files && e->type() == QEvent::FocusOut && files->currentItem() ) {
5336 } else if ( o == files && e->type() == QEvent::KeyPress ) {
5337 QTimer::singleShot( 0, this, SLOT(fixupNameEdit()) );
5338 } else if ( o == nameEdit && e->type() == QEvent::KeyPress && d->mode != AnyFile ) {
5339 if ( ( nameEdit->cursorPosition() == (int)nameEdit->text().length() || nameEdit->hasSelectedText() ) &&
5340 isprint(((QKeyEvent *)e)->ascii()) ) {
5341#if defined(Q_WS_WIN)
5342 QString nt( nameEdit->text().lower() );
5343#else
5344 QString nt( nameEdit->text() );
5345#endif
5346 nt.truncate( nameEdit->cursorPosition() );
5347 nt += (char)(((QKeyEvent *)e)->ascii());
5348 QListViewItem * i = files->firstChild();
5349#if defined(Q_WS_WIN)
5350 while( i && i->text( 0 ).left(nt.length()).lower() != nt )
5351#else
5352 while( i && i->text( 0 ).left(nt.length()) != nt )
5353#endif
5354 i = i->nextSibling();
5355 if ( i ) {
5356 nt = i->text( 0 );
5357 int cp = nameEdit->cursorPosition()+1;
5358 nameEdit->validateAndSet( nt, cp, cp, nt.length() );
5359 return TRUE;
5360 }
5361 }
5362 } else if ( o == nameEdit && e->type() == QEvent::FocusIn ) {
5363 fileNameEditDone();
5364 } else if ( d->moreFiles->renaming && o != d->moreFiles->lined && e->type() == QEvent::FocusIn ) {
5365 d->moreFiles->lined->setFocus();
5366 return TRUE;
5367 } else if ( files->renaming && o != files->lined && e->type() == QEvent::FocusIn ) {
5368 files->lined->setFocus();
5369 return TRUE;
5370 } else if ( ( o == d->moreFiles || o == d->moreFiles->viewport() ) &&
5371 e->type() == QEvent::FocusIn ) {
5372 if ( o == d->moreFiles->viewport() && !d->moreFiles->viewport()->hasFocus() ||
5373 o == d->moreFiles && !d->moreFiles->hasFocus() )
5374 ((QWidget*)o)->setFocus();
5375 return FALSE;
5376 }
5377
5378 return QDialog::eventFilter( o, e );
5379}
5380
5381/*!
5382 Sets the filters used in the file dialog to \a filters. Each group
5383 of filters must be separated by \c{;;} (\e two semi-colons).
5384
5385 \code
5386 QString types("Image files (*.png *.xpm *.jpg);;"
5387 "Text files (*.txt);;"
5388 "Any files (*)");
5389 QFileDialog fd = new QFileDialog( this );
5390 fd->setFilters( types );
5391 fd->show();
5392 \endcode
5393
5394*/
5395
5396void QFileDialog::setFilters( const QString &filters )
5397{
5398 QStringList lst = makeFiltersList( filters );
5399 setFilters( lst );
5400}
5401
5402/*!
5403 \overload
5404
5405 \a types must be a null-terminated list of strings.
5406
5407*/
5408
5409void QFileDialog::setFilters( const char ** types )
5410{
5411 if ( !types || !*types )
5412 return;
5413
5414 d->types->clear();
5415 while( types && *types ) {
5416 d->types->insertItem( QString::fromLatin1(*types) );
5417 types++;
5418 }
5419 d->types->setCurrentItem( 0 );
5420 setFilter( d->types->text( 0 ) );
5421}
5422
5423
5424/*! \overload void QFileDialog::setFilters( const QStringList & )
5425*/
5426
5427void QFileDialog::setFilters( const QStringList & types )
5428{
5429 if ( types.count() < 1 )
5430 return;
5431
5432 d->types->clear();
5433 for ( QStringList::ConstIterator it = types.begin(); it != types.end(); ++it )
5434 d->types->insertItem( *it );
5435 d->types->setCurrentItem( 0 );
5436 setFilter( d->types->text( 0 ) );
5437}
5438
5439/*!
5440 Adds the filter \a filter to the list of filters and makes it the
5441 current filter.
5442
5443 \code
5444 QFileDialog* fd = new QFileDialog( this );
5445 fd->addFilter( "Images (*.png *.jpg *.xpm)" );
5446 fd->show();
5447 \endcode
5448
5449 In the above example, a file dialog is created, and the file filter "Images
5450 (*.png *.jpg *.xpm)" is added and is set as the current filter. The original
5451 filter, "All Files (*)", is still available.
5452
5453 \sa setFilter(), setFilters()
5454*/
5455
5456void QFileDialog::addFilter( const QString &filter )
5457{
5458 if ( filter.isEmpty() )
5459 return;
5460 QString f = filter;
5461 QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) );
5462 int index = r.search( f );
5463 if ( index >= 0 )
5464 f = r.cap( 2 );
5465 for ( int i = 0; i < d->types->count(); ++i ) {
5466 QString f2( d->types->text( i ) );
5467 int index = r.search( f2 );
5468 if ( index >= 0 )
5469 f2 = r.cap( 1 );
5470 if ( f2 == f ) {
5471 d->types->setCurrentItem( i );
5472 setFilter( f2 );
5473 return;
5474 }
5475 }
5476
5477 d->types->insertItem( filter );
5478 d->types->setCurrentItem( d->types->count() - 1 );
5479 setFilter( d->types->text( d->types->count() - 1 ) );
5480}
5481
5482/*!
5483 Since modeButtons is a top-level widget, it may be destroyed by the
5484 kernel at application exit. Notice if this happens to
5485 avoid double deletion.
5486*/
5487
5488void QFileDialog::modeButtonsDestroyed()
5489{
5490 if ( d )
5491 d->modeButtons = 0;
5492}
5493
5494
5495/*!
5496 This is a convenience static function that will return one or more
5497 existing files selected by the user.
5498
5499 \code
5500 QStringList files = QFileDialog::getOpenFileNames(
5501 "Images (*.png *.xpm *.jpg)",
5502 "/home",
5503 this,
5504 "open files dialog"
5505 "Select one or more files to open" );
5506 \endcode
5507
5508 This function creates a modal file dialog called \a name, with
5509 parent \a parent. If \a parent is not 0, the dialog will be shown
5510 centered over the parent.
5511
5512 The file dialog's working directory will be set to \a dir. If \a
5513 dir includes a file name, the file will be selected. The filter
5514 is set to \a filter so that only those files which match the filter
5515 are shown. The filter selected is set to \a selectedFilter. The parameters
5516 \a dir, \a selectedFilter and \a filter may be QString::null.
5517
5518 The dialog's caption is set to \a caption. If \a caption is not
5519 specified then a default caption will be used.
5520
5521 Under Windows and Mac OS X, this static function will use the native
5522 file dialog and not a QFileDialog, unless the style of the application
5523 is set to something other than the native style. (Note that on Windows the
5524 dialog will spin a blocking modal event loop that will not dispatch any
5525 QTimers and if parent is not 0 then it will position the dialog just under
5526 the parent's titlebar).
5527
5528 Under Unix/X11, the normal behavior of the file dialog is to resolve
5529 and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
5530 the file dialog will change to /var/tmp after entering /usr/tmp.
5531 If \a resolveSymlinks is FALSE, the file dialog will treat
5532 symlinks as regular directories.
5533
5534 Note that if you want to iterate over the list of files, you should
5535 iterate over a copy, e.g.
5536 \code
5537 QStringList list = files;
5538 QStringList::Iterator it = list.begin();
5539 while( it != list.end() ) {
5540 myProcessing( *it );
5541 ++it;
5542 }
5543 \endcode
5544
5545 \sa getOpenFileName(), getSaveFileName(), getExistingDirectory()
5546*/
5547
5548QStringList QFileDialog::getOpenFileNames( const QString & filter,
5549 const QString& dir,
5550 QWidget *parent,
5551 const char* name,
5552 const QString& caption,
5553 QString *selectedFilter,
5554 bool resolveSymlinks )
5555{
5556 bool save_qt_resolve_symlinks = qt_resolve_symlinks;
5557 qt_resolve_symlinks = resolveSymlinks;
5558
5559 QStringList filters;
5560 if ( !filter.isEmpty() )
5561 filters = makeFiltersList( filter );
5562
5563 makeVariables();
5564
5565 if ( workingDirectory->isNull() )
5566 *workingDirectory = QDir::currentDirPath();
5567
5568 if ( !dir.isEmpty() ) {
5569 // #### works only correct for local files
5570 QUrlOperator u( QFileDialogPrivate::encodeFileName(dir) );
5571 if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) {
5572 *workingDirectory = dir;
5573 } else {
5574 *workingDirectory = u.toString();
5575 }
5576 }
5577
5578#if defined(Q_WS_WIN)
5579 if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle )
5580 return winGetOpenFileNames( filter, workingDirectory, parent, name, caption, selectedFilter );
5581#elif defined(Q_WS_MAC)
5582 if( qt_use_native_dialogs && ( qApp->style().inherits(QMAC_DEFAULT_STYLE) || qApp->style().inherits("QMacStyle") ) )
5583 return macGetOpenFileNames(filter, workingDirectory, parent, name, caption, selectedFilter );
5584#endif
5585
5586 QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gofns", TRUE );
5587
5588 Q_CHECK_PTR( dlg );
5589#ifndef QT_NO_WIDGET_TOPEXTRA
5590 if ( !caption.isNull() )
5591 dlg->setCaption( caption );
5592 else
5593 dlg->setCaption( QFileDialog::tr("Open") );
5594#endif
5595
5596 dlg->setFilters( filters );
5597 if ( selectedFilter )
5598 dlg->setFilter( *selectedFilter );
5599 dlg->setMode( QFileDialog::ExistingFiles );
5600 QString result;
5601 QStringList lst;
5602 if ( dlg->exec() == QDialog::Accepted ) {
5603 lst = dlg->selectedFiles();
5604 *workingDirectory = dlg->d->url;
5605 if ( selectedFilter )
5606 *selectedFilter = dlg->selectedFilter();
5607 }
5608 delete dlg;
5609
5610 qt_resolve_symlinks = save_qt_resolve_symlinks;
5611
5612 return lst;
5613}
5614
5615/*! Updates the line edit to match the speed-key usage in QListView. */
5616
5617void QFileDialog::fixupNameEdit()
5618{
5619 if ( files->currentItem() ) {
5620 if ( ( (QFileDialogPrivate::File*)files->currentItem() )->info.isFile() )
5621 nameEdit->setText( files->currentItem()->text( 0 ) );
5622 }
5623}
5624
5625/*!
5626 Returns the URL of the current working directory in the file dialog.
5627
5628 \sa setUrl()
5629*/
5630
5631QUrl QFileDialog::url() const
5632{
5633 return d->url;
5634}
5635
5636static bool isRoot( const QUrl &u )
5637{
5638#if defined(Q_OS_MAC9)
5639 QString p = QDir::convertSeparators(u.path());
5640 if(p.contains(':') == 1)
5641 return TRUE;
5642#elif defined(Q_OS_UNIX)
5643 if ( u.path() == "/" )
5644 return TRUE;
5645#elif defined(Q_OS_WIN32)
5646 QString p = u.path();
5647 if ( p.length() == 3 &&
5648 p.right( 2 ) == ":/" )
5649 return TRUE;
5650 if ( p[ 0 ] == '/' && p[ 1 ] == '/' ) {
5651 int slashes = p.contains( '/' );
5652 if ( slashes <= 3 )
5653 return TRUE;
5654 if ( slashes == 4 && p[ (int)p.length() - 1 ] == '/' )
5655 return TRUE;
5656 }
5657#else
5658#if defined(Q_CC_GNU)
5659#warning "case not covered.."
5660#endif
5661#endif
5662
5663 if ( !u.isLocalFile() && u.path() == "/" )
5664 return TRUE;
5665
5666 return FALSE;
5667}
5668
5669#if defined(Q_WS_WIN)
5670extern int qt_ntfs_permission_lookup;
5671#endif
5672
5673void QFileDialog::urlStart( QNetworkOperation *op )
5674{
5675 if ( !op )
5676 return;
5677
5678#if defined(Q_WS_WIN)
5679 qt_ntfs_permission_lookup--;
5680#endif
5681 if ( op->operation() == QNetworkProtocol::OpListChildren ) {
5682#ifndef QT_NO_CURSOR
5683 if ( !d->cursorOverride ) {
5684 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
5685 d->cursorOverride = TRUE;
5686 }
5687#endif
5688 if ( isRoot( d->url ) )
5689 d->cdToParent->setEnabled( FALSE );
5690 else
5691 d->cdToParent->setEnabled( TRUE );
5692 d->mimeTypeTimer->stop();
5693 d->sortedList.clear();
5694 d->pendingItems.clear();
5695 d->moreFiles->clearSelection();
5696 files->clearSelection();
5697 d->moreFiles->clear();
5698 files->clear();
5699 files->setSorting( -1 );
5700
5701 QString s = d->url.toString( FALSE, FALSE );
5702 bool found = FALSE;
5703 for ( int i = 0; i < d->paths->count(); ++i ) {
5704#if defined(Q_WS_WIN)
5705 if ( d->paths->text( i ).lower() == s.lower() ) {
5706#else
5707 if ( d->paths->text( i ) == s ) {
5708#endif
5709 found = TRUE;
5710 d->paths->setCurrentItem( i );
5711 break;
5712 }
5713 }
5714 if ( !found ) {
5715 d->paths->insertItem( *openFolderIcon, s, -1 );
5716 d->paths->setCurrentItem( d->paths->count() - 1 );
5717 }
5718 d->last = 0;
5719 d->hadDotDot = FALSE;
5720
5721 if ( d->goBack && d->history.last() != d->url.toString() ) {
5722 d->history.append( d->url.toString() );
5723 if ( d->history.count() > 1 )
5724 d->goBack->setEnabled( TRUE );
5725 }
5726 }
5727}
5728
5729void QFileDialog::urlFinished( QNetworkOperation *op )
5730{
5731 if ( !op )
5732 return;
5733
5734#ifndef QT_NO_CURSOR
5735 if ( op->operation() == QNetworkProtocol::OpListChildren &&
5736 d->cursorOverride ) {
5737 QApplication::restoreOverrideCursor();
5738 d->cursorOverride = FALSE;
5739 }
5740#endif
5741
5742 if ( op->state() == QNetworkProtocol::StFailed ) {
5743 if ( d->paths->hasFocus() )
5744 d->ignoreNextKeyPress = TRUE;
5745
5746 if ( d->progressDia ) {
5747 d->ignoreStop = TRUE;
5748 d->progressDia->close();
5749 delete d->progressDia;
5750 d->progressDia = 0;
5751 }
5752
5753 QMessageBox::critical( this, tr( "Error" ), op->protocolDetail() );
5754
5755 int ecode = op->errorCode();
5756 if ( ecode == QNetworkProtocol::ErrListChildren || ecode == QNetworkProtocol::ErrParse ||
5757 ecode == QNetworkProtocol::ErrUnknownProtocol || ecode == QNetworkProtocol::ErrLoginIncorrect ||
5758 ecode == QNetworkProtocol::ErrValid || ecode == QNetworkProtocol::ErrHostNotFound ||
5759 ecode == QNetworkProtocol::ErrFileNotExisting ) {
5760 if (d->url != d->oldUrl) {
5761 d->url = d->oldUrl;
5762 rereadDir();
5763 }
5764 } else {
5765 // another error happened, no need to go back to last dir
5766 }
5767 } else if ( op->operation() == QNetworkProtocol::OpListChildren &&
5768 op == d->currListChildren ) {
5769 if ( !d->hadDotDot && !isRoot( d->url ) ) {
5770 bool ok = TRUE;
5771#if defined(Q_WS_WIN)
5772 if ( d->url.path().left( 2 ) == "//" )
5773 ok = FALSE;
5774#endif
5775 if ( ok ) {
5776 QUrlInfo ui( d->url, ".." );
5777 ui.setName( ".." );
5778 ui.setDir( TRUE );
5779 ui.setFile( FALSE );
5780 ui.setSymLink( FALSE );
5781 ui.setSize( 0 );
5782 QValueList<QUrlInfo> lst;
5783 lst << ui;
5784 insertEntry( lst, 0 );
5785 }
5786 }
5787 resortDir();
5788 } else if ( op->operation() == QNetworkProtocol::OpGet ) {
5789 } else if ( op->operation() == QNetworkProtocol::OpPut ) {
5790 rereadDir();
5791 if ( d->progressDia ) {
5792 d->ignoreStop = TRUE;
5793 d->progressDia->close();
5794 }
5795 delete d->progressDia;
5796 d->progressDia = 0;
5797 }
5798
5799#if defined(Q_WS_WIN)
5800 qt_ntfs_permission_lookup++;
5801#endif
5802}
5803
5804void QFileDialog::dataTransferProgress( int bytesDone, int bytesTotal, QNetworkOperation *op )
5805{
5806 if ( !op )
5807 return;
5808
5809 QString label;
5810 QUrl u( op->arg( 0 ) );
5811 if ( u.isLocalFile() ) {
5812 label = u.path();
5813 } else {
5814 label = QString( "%1 (on %2)" );
5815 label = label.arg( u.path() ).arg( u.host() );
5816 }
5817
5818 if ( !d->progressDia ) {
5819 if ( bytesDone < bytesTotal) {
5820 d->ignoreStop = FALSE;
5821 d->progressDia = new QFDProgressDialog( this, label, bytesTotal );
5822 connect( d->progressDia, SIGNAL( cancelled() ),
5823 this, SLOT( stopCopy() ) );
5824 d->progressDia->show();
5825 } else
5826 return;
5827 }
5828
5829 if ( d->progressDia ) {
5830 if ( op->operation() == QNetworkProtocol::OpGet ) {
5831 if ( d->progressDia ) {
5832 d->progressDia->setReadProgress( bytesDone );
5833 }
5834 } else if ( op->operation() == QNetworkProtocol::OpPut ) {
5835 if ( d->progressDia ) {
5836 d->progressDia->setWriteLabel( label );
5837 d->progressDia->setWriteProgress( bytesDone );
5838 }
5839 } else {
5840 return;
5841 }
5842 }
5843}
5844
5845void QFileDialog::insertEntry( const QValueList<QUrlInfo> &lst, QNetworkOperation *op )
5846{
5847 if ( op && op->operation() == QNetworkProtocol::OpListChildren &&
5848 op != d->currListChildren )
5849 return;
5850 QValueList<QUrlInfo>::ConstIterator it = lst.begin();
5851 for ( ; it != lst.end(); ++it ) {
5852 const QUrlInfo &inf = *it;
5853 if ( d->mode == DirectoryOnly && !inf.isDir() )
5854 continue;
5855 if ( inf.name() == ".." ) {
5856 d->hadDotDot = TRUE;
5857 if ( isRoot( d->url ) )
5858 continue;
5859#if defined(Q_WS_WIN)
5860 if ( d->url.path().left( 2 ) == "//" )
5861 continue;
5862#endif
5863 } else if ( inf.name() == "." )
5864 continue;
5865
5866#if defined(Q_WS_WIN)
5867 // Workaround a Windows bug, '..' is apparantly hidden in directories
5868 // that are one level away from root
5869 if ( !bShowHiddenFiles && inf.name() != ".." ) {
5870 if ( d->url.isLocalFile() ) {
5871 QString file = d->url.path();
5872 if ( !file.endsWith( "/" ) )
5873 file.append( "/" );
5874 file += inf.name();
5875 QT_WA( {
5876 if ( GetFileAttributesW( (TCHAR*)file.ucs2() ) & FILE_ATTRIBUTE_HIDDEN )
5877 continue;
5878 } , {
5879 if ( GetFileAttributesA( file.local8Bit() ) & FILE_ATTRIBUTE_HIDDEN )
5880 continue;
5881 } );
5882 } else {
5883 if ( inf.name() != ".." && inf.name()[0] == QChar('.') )
5884 continue;
5885 }
5886 }
5887#else
5888 if ( !bShowHiddenFiles && inf.name() != ".." ) {
5889 if ( inf.name()[ 0 ] == QChar( '.' ) )
5890 continue;
5891 }
5892#endif
5893 if ( !d->url.isLocalFile() ) {
5894 QFileDialogPrivate::File * i = 0;
5895 QFileDialogPrivate::MCItem *i2 = 0;
5896 i = new QFileDialogPrivate::File( d, &inf, files );
5897 i2 = new QFileDialogPrivate::MCItem( d->moreFiles, i );
5898
5899 if ( d->mode == ExistingFiles && inf.isDir() ||
5900 ( isDirectoryMode( d->mode ) && inf.isFile() ) ) {
5901 i->setSelectable( FALSE );
5902 i2->setSelectable( FALSE );
5903 }
5904
5905 i->i = i2;
5906 }
5907
5908 d->sortedList.append( new QUrlInfo( inf ) );
5909 }
5910}
5911
5912void QFileDialog::removeEntry( QNetworkOperation *op )
5913{
5914 if ( !op )
5915 return;
5916
5917 QUrlInfo *i = 0;
5918 QListViewItemIterator it( files );
5919 bool ok1 = FALSE, ok2 = FALSE;
5920 for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) {
5921 if ( ( (QFileDialogPrivate::File*)it.current() )->info.name() == op->arg( 0 ) ) {
5922 d->pendingItems.removeRef( (QFileDialogPrivate::File*)it.current() );
5923 delete ( (QFileDialogPrivate::File*)it.current() )->i;
5924 delete it.current();
5925 ok1 = TRUE;
5926 }
5927 if ( i && i->name() == op->arg( 0 ) ) {
5928 d->sortedList.removeRef( i );
5929 i = d->sortedList.prev();
5930 ok2 = TRUE;
5931 }
5932 if ( ok1 && ok2 )
5933 break;
5934 }
5935}
5936
5937void QFileDialog::itemChanged( QNetworkOperation *op )
5938{
5939 if ( !op )
5940 return;
5941
5942 QUrlInfo *i = 0;
5943 QListViewItemIterator it1( files );
5944 bool ok1 = FALSE, ok2 = FALSE;
5945 // first check whether the new file replaces an existing file.
5946 for ( i = d->sortedList.first(); it1.current(); ++it1, i = d->sortedList.next() ) {
5947 if ( ( (QFileDialogPrivate::File*)it1.current() )->info.name() == op->arg( 1 ) ) {
5948 delete ( (QFileDialogPrivate::File*)it1.current() )->i;
5949 delete it1.current();
5950 ok1 = TRUE;
5951 }
5952 if ( i && i->name() == op->arg( 1 ) ) {
5953 d->sortedList.removeRef( i );
5954 i = d->sortedList.prev();
5955 ok2 = TRUE;
5956 }
5957 if ( ok1 && ok2 )
5958 break;
5959 }
5960
5961 i = 0;
5962 QListViewItemIterator it( files );
5963 ok1 = FALSE;
5964 ok2 = FALSE;
5965 for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) {
5966 if ( ( (QFileDialogPrivate::File*)it.current() )->info.name() == op->arg( 0 ) ) {
5967 ( (QFileDialogPrivate::File*)it.current() )->info.setName( op->arg( 1 ) );
5968 ok1 = TRUE;
5969 }
5970 if ( i && i->name() == op->arg( 0 ) ) {
5971 i->setName( op->arg( 1 ) );
5972 ok2 = TRUE;
5973 }
5974 if ( ok1 && ok2 )
5975 break;
5976 }
5977
5978 resortDir();
5979}
5980
5981/*!
5982 \property QFileDialog::infoPreview
5983
5984 \brief whether the file dialog can provide preview information about
5985 the currently selected file
5986
5987 The default is FALSE.
5988*/
5989bool QFileDialog::isInfoPreviewEnabled() const
5990{
5991 return d->infoPreview;
5992}
5993
5994void QFileDialog::setInfoPreviewEnabled( bool info )
5995{
5996 if ( info == d->infoPreview )
5997 return;
5998 d->geometryDirty = TRUE;
5999 d->infoPreview = info;
6000 updateGeometries();
6001}
6002
6003
6004/*!
6005 \property QFileDialog::contentsPreview
6006
6007 \brief whether the file dialog can provide a contents preview of the
6008 currently selected file
6009
6010 The default is FALSE.
6011
6012 \sa setContentsPreview() setInfoPreviewEnabled()
6013*/
6014// ### improve the above documentation: how is the preview done, how can I add
6015// support for customized preview, etc.
6016
6017bool QFileDialog::isContentsPreviewEnabled() const
6018{
6019 return d->contentsPreview;
6020}
6021
6022void QFileDialog::setContentsPreviewEnabled( bool contents )
6023{
6024 if ( contents == d->contentsPreview )
6025 return;
6026 d->geometryDirty = TRUE;
6027 d->contentsPreview = contents;
6028 updateGeometries();
6029}
6030
6031
6032/*!
6033 Sets the widget to be used for displaying information about the file
6034 to the widget \a w and a preview of that information to the
6035 QFilePreview \a preview.
6036
6037 Normally you would create a preview widget that derives from both QWidget and
6038 QFilePreview, so you should pass the same widget twice.
6039
6040 \code
6041 class Preview : public QLabel, public QFilePreview
6042 {
6043 public:
6044 Preview( QWidget *parent=0 ) : QLabel( parent ) {}
6045
6046 void previewUrl( const QUrl &u )
6047 {
6048 QString path = u.path();
6049 QPixmap pix( path );
6050 if ( pix.isNull() )
6051 setText( "This is not a pixmap" );
6052 else
6053 setText( "This is a pixmap" );
6054 }
6055 };
6056
6057 //...
6058
6059 int main( int argc, char** argv )
6060 {
6061 Preview* p = new Preview;
6062
6063 QFileDialog* fd = new QFileDialog( this );
6064 fd->setInfoPreviewEnabled( TRUE );
6065 fd->setInfoPreview( p, p );
6066 fd->setPreviewMode( QFileDialog::Info );
6067 fd->show();
6068 }
6069
6070 \endcode
6071
6072 \sa setContentsPreview(), setInfoPreviewEnabled(), setPreviewMode()
6073
6074*/
6075
6076void QFileDialog::setInfoPreview( QWidget *w, QFilePreview *preview )
6077{
6078 if ( !w || !preview )
6079 return;
6080
6081 if ( d->infoPreviewWidget ) {
6082 d->preview->removeWidget( d->infoPreviewWidget );
6083 delete d->infoPreviewWidget;
6084 }
6085 delete d->infoPreviewer;
6086 d->infoPreviewWidget = w;
6087 d->infoPreviewer = preview;
6088 w->reparent( d->preview, 0, QPoint( 0, 0 ) );
6089}
6090
6091/*!
6092 Sets the widget to be used for displaying the contents of the file
6093 to the widget \a w and a preview of those contents to the
6094 QFilePreview \a preview.
6095
6096 Normally you would create a preview widget that derives from both QWidget and
6097 QFilePreview, so you should pass the same widget twice.
6098
6099 \code
6100 class Preview : public QLabel, public QFilePreview
6101 {
6102 public:
6103 Preview( QWidget *parent=0 ) : QLabel( parent ) {}
6104
6105 void previewUrl( const QUrl &u )
6106 {
6107 QString path = u.path();
6108 QPixmap pix( path );
6109 if ( pix.isNull() )
6110 setText( "This is not a pixmap" );
6111 else
6112 setPixmap( pix );
6113 }
6114 };
6115
6116 //...
6117
6118 int main( int argc, char** argv )
6119 {
6120 Preview* p = new Preview;
6121
6122 QFileDialog* fd = new QFileDialog( this );
6123 fd->setContentsPreviewEnabled( TRUE );
6124 fd->setContentsPreview( p, p );
6125 fd->setPreviewMode( QFileDialog::Contents );
6126 fd->show();
6127 }
6128 \endcode
6129
6130 \sa setContentsPreviewEnabled(), setInfoPreview(), setPreviewMode()
6131*/
6132
6133void QFileDialog::setContentsPreview( QWidget *w, QFilePreview *preview )
6134{
6135 if ( !w || !preview )
6136 return;
6137
6138 if ( d->contentsPreviewWidget ) {
6139 d->preview->removeWidget( d->contentsPreviewWidget );
6140 delete d->contentsPreviewWidget;
6141 }
6142 delete d->contentsPreviewer;
6143 d->contentsPreviewWidget = w;
6144 d->contentsPreviewer = preview;
6145 w->reparent( d->preview, 0, QPoint( 0, 0 ) );
6146}
6147
6148/*!
6149 Re-sorts the displayed directory.
6150
6151 \sa rereadDir()
6152*/
6153
6154void QFileDialog::resortDir()
6155{
6156 d->mimeTypeTimer->stop();
6157 d->pendingItems.clear();
6158
6159 QFileDialogPrivate::File *item = 0;
6160 QFileDialogPrivate::MCItem *item2 = 0;
6161
6162 d->sortedList.sort();
6163
6164 if ( files->childCount() > 0 || d->moreFiles->count() > 0 ) {
6165 d->moreFiles->clear();
6166 files->clear();
6167 d->last = 0;
6168 files->setSorting( -1 );
6169 }
6170
6171 QUrlInfo *i = sortAscending ? d->sortedList.first() : d->sortedList.last();
6172 for ( ; i; i = sortAscending ? d->sortedList.next() : d->sortedList.prev() ) {
6173 item = new QFileDialogPrivate::File( d, i, files );
6174 item2 = new QFileDialogPrivate::MCItem( d->moreFiles, item, item2 );
6175 item->i = item2;
6176 d->pendingItems.append( item );
6177 if ( d->mode == ExistingFiles && item->info.isDir() ||
6178 ( isDirectoryMode( d->mode ) && item->info.isFile() ) ) {
6179 item->setSelectable( FALSE );
6180 item2->setSelectable( FALSE );
6181 }
6182 }
6183
6184 // ##### As the QFileIconProvider only support QFileInfo and no
6185 // QUrlInfo it can be only used for local files at the moment. In
6186 // 3.0 we have to change the API of QFileIconProvider to work on
6187 // QUrlInfo so that also remote filesystems can be show mime-type
6188 // specific icons.
6189 if ( d->url.isLocalFile() )
6190 d->mimeTypeTimer->start( 0 );
6191}
6192
6193/*!
6194 Stops the current copy operation.
6195*/
6196
6197void QFileDialog::stopCopy()
6198{
6199 if ( d->ignoreStop )
6200 return;
6201
6202 d->url.blockSignals( TRUE );
6203 d->url.stop();
6204 if ( d->progressDia ) {
6205 d->ignoreStop = TRUE;
6206 QTimer::singleShot( 100, this, SLOT( removeProgressDia() ) );
6207 }
6208 d->url.blockSignals( FALSE );
6209}
6210
6211/*!
6212 \internal
6213*/
6214
6215void QFileDialog::removeProgressDia()
6216{
6217 if ( d->progressDia )
6218 delete d->progressDia;
6219 d->progressDia = 0;
6220}
6221
6222/*!
6223 \internal
6224*/
6225
6226void QFileDialog::doMimeTypeLookup()
6227{
6228 if ( !iconProvider() ) {
6229 d->pendingItems.clear();
6230 d->mimeTypeTimer->stop();
6231 return;
6232 }
6233
6234 d->mimeTypeTimer->stop();
6235 if ( d->pendingItems.count() == 0 ) {
6236 return;
6237 }
6238
6239 QRect r;
6240 QFileDialogPrivate::File *item = d->pendingItems.first();
6241 if ( item ) {
6242 QFileInfo fi;
6243 if ( d->url.isLocalFile() ) {
6244 fi.setFile( QUrl( d->url.path(), QFileDialogPrivate::encodeFileName( item->info.name() ) ).path( FALSE ) );
6245 } else
6246 fi.setFile( item->info.name() ); // #####
6247 const QPixmap *p = iconProvider()->pixmap( fi );
6248 if ( p && p != item->pixmap( 0 ) &&
6249 ( !item->pixmap( 0 ) || p->serialNumber() != item->pixmap( 0 )->serialNumber() ) &&
6250 p != fifteenTransparentPixels ) {
6251 item->hasMimePixmap = TRUE;
6252
6253 // evil hack to avoid much too much repaints!
6254 QGuardedPtr<QFileDialog> that( this ); // this may be deleted by an event handler
6255 qApp->processEvents();
6256 if ( that.isNull() )
6257 return;
6258 files->setUpdatesEnabled( FALSE );
6259 files->viewport()->setUpdatesEnabled( FALSE );
6260 if ( item != d->pendingItems.first() )
6261 return;
6262 item->setPixmap( 0, *p );
6263 qApp->processEvents();
6264 if ( that.isNull() )
6265 return;
6266 files->setUpdatesEnabled( TRUE );
6267 files->viewport()->setUpdatesEnabled( TRUE );
6268
6269 if ( files->isVisible() ) {
6270 QRect ir( files->itemRect( item ) );
6271 if ( ir != QRect( 0, 0, -1, -1 ) ) {
6272 r = r.unite( ir );
6273 }
6274 } else {
6275 QRect ir( d->moreFiles->itemRect( item->i ) );
6276 if ( ir != QRect( 0, 0, -1, -1 ) ) {
6277 r = r.unite( ir );
6278 }
6279 }
6280 }
6281 if ( d->pendingItems.count() )
6282 d->pendingItems.removeFirst();
6283 }
6284
6285 if ( d->moreFiles->isVisible() ) {
6286 d->moreFiles->viewport()->repaint( r, FALSE );
6287 } else {
6288 files->viewport()->repaint( r, FALSE );
6289 }
6290
6291 if ( d->pendingItems.count() )
6292 d->mimeTypeTimer->start( 0 );
6293 else if ( d->moreFiles->isVisible() )
6294 d->moreFiles->triggerUpdate( TRUE );
6295}
6296
6297/*!
6298 If \a b is TRUE then all the files in the current directory are selected;
6299 otherwise, they are deselected.
6300*/
6301
6302void QFileDialog::selectAll( bool b )
6303{
6304 if ( d->mode != ExistingFiles )
6305 return;
6306 d->moreFiles->selectAll( b );
6307 files->selectAll( b );
6308}
6309
6310void QFileDialog::goBack()
6311{
6312 if ( !d->goBack || !d->goBack->isEnabled() )
6313 return;
6314 d->history.remove( d->history.last() );
6315 if ( d->history.count() < 2 )
6316 d->goBack->setEnabled( FALSE );
6317 setUrl( d->history.last() );
6318}
6319
6320// a class with wonderfully inflexible flexibility. why doesn't it
6321// just subclass QWidget in the first place? 'you have to derive your
6322// preview widget from QWidget and from this class' indeed.
6323
6324/*!
6325 \class QFilePreview qfiledialog.h
6326 \ingroup misc
6327 \brief The QFilePreview class provides file previewing in QFileDialog.
6328
6329 This class is an abstract base class which is used to implement
6330 widgets that can display a preview of a file in a QFileDialog.
6331
6332 You must derive the preview widget from both QWidget and from this
6333 class. Then you must reimplement this class's previewUrl() function,
6334 which is called by the file dialog if the preview of a file
6335 (specified as a URL) should be shown.
6336
6337 See also QFileDialog::setPreviewMode(), QFileDialog::setContentsPreview(),
6338 QFileDialog::setInfoPreview(), QFileDialog::setInfoPreviewEnabled(),
6339 QFileDialog::setContentsPreviewEnabled().
6340
6341 For an example of a preview widget see qt/examples/qdir/qdir.cpp.
6342*/
6343
6344/*!
6345 Constructs the QFilePreview.
6346*/
6347
6348QFilePreview::QFilePreview()
6349{
6350}
6351
6352/*!
6353 \fn void QFilePreview::previewUrl( const QUrl &url )
6354
6355 This function is called by QFileDialog if a preview
6356 for the \a url should be shown. Reimplement this
6357 function to provide file previewing.
6358*/
6359
6360
6361#include "qfiledialog.moc"
6362
6363#endif
Note: See TracBrowser for help on using the repository browser.