summaryrefslogtreecommitdiffstats
path: root/src/widgets/dialogs
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@qt.io>2019-01-18 15:02:32 +0100
committerMorten Johan Sørvig <morten.sorvig@qt.io>2019-02-07 06:49:31 +0000
commit928cab5ff1d931d00074d8930c41537109814371 (patch)
tree2e242d8143e4b975d1a22aa650de0060189db4bd /src/widgets/dialogs
parent790cf25f9d811f2cda7e252b4f1844e8fce27e2a (diff)
wasm: add public API for local file access
The web sandbox restricts access to the local file system, which means Qt needs new public API to provide such access to applications. This adds a new static, asynchornous getOpenFileContent() function to QFileDialog, which will show a file dialog, read the file contents once a file has been selected, and finally call the user-provided callback with the selected file name and file data. auto fileReady = [](const QString &fileName, const QByteArray &fileContents) { // Process file } QFileDialog::getOpenFileContent("*.*", fileReady); This API can be expanded in at least two ways in the future: allow reading multiple files, and allow file streaming by returning a QOIDevice. Change-Id: I011b92fbcf21f0696604e66b7f9eb265c1a07aaa Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
Diffstat (limited to 'src/widgets/dialogs')
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp82
-rw-r--r--src/widgets/dialogs/qfiledialog.h4
2 files changed, 86 insertions, 0 deletions
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index f42cf89708..3e756da505 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -73,6 +73,9 @@
#elif defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
#endif
+#if defined(Q_OS_WASM)
+#include <private/qwasmlocalfileaccess_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -2348,6 +2351,85 @@ QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
}
/*!
+ This is a convenience static function that will return the content of a file
+ selected by the user.
+
+ This function is used to access local files on Qt for WebAssembly, where the web
+ sandbox places restrictions on how such access may happen. Its implementation will
+ make the browser display a native file dialog, where the user makes the file selection.
+
+ It can also be used on other platforms, where it will fall back to using QFileDialog.
+
+ The function is asynchronous and returns immediately. The \a fileOpenCompleted
+ callback will be called when a file has been selected and its contents has been
+ read into memory.
+
+ \snippet code/src_gui_dialogs_qfiledialog.cpp 14
+ \since 5.13
+*/
+void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::function<void(const QString &, const QByteArray &)> &fileOpenCompleted)
+{
+#ifdef Q_OS_WASM
+ auto openFileImpl = std::make_shared<std::function<void(void)>>();
+ QString fileName;
+ QByteArray fileContent;
+ *openFileImpl = [=]() mutable {
+ auto fileDialogClosed = [&](bool fileSelected) {
+ if (!fileSelected) {
+ fileOpenCompleted(fileName, fileContent);
+ openFileImpl.reset();
+ }
+ };
+ auto acceptFile = [&](uint64_t size, const std::string name) -> char * {
+ const uint64_t twoGB = 1ULL << 31; // QByteArray limit
+ if (size > twoGB)
+ return nullptr;
+
+ fileName = QString::fromStdString(name);
+ fileContent.resize(size);
+ return fileContent.data();
+ };
+ auto fileContentReady = [&]() mutable {
+ fileOpenCompleted(fileName, fileContent);
+ openFileImpl.reset();
+ };
+
+ auto qtFilterStringToWebAcceptString = [](const QString &qtString) {
+ // The Qt and Web name filter string formats are similar, but
+ // not identical.
+ return qtString.toStdString(); // ### TODO
+ };
+
+ QWasmLocalFileAccess::openFile(qtFilterStringToWebAcceptString(nameFilter), fileDialogClosed, acceptFile, fileContentReady);
+ };
+
+ (*openFileImpl)();
+#else
+ QFileDialog *dialog = new QFileDialog();
+ dialog->selectNameFilter(nameFilter);
+
+ auto fileSelected = [=](const QString &fileName) {
+ QByteArray fileContent;
+ if (!fileName.isNull()) {
+ QFile selectedFile(fileName);
+ selectedFile.open(QIODevice::ReadOnly);
+ fileContent = selectedFile.readAll();
+ }
+ fileOpenCompleted(fileName, fileContent);
+ };
+
+ auto dialogClosed = [=](int code) {
+ Q_UNUSED(code);
+ delete dialog;
+ };
+
+ connect(dialog, &QFileDialog::fileSelected, fileSelected);
+ connect(dialog, &QFileDialog::finished, dialogClosed);
+ dialog->show();
+#endif
+}
+
+/*!
This is a convenience static function that will return a file name selected
by the user. The file does not have to exist.
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
index 8a99112081..c75795fd77 100644
--- a/src/widgets/dialogs/qfiledialog.h
+++ b/src/widgets/dialogs/qfiledialog.h
@@ -46,6 +46,8 @@
#include <QtCore/qurl.h>
#include <QtWidgets/qdialog.h>
+#include <functional>
+
QT_REQUIRE_CONFIG(filedialog);
QT_BEGIN_NAMESPACE
@@ -273,6 +275,8 @@ public:
Options options = Options(),
const QStringList &supportedSchemes = QStringList());
+ static void getOpenFileContent(const QString &nameFilter,
+ const std::function<void(const QString &, const QByteArray &)> &fileContentsReady);
protected:
QFileDialog(const QFileDialogArgs &args);