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

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

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

File size: 15.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 "q3filedialog.h"
43
44#ifndef QT_NO_FILEDIALOG
45
46#include "qapplication.h"
47#include "private/qapplication_p.h"
48#include "qt_windows.h"
49#include "qregexp.h"
50#include "qbuffer.h"
51#include "qdir.h"
52#include "qstringlist.h"
53#include "qlibrary.h"
54
55#ifndef QT_NO_THREAD
56# include "private/qmutexpool_p.h"
57#endif
58
59#include <shlobj.h>
60
61#ifdef Q_OS_WINCE
62#include <commdlg.h>
63#endif
64
65QT_BEGIN_NAMESPACE
66
67extern const char qt3_file_dialog_filter_reg_exp[]; // defined in qfiledialog.cpp
68
69const int maxNameLen = 1023;
70const int maxMultiLen = 65535;
71
72// Returns the wildcard part of a filter.
73static QString extractFilter(const QString& rawFilter)
74{
75 QString result = rawFilter;
76 QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
77 int index = r.indexIn(result);
78 if (index >= 0)
79 result = r.cap(2);
80 return result.replace(QLatin1Char(' '), QLatin1Char(';'));
81}
82
83// Makes a list of filters from ;;-separated text.
84static QStringList makeFiltersList(const QString &filter)
85{
86 QString f(filter);
87
88 if (f.isEmpty())
89 f = Q3FileDialog::tr("All Files (*.*)");
90
91 if (f.isEmpty())
92 return QStringList();
93
94 int i = f.find(QLatin1String(";;"), 0);
95 QString sep(QLatin1String(";;"));
96 if (i == -1) {
97 if (f.find(QLatin1String("\n"), 0) != -1) {
98 sep = QLatin1String("\n");
99 i = f.find(sep, 0);
100 }
101 }
102
103 return QStringList::split(sep, f );
104}
105
106// Makes a NUL-oriented Windows filter from a Qt filter.
107static QString winFilter(const QString& filter)
108{
109 QStringList filterLst = makeFiltersList(filter);
110 QStringList::Iterator it = filterLst.begin();
111 QString winfilters;
112 for (; it != filterLst.end(); ++it) {
113 winfilters += *it;
114 winfilters += QChar::null;
115 winfilters += extractFilter(*it);
116 winfilters += QChar::null;
117 }
118 winfilters += QChar::null;
119 return winfilters;
120}
121
122static QString selFilter(const QString& filter, DWORD idx)
123{
124 QStringList filterLst = makeFiltersList(filter);
125 return filterLst[(int)idx - 1];
126}
127
128static QString tFilters, tTitle, tInitDir;
129
130static
131OPENFILENAME* makeOFN(QWidget* parent,
132 const QString& initialSelection,
133 const QString& initialDirectory,
134 const QString& title,
135 const QString& filters,
136 Q3FileDialog::Mode mode)
137{
138 if (parent)
139 parent = parent->window();
140 else
141 parent = qApp->activeWindow();
142
143 tInitDir = QDir::toNativeSeparators(initialDirectory);
144 tFilters = filters;
145 tTitle = title;
146 QString initSel = QDir::toNativeSeparators(initialSelection);
147
148 int maxLen = mode == Q3FileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
149 wchar_t *tInitSel = new wchar_t[maxLen+1];
150 if (initSel.length() > 0 && initSel.length() <= maxLen)
151 memcpy(tInitSel, initSel.utf16(), (initSel.length() + 1) * sizeof(wchar_t));
152 else
153 tInitSel[0] = 0;
154
155 OPENFILENAME* ofn = new OPENFILENAME;
156 memset(ofn, 0, sizeof(OPENFILENAME));
157
158 ofn->lStructSize = sizeof(OPENFILENAME);
159 ofn->hwndOwner = parent ? parent->winId() : 0;
160 ofn->lpstrFilter = (wchar_t*)tFilters.utf16();
161 ofn->lpstrFile = tInitSel;
162 ofn->nMaxFile = maxLen;
163 ofn->lpstrInitialDir = (wchar_t*)tInitDir.utf16();
164 ofn->lpstrTitle = (wchar_t*)tTitle.utf16();
165 ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY);
166
167 if (mode == Q3FileDialog::ExistingFile ||
168 mode == Q3FileDialog::ExistingFiles)
169 ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
170 if (mode == Q3FileDialog::ExistingFiles)
171 ofn->Flags |= (OFN_ALLOWMULTISELECT | OFN_EXPLORER);
172
173 return ofn;
174}
175
176static void cleanUpOFN(OPENFILENAME** ofn)
177{
178 delete (*ofn)->lpstrFile;
179 delete *ofn;
180 *ofn = 0;
181}
182
183QString Q3FileDialog::winGetOpenFileName(const QString &initialSelection,
184 const QString &filter,
185 QString* initialDirectory,
186 QWidget *parent, const char* /*name*/,
187 const QString& caption,
188 QString* selectedFilter)
189{
190 QString result;
191
192 QString isel = initialSelection;
193
194 if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
195 initialDirectory->remove(0, 5);
196 QFileInfo fi(*initialDirectory);
197
198 if (initialDirectory && !fi.isDir()) {
199 *initialDirectory = fi.dirPath(true);
200 if (isel.isEmpty())
201 isel = fi.fileName();
202 }
203
204 if (!fi.exists())
205 *initialDirectory = QDir::homeDirPath();
206
207 QString title = caption;
208 if (title.isNull())
209 title = tr("Open");
210
211 DWORD selFilIdx = 0;
212
213 int idx = 0;
214 if (selectedFilter && !selectedFilter->isEmpty()) {
215 QStringList filterLst = makeFiltersList(filter);
216 idx = filterLst.findIndex(*selectedFilter);
217 }
218
219 if (parent) {
220 QEvent e(QEvent::WindowBlocked);
221 QApplication::sendEvent(parent, &e);
222 QApplicationPrivate::enterModal(parent);
223 }
224
225 OPENFILENAME* ofn = makeOFN(parent, isel,
226 *initialDirectory, title,
227 winFilter(filter), ExistingFile);
228 if (idx)
229 ofn->nFilterIndex = idx + 1;
230 if (GetOpenFileName(ofn)) {
231 result = QString::fromWCharArray(ofn->lpstrFile);
232 selFilIdx = ofn->nFilterIndex;
233 }
234 cleanUpOFN(&ofn);
235
236 if (parent) {
237 QApplicationPrivate::leaveModal(parent);
238 QEvent e(QEvent::WindowUnblocked);
239 QApplication::sendEvent(parent, &e);
240 }
241
242 if (result.isEmpty()) {
243 return result;
244 }
245 else {
246 QFileInfo fi(result);
247 *initialDirectory = fi.dirPath();
248 if (selectedFilter)
249 *selectedFilter = selFilter(filter, selFilIdx);
250 return fi.absFilePath();
251 }
252}
253
254
255QString Q3FileDialog::winGetSaveFileName(const QString &initialSelection,
256 const QString &filter,
257 QString* initialDirectory,
258 QWidget *parent, const char* /*name*/,
259 const QString& caption,
260 QString* selectedFilter)
261{
262 QString result;
263
264 QString isel = initialSelection;
265 if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
266 initialDirectory->remove(0, 5);
267 QFileInfo fi(*initialDirectory);
268
269 if (initialDirectory && !fi.isDir()) {
270 *initialDirectory = fi.dirPath(true);
271 if (isel.isEmpty())
272 isel = fi.fileName();
273 }
274
275 if (!fi.exists())
276 *initialDirectory = QDir::homeDirPath();
277
278 QString title = caption;
279 if (title.isNull())
280 title = tr("Save As");
281
282 DWORD selFilIdx = 0;
283
284 int idx = 0;
285 if (selectedFilter && !selectedFilter->isEmpty()) {
286 QStringList filterLst = makeFiltersList(filter);
287 idx = filterLst.findIndex(*selectedFilter);
288 }
289
290 if (parent) {
291 QEvent e(QEvent::WindowBlocked);
292 QApplication::sendEvent(parent, &e);
293 QApplicationPrivate::enterModal(parent);
294 }
295
296 OPENFILENAME* ofn = makeOFN(parent, isel,
297 *initialDirectory, title,
298 winFilter(filter), AnyFile);
299 if (idx)
300 ofn->nFilterIndex = idx + 1;
301 if (GetSaveFileName(ofn)) {
302 result = QString::fromWCharArray(ofn->lpstrFile);
303 selFilIdx = ofn->nFilterIndex;
304 }
305 cleanUpOFN(&ofn);
306
307 if (parent) {
308 QApplicationPrivate::leaveModal(parent);
309 QEvent e(QEvent::WindowUnblocked);
310 QApplication::sendEvent(parent, &e);
311 }
312
313 if (result.isEmpty()) {
314 return result;
315 }
316 else {
317 QFileInfo fi(result);
318 *initialDirectory = fi.dirPath();
319 if (selectedFilter)
320 *selectedFilter = selFilter(filter, selFilIdx);
321 return fi.absFilePath();
322 }
323}
324
325
326
327QStringList Q3FileDialog::winGetOpenFileNames(const QString &filter,
328 QString* initialDirectory,
329 QWidget *parent,
330 const char* /*name*/,
331 const QString& caption,
332 QString* selectedFilter)
333{
334 QStringList result;
335 QFileInfo fi;
336 QDir dir;
337 QString isel;
338
339 if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
340 initialDirectory->remove(0, 5);
341 fi = QFileInfo(*initialDirectory);
342
343 if (initialDirectory && !fi.isDir()) {
344 *initialDirectory = fi.dirPath(true);
345 isel = fi.fileName();
346 }
347
348 if (!fi.exists())
349 *initialDirectory = QDir::homeDirPath();
350
351 QString title = caption;
352 if (title.isNull())
353 title = tr("Open ");
354
355 DWORD selFilIdx = 0;
356
357 int idx = 0;
358 if (selectedFilter && !selectedFilter->isEmpty()) {
359 QStringList filterLst = makeFiltersList(filter);
360 idx = filterLst.findIndex(*selectedFilter);
361 }
362
363 if (parent) {
364 QEvent e(QEvent::WindowBlocked);
365 QApplication::sendEvent(parent, &e);
366 QApplicationPrivate::enterModal(parent);
367 }
368
369 OPENFILENAME* ofn = makeOFN(parent, isel,
370 *initialDirectory, title,
371 winFilter(filter), ExistingFiles);
372 if (idx)
373 ofn->nFilterIndex = idx + 1;
374 if (GetOpenFileName(ofn)) {
375 QString fileOrDir = QString::fromWCharArray(ofn->lpstrFile);
376 selFilIdx = ofn->nFilterIndex;
377 int offset = fileOrDir.length() + 1;
378 if (ofn->lpstrFile[offset] == 0) {
379 // Only one file selected; has full path
380 fi.setFile(fileOrDir);
381 QString res = fi.absFilePath();
382 if (!res.isEmpty())
383 result.append(res);
384 }
385 else {
386 // Several files selected; first string is path
387 dir.setPath(fileOrDir);
388 QString f;
389 while (!(f = QString::fromWCharArray(ofn->lpstrFile + offset)).isEmpty()) {
390 fi.setFile(dir, f);
391 QString res = fi.absFilePath();
392 if (!res.isEmpty())
393 result.append(res);
394 offset += f.length() + 1;
395 }
396 }
397 }
398 cleanUpOFN(&ofn);
399
400 if (parent) {
401 QApplicationPrivate::leaveModal(parent);
402 QEvent e(QEvent::WindowUnblocked);
403 QApplication::sendEvent(parent, &e);
404 }
405
406 if (!result.isEmpty()) {
407 *initialDirectory = fi.dirPath(); // only save the path if there is a result
408 if (selectedFilter)
409 *selectedFilter = selFilter(filter, selFilIdx);
410 }
411 return result;
412}
413
414// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
415
416static int __stdcall winGetExistDirCallbackProc(HWND hwnd,
417 UINT uMsg,
418 LPARAM lParam,
419 LPARAM lpData)
420{
421#ifndef Q_OS_WINCE
422 if (uMsg == BFFM_INITIALIZED && lpData != 0) {
423 QString *initDir = (QString *)(lpData);
424 if (!initDir->isEmpty()) {
425 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, Q_ULONG(initDir->utf16()));
426 }
427 } else if (uMsg == BFFM_SELCHANGED) {
428 wchar_t path[MAX_PATH];
429 SHGetPathFromIDList(LPITEMIDLIST(lParam), path);
430 QString tmpStr = QString::fromWCharArray(path);
431 if (!tmpStr.isEmpty())
432 SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
433 else
434 SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
435 SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, Q_ULONG(path));
436 }
437#endif
438 return 0;
439}
440
441#ifndef BIF_NEWDIALOGSTYLE
442#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
443#endif
444
445
446QString Q3FileDialog::winGetExistingDirectory(const QString& initialDirectory,
447 QWidget *parent,
448 const char* /*name*/,
449 const QString& caption)
450{
451#ifndef Q_OS_WINCE
452 QString currentDir = QDir::currentDirPath();
453 QString result;
454 if (parent)
455 parent = parent->window();
456 else
457 parent = qApp->activeWindow();
458 QString title = caption;
459 if (title.isNull())
460 title = tr("Select a Directory");
461
462 if (parent) {
463 QEvent e(QEvent::WindowBlocked);
464 QApplication::sendEvent(parent, &e);
465 QApplicationPrivate::enterModal(parent);
466 }
467
468 QString initDir = QDir::toNativeSeparators(initialDirectory);
469 wchar_t path[MAX_PATH];
470 wchar_t initPath[MAX_PATH];
471 initPath[0] = 0;
472 path[0] = 0;
473 tTitle = title;
474 BROWSEINFO bi;
475 bi.hwndOwner = (parent ? parent->winId() : 0);
476 bi.pidlRoot = NULL;
477 bi.lpszTitle = (wchar_t*)tTitle.utf16();
478 bi.pszDisplayName = initPath;
479 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
480 bi.lpfn = winGetExistDirCallbackProc;
481 bi.lParam = Q_ULONG(&initDir);
482 LPITEMIDLIST pItemIDList = SHBrowseForFolder(&bi);
483 if (pItemIDList) {
484 SHGetPathFromIDList(pItemIDList, path);
485 IMalloc *pMalloc;
486 if (SHGetMalloc(&pMalloc) != NOERROR)
487 result.clear();
488 else {
489 pMalloc->Free(pItemIDList);
490 pMalloc->Release();
491 result = QString::fromWCharArray(path);
492 }
493 } else
494 result.clear();
495 tTitle.clear();
496
497 if (parent) {
498 QApplicationPrivate::leaveModal(parent);
499 QEvent e(QEvent::WindowUnblocked);
500 QApplication::sendEvent(parent, &e);
501 }
502
503 if (!result.isEmpty())
504 result.replace(QLatin1Char('\\'), QLatin1Char('/'));
505 return result;
506#else
507 return QString();
508#endif
509}
510
511QT_END_NAMESPACE
512
513#endif
Note: See TracBrowser for help on using the repository browser.