source: trunk/src/dialogs/qfiledialog.cpp@ 90

Last change on this file since 90 was 8, checked in by dmik, 20 years ago

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

  • Property svn:keywords set to Id
File size: 174.4 KB
Line 
1/****************************************************************************
2** $Id: qfiledialog.cpp 8 2005-11-16 19:36:46Z 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) || defined(Q_OS_OS2)
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) || defined(Q_OS_OS2)
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) || defined(Q_OS_OS2)
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 // stop any pending operations
4600 d->url.stop();
4601
4602 if ( i == QDialog::Accepted && (d->mode == ExistingFile || d->mode == ExistingFiles) ) {
4603 QStringList selection = selectedFiles();
4604 for ( uint f = 0; f < selection.count(); f++ ) {
4605 QString file = selection[f];
4606 if ( file.isNull() )
4607 continue;
4608 if ( d->url.isLocalFile() && !QFile::exists( file ) ) {
4609 QMessageBox::information( this, tr("Error"),
4610 tr("%1\nFile not found.\nCheck path and filename.").arg( file ) );
4611 return;
4612 }
4613 }
4614 }
4615 QDialog::done( i );
4616}
4617
4618/*!
4619 \property QFileDialog::viewMode
4620
4621 \brief the file dialog's view mode
4622
4623 If you set the view mode to be \e Detail (the default), then you
4624 will see the file's details, such as the size of the file and the
4625 date the file was last modified in addition to the file's name.
4626
4627 If you set the view mode to be \e List, then you will just
4628 see a list of the files and folders.
4629
4630 See \l QFileDialog::ViewMode
4631*/
4632
4633
4634QFileDialog::ViewMode QFileDialog::viewMode() const
4635{
4636 if ( detailViewMode )
4637 return Detail;
4638 else
4639 return List;
4640}
4641
4642void QFileDialog::setViewMode( ViewMode m )
4643{
4644 if ( m == Detail ) {
4645 detailViewMode = TRUE;
4646 d->stack->raiseWidget( files );
4647 d->detailView->setOn( TRUE );
4648 d->mcView->setOn( FALSE );
4649 } else if ( m == List ) {
4650 detailViewMode = FALSE;
4651 d->stack->raiseWidget( d->moreFiles );
4652 d->detailView->setOn( FALSE );
4653 d->mcView->setOn( TRUE );
4654 }
4655}
4656
4657
4658/*!
4659 \property QFileDialog::previewMode
4660
4661 \brief the preview mode for the file dialog
4662
4663 If you set the mode to be a mode other than \e NoPreview, you must
4664 use setInfoPreview() or setContentsPreview() to set the dialog's
4665 preview widget to your preview widget and enable the preview
4666 widget(s) with setInfoPreviewEnabled() or
4667 setContentsPreviewEnabled().
4668
4669 \sa infoPreview, contentsPreview, viewMode
4670*/
4671
4672void QFileDialog::setPreviewMode( PreviewMode m )
4673{
4674 if ( m == NoPreview ) {
4675 d->previewInfo->setOn( FALSE );
4676 d->previewContents->setOn( FALSE );
4677 } else if ( m == Info && d->infoPreview ) {
4678 d->previewInfo->setOn( TRUE );
4679 d->previewContents->setOn( FALSE );
4680 changeMode( d->modeButtons->id( d->previewInfo ) );
4681 } else if ( m == Contents && d->contentsPreview ) {
4682 d->previewInfo->setOn( FALSE );
4683 d->previewContents->setOn( TRUE );
4684 changeMode( d->modeButtons->id( d->previewContents ) );
4685 }
4686}
4687QFileDialog::PreviewMode QFileDialog::previewMode() const
4688{
4689 if ( d->infoPreview && d->infoPreviewWidget->isVisible() )
4690 return Info;
4691 else if ( d->contentsPreview && d->contentsPreviewWidget->isVisible() )
4692 return Contents;
4693
4694 return NoPreview;
4695}
4696
4697
4698/*!
4699 Adds the specified widgets to the bottom of the file dialog. The
4700 label \a l is placed underneath the "file name" and the "file types"
4701 labels. The widget \a w is placed underneath the file types combobox.
4702 The button \a b is placed underneath the Cancel pushbutton.
4703
4704 \code
4705 MyFileDialog::MyFileDialog( QWidget* parent, const char* name ) :
4706 QFileDialog( parent, name )
4707 {
4708 QLabel* label = new QLabel( "Added widgets", this );
4709 QLineEdit* lineedit = new QLineEdit( this );
4710 QPushButton* pushbutton = new QPushButton( this );
4711
4712 addWidgets( label, lineedit, pushbutton );
4713 }
4714 \endcode
4715
4716 If you don't want to have one of the widgets added, pass 0 in that
4717 widget's position.
4718
4719 Every time you call this function, a new row of widgets will be added
4720 to the bottom of the file dialog.
4721
4722 \sa addToolButton(), addLeftWidget(), addRightWidget()
4723*/
4724
4725void QFileDialog::addWidgets( QLabel * l, QWidget * w, QPushButton * b )
4726{
4727 if ( !l && !w && !b )
4728 return;
4729
4730 d->geometryDirty = TRUE;
4731
4732 QHBoxLayout *lay = new QHBoxLayout();
4733 d->extraWidgetsLayouts.append( lay );
4734 d->topLevelLayout->addLayout( lay );
4735
4736 if ( !l )
4737 l = new QLabel( this, "qt_intern_lbl" );
4738 d->extraLabels.append( l );
4739 lay->addWidget( l );
4740
4741 if ( !w )
4742 w = new QWidget( this, "qt_intern_widget" );
4743 d->extraWidgets.append( w );
4744 lay->addWidget( w );
4745 lay->addSpacing( 15 );
4746
4747 if ( b ) {
4748 d->extraButtons.append( b );
4749 lay->addWidget( b );
4750 } else {
4751 QWidget *wid = new QWidget( this, "qt_extrabuttons_widget" );
4752 d->extraButtons.append( wid );
4753 lay->addWidget( wid );
4754 }
4755
4756 updateGeometries();
4757}
4758
4759/*!
4760 Adds the tool button \a b to the row of tool buttons at the top of the
4761 file dialog. The button is appended to the right of
4762 this row. If \a separator is TRUE, a small space is inserted between the
4763 last button of the row and the new button \a b.
4764
4765 \sa addWidgets(), addLeftWidget(), addRightWidget()
4766*/
4767
4768void QFileDialog::addToolButton( QButton *b, bool separator )
4769{
4770 if ( !b || !d->buttonLayout )
4771 return;
4772
4773 d->geometryDirty = TRUE;
4774
4775 d->toolButtons.append( b );
4776 if ( separator )
4777 d->buttonLayout->addSpacing( 8 );
4778 d->buttonLayout->addWidget( b );
4779
4780 updateGeometries();
4781}
4782
4783/*!
4784 Adds the widget \a w to the left-hand side of the file dialog.
4785
4786 \sa addRightWidget(), addWidgets(), addToolButton()
4787*/
4788
4789void QFileDialog::addLeftWidget( QWidget *w )
4790{
4791 if ( !w )
4792 return;
4793 d->geometryDirty = TRUE;
4794
4795 d->leftLayout->addWidget( w );
4796 d->leftLayout->addSpacing( 5 );
4797
4798 updateGeometries();
4799}
4800
4801/*!
4802 Adds the widget \a w to the right-hand side of the file dialog.
4803
4804 \sa addLeftWidget(), addWidgets(), addToolButton()
4805*/
4806
4807void QFileDialog::addRightWidget( QWidget *w )
4808{
4809 if ( !w )
4810 return;
4811 d->geometryDirty = TRUE;
4812
4813 d->rightLayout->addSpacing( 5 );
4814 d->rightLayout->addWidget( w );
4815
4816 updateGeometries();
4817}
4818
4819/*! \reimp */
4820
4821void QFileDialog::keyPressEvent( QKeyEvent * ke )
4822{
4823 if ( !d->ignoreNextKeyPress &&
4824 ke && ( ke->key() == Key_Enter ||
4825 ke->key() == Key_Return ) ) {
4826 ke->ignore();
4827 if ( d->paths->hasFocus() ) {
4828 ke->accept();
4829 if ( d->url == QUrl(d->paths->currentText()) )
4830 nameEdit->setFocus();
4831 } else if ( d->types->hasFocus() ) {
4832 ke->accept();
4833 // ### is there a suitable condition for this? only valid
4834 // wildcards?
4835 nameEdit->setFocus();
4836 } else if ( nameEdit->hasFocus() ) {
4837 if ( d->currentFileName.isNull() ) {
4838 // maybe change directory
4839 QUrlInfo i( d->url, nameEdit->text() );
4840 if ( i.isDir() ) {
4841 nameEdit->setText( QString::fromLatin1("") );
4842 setDir( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(i.name()) ) );
4843 }
4844 ke->accept();
4845 } else if ( mode() == ExistingFiles ) {
4846 QUrlInfo i( d->url, nameEdit->text() );
4847 if ( i.isFile() ) {
4848 QListViewItem * i = files->firstChild();
4849 while ( i && nameEdit->text() != i->text( 0 ) )
4850 i = i->nextSibling();
4851 if ( i )
4852 files->setSelected( i, TRUE );
4853 else
4854 ke->accept(); // strangely, means to ignore that event
4855 }
4856 }
4857 } else if ( files->hasFocus() || d->moreFiles->hasFocus() ) {
4858 ke->accept();
4859 }
4860 } else if ( ke->key() == Key_Escape ) {
4861 ke->ignore();
4862 }
4863
4864 d->ignoreNextKeyPress = FALSE;
4865
4866 if ( !ke->isAccepted() ) {
4867 QDialog::keyPressEvent( ke );
4868 }
4869}
4870
4871
4872/*! \class QFileIconProvider qfiledialog.h
4873
4874 \brief The QFileIconProvider class provides icons for QFileDialog to
4875 use.
4876
4877 \ingroup misc
4878
4879 By default QFileIconProvider is not used, but any application or
4880 library can subclass it, reimplement pixmap() to return a suitable
4881 icon, and make all QFileDialog objects use it by calling the static
4882 function QFileDialog::setIconProvider().
4883
4884 It is advisable to make all the icons that QFileIconProvider returns be
4885 the same size or at least the same width. This makes the list view
4886 look much better.
4887
4888 \sa QFileDialog
4889*/
4890
4891
4892/*! Constructs an empty file icon provider called \a name, with the
4893 parent \a parent.
4894*/
4895
4896QFileIconProvider::QFileIconProvider( QObject * parent, const char* name )
4897 : QObject( parent, name )
4898{
4899 // nothing necessary
4900}
4901
4902
4903/*!
4904 Returns a pointer to a pixmap that should be used to
4905 signify the file with the information \a info.
4906
4907 If pixmap() returns 0, QFileDialog draws the default pixmap.
4908
4909 The default implementation returns particular icons for files, directories,
4910 link-files and link-directories. It returns a blank "icon" for other types.
4911
4912 If you return a pixmap here, it should measure 16x16 pixels.
4913*/
4914
4915const QPixmap * QFileIconProvider::pixmap( const QFileInfo & info )
4916{
4917 if ( info.isSymLink() ) {
4918 if ( info.isFile() )
4919 return symLinkFileIcon;
4920 else
4921 return symLinkDirIcon;
4922 } else if ( info.isDir() ) {
4923 return closedFolderIcon;
4924 } else if ( info.isFile() ) {
4925 return fileIcon;
4926 } else {
4927 return fifteenTransparentPixels;
4928 }
4929}
4930
4931/*!
4932 Sets the QFileIconProvider used by the file dialog to \a provider.
4933
4934 The default is that there is no QFileIconProvider and QFileDialog
4935 just draws a folder icon next to each directory and nothing next
4936 to files.
4937
4938 \sa QFileIconProvider, iconProvider()
4939*/
4940
4941void QFileDialog::setIconProvider( QFileIconProvider * provider )
4942{
4943 fileIconProvider = provider;
4944}
4945
4946
4947/*!
4948 Returns a pointer to the icon provider currently set on the file dialog.
4949 By default there is no icon provider, and this function returns 0.
4950
4951 \sa setIconProvider(), QFileIconProvider
4952*/
4953
4954QFileIconProvider * QFileDialog::iconProvider()
4955{
4956 return fileIconProvider;
4957}
4958
4959
4960#if defined(Q_WS_WIN)
4961
4962// ### FIXME: this code is duplicated in qdns.cpp
4963static QString getWindowsRegString( HKEY key, const QString &subKey )
4964{
4965 QString s;
4966 QT_WA( {
4967 char buf[1024];
4968 DWORD bsz = sizeof(buf);
4969 int r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz );
4970 if ( r == ERROR_SUCCESS ) {
4971 s = QString::fromUcs2( (unsigned short *)buf );
4972 } else if ( r == ERROR_MORE_DATA ) {
4973 char *ptr = new char[bsz+1];
4974 r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz );
4975 if ( r == ERROR_SUCCESS )
4976 s = ptr;
4977 delete [] ptr;
4978 }
4979 } , {
4980 char buf[512];
4981 DWORD bsz = sizeof(buf);
4982 int r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz );
4983 if ( r == ERROR_SUCCESS ) {
4984 s = buf;
4985 } else if ( r == ERROR_MORE_DATA ) {
4986 char *ptr = new char[bsz+1];
4987 r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz );
4988 if ( r == ERROR_SUCCESS )
4989 s = ptr;
4990 delete [] ptr;
4991 }
4992 } );
4993 return s;
4994}
4995
4996static void initPixmap( QPixmap &pm )
4997{
4998 pm.fill( Qt::white );
4999}
5000
5001
5002QWindowsIconProvider::QWindowsIconProvider( QObject *parent, const char *name )
5003 : QFileIconProvider( parent, name )
5004{
5005 pixw = GetSystemMetrics( SM_CXSMICON );
5006 pixh = GetSystemMetrics( SM_CYSMICON );
5007
5008 HKEY k;
5009 HICON si;
5010 int r;
5011 QString s;
5012 UINT res;
5013
5014 // ---------- get default folder pixmap
5015 const wchar_t iconFolder[] = L"folder\\DefaultIcon"; // workaround for Borland
5016 QT_WA( {
5017 r = RegOpenKeyEx( HKEY_CLASSES_ROOT,
5018 iconFolder,
5019 0, KEY_READ, &k );
5020 } , {
5021 r = RegOpenKeyExA( HKEY_CLASSES_ROOT,
5022 "folder\\DefaultIcon",
5023 0, KEY_READ, &k );
5024 } );
5025 resolveLibs();
5026 if ( r == ERROR_SUCCESS ) {
5027 s = getWindowsRegString( k, QString::null );
5028 RegCloseKey( k );
5029
5030 QStringList lst = QStringList::split( ",", s );
5031
5032#ifndef Q_OS_TEMP
5033 QT_WA( {
5034 res = ptrExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(),
5035 lst[ 1 ].simplifyWhiteSpace().toInt(),
5036 0, &si, 1 );
5037 } , {
5038 res = ExtractIconExA( lst[ 0 ].simplifyWhiteSpace().local8Bit(),
5039 lst[ 1 ].simplifyWhiteSpace().toInt(),
5040 0, &si, 1 );
5041 } );
5042#else
5043 res = (UINT)ExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(),
5044 lst[ 1 ].simplifyWhiteSpace().toInt(),
5045 0, &si, 1 );
5046#endif
5047
5048 if ( res ) {
5049 defaultFolder.resize( pixw, pixh );
5050 initPixmap( defaultFolder );
5051 QPainter p( &defaultFolder );
5052 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5053 p.end();
5054 defaultFolder.setMask( defaultFolder.createHeuristicMask() );
5055 *closedFolderIcon = defaultFolder;
5056 DestroyIcon( si );
5057 } else {
5058 defaultFolder = *closedFolderIcon;
5059 }
5060 } else {
5061 RegCloseKey( k );
5062 }
5063
5064 //------------------------------- get default file pixmap
5065#ifndef Q_OS_TEMP
5066 QT_WA( {
5067 res = ptrExtractIconEx( L"shell32.dll",
5068 0, 0, &si, 1 );
5069 } , {
5070 res = ExtractIconExA( "shell32.dll",
5071 0, 0, &si, 1 );
5072 } );
5073#else
5074 res = (UINT)ExtractIconEx( L"shell32.dll",
5075 0, 0, &si, 1 );
5076#endif
5077
5078 if ( res ) {
5079 defaultFile.resize( pixw, pixh );
5080 initPixmap( defaultFile );
5081 QPainter p( &defaultFile );
5082 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5083 p.end();
5084 defaultFile.setMask( defaultFile.createHeuristicMask() );
5085 *fileIcon = defaultFile;
5086 DestroyIcon( si );
5087 } else {
5088 defaultFile = *fileIcon;
5089 }
5090
5091 //------------------------------- get default exe pixmap
5092#ifndef Q_OS_TEMP
5093 QT_WA( {
5094 res = ptrExtractIconEx( L"shell32.dll",
5095 2, 0, &si, 1 );
5096 } , {
5097 res = ExtractIconExA( "shell32.dll",
5098 2, 0, &si, 1 );
5099 } );
5100#else
5101 res = (UINT)ExtractIconEx( L"ceshell.dll",
5102 10, 0, &si, 1 );
5103#endif
5104
5105 if ( res ) {
5106 defaultExe.resize( pixw, pixh );
5107 initPixmap( defaultExe );
5108 QPainter p( &defaultExe );
5109 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5110 p.end();
5111 defaultExe.setMask( defaultExe.createHeuristicMask() );
5112 DestroyIcon( si );
5113 } else {
5114 defaultExe = *fileIcon;
5115 }
5116}
5117
5118QWindowsIconProvider::~QWindowsIconProvider()
5119{
5120 if ( this == fileIconProvider )
5121 fileIconProvider = 0;
5122}
5123
5124const QPixmap * QWindowsIconProvider::pixmap( const QFileInfo &fi )
5125{
5126 QString ext = fi.extension( FALSE ).upper();
5127 QString key = ext;
5128 ext.prepend( "." );
5129 QMap< QString, QPixmap >::Iterator it;
5130
5131 if ( fi.isDir() ) {
5132 return &defaultFolder;
5133 } else if ( ext.lower() != ".exe" ) {
5134 it = cache.find( key );
5135 if ( it != cache.end() )
5136 return &( *it );
5137
5138 HKEY k, k2;
5139 int r;
5140 QT_WA( {
5141 r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)ext.ucs2(),
5142 0, KEY_READ, &k );
5143 } , {
5144 r = RegOpenKeyExA( HKEY_CLASSES_ROOT, ext.local8Bit(),
5145 0, KEY_READ, &k );
5146 } );
5147 QString s;
5148 if ( r == ERROR_SUCCESS ) {
5149 s = getWindowsRegString( k, QString::null );
5150 } else {
5151 cache[ key ] = defaultFile;
5152 RegCloseKey( k );
5153 return &defaultFile;
5154 }
5155 RegCloseKey( k );
5156
5157 QT_WA( {
5158 r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)QString( s + "\\DefaultIcon" ).ucs2(),
5159 0, KEY_READ, &k2 );
5160 } , {
5161 r = RegOpenKeyExA( HKEY_CLASSES_ROOT, QString( s + "\\DefaultIcon" ).local8Bit() ,
5162 0, KEY_READ, &k2 );
5163 } );
5164 if ( r == ERROR_SUCCESS ) {
5165 s = getWindowsRegString( k2, QString::null );
5166 } else {
5167 cache[ key ] = defaultFile;
5168 RegCloseKey( k2 );
5169 return &defaultFile;
5170 }
5171 RegCloseKey( k2 );
5172
5173 QStringList lst = QStringList::split( ",", s );
5174
5175 HICON si;
5176 UINT res = 0;
5177 QString filepath = lst[ 0 ].stripWhiteSpace();
5178 if ( !filepath.isEmpty() ) {
5179 if ( filepath.find("%1") != -1 ) {
5180 filepath = filepath.arg( fi.filePath() );
5181 if ( ext.lower() == ".dll" ) {
5182 pix = defaultFile;
5183 return &pix;
5184 }
5185 }
5186 if ( filepath[0] == '"' && filepath[(int)filepath.length()-1] == '"' )
5187 filepath = filepath.mid( 1, filepath.length()-2 );
5188
5189 resolveLibs();
5190#ifndef Q_OS_TEMP
5191 QT_WA( {
5192 res = ptrExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(),
5193 0, &si, 1 );
5194 } , {
5195 res = ExtractIconExA( filepath.local8Bit(), lst[ 1 ].stripWhiteSpace().toInt(),
5196 0, &si, 1 );
5197 } );
5198#else
5199 res = (UINT)ExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(),
5200 0, &si, 1 );
5201#endif
5202 }
5203
5204 if ( res ) {
5205 pix.resize( pixw, pixh );
5206 initPixmap( pix );
5207 QPainter p( &pix );
5208 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5209 p.end();
5210 pix.setMask( pix.createHeuristicMask() );
5211 DestroyIcon( si );
5212 } else {
5213 pix = defaultFile;
5214 }
5215
5216 cache[ key ] = pix;
5217 return &pix;
5218 } else {
5219 HICON si;
5220 UINT res = 0;
5221 if ( !fi.absFilePath().isEmpty() ) {
5222#ifndef Q_OS_TEMP
5223 QT_WA( {
5224 res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1,
5225 0, 0, 1 );
5226 } , {
5227 res = ExtractIconExA( fi.absFilePath().local8Bit(), -1,
5228 0, 0, 1 );
5229 } );
5230
5231 if ( res ) {
5232 QT_WA( {
5233 res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1,
5234 0, &si, 1 );
5235 } , {
5236 res = ExtractIconExA( fi.absFilePath().local8Bit(), res - 1,
5237 0, &si, 1 );
5238 } );
5239 }
5240#else
5241 res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1,
5242 0, 0, 1 );
5243 if ( res )
5244 res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1,
5245 0, &si, 1 );
5246#endif
5247
5248 }
5249
5250 if ( res ) {
5251 pix.resize( pixw, pixh );
5252 initPixmap( pix );
5253 QPainter p( &pix );
5254 DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL );
5255 p.end();
5256 pix.setMask( pix.createHeuristicMask() );
5257 DestroyIcon( si );
5258 } else {
5259 pix = defaultExe;
5260 }
5261
5262 return &pix;
5263 }
5264
5265 // can't happen!
5266 return 0;
5267}
5268#endif
5269
5270
5271
5272/*!
5273 \reimp
5274*/
5275bool QFileDialog::eventFilter( QObject * o, QEvent * e )
5276{
5277 if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F5 ) {
5278 rereadDir();
5279 ((QKeyEvent *)e)->accept();
5280 return TRUE;
5281 } else if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F2 &&
5282 ( o == files || o == files->viewport() ) ) {
5283 if ( files->isVisible() && files->currentItem() ) {
5284 if ( QUrlInfo( d->url, "." ).isWritable() && files->currentItem()->text( 0 ) != ".." ) {
5285 files->renameItem = files->currentItem();
5286 files->startRename( TRUE );
5287 }
5288 }
5289 ((QKeyEvent *)e)->accept();
5290 return TRUE;
5291 } else if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F2 &&
5292 ( o == d->moreFiles || o == d->moreFiles->viewport() ) ) {
5293 if ( d->moreFiles->isVisible() && d->moreFiles->currentItem() != -1 ) {
5294 if ( QUrlInfo( d->url, "." ).isWritable() &&
5295 d->moreFiles->item( d->moreFiles->currentItem() )->text() != ".." ) {
5296 d->moreFiles->renameItem = d->moreFiles->item( d->moreFiles->currentItem() );
5297 d->moreFiles->startRename( TRUE );
5298 }
5299 }
5300 ((QKeyEvent *)e)->accept();
5301 return TRUE;
5302 } else if ( e->type() == QEvent::KeyPress && d->moreFiles->renaming ) {
5303 d->moreFiles->lined->setFocus();
5304 QApplication::sendEvent( d->moreFiles->lined, e );
5305 ((QKeyEvent *)e)->accept();
5306 return TRUE;
5307 } else if ( e->type() == QEvent::KeyPress && files->renaming ) {
5308 files->lined->setFocus();
5309 QApplication::sendEvent( files->lined, e );
5310 ((QKeyEvent *)e)->accept();
5311 return TRUE;
5312 } else if ( e->type() == QEvent::KeyPress &&
5313 ((QKeyEvent *)e)->key() == Key_Backspace &&
5314 ( o == files ||
5315 o == d->moreFiles ||
5316 o == files->viewport() ||
5317 o == d->moreFiles->viewport() ) ) {
5318 cdUpClicked();
5319 ((QKeyEvent *)e)->accept();
5320 return TRUE;
5321 } else if ( e->type() == QEvent::KeyPress &&
5322 ((QKeyEvent *)e)->key() == Key_Delete &&
5323 ( o == files ||
5324 o == files->viewport() ) ) {
5325 if ( files->currentItem() )
5326 deleteFile( files->currentItem()->text( 0 ) );
5327 ((QKeyEvent *)e)->accept();
5328 return TRUE;
5329 } else if ( e->type() == QEvent::KeyPress &&
5330 ((QKeyEvent *)e)->key() == Key_Delete &&
5331 ( o == d->moreFiles ||
5332 o == d->moreFiles->viewport() ) ) {
5333 int c = d->moreFiles->currentItem();
5334 if ( c >= 0 )
5335 deleteFile( d->moreFiles->item( c )->text() );
5336 ((QKeyEvent *)e)->accept();
5337 return TRUE;
5338 } else if ( o == files && e->type() == QEvent::FocusOut && files->currentItem() ) {
5339 } else if ( o == files && e->type() == QEvent::KeyPress ) {
5340 QTimer::singleShot( 0, this, SLOT(fixupNameEdit()) );
5341 } else if ( o == nameEdit && e->type() == QEvent::KeyPress && d->mode != AnyFile ) {
5342 if ( ( nameEdit->cursorPosition() == (int)nameEdit->text().length() || nameEdit->hasSelectedText() ) &&
5343 isprint(((QKeyEvent *)e)->ascii()) ) {
5344#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
5345 QString nt( nameEdit->text().lower() );
5346#else
5347 QString nt( nameEdit->text() );
5348#endif
5349 nt.truncate( nameEdit->cursorPosition() );
5350 nt += (char)(((QKeyEvent *)e)->ascii());
5351 QListViewItem * i = files->firstChild();
5352#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
5353 while( i && i->text( 0 ).left(nt.length()).lower() != nt )
5354#else
5355 while( i && i->text( 0 ).left(nt.length()) != nt )
5356#endif
5357 i = i->nextSibling();
5358 if ( i ) {
5359 nt = i->text( 0 );
5360 int cp = nameEdit->cursorPosition()+1;
5361 nameEdit->validateAndSet( nt, cp, cp, nt.length() );
5362 return TRUE;
5363 }
5364 }
5365 } else if ( o == nameEdit && e->type() == QEvent::FocusIn ) {
5366 fileNameEditDone();
5367 } else if ( d->moreFiles->renaming && o != d->moreFiles->lined && e->type() == QEvent::FocusIn ) {
5368 d->moreFiles->lined->setFocus();
5369 return TRUE;
5370 } else if ( files->renaming && o != files->lined && e->type() == QEvent::FocusIn ) {
5371 files->lined->setFocus();
5372 return TRUE;
5373 } else if ( ( o == d->moreFiles || o == d->moreFiles->viewport() ) &&
5374 e->type() == QEvent::FocusIn ) {
5375 if ( o == d->moreFiles->viewport() && !d->moreFiles->viewport()->hasFocus() ||
5376 o == d->moreFiles && !d->moreFiles->hasFocus() )
5377 ((QWidget*)o)->setFocus();
5378 return FALSE;
5379 }
5380
5381 return QDialog::eventFilter( o, e );
5382}
5383
5384/*!
5385 Sets the filters used in the file dialog to \a filters. Each group
5386 of filters must be separated by \c{;;} (\e two semi-colons).
5387
5388 \code
5389 QString types("Image files (*.png *.xpm *.jpg);;"
5390 "Text files (*.txt);;"
5391 "Any files (*)");
5392 QFileDialog fd = new QFileDialog( this );
5393 fd->setFilters( types );
5394 fd->show();
5395 \endcode
5396
5397*/
5398
5399void QFileDialog::setFilters( const QString &filters )
5400{
5401 QStringList lst = makeFiltersList( filters );
5402 setFilters( lst );
5403}
5404
5405/*!
5406 \overload
5407
5408 \a types must be a null-terminated list of strings.
5409
5410*/
5411
5412void QFileDialog::setFilters( const char ** types )
5413{
5414 if ( !types || !*types )
5415 return;
5416
5417 d->types->clear();
5418 while( types && *types ) {
5419 d->types->insertItem( QString::fromLatin1(*types) );
5420 types++;
5421 }
5422 d->types->setCurrentItem( 0 );
5423 setFilter( d->types->text( 0 ) );
5424}
5425
5426
5427/*! \overload void QFileDialog::setFilters( const QStringList & )
5428*/
5429
5430void QFileDialog::setFilters( const QStringList & types )
5431{
5432 if ( types.count() < 1 )
5433 return;
5434
5435 d->types->clear();
5436 for ( QStringList::ConstIterator it = types.begin(); it != types.end(); ++it )
5437 d->types->insertItem( *it );
5438 d->types->setCurrentItem( 0 );
5439 setFilter( d->types->text( 0 ) );
5440}
5441
5442/*!
5443 Adds the filter \a filter to the list of filters and makes it the
5444 current filter.
5445
5446 \code
5447 QFileDialog* fd = new QFileDialog( this );
5448 fd->addFilter( "Images (*.png *.jpg *.xpm)" );
5449 fd->show();
5450 \endcode
5451
5452 In the above example, a file dialog is created, and the file filter "Images
5453 (*.png *.jpg *.xpm)" is added and is set as the current filter. The original
5454 filter, "All Files (*)", is still available.
5455
5456 \sa setFilter(), setFilters()
5457*/
5458
5459void QFileDialog::addFilter( const QString &filter )
5460{
5461 if ( filter.isEmpty() )
5462 return;
5463 QString f = filter;
5464 QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) );
5465 int index = r.search( f );
5466 if ( index >= 0 )
5467 f = r.cap( 2 );
5468 for ( int i = 0; i < d->types->count(); ++i ) {
5469 QString f2( d->types->text( i ) );
5470 int index = r.search( f2 );
5471 if ( index >= 0 )
5472 f2 = r.cap( 1 );
5473 if ( f2 == f ) {
5474 d->types->setCurrentItem( i );
5475 setFilter( f2 );
5476 return;
5477 }
5478 }
5479
5480 d->types->insertItem( filter );
5481 d->types->setCurrentItem( d->types->count() - 1 );
5482 setFilter( d->types->text( d->types->count() - 1 ) );
5483}
5484
5485/*!
5486 Since modeButtons is a top-level widget, it may be destroyed by the
5487 kernel at application exit. Notice if this happens to
5488 avoid double deletion.
5489*/
5490
5491void QFileDialog::modeButtonsDestroyed()
5492{
5493 if ( d )
5494 d->modeButtons = 0;
5495}
5496
5497
5498/*!
5499 This is a convenience static function that will return one or more
5500 existing files selected by the user.
5501
5502 \code
5503 QStringList files = QFileDialog::getOpenFileNames(
5504 "Images (*.png *.xpm *.jpg)",
5505 "/home",
5506 this,
5507 "open files dialog"
5508 "Select one or more files to open" );
5509 \endcode
5510
5511 This function creates a modal file dialog called \a name, with
5512 parent \a parent. If \a parent is not 0, the dialog will be shown
5513 centered over the parent.
5514
5515 The file dialog's working directory will be set to \a dir. If \a
5516 dir includes a file name, the file will be selected. The filter
5517 is set to \a filter so that only those files which match the filter
5518 are shown. The filter selected is set to \a selectedFilter. The parameters
5519 \a dir, \a selectedFilter and \a filter may be QString::null.
5520
5521 The dialog's caption is set to \a caption. If \a caption is not
5522 specified then a default caption will be used.
5523
5524 Under Windows and Mac OS X, this static function will use the native
5525 file dialog and not a QFileDialog, unless the style of the application
5526 is set to something other than the native style. (Note that on Windows the
5527 dialog will spin a blocking modal event loop that will not dispatch any
5528 QTimers and if parent is not 0 then it will position the dialog just under
5529 the parent's titlebar).
5530
5531 Under Unix/X11, the normal behavior of the file dialog is to resolve
5532 and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp,
5533 the file dialog will change to /var/tmp after entering /usr/tmp.
5534 If \a resolveSymlinks is FALSE, the file dialog will treat
5535 symlinks as regular directories.
5536
5537 Note that if you want to iterate over the list of files, you should
5538 iterate over a copy, e.g.
5539 \code
5540 QStringList list = files;
5541 QStringList::Iterator it = list.begin();
5542 while( it != list.end() ) {
5543 myProcessing( *it );
5544 ++it;
5545 }
5546 \endcode
5547
5548 \sa getOpenFileName(), getSaveFileName(), getExistingDirectory()
5549*/
5550
5551QStringList QFileDialog::getOpenFileNames( const QString & filter,
5552 const QString& dir,
5553 QWidget *parent,
5554 const char* name,
5555 const QString& caption,
5556 QString *selectedFilter,
5557 bool resolveSymlinks )
5558{
5559 bool save_qt_resolve_symlinks = qt_resolve_symlinks;
5560 qt_resolve_symlinks = resolveSymlinks;
5561
5562 QStringList filters;
5563 if ( !filter.isEmpty() )
5564 filters = makeFiltersList( filter );
5565
5566 makeVariables();
5567
5568 if ( workingDirectory->isNull() )
5569 *workingDirectory = QDir::currentDirPath();
5570
5571 if ( !dir.isEmpty() ) {
5572 // #### works only correct for local files
5573 QUrlOperator u( QFileDialogPrivate::encodeFileName(dir) );
5574 if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) {
5575 *workingDirectory = dir;
5576 } else {
5577 *workingDirectory = u.toString();
5578 }
5579 }
5580
5581#if defined(Q_WS_WIN)
5582 if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle )
5583 return winGetOpenFileNames( filter, workingDirectory, parent, name, caption, selectedFilter );
5584#elif defined(Q_WS_MAC)
5585 if( qt_use_native_dialogs && ( qApp->style().inherits(QMAC_DEFAULT_STYLE) || qApp->style().inherits("QMacStyle") ) )
5586 return macGetOpenFileNames(filter, workingDirectory, parent, name, caption, selectedFilter );
5587#endif
5588
5589 QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gofns", TRUE );
5590
5591 Q_CHECK_PTR( dlg );
5592#ifndef QT_NO_WIDGET_TOPEXTRA
5593 if ( !caption.isNull() )
5594 dlg->setCaption( caption );
5595 else
5596 dlg->setCaption( QFileDialog::tr("Open") );
5597#endif
5598
5599 dlg->setFilters( filters );
5600 if ( selectedFilter )
5601 dlg->setFilter( *selectedFilter );
5602 dlg->setMode( QFileDialog::ExistingFiles );
5603 QString result;
5604 QStringList lst;
5605 if ( dlg->exec() == QDialog::Accepted ) {
5606 lst = dlg->selectedFiles();
5607 *workingDirectory = dlg->d->url;
5608 if ( selectedFilter )
5609 *selectedFilter = dlg->selectedFilter();
5610 }
5611 delete dlg;
5612
5613 qt_resolve_symlinks = save_qt_resolve_symlinks;
5614
5615 return lst;
5616}
5617
5618/*! Updates the line edit to match the speed-key usage in QListView. */
5619
5620void QFileDialog::fixupNameEdit()
5621{
5622 if ( files->currentItem() ) {
5623 if ( ( (QFileDialogPrivate::File*)files->currentItem() )->info.isFile() )
5624 nameEdit->setText( files->currentItem()->text( 0 ) );
5625 }
5626}
5627
5628/*!
5629 Returns the URL of the current working directory in the file dialog.
5630
5631 \sa setUrl()
5632*/
5633
5634QUrl QFileDialog::url() const
5635{
5636 return d->url;
5637}
5638
5639static bool isRoot( const QUrl &u )
5640{
5641#if defined(Q_OS_MAC9)
5642 QString p = QDir::convertSeparators(u.path());
5643 if(p.contains(':') == 1)
5644 return TRUE;
5645#elif defined(Q_OS_UNIX)
5646 if ( u.path() == "/" )
5647 return TRUE;
5648#elif defined(Q_OS_WIN32) || defined(Q_OS_OS2)
5649 QString p = u.path();
5650 if ( p.length() == 3 &&
5651 p.right( 2 ) == ":/" )
5652 return TRUE;
5653 if ( p[ 0 ] == '/' && p[ 1 ] == '/' ) {
5654 int slashes = p.contains( '/' );
5655 if ( slashes <= 3 )
5656 return TRUE;
5657 if ( slashes == 4 && p[ (int)p.length() - 1 ] == '/' )
5658 return TRUE;
5659 }
5660#else
5661#if defined(Q_CC_GNU)
5662#warning "case not covered.."
5663#endif
5664#endif
5665
5666 if ( !u.isLocalFile() && u.path() == "/" )
5667 return TRUE;
5668
5669 return FALSE;
5670}
5671
5672#if defined(Q_WS_WIN)
5673extern int qt_ntfs_permission_lookup;
5674#endif
5675
5676void QFileDialog::urlStart( QNetworkOperation *op )
5677{
5678 if ( !op )
5679 return;
5680
5681#if defined(Q_WS_WIN)
5682 qt_ntfs_permission_lookup--;
5683#endif
5684 if ( op->operation() == QNetworkProtocol::OpListChildren ) {
5685#ifndef QT_NO_CURSOR
5686 if ( !d->cursorOverride ) {
5687 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
5688 d->cursorOverride = TRUE;
5689 }
5690#endif
5691 if ( isRoot( d->url ) )
5692 d->cdToParent->setEnabled( FALSE );
5693 else
5694 d->cdToParent->setEnabled( TRUE );
5695 d->mimeTypeTimer->stop();
5696 d->sortedList.clear();
5697 d->pendingItems.clear();
5698 d->moreFiles->clearSelection();
5699 files->clearSelection();
5700 d->moreFiles->clear();
5701 files->clear();
5702 files->setSorting( -1 );
5703
5704 QString s = d->url.toString( FALSE, FALSE );
5705 bool found = FALSE;
5706 for ( int i = 0; i < d->paths->count(); ++i ) {
5707#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
5708 if ( d->paths->text( i ).lower() == s.lower() ) {
5709#else
5710 if ( d->paths->text( i ) == s ) {
5711#endif
5712 found = TRUE;
5713 d->paths->setCurrentItem( i );
5714 break;
5715 }
5716 }
5717 if ( !found ) {
5718 d->paths->insertItem( *openFolderIcon, s, -1 );
5719 d->paths->setCurrentItem( d->paths->count() - 1 );
5720 }
5721 d->last = 0;
5722 d->hadDotDot = FALSE;
5723
5724 if ( d->goBack && d->history.last() != d->url.toString() ) {
5725 d->history.append( d->url.toString() );
5726 if ( d->history.count() > 1 )
5727 d->goBack->setEnabled( TRUE );
5728 }
5729 }
5730}
5731
5732void QFileDialog::urlFinished( QNetworkOperation *op )
5733{
5734 if ( !op )
5735 return;
5736
5737#ifndef QT_NO_CURSOR
5738 if ( op->operation() == QNetworkProtocol::OpListChildren &&
5739 d->cursorOverride ) {
5740 QApplication::restoreOverrideCursor();
5741 d->cursorOverride = FALSE;
5742 }
5743#endif
5744
5745 if ( op->state() == QNetworkProtocol::StFailed ) {
5746 if ( d->paths->hasFocus() )
5747 d->ignoreNextKeyPress = TRUE;
5748
5749 if ( d->progressDia ) {
5750 d->ignoreStop = TRUE;
5751 d->progressDia->close();
5752 delete d->progressDia;
5753 d->progressDia = 0;
5754 }
5755
5756 QMessageBox::critical( this, tr( "Error" ), op->protocolDetail() );
5757
5758 int ecode = op->errorCode();
5759 if ( ecode == QNetworkProtocol::ErrListChildren || ecode == QNetworkProtocol::ErrParse ||
5760 ecode == QNetworkProtocol::ErrUnknownProtocol || ecode == QNetworkProtocol::ErrLoginIncorrect ||
5761 ecode == QNetworkProtocol::ErrValid || ecode == QNetworkProtocol::ErrHostNotFound ||
5762 ecode == QNetworkProtocol::ErrFileNotExisting ) {
5763 if (d->url != d->oldUrl) {
5764 d->url = d->oldUrl;
5765 rereadDir();
5766 }
5767 } else {
5768 // another error happened, no need to go back to last dir
5769 }
5770 } else if ( op->operation() == QNetworkProtocol::OpListChildren &&
5771 op == d->currListChildren ) {
5772 if ( !d->hadDotDot && !isRoot( d->url ) ) {
5773 bool ok = TRUE;
5774#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
5775 if ( d->url.path().left( 2 ) == "//" )
5776 ok = FALSE;
5777#endif
5778 if ( ok ) {
5779 QUrlInfo ui( d->url, ".." );
5780 ui.setName( ".." );
5781 ui.setDir( TRUE );
5782 ui.setFile( FALSE );
5783 ui.setSymLink( FALSE );
5784 ui.setSize( 0 );
5785 QValueList<QUrlInfo> lst;
5786 lst << ui;
5787 insertEntry( lst, 0 );
5788 }
5789 }
5790 resortDir();
5791 } else if ( op->operation() == QNetworkProtocol::OpGet ) {
5792 } else if ( op->operation() == QNetworkProtocol::OpPut ) {
5793 rereadDir();
5794 if ( d->progressDia ) {
5795 d->ignoreStop = TRUE;
5796 d->progressDia->close();
5797 }
5798 delete d->progressDia;
5799 d->progressDia = 0;
5800 }
5801
5802#if defined(Q_WS_WIN)
5803 qt_ntfs_permission_lookup++;
5804#endif
5805}
5806
5807void QFileDialog::dataTransferProgress( int bytesDone, int bytesTotal, QNetworkOperation *op )
5808{
5809 if ( !op )
5810 return;
5811
5812 QString label;
5813 QUrl u( op->arg( 0 ) );
5814 if ( u.isLocalFile() ) {
5815 label = u.path();
5816 } else {
5817 label = QString( "%1 (on %2)" );
5818 label = label.arg( u.path() ).arg( u.host() );
5819 }
5820
5821 if ( !d->progressDia ) {
5822 if ( bytesDone < bytesTotal) {
5823 d->ignoreStop = FALSE;
5824 d->progressDia = new QFDProgressDialog( this, label, bytesTotal );
5825 connect( d->progressDia, SIGNAL( cancelled() ),
5826 this, SLOT( stopCopy() ) );
5827 d->progressDia->show();
5828 } else
5829 return;
5830 }
5831
5832 if ( d->progressDia ) {
5833 if ( op->operation() == QNetworkProtocol::OpGet ) {
5834 if ( d->progressDia ) {
5835 d->progressDia->setReadProgress( bytesDone );
5836 }
5837 } else if ( op->operation() == QNetworkProtocol::OpPut ) {
5838 if ( d->progressDia ) {
5839 d->progressDia->setWriteLabel( label );
5840 d->progressDia->setWriteProgress( bytesDone );
5841 }
5842 } else {
5843 return;
5844 }
5845 }
5846}
5847
5848void QFileDialog::insertEntry( const QValueList<QUrlInfo> &lst, QNetworkOperation *op )
5849{
5850 if ( op && op->operation() == QNetworkProtocol::OpListChildren &&
5851 op != d->currListChildren )
5852 return;
5853 QValueList<QUrlInfo>::ConstIterator it = lst.begin();
5854 for ( ; it != lst.end(); ++it ) {
5855 const QUrlInfo &inf = *it;
5856 if ( d->mode == DirectoryOnly && !inf.isDir() )
5857 continue;
5858 if ( inf.name() == ".." ) {
5859 d->hadDotDot = TRUE;
5860 if ( isRoot( d->url ) )
5861 continue;
5862#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
5863 if ( d->url.path().left( 2 ) == "//" )
5864 continue;
5865#endif
5866 } else if ( inf.name() == "." )
5867 continue;
5868
5869#if defined(Q_WS_WIN)
5870 // Workaround a Windows bug, '..' is apparantly hidden in directories
5871 // that are one level away from root
5872 if ( !bShowHiddenFiles && inf.name() != ".." ) {
5873 if ( d->url.isLocalFile() ) {
5874 QString file = d->url.path();
5875 if ( !file.endsWith( "/" ) )
5876 file.append( "/" );
5877 file += inf.name();
5878 QT_WA( {
5879 if ( GetFileAttributesW( (TCHAR*)file.ucs2() ) & FILE_ATTRIBUTE_HIDDEN )
5880 continue;
5881 } , {
5882 if ( GetFileAttributesA( file.local8Bit() ) & FILE_ATTRIBUTE_HIDDEN )
5883 continue;
5884 } );
5885 } else {
5886 if ( inf.name() != ".." && inf.name()[0] == QChar('.') )
5887 continue;
5888 }
5889 }
5890#elif defined(Q_OS_OS2)
5891 if ( !bShowHiddenFiles ) {
5892 if ( d->url.isLocalFile() ) {
5893 QString file = d->url.path();
5894 if ( !file.endsWith( "/" ) )
5895 file.append( "/" );
5896 file += inf.name();
5897 if ( QFileInfo( file ).isHidden() )
5898 continue;
5899 } else {
5900 if ( inf.name() != ".." && inf.name()[0] == QChar('.') )
5901 continue;
5902 }
5903 }
5904#else
5905 if ( !bShowHiddenFiles && inf.name() != ".." ) {
5906 if ( inf.name()[ 0 ] == QChar( '.' ) )
5907 continue;
5908 }
5909#endif
5910 if ( !d->url.isLocalFile() ) {
5911 QFileDialogPrivate::File * i = 0;
5912 QFileDialogPrivate::MCItem *i2 = 0;
5913 i = new QFileDialogPrivate::File( d, &inf, files );
5914 i2 = new QFileDialogPrivate::MCItem( d->moreFiles, i );
5915
5916 if ( d->mode == ExistingFiles && inf.isDir() ||
5917 ( isDirectoryMode( d->mode ) && inf.isFile() ) ) {
5918 i->setSelectable( FALSE );
5919 i2->setSelectable( FALSE );
5920 }
5921
5922 i->i = i2;
5923 }
5924
5925 d->sortedList.append( new QUrlInfo( inf ) );
5926 }
5927}
5928
5929void QFileDialog::removeEntry( QNetworkOperation *op )
5930{
5931 if ( !op )
5932 return;
5933
5934 QUrlInfo *i = 0;
5935 QListViewItemIterator it( files );
5936 bool ok1 = FALSE, ok2 = FALSE;
5937 for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) {
5938 if ( ( (QFileDialogPrivate::File*)it.current() )->info.name() == op->arg( 0 ) ) {
5939 d->pendingItems.removeRef( (QFileDialogPrivate::File*)it.current() );
5940 delete ( (QFileDialogPrivate::File*)it.current() )->i;
5941 delete it.current();
5942 ok1 = TRUE;
5943 }
5944 if ( i && i->name() == op->arg( 0 ) ) {
5945 d->sortedList.removeRef( i );
5946 i = d->sortedList.prev();
5947 ok2 = TRUE;
5948 }
5949 if ( ok1 && ok2 )
5950 break;
5951 }
5952}
5953
5954void QFileDialog::itemChanged( QNetworkOperation *op )
5955{
5956 if ( !op )
5957 return;
5958
5959 QUrlInfo *i = 0;
5960 QListViewItemIterator it1( files );
5961 bool ok1 = FALSE, ok2 = FALSE;
5962 // first check whether the new file replaces an existing file.
5963 for ( i = d->sortedList.first(); it1.current(); ++it1, i = d->sortedList.next() ) {
5964 if ( ( (QFileDialogPrivate::File*)it1.current() )->info.name() == op->arg( 1 ) ) {
5965 delete ( (QFileDialogPrivate::File*)it1.current() )->i;
5966 delete it1.current();
5967 ok1 = TRUE;
5968 }
5969 if ( i && i->name() == op->arg( 1 ) ) {
5970 d->sortedList.removeRef( i );
5971 i = d->sortedList.prev();
5972 ok2 = TRUE;
5973 }
5974 if ( ok1 && ok2 )
5975 break;
5976 }
5977
5978 i = 0;
5979 QListViewItemIterator it( files );
5980 ok1 = FALSE;
5981 ok2 = FALSE;
5982 for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) {
5983 if ( ( (QFileDialogPrivate::File*)it.current() )->info.name() == op->arg( 0 ) ) {
5984 ( (QFileDialogPrivate::File*)it.current() )->info.setName( op->arg( 1 ) );
5985 ok1 = TRUE;
5986 }
5987 if ( i && i->name() == op->arg( 0 ) ) {
5988 i->setName( op->arg( 1 ) );
5989 ok2 = TRUE;
5990 }
5991 if ( ok1 && ok2 )
5992 break;
5993 }
5994
5995 resortDir();
5996}
5997
5998/*!
5999 \property QFileDialog::infoPreview
6000
6001 \brief whether the file dialog can provide preview information about
6002 the currently selected file
6003
6004 The default is FALSE.
6005*/
6006bool QFileDialog::isInfoPreviewEnabled() const
6007{
6008 return d->infoPreview;
6009}
6010
6011void QFileDialog::setInfoPreviewEnabled( bool info )
6012{
6013 if ( info == d->infoPreview )
6014 return;
6015 d->geometryDirty = TRUE;
6016 d->infoPreview = info;
6017 updateGeometries();
6018}
6019
6020
6021/*!
6022 \property QFileDialog::contentsPreview
6023
6024 \brief whether the file dialog can provide a contents preview of the
6025 currently selected file
6026
6027 The default is FALSE.
6028
6029 \sa setContentsPreview() setInfoPreviewEnabled()
6030*/
6031// ### improve the above documentation: how is the preview done, how can I add
6032// support for customized preview, etc.
6033
6034bool QFileDialog::isContentsPreviewEnabled() const
6035{
6036 return d->contentsPreview;
6037}
6038
6039void QFileDialog::setContentsPreviewEnabled( bool contents )
6040{
6041 if ( contents == d->contentsPreview )
6042 return;
6043 d->geometryDirty = TRUE;
6044 d->contentsPreview = contents;
6045 updateGeometries();
6046}
6047
6048
6049/*!
6050 Sets the widget to be used for displaying information about the file
6051 to the widget \a w and a preview of that information to the
6052 QFilePreview \a preview.
6053
6054 Normally you would create a preview widget that derives from both QWidget and
6055 QFilePreview, so you should pass the same widget twice.
6056
6057 \code
6058 class Preview : public QLabel, public QFilePreview
6059 {
6060 public:
6061 Preview( QWidget *parent=0 ) : QLabel( parent ) {}
6062
6063 void previewUrl( const QUrl &u )
6064 {
6065 QString path = u.path();
6066 QPixmap pix( path );
6067 if ( pix.isNull() )
6068 setText( "This is not a pixmap" );
6069 else
6070 setText( "This is a pixmap" );
6071 }
6072 };
6073
6074 //...
6075
6076 int main( int argc, char** argv )
6077 {
6078 Preview* p = new Preview;
6079
6080 QFileDialog* fd = new QFileDialog( this );
6081 fd->setInfoPreviewEnabled( TRUE );
6082 fd->setInfoPreview( p, p );
6083 fd->setPreviewMode( QFileDialog::Info );
6084 fd->show();
6085 }
6086
6087 \endcode
6088
6089 \sa setContentsPreview(), setInfoPreviewEnabled(), setPreviewMode()
6090
6091*/
6092
6093void QFileDialog::setInfoPreview( QWidget *w, QFilePreview *preview )
6094{
6095 if ( !w || !preview )
6096 return;
6097
6098 if ( d->infoPreviewWidget ) {
6099 d->preview->removeWidget( d->infoPreviewWidget );
6100 delete d->infoPreviewWidget;
6101 }
6102 delete d->infoPreviewer;
6103 d->infoPreviewWidget = w;
6104 d->infoPreviewer = preview;
6105 w->reparent( d->preview, 0, QPoint( 0, 0 ) );
6106}
6107
6108/*!
6109 Sets the widget to be used for displaying the contents of the file
6110 to the widget \a w and a preview of those contents to the
6111 QFilePreview \a preview.
6112
6113 Normally you would create a preview widget that derives from both QWidget and
6114 QFilePreview, so you should pass the same widget twice.
6115
6116 \code
6117 class Preview : public QLabel, public QFilePreview
6118 {
6119 public:
6120 Preview( QWidget *parent=0 ) : QLabel( parent ) {}
6121
6122 void previewUrl( const QUrl &u )
6123 {
6124 QString path = u.path();
6125 QPixmap pix( path );
6126 if ( pix.isNull() )
6127 setText( "This is not a pixmap" );
6128 else
6129 setPixmap( pix );
6130 }
6131 };
6132
6133 //...
6134
6135 int main( int argc, char** argv )
6136 {
6137 Preview* p = new Preview;
6138
6139 QFileDialog* fd = new QFileDialog( this );
6140 fd->setContentsPreviewEnabled( TRUE );
6141 fd->setContentsPreview( p, p );
6142 fd->setPreviewMode( QFileDialog::Contents );
6143 fd->show();
6144 }
6145 \endcode
6146
6147 \sa setContentsPreviewEnabled(), setInfoPreview(), setPreviewMode()
6148*/
6149
6150void QFileDialog::setContentsPreview( QWidget *w, QFilePreview *preview )
6151{
6152 if ( !w || !preview )
6153 return;
6154
6155 if ( d->contentsPreviewWidget ) {
6156 d->preview->removeWidget( d->contentsPreviewWidget );
6157 delete d->contentsPreviewWidget;
6158 }
6159 delete d->contentsPreviewer;
6160 d->contentsPreviewWidget = w;
6161 d->contentsPreviewer = preview;
6162 w->reparent( d->preview, 0, QPoint( 0, 0 ) );
6163}
6164
6165/*!
6166 Re-sorts the displayed directory.
6167
6168 \sa rereadDir()
6169*/
6170
6171void QFileDialog::resortDir()
6172{
6173 d->mimeTypeTimer->stop();
6174 d->pendingItems.clear();
6175
6176 QFileDialogPrivate::File *item = 0;
6177 QFileDialogPrivate::MCItem *item2 = 0;
6178
6179 d->sortedList.sort();
6180
6181 if ( files->childCount() > 0 || d->moreFiles->count() > 0 ) {
6182 d->moreFiles->clear();
6183 files->clear();
6184 d->last = 0;
6185 files->setSorting( -1 );
6186 }
6187
6188 QUrlInfo *i = sortAscending ? d->sortedList.first() : d->sortedList.last();
6189 for ( ; i; i = sortAscending ? d->sortedList.next() : d->sortedList.prev() ) {
6190 item = new QFileDialogPrivate::File( d, i, files );
6191 item2 = new QFileDialogPrivate::MCItem( d->moreFiles, item, item2 );
6192 item->i = item2;
6193 d->pendingItems.append( item );
6194 if ( d->mode == ExistingFiles && item->info.isDir() ||
6195 ( isDirectoryMode( d->mode ) && item->info.isFile() ) ) {
6196 item->setSelectable( FALSE );
6197 item2->setSelectable( FALSE );
6198 }
6199 }
6200
6201 // ##### As the QFileIconProvider only support QFileInfo and no
6202 // QUrlInfo it can be only used for local files at the moment. In
6203 // 3.0 we have to change the API of QFileIconProvider to work on
6204 // QUrlInfo so that also remote filesystems can be show mime-type
6205 // specific icons.
6206 if ( d->url.isLocalFile() )
6207 d->mimeTypeTimer->start( 0 );
6208}
6209
6210/*!
6211 Stops the current copy operation.
6212*/
6213
6214void QFileDialog::stopCopy()
6215{
6216 if ( d->ignoreStop )
6217 return;
6218
6219 d->url.blockSignals( TRUE );
6220 d->url.stop();
6221 if ( d->progressDia ) {
6222 d->ignoreStop = TRUE;
6223 QTimer::singleShot( 100, this, SLOT( removeProgressDia() ) );
6224 }
6225 d->url.blockSignals( FALSE );
6226}
6227
6228/*!
6229 \internal
6230*/
6231
6232void QFileDialog::removeProgressDia()
6233{
6234 if ( d->progressDia )
6235 delete d->progressDia;
6236 d->progressDia = 0;
6237}
6238
6239/*!
6240 \internal
6241*/
6242
6243void QFileDialog::doMimeTypeLookup()
6244{
6245 if ( !iconProvider() ) {
6246 d->pendingItems.clear();
6247 d->mimeTypeTimer->stop();
6248 return;
6249 }
6250
6251 d->mimeTypeTimer->stop();
6252 if ( d->pendingItems.count() == 0 ) {
6253 return;
6254 }
6255
6256 QRect r;
6257 QFileDialogPrivate::File *item = d->pendingItems.first();
6258 if ( item ) {
6259 QFileInfo fi;
6260 if ( d->url.isLocalFile() ) {
6261 fi.setFile( QUrl( d->url.path(), QFileDialogPrivate::encodeFileName( item->info.name() ) ).path( FALSE ) );
6262 } else
6263 fi.setFile( item->info.name() ); // #####
6264 const QPixmap *p = iconProvider()->pixmap( fi );
6265 if ( p && p != item->pixmap( 0 ) &&
6266 ( !item->pixmap( 0 ) || p->serialNumber() != item->pixmap( 0 )->serialNumber() ) &&
6267 p != fifteenTransparentPixels ) {
6268 item->hasMimePixmap = TRUE;
6269
6270 // evil hack to avoid much too much repaints!
6271 QGuardedPtr<QFileDialog> that( this ); // this may be deleted by an event handler
6272 qApp->processEvents();
6273 if ( that.isNull() )
6274 return;
6275 files->setUpdatesEnabled( FALSE );
6276 files->viewport()->setUpdatesEnabled( FALSE );
6277 if ( item != d->pendingItems.first() )
6278 return;
6279 item->setPixmap( 0, *p );
6280 qApp->processEvents();
6281 if ( that.isNull() )
6282 return;
6283 files->setUpdatesEnabled( TRUE );
6284 files->viewport()->setUpdatesEnabled( TRUE );
6285
6286 if ( files->isVisible() ) {
6287 QRect ir( files->itemRect( item ) );
6288 if ( ir != QRect( 0, 0, -1, -1 ) ) {
6289 r = r.unite( ir );
6290 }
6291 } else {
6292 QRect ir( d->moreFiles->itemRect( item->i ) );
6293 if ( ir != QRect( 0, 0, -1, -1 ) ) {
6294 r = r.unite( ir );
6295 }
6296 }
6297 }
6298 if ( d->pendingItems.count() )
6299 d->pendingItems.removeFirst();
6300 }
6301
6302 if ( d->moreFiles->isVisible() ) {
6303 d->moreFiles->viewport()->repaint( r, FALSE );
6304 } else {
6305 files->viewport()->repaint( r, FALSE );
6306 }
6307
6308 if ( d->pendingItems.count() )
6309 d->mimeTypeTimer->start( 0 );
6310 else if ( d->moreFiles->isVisible() )
6311 d->moreFiles->triggerUpdate( TRUE );
6312}
6313
6314/*!
6315 If \a b is TRUE then all the files in the current directory are selected;
6316 otherwise, they are deselected.
6317*/
6318
6319void QFileDialog::selectAll( bool b )
6320{
6321 if ( d->mode != ExistingFiles )
6322 return;
6323 d->moreFiles->selectAll( b );
6324 files->selectAll( b );
6325}
6326
6327void QFileDialog::goBack()
6328{
6329 if ( !d->goBack || !d->goBack->isEnabled() )
6330 return;
6331 d->history.remove( d->history.last() );
6332 if ( d->history.count() < 2 )
6333 d->goBack->setEnabled( FALSE );
6334 setUrl( d->history.last() );
6335}
6336
6337// a class with wonderfully inflexible flexibility. why doesn't it
6338// just subclass QWidget in the first place? 'you have to derive your
6339// preview widget from QWidget and from this class' indeed.
6340
6341/*!
6342 \class QFilePreview qfiledialog.h
6343 \ingroup misc
6344 \brief The QFilePreview class provides file previewing in QFileDialog.
6345
6346 This class is an abstract base class which is used to implement
6347 widgets that can display a preview of a file in a QFileDialog.
6348
6349 You must derive the preview widget from both QWidget and from this
6350 class. Then you must reimplement this class's previewUrl() function,
6351 which is called by the file dialog if the preview of a file
6352 (specified as a URL) should be shown.
6353
6354 See also QFileDialog::setPreviewMode(), QFileDialog::setContentsPreview(),
6355 QFileDialog::setInfoPreview(), QFileDialog::setInfoPreviewEnabled(),
6356 QFileDialog::setContentsPreviewEnabled().
6357
6358 For an example of a preview widget see qt/examples/qdir/qdir.cpp.
6359*/
6360
6361/*!
6362 Constructs the QFilePreview.
6363*/
6364
6365QFilePreview::QFilePreview()
6366{
6367}
6368
6369/*!
6370 \fn void QFilePreview::previewUrl( const QUrl &url )
6371
6372 This function is called by QFileDialog if a preview
6373 for the \a url should be shown. Reimplement this
6374 function to provide file previewing.
6375*/
6376
6377
6378#include "qfiledialog.moc"
6379
6380#endif
Note: See TracBrowser for help on using the repository browser.