summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp280
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.h12
-rw-r--r--src/winmain/qtmain_winrt.cpp24
3 files changed, 273 insertions, 43 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
index e1b2a07d5f..05b1fd76b1 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
@@ -37,25 +37,32 @@
#include "qwinrtfiledialoghelper.h"
#include "qwinrtfileengine.h"
+#include <QtCore/qcoreapplication.h>
#include <QtCore/QEventLoop>
#include <QtCore/QMap>
#include <QtCore/QVector>
#include <QtCore/qfunctions_winrt.h>
+#include <private/qeventdispatcher_winrt_p.h>
+#include <functional>
#include <wrl.h>
#include <windows.foundation.h>
#include <windows.storage.pickers.h>
+#include <Windows.ApplicationModel.activation.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::ApplicationModel::Activation;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Storage::Pickers;
+#ifndef Q_OS_WINPHONE
typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler;
typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler;
typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler;
+#endif
QT_BEGIN_NAMESPACE
@@ -142,6 +149,16 @@ private:
QVector<HSTRING> impl;
};
+#ifdef Q_OS_WINPHONE
+class QActivationEvent : public QEvent
+{
+public:
+ IInspectable *args() const {
+ return reinterpret_cast<IInspectable *>(d);
+ }
+};
+#endif
+
template<typename T>
static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options)
{
@@ -200,6 +217,99 @@ static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDia
return true;
}
+static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, bool singleFile)
+{
+ Q_ASSERT(picker);
+ Q_ASSERT(helper);
+ HRESULT hr;
+#ifdef Q_OS_WINPHONE
+ hr = QEventDispatcherWinRT::runOnXamlThread([picker, singleFile]() {
+ HRESULT hr;
+ ComPtr<IFileOpenPicker2> picker2;
+ hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf()));
+ RETURN_HR_IF_FAILED("Failed to cast file picker");
+ if (singleFile)
+ return picker2->PickSingleFileAndContinue();
+ else
+ return picker2->PickMultipleFilesAndContinue();
+ });
+ RETURN_FALSE_IF_FAILED("Failed to open file picker");
+ QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
+ Q_ASSERT(eventDispatcher);
+ eventDispatcher->installEventFilter(helper);
+ return true;
+#else
+ if (singleFile) {
+ ComPtr<IAsyncOperation<StorageFile *>> op;
+ hr = picker->PickSingleFileAsync(&op);
+ RETURN_FALSE_IF_FAILED("Failed to open single file picker");
+ hr = op->put_Completed(Callback<SingleFileHandler>(helper, &QWinRTFileDialogHelper::onSingleFilePicked).Get());
+ RETURN_FALSE_IF_FAILED("Failed to attach file picker callback");
+ } else {
+ ComPtr<IAsyncOperation<IVectorView<StorageFile *> *>> op;
+ hr = picker->PickMultipleFilesAsync(&op);
+ RETURN_FALSE_IF_FAILED("Failed to open multi file picker");
+ hr = op->put_Completed(Callback<MultipleFileHandler>(helper, &QWinRTFileDialogHelper::onMultipleFilesPicked).Get());
+ RETURN_FALSE_IF_FAILED("Failed to attach multi file callback");
+ }
+ return true;
+#endif
+}
+
+static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper)
+{
+ Q_ASSERT(picker);
+ Q_ASSERT(helper);
+ HRESULT hr;
+#ifdef Q_OS_WINPHONE
+ hr = QEventDispatcherWinRT::runOnXamlThread([picker]() {
+ HRESULT hr;
+ ComPtr<IFolderPicker2> picker2;
+ hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf()));
+ RETURN_HR_IF_FAILED("Failed to cast folder picker");
+ return picker2->PickFolderAndContinue();
+ });
+ RETURN_FALSE_IF_FAILED("Failed to open folder picker");
+ QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
+ Q_ASSERT(eventDispatcher);
+ eventDispatcher->installEventFilter(helper);
+#else
+ ComPtr<IAsyncOperation<StorageFolder *>> op;
+ hr = picker->PickSingleFolderAsync(&op);
+ RETURN_FALSE_IF_FAILED("Failed to open folder picker");
+ hr = op->put_Completed(Callback<SingleFolderHandler>(helper, &QWinRTFileDialogHelper::onSingleFolderPicked).Get());
+ RETURN_FALSE_IF_FAILED("Failed to attach folder picker callback");
+#endif
+ return true;
+}
+
+static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper)
+{
+ Q_ASSERT(picker);
+ Q_ASSERT(helper);
+ HRESULT hr;
+#ifdef Q_OS_WINPHONE
+ hr = QEventDispatcherWinRT::runOnXamlThread([picker]() {
+ HRESULT hr;
+ ComPtr<IFileSavePicker2> picker2;
+ hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf()));
+ RETURN_HR_IF_FAILED("Failed to cast save file picker");
+ return picker2->PickSaveFileAndContinue();
+ });
+ RETURN_FALSE_IF_FAILED("Failed to open single file picker");
+ QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
+ Q_ASSERT(eventDispatcher);
+ eventDispatcher->installEventFilter(helper);
+#else
+ ComPtr<IAsyncOperation<StorageFile *>> op;
+ hr = picker->PickSaveFileAsync(&op);
+ RETURN_FALSE_IF_FAILED("Failed to open save file picker");
+ hr = op->put_Completed(Callback<SingleFileHandler>(helper, &QWinRTFileDialogHelper::onSingleFilePicked).Get());
+ RETURN_FALSE_IF_FAILED("Failed to attach save file picker callback");
+#endif
+ return true;
+}
+
class QWinRTFileDialogHelperPrivate
{
public:
@@ -260,18 +370,9 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
if (!initializeOpenPickerOptions(picker.Get(), dialogOptions))
return false;
- if (dialogOptions->fileMode() == QFileDialogOptions::ExistingFiles) {
- ComPtr<IAsyncOperation<IVectorView<StorageFile *> *>> op;
- hr = picker->PickMultipleFilesAsync(&op);
- RETURN_FALSE_IF_FAILED("Failed to open multi file picker");
- hr = op->put_Completed(Callback<MultipleFileHandler>(this, &QWinRTFileDialogHelper::onMultipleFilesPicked).Get());
- } else {
- ComPtr<IAsyncOperation<StorageFile *>> op;
- hr = picker->PickSingleFileAsync(&op);
- RETURN_FALSE_IF_FAILED("Failed to open single file picker");
- hr = op->put_Completed(Callback<SingleFileHandler>(this, &QWinRTFileDialogHelper::onSingleFilePicked).Get());
- }
- RETURN_FALSE_IF_FAILED("Failed to attach file picker callback");
+ if (!pickFiles(picker.Get(), this, dialogOptions->fileMode() == QFileDialogOptions::ExistingFile))
+ return false;
+
break;
}
case QFileDialogOptions::Directory:
@@ -284,11 +385,9 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
if (!initializeOpenPickerOptions(picker.Get(), dialogOptions))
return false;
- ComPtr<IAsyncOperation<StorageFolder *>> op;
- hr = picker->PickSingleFolderAsync(&op);
- RETURN_FALSE_IF_FAILED("Failed to open folder picker");
- hr = op->put_Completed(Callback<SingleFolderHandler>(this, &QWinRTFileDialogHelper::onSingleFolderPicked).Get());
- RETURN_FALSE_IF_FAILED("Failed to attach folder picker callback");
+ if (!pickFolder(picker.Get(), this))
+ return false;
+
break;
}
}
@@ -344,11 +443,9 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
RETURN_FALSE_IF_FAILED("Failed to set suggested file name");
}
- ComPtr<IAsyncOperation<StorageFile *>> op;
- hr = picker->PickSaveFileAsync(&op);
- RETURN_FALSE_IF_FAILED("Failed to open save file picker");
- hr = op->put_Completed(Callback<SingleFileHandler>(this, &QWinRTFileDialogHelper::onSingleFilePicked).Get());
- RETURN_FALSE_IF_FAILED("Failed to attach file picker callback");
+ if (!pickSaveFile(picker.Get(), this))
+ return false;
+
break;
}
}
@@ -367,6 +464,68 @@ void QWinRTFileDialogHelper::hide()
d->shown = false;
}
+#ifdef Q_OS_WINPHONE
+bool QWinRTFileDialogHelper::eventFilter(QObject *, QEvent *e)
+{
+ if (e->type() != QEvent::WinEventAct)
+ return false;
+
+ HRESULT hr;
+ QActivationEvent *event = static_cast<QActivationEvent *>(e);
+ ComPtr<IInspectable> inspectable = event->args();
+ ComPtr<IActivatedEventArgs> arguments;
+ hr = inspectable.As(&arguments);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ActivationKind activationKind;
+ hr = arguments->get_Kind(&activationKind);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Handle only File, Folder and Save file pick continuation here.
+ if (activationKind != ActivationKind_PickFileContinuation
+ && activationKind != ActivationKind_PickFolderContinuation
+ && activationKind != ActivationKind_PickSaveFileContinuation) {
+ return false;
+ }
+
+ QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
+ Q_ASSERT(eventDispatcher);
+ eventDispatcher->removeEventFilter(this);
+ e->accept();
+
+ if (activationKind == ActivationKind_PickFileContinuation) {
+ ComPtr<IFileOpenPickerContinuationEventArgs> fileContinuationArgs;
+ hr = arguments.As(&fileContinuationArgs);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<StorageFile *>> files;
+ hr = fileContinuationArgs->get_Files(&files);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = onFilesPicked(files.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ } else if (activationKind == ActivationKind_PickFolderContinuation) {
+ ComPtr<IFolderPickerContinuationEventArgs> folderContinuationArgs;
+ hr = arguments.As(&folderContinuationArgs);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IStorageFolder> folder;
+ hr = folderContinuationArgs->get_Folder(&folder);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = onFolderPicked(folder.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ } else {
+ ComPtr<IFileSavePickerContinuationEventArgs> saveFileContinuationArgs;
+ hr = arguments.As(&saveFileContinuationArgs);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IStorageFile> file;
+ hr = saveFileContinuationArgs->get_File(&file);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = onFilePicked(file.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ return true;
+}
+#endif
+
void QWinRTFileDialogHelper::setDirectory(const QUrl &directory)
{
Q_D(QWinRTFileDialogHelper);
@@ -403,6 +562,7 @@ QString QWinRTFileDialogHelper::selectedNameFilter() const
return d->selectedNameFilter;
}
+#ifndef Q_OS_WINPHONE
HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *args, AsyncStatus status)
{
Q_D(QWinRTFileDialogHelper);
@@ -419,14 +579,7 @@ HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *
ComPtr<IStorageFile> file;
hr = args->GetResults(&file);
Q_ASSERT_SUCCEEDED(hr);
- if (!file) {
- emit reject();
- return S_OK;
- }
-
- appendFile(file.Get());
- emit accept();
- return S_OK;
+ return onFilePicked(file.Get());
}
HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorView<StorageFile *> *> *args, AsyncStatus status)
@@ -445,17 +598,50 @@ HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorVie
ComPtr<IVectorView<StorageFile *>> fileList;
hr = args->GetResults(&fileList);
RETURN_HR_IF_FAILED("Failed to get file list");
+ return onFilesPicked(fileList.Get());
+}
+
+HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFolder *> *args, AsyncStatus status)
+{
+ Q_D(QWinRTFileDialogHelper);
+
+ QEventLoopLocker locker(&d->loop);
+ d->shown = false;
+ d->selectedFiles.clear();
+ if (status == Canceled || status == Error) {
+ emit reject();
+ return S_OK;
+ }
+
+ HRESULT hr;
+ ComPtr<IStorageFolder> folder;
+ hr = args->GetResults(&folder);
+ Q_ASSERT_SUCCEEDED(hr);
+ return onFolderPicked(folder.Get());
+}
+#endif //Q_OS_WINPHONE
+
+HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files)
+{
+#ifdef Q_OS_WINPHONE
+ Q_D(QWinRTFileDialogHelper);
+ QEventLoopLocker locker(&d->loop);
+ d->shown = false;
+ d->selectedFiles.clear();
+#endif
+ HRESULT hr;
quint32 size;
- hr = fileList->get_Size(&size);
+ hr = files->get_Size(&size);
Q_ASSERT_SUCCEEDED(hr);
if (!size) {
emit reject();
return S_OK;
}
+
for (quint32 i = 0; i < size; ++i) {
ComPtr<IStorageFile> file;
- hr = fileList->GetAt(i, &file);
+ hr = files->GetAt(i, &file);
Q_ASSERT_SUCCEEDED(hr);
appendFile(file.Get());
}
@@ -464,28 +650,40 @@ HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorVie
return S_OK;
}
-HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFolder *> *args, AsyncStatus status)
+HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder)
{
+#ifdef Q_OS_WINPHONE
Q_D(QWinRTFileDialogHelper);
-
QEventLoopLocker locker(&d->loop);
d->shown = false;
d->selectedFiles.clear();
- if (status == Canceled || status == Error) {
+#endif
+
+ if (!folder) {
emit reject();
return S_OK;
}
- HRESULT hr;
- ComPtr<IStorageFolder> folder;
- hr = args->GetResults(&folder);
- Q_ASSERT_SUCCEEDED(hr);
- if (!folder) {
+ appendFile(folder);
+ emit accept();
+ return S_OK;
+}
+
+HRESULT QWinRTFileDialogHelper::onFilePicked(IStorageFile *file)
+{
+#ifdef Q_OS_WINPHONE
+ Q_D(QWinRTFileDialogHelper);
+ QEventLoopLocker locker(&d->loop);
+ d->shown = false;
+ d->selectedFiles.clear();
+#endif
+
+ if (!file) {
emit reject();
return S_OK;
}
- appendFile(folder.Get());
+ appendFile(file);
emit accept();
return S_OK;
}
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
index 51b79c84ef..d6bacd2db9 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
@@ -47,6 +47,7 @@ namespace ABI {
class StorageFile;
class StorageFolder;
struct IStorageFile;
+ struct IStorageFolder;
}
namespace Foundation {
enum class AsyncStatus;
@@ -71,6 +72,9 @@ public:
void exec() Q_DECL_OVERRIDE;
bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) Q_DECL_OVERRIDE;
void hide() Q_DECL_OVERRIDE;
+#ifdef Q_OS_WINPHONE
+ bool eventFilter(QObject *o, QEvent *e) Q_DECL_OVERRIDE;
+#endif
bool defaultNameFilterDisables() const Q_DECL_OVERRIDE { return false; }
void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE;
@@ -81,13 +85,19 @@ public:
void selectNameFilter(const QString &selectedNameFilter) Q_DECL_OVERRIDE;
QString selectedNameFilter() const;
-private:
+#ifndef Q_OS_WINPHONE
HRESULT onSingleFilePicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile *> *,
ABI::Windows::Foundation::AsyncStatus);
HRESULT onMultipleFilesPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *> *,
ABI::Windows::Foundation::AsyncStatus);
HRESULT onSingleFolderPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFolder *> *,
ABI::Windows::Foundation::AsyncStatus);
+#endif
+
+private:
+ HRESULT onFilesPicked(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *files);
+ HRESULT onFolderPicked(ABI::Windows::Storage::IStorageFolder *folder);
+ HRESULT onFilePicked(ABI::Windows::Storage::IStorageFile *file);
void appendFile(IInspectable *);
QScopedPointer<QWinRTFileDialogHelperPrivate> d_ptr;
diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp
index d9f8c8f991..b7125eec59 100644
--- a/src/winmain/qtmain_winrt.cpp
+++ b/src/winmain/qtmain_winrt.cpp
@@ -70,6 +70,7 @@ extern "C" {
#include <qdir.h>
#include <qstandardpaths.h>
#include <qfunctions_winrt.h>
+#include <qcoreapplication.h>
#include <wrl.h>
#include <Windows.ApplicationModel.core.h>
@@ -109,6 +110,24 @@ static void devMessageHandler(QtMsgType type, const QMessageLogContext &context,
defaultMessageHandler(type, context, message);
}
+class QActivationEvent : public QEvent
+{
+public:
+ explicit QActivationEvent(IInspectable *args)
+ : QEvent(QEvent::WinEventAct)
+ {
+ setAccepted(false);
+ args->AddRef();
+ d = reinterpret_cast<QEventPrivate *>(args);
+ }
+
+ ~QActivationEvent() {
+ IUnknown *args = reinterpret_cast<IUnknown *>(d);
+ args->Release();
+ d = nullptr;
+ }
+};
+
class AppContainer : public RuntimeClass<Xaml::IApplicationOverrides>
{
public:
@@ -158,7 +177,10 @@ public:
private:
HRESULT __stdcall OnActivated(IActivatedEventArgs *args) Q_DECL_OVERRIDE
{
- return base->OnActivated(args);
+ QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
+ if (dispatcher)
+ QCoreApplication::postEvent(dispatcher, new QActivationEvent(args));
+ return S_OK;
}
HRESULT __stdcall OnLaunched(ILaunchActivatedEventArgs *launchArgs) Q_DECL_OVERRIDE