/* * 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 DolphinFacetsWidget::DolphinFacetsWidget(QWidget *parent) : QWidget(parent) , m_typeSelector(nullptr) , m_dateSelector(nullptr) , m_ratingSelector(nullptr) , m_tagsSelector(nullptr) { 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() { } void DolphinFacetsWidget::changeEvent(QEvent *event) { if (event->type() == QEvent::EnabledChange) { if (isEnabled()) { updateTagsSelector(); } else { resetSearchTerms(); } } } 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); 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 (m_dateSelector->currentIndex() > 0) { const QDate date = m_dateSelector->currentData().toDate(); terms << QStringLiteral("modified>=%1").arg(date.toString(Qt::ISODate)); } 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 terms; } QString DolphinFacetsWidget::facetType() const { return m_typeSelector->currentData().toString(); } bool DolphinFacetsWidget::isSearchTerm(const QString &term) const { static const QLatin1String searchTokens[]{QLatin1String("modified>="), QLatin1String("rating>="), QLatin1String("tag:"), QLatin1String("tag=")}; for (const auto &searchToken : searchTokens) { if (term.startsWith(searchToken)) { return true; } } return false; } void DolphinFacetsWidget::setSearchTerm(const QString &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); } } 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; } } } void DolphinFacetsWidget::setRating(const int stars) { if (stars < 0 || stars > 5) { return; } m_ratingSelector->setCurrentIndex(stars); } void DolphinFacetsWidget::setTimespan(const QDate &date) { 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::addSearchTag(const QString &tag) { if (tag.isEmpty() || m_searchTags.contains(tag)) { return; } m_searchTags.append(tag); m_searchTags.sort(); updateTagsSelector(); } void DolphinFacetsWidget::removeSearchTag(const QString &tag) { if (tag.isEmpty() || !m_searchTags.contains(tag)) { return; } m_searchTags.removeAll(tag); updateTagsSelector(); } void DolphinFacetsWidget::resetSearchTags() { m_searchTags = QStringList(); updateTagsSelector(); updateTagsMenu(); } void DolphinFacetsWidget::initComboBox(QComboBox *combo) { combo->setFrame(false); combo->setMinimumHeight(parentWidget()->height()); combo->setCurrentIndex(0); connect(combo, &QComboBox::activated, this, &DolphinFacetsWidget::facetChanged); } void DolphinFacetsWidget::updateTagsSelector() { const bool hasListedTags = !m_tagsSelector->menu()->isEmpty(); const bool hasSelectedTags = !m_searchTags.isEmpty(); 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::updateTagsMenu() { updateTagsMenuItems({}, {}); if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) { m_tagsLister.openUrl(QUrl(QStringLiteral("tags:/")), KCoreDirLister::OpenUrlFlag::Reload); } } void DolphinFacetsWidget::updateTagsMenuItems(const QUrl &, const KFileItemList &items) { 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 "moc_dolphinfacetswidget.cpp"