summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMorten Sørvig <morten.sorvig@qt.io>2022-12-16 15:22:32 +0100
committerMorten Johan Sørvig <morten.sorvig@qt.io>2022-12-28 13:21:37 +0000
commitfbf2a318dd3f1e0f9fc8dadb68d47923dff3d672 (patch)
tree0e7047dcc1e93eeb959b5a8720220d274f47d925 /src
parent7b64eb71c0fe68540d97eb22492b4d0b0a647e9f (diff)
wasm: align QWasmLocalFileAccess API with 6.4
This API is undocumented, but by keeping unchanged makes it easier to use from external projects. openFile(): Copy the accept/filter list parsing function from 6.4. It makes sense to implement this behind the API, so that user code doesn't have to reimplement it. saveFile(): Slightly more complicated; the new variant which takes a QByteArray is better since the implementation can then keep a reference to the data for as long as it needs, without copying the data. Add the const char * variant to keep existing code going for now. Adjust the calling code in widgets. Pick-to: 6.5 Change-Id: I1899ebffdb90e40429dcb10313ccc5334f20c34f Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io> Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess.cpp89
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess_p.h5
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp2
3 files changed, 87 insertions, 9 deletions
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
index 47deb0d553..72f1dcc339 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
@@ -9,6 +9,8 @@
#include <emscripten/html5.h>
#include <emscripten/val.h>
+#include <QtCore/qregularexpression.h>
+
QT_BEGIN_NAMESPACE
namespace QWasmLocalFileAccess {
@@ -132,15 +134,76 @@ void readFiles(const qstdweb::FileList &fileList,
(*readFile)(0);
}
+
+QStringList acceptListFromQtFormat(const std::string &qtAcceptList)
+{
+ // copy of qt_make_filter_list() from qfiledialog.cpp
+ auto make_filter_list = [](const QString &filter) -> QStringList
+ {
+ if (filter.isEmpty())
+ return QStringList();
+
+ QString sep(";;");
+ if (!filter.contains(sep) && filter.contains(u'\n'))
+ sep = u'\n';
+
+ return filter.split(sep);
+ };
+
+ const QStringList fileFilter = make_filter_list(QString::fromStdString(qtAcceptList));
+ QStringList transformed;
+ for (const auto &element : fileFilter) {
+ // Accepts either a string in format:
+ // GROUP3
+ // or in this format:
+ // GROUP1 (GROUP2)
+ // Group 1 is treated as the description, whereas group 2 or 3 are treated as the filter
+ // list.
+ static QRegularExpression regex(
+ QString(QStringLiteral("(?:([^(]*)\\(([^()]+)\\)[^)]*)|([^()]+)")));
+ static QRegularExpression wordCharacterRegex(QString(QStringLiteral("\\w")));
+ const auto match = regex.match(element);
+
+ if (!match.hasMatch())
+ continue;
+
+ constexpr size_t FilterListFromParensIndex = 2;
+ constexpr size_t PlainFilterListIndex = 3;
+ QString filterList = match.captured(match.hasCaptured(FilterListFromParensIndex)
+ ? FilterListFromParensIndex
+ : PlainFilterListIndex);
+ for (auto singleExtension : filterList.split(QStringLiteral(" "), Qt::SkipEmptyParts)) {
+ // Checks for a filter that matches everything:
+ // Any number of asterisks or any number of asterisks with a '.' between them.
+ // The web filter does not support wildcards.
+ static QRegularExpression qtAcceptAllRegex(QRegularExpression::anchoredPattern(
+ QString(QStringLiteral("[*]+|[*]+\\.[*]+"))));
+ if (qtAcceptAllRegex.match(singleExtension).hasMatch())
+ continue;
+
+ // Checks for correctness. The web filter only allows filename extensions and does not
+ // filter the actual filenames, therefore we check whether the filter provided only
+ // filters for the extension.
+ static QRegularExpression qtFilenameMatcherRegex(QRegularExpression::anchoredPattern(
+ QString(QStringLiteral("(\\*?)(\\.[^*]+)"))));
+
+ auto extensionMatch = qtFilenameMatcherRegex.match(singleExtension);
+ if (extensionMatch.hasMatch())
+ transformed.append(extensionMatch.captured(2));
+ }
+ }
+ return transformed;
+}
+
}
-void downloadDataAsFile(const QByteArray &data, const std::string &fileNameHint)
+void downloadDataAsFile(const char *content, size_t size, const std::string &fileNameHint)
{
// Save a file by creating programmatically clicking a download
// link to an object url to a Blob containing a copy of the file
// content. The copy is made so that the passed in content buffer
// can be released as soon as this function returns.
- qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(data.constData(), data.size());
+ qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(content, size);
emscripten::val document = emscripten::val::global("document");
emscripten::val window = qstdweb::window();
emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob.val());
@@ -157,12 +220,12 @@ void downloadDataAsFile(const QByteArray &data, const std::string &fileNameHint)
window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl);
}
-void openFiles(const QStringList &accept, FileSelectMode fileSelectMode,
+void openFiles(const std::string &accept, FileSelectMode fileSelectMode,
const std::function<void (int fileCount)> &fileDialogClosed,
const std::function<char *(uint64_t size, const std::string& name)> &acceptFile,
const std::function<void()> &fileDataReady)
{
- FileDialog::showOpen(accept, fileSelectMode, {
+ FileDialog::showOpen(acceptListFromQtFormat(accept), fileSelectMode, {
.thenFunc = [=](emscripten::val result) {
auto files = qstdweb::FileList(result);
fileDialogClosed(files.length());
@@ -174,7 +237,7 @@ void openFiles(const QStringList &accept, FileSelectMode fileSelectMode,
});
}
-void openFile(const QStringList &accept,
+void openFile(const std::string &accept,
const std::function<void (bool fileSelected)> &fileDialogClosed,
const std::function<char *(uint64_t size, const std::string& name)> &acceptFile,
const std::function<void()> &fileDataReady)
@@ -220,7 +283,7 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data)
void saveFile(const QByteArray &data, const std::string &fileNameHint)
{
if (!FileDialog::canShowSave()) {
- downloadDataAsFile(data, fileNameHint);
+ downloadDataAsFile(data.constData(), data.size(), fileNameHint);
return;
}
@@ -231,6 +294,20 @@ void saveFile(const QByteArray &data, const std::string &fileNameHint)
});
}
+void saveFile(const char *content, size_t size, const std::string &fileNameHint)
+{
+ if (!FileDialog::canShowSave()) {
+ downloadDataAsFile(content, size, fileNameHint);
+ return;
+ }
+
+ FileDialog::showSave(fileNameHint, {
+ .thenFunc = [=](emscripten::val result) {
+ saveDataToFileInChunks(result, QByteArray(content, size));
+ },
+ });
+}
+
} // namespace QWasmLocalFileAccess
QT_END_NAMESPACE
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
index 040fe3c47a..77b14577f7 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
@@ -25,17 +25,18 @@ namespace QWasmLocalFileAccess {
enum class FileSelectMode { SingleFile, MultipleFiles };
-Q_CORE_EXPORT void openFiles(const QStringList &accept, FileSelectMode fileSelectMode,
+Q_CORE_EXPORT void openFiles(const std::string &accept, FileSelectMode fileSelectMode,
const std::function<void (int fileCount)> &fileDialogClosed,
const std::function<char *(uint64_t size, const std::string& name)> &acceptFile,
const std::function<void()> &fileDataReady);
-Q_CORE_EXPORT void openFile(const QStringList &accept,
+Q_CORE_EXPORT void openFile(const std::string &accept,
const std::function<void (bool fileSelected)> &fileDialogClosed,
const std::function<char *(uint64_t size, const std::string& name)> &acceptFile,
const std::function<void()> &fileDataReady);
Q_CORE_EXPORT void saveFile(const QByteArray &data, const std::string &fileNameHint);
+Q_CORE_EXPORT void saveFile(const char *content, size_t size, const std::string &fileNameHint);
} // namespace QWasmLocalFileAccess
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index e2f81c22a1..f3c28205fc 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -2296,7 +2296,7 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct
openFileImpl.reset();
};
- QWasmLocalFileAccess::openFile(qt_make_filter_list(nameFilter), fileDialogClosed, acceptFile, fileContentReady);
+ QWasmLocalFileAccess::openFile(nameFilter.toStdString(), fileDialogClosed, acceptFile, fileContentReady);
};
(*openFileImpl)();