diff --git a/src/filewidgets/kfilewidget.cpp b/src/filewidgets/kfilewidget.cpp --- a/src/filewidgets/kfilewidget.cpp +++ b/src/filewidgets/kfilewidget.cpp @@ -129,6 +129,7 @@ void setLocationText(const QList &); void appendExtension(QUrl &url); void updateLocationEditExtension(const QString &); + bool findMatchingFilter(const QString &filter, const QString &filename); void updateFilter(); void updateFilterText(); QList &parseSelectedUrls(); @@ -2452,6 +2453,19 @@ } } +QString KFileWidgetPrivate::findMatchingFilter(const QString &filter, const QString &filename) +{ + const QStringList patterns = filter.left(filter.indexOf(QLatin1Char('|'))).split(QLatin1Char(' '), QString::SkipEmptyParts); // '*.foo *.bar|Foo type' -> '*.foo', '*.bar' + for (const QString &p : patterns) { + QRegExp rx(p); + rx.setPatternSyntax(QRegExp::Wildcard); + if (rx.exactMatch(filename)) { + return p; + } + } + return QString(); +} + // Updates the filter if the extension of the filename specified in d->locationEdit is changed // (this prevents you from accidently saving "file.kwd" as RTF, for example) void KFileWidgetPrivate::updateFilter() @@ -2475,17 +2489,16 @@ } } else { QString filename = urlStr.mid(urlStr.lastIndexOf(QLatin1Char('/')) + 1); // only filename + if (!findMatchingFilter(filterWidget->currentFilter(), filename).isEmpty()) { + return; + } foreach (const QString &filter, filterWidget->filters()) { - const QStringList patterns = filter.left(filter.indexOf(QLatin1Char('|'))).split(QLatin1Char(' '), QString::SkipEmptyParts); // '*.foo *.bar|Foo type' -> '*.foo', '*.bar' - for (const QString &p : patterns) { - QRegExp rx(p); - rx.setPatternSyntax(QRegExp::Wildcard); - if (rx.exactMatch(filename)) { - if (p != QLatin1String("*")) { // never match the catch-all filter - filterWidget->setCurrentFilter(filter); - } - return; // do not repeat, could match a later filter + QString match = findMatchingFilter(filter, filename); + if (!match.isEmpty()) { + if (match != QLatin1String("*")) { // never match the catch-all filter + filterWidget->setCurrentFilter(filter); } + return; // do not repeat, could match a later filter } } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,6 +39,7 @@ udsentrybenchmark kurlnavigatortest_gui kprotocolinfo_dumper + kfilewidgettest_filter kfilewidgettest_gui kfilewidgettest_saving_gui runapplication diff --git a/tests/kfilewidgettest_filter.cpp b/tests/kfilewidgettest_filter.cpp new file mode 100644 --- /dev/null +++ b/tests/kfilewidgettest_filter.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include + +class KFileWidgetFilterTest : public QObject +{ + Q_OBJECT + +public: + KFileWidgetFilterTest() {}; + +private Q_SLOTS: + void testDuplicateMatch(); +}; + +void KFileWidgetFilterTest::testDuplicateMatch() +{ + KFileWidget *fileWidget = new KFileWidget(QUrl(QStringLiteral("kfiledialog:///SaveDialog")), nullptr); + fileWidget->setOperationMode(KFileWidget::Saving); + fileWidget->setMode(KFile::File); + fileWidget->setAttribute(Qt::WA_DeleteOnClose); + + fileWidget->setFilter(QStringLiteral( + "*.xml *.a|Word 2003 XML (.xml)\n" + "*.odt|ODF Text Document (.odt)\n" + "*.xml *.b|DocBook (.xml)\n" + "*|Raw (*)")); + + QCOMPARE(QStringLiteral("*.xml *.a"), fileWidget->currentFilter()); + + // setUrl runs with blocked signals, so use setUrls + // auto-select ODT filter + fileWidget->locationEdit()->setUrls(QStringList(QStringLiteral("test.odt"))); + QCOMPARE(QStringLiteral("test.odt"), fileWidget->locationEdit()->urls()[0]); + QCOMPARE(QStringLiteral("*.odt"), fileWidget->currentFilter()); + + // manual-select 2nd duplicate XML filter + fileWidget->filterWidget()->setCurrentFilter("*.xml *.b|DocBook (.xml)"); + QCOMPARE(QStringLiteral("*.xml *.b"), fileWidget->currentFilter()); + + // keep filter after file change with same extension + fileWidget->locationEdit()->setUrls(QStringList(QStringLiteral("test2.xml"))); + QCOMPARE(QStringLiteral("*.xml *.b"), fileWidget->currentFilter()); + + fileWidget->locationEdit()->setUrls(QStringList(QStringLiteral("test.odt"))); + QCOMPARE(QStringLiteral("*.odt"), fileWidget->currentFilter()); + + // auto-select 1st XML filter + fileWidget->locationEdit()->setUrls(QStringList(QStringLiteral("test.xml"))); + QCOMPARE(QStringLiteral("*.xml *.a"), fileWidget->currentFilter()); + + // test '*' filter + fileWidget->filterWidget()->setCurrentFilter("*|Raw (*)"); + QCOMPARE(QStringLiteral("*"), fileWidget->currentFilter()); + QCOMPARE(QStringLiteral("test.xml"), fileWidget->locationEdit()->urls()[0]); + + // keep '*' filter, even with matching file extension + fileWidget->locationEdit()->setUrls(QStringList(QStringLiteral("test.odt"))); + QCOMPARE(QStringLiteral("*"), fileWidget->currentFilter()); + QCOMPARE(QStringLiteral("test.odt"), fileWidget->locationEdit()->urls()[0]); + + // manual-select 2nd XML filter and change extension + fileWidget->filterWidget()->setCurrentFilter("*.xml *.b|DocBook (.xml)"); + QCOMPARE(QStringLiteral("*.xml *.b"), fileWidget->currentFilter()); + QCOMPARE(QStringLiteral("test.xml"), fileWidget->locationEdit()->urls()[0]); +} + +QTEST_MAIN(KFileWidgetFilterTest) + +#include "kfilewidgettest_filter.moc"