diff options
author | Morten Sørvig <morten.sorvig@qt.io> | 2022-12-16 15:22:32 +0100 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@qt.io> | 2022-12-28 13:21:37 +0000 |
commit | fbf2a318dd3f1e0f9fc8dadb68d47923dff3d672 (patch) | |
tree | 0e7047dcc1e93eeb959b5a8720220d274f47d925 /src | |
parent | 7b64eb71c0fe68540d97eb22492b4d0b0a647e9f (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.cpp | 89 | ||||
-rw-r--r-- | src/gui/platform/wasm/qwasmlocalfileaccess_p.h | 5 | ||||
-rw-r--r-- | src/widgets/dialogs/qfiledialog.cpp | 2 |
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)(); |