]> cloud.milkyroute.net Git - dolphin.git/blob - src/search/dolphinsearchbox.cpp
Remove DISABLE_NEPOMUK_LEGACY, it is defined now in kdebase/apps/CMakeLists.txt
[dolphin.git] / src / search / dolphinsearchbox.cpp
1 /***************************************************************************
2 * Copyright (C) 2010 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 * **************************************************************************/
19
20 #include "dolphinsearchbox.h"
21
22 #include "dolphin_searchsettings.h"
23
24 #include <kicon.h>
25 #include <klineedit.h>
26 #include <klocale.h>
27 #include <kseparator.h>
28
29 #include <QButtonGroup>
30 #include <QDir>
31 #include <QEvent>
32 #include <QFormLayout>
33 #include <QHBoxLayout>
34 #include <QKeyEvent>
35 #include <QLabel>
36 #include <QPushButton>
37 #include <QToolButton>
38 #include <QVBoxLayout>
39
40 #include <config-nepomuk.h>
41 #ifdef HAVE_NEPOMUK
42 #include <nepomuk/andterm.h>
43 #include <nepomuk/filequery.h>
44 #include <nepomuk/literalterm.h>
45 #include <nepomuk/query.h>
46 #include <nepomuk/queryparser.h>
47 #include <nepomuk/resourcemanager.h>
48 #include <nepomuk/resourcetypeterm.h>
49 #include "nfo.h"
50
51 #include "filters/datesearchfilterwidget.h"
52 #include "filters/ratingsearchfilterwidget.h"
53 #include "filters/tagsearchfilterwidget.h"
54 #endif
55
56 DolphinSearchBox::DolphinSearchBox(QWidget* parent) :
57 QWidget(parent),
58 m_startedSearching(false),
59 m_nepomukActivated(false),
60 m_topLayout(0),
61 m_searchInput(0),
62 m_fromHereButton(0),
63 m_everywhereButton(0),
64 m_fileNameButton(0),
65 m_contentButton(0),
66 m_filterButton(0),
67 m_filterWidgetsLayout(0),
68 m_filterWidgets(),
69 m_searchPath()
70 {
71 }
72
73 DolphinSearchBox::~DolphinSearchBox()
74 {
75 saveSettings();
76 }
77
78 QString DolphinSearchBox::text() const
79 {
80 return m_searchInput->text();
81 }
82
83 void DolphinSearchBox::setSearchPath(const KUrl& url)
84 {
85 m_searchPath = url;
86 m_filterButton->setVisible(isSearchPathIndexed());
87 }
88
89 KUrl DolphinSearchBox::searchPath() const
90 {
91 return m_searchPath;
92 }
93
94 KUrl DolphinSearchBox::urlForSearching() const
95 {
96 KUrl url;
97 if (isSearchPathIndexed() && !m_fileNameButton->isChecked()) {
98 // TODO: Currently Nepomuk is not used for searching filenames. Nepomuk
99 // is capable to provide this, but further investigations are necessary to
100 // also support regular expressions.
101 url = nepomukUrlForSearching();
102 } else {
103 url = m_searchPath;
104 url.setProtocol("filenamesearch");
105 url.addQueryItem("search", m_searchInput->text());
106 if (m_contentButton->isChecked()) {
107 url.addQueryItem("checkContent", "yes");
108 }
109 if (m_everywhereButton->isChecked()) {
110 // It is very unlikely, that the majority of Dolphins target users
111 // mean "the whole harddisk" instead of "my home folder" when
112 // selecting the "Everywhere" button.
113 url.setPath(QDir::homePath());
114 }
115 }
116
117 return url;
118 }
119
120 bool DolphinSearchBox::event(QEvent* event)
121 {
122 if (event->type() == QEvent::Polish) {
123 init();
124 } else if (event->type() == QEvent::KeyPress) {
125 if (static_cast<QKeyEvent* >(event)->key() == Qt::Key_Escape) {
126 m_searchInput->clear();
127 }
128 }
129 return QWidget::event(event);
130 }
131
132 void DolphinSearchBox::showEvent(QShowEvent* event)
133 {
134 if (!event->spontaneous()) {
135 #ifdef HAVE_NEPOMUK
136 m_nepomukActivated = (Nepomuk::ResourceManager::instance()->init() == 0);
137 #endif
138
139 m_searchInput->clear();
140 m_searchInput->setFocus();
141 m_startedSearching = false;
142 }
143 }
144
145 void DolphinSearchBox::keyReleaseEvent(QKeyEvent* event)
146 {
147 QWidget::keyReleaseEvent(event);
148 if ((event->key() == Qt::Key_Escape)) {
149 if (m_searchInput->text().isEmpty()) {
150 emit closeRequest();
151 } else {
152 m_searchInput->clear();
153 }
154 }
155 }
156
157 void DolphinSearchBox::emitSearchSignal()
158 {
159 m_startedSearching = true;
160 emit search(m_searchInput->text());
161 }
162
163 void DolphinSearchBox::slotConfigurationChanged()
164 {
165 if (m_startedSearching) {
166 emitSearchSignal();
167 }
168 }
169
170 void DolphinSearchBox::setFilterWidgetsVisible(bool visible)
171 {
172 #ifdef HAVE_NEPOMUK
173 if (visible) {
174 if (m_filterWidgetsLayout == 0) {
175 m_filterWidgetsLayout = new QFormLayout(this);
176 m_filterWidgetsLayout->setSpacing(0);
177
178 m_filterWidgets.append(new DateSearchFilterWidget(this));
179 m_filterWidgets.append(new RatingSearchFilterWidget(this));
180 m_filterWidgets.append(new TagSearchFilterWidget(this));
181
182 foreach (AbstractSearchFilterWidget* filterWidget, m_filterWidgets) {
183 const QString labelText = filterWidget->filterLabel() + QLatin1Char(':');
184 QLabel* label = new QLabel(labelText, this);
185 m_filterWidgetsLayout->addRow(label, filterWidget);
186 connect(filterWidget, SIGNAL(filterChanged()), this, SLOT(emitSearchSignal()));
187 }
188 }
189 m_topLayout->addLayout(m_filterWidgetsLayout);
190 } else {
191 m_topLayout->removeItem(m_filterWidgetsLayout);
192 }
193 #else
194 Q_UNUSED(visible);
195 #endif
196 }
197
198 void DolphinSearchBox::initButton(QPushButton* button)
199 {
200 button->setAutoExclusive(true);
201 button->setFlat(true);
202 button->setCheckable(true);
203 connect(button, SIGNAL(toggled(bool)), this, SLOT(slotConfigurationChanged()));
204 }
205
206 void DolphinSearchBox::loadSettings()
207 {
208 if (SearchSettings::location() == QLatin1String("Everywhere")) {
209 m_everywhereButton->setChecked(true);
210 } else {
211 m_fromHereButton->setChecked(true);
212 }
213
214 if (SearchSettings::what() == QLatin1String("Content")) {
215 m_contentButton->setChecked(true);
216 } else {
217 m_fileNameButton->setChecked(true);
218 }
219 }
220
221 void DolphinSearchBox::saveSettings()
222 {
223 SearchSettings::setLocation(m_fromHereButton->isChecked() ? "FromHere" : "Everywhere");
224 SearchSettings::setWhat(m_fileNameButton->isChecked() ? "FileName" : "Content");
225 SearchSettings::self()->writeConfig();
226 }
227
228 void DolphinSearchBox::init()
229 {
230 // Create close button
231 QToolButton* closeButton = new QToolButton(this);
232 closeButton->setAutoRaise(true);
233 closeButton->setIcon(KIcon("dialog-close"));
234 closeButton->setToolTip(i18nc("@info:tooltip", "Quit searching"));
235 connect(closeButton, SIGNAL(clicked()), SIGNAL(closeRequest()));
236
237 // Create search label
238 QLabel* searchLabel = new QLabel(i18nc("@label:textbox", "Find:"), this);
239
240 // Create search box
241 m_searchInput = new KLineEdit(this);
242 m_searchInput->setClearButtonShown(true);
243 m_searchInput->setFont(KGlobalSettings::generalFont());
244 connect(m_searchInput, SIGNAL(returnPressed()),
245 this, SLOT(emitSearchSignal()));
246 connect(m_searchInput, SIGNAL(textChanged(QString)),
247 this, SIGNAL(searchTextChanged(QString)));
248
249 // Apply layout for the search input
250 QHBoxLayout* searchInputLayout = new QHBoxLayout();
251 searchInputLayout->setMargin(0);
252 searchInputLayout->addWidget(closeButton);
253 searchInputLayout->addWidget(searchLabel);
254 searchInputLayout->addWidget(m_searchInput);
255
256 // Create "From Here" and "Everywhere"button
257 m_fromHereButton = new QPushButton();
258 m_fromHereButton->setText(i18nc("action:button", "From Here"));
259 initButton(m_fromHereButton);
260
261 m_everywhereButton = new QPushButton(this);
262 m_everywhereButton->setText(i18nc("action:button", "Everywhere"));
263 initButton(m_everywhereButton);
264
265 QButtonGroup* searchLocationGroup = new QButtonGroup(this);
266 searchLocationGroup->addButton(m_fromHereButton);
267 searchLocationGroup->addButton(m_everywhereButton);
268
269 // Create "Filename" and "Content" button
270 m_fileNameButton = new QPushButton(this);
271 m_fileNameButton->setText(i18nc("action:button", "Filename"));
272 initButton(m_fileNameButton);
273
274 m_contentButton = new QPushButton();
275 m_contentButton->setText(i18nc("action:button", "Content"));
276 initButton(m_contentButton);;
277
278 QButtonGroup* searchWhatGroup = new QButtonGroup(this);
279 searchWhatGroup->addButton(m_fileNameButton);
280 searchWhatGroup->addButton(m_contentButton);
281
282 // Create "Filter" button
283 m_filterButton = new QToolButton(this);
284 m_filterButton->setIcon(KIcon("view-filter"));
285 m_filterButton->setAutoRaise(true);
286 m_filterButton->setCheckable(true);
287 m_filterButton->hide();
288 connect(m_filterButton, SIGNAL(toggled(bool)), this, SLOT(setFilterWidgetsVisible(bool)));
289
290 // Apply layout for the options
291 QHBoxLayout* optionsLayout = new QHBoxLayout();
292 optionsLayout->setMargin(0);
293 optionsLayout->addWidget(m_fromHereButton);
294 optionsLayout->addWidget(m_everywhereButton);
295 optionsLayout->addWidget(new KSeparator(Qt::Vertical));
296 optionsLayout->addWidget(m_fileNameButton);
297 optionsLayout->addWidget(m_contentButton);
298 optionsLayout->addStretch(1);
299 optionsLayout->addWidget(m_filterButton);
300
301 m_topLayout = new QVBoxLayout(this);
302 m_topLayout->addLayout(searchInputLayout);
303 m_topLayout->addLayout(optionsLayout);
304
305 searchLabel->setBuddy(m_searchInput);
306 loadSettings();
307 }
308
309 bool DolphinSearchBox::isSearchPathIndexed() const
310 {
311 #ifdef HAVE_NEPOMUK
312 const QString path = m_searchPath.path();
313
314 const KConfig strigiConfig("nepomukstrigirc");
315 const QStringList indexedFolders = strigiConfig.group("General").readPathEntry("folders", QStringList());
316
317 // Check whether the current search path is part of an indexed folder
318 bool isIndexed = false;
319 foreach (const QString& indexedFolder, indexedFolders) {
320 if (path.startsWith(indexedFolder)) {
321 isIndexed = true;
322 break;
323 }
324 }
325
326 if (isIndexed) {
327 // The current search path is part of an indexed folder. Check whether no
328 // excluded folder is part of the search path.
329 const QStringList excludedFolders = strigiConfig.group("General").readPathEntry("exclude folders", QStringList());
330 foreach (const QString& excludedFolder, excludedFolders) {
331 if (excludedFolder.startsWith(path)) {
332 isIndexed = false;
333 break;
334 }
335 }
336 }
337
338 return isIndexed;
339 #else
340 return false;
341 #endif
342 }
343
344 KUrl DolphinSearchBox::nepomukUrlForSearching() const
345 {
346 #ifdef HAVE_NEPOMUK
347 Nepomuk::Query::AndTerm andTerm;
348
349 // Add filter terms
350 foreach (const AbstractSearchFilterWidget* filterWidget, m_filterWidgets) {
351 const Nepomuk::Query::Term term = filterWidget->queryTerm();
352 if (term.isValid()) {
353 andTerm.addSubTerm(term);
354 }
355 }
356
357 // Add input from search filter
358 const QString text = m_searchInput->text();
359 if (!text.isEmpty()) {
360 const Nepomuk::Query::Query customQuery = Nepomuk::Query::QueryParser::parseQuery(text);
361 if (customQuery.isValid()) {
362 andTerm.addSubTerm(customQuery.term());
363 }
364 }
365
366 Nepomuk::Query::FileQuery fileQuery;
367 fileQuery.setFileMode(Nepomuk::Query::FileQuery::QueryFiles);
368 fileQuery.setTerm(andTerm);
369
370 if (fileQuery.isValid()) {
371 return fileQuery.toSearchUrl(i18nc("@title UDS_DISPLAY_NAME for a KIO directory listing. %1 is the query the user entered.",
372 "Query Results from '%1'",
373 text));
374 }
375 #endif
376 return KUrl();
377 }
378
379 #include "dolphinsearchbox.moc"