]> cloud.milkyroute.net Git - dolphin.git/blob - src/search/dolphinfacetswidget.cpp
[src/settings/contextmenu/contextmenusettingspage] Fix Crash because of nullptr
[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")), i18nc("@item:inlistbox", "This Week") , currentDate.addDays(1 - currentDate.dayOfWeek()));
44 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-month")), i18nc("@item:inlistbox", "This Month"), currentDate.addDays(1 - currentDate.day()));
45 m_dateSelector->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-year")), i18nc("@item:inlistbox", "This Year") , currentDate.addDays(1 - currentDate.dayOfYear()));
46 initComboBox(m_dateSelector);
47
48 m_ratingSelector = new QComboBox(this);
49 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("non-starred-symbolic")), i18nc("@item:inlistbox", "Any Rating"), 0);
50 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "1 or more"), 1);
51 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "2 or more"), 2);
52 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "3 or more"), 3);
53 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "4 or more"), 4);
54 m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "Highest Rating"), 5);
55 initComboBox(m_ratingSelector);
56
57 m_tagsSelector = new QToolButton(this);
58 m_tagsSelector->setIcon(QIcon::fromTheme(QStringLiteral("tag")));
59 m_tagsSelector->setMenu(new QMenu(this));
60 m_tagsSelector->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
61 m_tagsSelector->setPopupMode(QToolButton::MenuButtonPopup);
62 m_tagsSelector->setAutoRaise(true);
63 updateTagsSelector();
64
65 connect(m_tagsSelector, &QToolButton::clicked, m_tagsSelector, &QToolButton::showMenu);
66 connect(m_tagsSelector->menu(), &QMenu::aboutToShow, this, &DolphinFacetsWidget::updateTagsMenu);
67 connect(&m_tagsLister, &KCoreDirLister::itemsAdded, this, &DolphinFacetsWidget::updateTagsMenuItems);
68 updateTagsMenu();
69
70 QHBoxLayout* topLayout = new QHBoxLayout(this);
71 topLayout->setContentsMargins(0, 0, 0, 0);
72 topLayout->addWidget(m_typeSelector);
73 topLayout->addWidget(m_dateSelector);
74 topLayout->addWidget(m_ratingSelector);
75 topLayout->addWidget(m_tagsSelector);
76
77 resetSearchTerms();
78 }
79
80 DolphinFacetsWidget::~DolphinFacetsWidget()
81 {
82 }
83
84 void DolphinFacetsWidget::changeEvent(QEvent *event)
85 {
86 if (event->type() == QEvent::EnabledChange) {
87 if (isEnabled()) {
88 updateTagsSelector();
89 } else {
90 resetSearchTerms();
91 }
92 }
93 }
94
95 void DolphinFacetsWidget::resetSearchTerms()
96 {
97 m_typeSelector->setCurrentIndex(0);
98 m_dateSelector->setCurrentIndex(0);
99 m_ratingSelector->setCurrentIndex(0);
100
101 m_searchTags = QStringList();
102 updateTagsSelector();
103 updateTagsMenu();
104 }
105
106 QStringList DolphinFacetsWidget::searchTerms() const
107 {
108 QStringList terms;
109
110 if (m_ratingSelector->currentIndex() > 0) {
111 const int rating = m_ratingSelector->currentData().toInt() * 2;
112 terms << QStringLiteral("rating>=%1").arg(rating);
113 }
114
115 if (m_dateSelector->currentIndex() > 0) {
116 const QDate date = m_dateSelector->currentData().toDate();
117 terms << QStringLiteral("modified>=%1").arg(date.toString(Qt::ISODate));
118 }
119
120 if (!m_searchTags.isEmpty()) {
121 for (auto const &tag : m_searchTags) {
122 if (tag.contains(QLatin1Char(' '))) {
123 terms << QStringLiteral("tag:\"%1\"").arg(tag);
124 } else {
125 terms << QStringLiteral("tag:%1").arg(tag);
126 }
127 }
128 }
129
130 return terms;
131 }
132
133 QString DolphinFacetsWidget::facetType() const
134 {
135 return m_typeSelector->currentData().toString();
136 }
137
138 bool DolphinFacetsWidget::isSearchTerm(const QString& term) const
139 {
140 static const QLatin1String searchTokens[] {
141 QLatin1String("modified>="),
142 QLatin1String("rating>="),
143 QLatin1String("tag:"), QLatin1String("tag=")
144 };
145
146 for (const auto &searchToken : searchTokens) {
147 if (term.startsWith(searchToken)) {
148 return true;
149 }
150 }
151 return false;
152 }
153
154 void DolphinFacetsWidget::setSearchTerm(const QString& term)
155 {
156 if (term.startsWith(QLatin1String("modified>="))) {
157 const QString value = term.mid(10);
158 const QDate date = QDate::fromString(value, Qt::ISODate);
159 setTimespan(date);
160 } else if (term.startsWith(QLatin1String("rating>="))) {
161 const QString value = term.mid(8);
162 const int stars = value.toInt() / 2;
163 setRating(stars);
164 } else if (term.startsWith(QLatin1String("tag:")) ||
165 term.startsWith(QLatin1String("tag="))) {
166 const QString value = term.mid(4);
167 addSearchTag(value);
168 }
169 }
170
171 void DolphinFacetsWidget::setFacetType(const QString& type)
172 {
173 for (int index = 0; index <= m_typeSelector->count(); index++) {
174 if (type == m_typeSelector->itemData(index).toString()) {
175 m_typeSelector->setCurrentIndex(index);
176 break;
177 }
178 }
179 }
180
181 void DolphinFacetsWidget::setRating(const int stars)
182 {
183 if (stars < 0 || stars > 5) {
184 return;
185 }
186 m_ratingSelector->setCurrentIndex(stars);
187 }
188
189 void DolphinFacetsWidget::setTimespan(const QDate& date)
190 {
191 if (!date.isValid()) {
192 return;
193 }
194 m_dateSelector->setCurrentIndex(0);
195 for (int index = 1; index <= m_dateSelector->count(); index++) {
196 if (date >= m_dateSelector->itemData(index).toDate()) {
197 m_dateSelector->setCurrentIndex(index);
198 break;
199 }
200 }
201 }
202
203 void DolphinFacetsWidget::addSearchTag(const QString& tag)
204 {
205 if (tag.isEmpty() || m_searchTags.contains(tag)) {
206 return;
207 }
208 m_searchTags.append(tag);
209 m_searchTags.sort();
210 updateTagsSelector();
211 }
212
213 void DolphinFacetsWidget::removeSearchTag(const QString& tag)
214 {
215 if (tag.isEmpty() || !m_searchTags.contains(tag)) {
216 return;
217 }
218 m_searchTags.removeAll(tag);
219 updateTagsSelector();
220 }
221
222 void DolphinFacetsWidget::initComboBox(QComboBox* combo)
223 {
224 combo->setFrame(false);
225 combo->setMinimumHeight(parentWidget()->height());
226 combo->setCurrentIndex(0);
227 connect(combo, QOverload<int>::of(&QComboBox::activated), this, &DolphinFacetsWidget::facetChanged);
228 }
229
230 void DolphinFacetsWidget::updateTagsSelector()
231 {
232 const bool hasListedTags = !m_tagsSelector->menu()->isEmpty();
233 const bool hasSelectedTags = !m_searchTags.isEmpty();
234
235 if (hasSelectedTags) {
236 const QString tagsText = m_searchTags.join(i18nc("String list separator", ", "));
237 m_tagsSelector->setText(i18ncp("@action:button %2 is a list of tags",
238 "Tag: %2", "Tags: %2",m_searchTags.count(), tagsText));
239 } else {
240 m_tagsSelector->setText(i18nc("@action:button", "Add Tags"));
241 }
242
243 m_tagsSelector->setEnabled(isEnabled() && (hasListedTags || hasSelectedTags));
244 }
245
246 void DolphinFacetsWidget::updateTagsMenu()
247 {
248 updateTagsMenuItems({}, {});
249 if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) {
250 m_tagsLister.openUrl(QUrl(QStringLiteral("tags:/")), KCoreDirLister::OpenUrlFlag::Reload);
251 }
252 }
253
254 void DolphinFacetsWidget::updateTagsMenuItems(const QUrl&, const KFileItemList& items)
255 {
256 m_tagsSelector->menu()->clear();
257
258 QStringList allTags = QStringList(m_searchTags);
259 for (const KFileItem &item: items) {
260 allTags.append(item.name());
261 }
262 allTags.sort(Qt::CaseInsensitive);
263 allTags.removeDuplicates();
264
265 const bool onlyOneTag = allTags.count() == 1;
266
267 for (const QString& tagName : qAsConst(allTags)) {
268 QAction* action = m_tagsSelector->menu()->addAction(QIcon::fromTheme(QStringLiteral("tag")), tagName);
269 action->setCheckable(true);
270 action->setChecked(m_searchTags.contains(tagName));
271
272 connect(action, &QAction::triggered, this, [this, tagName, onlyOneTag](bool isChecked) {
273 if (isChecked) {
274 addSearchTag(tagName);
275 } else {
276 removeSearchTag(tagName);
277 }
278 Q_EMIT facetChanged();
279
280 if (!onlyOneTag) {
281 m_tagsSelector->menu()->show();
282 }
283 });
284 }
285
286 updateTagsSelector();
287 }