]> cloud.milkyroute.net Git - dolphin.git/blob - src/search/dolphinfacetswidget.cpp
GIT_SILENT made messages (after extraction)
[dolphin.git] / src / search / dolphinfacetswidget.cpp
1 /*
2 * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
3 * SPDX-FileCopyrightText: 2019 Ismael Asensio <isma.af@mgmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "dolphinfacetswidget.h"
9
10 #include <KLocalizedString>
11 #include <KProtocolInfo>
12
13 #include <QComboBox>
14 #include <QDate>
15 #include <QEvent>
16 #include <QHBoxLayout>
17 #include <QIcon>
18 #include <QMenu>
19 #include <QToolButton>
20
21 DolphinFacetsWidget::DolphinFacetsWidget(QWidget *parent)
22 : QWidget(parent)
23 , m_typeSelector(nullptr)
24 , m_dateSelector(nullptr)
25 , m_ratingSelector(nullptr)
26 , m_tagsSelector(nullptr)
27 {
28 m_typeSelector = new QComboBox(this);
29 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("none")), i18nc("@item:inlistbox", "Any Type"), QString());
30 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("inode-directory")), i18nc("@item:inlistbox", "Folders"), QStringLiteral("Folder"));
31 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("text-x-generic")), i18nc("@item:inlistbox", "Documents"), QStringLiteral("Document"));
32 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("image-x-generic")), i18nc("@item:inlistbox", "Images"), QStringLiteral("Image"));
33 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("audio-x-generic")), i18nc("@item:inlistbox", "Audio Files"), QStringLiteral("Audio"));
34 m_typeSelector->addItem(QIcon::fromTheme(QStringLiteral("video-x-generic")), i18nc("@item:inlistbox", "Videos"), QStringLiteral("Video"));
35 initComboBox(m_typeSelector);
36
37 const QDate currentDate = QDate::currentDate();
38
39 m_dateSelector = new QComboBox(this);
40 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar")), i18nc("@item:inlistbox", "Any Date"), QDate());
41 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@item:inlistbox", "Today"), currentDate);
42 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("go-jump-today")), i18nc("@item:inlistbox", "Yesterday"), currentDate.addDays(-1));
43 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-week")),
44 i18nc("@item:inlistbox", "This Week"),
45 currentDate.addDays(1 - currentDate.dayOfWeek()));
46 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-month")),
47 i18nc("@item:inlistbox", "This Month"),
48 currentDate.addDays(1 - currentDate.day()));
49 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-year")),
50 i18nc("@item:inlistbox", "This Year"),
51 currentDate.addDays(1 - currentDate.dayOfYear()));
52 initComboBox(m_dateSelector);
53
54 m_ratingSelector = new QComboBox(this);
55 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("non-starred-symbolic")), i18nc("@item:inlistbox", "Any Rating"), 0);
56 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "1 or more"), 1);
57 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "2 or more"), 2);
58 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "3 or more"), 3);
59 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "4 or more"), 4);
60 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "Highest Rating"), 5);
61 initComboBox(m_ratingSelector);
62
63 m_clearTagsAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear-all")), i18nc("@action:inmenu", "Clear Selection"), this);
64 connect(m_clearTagsAction, &QAction::triggered, this, [this]() {
65 resetSearchTags();
66 Q_EMIT facetChanged();
67 });
68
69 m_tagsSelector = new QToolButton(this);
70 m_tagsSelector->setIcon(QIcon::fromTheme(QStringLiteral("tag")));
71 m_tagsSelector->setMenu(new QMenu(this));
72 m_tagsSelector->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
73 m_tagsSelector->setPopupMode(QToolButton::MenuButtonPopup);
74 m_tagsSelector->setAutoRaise(true);
75 updateTagsSelector();
76
77 connect(m_tagsSelector, &QToolButton::clicked, m_tagsSelector, &QToolButton::showMenu);
78 connect(m_tagsSelector->menu(), &QMenu::aboutToShow, this, &DolphinFacetsWidget::updateTagsMenu);
79 connect(&m_tagsLister, &KCoreDirLister::itemsAdded, this, &DolphinFacetsWidget::updateTagsMenuItems);
80 updateTagsMenu();
81
82 QHBoxLayout *topLayout = new QHBoxLayout(this);
83 topLayout->setContentsMargins(0, 0, 0, 0);
84 topLayout->addWidget(m_typeSelector);
85 topLayout->addWidget(m_dateSelector);
86 topLayout->addWidget(m_ratingSelector);
87 topLayout->addWidget(m_tagsSelector);
88
89 resetSearchTerms();
90 }
91
92 DolphinFacetsWidget::~DolphinFacetsWidget()
93 {
94 }
95
96 void DolphinFacetsWidget::changeEvent(QEvent *event)
97 {
98 if (event->type() == QEvent::EnabledChange) {
99 if (isEnabled()) {
100 updateTagsSelector();
101 } else {
102 resetSearchTerms();
103 }
104 }
105 }
106
107 QSize DolphinFacetsWidget::minimumSizeHint() const
108 {
109 return QSize(0, m_typeSelector->minimumHeight());
110 }
111
112 void DolphinFacetsWidget::resetSearchTerms()
113 {
114 m_typeSelector->setCurrentIndex(0);
115 m_dateSelector->setCurrentIndex(0);
116 m_ratingSelector->setCurrentIndex(0);
117
118 resetSearchTags();
119 }
120
121 QStringList DolphinFacetsWidget::searchTerms() const
122 {
123 QStringList terms;
124
125 if (m_ratingSelector->currentIndex() > 0) {
126 const int rating = m_ratingSelector->currentData().toInt() * 2;
127 terms << QStringLiteral("rating>=%1").arg(rating);
128 }
129
130 if (m_dateSelector->currentIndex() > 0) {
131 const QDate date = m_dateSelector->currentData().toDate();
132 terms << QStringLiteral("modified>=%1").arg(date.toString(Qt::ISODate));
133 }
134
135 if (!m_searchTags.isEmpty()) {
136 for (auto const &tag : m_searchTags) {
137 if (tag.contains(QLatin1Char(' '))) {
138 terms << QStringLiteral("tag:\"%1\"").arg(tag);
139 } else {
140 terms << QStringLiteral("tag:%1").arg(tag);
141 }
142 }
143 }
144
145 return terms;
146 }
147
148 QString DolphinFacetsWidget::facetType() const
149 {
150 return m_typeSelector->currentData().toString();
151 }
152
153 bool DolphinFacetsWidget::isSearchTerm(const QString &term) const
154 {
155 static const QLatin1String searchTokens[]{QLatin1String("modified>="), QLatin1String("rating>="), QLatin1String("tag:"), QLatin1String("tag=")};
156
157 for (const auto &searchToken : searchTokens) {
158 if (term.startsWith(searchToken)) {
159 return true;
160 }
161 }
162 return false;
163 }
164
165 void DolphinFacetsWidget::setSearchTerm(const QString &term)
166 {
167 if (term.startsWith(QLatin1String("modified>="))) {
168 const QString value = term.mid(10);
169 const QDate date = QDate::fromString(value, Qt::ISODate);
170 setTimespan(date);
171 } else if (term.startsWith(QLatin1String("rating>="))) {
172 const QString value = term.mid(8);
173 const int stars = value.toInt() / 2;
174 setRating(stars);
175 } else if (term.startsWith(QLatin1String("tag:")) || term.startsWith(QLatin1String("tag="))) {
176 const QString value = term.mid(4);
177 addSearchTag(value);
178 }
179 }
180
181 void DolphinFacetsWidget::setFacetType(const QString &type)
182 {
183 for (int index = 0; index <= m_typeSelector->count(); index++) {
184 if (type == m_typeSelector->itemData(index).toString()) {
185 m_typeSelector->setCurrentIndex(index);
186 break;
187 }
188 }
189 }
190
191 void DolphinFacetsWidget::setRating(const int stars)
192 {
193 if (stars < 0 || stars > 5) {
194 return;
195 }
196 m_ratingSelector->setCurrentIndex(stars);
197 }
198
199 void DolphinFacetsWidget::setTimespan(const QDate &date)
200 {
201 if (!date.isValid()) {
202 return;
203 }
204 m_dateSelector->setCurrentIndex(0);
205 for (int index = 1; index <= m_dateSelector->count(); index++) {
206 if (date >= m_dateSelector->itemData(index).toDate()) {
207 m_dateSelector->setCurrentIndex(index);
208 break;
209 }
210 }
211 }
212
213 void DolphinFacetsWidget::addSearchTag(const QString &tag)
214 {
215 if (tag.isEmpty() || m_searchTags.contains(tag)) {
216 return;
217 }
218 m_searchTags.append(tag);
219 m_searchTags.sort();
220 updateTagsSelector();
221 }
222
223 void DolphinFacetsWidget::removeSearchTag(const QString &tag)
224 {
225 if (tag.isEmpty() || !m_searchTags.contains(tag)) {
226 return;
227 }
228 m_searchTags.removeAll(tag);
229 updateTagsSelector();
230 }
231
232 void DolphinFacetsWidget::resetSearchTags()
233 {
234 m_searchTags = QStringList();
235 updateTagsSelector();
236 updateTagsMenu();
237 }
238
239 void DolphinFacetsWidget::initComboBox(QComboBox *combo)
240 {
241 combo->setFrame(false);
242 combo->setMinimumHeight(parentWidget()->height());
243 combo->setCurrentIndex(0);
244 connect(combo, &QComboBox::activated, this, &DolphinFacetsWidget::facetChanged);
245 }
246
247 void DolphinFacetsWidget::updateTagsSelector()
248 {
249 const bool hasListedTags = !m_tagsSelector->menu()->isEmpty();
250 const bool hasSelectedTags = !m_searchTags.isEmpty();
251
252 if (hasSelectedTags) {
253 const QString tagsText = m_searchTags.join(i18nc("String list separator", ", "));
254 m_tagsSelector->setText(i18ncp("@action:button %2 is a list of tags", "Tag: %2", "Tags: %2", m_searchTags.count(), tagsText));
255 } else {
256 m_tagsSelector->setText(i18nc("@action:button", "Add Tags"));
257 }
258
259 m_tagsSelector->setEnabled(isEnabled() && (hasListedTags || hasSelectedTags));
260 m_clearTagsAction->setEnabled(hasSelectedTags);
261 }
262
263 void DolphinFacetsWidget::updateTagsMenu()
264 {
265 updateTagsMenuItems({}, {});
266 if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) {
267 m_tagsLister.openUrl(QUrl(QStringLiteral("tags:/")), KCoreDirLister::OpenUrlFlag::Reload);
268 }
269 }
270
271 void DolphinFacetsWidget::updateTagsMenuItems(const QUrl &, const KFileItemList &items)
272 {
273 QMenu *tagsMenu = m_tagsSelector->menu();
274 tagsMenu->clear();
275
276 QStringList allTags = QStringList(m_searchTags);
277 for (const KFileItem &item : items) {
278 allTags.append(item.name());
279 }
280 allTags.sort(Qt::CaseInsensitive);
281 allTags.removeDuplicates();
282
283 const bool onlyOneTag = allTags.count() == 1;
284
285 for (const QString &tagName : std::as_const(allTags)) {
286 QAction *action = tagsMenu->addAction(QIcon::fromTheme(QStringLiteral("tag")), tagName);
287 action->setCheckable(true);
288 action->setChecked(m_searchTags.contains(tagName));
289
290 connect(action, &QAction::triggered, this, [this, tagName, onlyOneTag](bool isChecked) {
291 if (isChecked) {
292 addSearchTag(tagName);
293 } else {
294 removeSearchTag(tagName);
295 }
296 Q_EMIT facetChanged();
297
298 if (!onlyOneTag) {
299 m_tagsSelector->menu()->show();
300 }
301 });
302 }
303
304 if (allTags.count() > 1) {
305 tagsMenu->addSeparator();
306 tagsMenu->addAction(m_clearTagsAction);
307 }
308
309 updateTagsSelector();
310 }
311
312 #include "moc_dolphinfacetswidget.cpp"