summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/winrt
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@digia.com>2014-08-08 13:25:51 +0300
committerOswald Buddenhagen <oswald.buddenhagen@digia.com>2014-08-09 15:37:09 +0200
commit5dd7164c97bee863d29bfd724cfcad380e2c786a (patch)
treed3701f0dc6f732678a0513efe12d4cf1f0e5d866 /src/plugins/platforms/winrt
parent4413254ff603fa19f4fa22d4936e69f4a6dbbc2b (diff)
winrt: Use native file dialog
The native Windows Runtime file picker is required to support picking of any file/folder from the system. Due to platform security restrictions, the non-native file dialog is effectively useless when outside of the application's installation or local storage directories. This adds a QPA implementation for the WinRT file picker, as well as a simple file system engine to handle files which were opened by the picker. This necessary for platform security reasons, as it is not possible to open files from arbitrary paths - only file handles opened by the picker can be used, so these are kept inside this file system engine and acted upon when a known path is observed. The file system engine is only instantiated when needed, and may prove useful for other areas of Qt (such as known folders/standard paths) which must operate on a virtual file rather than an absolute path. Task-number: QTBUG-37748 Change-Id: Ia4fd6c5065ac92101ce34adcb6c9026fbcff56df Reviewed-by: Maurice Kalinowski <maurice.kalinowski@digia.com>
Diffstat (limited to 'src/plugins/platforms/winrt')
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp512
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.h104
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.cpp505
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.h104
-rw-r--r--src/plugins/platforms/winrt/qwinrtservices.cpp9
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.cpp5
-rw-r--r--src/plugins/platforms/winrt/winrt.pro4
7 files changed, 1241 insertions, 2 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
new file mode 100644
index 0000000000..768a94e951
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
@@ -0,0 +1,512 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtfiledialoghelper.h"
+#include "qwinrtfileengine.h"
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QMap>
+#include <QtCore/QVector>
+#include <QtCore/qfunctions_winrt.h>
+
+#include <wrl.h>
+#include <windows.foundation.h>
+#include <windows.storage.pickers.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::Storage::Pickers;
+
+typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler;
+typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler;
+typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler;
+
+QT_BEGIN_NAMESPACE
+
+// Required for save file picker
+class WindowsStringVector : public RuntimeClass<IVector<HSTRING>>
+{
+public:
+ HRESULT __stdcall GetAt(quint32 index, HSTRING *item)
+ {
+ *item = impl.at(index);
+ return S_OK;
+ }
+ HRESULT __stdcall get_Size(quint32 *size)
+ {
+ *size = impl.size();
+ return S_OK;
+ }
+ HRESULT __stdcall GetView(IVectorView<HSTRING> **view)
+ {
+ *view = Q_NULLPTR;
+ return E_NOTIMPL;
+ }
+ HRESULT __stdcall IndexOf(HSTRING value, quint32 *index, boolean *found)
+ {
+ *found = false;
+ for (int i = 0; i < impl.size(); ++i) {
+ qint32 result;
+ HRESULT hr = WindowsCompareStringOrdinal(impl.at(i), value, &result);
+ if (FAILED(hr))
+ return hr;
+ if (result == 0) {
+ *index = quint32(i);
+ *found = true;
+ break;
+ }
+ }
+ return S_OK;
+ }
+ HRESULT __stdcall SetAt(quint32 index, HSTRING item)
+ {
+ HSTRING newItem;
+ HRESULT hr = WindowsDuplicateString(item, &newItem);
+ if (FAILED(hr))
+ return hr;
+ impl[index] = newItem;
+ return S_OK;
+ }
+ HRESULT __stdcall InsertAt(quint32 index, HSTRING item)
+ {
+ HSTRING newItem;
+ HRESULT hr = WindowsDuplicateString(item, &newItem);
+ if (FAILED(hr))
+ return hr;
+ impl.insert(index, newItem);
+ return S_OK;
+ }
+ HRESULT __stdcall RemoveAt(quint32 index)
+ {
+ WindowsDeleteString(impl.takeAt(index));
+ return S_OK;
+ }
+ HRESULT __stdcall Append(HSTRING item)
+ {
+ HSTRING newItem;
+ HRESULT hr = WindowsDuplicateString(item, &newItem);
+ if (FAILED(hr))
+ return hr;
+ impl.append(newItem);
+ return S_OK;
+ }
+ HRESULT __stdcall RemoveAtEnd()
+ {
+ WindowsDeleteString(impl.takeLast());
+ return S_OK;
+ }
+ HRESULT __stdcall Clear()
+ {
+ foreach (const HSTRING &item, impl)
+ WindowsDeleteString(item);
+ impl.clear();
+ return S_OK;
+ }
+private:
+ QVector<HSTRING> impl;
+};
+
+template<typename T>
+static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options)
+{
+ HRESULT hr;
+
+ ComPtr<IInspectable> basePicker;
+ hr = RoActivateInstance(runtimeId, &basePicker);
+ RETURN_FALSE_IF_FAILED("Failed to instantiate file picker");
+ hr = basePicker.Get()->QueryInterface(IID_PPV_ARGS(picker));
+ RETURN_FALSE_IF_FAILED("Failed to cast file picker");
+
+ if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) {
+ const QString labelText = options->labelText(QFileDialogOptions::Accept);
+ HStringReference labelTextRef(reinterpret_cast<const wchar_t *>(labelText.utf16()),
+ labelText.length());
+ hr = (*picker)->put_CommitButtonText(labelTextRef.Get());
+ RETURN_FALSE_IF_FAILED("Failed to set commit button text");
+ }
+
+ return true;
+}
+
+template<typename T>
+static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDialogOptions> &options)
+{
+ HRESULT hr;
+ hr = picker->put_ViewMode(options->viewMode() == QFileDialogOptions::Detail
+ ? PickerViewMode_Thumbnail : PickerViewMode_List);
+ RETURN_FALSE_IF_FAILED("Failed to set picker view mode");
+
+ ComPtr<IVector<HSTRING>> filters;
+ hr = picker->get_FileTypeFilter(&filters);
+ RETURN_FALSE_IF_FAILED("Failed to get file type filters list");
+ foreach (const QString &namedFilter, options->nameFilters()) {
+ foreach (const QString &filter, QPlatformFileDialogHelper::cleanFilterList(namedFilter)) {
+ // Remove leading star
+ const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0;
+ HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset),
+ filter.length() - offset);
+ hr = filters->Append(filterRef.Get());
+ if (FAILED(hr)) {
+ qWarning("Failed to add named file filter \"%s\": %s",
+ qPrintable(filter), qPrintable(qt_error_string(hr)));
+ }
+ }
+ }
+ // The file dialog won't open with an empty list - add a default wildcard
+ quint32 size;
+ hr = filters->get_Size(&size);
+ RETURN_FALSE_IF_FAILED("Failed to get file type filters list size");
+ if (!size) {
+ hr = filters->Append(HString::MakeReference(L"*").Get());
+ RETURN_FALSE_IF_FAILED("Failed to add default wildcard to file type filters list");
+ }
+
+ return true;
+}
+
+class QWinRTFileDialogHelperPrivate
+{
+public:
+ bool shown;
+ QEventLoop loop;
+
+ // Input
+ QUrl directory;
+ QUrl saveFileName;
+ QString selectedNameFilter;
+
+ // Output
+ QList<QUrl> selectedFiles;
+};
+
+QWinRTFileDialogHelper::QWinRTFileDialogHelper()
+ : QPlatformFileDialogHelper(), d_ptr(new QWinRTFileDialogHelperPrivate)
+{
+ Q_D(QWinRTFileDialogHelper);
+
+ d->shown = false;
+}
+
+QWinRTFileDialogHelper::~QWinRTFileDialogHelper()
+{
+}
+
+void QWinRTFileDialogHelper::exec()
+{
+ Q_D(QWinRTFileDialogHelper);
+
+ if (!d->shown)
+ show(Qt::Dialog, Qt::ApplicationModal, 0);
+ d->loop.exec();
+}
+
+bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
+{
+ Q_UNUSED(windowFlags)
+ Q_UNUSED(windowModality)
+ Q_UNUSED(parent)
+ Q_D(QWinRTFileDialogHelper);
+
+ HRESULT hr;
+ const QSharedPointer<QFileDialogOptions> dialogOptions = options();
+ switch (dialogOptions->acceptMode()) {
+ default:
+ case QFileDialogOptions::AcceptOpen: {
+ switch (dialogOptions->fileMode()) {
+ case QFileDialogOptions::AnyFile:
+ case QFileDialogOptions::ExistingFile:
+ case QFileDialogOptions::ExistingFiles: {
+ ComPtr<IFileOpenPicker> picker;
+ if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileOpenPicker).Get(),
+ picker.GetAddressOf(), dialogOptions)) {
+ return false;
+ }
+ 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");
+ break;
+ }
+ case QFileDialogOptions::Directory:
+ case QFileDialogOptions::DirectoryOnly: {
+ ComPtr<IFolderPicker> picker;
+ if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FolderPicker).Get(),
+ picker.GetAddressOf(), dialogOptions)) {
+ return false;
+ }
+ 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");
+ break;
+ }
+ }
+ break;
+ }
+ case QFileDialogOptions::AcceptSave: {
+ ComPtr<IFileSavePicker> picker;
+ if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileSavePicker).Get(),
+ picker.GetAddressOf(), dialogOptions)) {
+ return false;
+ }
+
+ ComPtr<IMap<HSTRING, IVector<HSTRING> *>> choices;
+ hr = picker->get_FileTypeChoices(&choices);
+ RETURN_FALSE_IF_FAILED("Failed to get file extension choices");
+ foreach (const QString &namedFilter, dialogOptions->nameFilters()) {
+ ComPtr<IVector<HSTRING>> entry = Make<WindowsStringVector>();
+ foreach (const QString &filter, QPlatformFileDialogHelper::cleanFilterList(namedFilter)) {
+ // Remove leading star
+ const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0;
+ HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset),
+ filter.length() - offset);
+ hr = entry->Append(filterRef.Get());
+ if (FAILED(hr)) {
+ qWarning("Failed to add named file filter \"%s\": %s",
+ qPrintable(filter), qPrintable(qt_error_string(hr)));
+ }
+ }
+ const int offset = namedFilter.indexOf(QLatin1String(" ("));
+ const QString filterTitle = offset > 0 ? namedFilter.left(offset) : filterTitle;
+ HStringReference namedFilterRef(reinterpret_cast<const wchar_t *>(filterTitle.utf16()),
+ filterTitle.length());
+ boolean replaced;
+ hr = choices->Insert(namedFilterRef.Get(), entry.Get(), &replaced);
+ RETURN_FALSE_IF_FAILED("Failed to insert file extension choice entry");
+ }
+
+ const QString suffix = dialogOptions->defaultSuffix();
+ HStringReference nativeSuffix(reinterpret_cast<const wchar_t *>(suffix.utf16()),
+ suffix.length());
+ hr = picker->put_DefaultFileExtension(nativeSuffix.Get());
+ RETURN_FALSE_IF_FAILED("Failed to set default file extension");
+
+ const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName();
+ HStringReference nativeSuggestedName(reinterpret_cast<const wchar_t *>(suggestedName.utf16()),
+ suggestedName.length());
+ hr = picker->put_SuggestedFileName(nativeSuggestedName.Get());
+ 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");
+ break;
+ }
+ }
+
+ d->shown = true;
+ return true;
+}
+
+void QWinRTFileDialogHelper::hide()
+{
+ Q_D(QWinRTFileDialogHelper);
+
+ if (!d->shown)
+ return;
+
+ d->shown = false;
+}
+
+void QWinRTFileDialogHelper::setDirectory(const QUrl &directory)
+{
+ Q_D(QWinRTFileDialogHelper);
+ d->directory = directory;
+}
+
+QUrl QWinRTFileDialogHelper::directory() const
+{
+ Q_D(const QWinRTFileDialogHelper);
+ return d->directory;
+}
+
+void QWinRTFileDialogHelper::selectFile(const QUrl &saveFileName)
+{
+ Q_D(QWinRTFileDialogHelper);
+ d->saveFileName = saveFileName;
+}
+
+QList<QUrl> QWinRTFileDialogHelper::selectedFiles() const
+{
+ Q_D(const QWinRTFileDialogHelper);
+ return d->selectedFiles;
+}
+
+void QWinRTFileDialogHelper::selectNameFilter(const QString &selectedNameFilter)
+{
+ Q_D(QWinRTFileDialogHelper);
+ d->selectedNameFilter = selectedNameFilter;
+}
+
+QString QWinRTFileDialogHelper::selectedNameFilter() const
+{
+ Q_D(const QWinRTFileDialogHelper);
+ return d->selectedNameFilter;
+}
+
+HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *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<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;
+}
+
+HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorView<StorageFile *> *> *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<IVectorView<StorageFile *>> fileList;
+ hr = args->GetResults(&fileList);
+ RETURN_HR_IF_FAILED("Failed to get file list");
+
+ quint32 size;
+ hr = fileList->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);
+ Q_ASSERT_SUCCEEDED(hr);
+ appendFile(file.Get());
+ }
+
+ emit accept();
+ return S_OK;
+}
+
+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);
+ if (!folder) {
+ emit reject();
+ return S_OK;
+ }
+
+ appendFile(folder.Get());
+ emit accept();
+ return S_OK;
+}
+
+void QWinRTFileDialogHelper::appendFile(IInspectable *file)
+{
+ Q_D(QWinRTFileDialogHelper);
+
+ HRESULT hr;
+ ComPtr<IStorageItem> item;
+ hr = file->QueryInterface(IID_PPV_ARGS(&item));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ HString path;
+ hr = item->get_Path(path.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ quint32 pathLen;
+ const wchar_t *pathStr = path.GetRawBuffer(&pathLen);
+ const QString filePath = QString::fromWCharArray(pathStr, pathLen);
+ QWinRTFileEngineHandler::registerFile(filePath, item.Get());
+ d->selectedFiles.append(QUrl::fromLocalFile(filePath));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
new file mode 100644
index 0000000000..f333f3f4ae
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTFILEDIALOGHELPER_H
+#define QWINRTFILEDIALOGHELPER_H
+
+#include <qpa/qplatformdialoghelper.h>
+#include <QtCore/qt_windows.h>
+
+struct IInspectable;
+namespace ABI {
+ namespace Windows {
+ namespace Storage {
+ class StorageFile;
+ class StorageFolder;
+ struct IStorageFile;
+ }
+ namespace Foundation {
+ enum class AsyncStatus;
+ template <typename T> struct IAsyncOperation;
+ namespace Collections {
+ template <typename T> struct IVectorView;
+ }
+ }
+ }
+}
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTFileDialogHelperPrivate;
+class QWinRTFileDialogHelper : public QPlatformFileDialogHelper
+{
+ Q_OBJECT
+public:
+ explicit QWinRTFileDialogHelper();
+ ~QWinRTFileDialogHelper();
+
+ void exec() Q_DECL_OVERRIDE;
+ bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) Q_DECL_OVERRIDE;
+ void hide() Q_DECL_OVERRIDE;
+
+ bool defaultNameFilterDisables() const Q_DECL_OVERRIDE { return false; }
+ void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE;
+ QUrl directory() const Q_DECL_OVERRIDE;
+ void selectFile(const QUrl &saveFileName);
+ QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
+ void setFilter() Q_DECL_OVERRIDE { }
+ void selectNameFilter(const QString &selectedNameFilter) Q_DECL_OVERRIDE;
+ QString selectedNameFilter() const;
+
+private:
+ 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);
+ void appendFile(IInspectable *);
+
+ QScopedPointer<QWinRTFileDialogHelperPrivate> d_ptr;
+ Q_DECLARE_PRIVATE(QWinRTFileDialogHelper)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTFILEDIALOGHELPER_H
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
new file mode 100644
index 0000000000..3a4aa519cc
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
@@ -0,0 +1,505 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtfileengine.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QHash>
+#include <QtCore/qfunctions_winrt.h>
+
+#include <wrl.h>
+#include <windows.storage.h>
+#include <robuffer.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::Storage::Streams;
+
+typedef IAsyncOperationCompletedHandler<IRandomAccessStream *> StreamCompletedHandler;
+typedef IAsyncOperationWithProgressCompletedHandler<IBuffer *, UINT32> StreamReadCompletedHandler;
+
+QT_BEGIN_NAMESPACE
+
+#define RETURN_AND_SET_ERROR_IF_FAILED(error, ret) \
+ setError(error, qt_error_string(hr)); \
+ if (FAILED(hr)) \
+ return ret;
+
+Q_GLOBAL_STATIC(QWinRTFileEngineHandler, handlerInstance)
+
+class QWinRTFileEngineHandlerPrivate
+{
+public:
+ QHash<QString, ComPtr<IStorageItem>> files;
+};
+
+class QWinRTFileEnginePrivate
+{
+public:
+ QWinRTFileEnginePrivate(const QString &fileName, IStorageItem *file)
+ : fileName(fileName), file(file)
+ {
+ HRESULT hr;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ IID_PPV_ARGS(&bufferFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ lastSeparator = fileName.size() - 1;
+ for (int i = lastSeparator; i >= 0; --i) {
+ if (fileName.at(i).unicode() == '/' || fileName.at(i).unicode() == '\\') {
+ lastSeparator = i;
+ break;
+ }
+ }
+
+ firstDot = fileName.size();
+ for (int i = lastSeparator; i > fileName.size(); ++i) {
+ if (fileName.at(i).unicode() == '.') {
+ firstDot = i;
+ break;
+ }
+ }
+ }
+
+ ComPtr<IBufferFactory> bufferFactory;
+
+ QString fileName;
+ int lastSeparator;
+ int firstDot;
+ ComPtr<IStorageItem> file;
+ ComPtr<IRandomAccessStream> stream;
+
+ qint64 pos;
+
+private:
+ QWinRTFileEngineHandler *q_ptr;
+ Q_DECLARE_PUBLIC(QWinRTFileEngineHandler)
+};
+
+
+QWinRTFileEngineHandler::QWinRTFileEngineHandler()
+ : d_ptr(new QWinRTFileEngineHandlerPrivate)
+{
+}
+
+QWinRTFileEngineHandler::~QWinRTFileEngineHandler()
+{
+}
+
+void QWinRTFileEngineHandler::registerFile(const QString &fileName, IStorageItem *file)
+{
+ handlerInstance->d_func()->files.insert(QDir::cleanPath(fileName), file);
+}
+
+IStorageItem *QWinRTFileEngineHandler::registeredFile(const QString &fileName)
+{
+ return handlerInstance->d_func()->files.value(fileName).Get();
+}
+
+QAbstractFileEngine *QWinRTFileEngineHandler::create(const QString &fileName) const
+{
+ Q_D(const QWinRTFileEngineHandler);
+
+ QHash<QString, ComPtr<IStorageItem>>::const_iterator file = d->files.find(fileName);
+ if (file != d->files.end())
+ return new QWinRTFileEngine(fileName, file.value().Get());
+
+ return Q_NULLPTR;
+}
+
+static HRESULT getDestinationFolder(const QString &fileName, const QString newFileName,
+ IStorageItem *file, IStorageFolder **folder)
+{
+ HRESULT hr;
+ ComPtr<IAsyncOperation<StorageFolder *>> op;
+ QFileInfo newFileInfo(newFileName);
+#ifndef Q_OS_WINPHONE
+ QFileInfo fileInfo(fileName);
+ if (fileInfo.dir() == newFileInfo.dir()) {
+ ComPtr<IStorageItem2> item;
+ hr = file->QueryInterface(IID_PPV_ARGS(&item));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = item->GetParentAsync(&op);
+ } else
+#else
+ Q_UNUSED(fileName);
+ Q_UNUSED(file)
+#endif
+ {
+ ComPtr<IStorageFolderStatics> folderFactory;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFolder).Get(),
+ IID_PPV_ARGS(&folderFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ const QString newFilePath = QDir::toNativeSeparators(newFileInfo.absolutePath());
+ HStringReference nativeNewFilePath(reinterpret_cast<LPCWSTR>(newFilePath.utf16()),
+ newFilePath.length());
+ hr = folderFactory->GetFolderFromPathAsync(nativeNewFilePath.Get(), &op);
+ }
+ if (FAILED(hr))
+ return hr;
+ return QWinRTFunctions::await(op, folder);
+}
+
+QWinRTFileEngine::QWinRTFileEngine(const QString &fileName, IStorageItem *file)
+ : d_ptr(new QWinRTFileEnginePrivate(fileName, file))
+{
+}
+
+QWinRTFileEngine::~QWinRTFileEngine()
+{
+}
+
+bool QWinRTFileEngine::open(QIODevice::OpenMode openMode)
+{
+ Q_D(QWinRTFileEngine);
+
+ FileAccessMode fileAccessMode = (openMode & QIODevice::WriteOnly)
+ ? FileAccessMode_ReadWrite : FileAccessMode_Read;
+
+ HRESULT hr;
+ ComPtr<IStorageFile> file;
+ hr = d->file.As(&file);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false);
+
+ ComPtr<IAsyncOperation<IRandomAccessStream *>> op;
+ hr = file->OpenAsync(fileAccessMode, &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false);
+
+ hr = QWinRTFunctions::await(op, d->stream.GetAddressOf());
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false);
+
+ return SUCCEEDED(hr);
+}
+
+bool QWinRTFileEngine::close()
+{
+ Q_D(QWinRTFileEngine);
+
+ if (!d->stream)
+ return false;
+
+ ComPtr<IClosable> closable;
+ HRESULT hr = d->stream.As(&closable);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = closable->Close();
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::UnspecifiedError, false);
+ d->stream.Reset();
+ return SUCCEEDED(hr);
+}
+
+qint64 QWinRTFileEngine::size() const
+{
+ Q_D(const QWinRTFileEngine);
+
+ if (!d->stream)
+ return 0;
+
+ UINT64 size;
+ HRESULT hr;
+ hr = d->stream->get_Size(&size);
+ RETURN_IF_FAILED("Failed to get file size", return 0);
+
+ return qint64(size);
+}
+
+qint64 QWinRTFileEngine::pos() const
+{
+ Q_D(const QWinRTFileEngine);
+ return d->pos;
+}
+
+bool QWinRTFileEngine::seek(qint64 pos)
+{
+ Q_D(QWinRTFileEngine);
+
+ if (!d->stream)
+ return false;
+
+ HRESULT hr = d->stream->Seek(pos);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::PositionError, false);
+ d->pos = pos;
+ return SUCCEEDED(hr);
+}
+
+bool QWinRTFileEngine::remove()
+{
+ Q_D(QWinRTFileEngine);
+
+ ComPtr<IAsyncAction> op;
+ HRESULT hr = d->file->DeleteAsync(StorageDeleteOption_Default, &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RemoveError, false);
+
+ hr = QWinRTFunctions::await(op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RemoveError, false);
+ return SUCCEEDED(hr);
+}
+
+bool QWinRTFileEngine::copy(const QString &newName)
+{
+ Q_D(QWinRTFileEngine);
+
+ HRESULT hr;
+ ComPtr<IStorageFolder> destinationFolder;
+ hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf());
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
+
+ ComPtr<IStorageFile> file;
+ hr = d->file.As(&file);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
+
+ const QString destinationName = QFileInfo(newName).fileName();
+ HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length());
+ ComPtr<IAsyncOperation<StorageFile *>> op;
+ hr = file->CopyOverloadDefaultOptions(destinationFolder.Get(), nativeDestinationName.Get(), &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
+
+ ComPtr<IStorageFile> newFile;
+ hr = QWinRTFunctions::await(op, newFile.GetAddressOf());
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
+ return SUCCEEDED(hr);
+}
+
+bool QWinRTFileEngine::rename(const QString &newName)
+{
+ Q_D(QWinRTFileEngine);
+
+ HRESULT hr;
+ ComPtr<IStorageFolder> destinationFolder;
+ hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf());
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
+
+ const QString destinationName = QFileInfo(newName).fileName();
+ HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length());
+ ComPtr<IAsyncAction> op;
+ hr = d->file->RenameAsyncOverloadDefaultOptions(nativeDestinationName.Get(), &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
+ return SUCCEEDED(hr);
+}
+
+bool QWinRTFileEngine::renameOverwrite(const QString &newName)
+{
+ Q_D(QWinRTFileEngine);
+
+ HRESULT hr;
+ ComPtr<IStorageFolder> destinationFolder;
+ hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf());
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
+
+ const QString destinationName = QFileInfo(newName).fileName();
+ HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length());
+ ComPtr<IAsyncAction> op;
+ hr = d->file->RenameAsync(nativeDestinationName.Get(), NameCollisionOption_ReplaceExisting, &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
+ return SUCCEEDED(hr);
+}
+
+QAbstractFileEngine::FileFlags QWinRTFileEngine::fileFlags(FileFlags type) const
+{
+ Q_D(const QWinRTFileEngine);
+
+ FileFlags flags = ExistsFlag|ReadOwnerPerm|ReadUserPerm|WriteOwnerPerm|WriteUserPerm;
+
+ HRESULT hr;
+ FileAttributes attributes;
+ hr = d->file->get_Attributes(&attributes);
+ RETURN_IF_FAILED("Failed to get file attributes", return flags);
+ if (attributes & FileAttributes_ReadOnly)
+ flags ^= WriteUserPerm;
+ if (attributes & FileAttributes_Directory)
+ flags |= DirectoryType;
+ else
+ flags |= FileType;
+
+ return type & flags;
+}
+
+bool QWinRTFileEngine::setPermissions(uint perms)
+{
+ Q_UNUSED(perms);
+ Q_UNIMPLEMENTED();
+ return false;
+}
+
+QString QWinRTFileEngine::fileName(FileName type) const
+{
+ Q_D(const QWinRTFileEngine);
+
+ switch (type) {
+ default:
+ case DefaultName:
+ case AbsoluteName:
+ case CanonicalName:
+ break;
+ case BaseName:
+ return d->lastSeparator < 0
+ ? d->fileName : d->fileName.mid(d->lastSeparator, d->firstDot - d->lastSeparator);
+ case PathName:
+ case AbsolutePathName:
+ case CanonicalPathName:
+ return d->fileName.mid(0, d->lastSeparator);
+ case LinkName:
+ case BundleName:
+ return QString();
+ }
+ return d->fileName;
+}
+
+QDateTime QWinRTFileEngine::fileTime(FileTime type) const
+{
+ Q_D(const QWinRTFileEngine);
+
+ HRESULT hr;
+ DateTime dateTime = { 0 };
+ switch (type) {
+ case CreationTime:
+ hr = d->file->get_DateCreated(&dateTime);
+ RETURN_IF_FAILED("Failed to get file creation time", return QDateTime());
+ break;
+ case ModificationTime:
+ case AccessTime: {
+ ComPtr<IAsyncOperation<FileProperties::BasicProperties *>> op;
+ hr = d->file->GetBasicPropertiesAsync(&op);
+ RETURN_IF_FAILED("Failed to initiate file properties", return QDateTime());
+ ComPtr<FileProperties::IBasicProperties> properties;
+ hr = QWinRTFunctions::await(op, properties.GetAddressOf());
+ RETURN_IF_FAILED("Failed to get file properties", return QDateTime());
+ hr = type == ModificationTime ? properties->get_DateModified(&dateTime)
+ : properties->get_ItemDate(&dateTime);
+ RETURN_IF_FAILED("Failed to get file date", return QDateTime());
+ }
+ break;
+ }
+
+ SYSTEMTIME systemTime;
+ FileTimeToSystemTime((const FILETIME *)&dateTime, &systemTime);
+ QDate date(systemTime.wYear, systemTime.wMonth, systemTime.wDay);
+ QTime time(systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
+ return QDateTime(date, time);
+}
+
+qint64 QWinRTFileEngine::read(char *data, qint64 maxlen)
+{
+ Q_D(QWinRTFileEngine);
+
+ if (!d->stream)
+ return -1;
+
+ ComPtr<IInputStream> stream;
+ HRESULT hr = d->stream.As(&stream);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+
+ UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX));
+ ComPtr<IBuffer> buffer;
+ hr = d->bufferFactory->Create(length, &buffer);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+
+ ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> op;
+ hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+
+ hr = QWinRTFunctions::await(op, buffer.GetAddressOf());
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+
+ hr = buffer->get_Length(&length);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
+ memcpy(data, bytes, length);
+ return qint64(length);
+}
+
+qint64 QWinRTFileEngine::write(const char *data, qint64 maxlen)
+{
+ Q_D(QWinRTFileEngine);
+
+ if (!d->stream)
+ return -1;
+
+ ComPtr<IOutputStream> stream;
+ HRESULT hr = d->stream.As(&stream);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+
+ UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX));
+ ComPtr<IBuffer> buffer;
+ hr = d->bufferFactory->Create(length, &buffer);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+ hr = buffer->put_Length(length);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+ memcpy(bytes, data, length);
+
+ ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
+ hr = stream->WriteAsync(buffer.Get(), &op);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+
+ hr = QWinRTFunctions::await(op, &length);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+
+ ComPtr<IAsyncOperation<bool>> flushOp;
+ hr = stream->FlushAsync(&flushOp);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+ boolean flushed;
+ hr = QWinRTFunctions::await(flushOp, &flushed);
+ RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
+
+ return qint64(length);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.h b/src/plugins/platforms/winrt/qwinrtfileengine.h
new file mode 100644
index 0000000000..59eeb1c44c
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtfileengine.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTFILEENGINE_H
+#define QWINRTFILEENGINE_H
+
+#include <private/qabstractfileengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace ABI {
+ namespace Windows {
+ namespace Storage {
+ struct IStorageItem;
+ }
+ }
+}
+
+class QWinRTFileEngineHandlerPrivate;
+class QWinRTFileEngineHandler : public QAbstractFileEngineHandler
+{
+public:
+ QWinRTFileEngineHandler();
+ ~QWinRTFileEngineHandler();
+ QAbstractFileEngine *create(const QString &fileName) const Q_DECL_OVERRIDE;
+
+ static void registerFile(const QString &fileName, ABI::Windows::Storage::IStorageItem *file);
+ static ABI::Windows::Storage::IStorageItem *registeredFile(const QString &fileName);
+
+private:
+ QScopedPointer<QWinRTFileEngineHandlerPrivate> d_ptr;
+ Q_DECLARE_PRIVATE(QWinRTFileEngineHandler)
+};
+
+class QWinRTFileEnginePrivate;
+class QWinRTFileEngine : public QAbstractFileEngine
+{
+public:
+ QWinRTFileEngine(const QString &fileName, ABI::Windows::Storage::IStorageItem *file);
+ ~QWinRTFileEngine();
+
+ bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE;
+ bool close() Q_DECL_OVERRIDE;
+ qint64 size() const Q_DECL_OVERRIDE;
+ qint64 pos() const Q_DECL_OVERRIDE;
+ bool seek(qint64 pos) Q_DECL_OVERRIDE;
+ bool remove() Q_DECL_OVERRIDE;
+ bool copy(const QString &newName) Q_DECL_OVERRIDE;
+ bool rename(const QString &newName) Q_DECL_OVERRIDE;
+ bool renameOverwrite(const QString &newName) Q_DECL_OVERRIDE;
+ FileFlags fileFlags(FileFlags type=FileInfoAll) const Q_DECL_OVERRIDE;
+ bool setPermissions(uint perms) Q_DECL_OVERRIDE;
+ QString fileName(FileName type=DefaultName) const Q_DECL_OVERRIDE;
+ QDateTime fileTime(FileTime type) const Q_DECL_OVERRIDE;
+
+ qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
+ qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE;
+
+private:
+ QScopedPointer<QWinRTFileEnginePrivate> d_ptr;
+ Q_DECLARE_PRIVATE(QWinRTFileEngine)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTFILEENGINE_H
diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp
index 6272b46f44..4ee2aa68f8 100644
--- a/src/plugins/platforms/winrt/qwinrtservices.cpp
+++ b/src/plugins/platforms/winrt/qwinrtservices.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qwinrtservices.h"
+#include "qwinrtfileengine.h"
#include <QtCore/QUrl>
#include <QtCore/QDir>
#include <QtCore/QCoreApplication>
@@ -115,7 +116,13 @@ bool QWinRTServices::openDocument(const QUrl &url)
HRESULT hr;
ComPtr<IStorageFile> file;
- {
+ ComPtr<IStorageItem> item = QWinRTFileEngineHandler::registeredFile(url.toLocalFile());
+ if (item) {
+ hr = item.As(&file);
+ if (FAILED(hr))
+ qErrnoWarning(hr, "Failed to cast picked item to a file");
+ }
+ if (!file) {
const QString pathString = QDir::toNativeSeparators(url.toLocalFile());
HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), pathString.length());
ComPtr<IAsyncOperation<StorageFile *>> op;
diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp
index f9c2e21676..3566683163 100644
--- a/src/plugins/platforms/winrt/qwinrttheme.cpp
+++ b/src/plugins/platforms/winrt/qwinrttheme.cpp
@@ -41,6 +41,7 @@
#include "qwinrttheme.h"
#include "qwinrtmessagedialoghelper.h"
+#include "qwinrtfiledialoghelper.h"
#include <QtCore/qfunctions_winrt.h>
#include <QtGui/QPalette>
@@ -134,7 +135,7 @@ bool QWinRTTheme::usePlatformNativeDialog(DialogType type) const
static bool useNativeDialogs = qEnvironmentVariableIsSet("QT_USE_WINRT_NATIVE_DIALOGS")
? qgetenv("QT_USE_WINRT_NATIVE_DIALOGS").toInt() : true;
- if (type == MessageDialog)
+ if (type == FileDialog || type == MessageDialog)
return useNativeDialogs;
return false;
}
@@ -142,6 +143,8 @@ bool QWinRTTheme::usePlatformNativeDialog(DialogType type) const
QPlatformDialogHelper *QWinRTTheme::createPlatformDialogHelper(DialogType type) const
{
switch (type) {
+ case FileDialog:
+ return new QWinRTFileDialogHelper;
case MessageDialog:
return new QWinRTMessageDialogHelper(this);
default:
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 214ac0e154..80429daeed 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -32,6 +32,8 @@ SOURCES = \
qwinrtcursor.cpp \
qwinrteglcontext.cpp \
qwinrteventdispatcher.cpp \
+ qwinrtfiledialoghelper.cpp \
+ qwinrtfileengine.cpp \
qwinrtfontdatabase.cpp \
qwinrtinputcontext.cpp \
qwinrtintegration.cpp \
@@ -47,6 +49,8 @@ HEADERS = \
qwinrtcursor.h \
qwinrteglcontext.h \
qwinrteventdispatcher.h \
+ qwinrtfiledialoghelper.h \
+ qwinrtfileengine.h \
qwinrtfontdatabase.h \
qwinrtinputcontext.h \
qwinrtintegration.h \