source: trunk/src/qt3support/dialogs/q3filedialog.cpp@ 318

Last change on this file since 318 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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