-/***************************************************************************
-* Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
-* *
-* 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 <peter.penz19@gmail.com>
+ * SPDX-FileCopyrightText: 2019 Ismael Asensio <isma.af@mgmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "dolphinfacetswidget.h"
-#include <KLocale>
-#include <QButtonGroup>
-#include <QCheckBox>
+#include <KLocalizedString>
+#include <KProtocolInfo>
+
+#include <QComboBox>
#include <QDate>
-#include <QRadioButton>
+#include <QEvent>
#include <QHBoxLayout>
-#include <QVBoxLayout>
-
-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)
+#include <QIcon>
+#include <QMenu>
+#include <QToolButton>
+
+DolphinFacetsWidget::DolphinFacetsWidget(QWidget *parent)
+ : QWidget(parent)
+ , 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);
-
- 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);
+ 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->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());
- }
+QSize DolphinFacetsWidget::minimumSizeHint() const
+{
+ return QSize(0, m_typeSelector->minimumHeight());
+}
+
+void DolphinFacetsWidget::resetSearchTerms()
+{
+ m_typeSelector->setCurrentIndex(0);
+ m_dateSelector->setCurrentIndex(0);
+ m_ratingSelector->setCurrentIndex(0);
- modifiedTerm = Baloo::Term("modified", date, Baloo::Term::GreaterEqual);
+ resetSearchTags();
+}
+
+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<Baloo::Term> 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=")};
- return properties.contains(QLatin1String("modified")) &&
- properties.contains(QLatin1String("rating"));
+ for (const auto &searchToken : searchTokens) {
+ if (term.startsWith(searchToken)) {
+ return true;
+ }
}
-
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<Baloo::Term> 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, &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();
+
+ 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 : std::as_const(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();
}
-#include "dolphinfacetswidget.moc"
+#include "moc_dolphinfacetswidget.cpp"