summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2015-03-25 10:45:58 +0100
committerFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2015-03-27 14:24:03 +0000
commit4347e811611ab15e544765a3a34761d2f5c68cb3 (patch)
tree62375a984ad93097e4c5ffcc25773c2094686987 /src/plugins
parent696a18b063a890c4425121a6011d6fd5ba1c3f00 (diff)
Windows: Support virtual folders as initial directory for file dialog.
Use the scheme "clsid" to be able to pass them as "clsid:<GUID>" (with '{', '}' stripped). Task-number: QTBUG-33962 Change-Id: Ib045fe81518bca6e91588007ce8a245a48479b1f Reviewed-by: Leena Miettinen <riitta-leena.miettinen@theqtcompany.com> Reviewed-by: Patrick Spendrin <patrick.spendrin@kdab.com> Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com> Reviewed-by: Björn Breitmeyer <bjoern.breitmeyer@kdab.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h8
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp80
3 files changed, 73 insertions, 19 deletions
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index fa355f6201..7264fdcbb6 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -225,8 +225,10 @@ bool QWindowsUser32DLL::initTouch()
QWindowsShell32DLL::QWindowsShell32DLL()
: sHCreateItemFromParsingName(0)
+ , sHGetKnownFolderIDList(0)
, sHGetStockIconInfo(0)
, sHGetImageList(0)
+ , sHCreateItemFromIDList(0)
{
}
@@ -234,8 +236,10 @@ void QWindowsShell32DLL::init()
{
QSystemLibrary library(QStringLiteral("shell32"));
sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName"));
+ sHGetKnownFolderIDList = (SHGetKnownFolderIDList)(library.resolve("SHGetKnownFolderIDList"));
sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo");
sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList");
+ sHCreateItemFromIDList = (SHCreateItemFromIDList)library.resolve("SHCreateItemFromIDList");
}
QWindowsShcoreDLL::QWindowsShcoreDLL()
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 81f4a36433..d2a3481b28 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -41,6 +41,10 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QLoggingCategory>
+#define STRICT_TYPED_ITEMIDS
+#include <shlobj.h>
+#include <shlwapi.h>
+
struct IBindCtx;
struct _SHSTOCKICONINFO;
@@ -120,12 +124,16 @@ struct QWindowsShell32DLL
inline void init();
typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **);
+ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *);
typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *);
typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **);
+ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **);
SHCreateItemFromParsingName sHCreateItemFromParsingName;
+ SHGetKnownFolderIDList sHGetKnownFolderIDList;
SHGetStockIconInfo sHGetStockIconInfo;
SHGetImageList sHGetImageList;
+ SHCreateItemFromIDList sHCreateItemFromIDList;
};
// Shell scaling library (Windows 8.1 onwards)
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 3b47829402..3284795fc1 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -58,16 +58,14 @@
#include <QtCore/QExplicitlySharedDataPointer>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
+#include <QtCore/QUuid>
+#include <QtCore/QRegularExpression>
#include <QtCore/private/qsystemlibrary_p.h>
#include <algorithm>
#include "qtwindows_additional.h"
-#define STRICT_TYPED_ITEMIDS
-#include <shlobj.h>
-#include <shlwapi.h>
-
// #define USE_NATIVE_COLOR_DIALOG /* Testing purposes only */
#ifdef Q_CC_MINGW /* Add missing declarations for MinGW */
@@ -873,8 +871,8 @@ public:
virtual void setWindowTitle(const QString &title);
inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::AcceptMode acceptMode, QFileDialogOptions::FileDialogOptions options);
- inline void setDirectory(const QString &directory);
- inline void updateDirectory() { setDirectory(m_data.directory().toLocalFile()); }
+ inline void setDirectory(const QUrl &directory);
+ inline void updateDirectory() { setDirectory(m_data.directory()); }
inline QString directory() const;
virtual void doExec(HWND owner = 0);
virtual void setNameFilters(const QStringList &f);
@@ -916,7 +914,7 @@ protected:
static QList<QUrl> libraryItemFolders(IShellItem *item);
static QString libraryItemDefaultSaveFolder(IShellItem *item);
static int itemPaths(IShellItemArray *items, QList<QUrl> *fileResult = 0);
- static IShellItem *shellItem(const QString &path);
+ static IShellItem *shellItem(const QUrl &url);
const QWindowsFileDialogSharedData &data() const { return m_data; }
QWindowsFileDialogSharedData &data() { return m_data; }
@@ -976,25 +974,58 @@ void QWindowsNativeFileDialogBase::setWindowTitle(const QString &title)
m_fileDialog->SetTitle(reinterpret_cast<const wchar_t *>(title.utf16()));
}
-IShellItem *QWindowsNativeFileDialogBase::shellItem(const QString &path)
+IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url)
{
#ifndef Q_OS_WINCE
- if (QWindowsContext::shell32dll.sHCreateItemFromParsingName) {
- IShellItem *result = 0;
- const QString native = QDir::toNativeSeparators(path);
+ if (url.isLocalFile()) {
+ if (!QWindowsContext::shell32dll.sHCreateItemFromParsingName)
+ return Q_NULLPTR;
+ IShellItem *result = Q_NULLPTR;
+ const QString native = QDir::toNativeSeparators(url.toLocalFile());
const HRESULT hr =
- QWindowsContext::shell32dll.sHCreateItemFromParsingName(reinterpret_cast<const wchar_t *>(native.utf16()),
- NULL, IID_IShellItem,
- reinterpret_cast<void **>(&result));
- if (SUCCEEDED(hr))
- return result;
+ QWindowsContext::shell32dll.sHCreateItemFromParsingName(reinterpret_cast<const wchar_t *>(native.utf16()),
+ NULL, IID_IShellItem,
+ reinterpret_cast<void **>(&result));
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
+ return Q_NULLPTR;
+ }
+ return result;
+ } else if (url.scheme() == QLatin1String("clsid")) {
+ if (!QWindowsContext::shell32dll.sHGetKnownFolderIDList || !QWindowsContext::shell32dll.sHCreateItemFromIDList)
+ return Q_NULLPTR;
+ // Support for virtual folders via GUID
+ // (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx)
+ // specified as "clsid:<GUID>" (without '{', '}').
+ IShellItem *result = Q_NULLPTR;
+ const QUuid uuid(url.path());
+ if (uuid.isNull()) {
+ qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path();
+ return Q_NULLPTR;
+ }
+ PIDLIST_ABSOLUTE idList;
+ HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList);
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
+ return Q_NULLPTR;
+ }
+ hr = QWindowsContext::shell32dll.sHCreateItemFromIDList(idList, IID_IShellItem, reinterpret_cast<void **>(&result));
+ CoTaskMemFree(idList);
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: SHCreateItemFromIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
+ return Q_NULLPTR;
+ }
+ return result;
+ } else {
+ qWarning() << __FUNCTION__ << ": Unhandled scheme: " << url.scheme();
}
+#else // !Q_OS_WINCE
+ Q_UNUSED(url)
#endif
- qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(path));
return 0;
}
-void QWindowsNativeFileDialogBase::setDirectory(const QString &directory)
+void QWindowsNativeFileDialogBase::setDirectory(const QUrl &directory)
{
if (!directory.isEmpty()) {
if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) {
@@ -1284,9 +1315,20 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel
}
}
+static inline bool isClsid(const QString &s)
+{
+ // detect "374DE290-123F-4565-9164-39C4925E467B".
+ static const QRegularExpression pattern(QLatin1String("[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{8}"));
+ Q_ASSERT(pattern.isValid());
+ return pattern.match(s).hasMatch();
+}
+
void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const
{
- m_fileDialog->SetFileName((wchar_t*)fileName.utf16());
+ // Hack to prevent CLSIDs from being set as file name due to
+ // QFileDialogPrivate::initialSelection() being QString-based.
+ if (!isClsid(fileName))
+ m_fileDialog->SetFileName((wchar_t*)fileName.utf16());
}
// Return the index of the selected filter, accounting for QFileDialog