X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/c12dc996f535f787ab828560068a2c8b7f98c5cf..4d9ea4261a1f24e299595b897ea790eab1748fe9:/src/search/dolphinfacetswidget.cpp diff --git a/src/search/dolphinfacetswidget.cpp b/src/search/dolphinfacetswidget.cpp index fa46a50e8..db53d595f 100644 --- a/src/search/dolphinfacetswidget.cpp +++ b/src/search/dolphinfacetswidget.cpp @@ -1,303 +1,305 @@ -/*************************************************************************** -* Copyright (C) 2012 by Peter Penz * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License for more details. * -* * -* You should have received a copy of the GNU General Public License * -* along with this program; if not, write to the * -* Free Software Foundation, Inc., * -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * -* **************************************************************************/ +/* + * SPDX-FileCopyrightText: 2012 Peter Penz + * SPDX-FileCopyrightText: 2019 Ismael Asensio + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "dolphinfacetswidget.h" -#include -#include -#include +#include +#include + +#include #include -#include +#include #include -#include +#include +#include +#include DolphinFacetsWidget::DolphinFacetsWidget(QWidget* parent) : QWidget(parent), - m_documents(0), - m_images(0), - m_audio(0), - m_videos(0), - m_anytime(0), - m_today(0), - m_yesterday(0), - m_thisWeek(0), - m_thisMonth(0), - m_thisYear(0), - m_anyRating(0), - m_oneOrMore(0), - m_twoOrMore(0), - m_threeOrMore(0), - m_fourOrMore(0), - m_maxRating(0) + m_typeSelector(nullptr), + m_dateSelector(nullptr), + m_ratingSelector(nullptr), + m_tagsSelector(nullptr) { - QButtonGroup* filetypeGroup = new QButtonGroup(this); - m_anyType = createRadioButton(i18nc("@option:check", "Any"), filetypeGroup); - m_documents = createRadioButton(i18nc("@option:check", "Documents"), filetypeGroup); - m_images = createRadioButton(i18nc("@option:check", "Images"), filetypeGroup); - m_audio = createRadioButton(i18nc("@option:check", "Audio Files"), filetypeGroup); - m_videos = createRadioButton(i18nc("@option:check", "Videos"), filetypeGroup); - - QVBoxLayout* typeLayout = new QVBoxLayout(); - typeLayout->setSpacing(0); - typeLayout->addWidget(m_anyType); - typeLayout->addWidget(m_documents); - typeLayout->addWidget(m_images); - typeLayout->addWidget(m_audio); - typeLayout->addWidget(m_videos); - typeLayout->addStretch(); - - QButtonGroup* timespanGroup = new QButtonGroup(this); - m_anytime = createRadioButton(i18nc("@option:option", "Anytime"), timespanGroup); - m_today = createRadioButton(i18nc("@option:option", "Today"), timespanGroup); - m_yesterday = createRadioButton(i18nc("@option:option", "Yesterday"), timespanGroup); - m_thisWeek = createRadioButton(i18nc("@option:option", "This Week"), timespanGroup); - m_thisMonth = createRadioButton(i18nc("@option:option", "This Month"), timespanGroup); - m_thisYear = createRadioButton(i18nc("@option:option", "This Year"), timespanGroup); - - QVBoxLayout* timespanLayout = new QVBoxLayout(); - timespanLayout->setSpacing(0); - timespanLayout->addWidget(m_anytime); - timespanLayout->addWidget(m_today); - timespanLayout->addWidget(m_yesterday); - timespanLayout->addWidget(m_thisWeek); - timespanLayout->addWidget(m_thisMonth); - timespanLayout->addWidget(m_thisYear); - timespanLayout->addStretch(); - - QButtonGroup* ratingGroup = new QButtonGroup(this); - m_anyRating = createRadioButton(i18nc("@option:option", "Any Rating"), ratingGroup); - m_oneOrMore = createRadioButton(i18nc("@option:option", "1 or more"), ratingGroup); - m_twoOrMore = createRadioButton(i18nc("@option:option", "2 or more"), ratingGroup); - m_threeOrMore = createRadioButton(i18nc("@option:option", "3 or more"), ratingGroup); - m_fourOrMore = createRadioButton(i18nc("@option:option", "4 or more"), ratingGroup); - m_maxRating = createRadioButton(i18nc("@option:option", "Highest Rating"), ratingGroup); - - QVBoxLayout* ratingLayout = new QVBoxLayout(); - ratingLayout->setSpacing(0); - ratingLayout->addWidget(m_anyRating); - ratingLayout->addWidget(m_oneOrMore); - ratingLayout->addWidget(m_twoOrMore); - ratingLayout->addWidget(m_threeOrMore); - ratingLayout->addWidget(m_fourOrMore); - ratingLayout->addWidget(m_maxRating); + m_typeSelector = new QComboBox(this); + m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("none")), i18nc("@item:inlistbox", "Any Type"), QString()); + m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("inode-directory")), i18nc("@item:inlistbox", "Folders") , QStringLiteral("Folder")); + m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("text-x-generic")), i18nc("@item:inlistbox", "Documents") , QStringLiteral("Document")); + m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("image-x-generic")), i18nc("@item:inlistbox", "Images") , QStringLiteral("Image")); + m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("audio-x-generic")), i18nc("@item:inlistbox", "Audio Files"), QStringLiteral("Audio")); + m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("video-x-generic")), i18nc("@item:inlistbox", "Videos") , QStringLiteral("Video")); + initComboBox(m_typeSelector); + + const QDate currentDate = QDate::currentDate(); + + m_dateSelector = new QComboBox(this); + m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar")), i18nc("@item:inlistbox", "Any Date"), QDate()); + m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@item:inlistbox", "Today") , currentDate); + m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@item:inlistbox", "Yesterday") , currentDate.addDays(-1)); + m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-week")), i18nc("@item:inlistbox", "This Week") , currentDate.addDays(1 - currentDate.dayOfWeek())); + m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-month")), i18nc("@item:inlistbox", "This Month"), currentDate.addDays(1 - currentDate.day())); + m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-year")), i18nc("@item:inlistbox", "This Year") , currentDate.addDays(1 - currentDate.dayOfYear())); + initComboBox(m_dateSelector); + + m_ratingSelector = new QComboBox(this); + m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("non-starred-symbolic")), i18nc("@item:inlistbox", "Any Rating"), 0); + m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "1 or more"), 1); + m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "2 or more"), 2); + m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "3 or more"), 3); + m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "4 or more"), 4); + m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "Highest Rating"), 5); + initComboBox(m_ratingSelector); + + m_clearTagsAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear-all")), i18nc("@action:inmenu", "Clear Selection"), this); + connect(m_clearTagsAction, &QAction::triggered, this, [this]() { + resetSearchTags(); + Q_EMIT facetChanged(); + }); + + m_tagsSelector = new QToolButton(this); + m_tagsSelector->setIcon(QIcon::fromTheme(QStringLiteral("tag"))); + m_tagsSelector->setMenu(new QMenu(this)); + m_tagsSelector->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_tagsSelector->setPopupMode(QToolButton::MenuButtonPopup); + m_tagsSelector->setAutoRaise(true); + updateTagsSelector(); + + connect(m_tagsSelector, &QToolButton::clicked, m_tagsSelector, &QToolButton::showMenu); + connect(m_tagsSelector->menu(), &QMenu::aboutToShow, this, &DolphinFacetsWidget::updateTagsMenu); + connect(&m_tagsLister, &KCoreDirLister::itemsAdded, this, &DolphinFacetsWidget::updateTagsMenuItems); + updateTagsMenu(); QHBoxLayout* topLayout = new QHBoxLayout(this); - topLayout->addLayout(typeLayout); - topLayout->addLayout(timespanLayout); - topLayout->addLayout(ratingLayout); - topLayout->addStretch(); - - m_anyType->setChecked(true); - m_anytime->setChecked(true); - m_anyRating->setChecked(true); + topLayout->setContentsMargins(0, 0, 0, 0); + topLayout->addWidget(m_typeSelector); + topLayout->addWidget(m_dateSelector); + topLayout->addWidget(m_ratingSelector); + topLayout->addWidget(m_tagsSelector); + + resetSearchTerms(); } DolphinFacetsWidget::~DolphinFacetsWidget() { } -#ifdef HAVE_BALOO -Baloo::Term DolphinFacetsWidget::ratingTerm() const +void DolphinFacetsWidget::changeEvent(QEvent *event) { - Baloo::Term ratingTerm; - Baloo::Term modifiedTerm; - - if (!m_anyRating->isChecked()) { - int stars = 1; // represents m_oneOrMore - if (m_twoOrMore->isChecked()) { - stars = 2; - } else if (m_threeOrMore->isChecked()) { - stars = 3; - } else if (m_fourOrMore->isChecked()) { - stars = 4; - } else if (m_maxRating->isChecked()) { - stars = 5; + if (event->type() == QEvent::EnabledChange) { + if (isEnabled()) { + updateTagsSelector(); + } else { + resetSearchTerms(); } - - const int rating = stars * 2; - ratingTerm = Baloo::Term("rating", rating, Baloo::Term::GreaterEqual); } +} - if (!m_anytime->isChecked()) { - QDate date = QDate::currentDate(); // represents m_today - if (m_yesterday->isChecked()) { - date = date.addDays(-1); - } else if (m_thisWeek->isChecked()) { - date = date.addDays(1 - date.dayOfWeek()); - } else if (m_thisMonth->isChecked()) { - date = date.addDays(1 - date.day()); - } else if (m_thisYear->isChecked()) { - date = date.addDays(1 - date.dayOfYear()); - } +void DolphinFacetsWidget::resetSearchTerms() +{ + m_typeSelector->setCurrentIndex(0); + m_dateSelector->setCurrentIndex(0); + m_ratingSelector->setCurrentIndex(0); + + resetSearchTags(); +} - modifiedTerm = Baloo::Term("modified", date, Baloo::Term::GreaterEqual); +QStringList DolphinFacetsWidget::searchTerms() const +{ + QStringList terms; + + if (m_ratingSelector->currentIndex() > 0) { + const int rating = m_ratingSelector->currentData().toInt() * 2; + terms << QStringLiteral("rating>=%1").arg(rating); } - if (ratingTerm.isValid() && modifiedTerm.isValid()) { - Baloo::Term term(Baloo::Term::And); - term.addSubTerm(ratingTerm); - term.addSubTerm(modifiedTerm); + if (m_dateSelector->currentIndex() > 0) { + const QDate date = m_dateSelector->currentData().toDate(); + terms << QStringLiteral("modified>=%1").arg(date.toString(Qt::ISODate)); + } - return term; - } else if (modifiedTerm.isValid()) { - return modifiedTerm; - } else if (ratingTerm.isValid()) { - return ratingTerm; + if (!m_searchTags.isEmpty()) { + for (auto const &tag : m_searchTags) { + if (tag.contains(QLatin1Char(' '))) { + terms << QStringLiteral("tag:\"%1\"").arg(tag); + } else { + terms << QStringLiteral("tag:%1").arg(tag); + } + } } - return Baloo::Term(); + return terms; } QString DolphinFacetsWidget::facetType() const { - if (m_documents->isChecked()) { - return QLatin1String("Document"); - } else if (m_images->isChecked()) { - return QLatin1String("Image"); - } else if (m_audio->isChecked()) { - return QLatin1String("Audio"); - } else if (m_videos->isChecked()) { - return QLatin1String("Video"); - } - - return QString(); + return m_typeSelector->currentData().toString(); } -bool DolphinFacetsWidget::isRatingTerm(const Baloo::Term& term) const +bool DolphinFacetsWidget::isSearchTerm(const QString& term) const { - const QList subTerms = term.subTerms(); - if (subTerms.isEmpty()) { - // If term has no sub terms, then the term itself is either a "rating" term - // or a "modified" term. - return term.property() == QLatin1String("modified") || - term.property() == QLatin1String("rating"); - - } else if (subTerms.size() == 2) { - // If term has sub terms, then the sub terms are always "rating" and "modified" terms. - - QStringList properties; - foreach (const Baloo::Term& subTerm, subTerms) { - properties << subTerm.property(); + static const QLatin1String searchTokens[] { + QLatin1String("modified>="), + QLatin1String("rating>="), + QLatin1String("tag:"), QLatin1String("tag=") + }; + + for (const auto &searchToken : searchTokens) { + if (term.startsWith(searchToken)) { + return true; } - - return properties.contains(QLatin1String("modified")) && - properties.contains(QLatin1String("rating")); } - return false; } -void DolphinFacetsWidget::setRatingTerm(const Baloo::Term& term) +void DolphinFacetsWidget::setSearchTerm(const QString& term) { - // If term has sub terms, then the sub terms are always "rating" and "modified" terms. - // If term has no sub terms, then the term itself is either a "rating" term or a "modified" - // term. To avoid code duplication we add term to subTerms list, if the list is empty. - QList subTerms = term.subTerms(); - if (subTerms.isEmpty()) { - subTerms << term; + if (term.startsWith(QLatin1String("modified>="))) { + const QString value = term.mid(10); + const QDate date = QDate::fromString(value, Qt::ISODate); + setTimespan(date); + } else if (term.startsWith(QLatin1String("rating>="))) { + const QString value = term.mid(8); + const int stars = value.toInt() / 2; + setRating(stars); + } else if (term.startsWith(QLatin1String("tag:")) || + term.startsWith(QLatin1String("tag="))) { + const QString value = term.mid(4); + addSearchTag(value); } +} - foreach (const Baloo::Term& subTerm, subTerms) { - const QString property = subTerm.property(); - - if (property == QLatin1String("modified")) { - const QDate date = subTerm.value().toDate(); - setTimespan(date); - } else if (property == QLatin1String("rating")) { - const int stars = subTerm.value().toInt() / 2; - setRating(stars); +void DolphinFacetsWidget::setFacetType(const QString& type) +{ + for (int index = 0; index <= m_typeSelector->count(); index++) { + if (type == m_typeSelector->itemData(index).toString()) { + m_typeSelector->setCurrentIndex(index); + break; } } } -#endif +void DolphinFacetsWidget::setRating(const int stars) +{ + if (stars < 0 || stars > 5) { + return; + } + m_ratingSelector->setCurrentIndex(stars); +} -void DolphinFacetsWidget::setFacetType(const QString& type) +void DolphinFacetsWidget::setTimespan(const QDate& date) { - if (type == QLatin1String("Document")) { - m_documents->setChecked(true); - } else if (type == QLatin1String("Image")) { - m_images->setChecked(true); - } else if (type == QLatin1String("Audio")) { - m_audio->setChecked(true); - } else if (type == QLatin1String("Video")) { - m_videos->setChecked(true); - } else { - m_anyType->setChecked(true); + if (!date.isValid()) { + return; + } + m_dateSelector->setCurrentIndex(0); + for (int index = 1; index <= m_dateSelector->count(); index++) { + if (date >= m_dateSelector->itemData(index).toDate()) { + m_dateSelector->setCurrentIndex(index); + break; + } } } -void DolphinFacetsWidget::setRating(const int stars) +void DolphinFacetsWidget::addSearchTag(const QString& tag) { - switch (stars) { - case 5: - m_maxRating->setChecked(true); - break; + if (tag.isEmpty() || m_searchTags.contains(tag)) { + return; + } + m_searchTags.append(tag); + m_searchTags.sort(); + updateTagsSelector(); +} - case 4: - m_fourOrMore->setChecked(true); - break; +void DolphinFacetsWidget::removeSearchTag(const QString& tag) +{ + if (tag.isEmpty() || !m_searchTags.contains(tag)) { + return; + } + m_searchTags.removeAll(tag); + updateTagsSelector(); +} - case 3: - m_threeOrMore->setChecked(true); - break; +void DolphinFacetsWidget::resetSearchTags() +{ + m_searchTags = QStringList(); + updateTagsSelector(); + updateTagsMenu(); +} - case 2: - m_twoOrMore->setChecked(true); - break; +void DolphinFacetsWidget::initComboBox(QComboBox* combo) +{ + combo->setFrame(false); + combo->setMinimumHeight(parentWidget()->height()); + combo->setCurrentIndex(0); + connect(combo, QOverload::of(&QComboBox::activated), this, &DolphinFacetsWidget::facetChanged); +} - case 1: - m_oneOrMore->setChecked(true); - break; +void DolphinFacetsWidget::updateTagsSelector() +{ + const bool hasListedTags = !m_tagsSelector->menu()->isEmpty(); + const bool hasSelectedTags = !m_searchTags.isEmpty(); - default: - m_anyRating->setChecked(true); + if (hasSelectedTags) { + const QString tagsText = m_searchTags.join(i18nc("String list separator", ", ")); + m_tagsSelector->setText(i18ncp("@action:button %2 is a list of tags", + "Tag: %2", "Tags: %2",m_searchTags.count(), tagsText)); + } else { + m_tagsSelector->setText(i18nc("@action:button", "Add Tags")); } + + m_tagsSelector->setEnabled(isEnabled() && (hasListedTags || hasSelectedTags)); + m_clearTagsAction->setEnabled(hasSelectedTags); } -void DolphinFacetsWidget::setTimespan(const QDate& date) +void DolphinFacetsWidget::updateTagsMenu() { - const QDate currentDate = QDate::currentDate(); - const int days = date.daysTo(currentDate); - - if (days <= 0) { - m_today->setChecked(true); - } else if (days <= 1) { - m_yesterday->setChecked(true); - } else if (days <= currentDate.dayOfWeek()) { - m_thisWeek->setChecked(true); - } else if (days <= currentDate.day()) { - m_thisMonth->setChecked(true); - } else if (days <= currentDate.dayOfYear()) { - m_thisYear->setChecked(true); - } else { - m_anytime->setChecked(true); + updateTagsMenuItems({}, {}); + if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) { + m_tagsLister.openUrl(QUrl(QStringLiteral("tags:/")), KCoreDirLister::OpenUrlFlag::Reload); } } -QRadioButton* DolphinFacetsWidget::createRadioButton(const QString& text, - QButtonGroup* group) +void DolphinFacetsWidget::updateTagsMenuItems(const QUrl&, const KFileItemList& items) { - QRadioButton* button = new QRadioButton(text); - connect(button, &QRadioButton::clicked, this, &DolphinFacetsWidget::facetChanged); - group->addButton(button); - return button; -} + QMenu *tagsMenu = m_tagsSelector->menu(); + tagsMenu->clear(); -#include "dolphinfacetswidget.moc" + QStringList allTags = QStringList(m_searchTags); + for (const KFileItem &item: items) { + allTags.append(item.name()); + } + allTags.sort(Qt::CaseInsensitive); + allTags.removeDuplicates(); + + const bool onlyOneTag = allTags.count() == 1; + + for (const QString& tagName : qAsConst(allTags)) { + QAction *action = tagsMenu->addAction(QIcon::fromTheme(QStringLiteral("tag")), tagName); + action->setCheckable(true); + action->setChecked(m_searchTags.contains(tagName)); + + connect(action, &QAction::triggered, this, [this, tagName, onlyOneTag](bool isChecked) { + if (isChecked) { + addSearchTag(tagName); + } else { + removeSearchTag(tagName); + } + Q_EMIT facetChanged(); + + if (!onlyOneTag) { + m_tagsSelector->menu()->show(); + } + }); + } + + if (allTags.count() > 1) { + tagsMenu->addSeparator(); + tagsMenu->addAction(m_clearTagsAction); + } + + updateTagsSelector(); +}