diff options
| author | Felix Ernst <[email protected]> | 2025-04-07 21:09:00 +0000 |
|---|---|---|
| committer | Felix Ernst <[email protected]> | 2025-04-07 21:09:00 +0000 |
| commit | 4102ccb80457eea44ea280f0ace2a419602bc34b (patch) | |
| tree | 841e039cf9864276c968a397a2ae75c363199342 /src/search/selectors | |
| parent | bfc177d3d1bc5a4a241e35d59086e4824e7c0bd3 (diff) | |
Rewrite search integration
This huge commit is a nearly complete rewrite of the Dolphin search
code. It implements most of the improved Dolphin search UI/UX as
designed and discussed in a collaborative effort by Kristen McWilliam,
Jin Liu, Andy Betts, Tagwerk, a few others and me.
See https://invent.kde.org/system/dolphin/-/issues/46.
# Notable changes
- A toggle to change the search tool is provided as most contributors
deemed that useful in
https://invent.kde.org/system/dolphin/-/merge_requests/642#note_985112.
- The default search is changed to filenamesearch for maximum
reliability.
- Removing all search parameters will take users back to the view state
prior to starting a search instead of keeping the search results open.
- The UI for choosing file types or modification dates has been made
more powerful with more granularity and more options.
- Most search parameters can be configured from a popup menu which
gives us extra space for extra clarity.
- Labels and help buttons as well as hyperlinks to settings makes sure
the user always knows why some search parameters are unavailable in
some contexts.
- Chips show important search parameters while the popup is closed.
They allow quickly removing filters.
- The titles of the search and the input field placeholder message
change to make clear whether file names or file contents are searched.
- When the user actively switches the search tool, whether content
should be searched, or whether to search everywhere, this is preserved
for the initial state of the search bar when the user opens it the next
time after restarting Dolphin.
# Architecture
- The new DolphinQuery class is independent of the UI and contains all
search parameters modifiable in Dolphin as easy setters and getters.
- DolphinQuery objects are also used to update the states of every
component in the search UI. There is now a clear separation of UI and
search configuration/DolphinQuery.
- DolphinQuery is responsible for exporting to and importing from
search URLs.
- The search UI always reflects the currently configured DolphinQuery
no matter if the user changed the UI to change the DolphinQuery or
loaded a DolphinQuery/older search URL which then is reflected in the
UI.
- I tried to simplify all classes and their interaction between each
other as much as possible.
- I added some tests
BUG: 386754
CCBUG: 435119
CCBUG: 458761
BUG: 446387
BUG: 470136
CCBUG: 471556
CCBUG: 475439
CCBUG: 477969
BUG: 480001
BUG: 483578
BUG: 488047
BUG: 488845
BUG: 500103
FIXED-IN: 25.08
Diffstat (limited to 'src/search/selectors')
| -rw-r--r-- | src/search/selectors/dateselector.cpp | 61 | ||||
| -rw-r--r-- | src/search/selectors/dateselector.h | 42 | ||||
| -rw-r--r-- | src/search/selectors/filetypeselector.cpp | 81 | ||||
| -rw-r--r-- | src/search/selectors/filetypeselector.h | 36 | ||||
| -rw-r--r-- | src/search/selectors/minimumratingselector.cpp | 51 | ||||
| -rw-r--r-- | src/search/selectors/minimumratingselector.h | 42 | ||||
| -rw-r--r-- | src/search/selectors/tagsselector.cpp | 189 | ||||
| -rw-r--r-- | src/search/selectors/tagsselector.h | 45 |
8 files changed, 547 insertions, 0 deletions
diff --git a/src/search/selectors/dateselector.cpp b/src/search/selectors/dateselector.cpp new file mode 100644 index 000000000..2951b1dc4 --- /dev/null +++ b/src/search/selectors/dateselector.cpp @@ -0,0 +1,61 @@ +/* + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "dateselector.h" + +#include "../dolphinquery.h" + +#include <KDatePicker> +#include <KDatePickerPopup> +#include <KFormat> +#include <KLocalizedString> + +using namespace Search; + +Search::DateSelector::DateSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent) + : QToolButton{parent} + , UpdatableStateInterface{dolphinQuery} + , m_datePickerPopup{ + new KDatePickerPopup{KDatePickerPopup::NoDate | KDatePickerPopup::DatePicker | KDatePickerPopup::Words, dolphinQuery->modifiedSinceDate(), this}} +{ + setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + setPopupMode(QToolButton::InstantPopup); + + m_datePickerPopup->setDateRange(QDate{}, QDate::currentDate()); + connect(m_datePickerPopup, &KDatePickerPopup::dateChanged, this, [this](const QDate &activatedDate) { + if (activatedDate == m_searchConfiguration->modifiedSinceDate()) { + return; // Already selected. + } + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setModifiedSinceDate(activatedDate); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); + }); + setMenu(m_datePickerPopup); + + updateStateToMatch(std::move(dolphinQuery)); +} + +void DateSelector::removeRestriction() +{ + Q_ASSERT(m_searchConfiguration->modifiedSinceDate().isValid()); + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setModifiedSinceDate(QDate{}); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); +} + +void DateSelector::updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) +{ + m_datePickerPopup->setDate(dolphinQuery->modifiedSinceDate()); + if (!dolphinQuery->modifiedSinceDate().isValid()) { + setIcon(QIcon{}); // No icon for the empty state + setText(i18nc("@item:inlistbox", "Any Date")); + return; + } + setIcon(QIcon::fromTheme(QStringLiteral("view-calendar"))); + QLocale local; + KFormat formatter(local); + setText(formatter.formatRelativeDate(dolphinQuery->modifiedSinceDate(), QLocale::ShortFormat)); +} diff --git a/src/search/selectors/dateselector.h b/src/search/selectors/dateselector.h new file mode 100644 index 000000000..99cecec06 --- /dev/null +++ b/src/search/selectors/dateselector.h @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#ifndef DATESELECTOR_H +#define DATESELECTOR_H + +#include "../updatablestateinterface.h" + +#include <QToolButton> + +class KDatePickerPopup; + +namespace Search +{ + +class DateSelector : public QToolButton, public UpdatableStateInterface +{ + Q_OBJECT + +public: + explicit DateSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent = nullptr); + + /** Causes configurationChanged() to be emitted with a DolphinQuery object that does not contain any restriction settable by this class. */ + void removeRestriction(); + +Q_SIGNALS: + /** Is emitted whenever settings have changed and a new search might be necessary. */ + void configurationChanged(const DolphinQuery &dolphinQuery); + +private: + void updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) override; + +private: + KDatePickerPopup *m_datePickerPopup = nullptr; +}; + +} + +#endif // DATESELECTOR_H diff --git a/src/search/selectors/filetypeselector.cpp b/src/search/selectors/filetypeselector.cpp new file mode 100644 index 000000000..7852aced2 --- /dev/null +++ b/src/search/selectors/filetypeselector.cpp @@ -0,0 +1,81 @@ +/* + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "filetypeselector.h" + +#include "../dolphinquery.h" + +#include <KFileMetaData/TypeInfo> +#include <KLocalizedString> + +using namespace Search; + +FileTypeSelector::FileTypeSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent) + : QComboBox{parent} + , UpdatableStateInterface{dolphinQuery} +{ + for (KFileMetaData::Type::Type type = KFileMetaData::Type::FirstType; type <= KFileMetaData::Type::LastType; type = KFileMetaData::Type::Type(type + 1)) { + switch (type) { + case KFileMetaData::Type::Empty: + addItem(/** No icon for the empty state */ i18nc("@item:inlistbox", "Any Type"), type); + continue; + case KFileMetaData::Type::Archive: + addItem(QIcon::fromTheme(QStringLiteral("package-x-generic")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Audio: + addItem(QIcon::fromTheme(QStringLiteral("audio-x-generic")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Video: + addItem(QIcon::fromTheme(QStringLiteral("video-x-generic")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Image: + addItem(QIcon::fromTheme(QStringLiteral("image-x-generic")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Document: + addItem(QIcon::fromTheme(QStringLiteral("text-x-generic")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Spreadsheet: + addItem(QIcon::fromTheme(QStringLiteral("table")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Presentation: + addItem(QIcon::fromTheme(QStringLiteral("view-presentation")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Text: + addItem(QIcon::fromTheme(QStringLiteral("text-x-generic")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + case KFileMetaData::Type::Folder: + addItem(QIcon::fromTheme(QStringLiteral("inode-directory")), KFileMetaData::TypeInfo{type}.displayName(), type); + continue; + default: + addItem(QIcon(), KFileMetaData::TypeInfo{type}.displayName(), type); + } + } + + connect(this, &QComboBox::activated, this, [this](int activatedIndex) { + auto activatedType = itemData(activatedIndex).value<KFileMetaData::Type::Type>(); + if (activatedType == m_searchConfiguration->fileType()) { + return; // Already selected. + } + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setFileType(activatedType); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); + }); + + updateStateToMatch(std::move(dolphinQuery)); +} + +void Search::FileTypeSelector::removeRestriction() +{ + Q_ASSERT(m_searchConfiguration->fileType() != KFileMetaData::Type::Empty); + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setFileType(KFileMetaData::Type::Empty); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); +} + +void FileTypeSelector::updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) +{ + setCurrentIndex(findData(dolphinQuery->fileType())); +} diff --git a/src/search/selectors/filetypeselector.h b/src/search/selectors/filetypeselector.h new file mode 100644 index 000000000..bfc827344 --- /dev/null +++ b/src/search/selectors/filetypeselector.h @@ -0,0 +1,36 @@ +/* + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#ifndef FILETYPESELECTOR_H +#define FILETYPESELECTOR_H + +#include "../updatablestateinterface.h" + +#include <QComboBox> + +namespace Search +{ + +class FileTypeSelector : public QComboBox, public UpdatableStateInterface +{ + Q_OBJECT + +public: + explicit FileTypeSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent = nullptr); + + /** Causes configurationChanged() to be emitted with a DolphinQuery object that does not contain any restriction settable by this class. */ + void removeRestriction(); + +Q_SIGNALS: + /** Is emitted whenever settings have changed and a new search might be necessary. */ + void configurationChanged(const DolphinQuery &dolphinQuery); + +private: + void updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) override; +}; +} + +#endif // FILETYPESELECTOR_H diff --git a/src/search/selectors/minimumratingselector.cpp b/src/search/selectors/minimumratingselector.cpp new file mode 100644 index 000000000..e46dfd4e0 --- /dev/null +++ b/src/search/selectors/minimumratingselector.cpp @@ -0,0 +1,51 @@ +/* + SPDX-FileCopyrightText: 2012 Peter Penz <[email protected]> + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "minimumratingselector.h" + +#include "../dolphinquery.h" + +#include <KLocalizedString> + +using namespace Search; + +MinimumRatingSelector::MinimumRatingSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent) + : QComboBox{parent} + , UpdatableStateInterface{dolphinQuery} +{ + addItem(/** No icon for the empty state */ i18nc("@item:inlistbox", "Any Rating"), 0); + addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "1 or more"), 2); + addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "2 or more"), 4); + addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "3 or more"), 6); + addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "4 or more"), 8); + addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox 5 star rating, has a star icon in front", "5"), 10); + + connect(this, &QComboBox::activated, this, [this](int activatedIndex) { + auto activatedMinimumRating = itemData(activatedIndex).value<int>(); + if (activatedMinimumRating == m_searchConfiguration->minimumRating()) { + return; // Already selected. + } + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setMinimumRating(activatedMinimumRating); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); + }); + + updateStateToMatch(std::move(dolphinQuery)); +} + +void MinimumRatingSelector::removeRestriction() +{ + Q_ASSERT(m_searchConfiguration->minimumRating() > 0); + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setMinimumRating(0); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); +} + +void MinimumRatingSelector::updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) +{ + setCurrentIndex(findData(dolphinQuery->minimumRating())); +} diff --git a/src/search/selectors/minimumratingselector.h b/src/search/selectors/minimumratingselector.h new file mode 100644 index 000000000..02364cd1a --- /dev/null +++ b/src/search/selectors/minimumratingselector.h @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#ifndef MINIMUMRATINGSELECTOR_H +#define MINIMUMRATINGSELECTOR_H + +#include "../updatablestateinterface.h" + +#include <QComboBox> + +namespace Search +{ + +/** + * @brief Select the minimum rating search results should have. + * Values <= 0 mean no restriction. 1 is half a star, 2 one full star, etc. 10 is typically the maximum in KDE software. + * Since this box only allows selecting full star ratings, the possible values are 0, 2, 4, 6, 8, 10. + */ +class MinimumRatingSelector : public QComboBox, public UpdatableStateInterface +{ + Q_OBJECT + +public: + explicit MinimumRatingSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent = nullptr); + + /** Causes configurationChanged() to be emitted with a DolphinQuery object that does not contain any restriction settable by this class. */ + void removeRestriction(); + +Q_SIGNALS: + /** Is emitted whenever settings have changed and a new search might be necessary. */ + void configurationChanged(const DolphinQuery &dolphinQuery); + +private: + void updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) override; +}; + +} + +#endif // MINIMUMRATINGSELECTOR_H diff --git a/src/search/selectors/tagsselector.cpp b/src/search/selectors/tagsselector.cpp new file mode 100644 index 000000000..95d7ff52a --- /dev/null +++ b/src/search/selectors/tagsselector.cpp @@ -0,0 +1,189 @@ +/* + SPDX-FileCopyrightText: 2019 Ismael Asensio <[email protected]> + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "tagsselector.h" + +#include "../dolphinquery.h" + +#include <KCoreDirLister> +#include <KLocalizedString> +#include <KProtocolInfo> + +#include <QMenu> +#include <QStringList> + +using namespace Search; + +namespace +{ +/** + * @brief Provides the list of tags to all TagsSelectors. + * + * This QStringList of tags populates itself. Additional tags the user is actively searching for can be added with addTag() even though we assume that no file + * with such a tag exists if we did not find it automatically. + * @note Use the tagsList() function below instead of constructing TagsList objects yourself. + */ +class TagsList : public QStringList, public QObject +{ +public: + TagsList() + : QStringList{} + { + m_tagsLister->openUrl(QUrl(QStringLiteral("tags:/")), KCoreDirLister::OpenUrlFlag::Reload); + connect(m_tagsLister.get(), &KCoreDirLister::itemsAdded, this, [this](const QUrl &, const KFileItemList &items) { + for (const KFileItem &item : items) { + append(item.text()); + } + removeDuplicates(); + sort(Qt::CaseInsensitive); + }); + }; + + virtual ~TagsList() = default; + + void addTag(const QString &tag) + { + if (contains(tag)) { + return; + } + append(tag); + sort(Qt::CaseInsensitive); + }; + + /** Used to access to the itemsAdded signal so outside users of this class know when items were added. */ + KCoreDirLister *tagsLister() const + { + return m_tagsLister.get(); + }; + +private: + std::unique_ptr<KCoreDirLister> m_tagsLister = std::make_unique<KCoreDirLister>(); +}; + +/** + * @returns a list of all tags found since the construction of the first TagsSelector object. + * @note Use this function instead of constructing additional TagsList objects. + */ +TagsList *tagsList() +{ + static TagsList *g_tagsList = new TagsList; + return g_tagsList; +} +} + +Search::TagsSelector::TagsSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent) + : QToolButton{parent} + , UpdatableStateInterface{dolphinQuery} +{ + setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + setPopupMode(QToolButton::InstantPopup); + + auto menu = new QMenu{this}; + setMenu(menu); + connect(menu, &QMenu::aboutToShow, this, [this]() { + TagsList *tags = tagsList(); + // The TagsList might not have been updated for a while and new tags might be available. We update now, but this is unfortunately not instant. + // However this selector is connected to the itemsAdded() signal, so we will add any new tags eventually. + tags->tagsLister()->updateDirectory(tags->tagsLister()->url()); + updateMenu(m_searchConfiguration); + }); + + TagsList *tags = tagsList(); + if (tags->isEmpty()) { + // Either there really are no tags or the TagsList has not loaded the tags yet. It only begins loading the first time tagsList() is globally called. + setEnabled(false); + connect( + tags->tagsLister(), + &KCoreDirLister::itemsAdded, + this, + [this]() { + setEnabled(true); + }, + Qt::SingleShotConnection); + } + + connect(tags->tagsLister(), &KCoreDirLister::itemsAdded, this, [this, menu]() { + if (menu->isVisible()) { + updateMenu(m_searchConfiguration); + } + }); + + updateStateToMatch(std::move(dolphinQuery)); +} + +void TagsSelector::removeRestriction() +{ + Q_ASSERT(!m_searchConfiguration->requiredTags().isEmpty()); + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setRequiredTags({}); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); +} + +void TagsSelector::updateMenu(const std::shared_ptr<const DolphinQuery> &dolphinQuery) +{ + if (!KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) { + return; + } + const bool menuWasVisible = menu()->isVisible(); + if (menuWasVisible) { + menu()->hide(); // The menu needs to be hidden now, then updated, and then shown again. + } + // Delete all existing actions in the menu + for (QAction *action : menu()->actions()) { + action->deleteLater(); + } + menu()->clear(); + // Populate the menu + const TagsList *tags = tagsList(); + const bool onlyOneTagExists = tags->count() == 1; + + for (const QString &tag : *tags) { + QAction *tagAction = new QAction{QIcon::fromTheme(QStringLiteral("tag")), tag, menu()}; + tagAction->setCheckable(true); + tagAction->setChecked(dolphinQuery->requiredTags().contains(tag)); + connect(tagAction, &QAction::triggered, this, [this, tag, onlyOneTagExists](bool checked) { + QStringList requiredTags = m_searchConfiguration->requiredTags(); + if (checked == requiredTags.contains(tag)) { + return; // Already selected. + } + if (checked) { + requiredTags.append(tag); + } else { + requiredTags.removeOne(tag); + } + DolphinQuery searchConfigurationCopy = *m_searchConfiguration; + searchConfigurationCopy.setRequiredTags(requiredTags); + Q_EMIT configurationChanged(std::move(searchConfigurationCopy)); + + if (!onlyOneTagExists) { + // Keep the menu open to allow easier tag multi-selection. + menu()->show(); + } + }); + menu()->addAction(tagAction); + } + if (menuWasVisible) { + menu()->show(); + } +} + +void TagsSelector::updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) +{ + if (dolphinQuery->requiredTags().count()) { + setIcon(QIcon::fromTheme(QStringLiteral("tag"))); + setText(dolphinQuery->requiredTags().join(i18nc("list separator for file tags e.g. all images tagged 'family & party & 2025'", " && "))); + } else { + setIcon(QIcon{}); // No icon for the empty state + setText(i18nc("@action:button Required tags for search results: None", "None")); + } + for (const auto &tag : dolphinQuery->requiredTags()) { + tagsList()->addTag(tag); // We add it just in case this tag is not (or no longer) available on the system. This way the UI always works as expected. + } + if (menu()->isVisible()) { + updateMenu(dolphinQuery); + } +} diff --git a/src/search/selectors/tagsselector.h b/src/search/selectors/tagsselector.h new file mode 100644 index 000000000..386cbb924 --- /dev/null +++ b/src/search/selectors/tagsselector.h @@ -0,0 +1,45 @@ +/* + SPDX-FileCopyrightText: 2019 Ismael Asensio <[email protected]> + SPDX-FileCopyrightText: 2025 Felix Ernst <[email protected]> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef TAGSSELECTOR_H +#define TAGSSELECTOR_H + +#include "../updatablestateinterface.h" + +#include <QToolButton> + +namespace Search +{ + +class TagsSelector : public QToolButton, public UpdatableStateInterface +{ + Q_OBJECT + +public: + explicit TagsSelector(std::shared_ptr<const DolphinQuery> dolphinQuery, QWidget *parent = nullptr); + + /** Causes configurationChanged() to be emitted with a DolphinQuery object that does not contain any restriction settable by this class. */ + void removeRestriction(); + +Q_SIGNALS: + /** Is emitted whenever settings have changed and a new search might be necessary. */ + void configurationChanged(const DolphinQuery &dolphinQuery); + +private: + /** + * Updates the menu items for the various tags based on @p dolphinQuery and the available tags. + * This method should only be called when the menu is QMenu::aboutToShow() or the menu is currently visible already while this selector's state changes. + * If the menu is open when this method is called, the menu will automatically be reopened to reflect the updated contents. + */ + void updateMenu(const std::shared_ptr<const DolphinQuery> &dolphinQuery); + + void updateState(const std::shared_ptr<const DolphinQuery> &dolphinQuery) override; +}; + +} + +#endif // TAGSSELECTOR_H |
