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
63static const int MIN_WIDTH = 420;
64
65Interface::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
229bool 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
257void Interface::saveDialogSize(KConfigGroup &group)
258{
259 group.writeEntry("Size", m_defaultSize);
260}
261
262void Interface::restoreDialogSize(KConfigGroup &group)
263{
264 resize(group.readEntry("Size", size()));
265}
266
267void 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
282void 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
299void Interface::configWidgetDestroyed()
300{
301 QTimer::singleShot(0, this, SLOT(cleanupAfterConfigWidget()));
302}
303
304void Interface::cleanupAfterConfigWidget()
305{
306 m_searchTerm->setEnabled(true);
307 resetInterface();
308 searchTermSetFocus();
309}
310
311void 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
329void Interface::saveCurrentDialogSize()
330{
331 KConfigGroup interfaceConfig(KGlobal::config(), "Interface");
332 saveDialogSize(interfaceConfig);
333}
334
335Interface::~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
349void Interface::searchTermSetFocus()
350{
351 if (m_runnerManager->singleMode()) {
352 m_singleRunnerSearchTerm->setFocus();
353 } else {
354 m_searchTerm->setFocus();
355 }
356}
357
358
359void 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
368void Interface::clearHistory()
369{
370 m_searchTerm->clearHistory();
371 KRunnerSettings::setPastQueries(m_searchTerm->historyItems());
372}
373
374void 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
401void 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
415void 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
450void 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
468void Interface::hideEvent(QHideEvent *e)
469{
470 resetInterface();
471 KRunnerDialog::hideEvent(e);
472}
473
474void 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
530void Interface::resetAndClose()
531{
532 resetInterface();
533 close();
534}
535
536
537void Interface::runDefaultResultItem()
538{
539 if (m_queryRunning) {
540 m_delayedRun = true;
541 } else {
542 run(m_resultsScene->defaultResultItem());
543 }
544}
545
546void 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
566void 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
581void 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
615void Interface::reenableHoverEvents()
616{
617 //kDebug() << "reenabling hover events, for better or worse";
618 m_resultData.processHoverEvents = true;
619}
620
621void 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
651void Interface::hideResultsArea()
652{
653 searchTermSetFocus();
654 resetResultsArea();
655}
656
657void 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