src/gui/dialogs/qfiledialog_win.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
--- a/src/gui/dialogs/qfiledialog_win.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/gui/dialogs/qfiledialog_win.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -53,53 +53,27 @@
 #include <qdir.h>
 #include <qstringlist.h>
 #include <qlibrary.h>
+#include "qfiledialog_win_p.h"
 
 #ifndef QT_NO_THREAD
 #  include <private/qmutexpool_p.h>
 #endif
 
+#ifdef Q_WS_WINCE
 #include <shlobj.h>
-//At some point we can hope that mingw will support that interface
-#if !defined(Q_WS_WINCE) && !defined(Q_CC_MINGW)
-#include <shobjidl.h>
-#endif
-
-#include <objbase.h>
-
-#if defined(__IFileDialog_INTERFACE_DEFINED__) \
-	&& defined(__IFileOpenDialog_INTERFACE_DEFINED__)
-#define USE_COMMON_ITEM_DIALOG
-#endif
-
-#ifdef Q_WS_WINCE
 #include <commdlg.h>
-#  ifndef BFFM_SETSELECTION
-#    define BFFM_SETSELECTION (WM_USER + 102)
-#  endif
-// Windows Mobile has a broken definition for BROWSEINFO
-// Only compile fix
-typedef struct qt_priv_browseinfo {
-    HWND          hwndOwner;
-    LPCITEMIDLIST pidlRoot;
-    LPWSTR        pszDisplayName;
-    LPCWSTR       lpszTitle;
-    UINT          ulFlags;
-    BFFCALLBACK   lpfn;
-    LPARAM        lParam;
-    int           iImage;
-} qt_BROWSEINFO;
 bool qt_priv_ptr_valid = false;
+#else
+//we have to declare them here because they're not present for all SDK/compilers
+static const IID   QT_IID_IFileOpenDialog  = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60} };
+static const IID   QT_IID_IShellItem       = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe} };
+static const CLSID QT_CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7} };
 #endif
 
 
-// Don't remove the lines below!
-//
-// resolving the W methods manually is needed, because Windows 95 doesn't include
-// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol
-// when Qt calls getExistingDirectory(), etc.
-typedef LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(BROWSEINFO*);
+typedef qt_LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(qt_BROWSEINFO*);
 static PtrSHBrowseForFolder ptrSHBrowseForFolder = 0;
-typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(LPITEMIDLIST,LPWSTR);
+typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(qt_LPITEMIDLIST, LPWSTR);
 static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 0;
 typedef HRESULT (WINAPI *PtrSHGetMalloc)(LPMALLOC *);
 static PtrSHGetMalloc ptrSHGetMalloc = 0;
@@ -132,7 +106,7 @@
         ptrSHGetMalloc = (PtrSHGetMalloc) lib.resolve("SHGetMalloc");
 #else
         // CE stores them in a different lib and does not use unicode version
-        HINSTANCE handle = LoadLibraryW(L"Ceshell");
+        HINSTANCE handle = LoadLibrary(L"Ceshell");
         ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder");
         ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList");
         ptrSHGetMalloc = (PtrSHGetMalloc)GetProcAddress(handle, L"SHGetMalloc");
@@ -244,7 +218,6 @@
     memset(ofn, 0, sizeof(OPENFILENAME));
 
     ofn->lStructSize = sizeof(OPENFILENAME);
-    Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
     ofn->hwndOwner = parent ? parent->winId() : 0;
     ofn->lpstrFilter = (wchar_t*)tFilters.utf16();
     ofn->lpstrFile = tInitSel;
@@ -421,7 +394,7 @@
 }
 
 
-#if defined(USE_COMMON_ITEM_DIALOG)
+#ifndef Q_WS_WINCE
 
 typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);
 static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0;
@@ -469,7 +442,7 @@
     // Add the filters to the file dialog.
     if (numFilters) {
         wchar_t *szData = (wchar_t*)winfilters.utf16();
-        COMDLG_FILTERSPEC *filterSpec = new COMDLG_FILTERSPEC[numFilters];
+        qt_COMDLG_FILTERSPEC *filterSpec = new qt_COMDLG_FILTERSPEC[numFilters];
         for(int i = 0; i<numFilters; i++) {
             filterSpec[i].pszName = szData+offsets[i*2];
             filterSpec[i].pszSpec = szData+offsets[(i*2)+1];
@@ -481,9 +454,8 @@
     tInitDir = QDir::toNativeSeparators(initialDirectory);
     if (!tInitDir.isEmpty()) {
         IShellItem *psiDefaultFolder;
-        hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(),
-                                      NULL,
-                                      IID_PPV_ARGS(&psiDefaultFolder));
+        hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), NULL, QT_IID_IShellItem, 
+            reinterpret_cast<void**>(&psiDefaultFolder));
 
         if (SUCCEEDED(hr)) {
             hr = pfd->SetFolder(psiDefaultFolder);
@@ -522,7 +494,7 @@
     return SUCCEEDED(hr);
 }
 
-QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args,
+static QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args,
                                        QString *initialDirectory,
                                        const QStringList &filterList,
                                        QString *selectedFilter,
@@ -535,10 +507,8 @@
     QApplicationPrivate::enterModal(&modal_widget);
     // Multiple selection is allowed only in IFileOpenDialog.
     IFileOpenDialog *pfd = 0;
-    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog,
-                                  NULL,
-                                  CLSCTX_INPROC_SERVER,
-                                  IID_PPV_ARGS(&pfd));
+    HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, QT_IID_IFileOpenDialog, 
+        reinterpret_cast<void**>(&pfd));
 
     if (SUCCEEDED(hr)) {
         qt_win_set_IFileDialogOptions(pfd, args.selection,
@@ -612,6 +582,63 @@
     return result;
 }
 
+QString qt_win_CID_get_existing_directory(const QFileDialogArgs &args)
+{
+    QString result;
+    QDialog modal_widget;
+    modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+    modal_widget.setParent(args.parent, Qt::Window);
+    QApplicationPrivate::enterModal(&modal_widget);
+
+    IFileOpenDialog *pfd = 0;
+    HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
+                                  QT_IID_IFileOpenDialog, reinterpret_cast<void**>(&pfd));
+
+    if (SUCCEEDED(hr)) {
+        qt_win_set_IFileDialogOptions(pfd, args.selection,
+                                      args.directory, args.caption,
+                                      QStringList(), QFileDialog::ExistingFiles,
+                                      args.options);
+
+        // Set the FOS_PICKFOLDERS flag
+        DWORD newOptions;
+        hr = pfd->GetOptions(&newOptions);
+        newOptions |= FOS_PICKFOLDERS;
+        if (SUCCEEDED(hr) && SUCCEEDED((hr = pfd->SetOptions(newOptions)))) {
+            QWidget *parentWindow = args.parent;
+            if (parentWindow)
+                parentWindow = parentWindow->window();
+            else
+                parentWindow = QApplication::activeWindow();
+
+            // Show the file dialog.
+            hr = pfd->Show(parentWindow ? parentWindow->winId() : 0);
+            if (SUCCEEDED(hr)) {
+                // Retrieve the result
+                IShellItem *psi = 0;
+                hr = pfd->GetResult(&psi);
+                if (SUCCEEDED(hr)) {
+                    // Retrieve the file name from shell item.
+                    wchar_t *pszPath;
+                    hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
+                    if (SUCCEEDED(hr)) {
+                        result = QString::fromWCharArray(pszPath);
+                        CoTaskMemFree(pszPath);
+                    }
+                    psi->Release(); // Free the current item.
+                }
+            }
+        }
+    }
+    QApplicationPrivate::leaveModal(&modal_widget);
+
+    qt_win_eatMouseMove();
+
+    if (pfd)
+        pfd->Release();
+    return result;
+}
+
 #endif
 
 QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
@@ -643,7 +670,7 @@
     // multiple files belonging to different folders from these search results, the
     // GetOpenFileName() will return only one folder name for all the files. To retrieve
     // the correct path for all selected files, we have to use Common Item Dialog interfaces.
-#if defined(USE_COMMON_ITEM_DIALOG)
+#ifndef Q_WS_WINCE
     if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
         return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx);
 #endif
@@ -716,7 +743,7 @@
         qt_win_resolve_libs();
         if (ptrSHGetPathFromIDList) {
             wchar_t path[MAX_PATH];
-            ptrSHGetPathFromIDList(LPITEMIDLIST(lParam), path);
+            ptrSHGetPathFromIDList(qt_LPITEMIDLIST(lParam), path);
             QString tmpStr = QString::fromWCharArray(path);
             if (!tmpStr.isEmpty())
                 SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
@@ -728,13 +755,13 @@
     return 0;
 }
 
-#ifndef BIF_NEWDIALOGSTYLE
-#define BIF_NEWDIALOGSTYLE     0x0040   // Use the new dialog layout with the ability to resize
+QString qt_win_get_existing_directory(const QFileDialogArgs &args)
+{
+#ifndef Q_WS_WINCE
+    if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
+        return qt_win_CID_get_existing_directory(args);
 #endif
 
-
-QString qt_win_get_existing_directory(const QFileDialogArgs &args)
-{
     QString currentDir = QDir::currentPath();
     QString result;
     QWidget *parent = args.parent;
@@ -757,11 +784,7 @@
     path[0] = 0;
     tTitle = args.caption;
 
-#if !defined(Q_WS_WINCE)
-    BROWSEINFO bi;
-#else
     qt_BROWSEINFO bi;
-#endif
 
     Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
     bi.hwndOwner = (parent ? parent->winId() : 0);
@@ -775,7 +798,7 @@
 
     qt_win_resolve_libs();
     if (ptrSHBrowseForFolder) {
-        LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder((BROWSEINFO*)&bi);
+        qt_LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
         if (pItemIDList) {
             ptrSHGetPathFromIDList(pItemIDList, path);
             IMalloc *pMalloc;