]> cloud.milkyroute.net Git - dolphin.git/blob - src/search/dolphinsearchbox.cpp
Use capitalized includes of recently committed kdelibs headers
[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 #include "dolphinsearchinformation.h"
24
25 #include <KIcon>
26 #include <KLineEdit>
27 #include <KLocale>
28 #include <KSeparator>
29
30 #include <QButtonGroup>
31 #include <QDir>
32 #include <QEvent>
33 #include <QFormLayout>
34 #include <QHBoxLayout>
35 #include <QKeyEvent>
36 #include <QLabel>
37 #include <QPushButton>
38 #include <QScrollArea>
39 #include <QTimer>
40 #include <QToolButton>
41 #include <QVBoxLayout>
42
43 #include <config-nepomuk.h>
44 #ifdef HAVE_NEPOMUK
45 #include <Nepomuk/Query/AndTerm>
46 #include <Nepomuk/Query/FileQuery>
47 #include <Nepomuk/Query/LiteralTerm>
48 #include <Nepomuk/Query/Query>
49 #include <Nepomuk/Query/QueryParser>
50 #include <Nepomuk/Query/ResourceTypeTerm>
51 #include <Nepomuk/Query/ComparisonTerm>
52 #include <Nepomuk/ResourceManager>
53 #include <Nepomuk/Vocabulary/NFO>
54 #endif
55
56 DolphinSearchBox::DolphinSearchBox(QWidget* parent) :
57 QWidget(parent),
58 m_startedSearching(false),
59 m_readOnly(false),
60 m_topLayout(0),
61 m_searchInput(0),
62 m_fileNameButton(0),
63 m_contentButton(0),
64 m_separator(0),
65 m_fromHereButton(0),
66 m_everywhereButton(0),
67 m_infoLabel(0),
68 m_searchPath(),
69 m_startSearchTimer(0)
70 {
71 }
72
73 DolphinSearchBox::~DolphinSearchBox()
74 {
75 saveSettings();
76 }
77
78 void DolphinSearchBox::setText(const QString& text)
79 {
80 m_searchInput->setText(text);
81 }
82
83 QString DolphinSearchBox::text() const
84 {
85 return m_searchInput->text();
86 }
87
88 void DolphinSearchBox::setSearchPath(const KUrl& url)
89 {
90 m_searchPath = url;
91
92 QFontMetrics metrics(m_fromHereButton->font());
93 const int maxWidth = metrics.averageCharWidth() * 15;
94
95 QString location = url.fileName();
96 if (location.isEmpty()) {
97 if (url.isLocalFile()) {
98 location = QLatin1String("/");
99 } else {
100 location = url.protocol() + QLatin1String(" - ") + url.host();
101 }
102 }
103
104 const QString elidedLocation = metrics.elidedText(location, Qt::ElideMiddle, maxWidth);
105 m_fromHereButton->setText(i18nc("action:button", "From Here (%1)", elidedLocation));
106
107 const bool showSearchFromButtons = url.isLocalFile();
108 m_separator->setVisible(showSearchFromButtons);
109 m_fromHereButton->setVisible(showSearchFromButtons);
110 m_everywhereButton->setVisible(showSearchFromButtons);
111 }
112
113 KUrl DolphinSearchBox::searchPath() const
114 {
115 return m_searchPath;
116 }
117
118 KUrl DolphinSearchBox::urlForSearching() const
119 {
120 KUrl url;
121 const DolphinSearchInformation& searchInfo = DolphinSearchInformation::instance();
122 if (searchInfo.isIndexingEnabled() && searchInfo.isPathIndexed(m_searchPath)) {
123 url = nepomukUrlForSearching();
124 } else {
125 url.setProtocol("filenamesearch");
126 url.addQueryItem("search", m_searchInput->text());
127 if (m_contentButton->isChecked()) {
128 url.addQueryItem("checkContent", "yes");
129 }
130
131 QString encodedUrl;
132 if (m_everywhereButton->isChecked()) {
133 // It is very unlikely, that the majority of Dolphins target users
134 // mean "the whole harddisk" instead of "my home folder" when
135 // selecting the "Everywhere" button.
136 encodedUrl = QDir::homePath();
137 } else {
138 encodedUrl = m_searchPath.url();
139 }
140 url.addQueryItem("url", encodedUrl);
141 }
142
143 return url;
144 }
145
146 void DolphinSearchBox::selectAll()
147 {
148 m_searchInput->selectAll();
149 }
150
151 void DolphinSearchBox::setReadOnly(bool readOnly)
152 {
153 if (m_readOnly != readOnly) {
154 m_readOnly = readOnly;
155 applyReadOnlyState();
156 }
157 }
158
159 bool DolphinSearchBox::isReadOnly() const
160 {
161 return m_readOnly;
162 }
163
164 bool DolphinSearchBox::event(QEvent* event)
165 {
166 if (event->type() == QEvent::Polish) {
167 init();
168 }
169 return QWidget::event(event);
170 }
171
172 void DolphinSearchBox::showEvent(QShowEvent* event)
173 {
174 if (!event->spontaneous()) {
175 m_searchInput->setFocus();
176 m_startedSearching = false;
177 }
178 }
179
180 void DolphinSearchBox::keyReleaseEvent(QKeyEvent* event)
181 {
182 QWidget::keyReleaseEvent(event);
183 if (event->key() == Qt::Key_Escape) {
184 if (m_searchInput->text().isEmpty()) {
185 emit closeRequest();
186 } else {
187 m_searchInput->clear();
188 }
189 }
190 }
191
192 void DolphinSearchBox::emitSearchSignal()
193 {
194 m_startSearchTimer->stop();
195 m_startedSearching = true;
196 emit search(m_searchInput->text());
197 }
198
199 void DolphinSearchBox::slotConfigurationChanged()
200 {
201 if (m_startedSearching) {
202 emitSearchSignal();
203 }
204 }
205
206 void DolphinSearchBox::slotSearchTextChanged(const QString& text)
207 {
208 if (text.isEmpty()) {
209 m_startSearchTimer->stop();
210 } else {
211 m_startSearchTimer->start();
212 }
213 emit searchTextChanged(text);
214 }
215
216 void DolphinSearchBox::slotReturnPressed(const QString& text)
217 {
218 emitSearchSignal();
219 emit returnPressed(text);
220 }
221
222 void DolphinSearchBox::initButton(QPushButton* button)
223 {
224 button->setAutoExclusive(true);
225 button->setFlat(true);
226 button->setCheckable(true);
227 connect(button, SIGNAL(toggled(bool)), this, SLOT(slotConfigurationChanged()));
228 }
229
230 void DolphinSearchBox::loadSettings()
231 {
232 if (SearchSettings::location() == QLatin1String("Everywhere")) {
233 m_everywhereButton->setChecked(true);
234 } else {
235 m_fromHereButton->setChecked(true);
236 }
237
238 if (SearchSettings::what() == QLatin1String("Content")) {
239 m_contentButton->setChecked(true);
240 } else {
241 m_fileNameButton->setChecked(true);
242 }
243 }
244
245 void DolphinSearchBox::saveSettings()
246 {
247 SearchSettings::setLocation(m_fromHereButton->isChecked() ? "FromHere" : "Everywhere");
248 SearchSettings::setWhat(m_fileNameButton->isChecked() ? "FileName" : "Content");
249 SearchSettings::self()->writeConfig();
250 }
251
252 void DolphinSearchBox::init()
253 {
254 // Create close button
255 QToolButton* closeButton = new QToolButton(this);
256 closeButton->setAutoRaise(true);
257 closeButton->setIcon(KIcon("dialog-close"));
258 closeButton->setToolTip(i18nc("@info:tooltip", "Quit searching"));
259 connect(closeButton, SIGNAL(clicked()), SIGNAL(closeRequest()));
260
261 // Create search label
262 QLabel* searchLabel = new QLabel(i18nc("@label:textbox", "Find:"), this);
263
264 // Create search box
265 m_searchInput = new KLineEdit(this);
266 m_searchInput->setClearButtonShown(true);
267 m_searchInput->setFont(KGlobalSettings::generalFont());
268 setFocusProxy(m_searchInput);
269 connect(m_searchInput, SIGNAL(returnPressed(QString)),
270 this, SLOT(slotReturnPressed(QString)));
271 connect(m_searchInput, SIGNAL(textChanged(QString)),
272 this, SLOT(slotSearchTextChanged(QString)));
273
274 // Create information label
275 m_infoLabel = new QLabel("TODO: Provide information about the current query", this);
276
277 // Apply layout for the search input
278 QHBoxLayout* searchInputLayout = new QHBoxLayout();
279 searchInputLayout->setMargin(0);
280 searchInputLayout->addWidget(closeButton);
281 searchInputLayout->addWidget(searchLabel);
282 searchInputLayout->addWidget(m_searchInput);
283 searchInputLayout->addWidget(m_infoLabel);
284
285 // Create "Filename" and "Content" button
286 m_fileNameButton = new QPushButton(this);
287 m_fileNameButton->setText(i18nc("action:button", "Filename"));
288 initButton(m_fileNameButton);
289
290 m_contentButton = new QPushButton();
291 m_contentButton->setText(i18nc("action:button", "Content"));
292 initButton(m_contentButton);;
293
294 QButtonGroup* searchWhatGroup = new QButtonGroup(this);
295 searchWhatGroup->addButton(m_fileNameButton);
296 searchWhatGroup->addButton(m_contentButton);
297
298 m_separator = new KSeparator(Qt::Vertical, this);
299
300 // Create "From Here" and "Everywhere"button
301 m_fromHereButton = new QPushButton(this);
302 m_fromHereButton->setText(i18nc("action:button", "From Here"));
303 initButton(m_fromHereButton);
304
305 m_everywhereButton = new QPushButton(this);
306 m_everywhereButton->setText(i18nc("action:button", "Everywhere"));
307 initButton(m_everywhereButton);
308
309 QButtonGroup* searchLocationGroup = new QButtonGroup(this);
310 searchLocationGroup->addButton(m_fromHereButton);
311 searchLocationGroup->addButton(m_everywhereButton);
312
313 // Apply layout for the options
314 QHBoxLayout* optionsLayout = new QHBoxLayout();
315 optionsLayout->setMargin(0);
316 optionsLayout->addWidget(m_fileNameButton);
317 optionsLayout->addWidget(m_contentButton);
318 optionsLayout->addWidget(m_separator);
319 optionsLayout->addWidget(m_fromHereButton);
320 optionsLayout->addWidget(m_everywhereButton);
321 optionsLayout->addStretch(1);
322
323 // Put the options into a QScrollArea. This prevents increasing the view width
324 // in case that not enough width for the options is available.
325 QWidget* optionsContainer = new QWidget(this);
326 optionsContainer->setLayout(optionsLayout);
327 QScrollArea* optionsScrollArea = new QScrollArea(this);
328 optionsScrollArea->setFrameShape(QFrame::NoFrame);
329 optionsScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
330 optionsScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
331 optionsScrollArea->setMaximumHeight(optionsContainer->sizeHint().height());
332 optionsScrollArea->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
333 optionsScrollArea->setWidget(optionsContainer);
334 optionsScrollArea->setWidgetResizable(true);
335
336 m_topLayout = new QVBoxLayout(this);
337 m_topLayout->addLayout(searchInputLayout);
338 m_topLayout->addWidget(optionsScrollArea);
339
340 searchLabel->setBuddy(m_searchInput);
341 loadSettings();
342
343 // The searching should be started automatically after the user did not change
344 // the text within one second
345 m_startSearchTimer = new QTimer(this);
346 m_startSearchTimer->setSingleShot(true);
347 m_startSearchTimer->setInterval(1000);
348 connect(m_startSearchTimer, SIGNAL(timeout()), this, SLOT(emitSearchSignal()));
349
350 applyReadOnlyState();
351 }
352
353 KUrl DolphinSearchBox::nepomukUrlForSearching() const
354 {
355 #ifdef HAVE_NEPOMUK
356 Nepomuk::Query::AndTerm andTerm;
357
358 // Add input from search filter
359 const QString text = m_searchInput->text();
360 if (!text.isEmpty()) {
361 if (m_fileNameButton->isChecked()) {
362 QString regex = QRegExp::escape(text);
363 regex.replace("\\*", QLatin1String(".*"));
364 regex.replace("\\?", QLatin1String("."));
365 regex.replace("\\", "\\\\");
366 andTerm.addSubTerm(Nepomuk::Query::ComparisonTerm(
367 Nepomuk::Vocabulary::NFO::fileName(),
368 Nepomuk::Query::LiteralTerm(regex),
369 Nepomuk::Query::ComparisonTerm::Regexp));
370 } else {
371 const Nepomuk::Query::Query customQuery = Nepomuk::Query::QueryParser::parseQuery(text, Nepomuk::Query::QueryParser::DetectFilenamePattern);
372 if (customQuery.isValid()) {
373 andTerm.addSubTerm(customQuery.term());
374 }
375 }
376 }
377
378 Nepomuk::Query::FileQuery fileQuery;
379 fileQuery.setFileMode(Nepomuk::Query::FileQuery::QueryFilesAndFolders);
380 fileQuery.setTerm(andTerm);
381 if (m_fromHereButton->isChecked()) {
382 const bool recursive = true;
383 fileQuery.addIncludeFolder(m_searchPath, recursive);
384 }
385
386 return fileQuery.toSearchUrl(i18nc("@title UDS_DISPLAY_NAME for a KIO directory listing. %1 is the query the user entered.",
387 "Query Results from '%1'",
388 text));
389 #else
390 return KUrl();
391 #endif
392 }
393
394 void DolphinSearchBox::applyReadOnlyState()
395 {
396 // TODO: This is just an early draft to indicate that a state change
397 // has been done
398 m_searchInput->setVisible(!m_readOnly);
399 m_infoLabel->setVisible(m_readOnly);
400 m_fileNameButton->setEnabled(!m_readOnly);
401 m_contentButton->setEnabled(!m_readOnly);
402 m_fromHereButton->setEnabled(!m_readOnly);
403 m_everywhereButton->setEnabled(!m_readOnly);
404 }
405
406 #include "dolphinsearchbox.moc"