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