1 | /*************************************************************************** |
2 | * Copyright 2006 by Aaron Seigo <aseigo@kde.org> * |
3 | * Copyright 2008 by Davide Bettio <davide.bettio@kdemail.net> * |
4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * |
7 | * the Free Software Foundation; either version 2 of the License, or * |
8 | * (at your option) any later version. * |
9 | * * |
10 | * This program is distributed in the hope that it will be useful, * |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 | * GNU General Public License for more details. * |
14 | * * |
15 | * You should have received a copy of the GNU General Public License * |
16 | * along with this program; if not, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * |
19 | ***************************************************************************/ |
20 | |
21 | #include "interface.h" |
22 | |
23 | #include <QAction> |
24 | #include <QApplication> |
25 | #include <QClipboard> |
26 | #include <QDesktopWidget> |
27 | #include <QGraphicsView> |
28 | #include <QHBoxLayout> |
29 | #include <QHideEvent> |
30 | #include <QLabel> |
31 | #include <QShortcut> |
32 | #include <QToolButton> |
33 | #include <QVBoxLayout> |
34 | |
35 | #include <KAction> |
36 | #include <KActionCollection> |
37 | #include <KHistoryComboBox> |
38 | #include <KCompletion> |
39 | #include <KCompletionBox> |
40 | #include <KDebug> |
41 | #include <KDialog> |
42 | #include <KLineEdit> |
43 | #include <KLocale> |
44 | #include <KGlobalSettings> |
45 | #include <KPushButton> |
46 | #include <KStyle> |
47 | #include <KTitleWidget> |
48 | #include <KWindowSystem> |
49 | |
50 | #include <Plasma/AbstractRunner> |
51 | #include <Plasma/RunnerManager> |
52 | #include <Plasma/Theme> |
53 | #include <Plasma/Svg> |
54 | |
55 | #include "krunnerapp.h" |
56 | #include "krunnersettings.h" |
57 | #include "interfaces/default/resultscene.h" |
58 | #include "interfaces/default/resultitem.h" |
59 | #include "interfaces/default/krunnerhistorycombobox.h" |
60 | #include "interfaces/default/resultview.h" |
61 | #include "toolbutton.h" |
62 | |
63 | static const int MIN_WIDTH = 420; |
64 | |
65 | Interface::Interface(Plasma::RunnerManager *runnerManager, QWidget *parent) |
66 | : KRunnerDialog(runnerManager, parent), |
67 | m_delayedRun(false), |
68 | m_running(false), |
69 | m_queryRunning(false) |
70 | { |
71 | m_resultData.processHoverEvents = true; |
72 | m_resultData.mouseHovering = false; |
73 | m_resultData.runnerManager = runnerManager; |
74 | |
75 | m_hideResultsTimer.setSingleShot(true); |
76 | connect(&m_hideResultsTimer, SIGNAL(timeout()), this, SLOT(hideResultsArea())); |
77 | |
78 | m_reenableHoverEventsTimer.setSingleShot(true); |
79 | m_reenableHoverEventsTimer.setInterval(50); |
80 | connect(&m_reenableHoverEventsTimer, SIGNAL(timeout()), this, SLOT(reenableHoverEvents())); |
81 | |
82 | m_layout = new QVBoxLayout(this); |
83 | m_layout->setMargin(0); |
84 | |
85 | m_buttonContainer = new QWidget(this); |
86 | QHBoxLayout *bottomLayout = new QHBoxLayout(m_buttonContainer); |
87 | bottomLayout->setMargin(0); |
88 | |
89 | m_configButton = new ToolButton(m_buttonContainer); |
90 | m_configButton->setText(i18n("Settings" )); |
91 | m_configButton->setToolTip(i18n("Settings" )); |
92 | connect(m_configButton, SIGNAL(clicked()), SLOT(toggleConfigDialog())); |
93 | bottomLayout->addWidget(m_configButton); |
94 | |
95 | //Set up the system activity button, using the krunner global action, showing the global shortcut in the tooltip |
96 | m_activityButton = new ToolButton(m_buttonContainer); |
97 | KRunnerApp *krunnerApp = KRunnerApp::self(); |
98 | QAction *showSystemActivityAction = krunnerApp->actionCollection()->action(QLatin1String( "Show System Activity" )); |
99 | m_activityButton->setDefaultAction(showSystemActivityAction); |
100 | |
101 | updateSystemActivityToolTip(); |
102 | connect(showSystemActivityAction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(updateSystemActivityToolTip())); |
103 | connect(showSystemActivityAction, SIGNAL(triggered(bool)), this, SLOT(resetAndClose())); |
104 | bottomLayout->addWidget(m_activityButton); |
105 | |
106 | m_singleRunnerIcon = new QLabel(); |
107 | bottomLayout->addWidget(m_singleRunnerIcon); |
108 | m_singleRunnerDisplayName = new QLabel(); |
109 | bottomLayout->addWidget(m_singleRunnerDisplayName); |
110 | |
111 | m_helpButton = new ToolButton(m_buttonContainer); |
112 | m_helpButton->setText(i18n("Help" )); |
113 | m_helpButton->setToolTip(i18n("Information on using this application" )); |
114 | connect(m_helpButton, SIGNAL(clicked(bool)), SLOT(showHelp())); |
115 | connect(m_helpButton, SIGNAL(clicked(bool)), SLOT(configCompleted())); |
116 | bottomLayout->addWidget(m_helpButton); |
117 | |
118 | QSpacerItem* closeButtonSpacer = new QSpacerItem(0,0,QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); |
119 | bottomLayout->addSpacerItem(closeButtonSpacer); |
120 | |
121 | m_closeButton = new ToolButton(m_buttonContainer); |
122 | KGuiItem guiItem = KStandardGuiItem::close(); |
123 | m_closeButton->setText(guiItem.text()); |
124 | m_closeButton->setToolTip(guiItem.text().remove(QLatin1Char( '&' ))); |
125 | connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(resetAndClose())); |
126 | bottomLayout->addWidget(m_closeButton); |
127 | |
128 | m_layout->addWidget(m_buttonContainer); |
129 | |
130 | m_searchTerm = new KrunnerHistoryComboBox(false, this); |
131 | |
132 | KLineEdit *lineEdit = new KLineEdit(m_searchTerm); |
133 | QAction *focusEdit = new QAction(this); |
134 | focusEdit->setShortcut(Qt::Key_F6); |
135 | |
136 | connect(focusEdit, SIGNAL(triggered(bool)), this, SLOT(searchTermSetFocus())); |
137 | addAction(focusEdit); |
138 | |
139 | // the order of these next few lines if very important. |
140 | // QComboBox::setLineEdit sets the autoComplete flag on the lineedit, |
141 | // and KComboBox::setAutoComplete resets the autocomplete mode! ugh! |
142 | m_searchTerm->setLineEdit(lineEdit); |
143 | |
144 | m_completion = new KCompletion(); |
145 | lineEdit->setCompletionObject(m_completion); |
146 | lineEdit->setCompletionMode(static_cast<KGlobalSettings::Completion>(KRunnerSettings::queryTextCompletionMode())); |
147 | lineEdit->setClearButtonShown(true); |
148 | QStringList pastQueryItems = KRunnerSettings::pastQueries(); |
149 | m_searchTerm->setHistoryItems(pastQueryItems); |
150 | m_completion->insertItems(pastQueryItems); |
151 | bottomLayout->insertWidget(4, m_searchTerm, 10); |
152 | |
153 | m_singleRunnerSearchTerm = new KLineEdit(this); |
154 | bottomLayout->insertWidget(4, m_singleRunnerSearchTerm, 10 ); |
155 | |
156 | //kDebug() << "size:" << m_resultsView->size() << m_resultsView->minimumSize(); |
157 | m_resultsScene = new ResultScene(&m_resultData, runnerManager, m_searchTerm, this); |
158 | m_resultsView = new ResultsView(m_resultsScene, &m_resultData, this); |
159 | m_layout->addWidget(m_resultsView); |
160 | |
161 | connect(m_resultsScene, SIGNAL(viewableHeightChanged()), this, SLOT(fitWindow())); |
162 | connect(m_resultsScene, SIGNAL(matchCountChanged(int)), this, SLOT(matchCountChanged(int))); |
163 | connect(m_resultsScene, SIGNAL(itemActivated(ResultItem*)), this, SLOT(run(ResultItem*))); |
164 | |
165 | connect(m_searchTerm, SIGNAL(queryTextEdited(QString)), this, SLOT(queryTextEdited(QString))); |
166 | connect(m_searchTerm, SIGNAL(returnPressed()), this, SLOT(runDefaultResultItem())); |
167 | connect(m_singleRunnerSearchTerm, SIGNAL(textChanged(QString)), this, SLOT(queryTextEdited(QString))); |
168 | connect(m_singleRunnerSearchTerm, SIGNAL(returnPressed()), this, SLOT(runDefaultResultItem())); |
169 | |
170 | lineEdit->installEventFilter(this); |
171 | m_searchTerm->installEventFilter(this); |
172 | |
173 | themeUpdated(); |
174 | connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated())); |
175 | |
176 | new QShortcut(QKeySequence(Qt::Key_Escape), this, SLOT(resetAndClose())); |
177 | |
178 | m_layout->setAlignment(Qt::AlignTop); |
179 | |
180 | setTabOrder(0, m_configButton); |
181 | setTabOrder(m_configButton, m_activityButton); |
182 | setTabOrder(m_activityButton, m_searchTerm); |
183 | setTabOrder(m_searchTerm, m_singleRunnerSearchTerm); |
184 | setTabOrder(m_singleRunnerSearchTerm, m_resultsView); |
185 | setTabOrder(m_resultsView, m_helpButton); |
186 | setTabOrder(m_helpButton, m_closeButton); |
187 | |
188 | //kDebug() << "size:" << m_resultsView->size() << m_resultsView->minimumSize() << minimumSizeHint(); |
189 | |
190 | // we restore the original size, which will set the results view back to its |
191 | // normal size, then we hide the results view and resize the dialog |
192 | |
193 | setMinimumSize(QSize(MIN_WIDTH, m_searchTerm->sizeHint().height())); |
194 | |
195 | // we load the last used size; the saved value is the size of the dialog when the |
196 | // results are visible; |
197 | adjustSize(); |
198 | |
199 | if (KGlobal::config()->hasGroup("Interface" )) { |
200 | KConfigGroup interfaceConfig(KGlobal::config(), "Interface" ); |
201 | restoreDialogSize(interfaceConfig); |
202 | m_defaultSize = size(); |
203 | } else { |
204 | const int screenWidth = qApp->desktop()->screenGeometry().width(); |
205 | int width = size().width(); |
206 | |
207 | if (screenWidth >= 1920) { |
208 | width = qMax(width, 550); |
209 | } else if (screenWidth >= 1024) { |
210 | width = qMax(width, 300); |
211 | } |
212 | |
213 | m_defaultSize = QSize(width, 500); |
214 | } |
215 | |
216 | m_resultsView->hide(); |
217 | |
218 | m_delayedQueryTimer.setSingleShot(true); |
219 | m_delayedQueryTimer.setInterval(50); |
220 | connect(&m_delayedQueryTimer, SIGNAL(timeout()), this, SLOT(delayedQueryLaunch())); |
221 | |
222 | m_saveDialogSizeTimer.setSingleShot(true); |
223 | m_saveDialogSizeTimer.setInterval(1000); |
224 | connect(&m_saveDialogSizeTimer, SIGNAL(timeout()), SLOT(saveCurrentDialogSize())); |
225 | |
226 | QTimer::singleShot(0, this, SLOT(resetInterface())); |
227 | } |
228 | |
229 | bool Interface::eventFilter(QObject *obj, QEvent *event) |
230 | { |
231 | if (obj == m_searchTerm->lineEdit() && event->type() == QEvent::MouseButtonPress) { |
232 | if (KWindowSystem::activeWindow() != winId()) { |
233 | // this overcomes problems with click-to-focus and being a Dock window |
234 | KWindowSystem::forceActiveWindow(winId()); |
235 | searchTermSetFocus(); |
236 | } |
237 | } else if (obj == m_searchTerm && event->type() == QEvent::KeyPress) { |
238 | QKeyEvent *ke = static_cast<QKeyEvent *>(event); |
239 | // the comparision between itemText(1) and the currentText is an artifact |
240 | // of KHistoryComboBox: it sets the combobox to index 1 when using arrow-down |
241 | // through entries after having arrow-up'd through them and hitting the |
242 | // last item ... which one would expect to be index 0. index 1 is _also_ |
243 | // the first item in the history at other times, however, so we need to |
244 | // check if index 1 is indeed the actual item or if item 1 is not the same |
245 | // the current text. very, very odd. but it works. - aseigo. |
246 | if (ke->key() == Qt::Key_Down && |
247 | (m_searchTerm->currentIndex() < 1 || |
248 | (m_searchTerm->currentIndex() == 1 && |
249 | m_searchTerm->itemText(1) != m_searchTerm->currentText()))) { |
250 | m_resultsView->setFocus(); |
251 | } |
252 | } |
253 | |
254 | return KRunnerDialog::eventFilter(obj, event); |
255 | } |
256 | |
257 | void Interface::saveDialogSize(KConfigGroup &group) |
258 | { |
259 | group.writeEntry("Size" , m_defaultSize); |
260 | } |
261 | |
262 | void Interface::restoreDialogSize(KConfigGroup &group) |
263 | { |
264 | resize(group.readEntry("Size" , size())); |
265 | } |
266 | |
267 | void Interface::updateSystemActivityToolTip() |
268 | { |
269 | /* Set the tooltip for the Show System Activity button to include the global shortcut */ |
270 | KRunnerApp *krunnerApp = KRunnerApp::self(); |
271 | KAction *showSystemActivityAction = dynamic_cast<KAction *>(krunnerApp->actionCollection()->action(QLatin1String( "Show System Activity" ))); |
272 | if (showSystemActivityAction) { |
273 | QString shortcut = showSystemActivityAction->globalShortcut().toString(); |
274 | if (shortcut.isEmpty()) { |
275 | m_activityButton->setToolTip( showSystemActivityAction->toolTip() ); |
276 | } else { |
277 | m_activityButton->setToolTip( i18nc("tooltip, shortcut" , "%1 (%2)" , showSystemActivityAction->toolTip(), shortcut)); |
278 | } |
279 | } |
280 | } |
281 | |
282 | void Interface::setConfigWidget(QWidget *w) |
283 | { |
284 | const int screenId = qApp->desktop()->screenNumber(this); |
285 | const int maxHeight = qApp->desktop()->availableGeometry(screenId).height(); |
286 | |
287 | int left, top, right, bottom; |
288 | getContentsMargins(&left, &top, &right, &bottom); |
289 | const int padding = top + bottom + m_activityButton->height(); |
290 | resize(width(), qMin(maxHeight, qMax(w->sizeHint().height() + padding, m_defaultSize.height()))); |
291 | |
292 | m_resultsView->hide(); |
293 | m_searchTerm->setEnabled(false); |
294 | m_layout->addWidget(w); |
295 | |
296 | connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(configWidgetDestroyed())); |
297 | } |
298 | |
299 | void Interface::configWidgetDestroyed() |
300 | { |
301 | QTimer::singleShot(0, this, SLOT(cleanupAfterConfigWidget())); |
302 | } |
303 | |
304 | void Interface::cleanupAfterConfigWidget() |
305 | { |
306 | m_searchTerm->setEnabled(true); |
307 | resetInterface(); |
308 | searchTermSetFocus(); |
309 | } |
310 | |
311 | void Interface::resizeEvent(QResizeEvent *event) |
312 | { |
313 | // We set m_defaultSize only when the event is spontaneous, i.e. when the user resizes the |
314 | // window, or if they are manually resizing it |
315 | if ((freeFloating() && event->spontaneous()) || manualResizing() != NotResizing) { |
316 | if (manualResizing() == HorizontalResizing) { |
317 | m_defaultSize = QSize(size().width(), m_defaultSize.height()); |
318 | } else { |
319 | m_defaultSize = QSize(m_defaultSize.width(), size().height()); |
320 | } |
321 | m_saveDialogSizeTimer.start(); |
322 | } |
323 | |
324 | m_resultsView->resize(m_buttonContainer->width(), m_resultsView->height()); |
325 | m_resultsScene->setWidth(m_resultsView->width()); |
326 | KRunnerDialog::resizeEvent(event); |
327 | } |
328 | |
329 | void Interface::saveCurrentDialogSize() |
330 | { |
331 | KConfigGroup interfaceConfig(KGlobal::config(), "Interface" ); |
332 | saveDialogSize(interfaceConfig); |
333 | } |
334 | |
335 | Interface::~Interface() |
336 | { |
337 | KRunnerSettings::setPastQueries(m_searchTerm->historyItems()); |
338 | KRunnerSettings::setQueryTextCompletionMode(m_searchTerm->completionMode()); |
339 | KRunnerSettings::self()->writeConfig(); |
340 | |
341 | // Before saving the size we resize to the default size, with the results container shown. |
342 | resize(m_defaultSize); |
343 | KConfigGroup interfaceConfig(KGlobal::config(), "Interface" ); |
344 | saveCurrentDialogSize(); |
345 | KGlobal::config()->sync(); |
346 | } |
347 | |
348 | |
349 | void Interface::searchTermSetFocus() |
350 | { |
351 | if (m_runnerManager->singleMode()) { |
352 | m_singleRunnerSearchTerm->setFocus(); |
353 | } else { |
354 | m_searchTerm->setFocus(); |
355 | } |
356 | } |
357 | |
358 | |
359 | void Interface::themeUpdated() |
360 | { |
361 | //reset the icons |
362 | m_helpButton->setIcon(m_iconSvg->pixmap(QLatin1String( "help" ))); |
363 | m_configButton->setIcon(m_iconSvg->pixmap(QLatin1String( "configure" ))); |
364 | m_activityButton->setIcon(m_iconSvg->pixmap(QLatin1String( "status" ))); |
365 | m_closeButton->setIcon(m_iconSvg->pixmap(QLatin1String( "close" ))); |
366 | } |
367 | |
368 | void Interface::clearHistory() |
369 | { |
370 | m_searchTerm->clearHistory(); |
371 | KRunnerSettings::setPastQueries(m_searchTerm->historyItems()); |
372 | } |
373 | |
374 | void Interface::display(const QString &term) |
375 | { |
376 | if (!term.isEmpty() || !isVisible() || |
377 | m_runnerManager->singleMode() != m_singleRunnerIcon->isVisible()) { |
378 | resetInterface(); |
379 | } |
380 | |
381 | positionOnScreen(); |
382 | searchTermSetFocus(); |
383 | |
384 | if (m_runnerManager->singleMode()) { |
385 | if (term.isEmpty()) { |
386 | // We need to manually trigger queryTextEdited, since |
387 | // with an empty query it won't be triggered; still we need it |
388 | // to launch the query |
389 | queryTextEdited(QString()); |
390 | } else { |
391 | m_singleRunnerSearchTerm->setText(term); |
392 | } |
393 | } else if (!term.isEmpty()) { |
394 | m_searchTerm->setItemText(0, term); |
395 | m_searchTerm->setCurrentIndex(0); |
396 | } else { |
397 | m_searchTerm->reset(); |
398 | } |
399 | } |
400 | |
401 | void Interface::resetInterface() |
402 | { |
403 | setStaticQueryMode(false); |
404 | m_delayedRun = false; |
405 | m_searchTerm->setCurrentItem(QString(), true, 0); |
406 | m_singleRunnerSearchTerm->clear(); |
407 | m_resultsScene->queryCleared(); |
408 | if (!m_running) { |
409 | m_runnerManager->reset(); |
410 | } |
411 | resetResultsArea(); |
412 | m_minimumHeight = height(); |
413 | } |
414 | |
415 | void Interface::showHelp() |
416 | { |
417 | QMap<QString, Plasma::QueryMatch> matches; |
418 | QList<Plasma::AbstractRunner*> runnerList; |
419 | |
420 | Plasma::AbstractRunner *singleRunner = m_runnerManager->singleModeRunner(); |
421 | if (singleRunner) { |
422 | runnerList << singleRunner; |
423 | } else { |
424 | runnerList = m_runnerManager->runners(); |
425 | } |
426 | |
427 | |
428 | foreach (Plasma::AbstractRunner *runner, runnerList) { |
429 | int count = 0; |
430 | QIcon icon(runner->icon()); |
431 | if (icon.isNull()) { |
432 | icon = KIcon(QLatin1String( "system-run" )); |
433 | } |
434 | |
435 | foreach (const Plasma::RunnerSyntax &syntax, runner->syntaxes()) { |
436 | Plasma::QueryMatch match(0); |
437 | match.setType(Plasma::QueryMatch::InformationalMatch); |
438 | match.setIcon(icon); |
439 | match.setText(syntax.exampleQueriesWithTermDescription().join(QLatin1String( ", " ))); |
440 | match.setSubtext(syntax.description() + QLatin1Char( '\n' ) + |
441 | i18n("(From %1, %2)" , runner->name(), runner->description())); |
442 | match.setData(syntax.exampleQueries().first()); |
443 | matches.insert(runner->name() + QString::number(++count), match); |
444 | } |
445 | } |
446 | |
447 | m_resultsScene->setQueryMatches(matches.values()); |
448 | } |
449 | |
450 | void Interface::setStaticQueryMode(bool staticQuery) |
451 | { |
452 | // don't show the search and other control buttons in the case of a static querymatch |
453 | const bool visible = !staticQuery; |
454 | Plasma::AbstractRunner *singleRunner = m_runnerManager->singleModeRunner(); |
455 | m_configButton->setVisible(visible && !singleRunner); |
456 | m_activityButton->setVisible(visible && !singleRunner); |
457 | m_helpButton->setVisible(visible); |
458 | m_searchTerm->setVisible(visible && !singleRunner); |
459 | m_singleRunnerSearchTerm->setVisible(visible && singleRunner); |
460 | if (singleRunner) { |
461 | m_singleRunnerIcon->setPixmap(singleRunner->icon().pixmap(QSize(22, 22))); |
462 | m_singleRunnerDisplayName->setText(singleRunner->name()); |
463 | } |
464 | m_singleRunnerIcon->setVisible(singleRunner); |
465 | m_singleRunnerDisplayName->setVisible(singleRunner); |
466 | } |
467 | |
468 | void Interface::hideEvent(QHideEvent *e) |
469 | { |
470 | resetInterface(); |
471 | KRunnerDialog::hideEvent(e); |
472 | } |
473 | |
474 | void Interface::run(ResultItem *item) |
475 | { |
476 | if (!item || !item->isValid() || item->group() < Plasma::QueryMatch::PossibleMatch) { |
477 | m_delayedRun = true; |
478 | return; |
479 | } |
480 | |
481 | kDebug() << item->name() << item->id(); |
482 | m_delayedRun = false; |
483 | |
484 | if (item->group() == Plasma::QueryMatch::InformationalMatch) { |
485 | QString info = item->data(); |
486 | int editPos = info.length(); |
487 | |
488 | if (!info.isEmpty()) { |
489 | if (item->isQueryPrototype()) { |
490 | // lame way of checking to see if this is a Help Button generated match! |
491 | int index = info.indexOf(QLatin1String( ":q:" )); |
492 | |
493 | if (index != -1) { |
494 | editPos = index; |
495 | info.replace(QLatin1String( ":q:" ), QLatin1String( "" )); |
496 | } |
497 | } |
498 | |
499 | QStringList history = m_searchTerm->historyItems(); |
500 | history.prepend(m_searchTerm->currentText().trimmed()); |
501 | kDebug() << m_searchTerm->currentText() << history; |
502 | m_searchTerm->setHistoryItems(history); |
503 | m_searchTerm->setCurrentIndex(0); |
504 | m_searchTerm->lineEdit()->setText(info); |
505 | m_searchTerm->lineEdit()->setCursorPosition(editPos); |
506 | QApplication::clipboard()->setText(info); |
507 | } |
508 | return; |
509 | } |
510 | |
511 | //TODO: check if run is succesful before adding the term to history |
512 | if ((item->group() == Plasma::QueryMatch::CompletionMatch) || |
513 | (item->group() == Plasma::QueryMatch::PossibleMatch)) { |
514 | m_searchTerm->addToHistory(item->name()); |
515 | } else { |
516 | m_searchTerm->addToHistory(m_searchTerm->currentText().trimmed()); |
517 | } |
518 | |
519 | m_running = true; |
520 | // must run the result first before clearing the interface |
521 | // in a way that will cause the results scene to be cleared and |
522 | // the RunnerManager to be cleared of context as a result |
523 | close(); |
524 | item->run(m_runnerManager); |
525 | m_running = false; |
526 | |
527 | resetInterface(); |
528 | } |
529 | |
530 | void Interface::resetAndClose() |
531 | { |
532 | resetInterface(); |
533 | close(); |
534 | } |
535 | |
536 | |
537 | void Interface::runDefaultResultItem() |
538 | { |
539 | if (m_queryRunning) { |
540 | m_delayedRun = true; |
541 | } else { |
542 | run(m_resultsScene->defaultResultItem()); |
543 | } |
544 | } |
545 | |
546 | void Interface::queryTextEdited(const QString &query) |
547 | { |
548 | if (query.isEmpty() || query.trimmed() != m_runnerManager->query()) { |
549 | // if the query is empty and the query is NOT what we are currently looking for ... then |
550 | // reset m_delayedRun. it does happen, however, that a search is being made already for the |
551 | // query text and this method gets called again, in which case we do NOT want to reset |
552 | // m_delayedRun |
553 | m_delayedRun = false; |
554 | } |
555 | |
556 | if (query.isEmpty() && !m_runnerManager->singleMode()) { |
557 | m_delayedQueryTimer.stop(); |
558 | resetInterface(); |
559 | m_queryRunning = false; |
560 | } else { |
561 | m_delayedQueryTimer.start(); |
562 | m_queryRunning = true; |
563 | } |
564 | } |
565 | |
566 | void Interface::delayedQueryLaunch() |
567 | { |
568 | const QString query = (m_runnerManager->singleMode() ? m_singleRunnerSearchTerm->userText() |
569 | : static_cast<KLineEdit*>(m_searchTerm->lineEdit())->userText()).trimmed(); |
570 | const QString runnerId = m_runnerManager->singleMode() ? m_runnerManager->singleModeRunnerId() : QString(); |
571 | |
572 | // we want to check if this is a new query or not for the later running of |
573 | // the default item |
574 | if (!query.isEmpty() || m_runnerManager->singleMode()) { |
575 | const bool newQuery = !query.isEmpty() && m_runnerManager->query() != query; |
576 | m_queryRunning = m_queryRunning || newQuery || !runnerId.isEmpty(); |
577 | m_runnerManager->launchQuery(query, runnerId); |
578 | } |
579 | } |
580 | |
581 | void Interface::matchCountChanged(int count) |
582 | { |
583 | m_queryRunning = false; |
584 | const bool show = count > 0; |
585 | m_hideResultsTimer.stop(); |
586 | |
587 | if (show && m_delayedRun) { |
588 | kDebug() << "delayed run with" << count << "items" ; |
589 | runDefaultResultItem(); |
590 | return; |
591 | } |
592 | |
593 | if (show) { |
594 | //kDebug() << "showing!" << minimumSizeHint(); |
595 | if (!m_resultsView->isVisible()) { |
596 | fitWindow(); |
597 | |
598 | // Next 2 lines are a workaround to allow arrow |
599 | // keys navigation in krunner's result list. |
600 | // Patch submited in bugreport #211578 |
601 | QEvent event(QEvent::WindowActivate); |
602 | QApplication::sendEvent(m_resultsView, &event); |
603 | |
604 | m_resultsView->show(); |
605 | } |
606 | //m_resultsScene->resize(m_resultsView->width(), qMax(m_resultsView->height(), int(m_resultsScene->height()))); |
607 | //kDebug() << s << size(); |
608 | } else { |
609 | //kDebug() << "hiding ... eventually"; |
610 | m_delayedRun = false; |
611 | m_hideResultsTimer.start(1000); |
612 | } |
613 | } |
614 | |
615 | void Interface::reenableHoverEvents() |
616 | { |
617 | //kDebug() << "reenabling hover events, for better or worse"; |
618 | m_resultData.processHoverEvents = true; |
619 | } |
620 | |
621 | void Interface::fitWindow() |
622 | { |
623 | m_resultData.processHoverEvents = false; |
624 | QSize s = m_defaultSize; |
625 | const int resultsHeight = m_resultsScene->viewableHeight() + 2; |
626 | int spacing = m_layout->spacing(); |
627 | if (spacing < 0) { |
628 | // KStyles allow for variable spacing via the layoutSpacingImplementation() method; |
629 | // in this case m_layout->spacing() returns -1 and we should ask for the |
630 | // spacing by ourselves. |
631 | // This is quite ugly, but at least gives the right guess, so that we avoid |
632 | // multiple resize events |
633 | spacing = style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Vertical); |
634 | } |
635 | |
636 | //kDebug() << m_minimumHeight << resultsHeight << spacing << s.height(); |
637 | |
638 | if (m_minimumHeight + resultsHeight + spacing < s.height()) { |
639 | s.setHeight(m_minimumHeight + resultsHeight + spacing); |
640 | m_resultsView->setMinimumHeight(resultsHeight); |
641 | // The layout will activate on the next event cycle, but |
642 | // we need to update the minimum size now, as we are going to |
643 | // resize the krunner window right away. |
644 | m_layout->activate(); |
645 | } |
646 | |
647 | resize(s); |
648 | m_reenableHoverEventsTimer.start(); |
649 | } |
650 | |
651 | void Interface::hideResultsArea() |
652 | { |
653 | searchTermSetFocus(); |
654 | resetResultsArea(); |
655 | } |
656 | |
657 | void Interface::resetResultsArea() |
658 | { |
659 | m_resultsView->hide(); |
660 | setMinimumSize(QSize(MIN_WIDTH, m_searchTerm->sizeHint().height())); |
661 | resize(qMax(minimumSizeHint().width(), m_defaultSize.width()), minimumSizeHint().height()); |
662 | } |
663 | |
664 | #include "interface.moc" |
665 | |