Changeset View
Standalone View
src/filechooser.cpp
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * Copyright © 2016 Red Hat, Inc | 2 | * Copyright © 2016-2018 Red Hat, Inc | ||
3 | * | 3 | * | ||
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Lesser General Public | 5 | * modify it under the terms of the GNU Lesser General Public | ||
6 | * License as published by the Free Software Foundation; either | 6 | * License as published by the Free Software Foundation; either | ||
7 | * version 2 of the License, or (at your option) any later version. | 7 | * version 2 of the License, or (at your option) any later version. | ||
8 | * | 8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | 9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * Lesser General Public License for more details. | 12 | * Lesser General Public License for more details. | ||
13 | * | 13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public | 14 | * You should have received a copy of the GNU Lesser General Public | ||
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. | 15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | 16 | * | ||
17 | * Authors: | 17 | * Authors: | ||
18 | * Jan Grulich <jgrulich@redhat.com> | 18 | * Jan Grulich <jgrulich@redhat.com> | ||
19 | */ | 19 | */ | ||
20 | 20 | | |||
21 | #include "filechooser.h" | 21 | #include "filechooser.h" | ||
22 | 22 | | |||
23 | #include <QDBusMetaType> | 23 | #include <QDBusMetaType> | ||
24 | #include <QDBusArgument> | 24 | #include <QDBusArgument> | ||
25 | #include <QLoggingCategory> | 25 | #include <QLoggingCategory> | ||
26 | #include <QFileDialog> | 26 | #include <QFileDialog> | ||
27 | #include <QRegularExpression> | ||||
27 | #include <KLocalizedString> | 28 | #include <KLocalizedString> | ||
28 | 29 | | |||
29 | Q_LOGGING_CATEGORY(XdgDesktopPortalKdeFileChooser, "xdp-kde-file-chooser") | 30 | Q_LOGGING_CATEGORY(XdgDesktopPortalKdeFileChooser, "xdp-kde-file-chooser") | ||
30 | 31 | | |||
31 | // Keep in sync with qflatpakfiledialog from flatpak-platform-plugin | 32 | // Keep in sync with qflatpakfiledialog from flatpak-platform-plugin | ||
32 | Q_DECLARE_METATYPE(FileChooserPortal::Filter); | 33 | Q_DECLARE_METATYPE(FileChooserPortal::Filter); | ||
33 | Q_DECLARE_METATYPE(FileChooserPortal::Filters); | 34 | Q_DECLARE_METATYPE(FileChooserPortal::Filters); | ||
34 | Q_DECLARE_METATYPE(FileChooserPortal::FilterList); | 35 | Q_DECLARE_METATYPE(FileChooserPortal::FilterList); | ||
Show All 36 Lines | 68 | { | |||
71 | arg >> userVisibleName >> filters; | 72 | arg >> userVisibleName >> filters; | ||
72 | filterList.userVisibleName = userVisibleName; | 73 | filterList.userVisibleName = userVisibleName; | ||
73 | filterList.filters = filters; | 74 | filterList.filters = filters; | ||
74 | arg.endStructure(); | 75 | arg.endStructure(); | ||
75 | 76 | | |||
76 | return arg; | 77 | return arg; | ||
77 | } | 78 | } | ||
78 | 79 | | |||
80 | static bool isGtkFilterPattern(const QString &pattern) | ||||
81 | { | ||||
82 | // We are looking for patterns containing regexp looking like "[Pp][Nn][Gg]" | ||||
83 | QRegularExpression re(QStringLiteral("\\*\\.(\\w*(\\[\\w+\\])+\\w*)+")); | ||||
84 | return re.match(pattern).hasMatch(); | ||||
85 | } | ||||
86 | | ||||
87 | static QString gtkToQtFilterPattern(const QString &pattern) | ||||
88 | { | ||||
89 | QRegularExpression re(QStringLiteral("[\\[\\]]")); | ||||
90 | | ||||
91 | QString result; | ||||
92 | const QStringList list = pattern.split(re, QString::SkipEmptyParts); | ||||
93 | for (const QString &str : list) { | ||||
94 | if (str.startsWith(QStringLiteral("*."))) { | ||||
95 | result += str; | ||||
96 | } else { | ||||
97 | // Check if first and last letter are same | ||||
98 | if (str.at(0).toLower() == str.at(str.length() - 1).toLower()) { | ||||
99 | // Take first letter and convert it to lower, so for example from "[Aa]" we get just "a" | ||||
100 | result += str.at(0).toLower(); | ||||
101 | } else { | ||||
102 | // If not, take whole string as it's probably a string between two patterns, like [aA]bc[dD] | ||||
103 | result += str; | ||||
104 | } | ||||
105 | } | ||||
106 | } | ||||
107 | | ||||
108 | return result; | ||||
109 | } | ||||
110 | | ||||
79 | FileChooserPortal::FileChooserPortal(QObject *parent) | 111 | FileChooserPortal::FileChooserPortal(QObject *parent) | ||
80 | : QDBusAbstractAdaptor(parent) | 112 | : QDBusAbstractAdaptor(parent) | ||
81 | { | 113 | { | ||
82 | qDBusRegisterMetaType<Filter>(); | 114 | qDBusRegisterMetaType<Filter>(); | ||
83 | qDBusRegisterMetaType<Filters>(); | 115 | qDBusRegisterMetaType<Filters>(); | ||
84 | qDBusRegisterMetaType<FilterList>(); | 116 | qDBusRegisterMetaType<FilterList>(); | ||
85 | qDBusRegisterMetaType<FilterListList>(); | 117 | qDBusRegisterMetaType<FilterListList>(); | ||
86 | } | 118 | } | ||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Line(s) | 130 | { | |||
135 | } | 167 | } | ||
136 | 168 | | |||
137 | if (options.contains(QLatin1String("filters"))) { | 169 | if (options.contains(QLatin1String("filters"))) { | ||
138 | FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QLatin1String("filters"))); | 170 | FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QLatin1String("filters"))); | ||
139 | Q_FOREACH (const FilterList &filterList, filterListList) { | 171 | Q_FOREACH (const FilterList &filterList, filterListList) { | ||
140 | QStringList filterStrings; | 172 | QStringList filterStrings; | ||
141 | Q_FOREACH (const Filter &filterStruct, filterList.filters) { | 173 | Q_FOREACH (const Filter &filterStruct, filterList.filters) { | ||
142 | if (filterStruct.type == 0) { | 174 | if (filterStruct.type == 0) { | ||
143 | filterStrings << filterStruct.filterString; | 175 | QString filterString = filterStruct.filterString; | ||
176 | if (isGtkFilterPattern(filterString)) { | ||||
177 | filterString = gtkToQtFilterPattern(filterString); | ||||
178 | } | ||||
179 | filterStrings << filterString; | ||||
144 | } else { | 180 | } else { | ||
145 | mimeTypeFilters << filterStruct.filterString; | 181 | mimeTypeFilters << filterStruct.filterString; | ||
146 | } | 182 | } | ||
147 | } | 183 | } | ||
148 | 184 | | |||
149 | if (!filterStrings.isEmpty()) { | 185 | if (!filterStrings.isEmpty()) { | ||
150 | nameFilters << QString("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" "))); | 186 | nameFilters << QString("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" "))); | ||
151 | } | 187 | } | ||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Line(s) | 226 | { | |||
227 | } | 263 | } | ||
228 | 264 | | |||
229 | if (options.contains(QLatin1String("filters"))) { | 265 | if (options.contains(QLatin1String("filters"))) { | ||
230 | FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QLatin1String("filters"))); | 266 | FilterListList filterListList = qdbus_cast<FilterListList>(options.value(QLatin1String("filters"))); | ||
231 | Q_FOREACH (const FilterList &filterList, filterListList) { | 267 | Q_FOREACH (const FilterList &filterList, filterListList) { | ||
232 | QStringList filterStrings; | 268 | QStringList filterStrings; | ||
233 | Q_FOREACH (const Filter &filterStruct, filterList.filters) { | 269 | Q_FOREACH (const Filter &filterStruct, filterList.filters) { | ||
234 | if (filterStruct.type == 0) { | 270 | if (filterStruct.type == 0) { | ||
235 | filterStrings << filterStruct.filterString; | 271 | QString filterString = filterStruct.filterString; | ||
272 | if (isGtkFilterPattern(filterString)) { | ||||
273 | filterString = gtkToQtFilterPattern(filterString); | ||||
274 | } | ||||
275 | filterStrings << filterString; | ||||
236 | } else { | 276 | } else { | ||
237 | mimeTypeFilters << filterStruct.filterString; | 277 | mimeTypeFilters << filterStruct.filterString; | ||
238 | } | 278 | } | ||
239 | } | 279 | } | ||
240 | 280 | | |||
241 | if (!filterStrings.isEmpty()) { | 281 | if (!filterStrings.isEmpty()) { | ||
242 | nameFilters << QString("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" "))); | 282 | nameFilters << QString("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" "))); | ||
243 | } | 283 | } | ||
244 | } | 284 | } | ||
245 | } | 285 | } | ||
246 | 286 | | |||
247 | QFileDialog *fileDialog = new QFileDialog(); | 287 | QFileDialog *fileDialog = new QFileDialog(); | ||
davidedmundson: Given this is the plasma portal, it might be a good case to use the KFileWidget directly rather… | |||||
This can be done of course, but it will not fix this problem. It's reasonable to use it directly and maybe add support for regular expressions in filters to KIO, but this is something what will need more work and require changes on two places. I would like to have now a workaround that can be pushed to stable Plasma release now. jgrulich: This can be done of course, but it will not fix this problem. It's reasonable to use it… | |||||
KFileWidget::setFilter exists and takes regular expressions already. davidedmundson: KFileWidget::setFilter exists and takes regular expressions already.
| |||||
Does it really support regexp in this form? If so, why it doesn't work when used by plasma-integration? I see plasma-integration internally uses KFileWidget and passes filters to it. jgrulich: Does it really support regexp in this form? If so, why it doesn't work when used by plasma… | |||||
It should do: It goes through: QRegExp rx(p); rx.setPatternSyntax(QRegExp::Wildcard); Wildcard in the Qt docs sounds very much like the "glob" format that's in the XDG spec. Running ./kfilewidgettest_gui in kio/bin you can type a filter manually I did: It doesn't work in plasma-integration because it goes through a method qt2KdeFilter - to turn Qt's weird custom syntax into reg ex patterns. davidedmundson: It should do:
It goes through:
QRegExp rx(p);
rx. | |||||
248 | fileDialog->setWindowTitle(title); | 288 | fileDialog->setWindowTitle(title); | ||
249 | fileDialog->setModal(modalDialog); | 289 | fileDialog->setModal(modalDialog); | ||
250 | fileDialog->setAcceptMode(QFileDialog::AcceptSave); | 290 | fileDialog->setAcceptMode(QFileDialog::AcceptSave); | ||
251 | 291 | | |||
252 | if (!currentFolder.isEmpty()) { | 292 | if (!currentFolder.isEmpty()) { | ||
253 | fileDialog->setDirectoryUrl(QUrl(currentFolder)); | 293 | fileDialog->setDirectoryUrl(QUrl(currentFolder)); | ||
254 | } | 294 | } | ||
255 | 295 | | |||
Show All 35 Lines |
Given this is the plasma portal, it might be a good case to use the KFileWidget directly rather than have a proxy layer in the way which converts filter strings back again.
KFileWidget::setFilter takes an expression directly - and if it doesn't match perfectly we can change KIO to come up with something that does.