Commit 8922d260 authored by Michael Weghorn's avatar Michael Weghorn Committed by Jan Grulich
Browse files

FileChooser: Return selected filter

This implements handling the 'current_filter' return
value which returns the filter that was selected in the
file chooser and was added to 'xdg-desktop-portal'
and thus the FileChooser API in commit [1].

Keep a mapping between the user-visible names
(for name filters) or MIME types (for MIME type
filters) to the actual filters in order to retrieve
the actual filter to return after running the file dialog.

Since multiple name filters can use the same filter string,
those aren't necessarily unique, so use the user-visible
names rather than just the filter string to avoid
potential name clashes and be able to retrieve the correct
filter again in the end.

Mapping back to an actual filter does not necessarily
work in all cases, e.g. if a manual filter string was
entered in the file widget. No 'current_filter' is
returned in that case.

This commit moves the extraction of the filters to a
separate method to avoid code duplication.

Handling 'current_filter' is e.g. needed to make gtk's
'gtk_file_chooser_get_filter' function work for the portal
use case. The filter returned by 'gtk_file_chooser_get_filter'
(not just the file extension) is used e.g. by Firefox and
Thunderbird to determine what file format to save a file in,
s. Mozilla bug [2] and gtk issue [3] for more details.

This way, this commit makes that scenario work for the
KF5 native file chooser as well (with 'GTK_USE_PORTAL=1'
set and 'xdg-desktop-portal-kde' in use).

Note: For the case of a gtk program, like the Firefox use case,
this depends on the gtk commits [4] and and [5] in addition
to xdg-desktop-portal commit [1] to actually work as expected.

