source: branches/4.5.1/src/gui/dialogs/qfiledialog_win.cpp

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

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

File size: 28.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfiledialog.h"
43
44#ifndef QT_NO_FILEDIALOG
45
46#include <private/qfiledialog_p.h>
47#include <qapplication.h>
48#include <private/qapplication_p.h>
49#include <qt_windows.h>
50#include <qglobal.h>
51#include <qregexp.h>
52#include <qbuffer.h>
53#include <qdir.h>
54#include <qstringlist.h>
55#include <qlibrary.h>
56
57#ifndef QT_NO_THREAD
58# include <private/qmutexpool_p.h>
59#endif
60
61#include <shlobj.h>
62
63#ifdef Q_OS_WINCE
64#include <commdlg.h>
65# ifndef BFFM_SETSELECTION
66# define BFFM_SETSELECTION (WM_USER + 102)
67# endif
68// Windows Mobile has a broken definition for BROWSEINFO
69// Only compile fix
70typedef struct qt_priv_browseinfo {
71 HWND hwndOwner;
72 LPCITEMIDLIST pidlRoot;
73 LPTSTR pszDisplayName;
74 LPCTSTR lpszTitle;
75 UINT ulFlags;
76 BFFCALLBACK lpfn;
77 LPARAM lParam;
78 int iImage;
79} qt_BROWSEINFO;
80bool qt_priv_ptr_valid = false;
81#endif
82
83
84// Don't remove the lines below!
85//
86// resolving the W methods manually is needed, because Windows 95 doesn't include
87// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol
88// when Qt calls getExistingDirectory(), etc.
89typedef LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(BROWSEINFO*);
90static PtrSHBrowseForFolder ptrSHBrowseForFolder = 0;
91typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(LPITEMIDLIST,LPWSTR);
92static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 0;
93
94QT_BEGIN_NAMESPACE
95
96static void qt_win_resolve_libs()
97{
98 static bool triedResolve = false;
99
100 if (!triedResolve) {
101#ifndef QT_NO_THREAD
102 // protect initialization
103 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
104 // check triedResolve again, since another thread may have already
105 // done the initialization
106 if (triedResolve) {
107 // another thread did initialize the security function pointers,
108 // so we shouldn't do it again.
109 return;
110 }
111#endif
112
113 triedResolve = true;
114 if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
115#if !defined(Q_OS_WINCE)
116 QLibrary lib(QLatin1String("shell32"));
117 ptrSHBrowseForFolder = (PtrSHBrowseForFolder) lib.resolve("SHBrowseForFolderW");
118 ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList) lib.resolve("SHGetPathFromIDListW");
119#else
120 // CE stores them in a different lib and does not use unicode version
121 HINSTANCE handle = LoadLibraryW(L"Ceshell");
122 ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder");
123 ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList");
124 if (ptrSHBrowseForFolder && ptrSHGetPathFromIDList)
125 qt_priv_ptr_valid = true;
126#endif
127 }
128 }
129}
130
131extern const char* qt_file_dialog_filter_reg_exp; // defined in qfiledialog.cpp
132extern QStringList qt_make_filter_list(const QString &filter);
133
134const int maxNameLen = 1023;
135const int maxMultiLen = 65535;
136
137// Returns the wildcard part of a filter.
138static QString qt_win_extract_filter(const QString &rawFilter)
139{
140 QString result = rawFilter;
141 QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
142 int index = r.indexIn(result);
143 if (index >= 0)
144 result = r.cap(2);
145 QStringList list = result.split(QLatin1Char(' '));
146 for(QStringList::iterator it = list.begin(); it < list.end(); ++it) {
147 if (*it == QLatin1String("*")) {
148 *it = QLatin1String("*.*");
149 break;
150 }
151 }
152 return list.join(QLatin1String(";"));
153}
154
155static QStringList qt_win_make_filters_list(const QString &filter)
156{
157 QString f(filter);
158
159 if (f.isEmpty())
160 f = QFileDialog::tr("All Files (*.*)");
161
162 return qt_make_filter_list(f);
163}
164
165// Makes a NUL-oriented Windows filter from a Qt filter.
166static QString qt_win_filter(const QString &filter)
167{
168 QStringList filterLst = qt_win_make_filters_list(filter);
169 QStringList::Iterator it = filterLst.begin();
170 QString winfilters;
171 for (; it != filterLst.end(); ++it) {
172 QString subfilter = *it;
173 if (!subfilter.isEmpty()) {
174 winfilters += subfilter;
175 winfilters += QChar();
176 winfilters += qt_win_extract_filter(subfilter);
177 winfilters += QChar();
178 }
179 }
180 winfilters += QChar();
181 return winfilters;
182}
183
184static QString qt_win_selected_filter(const QString &filter, DWORD idx)
185{
186 return qt_win_make_filters_list(filter).at((int)idx - 1);
187}
188
189#ifndef Q_OS_WINCE
190// Static vars for OFNA funcs:
191static QByteArray aInitDir;
192static QByteArray aInitSel;
193static QByteArray aTitle;
194static QByteArray aFilter;
195// Use ANSI strings and API
196
197// If you change this, then make sure you change qt_win_make_OFN (below) too
198static OPENFILENAMEA *qt_win_make_OFNA(QWidget *parent,
199 const QString &initialSelection,
200 const QString &initialDirectory,
201 const QString &title,
202 const QString &filters,
203 QFileDialog::FileMode mode,
204 QFileDialog::Options options)
205{
206 if (parent)
207 parent = parent->window();
208 else
209 parent = qApp->activeWindow();
210
211 aTitle = title.toLocal8Bit();
212 aInitDir = QDir::toNativeSeparators(initialDirectory).toLocal8Bit();
213 if (initialSelection.isEmpty()) {
214 aInitSel = "";
215 } else {
216 aInitSel = QDir::toNativeSeparators(initialSelection).toLocal8Bit();
217 aInitSel.replace("<", "");
218 aInitSel.replace(">", "");
219 aInitSel.replace("\"", "");
220 aInitSel.replace("|", "");
221 }
222 int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
223 aInitSel.resize(maxLen + 1); // make room for return value
224 aFilter = filters.toLocal8Bit();
225
226 OPENFILENAMEA* ofn = new OPENFILENAMEA;
227 memset(ofn, 0, sizeof(OPENFILENAMEA));
228
229#if defined(Q_CC_BOR) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0500)
230 // according to the MSDN, this should also be necessary for MSVC, but
231 // OPENFILENAME_SIZE_VERSION_400A is in not Microsoft header, as it seems
232 if (QApplication::winVersion()==Qt::WV_NT || QApplication::winVersion()&Qt::WV_DOS_based) {
233 ofn->lStructSize = OPENFILENAME_SIZE_VERSION_400A;
234 } else {
235 ofn->lStructSize = sizeof(OPENFILENAMEA);
236 }
237#else
238 ofn->lStructSize = sizeof(OPENFILENAMEA);
239#endif
240 Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
241 ofn->hwndOwner = parent ? parent->winId() : 0;
242 ofn->lpstrFilter = aFilter;
243 ofn->lpstrFile = aInitSel.data();
244 ofn->nMaxFile = maxLen;
245 ofn->lpstrInitialDir = aInitDir.data();
246 ofn->lpstrTitle = aTitle.data();
247 ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER);
248
249 if (mode == QFileDialog::ExistingFile ||
250 mode == QFileDialog::ExistingFiles)
251 ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
252 if (mode == QFileDialog::ExistingFiles)
253 ofn->Flags |= (OFN_ALLOWMULTISELECT);
254 if (!(options & QFileDialog::DontConfirmOverwrite))
255 ofn->Flags |= OFN_OVERWRITEPROMPT;
256
257 return ofn;
258}
259
260static void qt_win_clean_up_OFNA(OPENFILENAMEA **ofn)
261{
262 delete *ofn;
263 *ofn = 0;
264}
265#endif
266
267static QString tFilters, tTitle, tInitDir;
268
269#ifdef UNICODE
270// If you change this, then make sure you change qt_win_make_OFNA (above) too
271static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
272 const QString& initialSelection,
273 const QString& initialDirectory,
274 const QString& title,
275 const QString& filters,
276 QFileDialog::FileMode mode,
277 QFileDialog::Options options)
278{
279 if (parent)
280 parent = parent->window();
281 else
282 parent = qApp->activeWindow();
283
284 tInitDir = QDir::toNativeSeparators(initialDirectory);
285 tFilters = filters;
286 tTitle = title;
287 QString initSel = QDir::toNativeSeparators(initialSelection);
288 if (!initSel.isEmpty()) {
289 initSel.replace(QLatin1String("<"), QLatin1String(""));
290 initSel.replace(QLatin1String(">"), QLatin1String(""));
291 initSel.replace(QLatin1String("\""), QLatin1String(""));
292 initSel.replace(QLatin1String("|"), QLatin1String(""));
293 }
294
295 int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
296 TCHAR *tInitSel = new TCHAR[maxLen+1];
297 if (initSel.length() > 0 && initSel.length() <= maxLen)
298 memcpy(tInitSel, initSel.utf16(), (initSel.length()+1)*sizeof(QChar));
299 else
300 tInitSel[0] = 0;
301
302 OPENFILENAME* ofn = new OPENFILENAME;
303 memset(ofn, 0, sizeof(OPENFILENAME));
304
305#if defined(Q_CC_BOR) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0500)
306 // according to the MSDN, this should also be necessary for MSVC, but
307 // OPENFILENAME_SIZE_VERSION_400 is in not Microsoft header, as it seems
308 if (QApplication::winVersion()==Qt::WV_NT || QApplication::winVersion()&Qt::WV_DOS_based) {
309 ofn->lStructSize= OPENFILENAME_SIZE_VERSION_400;
310 } else {
311 ofn->lStructSize = sizeof(OPENFILENAME);
312 }
313#else
314 ofn->lStructSize = sizeof(OPENFILENAME);
315#endif
316 Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
317 ofn->hwndOwner = parent ? parent->winId() : 0;
318 ofn->lpstrFilter = (TCHAR *)tFilters.utf16();
319 ofn->lpstrFile = tInitSel;
320 ofn->nMaxFile = maxLen;
321 ofn->lpstrInitialDir = (TCHAR *)tInitDir.utf16();
322 ofn->lpstrTitle = (TCHAR *)tTitle.utf16();
323 ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER);
324 if (mode == QFileDialog::ExistingFile ||
325 mode == QFileDialog::ExistingFiles)
326 ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
327 if (mode == QFileDialog::ExistingFiles)
328 ofn->Flags |= (OFN_ALLOWMULTISELECT);
329 if (!(options & QFileDialog::DontConfirmOverwrite))
330 ofn->Flags |= OFN_OVERWRITEPROMPT;
331
332 return ofn;
333}
334
335
336static void qt_win_clean_up_OFN(OPENFILENAME **ofn)
337{
338 delete [] (*ofn)->lpstrFile;
339 delete *ofn;
340 *ofn = 0;
341}
342
343#endif // UNICODE
344
345extern void qt_win_eatMouseMove();
346
347QString qt_win_get_open_file_name(const QFileDialogArgs &args,
348 QString *initialDirectory,
349 QString *selectedFilter)
350{
351 QString result;
352
353 QString isel = args.selection;
354
355 if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
356 initialDirectory->remove(0, 5);
357 QFileInfo fi(*initialDirectory);
358
359 if (initialDirectory && !fi.isDir()) {
360 *initialDirectory = fi.absolutePath();
361 if (isel.isEmpty())
362 isel = fi.fileName();
363 }
364
365 if (!fi.exists())
366 *initialDirectory = QDir::homePath();
367
368 DWORD selFilIdx = 0;
369
370 int idx = 0;
371 if (selectedFilter) {
372 QStringList filterLst = qt_win_make_filters_list(args.filter);
373 idx = filterLst.indexOf(*selectedFilter);
374 }
375
376 QDialog modal_widget;
377 modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
378 modal_widget.setParent(args.parent, Qt::Window);
379 QApplicationPrivate::enterModal(&modal_widget);
380 QT_WA({
381 // Use Unicode strings and API
382 OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
383 args.directory, args.caption,
384 qt_win_filter(args.filter),
385 QFileDialog::ExistingFile,
386 args.options);
387 if (idx)
388 ofn->nFilterIndex = idx + 1;
389 if (GetOpenFileName(ofn)) {
390 result = QString::fromUtf16((ushort*)ofn->lpstrFile);
391 selFilIdx = ofn->nFilterIndex;
392 }
393 qt_win_clean_up_OFN(&ofn);
394 } , {
395 // Use ANSI strings and API
396 OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection,
397 args.directory, args.caption,
398 qt_win_filter(args.filter),
399 QFileDialog::ExistingFile,
400 args.options);
401 if (idx)
402 ofn->nFilterIndex = idx + 1;
403 if (GetOpenFileNameA(ofn)) {
404 result = QString::fromLocal8Bit(ofn->lpstrFile);
405 selFilIdx = ofn->nFilterIndex;
406 }
407 qt_win_clean_up_OFNA(&ofn);
408 });
409 QApplicationPrivate::leaveModal(&modal_widget);
410
411 qt_win_eatMouseMove();
412
413 if (result.isEmpty())
414 return result;
415
416 fi = result;
417 *initialDirectory = fi.path();
418 if (selectedFilter)
419 *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
420 return fi.absoluteFilePath();
421}
422
423QString qt_win_get_save_file_name(const QFileDialogArgs &args,
424 QString *initialDirectory,
425 QString *selectedFilter)
426{
427 QString result;
428
429 QString isel = args.selection;
430 if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
431 initialDirectory->remove(0, 5);
432 QFileInfo fi(*initialDirectory);
433
434 if (initialDirectory && !fi.isDir()) {
435 *initialDirectory = fi.absolutePath();
436 if (isel.isEmpty())
437 isel = fi.fileName();
438 }
439
440 if (!fi.exists())
441 *initialDirectory = QDir::homePath();
442
443 DWORD selFilIdx = 0;
444
445 int idx = 0;
446 if (selectedFilter) {
447 QStringList filterLst = qt_win_make_filters_list(args.filter);
448 idx = filterLst.indexOf(*selectedFilter);
449 }
450
451 QDialog modal_widget;
452 modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
453 modal_widget.setParent(args.parent, Qt::Window);
454 QApplicationPrivate::enterModal(&modal_widget);
455
456 // This block is used below for the lpstrDefExt member.
457 // Note that the current MSDN docs document this member wrong.
458 // It should rather be documented as "the default extension if no extension was given and if the
459 // current filter does not have a extension (e.g (*)). If the current filter have an extension, use
460 // the extension of the current filter"
461 QString defaultSaveExt;
462 if (selectedFilter && !selectedFilter->isEmpty()) {
463 defaultSaveExt = qt_win_extract_filter(*selectedFilter);
464 // make sure we only have the extension
465 int firstDot = defaultSaveExt.indexOf(QLatin1Char('.'));
466 if (firstDot != -1) {
467 defaultSaveExt.remove(0, firstDot + 1);
468 } else {
469 defaultSaveExt.clear();
470 }
471 }
472
473 QT_WA({
474 // Use Unicode strings and API
475 OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection,
476 args.directory, args.caption,
477 qt_win_filter(args.filter),
478 QFileDialog::AnyFile,
479 args.options);
480
481 ofn->lpstrDefExt = (TCHAR *)defaultSaveExt.utf16();
482
483 if (idx)
484 ofn->nFilterIndex = idx + 1;
485 if (GetSaveFileName(ofn)) {
486 result = QString::fromUtf16((ushort*)ofn->lpstrFile);
487 selFilIdx = ofn->nFilterIndex;
488 }
489 qt_win_clean_up_OFN(&ofn);
490 } , {
491 // Use ANSI strings and API
492 OPENFILENAMEA *ofn = qt_win_make_OFNA(args.parent, args.selection,
493 args.directory, args.caption,
494 qt_win_filter(args.filter),
495 QFileDialog::AnyFile,
496 args.options);
497 QByteArray asciiExt = defaultSaveExt.toAscii();
498 ofn->lpstrDefExt = asciiExt.data();
499
500 if (idx)
501 ofn->nFilterIndex = idx + 1;
502 if (GetSaveFileNameA(ofn)) {
503 result = QString::fromLocal8Bit(ofn->lpstrFile);
504 selFilIdx = ofn->nFilterIndex;
505 }
506 qt_win_clean_up_OFNA(&ofn);
507 });
508#if defined(Q_OS_WINCE)
509 int semIndex = result.indexOf(QLatin1Char(';'));
510 if (semIndex >= 0)
511 result = result.left(semIndex);
512#endif
513
514 QApplicationPrivate::leaveModal(&modal_widget);
515
516 qt_win_eatMouseMove();
517
518 if (result.isEmpty())
519 return result;
520
521 fi = result;
522 *initialDirectory = fi.path();
523 if (selectedFilter)
524 *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
525 return fi.absoluteFilePath();
526}
527
528QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
529 QString *initialDirectory,
530 QString *selectedFilter)
531{
532 QStringList result;
533 QFileInfo fi;
534 QDir dir;
535 QString isel;
536
537 if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
538 initialDirectory->remove(0, 5);
539 fi = QFileInfo(*initialDirectory);
540
541 if (initialDirectory && !fi.isDir()) {
542 *initialDirectory = fi.absolutePath();
543 isel = fi.fileName();
544 }
545
546 if (!fi.exists())
547 *initialDirectory = QDir::homePath();
548
549 DWORD selFilIdx = 0;
550
551 int idx = 0;
552 if (selectedFilter) {
553 QStringList filterLst = qt_win_make_filters_list(args.filter);
554 idx = filterLst.indexOf(*selectedFilter);
555 }
556
557 QDialog modal_widget;
558 modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
559 modal_widget.setParent(args.parent, Qt::Window);
560 QApplicationPrivate::enterModal(&modal_widget);
561 QT_WA({
562 OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
563 args.directory, args.caption,
564 qt_win_filter(args.filter),
565 QFileDialog::ExistingFiles,
566 args.options);
567 if (idx)
568 ofn->nFilterIndex = idx + 1;
569 if (GetOpenFileName(ofn)) {
570 QString fileOrDir = QString::fromUtf16((ushort*)ofn->lpstrFile);
571 selFilIdx = ofn->nFilterIndex;
572 int offset = fileOrDir.length() + 1;
573 if (ofn->lpstrFile[offset] == 0) {
574 // Only one file selected; has full path
575 fi.setFile(fileOrDir);
576 QString res = fi.absoluteFilePath();
577 if (!res.isEmpty())
578 result.append(res);
579 }
580 else {
581 // Several files selected; first string is path
582 dir.setPath(fileOrDir);
583 QString f;
584 while(!(f = QString::fromUtf16((ushort*)ofn->lpstrFile+offset)).isEmpty()) {
585 fi.setFile(dir, f);
586 QString res = fi.absoluteFilePath();
587 if (!res.isEmpty())
588 result.append(res);
589 offset += f.length() + 1;
590 }
591 }
592 }
593 qt_win_clean_up_OFN(&ofn);
594 } , {
595 OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection,
596 args.directory, args.caption,
597 qt_win_filter(args.filter),
598 QFileDialog::ExistingFiles,
599 args.options);
600 if (idx)
601 ofn->nFilterIndex = idx + 1;
602 if (GetOpenFileNameA(ofn)) {
603 QByteArray fileOrDir(ofn->lpstrFile);
604 selFilIdx = ofn->nFilterIndex;
605 int offset = fileOrDir.length() + 1;
606 if (ofn->lpstrFile[offset] == '\0') {
607 // Only one file selected; has full path
608 fi.setFile(QString::fromLocal8Bit(fileOrDir));
609 QString res = fi.absoluteFilePath();
610 if (!res.isEmpty())
611 result.append(res);
612 }
613 else {
614 // Several files selected; first string is path
615 dir.setPath(QString::fromLocal8Bit(fileOrDir));
616 QByteArray f;
617 while (!(f = QByteArray(ofn->lpstrFile + offset)).isEmpty()) {
618 fi.setFile(dir, QString::fromLocal8Bit(f));
619 QString res = fi.absoluteFilePath();
620 if (!res.isEmpty())
621 result.append(res);
622 offset += f.length() + 1;
623 }
624 }
625 qt_win_clean_up_OFNA(&ofn);
626 }
627 });
628 QApplicationPrivate::leaveModal(&modal_widget);
629
630 qt_win_eatMouseMove();
631
632 if (!result.isEmpty()) {
633 *initialDirectory = fi.path(); // only save the path if there is a result
634 if (selectedFilter)
635 *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
636 }
637 return result;
638}
639
640// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
641
642static int __stdcall winGetExistDirCallbackProc(HWND hwnd,
643 UINT uMsg,
644 LPARAM lParam,
645 LPARAM lpData)
646{
647 if (uMsg == BFFM_INITIALIZED && lpData != 0) {
648 QString *initDir = (QString *)(lpData);
649 if (!initDir->isEmpty()) {
650 // ### Lars asks: is this correct for the A version????
651 QT_WA({
652 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
653 } , {
654 SendMessageA(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
655 });
656 }
657 } else if (uMsg == BFFM_SELCHANGED) {
658 QT_WA({
659 qt_win_resolve_libs();
660 TCHAR path[MAX_PATH];
661 ptrSHGetPathFromIDList(LPITEMIDLIST(lParam), path);
662 QString tmpStr = QString::fromUtf16((ushort*)path);
663 if (!tmpStr.isEmpty())
664 SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
665 else
666 SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
667 SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
668 } , {
669 char path[MAX_PATH];
670 SHGetPathFromIDListA(LPITEMIDLIST(lParam), path);
671 QString tmpStr = QString::fromLocal8Bit(path);
672 if (!tmpStr.isEmpty())
673 SendMessageA(hwnd, BFFM_ENABLEOK, 1, 1);
674 else
675 SendMessageA(hwnd, BFFM_ENABLEOK, 0, 0);
676 SendMessageA(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
677 });
678 }
679 return 0;
680}
681
682#ifndef BIF_NEWDIALOGSTYLE
683#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
684#endif
685
686
687QString qt_win_get_existing_directory(const QFileDialogArgs &args)
688{
689 QString currentDir = QDir::currentPath();
690 QString result;
691 QWidget *parent = args.parent;
692 if (parent)
693 parent = parent->window();
694 else
695 parent = qApp->activeWindow();
696 if (parent)
697 parent->createWinId();
698
699 QDialog modal_widget;
700 modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
701 modal_widget.setParent(parent, Qt::Window);
702 QApplicationPrivate::enterModal(&modal_widget);
703#if !defined(Q_OS_WINCE)
704 QT_WA({
705 qt_win_resolve_libs();
706 QString initDir = QDir::toNativeSeparators(args.directory);
707 TCHAR path[MAX_PATH];
708 TCHAR initPath[MAX_PATH];
709 initPath[0] = 0;
710 path[0] = 0;
711 tTitle = args.caption;
712 BROWSEINFO bi;
713 Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
714 bi.hwndOwner = (parent ? parent->winId() : 0);
715 bi.pidlRoot = NULL;
716 //### This does not seem to be respected? - the dialog always displays "Browse for folder"
717 bi.lpszTitle = (TCHAR*)tTitle.utf16();
718 bi.pszDisplayName = initPath;
719 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
720 bi.lpfn = winGetExistDirCallbackProc;
721 bi.lParam = LPARAM(&initDir);
722 if (ptrSHBrowseForFolder) {
723 LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
724 if (pItemIDList && ptrSHGetPathFromIDList) {
725 ptrSHGetPathFromIDList(pItemIDList, path);
726 IMalloc *pMalloc;
727 if (SHGetMalloc(&pMalloc) != NOERROR)
728 result = QString();
729 else {
730 pMalloc->Free(pItemIDList);
731 pMalloc->Release();
732 result = QString::fromUtf16((ushort*)path);
733 }
734 } else
735 result = QString();
736 }
737 tTitle = QString();
738 } , {
739 QString initDir = QDir::toNativeSeparators(args.directory);
740 char path[MAX_PATH];
741 char initPath[MAX_PATH];
742 QByteArray ctitle = args.caption.toLocal8Bit();
743 initPath[0]=0;
744 path[0]=0;
745 BROWSEINFOA bi;
746 Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
747 bi.hwndOwner = (parent ? parent->winId() : 0);
748 bi.pidlRoot = NULL;
749 bi.lpszTitle = ctitle;
750 bi.pszDisplayName = initPath;
751 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
752 bi.lpfn = winGetExistDirCallbackProc;
753 bi.lParam = LPARAM(&initDir);
754 LPITEMIDLIST pItemIDList = SHBrowseForFolderA(&bi);
755 if (pItemIDList) {
756 SHGetPathFromIDListA(pItemIDList, path);
757 IMalloc *pMalloc;
758 if (SHGetMalloc(&pMalloc) != NOERROR)
759 result = QString();
760 else {
761 pMalloc->Free(pItemIDList);
762 pMalloc->Release();
763 result = QString::fromLocal8Bit(path);
764 }
765 } else
766 result = QString();
767 });
768#else
769 qt_win_resolve_libs();
770 QString initDir = QDir::toNativeSeparators(args.directory);
771 TCHAR path[MAX_PATH];
772 TCHAR initPath[MAX_PATH];
773 memset(initPath, 0 , MAX_PATH*sizeof(TCHAR));
774 memset(path, 0, MAX_PATH*sizeof(TCHAR));
775 tTitle = args.caption;
776 qt_BROWSEINFO bi;
777 Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
778 bi.hwndOwner = (parent ? parent->winId() : 0);
779 bi.pidlRoot = NULL;
780 bi.lpszTitle = (TCHAR*)tTitle.utf16();
781 bi.pszDisplayName = initPath;
782 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
783 bi.lpfn = winGetExistDirCallbackProc;
784 bi.lParam = LPARAM(&initDir);
785 if (ptrSHBrowseForFolder) {
786 LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder((BROWSEINFO*)&bi);
787 if (pItemIDList && ptrSHGetPathFromIDList) {
788 ptrSHGetPathFromIDList(pItemIDList, path);
789 IMalloc *pMalloc;
790 if (SHGetMalloc(&pMalloc) != NOERROR)
791 result = QString();
792 else {
793 pMalloc->Free(pItemIDList);
794 pMalloc->Release();
795 result = QString::fromUtf16((ushort*)path);
796 }
797 } else
798 result = QString();
799 }
800 tTitle = QString();
801
802#endif
803 QApplicationPrivate::leaveModal(&modal_widget);
804
805 qt_win_eatMouseMove();
806
807 // Due to a bug on Windows Me, we need to reset the current
808 // directory
809 if ((QSysInfo::WindowsVersion == QSysInfo::WV_98 || QSysInfo::WindowsVersion == QSysInfo::WV_Me)
810 && QDir::currentPath() != currentDir)
811 QDir::setCurrent(currentDir);
812
813 if (!result.isEmpty())
814 result.replace(QLatin1String("\\"), QLatin1String("/"));
815 return result;
816}
817
818
819QT_END_NAMESPACE
820
821#endif
Note: See TracBrowser for help on using the repository browser.