diff options
author | Morten Sørvig <morten.sorvig@qt.io> | 2022-10-07 16:56:37 +0200 |
---|---|---|
committer | Mikołaj Boc <Mikolaj.Boc@qt.io> | 2022-10-28 12:57:43 +0000 |
commit | 315a5e3257ba2a3258f78a9a5387c07304479dbb (patch) | |
tree | f4f181fc61dfd6e933b914d3678740e073f5fccd | |
parent | 688eee28212b4918a46e0d965e19137bba3586d7 (diff) |
wasm: convert and propagate filetype accept list
Backport the LocalFileApi::Type::fromQt() function from the dev
branch, and adapt it for use with the <input type=file> file dialog
API, which expects an accept string in a certain format (see code).
A similar change will be made for the dev, with adaptions
suitable for that branch.
Change-Id: I11585ae3d445634e123ce6394cada7b34af4d85a
Fixes: QTBUG-105472
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
Reviewed-by: David Skoland <david.skoland@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
-rw-r--r-- | src/gui/platform/wasm/qwasmlocalfileaccess.cpp | 66 | ||||
-rw-r--r-- | src/widgets/dialogs/qfiledialog.cpp | 9 |
2 files changed, 67 insertions, 8 deletions
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index 172c8f6814..521aa7513b 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -8,8 +8,12 @@ #include <emscripten/html5.h> #include <emscripten/val.h> +#include <QtCore/qregularexpression.h> + QT_BEGIN_NAMESPACE +using namespace Qt::Literals::StringLiterals; + namespace QWasmLocalFileAccess { void readFiles(const qstdweb::FileList &fileList, @@ -44,6 +48,66 @@ void readFiles(const qstdweb::FileList &fileList, (*readFile)(0); } +std::string 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(";;"_L1); + 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.join(QStringLiteral(",")).toStdString(); +} + typedef std::function<void (const qstdweb::FileList &fileList)> OpenFileDialogCallback; void openFileDialog(const std::string &accept, FileSelectMode fileSelectMode, const OpenFileDialogCallback &filesSelected) @@ -55,7 +119,7 @@ void openFileDialog(const std::string &accept, FileSelectMode fileSelectMode, emscripten::val input = document.call<emscripten::val>("createElement", std::string("input")); input.set("type", "file"); input.set("style", "display:none"); - input.set("accept", emscripten::val(accept)); + input.set("accept", acceptListFromQtFormat(accept)); input.set("multiple", emscripten::val(fileSelectMode == MultipleFiles)); // Note: there is no event in case the user cancels the file dialog. diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 59ac84ced0..3f4deaac1e 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -2304,13 +2304,8 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct 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); + QWasmLocalFileAccess::openFile(nameFilter.toStdString(), fileDialogClosed, + acceptFile, fileContentReady); }; (*openFileImpl)(); |