[1] https://github.com/flatpak/xdg-desktop-portal/commit/35fca7fae881bdaba1bebccf7775eba84407a488
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=1517074
[3] https://gitlab.gnome.org/GNOME/gtk/-/issues/1820
[4] https://gitlab.gnome.org/GNOME/gtk/-/commit/baddc90c26f65a0867aa6b4073e1a6b689d87136
[5] https://gitlab.gnome.org/GNOME/gtk/-/commit/d59b28d5f4e2c4ff4cb51df0a39d94c7df7fee96
parent 11ad7b5d
......@@ -33,6 +33,7 @@
#include <QUrl>
#include <KLocalizedString>
#include <KFileFilterCombo>
#include <KFileWidget>
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeFileChooser, "xdp-kde-file-chooser")
......@@ -194,6 +195,8 @@ uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle,
QString acceptLabel;
QStringList nameFilters;
QStringList mimeTypeFilters;
// mapping between filter strings and actual filters
QMap<QString, FilterList> allFilters;
// for handling of options - choices
QScopedPointer<QWidget> optionsWidget;
......@@ -217,23 +220,7 @@ uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle,
directory = options.value(QStringLiteral("directory")).toBool();
}
if (options.contains(QStringLiteral("filters"))) {
FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QStringLiteral("filters")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
}
}
if (!filterStrings.isEmpty()) {
nameFilters << QStringLiteral("%1|%2").arg(filterStrings.join(QLatin1Char(' '))).arg(filterList.userVisibleName);
}
}
}
ExtractFilters(options, nameFilters, mimeTypeFilters, allFilters);
if (options.contains(QStringLiteral("current_filter"))) {
FilterList filterList = qdbus_cast<FilterList>(options.value(QStringLiteral("current_filter")));
......@@ -267,12 +254,13 @@ uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle,
fileDialog->m_fileWidget->setMode(mode | KFile::Mode::ExistingOnly);
fileDialog->m_fileWidget->okButton()->setText(!acceptLabel.isEmpty() ? acceptLabel : i18n("Open"));
if (!nameFilters.isEmpty()) {
fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
bool bMimeFilters = false;
if (!mimeTypeFilters.isEmpty()) {
fileDialog->m_fileWidget->setMimeFilter(mimeTypeFilters);
bMimeFilters = true;
} else if (!nameFilters.isEmpty()) {
fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
if (optionsWidget) {
......@@ -299,6 +287,17 @@ uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle,
results.insert(QStringLiteral("choices"), choices);
}
// try to map current filter back to one of the predefined ones
QString selectedFilter;
if (bMimeFilters) {
selectedFilter = fileDialog->m_fileWidget->currentMimeFilter();
} else {
selectedFilter = fileDialog->m_fileWidget->filterWidget()->currentText();
}
if (allFilters.contains(selectedFilter)) {
results.insert(QStringLiteral("current_filter"), QVariant::fromValue<FilterList>(allFilters.value(selectedFilter)));
}
return 0;
}
......@@ -327,6 +326,8 @@ uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
QString currentFile;
QStringList nameFilters;
QStringList mimeTypeFilters;
// mapping between filter strings and actual filters
QMap<QString, FilterList> allFilters;
// for handling of options - choices
QScopedPointer<QWidget> optionsWidget;
......@@ -354,23 +355,7 @@ uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
currentFile = QFile::decodeName(options.value(QStringLiteral("current_file")).toByteArray());
}
if (options.contains(QStringLiteral("filters"))) {
FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QStringLiteral("filters")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
}
}
if (!filterStrings.isEmpty()) {
nameFilters << QStringLiteral("%1|%2").arg(filterStrings.join(QLatin1Char(' '))).arg(filterList.userVisibleName);
}
}
}
ExtractFilters(options, nameFilters, mimeTypeFilters, allFilters);
if (options.contains(QStringLiteral("current_filter"))) {
FilterList filterList = qdbus_cast<FilterList>(options.value(QStringLiteral("current_filter")));
......@@ -420,12 +405,12 @@ uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
fileDialog->m_fileWidget->okButton()->setText(acceptLabel);
}
if (!nameFilters.isEmpty()) {
fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
bool bMimeFilters = false;
if (!mimeTypeFilters.isEmpty()) {
fileDialog->m_fileWidget->setMimeFilter(mimeTypeFilters);
bMimeFilters = true;
} else if (!nameFilters.isEmpty()) {
fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
if (optionsWidget) {
......@@ -443,6 +428,17 @@ uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
results.insert(QStringLiteral("choices"), choices);
}
// try to map current filter back to one of the predefined ones
QString selectedFilter;
if (bMimeFilters) {
selectedFilter = fileDialog->m_fileWidget->currentMimeFilter();
} else {
selectedFilter = fileDialog->m_fileWidget->filterWidget()->currentText();
}
if (allFilters.contains(selectedFilter)) {
results.insert(QStringLiteral("current_filter"), QVariant::fromValue<FilterList>(allFilters.value(selectedFilter)));
}
return 0;
}
......@@ -514,3 +510,29 @@ QVariant FileChooserPortal::EvaluateSelectedChoices(const QMap<QString, QCheckBo
return QVariant::fromValue<Choices>(selectedChoices);
}
void FileChooserPortal::ExtractFilters(const QVariantMap &options, QStringList &nameFilters,
QStringList &mimeTypeFilters, QMap<QString, FilterList> &allFilters)
{
if (options.contains(QStringLiteral("filters"))) {
FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QStringLiteral("filters")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
allFilters[filterStruct.filterString] = filterList;
}
}
if (!filterStrings.isEmpty()) {
const QString filterString = filterStrings.join(QLatin1Char(' '));
const QString nameFilter = QStringLiteral("%1|%2").arg(filterString, filterList.userVisibleName);
nameFilters << nameFilter;
allFilters[filterList.userVisibleName] = filterList;
}
}
}
}
......@@ -102,6 +102,9 @@ private:
static QVariant EvaluateSelectedChoices(const QMap<QString, QCheckBox*>& checkboxes,
const QMap<QString, QComboBox*>& comboboxes);
static void ExtractFilters(const QVariantMap &options, QStringList &nameFilters,
QStringList &mimeTypeFilters, QMap<QString, FilterList> &allFilters);
};
#endif // XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment