diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dolphinviewcontainer.cpp | 18 | ||||
| -rw-r--r-- | src/dolphinviewcontainer.h | 10 | ||||
| -rw-r--r-- | src/filterbar/filterbar.cpp | 100 | ||||
| -rw-r--r-- | src/filterbar/filterbar.h | 22 | ||||
| -rw-r--r-- | src/kitemviews/kfileitemmodel.cpp | 28 | ||||
| -rw-r--r-- | src/kitemviews/kfileitemmodel.h | 6 | ||||
| -rw-r--r-- | src/kitemviews/private/kfileitemmodelfilter.cpp | 62 | ||||
| -rw-r--r-- | src/kitemviews/private/kfileitemmodelfilter.h | 36 | ||||
| -rw-r--r-- | src/views/dolphinview.cpp | 20 | ||||
| -rw-r--r-- | src/views/dolphinview.h | 13 |
10 files changed, 293 insertions, 22 deletions
diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 5c054eab8..4d7472ed3 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -110,6 +110,8 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent) m_filterBar->setVisible(GeneralSettings::filterBar(), WithoutAnimation); connect(m_filterBar, &FilterBar::filterChanged, this, &DolphinViewContainer::setNameFilter); + connect(m_filterBar, &FilterBar::filterModeChanged, this, &DolphinViewContainer::setFilterMode); + connect(m_filterBar, &FilterBar::caseSensitiveChanged, this, &DolphinViewContainer::setFilterCaseSensitive); connect(m_filterBar, &FilterBar::closeRequest, this, &DolphinViewContainer::closeFilterBar); connect(m_filterBar, &FilterBar::focusViewRequest, this, &DolphinViewContainer::requestFocus); @@ -208,6 +210,10 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent) connect(placesModel, &KFilePlacesModel::rowsRemoved, this, &DolphinViewContainer::slotPlacesModelChanged); QApplication::instance()->installEventFilter(this); + + // Update the view with the current state of the filter bar (from the state config) + m_view->setFilterMode(m_filterBar->filterMode()); + m_view->setFilterCaseSensitive(m_filterBar->isCaseSensitive()); } DolphinViewContainer::~DolphinViewContainer() = default; @@ -867,6 +873,18 @@ void DolphinViewContainer::setNameFilter(const QString &nameFilter) delayedStatusBarUpdate(); } +void DolphinViewContainer::setFilterMode(const KFileItemModelFilter::FilterMode mode) +{ + m_view->setFilterMode(mode); + delayedStatusBarUpdate(); +} + +void DolphinViewContainer::setFilterCaseSensitive(const bool caseSensitive) +{ + m_view->setFilterCaseSensitive(caseSensitive); + delayedStatusBarUpdate(); +} + void DolphinViewContainer::activate() { setActive(true); diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h index 3829a4f78..f7ec01885 100644 --- a/src/dolphinviewcontainer.h +++ b/src/dolphinviewcontainer.h @@ -372,6 +372,16 @@ private Q_SLOTS: void setNameFilter(const QString &nameFilter); /** + * Set the filtering mode of the filter. + */ + void setFilterMode(const KFileItemModelFilter::FilterMode mode); + + /** + * Enable or disable the case sensitive filtering. + */ + void setFilterCaseSensitive(const bool caseSensitive); + + /** * Marks the view container as active * (see DolphinViewContainer::setActive()). */ diff --git a/src/filterbar/filterbar.cpp b/src/filterbar/filterbar.cpp index 6cb8d5e2a..08bff24fc 100644 --- a/src/filterbar/filterbar.cpp +++ b/src/filterbar/filterbar.cpp @@ -2,18 +2,25 @@ * SPDX-FileCopyrightText: 2006-2010 Peter Penz <[email protected]> * SPDX-FileCopyrightText: 2006 Gregor Kališnik <[email protected]> * SPDX-FileCopyrightText: 2012 Stuart Citrin <[email protected]> + * SPDX-FileCopyrightText: 2026 Alessio Bonfiglio <[email protected]> * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "filterbar.h" +#include <KConfigGroup> #include <KLocalizedString> +#include <KSharedConfig> +#include <KColorScheme> +#include <QAction> #include <QApplication> +#include <QComboBox> #include <QHBoxLayout> #include <QKeyEvent> #include <QLineEdit> +#include <QPalette> #include <QToolButton> FilterBar::FilterBar(QWidget *parent) @@ -35,8 +42,35 @@ FilterBar::FilterBar(QWidget *parent) m_filterInput->setClearButtonEnabled(true); m_filterInput->setPlaceholderText(i18n("Filter…")); connect(m_filterInput, &QLineEdit::textChanged, this, &FilterBar::filterChanged); + connect(m_filterInput, &QLineEdit::textChanged, this, &FilterBar::updateInvalidPatternView); setFocusProxy(m_filterInput); + m_invalidPatternAction = new QAction(m_filterInput); + m_invalidPatternAction->setCheckable(false); + m_invalidPatternAction->setIcon(QIcon::fromTheme(QStringLiteral("error-symbolic"))); + m_invalidPatternAction->setToolTip(i18n("Invalid expression")); + m_filterInput->addAction(m_invalidPatternAction, QLineEdit::TrailingPosition); + m_invalidPatternAction->setVisible(false); + + // Create case sensitive button + m_caseSensitiveButton = new QToolButton(contentsContainer); + m_caseSensitiveButton->setAutoRaise(true); + m_caseSensitiveButton->setCheckable(true); + m_caseSensitiveButton->setIcon(QIcon::fromTheme(QStringLiteral("format-text-superscript"), QIcon::fromTheme(QStringLiteral("format-text-bold")))); + m_caseSensitiveButton->setToolTip(i18nc("@info:tooltip", "Match case")); + connect(m_caseSensitiveButton, &QToolButton::toggled, this, &FilterBar::caseSensitiveChanged); + connect(m_caseSensitiveButton, &QToolButton::toggled, this, &FilterBar::updateInvalidPatternView); + + // Create filter mode combobox + m_filterModeComboBox = new QComboBox(contentsContainer); + m_filterModeComboBox->addItem(i18nc("@item:inlistbox", "Plain Text"), KFileItemModelFilter::FilterMode::PlainText); + m_filterModeComboBox->addItem(i18nc("@item:inlistbox", "Glob Pattern"), KFileItemModelFilter::FilterMode::Glob); + m_filterModeComboBox->addItem(i18nc("@item:inlistbox", "Regular Expression"), KFileItemModelFilter::FilterMode::Regex); + connect(m_filterModeComboBox, &QComboBox::currentIndexChanged, this, [this](int index) { + Q_EMIT filterModeChanged(m_filterModeComboBox->itemData(index).value<KFileItemModelFilter::FilterMode>()); + }); + connect(m_filterModeComboBox, &QComboBox::currentIndexChanged, this, &FilterBar::updateInvalidPatternView); + // Create close button QToolButton *closeButton = new QToolButton(contentsContainer); closeButton->setAutoRaise(true); @@ -49,13 +83,25 @@ FilterBar::FilterBar(QWidget *parent) hLayout->setContentsMargins(0, 0, 0, 0); hLayout->addWidget(m_lockButton); hLayout->addWidget(m_filterInput); + hLayout->addWidget(m_caseSensitiveButton); + hLayout->addWidget(m_filterModeComboBox); hLayout->addWidget(closeButton); - setTabOrder(m_lockButton, closeButton); - setTabOrder(closeButton, m_filterInput); + setTabOrder({m_lockButton, m_caseSensitiveButton, m_filterModeComboBox, closeButton, m_filterInput}); + + KConfigGroup filterBarConfig(KSharedConfig::openStateConfig(), QStringLiteral("FilterBar")); + bool caseSensitiveEnabled = filterBarConfig.readEntry("caseSensitive", false); + int filterModeComboBoxIndex = filterBarConfig.readEntry("filterMode", m_filterModeComboBox->findData(KFileItemModelFilter::FilterMode::Glob)); + m_caseSensitiveButton->setChecked(caseSensitiveEnabled); + m_filterModeComboBox->setCurrentIndex(filterModeComboBoxIndex); } -FilterBar::~FilterBar() = default; +FilterBar::~FilterBar() +{ + KConfigGroup filterBarConfig(KSharedConfig::openStateConfig(), QStringLiteral("FilterBar")); + filterBarConfig.writeEntry("caseSensitive", this->m_caseSensitiveButton->isChecked()); + filterBarConfig.writeEntry("filterMode", this->m_filterModeComboBox->currentIndex()); +} void FilterBar::closeFilterBar() { @@ -71,6 +117,16 @@ void FilterBar::selectAll() m_filterInput->selectAll(); } +KFileItemModelFilter::FilterMode FilterBar::filterMode() const +{ + return m_filterModeComboBox->itemData(m_filterModeComboBox->currentIndex()).value<KFileItemModelFilter::FilterMode>(); +} + +bool FilterBar::isCaseSensitive() const +{ + return m_caseSensitiveButton->isChecked(); +} + void FilterBar::clear() { m_filterInput->clear(); @@ -93,6 +149,39 @@ void FilterBar::slotToggleLockButton(bool checked) } } +void FilterBar::updateInvalidPatternView() +{ + bool valid = true; + + KFileItemModelFilter::FilterMode current_filter_mode = filterMode(); + if (current_filter_mode != KFileItemModelFilter::FilterMode::PlainText) { + QRegularExpression regExp = QRegularExpression(); + QString pattern = m_filterInput->text(); + + QRegularExpression::PatternOptions options = + m_caseSensitiveButton->isChecked() ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; + if (current_filter_mode == KFileItemModelFilter::FilterMode::Regex) { + regExp.setPattern(pattern); + regExp.setPatternOptions(options); + } else if (current_filter_mode == KFileItemModelFilter::FilterMode::Glob) { + regExp.setPattern(QRegularExpression::wildcardToRegularExpression(pattern, QRegularExpression::UnanchoredWildcardConversion)); + regExp.setPatternOptions(options); + } + + valid = regExp.isValid(); + } + + if (valid) { + m_filterInput->setPalette(QPalette()); + m_invalidPatternAction->setVisible(false); + } else { + auto pal = m_filterInput->palette(); + KColorScheme::adjustBackground(pal, KColorScheme::NegativeBackground); + m_filterInput->setPalette(pal); + m_invalidPatternAction->setVisible(true); + } +} + void FilterBar::showEvent(QShowEvent *event) { if (!event->spontaneous()) { @@ -137,7 +226,10 @@ void FilterBar::keyPressEvent(QKeyEvent *event) int FilterBar::preferredHeight() const { - return std::max(m_filterInput->sizeHint().height(), m_lockButton->sizeHint().height()); + return std::max({m_filterInput->sizeHint().height(), + m_lockButton->sizeHint().height(), + m_caseSensitiveButton->sizeHint().height(), + m_filterModeComboBox->sizeHint().height()}); } #include "moc_filterbar.cpp" diff --git a/src/filterbar/filterbar.h b/src/filterbar/filterbar.h index 1424f4cb8..924c6dba3 100644 --- a/src/filterbar/filterbar.h +++ b/src/filterbar/filterbar.h @@ -10,9 +10,12 @@ #define FILTERBAR_H #include "animatedheightwidget.h" +#include "kitemviews/private/kfileitemmodelfilter.h" class QLineEdit; class QToolButton; +class QComboBox; +class QAction; /** * @brief Provides an input field for filtering the currently shown items. @@ -35,6 +38,9 @@ public: */ void selectAll(); + KFileItemModelFilter::FilterMode filterMode() const; + bool isCaseSensitive() const; + public Q_SLOTS: /** Clears the input field. */ void clear(); @@ -51,6 +57,16 @@ Q_SIGNALS: void filterChanged(const QString &nameFilter); /** + * Emitted when the case sensitive mode has been changed + */ + void caseSensitiveChanged(bool caseSensitive); + + /** + * Emitted when the filter mode has been changed + */ + void filterModeChanged(KFileItemModelFilter::FilterMode mode); + + /** * Emitted as soon as the filterbar should get closed. */ void closeRequest(); @@ -70,6 +86,12 @@ protected: private: QLineEdit *m_filterInput; QToolButton *m_lockButton; + QToolButton *m_caseSensitiveButton; + QComboBox *m_filterModeComboBox; + QAction *m_invalidPatternAction; + + /** Enable or disable the alterative view for when a pattern is invalid */ + void updateInvalidPatternView(); }; #endif diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index c8bac0b9d..1f291d40c 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -817,6 +817,34 @@ QStringList KFileItemModel::mimeTypeFilters() const return m_filter.mimeTypes(); } +void KFileItemModel::setFilterMode(KFileItemModelFilter::FilterMode mode) +{ + if (m_filter.filterMode() != mode) { + dispatchPendingItemsToInsert(); + m_filter.setFilterMode(mode); + applyFilters(); + } +} + +KFileItemModelFilter::FilterMode KFileItemModel::filterMode() const +{ + return m_filter.filterMode(); +} + +void KFileItemModel::setFilterCaseSensitive(bool caseSensitive) +{ + if (m_filter.isCaseSensitive() != caseSensitive) { + dispatchPendingItemsToInsert(); + m_filter.setCaseSensitive(caseSensitive); + applyFilters(); + } +} + +bool KFileItemModel::isFilterCaseSensitive() const +{ + return m_filter.isCaseSensitive(); +} + void KFileItemModel::setExcludeMimeTypeFilter(const QStringList &filters) { if (m_filter.excludeMimeTypes() != filters) { diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 3749b0c1b..2a6e710c3 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -184,6 +184,12 @@ public: void setMimeTypeFilters(const QStringList &filters); QStringList mimeTypeFilters() const; + void setFilterMode(KFileItemModelFilter::FilterMode mode); + KFileItemModelFilter::FilterMode filterMode() const; + + void setFilterCaseSensitive(bool caseSensitive); + bool isFilterCaseSensitive() const; + void setExcludeMimeTypeFilter(const QStringList &filters); QStringList excludeMimeTypeFilter() const; diff --git a/src/kitemviews/private/kfileitemmodelfilter.cpp b/src/kitemviews/private/kfileitemmodelfilter.cpp index 45c62e7ca..48d2f6276 100644 --- a/src/kitemviews/private/kfileitemmodelfilter.cpp +++ b/src/kitemviews/private/kfileitemmodelfilter.cpp @@ -13,7 +13,8 @@ #include <KFileItem> KFileItemModelFilter::KFileItemModelFilter() - : m_useRegExp(false) + : m_filterMode(Glob) + , m_caseSensitive(false) , m_regExp(nullptr) , m_lowerCasePattern() , m_pattern() @@ -31,16 +32,29 @@ void KFileItemModelFilter::setPattern(const QString &filter) m_pattern = filter; m_lowerCasePattern = filter.toLower(); - if (filter.contains(QLatin1Char('*')) || filter.contains(QLatin1Char('?')) || filter.contains(QLatin1Char('['))) { - if (!m_regExp) { - m_regExp = new QRegularExpression(); - m_regExp->setPatternOptions(QRegularExpression::CaseInsensitiveOption); - } - m_regExp->setPattern(QRegularExpression::wildcardToRegularExpression(filter)); - m_useRegExp = m_regExp->isValid(); - } else { - m_useRegExp = false; - } + updateFilter(); +} + +void KFileItemModelFilter::setFilterMode(FilterMode mode) +{ + m_filterMode = mode; + updateFilter(); +} + +KFileItemModelFilter::FilterMode KFileItemModelFilter::filterMode() const +{ + return m_filterMode; +} + +void KFileItemModelFilter::setCaseSensitive(bool caseSensitive) +{ + m_caseSensitive = caseSensitive; + updateFilter(); +} + +bool KFileItemModelFilter::isCaseSensitive() const +{ + return m_caseSensitive; } QString KFileItemModelFilter::pattern() const @@ -48,6 +62,26 @@ QString KFileItemModelFilter::pattern() const return m_pattern; } +void KFileItemModelFilter::updateFilter() +{ + if (m_filterMode == PlainText) { + return; + } + + if (!m_regExp) { + m_regExp = new QRegularExpression(); + } + + QRegularExpression::PatternOptions options = m_caseSensitive ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; + if (m_filterMode == Regex) { + m_regExp->setPattern(m_pattern); + m_regExp->setPatternOptions(options); + } else if (m_filterMode == Glob) { + m_regExp->setPattern(QRegularExpression::wildcardToRegularExpression(m_pattern, QRegularExpression::UnanchoredWildcardConversion)); + m_regExp->setPatternOptions(options); + } +} + void KFileItemModelFilter::setMimeTypes(const QStringList &types) { m_mimeTypes = types; @@ -98,8 +132,10 @@ bool KFileItemModelFilter::matches(const KFileItem &item) const bool KFileItemModelFilter::matchesPattern(const KFileItem &item) const { - if (m_useRegExp) { - return m_regExp->match(item.text()).hasMatch(); + if (m_filterMode == Glob || m_filterMode == Regex) { + return m_regExp->isValid() && m_regExp->match(item.text()).hasMatch(); + } else if (m_caseSensitive) { + return item.text().contains(m_pattern); } else { return item.text().toLower().contains(m_lowerCasePattern); } diff --git a/src/kitemviews/private/kfileitemmodelfilter.h b/src/kitemviews/private/kfileitemmodelfilter.h index ce6cbeebb..9d93d42cc 100644 --- a/src/kitemviews/private/kfileitemmodelfilter.h +++ b/src/kitemviews/private/kfileitemmodelfilter.h @@ -28,16 +28,36 @@ public: KFileItemModelFilter(); virtual ~KFileItemModelFilter(); + /** Filtering modes of KFileItemModelFilter */ + enum FilterMode { + /** Substring matching. */ + PlainText = 0, + /** Matching with glob, default. */ + Glob, + /** Matching with regex. */ + Regex + }; + /** * Sets the pattern that is used for a comparison with the item - * in KFileItemModelFilter::matches(). Per default the pattern - * defines a sub-string. As soon as the pattern contains at least - * a '*', '?' or '[' the pattern represents a regular expression. + * in KFileItemModelFilter::matches(). */ void setPattern(const QString &pattern); QString pattern() const; /** + * Sets the filtering mode used in KFileItemModelFilter::matches(). + */ + void setFilterMode(FilterMode mode); + FilterMode filterMode() const; + + /** + * Enable or disable the case sensitive filtering. + */ + void setCaseSensitive(bool caseSensitive); + bool isCaseSensitive() const; + + /** * Set the list of mimetypes that are used for comparison with the * item in KFileItemModelFilter::matchesMimeType. */ @@ -73,8 +93,14 @@ private: */ bool matchesType(const KFileItem &item) const; - bool m_useRegExp; // If true, m_regExp is used for filtering, - // otherwise m_lowerCaseFilter is used. + /** + * Instantiate and configure m_regExp according to m_filterMode and m_caseSensitive. + */ + void updateFilter(); + + FilterMode m_filterMode; // The current filtering mode. + bool m_caseSensitive; // If true the matching will be case sensitive. + QRegularExpression *m_regExp; QString m_lowerCasePattern; // Lowercase version of m_filter for // faster comparison in matches(). diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index b48e1ae74..2213e2c82 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -639,6 +639,26 @@ QStringList DolphinView::mimeTypeFilters() const return m_model->mimeTypeFilters(); } +void DolphinView::setFilterMode(KFileItemModelFilter::FilterMode mode) +{ + m_model->setFilterMode(mode); +} + +KFileItemModelFilter::FilterMode DolphinView::filterMode() const +{ + return m_model->filterMode(); +} + +void DolphinView::setFilterCaseSensitive(bool caseSensitive) +{ + m_model->setFilterCaseSensitive(caseSensitive); +} + +bool DolphinView::isFilterCaseSensitive() const +{ + return m_model->isFilterCaseSensitive(); +} + void DolphinView::requestStatusBarText() { if (m_statJobForStatusBarText) { diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 67233b668..6aa5b595d 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -10,6 +10,7 @@ #include "dolphin_export.h" #include "dolphintabwidget.h" +#include "kitemviews/private/kfileitemmodelfilter.h" #include "tooltips/tooltipmanager.h" #include "config-dolphin.h" @@ -277,6 +278,18 @@ public: QStringList mimeTypeFilters() const; /** + * Sets the filtering mode of the currently used nameFilter. + */ + void setFilterMode(KFileItemModelFilter::FilterMode mode); + KFileItemModelFilter::FilterMode filterMode() const; + + /** + * Enables or disable the caseSensitive matching of the currently used nameFilter. + */ + void setFilterCaseSensitive(bool caseSensitive); + bool isFilterCaseSensitive() const; + + /** * Tells the view to generate an updated status bar text. The result * is returned through the statusBarTextChanged(QString statusBarText) signal. * It will carry a textual representation of the state of the current |
