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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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