Filechooser portal: Implement "current_filter"

This adds supports for setting and retrieving the selected
MIME and name filter for 'QXdgDesktopPortalFileDialog'.

For preselecting a filter [1]:

> current_filter (sa(us))
>
>     Request that this filter be set by default at dialog creation. If
>     the filters list is nonempty, it should match a filter in the list
>     to set the default filter from the list. Alternatively, it may be
>     specified when the list is empty to apply the filter
>     unconditionally.

The "current_filter" return value was added in xdg-desktop-portal
commit [2].

[1] https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser
[2] 35fca7fae8

Fixes: QTBUG-85658
Pick-to: 5.15
Change-Id: I8651c1a8942dfd358895b7826730729c4d22e680
Reviewed-by: Jan Grulich <jgrulich@redhat.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Michael Weghorn 2020-07-18 15:07:05 +02:00
parent ecc72bc63d
commit 3e09c28101
2 changed files with 58 additions and 5 deletions

View File

@ -116,6 +116,10 @@ public:
QString title;
QStringList nameFilters;
QStringList mimeTypesFilters;
// maps user-visible name for portal to full name filter
QMap<QString, QString> userVisibleToNameFilter;
QString selectedMimeTypeFilter;
QString selectedNameFilter;
QStringList selectedFiles;
QPlatformFileDialogHelper *nativeFileDialog = nullptr;
};
@ -164,12 +168,18 @@ void QXdgDesktopPortalFileDialog::initializeDialog()
if (!options()->mimeTypeFilters().isEmpty())
d->mimeTypesFilters = options()->mimeTypeFilters();
if (!options()->initiallySelectedMimeTypeFilter().isEmpty())
d->selectedMimeTypeFilter = options()->initiallySelectedMimeTypeFilter();
if (!options()->initiallySelectedNameFilter().isEmpty())
d->selectedNameFilter = options()->initiallySelectedNameFilter();
setDirectory(options()->initialDirectory());
}
void QXdgDesktopPortalFileDialog::openPortal()
{
Q_D(const QXdgDesktopPortalFileDialog);
Q_D(QXdgDesktopPortalFileDialog);
QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"),
QLatin1String("/org/freedesktop/portal/desktop"),
@ -200,6 +210,9 @@ void QXdgDesktopPortalFileDialog::openPortal()
qDBusRegisterMetaType<FilterList>();
FilterList filterList;
Filter* selectedFilter = nullptr;
d->userVisibleToNameFilter.clear();
if (!d->mimeTypesFilters.isEmpty()) {
for (const QString &mimeTypefilter : d->mimeTypesFilters) {
@ -221,13 +234,16 @@ void QXdgDesktopPortalFileDialog::openPortal()
filter.filterConditions = filterConditions;
filterList << filter;
if (!d->selectedMimeTypeFilter.isEmpty() && d->selectedMimeTypeFilter == mimeTypefilter)
selectedFilter = &filter;
}
} else if (!d->nameFilters.isEmpty()) {
for (const QString &filter : d->nameFilters) {
for (const QString &nameFilter : d->nameFilters) {
// Do parsing:
// Supported format is ("Images (*.png *.jpg)")
QRegularExpression regexp(QPlatformFileDialogHelper::filterRegExp);
QRegularExpressionMatch match = regexp.match(filter);
QRegularExpressionMatch match = regexp.match(nameFilter);
if (match.hasMatch()) {
QString userVisibleName = match.captured(1);
QStringList filterStrings = match.captured(2).split(QLatin1Char(' '), Qt::SkipEmptyParts);
@ -245,6 +261,11 @@ void QXdgDesktopPortalFileDialog::openPortal()
filter.filterConditions = filterConditions;
filterList << filter;
d->userVisibleToNameFilter.insert(userVisibleName, nameFilter);
if (!d->selectedNameFilter.isEmpty() && d->selectedNameFilter == nameFilter)
selectedFilter = &filter;
}
}
}
@ -252,6 +273,10 @@ void QXdgDesktopPortalFileDialog::openPortal()
if (!filterList.isEmpty())
options.insert(QLatin1String("filters"), QVariant::fromValue(filterList));
if (selectedFilter) {
options.insert(QLatin1String("current_filter"), QVariant::fromValue(*selectedFilter));
}
options.insert(QLatin1String("handle_token"), QStringLiteral("qt%1").arg(QRandomGenerator::global()->generate()));
// TODO choices a(ssa(ss)s)
@ -339,6 +364,21 @@ void QXdgDesktopPortalFileDialog::setFilter()
}
}
void QXdgDesktopPortalFileDialog::selectMimeTypeFilter(const QString &filter)
{
Q_D(QXdgDesktopPortalFileDialog);
if (d->nativeFileDialog) {
d->nativeFileDialog->setOptions(options());
d->nativeFileDialog->selectMimeTypeFilter(filter);
}
}
QString QXdgDesktopPortalFileDialog::selectedMimeTypeFilter() const
{
Q_D(const QXdgDesktopPortalFileDialog);
return d->selectedMimeTypeFilter;
}
void QXdgDesktopPortalFileDialog::selectNameFilter(const QString &filter)
{
Q_D(QXdgDesktopPortalFileDialog);
@ -351,8 +391,8 @@ void QXdgDesktopPortalFileDialog::selectNameFilter(const QString &filter)
QString QXdgDesktopPortalFileDialog::selectedNameFilter() const
{
// TODO
return QString();
Q_D(const QXdgDesktopPortalFileDialog);
return d->selectedNameFilter;
}
void QXdgDesktopPortalFileDialog::exec()
@ -404,6 +444,17 @@ void QXdgDesktopPortalFileDialog::gotResponse(uint response, const QVariantMap &
if (results.contains(QLatin1String("uris")))
d->selectedFiles = results.value(QLatin1String("uris")).toStringList();
if (results.contains(QLatin1String("current_filter"))) {
const Filter selectedFilter = qdbus_cast<Filter>(results.value(QStringLiteral("current_filter")));
if (!selectedFilter.filterConditions.empty() && selectedFilter.filterConditions[0].type == MimeType) {
// s.a. QXdgDesktopPortalFileDialog::openPortal which basically does the inverse
d->selectedMimeTypeFilter = selectedFilter.filterConditions[0].pattern;
d->selectedNameFilter.clear();
} else {
d->selectedNameFilter = d->userVisibleToNameFilter.value(selectedFilter.name);
d->selectedMimeTypeFilter.clear();
}
}
Q_EMIT accept();
} else {
Q_EMIT reject();

View File

@ -80,6 +80,8 @@ public:
void setFilter() override;
void selectNameFilter(const QString &filter) override;
QString selectedNameFilter() const override;
void selectMimeTypeFilter(const QString &filter) override;
QString selectedMimeTypeFilter() const override;
void exec() override;
bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;