Qt 4.8
qfiledialog_win.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
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 <private/qsystemlibrary_p.h>
56 #include "qfiledialog_win_p.h"
57 
58 #ifdef Q_WS_WINCE
59 #include <commdlg.h>
60 bool qt_priv_ptr_valid = false;
61 #else
62 //we have to declare them here because they're not present for all SDK/compilers
63 static const IID QT_IID_IFileOpenDialog = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60} };
64 static const IID QT_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe} };
65 static const CLSID QT_CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7} };
66 #endif
67 
68 
71 typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(qt_LPITEMIDLIST, LPWSTR);
73 typedef HRESULT (WINAPI *PtrSHGetMalloc)(LPMALLOC *);
75 
76 
78 
79 static void qt_win_resolve_libs()
80 {
81  static bool triedResolve = false;
82  if (!triedResolve) {
83 #if !defined(Q_WS_WINCE)
84  QSystemLibrary lib(QLatin1String("shell32"));
85  ptrSHBrowseForFolder = (PtrSHBrowseForFolder)lib.resolve("SHBrowseForFolderW");
86  ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)lib.resolve("SHGetPathFromIDListW");
87  ptrSHGetMalloc = (PtrSHGetMalloc)lib.resolve("SHGetMalloc");
88 #else
89  // CE stores them in a different lib and does not use unicode version
90  QSystemLibrary lib(QLatin1String("Ceshell"));
91  ptrSHBrowseForFolder = (PtrSHBrowseForFolder)lib.resolve("SHBrowseForFolder");
92  ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)lib.resolve("SHGetPathFromIDList");
93  ptrSHGetMalloc = (PtrSHGetMalloc)lib.resolve("SHGetMalloc");
95  qt_priv_ptr_valid = true;
96 #endif
97 
98  triedResolve = true;
99  }
100 }
101 
102 extern const char* qt_file_dialog_filter_reg_exp; // defined in qfiledialog.cpp
104 
105 const int maxNameLen = 1023;
106 const int maxMultiLen = 65535;
107 
108 // Returns the wildcard part of a filter.
109 static QString qt_win_extract_filter(const QString &rawFilter)
110 {
111  QString result = rawFilter;
113  int index = r.indexIn(result);
114  if (index >= 0)
115  result = r.cap(2);
116  QStringList list = result.split(QLatin1Char(' '));
117  for(QStringList::iterator it = list.begin(); it < list.end(); ++it) {
118  if (*it == QLatin1String("*")) {
119  *it = QLatin1String("*.*");
120  break;
121  }
122  }
123  return list.join(QLatin1String(";"));
124 }
125 
127 {
128  QString f(filter);
129 
130  if (f.isEmpty())
131  f = QFileDialog::tr("All Files (*.*)");
132 
133  return qt_make_filter_list(f);
134 }
135 
136 // Makes a NUL-oriented Windows filter from a Qt filter.
137 static QString qt_win_filter(const QString &filter, bool hideFiltersDetails)
138 {
139  QStringList filterLst = qt_win_make_filters_list(filter);
140  QStringList::Iterator it = filterLst.begin();
141  QString winfilters;
143  for (; it != filterLst.end(); ++it) {
144  QString subfilter = *it;
145  if (!subfilter.isEmpty()) {
146  if (hideFiltersDetails) {
147  int index = r.indexIn(subfilter);
148  if (index >= 0)
149  winfilters += r.cap(1);
150  } else {
151  winfilters += subfilter;
152  }
153  winfilters += QChar();
154  winfilters += qt_win_extract_filter(subfilter);
155  winfilters += QChar();
156  }
157  }
158  winfilters += QChar();
159  return winfilters;
160 }
161 
162 static QString qt_win_selected_filter(const QString &filter, DWORD idx)
163 {
164  return qt_win_make_filters_list(filter).at((int)idx - 1);
165 }
166 
168 
169 static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
170  const QString& initialSelection,
171  const QString& initialDirectory,
172  const QString& title,
173  const QString& filters,
175  QFileDialog::Options options)
176 {
177  if (parent)
178  parent = parent->window();
179  else
180  parent = QApplication::activeWindow();
181 
182  tInitDir = QDir::toNativeSeparators(initialDirectory);
183  tFilters = filters;
184  tTitle = title;
185  QString initSel = QDir::toNativeSeparators(initialSelection);
186  if (!initSel.isEmpty()) {
187  initSel.remove(QLatin1Char('<'));
188  initSel.remove(QLatin1Char('>'));
189  initSel.remove(QLatin1Char('\"'));
190  initSel.remove(QLatin1Char('|'));
191  }
192 
193  int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
194  wchar_t *tInitSel = new wchar_t[maxLen + 1];
195  if (initSel.length() > 0 && initSel.length() <= maxLen)
196  memcpy(tInitSel, initSel.utf16(), (initSel.length()+1)*sizeof(QChar));
197  else
198  tInitSel[0] = 0;
199 
200  OPENFILENAME* ofn = new OPENFILENAME;
201  memset(ofn, 0, sizeof(OPENFILENAME));
202 
203  ofn->lStructSize = sizeof(OPENFILENAME);
204  ofn->hwndOwner = parent ? parent->winId() : 0;
205  ofn->lpstrFilter = (wchar_t*)tFilters.utf16();
206  ofn->lpstrFile = tInitSel;
207  ofn->nMaxFile = maxLen;
208  ofn->lpstrInitialDir = (wchar_t*)tInitDir.utf16();
209  ofn->lpstrTitle = (wchar_t*)tTitle.utf16();
210  ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST);
211  if (mode == QFileDialog::ExistingFile ||
213  ofn->Flags |= (OFN_FILEMUSTEXIST);
214  if (mode == QFileDialog::ExistingFiles)
215  ofn->Flags |= (OFN_ALLOWMULTISELECT);
216  if (!(options & QFileDialog::DontConfirmOverwrite))
217  ofn->Flags |= OFN_OVERWRITEPROMPT;
218 
219  return ofn;
220 }
221 
222 static void qt_win_clean_up_OFN(OPENFILENAME **ofn)
223 {
224  delete [] (*ofn)->lpstrFile;
225  delete *ofn;
226  *ofn = 0;
227 }
228 
229 extern void qt_win_eatMouseMove();
230 
232  QString *initialDirectory,
233  QString *selectedFilter)
234 {
235  QString result;
236 
237  QString isel = args.selection;
238 
239  if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
240  initialDirectory->remove(0, 5);
241  QFileInfo fi(*initialDirectory);
242 
243  if (initialDirectory && !fi.isDir()) {
244  *initialDirectory = fi.absolutePath();
245  if (isel.isEmpty())
246  isel = fi.fileName();
247  }
248 
249  if (!fi.exists())
250  *initialDirectory = QDir::homePath();
251 
252  DWORD selFilIdx = 0;
253 
254  int idx = 0;
255  if (selectedFilter) {
256  QStringList filterLst = qt_win_make_filters_list(args.filter);
257  idx = filterLst.indexOf(*selectedFilter);
258  }
259 
260  QDialog modal_widget;
261  modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
262  modal_widget.setParent(args.parent, Qt::Window);
263  QApplicationPrivate::enterModal(&modal_widget);
264 
265  bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
266  OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
267  args.directory, args.caption,
268  qt_win_filter(args.filter, hideFiltersDetails),
270  args.options);
271  if (idx)
272  ofn->nFilterIndex = idx + 1;
273  if (GetOpenFileName(ofn)) {
274  result = QString::fromWCharArray(ofn->lpstrFile);
275  selFilIdx = ofn->nFilterIndex;
276  }
277  qt_win_clean_up_OFN(&ofn);
278 
279  QApplicationPrivate::leaveModal(&modal_widget);
280 
282 
283  if (result.isEmpty())
284  return result;
285 
286  fi = result;
287  *initialDirectory = fi.path();
288  if (selectedFilter)
289  *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
290  return fi.absoluteFilePath();
291 }
292 
294  QString *initialDirectory,
295  QString *selectedFilter)
296 {
297  QString result;
298 
299  QString isel = args.selection;
300  if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
301  initialDirectory->remove(0, 5);
302  QFileInfo fi(*initialDirectory);
303 
304  if (initialDirectory && !fi.isDir()) {
305  *initialDirectory = fi.absolutePath();
306  if (isel.isEmpty())
307  isel = fi.fileName();
308  }
309 
310  if (!fi.exists())
311  *initialDirectory = QDir::homePath();
312 
313  DWORD selFilIdx = 0;
314 
315  int idx = 0;
316  if (selectedFilter) {
317  QStringList filterLst = qt_win_make_filters_list(args.filter);
318  idx = filterLst.indexOf(*selectedFilter);
319  }
320 
321  QDialog modal_widget;
322  modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
323  modal_widget.setParent(args.parent, Qt::Window);
324  QApplicationPrivate::enterModal(&modal_widget);
325  bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
326  // This block is used below for the lpstrDefExt member.
327  // Note that the current MSDN docs document this member wrong.
328  // It should rather be documented as "the default extension if no extension was given and if the
329  // current filter does not have a extension (e.g (*)). If the current filter have an extension, use
330  // the extension of the current filter"
331  QString defaultSaveExt;
332  if (selectedFilter && !selectedFilter->isEmpty()) {
333  defaultSaveExt = qt_win_extract_filter(*selectedFilter);
334  // make sure we only have the extension
335  int firstDot = defaultSaveExt.indexOf(QLatin1Char('.'));
336  if (firstDot != -1) {
337  defaultSaveExt.remove(0, firstDot + 1);
338  } else {
339  defaultSaveExt.clear();
340  }
341  }
342 
343  OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection,
344  args.directory, args.caption,
345  qt_win_filter(args.filter, hideFiltersDetails),
347  args.options);
348 
349  ofn->lpstrDefExt = (wchar_t*)defaultSaveExt.utf16();
350 
351  if (idx)
352  ofn->nFilterIndex = idx + 1;
353  if (GetSaveFileName(ofn)) {
354  result = QString::fromWCharArray(ofn->lpstrFile);
355  selFilIdx = ofn->nFilterIndex;
356  }
357  qt_win_clean_up_OFN(&ofn);
358 
359 #if defined(Q_WS_WINCE)
360  int semIndex = result.indexOf(QLatin1Char(';'));
361  if (semIndex >= 0)
362  result = result.left(semIndex);
363 #endif
364 
365  QApplicationPrivate::leaveModal(&modal_widget);
366 
368 
369  if (result.isEmpty())
370  return result;
371 
372  fi = result;
373  *initialDirectory = fi.path();
374  if (selectedFilter)
375  *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
376  return fi.absoluteFilePath();
377 }
378 
379 
380 #ifndef Q_WS_WINCE
381 
382 typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);
383 static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0;
384 
385 static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd,
386  const QString& initialSelection,
387  const QString& initialDirectory,
388  const QString& title,
389  const QStringList& filterLst,
391  QFileDialog::Options options)
392 {
393  if (!pSHCreateItemFromParsingName) {
394  // This function is available only in Vista & above.
395  QSystemLibrary shellLib(QLatin1String("Shell32"));
396  pSHCreateItemFromParsingName = (PtrSHCreateItemFromParsingName)
397  shellLib.resolve("SHCreateItemFromParsingName");
398  if (!pSHCreateItemFromParsingName)
399  return false;
400  }
401  HRESULT hr;
402  QString winfilters;
403  int numFilters = 0;
404  quint32 currentOffset = 0;
405  QList<quint32> offsets;
406  QStringList::ConstIterator it = filterLst.begin();
407  // Create the native filter string and save offset to each entry.
408  for (; it != filterLst.end(); ++it) {
409  QString subfilter = *it;
410  if (!subfilter.isEmpty()) {
411  offsets<<currentOffset;
412  //Here the COMMON_ITEM_DIALOG API always add the details for the filter (e.g. *.txt)
413  //so we don't need to handle the flag HideNameFilterDetails.
414  winfilters += subfilter; // The name of the filter.
415  winfilters += QChar();
416  currentOffset += subfilter.size()+1;
417  offsets<<currentOffset;
418  QString spec = qt_win_extract_filter(subfilter);
419  winfilters += spec; // The actual filter spec.
420  winfilters += QChar();
421  currentOffset += spec.size()+1;
422  numFilters++;
423  }
424  }
425  // Add the filters to the file dialog.
426  if (numFilters) {
427  wchar_t *szData = (wchar_t*)winfilters.utf16();
428  qt_COMDLG_FILTERSPEC *filterSpec = new qt_COMDLG_FILTERSPEC[numFilters];
429  for(int i = 0; i<numFilters; i++) {
430  filterSpec[i].pszName = szData+offsets[i*2];
431  filterSpec[i].pszSpec = szData+offsets[(i*2)+1];
432  }
433  hr = pfd->SetFileTypes(numFilters, filterSpec);
434  delete []filterSpec;
435  }
436  // Set the starting folder.
437  tInitDir = QDir::toNativeSeparators(initialDirectory);
438  if (!tInitDir.isEmpty()) {
439  IShellItem *psiDefaultFolder;
440  hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), NULL, QT_IID_IShellItem,
441  reinterpret_cast<void**>(&psiDefaultFolder));
442 
443  if (SUCCEEDED(hr)) {
444  hr = pfd->SetFolder(psiDefaultFolder);
445  psiDefaultFolder->Release();
446  }
447  }
448  // Set the currently selected file.
449  QString initSel = QDir::toNativeSeparators(initialSelection);
450  if (!initSel.isEmpty()) {
451  initSel.remove(QLatin1Char('<'));
452  initSel.remove(QLatin1Char('>'));
453  initSel.remove(QLatin1Char('\"'));
454  initSel.remove(QLatin1Char('|'));
455  }
456  if (!initSel.isEmpty()) {
457  hr = pfd->SetFileName((wchar_t*)initSel.utf16());
458  }
459  // Set the title for the file dialog.
460  if (!title.isEmpty()) {
461  hr = pfd->SetTitle((wchar_t*)title.utf16());
462  }
463  // Set other flags for the dialog.
464  DWORD newOptions;
465  hr = pfd->GetOptions(&newOptions);
466  if (SUCCEEDED(hr)) {
467  newOptions |= FOS_NOCHANGEDIR;
468  if (mode == QFileDialog::ExistingFile ||
470  newOptions |= (FOS_FILEMUSTEXIST | FOS_PATHMUSTEXIST);
471  if (mode == QFileDialog::ExistingFiles)
472  newOptions |= FOS_ALLOWMULTISELECT;
473  if (!(options & QFileDialog::DontConfirmOverwrite))
474  newOptions |= FOS_OVERWRITEPROMPT;
475  hr = pfd->SetOptions(newOptions);
476  }
477  return SUCCEEDED(hr);
478 }
479 
480 static QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args,
481  QString *initialDirectory,
482  const QStringList &filterList,
483  QString *selectedFilter,
484  int selectedFilterIndex)
485 {
486  QStringList result;
487  QDialog modal_widget;
488  modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
489  modal_widget.setParent(args.parent, Qt::Window);
490  QApplicationPrivate::enterModal(&modal_widget);
491  // Multiple selection is allowed only in IFileOpenDialog.
492  IFileOpenDialog *pfd = 0;
493  HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, QT_IID_IFileOpenDialog,
494  reinterpret_cast<void**>(&pfd));
495 
496  if (SUCCEEDED(hr)) {
497  qt_win_set_IFileDialogOptions(pfd, args.selection,
498  args.directory, args.caption,
499  filterList, QFileDialog::ExistingFiles,
500  args.options);
501  // Set the currently selected filter (one-based index).
502  hr = pfd->SetFileTypeIndex(selectedFilterIndex+1);
503  QWidget *parentWindow = args.parent;
504  if (parentWindow)
505  parentWindow = parentWindow->window();
506  else
507  parentWindow = QApplication::activeWindow();
508  // Show the file dialog.
509  hr = pfd->Show(parentWindow ? parentWindow->winId() : 0);
510  if (SUCCEEDED(hr)) {
511  // Retrieve the results.
512  IShellItemArray *psiaResults;
513  hr = pfd->GetResults(&psiaResults);
514  if (SUCCEEDED(hr)) {
515  DWORD numItems = 0;
516  psiaResults->GetCount(&numItems);
517  for (DWORD i = 0; i<numItems; i++) {
518  IShellItem *psi = 0;
519  hr = psiaResults->GetItemAt(i, &psi);
520  if (SUCCEEDED(hr)) {
521  // Retrieve the file name from shell item.
522  wchar_t *pszPath;
523  hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
524  if (SUCCEEDED(hr)) {
526  result.append(fileName);
527  CoTaskMemFree(pszPath);
528  }
529  psi->Release(); // Free the current item.
530  }
531  }
532  psiaResults->Release(); // Free the array of items.
533  }
534  }
535  }
536  QApplicationPrivate::leaveModal(&modal_widget);
537 
539 
540  if (!result.isEmpty()) {
541  // Retrieve the current folder name.
542  IShellItem *psi = 0;
543  hr = pfd->GetFolder(&psi);
544  if (SUCCEEDED(hr)) {
545  wchar_t *pszPath;
546  hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
547  if (SUCCEEDED(hr)) {
548  *initialDirectory = QString::fromWCharArray(pszPath);
549  CoTaskMemFree(pszPath);
550  }
551  psi->Release();
552  }
553  // Retrieve the currently selected filter.
554  if (selectedFilter) {
555  quint32 filetype = 0;
556  hr = pfd->GetFileTypeIndex(&filetype);
557  if (SUCCEEDED(hr) && filetype && filetype <= (quint32)filterList.length()) {
558  // This is a one-based index, not zero-based.
559  *selectedFilter = filterList[filetype-1];
560  }
561  }
562  }
563  if (pfd)
564  pfd->Release();
565  return result;
566 }
567 
568 QString qt_win_CID_get_existing_directory(const QFileDialogArgs &args)
569 {
570  QString result;
571  QDialog modal_widget;
572  modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
573  modal_widget.setParent(args.parent, Qt::Window);
574  QApplicationPrivate::enterModal(&modal_widget);
575 
576  IFileOpenDialog *pfd = 0;
577  HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
578  QT_IID_IFileOpenDialog, reinterpret_cast<void**>(&pfd));
579 
580  if (SUCCEEDED(hr)) {
581  qt_win_set_IFileDialogOptions(pfd, args.selection,
582  args.directory, args.caption,
584  args.options);
585 
586  // Set the FOS_PICKFOLDERS flag
587  DWORD newOptions;
588  hr = pfd->GetOptions(&newOptions);
589  newOptions |= (FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM);
590  if (SUCCEEDED(hr) && SUCCEEDED((hr = pfd->SetOptions(newOptions)))) {
591  QWidget *parentWindow = args.parent;
592  if (parentWindow)
593  parentWindow = parentWindow->window();
594  else
595  parentWindow = QApplication::activeWindow();
596 
597  // Show the file dialog.
598  hr = pfd->Show(parentWindow ? parentWindow->winId() : 0);
599  if (SUCCEEDED(hr)) {
600  // Retrieve the result
601  IShellItem *psi = 0;
602  hr = pfd->GetResult(&psi);
603  if (SUCCEEDED(hr)) {
604  // Retrieve the file name from shell item.
605  wchar_t *pszPath;
606  hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
607  if (SUCCEEDED(hr)) {
608  result = QString::fromWCharArray(pszPath);
609  CoTaskMemFree(pszPath);
610  }
611  psi->Release(); // Free the current item.
612  }
613  }
614  }
615  }
616  QApplicationPrivate::leaveModal(&modal_widget);
617 
619 
620  if (pfd)
621  pfd->Release();
622  return result;
623 }
624 
625 #endif
626 
628  QString *initialDirectory,
629  QString *selectedFilter)
630 {
631  QFileInfo fi;
632  QDir dir;
633 
634  if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
635  initialDirectory->remove(0, 5);
636  fi = QFileInfo(*initialDirectory);
637 
638  if (initialDirectory && !fi.isDir()) {
639  *initialDirectory = fi.absolutePath();
640  }
641 
642  if (!fi.exists())
643  *initialDirectory = QDir::homePath();
644 
645  DWORD selFilIdx = 0;
646 
647  QStringList filterLst = qt_win_make_filters_list(args.filter);
648  int idx = 0;
649  if (selectedFilter) {
650  idx = filterLst.indexOf(*selectedFilter);
651  }
652  // Windows Vista (& above) allows users to search from file dialogs. If user selects
653  // multiple files belonging to different folders from these search results, the
654  // GetOpenFileName() will return only one folder name for all the files. To retrieve
655  // the correct path for all selected files, we have to use Common Item Dialog interfaces.
656 #ifndef Q_WS_WINCE
658  return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx);
659 #endif
660 
661  QStringList result;
662  QDialog modal_widget;
663  modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
664  modal_widget.setParent(args.parent, Qt::Window);
665  QApplicationPrivate::enterModal(&modal_widget);
666 
667  bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
668  OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
669  args.directory, args.caption,
670  qt_win_filter(args.filter, hideFiltersDetails),
672  args.options);
673  if (idx)
674  ofn->nFilterIndex = idx + 1;
675  if (GetOpenFileName(ofn)) {
676  QString fileOrDir = QString::fromWCharArray(ofn->lpstrFile);
677  selFilIdx = ofn->nFilterIndex;
678  int offset = fileOrDir.length() + 1;
679  if (ofn->lpstrFile[offset] == 0) {
680  // Only one file selected; has full path
681  fi.setFile(fileOrDir);
682  QString res = fi.absoluteFilePath();
683  if (!res.isEmpty())
684  result.append(res);
685  }
686  else {
687  // Several files selected; first string is path
688  dir.setPath(fileOrDir);
689  QString f;
690  while(!(f = QString::fromWCharArray(ofn->lpstrFile + offset)).isEmpty()) {
691  fi.setFile(dir, f);
692  QString res = fi.absoluteFilePath();
693  if (!res.isEmpty())
694  result.append(res);
695  offset += f.length() + 1;
696  }
697  }
698  }
699  qt_win_clean_up_OFN(&ofn);
700 
701  QApplicationPrivate::leaveModal(&modal_widget);
702 
704 
705  if (!result.isEmpty()) {
706  *initialDirectory = fi.path(); // only save the path if there is a result
707  if (selectedFilter)
708  *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
709  }
710  return result;
711 }
712 
713 // MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
714 
715 static int __stdcall winGetExistDirCallbackProc(HWND hwnd,
716  UINT uMsg,
717  LPARAM lParam,
718  LPARAM lpData)
719 {
720  if (uMsg == BFFM_INITIALIZED && lpData != 0) {
721  QString *initDir = (QString *)(lpData);
722  if (!initDir->isEmpty()) {
723  SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
724  }
725  } else if (uMsg == BFFM_SELCHANGED) {
728  wchar_t path[MAX_PATH];
730  QString tmpStr = QString::fromWCharArray(path);
731  if (!tmpStr.isEmpty())
732  SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
733  else
734  SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
735  SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
736  }
737  }
738  return 0;
739 }
740 
742 {
743 #ifndef Q_WS_WINCE
745  return qt_win_CID_get_existing_directory(args);
746 #endif
747 
748  QString currentDir = QDir::currentPath();
749  QString result;
750  QWidget *parent = args.parent;
751  if (parent)
752  parent = parent->window();
753  else
754  parent = QApplication::activeWindow();
755  if (parent)
756  parent->createWinId();
757 
758  QDialog modal_widget;
759  modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
760  modal_widget.setParent(parent, Qt::Window);
761  QApplicationPrivate::enterModal(&modal_widget);
762 
764  wchar_t path[MAX_PATH];
765  wchar_t initPath[MAX_PATH];
766  initPath[0] = 0;
767  path[0] = 0;
768  tTitle = args.caption;
769 
770  qt_BROWSEINFO bi;
771 
772  Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
773  bi.hwndOwner = (parent ? parent->winId() : 0);
774  bi.pidlRoot = NULL;
775  //### This does not seem to be respected? - the dialog always displays "Browse for folder"
776  bi.lpszTitle = (wchar_t*)tTitle.utf16();
777  bi.pszDisplayName = initPath;
780  bi.lParam = LPARAM(&initDir);
781 
783  if (ptrSHBrowseForFolder) {
784  qt_LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
785  if (pItemIDList) {
786  ptrSHGetPathFromIDList(pItemIDList, path);
787  IMalloc *pMalloc;
788  if (ptrSHGetMalloc(&pMalloc) == NOERROR) {
789  pMalloc->Free(pItemIDList);
790  pMalloc->Release();
791  result = QString::fromWCharArray(path);
792  }
793  }
794  }
795  tTitle = QString();
796 
797  QApplicationPrivate::leaveModal(&modal_widget);
798 
800 
801  if (!result.isEmpty())
802  result.replace(QLatin1Char('\\'), QLatin1Char('/'));
803  return result;
804 }
805 
806 
808 
809 #endif
static QString fromWCharArray(const wchar_t *, int size=-1)
Returns a copy of the string, where the encoding of string depends on the size of wchar...
Definition: qstring.cpp:1019
The QDir class provides access to directory structures and their contents.
Definition: qdir.h:58
static QStringList qt_win_make_filters_list(const QString &filter)
static OPENFILENAME * qt_win_make_OFN(QWidget *parent, const QString &initialSelection, const QString &initialDirectory, const QString &title, const QString &filters, QFileDialog::FileMode mode, QFileDialog::Options options)
QString cap(int nth=0) const
Returns the text captured by the nth subexpression.
Definition: qregexp.cpp:4310
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void setParent(QWidget *parent)
Sets the parent of the widget to parent, and resets the window flags.
Definition: qwidget.cpp:10479
The QRegExp class provides pattern matching using regular expressions.
Definition: qregexp.h:61
#define it(className, varName)
The QDialog class is the base class of dialog windows.
Definition: qdialog.h:56
BOOL(WINAPI * PtrSHGetPathFromIDList)(qt_LPITEMIDLIST, LPWSTR)
void setPath(const QString &path)
Sets the path of the directory to path.
Definition: qdir.cpp:590
static QString tInitDir
QString & replace(int i, int len, QChar after)
Definition: qstring.cpp:2005
#define BFFM_SETSELECTION
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
static QWidget * activeWindow()
Returns the application top-level window that has the keyboard input focus, or 0 if no application wi...
#define BFFM_SETSTATUSTEXT
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
QString fileName() const
Returns the name of the file, excluding the path.
Definition: qfileinfo.cpp:726
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
#define BIF_NEWDIALOGSTYLE
QString qt_win_get_save_file_name(const QFileDialogArgs &args, QString *initialDirectory, QString *selectedFilter)
QString absoluteFilePath() const
Returns an absolute path including the file name.
Definition: qfileinfo.cpp:534
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
void qt_win_eatMouseMove()
bool exists() const
Returns true if the file exists; otherwise returns false.
Definition: qfileinfo.cpp:675
#define FOS_ALLOWMULTISELECT
static const WinVersion WindowsVersion
the version of the Windows operating system on which the application is run (Windows only) ...
Definition: qglobal.h:1613
The QString class provides a Unicode character string.
Definition: qstring.h:83
static QString currentPath()
Returns the absolute path of the application&#39;s current directory.
Definition: qdir.cpp:1875
static QString qt_win_filter(const QString &filter, bool hideFiltersDetails)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
iterator Iterator
Qt-style synonym for QList::iterator.
Definition: qlist.h:278
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
BFFCALLBACK lpfn
const int maxMultiLen
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
int indexOf(const QRegExp &rx, int from=0) const
Returns the index position of the first exact match of rx in the list, searching forward from index p...
Definition: qstringlist.h:195
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QString tTitle
int indexIn(const QString &str, int offset=0, CaretMode caretMode=CaretAtZero) const
Attempts to find a match in str from position offset (0 by default).
Definition: qregexp.cpp:4136
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory; otherwise ret...
Definition: qfileinfo.cpp:990
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
int size() const
Returns the number of characters in this string.
Definition: qstring.h:102
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition: qwidget.h:1041
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
static void qt_win_resolve_libs()
static QString qt_win_extract_filter(const QString &rawFilter)
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
void setFile(const QString &file)
Sets the file that the QFileInfo provides information about to file.
Definition: qfileinfo.cpp:468
#define BIF_STATUSTEXT
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
friend class iterator
Definition: qlist.h:226
#define FOS_PATHMUSTEXIST
#define BFFM_SELCHANGED
static int __stdcall winGetExistDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
const char * qt_file_dialog_filter_reg_exp
#define TRUE
Synonym for true.
Definition: qglobal.h:1018
bool qt_priv_ptr_valid
#define FOS_FORCEFILESYSTEM
QString join(const QString &sep) const
Joins all the string list&#39;s strings into a single string with each element separated by the given sep...
Definition: qstringlist.h:162
QWidget * parent
static const char *const filters[3]
HRESULT(WINAPI * PtrSHGetMalloc)(LPMALLOC *)
FileMode
This enum is used to indicate what the user may select in the file dialog; i.
Definition: qfiledialog.h:83
long HRESULT
QFileDialog::Options options
void * resolve(const char *symbol)
#define FOS_FILEMUSTEXIST
struct qt_ITEMIDLIST * qt_LPITEMIDLIST
static PtrSHGetMalloc ptrSHGetMalloc
#define BFFM_INITIALIZED
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
int length() const
This function is identical to count().
Definition: qlist.h:281
const_iterator ConstIterator
Qt-style synonym for QList::const_iterator.
Definition: qlist.h:279
qt_LPCITEMIDLIST pidlRoot
static void qt_win_clean_up_OFN(OPENFILENAME **ofn)
unsigned int quint32
Definition: qglobal.h:938
QString qt_win_get_existing_directory(const QFileDialogArgs &args)
static QString qt_win_selected_filter(const QString &filter, DWORD idx)
#define FOS_OVERWRITEPROMPT
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, QString *initialDirectory, QString *selectedFilter)
static PtrSHBrowseForFolder ptrSHBrowseForFolder
void setAttribute(Qt::WidgetAttribute, bool on=true)
Sets the attribute attribute on this widget if on is true; otherwise clears the attribute.
Definition: qwidget.cpp:11087
quint16 index
QWidget * window() const
Returns the window for this widget, i.e.
Definition: qwidget.cpp:4492
static QString tFilters
void createWinId()
Definition: qwidget.cpp:2626
WId winId() const
Returns the window system identifier of the widget.
Definition: qwidget.cpp:2557
QStringList split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const Q_REQUIRED_RESULT
Splits the string into substrings wherever sep occurs, and returns the list of those strings...
Definition: qstring.cpp:6526
#define FOS_PICKFOLDERS
qt_LPITEMIDLIST(WINAPI * PtrSHBrowseForFolder)(qt_BROWSEINFO *)
QString qt_win_get_open_file_name(const QFileDialogArgs &args, QString *initialDirectory, QString *selectedFilter)
QString path() const
Returns the file&#39;s path.
Definition: qfileinfo.cpp:615
QString & remove(int i, int len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition: qstring.cpp:1867
static PtrSHGetPathFromIDList ptrSHGetPathFromIDList
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
static QString toNativeSeparators(const QString &pathName)
Returns pathName with the &#39;/&#39; separators converted to separators that are appropriate for the underly...
Definition: qdir.cpp:812
#define BIF_RETURNONLYFSDIRS
static void leaveModal(QWidget *)
static QString fileName(const QString &fileUrl)
#define BFFM_ENABLEOK
QString absolutePath() const
Returns a file&#39;s path absolute path.
Definition: qfileinfo.cpp:577
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
const int maxNameLen
static void enterModal(QWidget *)
QStringList qt_make_filter_list(const QString &filter)
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
const ushort * utf16() const
Returns the QString as a &#39;\0\&#39;-terminated array of unsigned shorts.
Definition: qstring.cpp:5290
#define FOS_NOCHANGEDIR
static QString homePath()
Returns the absolute path of the user&#39;s home directory.
Definition: qdir.cpp:1942