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

Last change on this file since 802 was 769, checked in by Dmitry A. Kuminov, 15 years ago

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

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