File indexing completed on 2024-04-28 05:45:14
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com> 0003 * SPDX-FileCopyrightText: 2019 Ismael Asensio <isma.af@mgmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "dolphinfacetswidget.h" 0009 0010 #include <KLocalizedString> 0011 #include <KProtocolInfo> 0012 0013 #include <QComboBox> 0014 #include <QDate> 0015 #include <QEvent> 0016 #include <QHBoxLayout> 0017 #include <QIcon> 0018 #include <QMenu> 0019 #include <QToolButton> 0020 0021 DolphinFacetsWidget::DolphinFacetsWidget(QWidget *parent) 0022 : QWidget(parent) 0023 , m_typeSelector(nullptr) 0024 , m_dateSelector(nullptr) 0025 , m_ratingSelector(nullptr) 0026 , m_tagsSelector(nullptr) 0027 { 0028 m_typeSelector = new QComboBox(this); 0029 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("none")), i18nc("@item:inlistbox", "Any Type"), QString()); 0030 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("inode-directory")), i18nc("@item:inlistbox", "Folders"), QStringLiteral("Folder")); 0031 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("text-x-generic")), i18nc("@item:inlistbox", "Documents"), QStringLiteral("Document")); 0032 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("image-x-generic")), i18nc("@item:inlistbox", "Images"), QStringLiteral("Image")); 0033 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("audio-x-generic")), i18nc("@item:inlistbox", "Audio Files"), QStringLiteral("Audio")); 0034 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("video-x-generic")), i18nc("@item:inlistbox", "Videos"), QStringLiteral("Video")); 0035 initComboBox(m_typeSelector); 0036 0037 const QDate currentDate = QDate::currentDate(); 0038 0039 m_dateSelector = new QComboBox(this); 0040 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar")), i18nc("@item:inlistbox", "Any Date"), QDate()); 0041 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@item:inlistbox", "Today"), currentDate); 0042 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@item:inlistbox", "Yesterday"), currentDate.addDays(-1)); 0043 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-week")), 0044 i18nc("@item:inlistbox", "This Week"), 0045 currentDate.addDays(1 - currentDate.dayOfWeek())); 0046 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-month")), 0047 i18nc("@item:inlistbox", "This Month"), 0048 currentDate.addDays(1 - currentDate.day())); 0049 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-year")), 0050 i18nc("@item:inlistbox", "This Year"), 0051 currentDate.addDays(1 - currentDate.dayOfYear())); 0052 initComboBox(m_dateSelector); 0053 0054 m_ratingSelector = new QComboBox(this); 0055 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("non-starred-symbolic")), i18nc("@item:inlistbox", "Any Rating"), 0); 0056 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "1 or more"), 1); 0057 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "2 or more"), 2); 0058 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "3 or more"), 3); 0059 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "4 or more"), 4); 0060 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "Highest Rating"), 5); 0061 initComboBox(m_ratingSelector); 0062 0063 m_clearTagsAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear-all")), i18nc("@action:inmenu", "Clear Selection"), this); 0064 connect(m_clearTagsAction, &QAction::triggered, this, [this]() { 0065 resetSearchTags(); 0066 Q_EMIT facetChanged(); 0067 }); 0068 0069 m_tagsSelector = new QToolButton(this); 0070 m_tagsSelector->setIcon(QIcon::fromTheme(QStringLiteral("tag"))); 0071 m_tagsSelector->setMenu(new QMenu(this)); 0072 m_tagsSelector->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0073 m_tagsSelector->setPopupMode(QToolButton::MenuButtonPopup); 0074 m_tagsSelector->setAutoRaise(true); 0075 updateTagsSelector(); 0076 0077 connect(m_tagsSelector, &QToolButton::clicked, m_tagsSelector, &QToolButton::showMenu); 0078 connect(m_tagsSelector->menu(), &QMenu::aboutToShow, this, &DolphinFacetsWidget::updateTagsMenu); 0079 connect(&m_tagsLister, &KCoreDirLister::itemsAdded, this, &DolphinFacetsWidget::updateTagsMenuItems); 0080 updateTagsMenu(); 0081 0082 QHBoxLayout *topLayout = new QHBoxLayout(this); 0083 topLayout->setContentsMargins(0, 0, 0, 0); 0084 topLayout->addWidget(m_typeSelector); 0085 topLayout->addWidget(m_dateSelector); 0086 topLayout->addWidget(m_ratingSelector); 0087 topLayout->addWidget(m_tagsSelector); 0088 0089 resetSearchTerms(); 0090 } 0091 0092 DolphinFacetsWidget::~DolphinFacetsWidget() 0093 { 0094 } 0095 0096 void DolphinFacetsWidget::changeEvent(QEvent *event) 0097 { 0098 if (event->type() == QEvent::EnabledChange) { 0099 if (isEnabled()) { 0100 updateTagsSelector(); 0101 } else { 0102 resetSearchTerms(); 0103 } 0104 } 0105 } 0106 0107 QSize DolphinFacetsWidget::minimumSizeHint() const 0108 { 0109 return QSize(0, m_typeSelector->minimumHeight()); 0110 } 0111 0112 void DolphinFacetsWidget::resetSearchTerms() 0113 { 0114 m_typeSelector->setCurrentIndex(0); 0115 m_dateSelector->setCurrentIndex(0); 0116 m_ratingSelector->setCurrentIndex(0); 0117 0118 resetSearchTags(); 0119 } 0120 0121 QStringList DolphinFacetsWidget::searchTerms() const 0122 { 0123 QStringList terms; 0124 0125 if (m_ratingSelector->currentIndex() > 0) { 0126 const int rating = m_ratingSelector->currentData().toInt() * 2; 0127 terms << QStringLiteral("rating>=%1").arg(rating); 0128 } 0129 0130 if (m_dateSelector->currentIndex() > 0) { 0131 const QDate date = m_dateSelector->currentData().toDate(); 0132 terms << QStringLiteral("modified>=%1").arg(date.toString(Qt::ISODate)); 0133 } 0134 0135 if (!m_searchTags.isEmpty()) { 0136 for (auto const &tag : m_searchTags) { 0137 if (tag.contains(QLatin1Char(' '))) { 0138 terms << QStringLiteral("tag:\"%1\"").arg(tag); 0139 } else { 0140 terms << QStringLiteral("tag:%1").arg(tag); 0141 } 0142 } 0143 } 0144 0145 return terms; 0146 } 0147 0148 QString DolphinFacetsWidget::facetType() const 0149 { 0150 return m_typeSelector->currentData().toString(); 0151 } 0152 0153 bool DolphinFacetsWidget::isSearchTerm(const QString &term) const 0154 { 0155 static const QLatin1String searchTokens[]{QLatin1String("modified>="), QLatin1String("rating>="), QLatin1String("tag:"), QLatin1String("tag=")}; 0156 0157 for (const auto &searchToken : searchTokens) { 0158 if (term.startsWith(searchToken)) { 0159 return true; 0160 } 0161 } 0162 return false; 0163 } 0164 0165 void DolphinFacetsWidget::setSearchTerm(const QString &term) 0166 { 0167 if (term.startsWith(QLatin1String("modified>="))) { 0168 const QString value = term.mid(10); 0169 const QDate date = QDate::fromString(value, Qt::ISODate); 0170 setTimespan(date); 0171 } else if (term.startsWith(QLatin1String("rating>="))) { 0172 const QString value = term.mid(8); 0173 const int stars = value.toInt() / 2; 0174 setRating(stars); 0175 } else if (term.startsWith(QLatin1String("tag:")) || term.startsWith(QLatin1String("tag="))) { 0176 const QString value = term.mid(4); 0177 addSearchTag(value); 0178 } 0179 } 0180 0181 void DolphinFacetsWidget::setFacetType(const QString &type) 0182 { 0183 for (int index = 0; index <= m_typeSelector->count(); index++) { 0184 if (type == m_typeSelector->itemData(index).toString()) { 0185 m_typeSelector->setCurrentIndex(index); 0186 break; 0187 } 0188 } 0189 } 0190 0191 void DolphinFacetsWidget::setRating(const int stars) 0192 { 0193 if (stars < 0 || stars > 5) { 0194 return; 0195 } 0196 m_ratingSelector->setCurrentIndex(stars); 0197 } 0198 0199 void DolphinFacetsWidget::setTimespan(const QDate &date) 0200 { 0201 if (!date.isValid()) { 0202 return; 0203 } 0204 m_dateSelector->setCurrentIndex(0); 0205 for (int index = 1; index <= m_dateSelector->count(); index++) { 0206 if (date >= m_dateSelector->itemData(index).toDate()) { 0207 m_dateSelector->setCurrentIndex(index); 0208 break; 0209 } 0210 } 0211 } 0212 0213 void DolphinFacetsWidget::addSearchTag(const QString &tag) 0214 { 0215 if (tag.isEmpty() || m_searchTags.contains(tag)) { 0216 return; 0217 } 0218 m_searchTags.append(tag); 0219 m_searchTags.sort(); 0220 updateTagsSelector(); 0221 } 0222 0223 void DolphinFacetsWidget::removeSearchTag(const QString &tag) 0224 { 0225 if (tag.isEmpty() || !m_searchTags.contains(tag)) { 0226 return; 0227 } 0228 m_searchTags.removeAll(tag); 0229 updateTagsSelector(); 0230 } 0231 0232 void DolphinFacetsWidget::resetSearchTags() 0233 { 0234 m_searchTags = QStringList(); 0235 updateTagsSelector(); 0236 updateTagsMenu(); 0237 } 0238 0239 void DolphinFacetsWidget::initComboBox(QComboBox *combo) 0240 { 0241 combo->setFrame(false); 0242 combo->setMinimumHeight(parentWidget()->height()); 0243 combo->setCurrentIndex(0); 0244 connect(combo, &QComboBox::activated, this, &DolphinFacetsWidget::facetChanged); 0245 } 0246 0247 void DolphinFacetsWidget::updateTagsSelector() 0248 { 0249 const bool hasListedTags = !m_tagsSelector->menu()->isEmpty(); 0250 const bool hasSelectedTags = !m_searchTags.isEmpty(); 0251 0252 if (hasSelectedTags) { 0253 const QString tagsText = m_searchTags.join(i18nc("String list separator", ", ")); 0254 m_tagsSelector->setText(i18ncp("@action:button %2 is a list of tags", "Tag: %2", "Tags: %2", m_searchTags.count(), tagsText)); 0255 } else { 0256 m_tagsSelector->setText(i18nc("@action:button", "Add Tags")); 0257 } 0258 0259 m_tagsSelector->setEnabled(isEnabled() && (hasListedTags || hasSelectedTags)); 0260 m_clearTagsAction->setEnabled(hasSelectedTags); 0261 } 0262 0263 void DolphinFacetsWidget::updateTagsMenu() 0264 { 0265 updateTagsMenuItems({}, {}); 0266 if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) { 0267 m_tagsLister.openUrl(QUrl(QStringLiteral("tags:/")), KCoreDirLister::OpenUrlFlag::Reload); 0268 } 0269 } 0270 0271 void DolphinFacetsWidget::updateTagsMenuItems(const QUrl &, const KFileItemList &items) 0272 { 0273 QMenu *tagsMenu = m_tagsSelector->menu(); 0274 tagsMenu->clear(); 0275 0276 QStringList allTags = QStringList(m_searchTags); 0277 for (const KFileItem &item : items) { 0278 allTags.append(item.name()); 0279 } 0280 allTags.sort(Qt::CaseInsensitive); 0281 allTags.removeDuplicates(); 0282 0283 const bool onlyOneTag = allTags.count() == 1; 0284 0285 for (const QString &tagName : std::as_const(allTags)) { 0286 QAction *action = tagsMenu->addAction(QIcon::fromTheme(QStringLiteral("tag")), tagName); 0287 action->setCheckable(true); 0288 action->setChecked(m_searchTags.contains(tagName)); 0289 0290 connect(action, &QAction::triggered, this, [this, tagName, onlyOneTag](bool isChecked) { 0291 if (isChecked) { 0292 addSearchTag(tagName); 0293 } else { 0294 removeSearchTag(tagName); 0295 } 0296 Q_EMIT facetChanged(); 0297 0298 if (!onlyOneTag) { 0299 m_tagsSelector->menu()->show(); 0300 } 0301 }); 0302 } 0303 0304 if (allTags.count() > 1) { 0305 tagsMenu->addSeparator(); 0306 tagsMenu->addAction(m_clearTagsAction); 0307 } 0308 0309 updateTagsSelector(); 0310 } 0311 0312 #include "moc_dolphinfacetswidget.cpp"