Removed backup files
[krunner.git] / interface.cpp
blob94eb472e576d4ba4f0c1dac670da3687f7c93ba4
1 /*
2 * Copyright (C) 2006 Aaron Seigo <aseigo@kde.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License version 2 as
6 * published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details
13 * You should have received a copy of the GNU Library General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <QAction>
20 #include <QApplication>
21 #include <QLabel>
22 #include <QListWidget>
23 #include <QVBoxLayout>
24 #include <QHBoxLayout>
25 #include <QShortcut>
26 #include <QTimer>
27 #include <QHideEvent>
28 #include <QGraphicsItem>
30 #include <KActionCollection>
31 #include <KDebug>
32 #include <KDialog>
33 #include <KLineEdit>
34 #include <KLocale>
35 #include <KGlobalSettings>
36 #include <KPushButton>
37 #include <KStandardGuiItem>
38 #include <KTitleWidget>
39 #include <KWindowSystem>
41 #include <plasma/abstractrunner.h>
42 #include <QPainter>
43 #include <QSvgRenderer>
44 #include <QResizeEvent>
45 #include <QBitmap>
47 #include <KDebug>
49 #include <plasma/widgets/lineedit.h>
51 #include "runners/services/servicerunner.h"
52 #include "runners/sessions/sessionrunner.h"
53 #include "runners/shell/shellrunner.h"
54 #include "collapsiblewidget.h"
55 #include "interface.h"
56 #include "interfaceadaptor.h"
57 #include "krunnerapp.h"
59 //FIXME:
61 #define KRUNNER_SIZE 350, 101
64 // A little hack of a class to let us easily activate a match
66 class SearchMatch : public QListWidgetItem
68 public:
69 SearchMatch( QAction* action, Plasma::AbstractRunner* runner, QListWidget* parent )
70 : QListWidgetItem( parent ),
71 m_default( false ),
72 m_action( 0 ),
73 m_runner( runner )
75 setAction( action );
78 void activate()
80 m_action->activate( QAction::Trigger );
83 bool actionEnabled()
85 return m_action->isEnabled();
88 void setAction( QAction* action )
90 m_action = action;
91 setIcon( m_action->icon() );
92 setText( i18n("%1 (%2)",
93 m_action->text(),
94 m_runner->objectName() ) );
96 // in case our new action is now enabled and the old one wasn't, or
97 // vice versa
98 setDefault( m_default );
101 Plasma::AbstractRunner* runner()
103 return m_runner;
106 void setDefault( bool def ) {
107 if ( m_default == def ) {
108 return;
111 m_default = def;
113 if ( m_default ) {
114 if ( m_action->isEnabled() ) {
115 setText( text().prepend( i18n("Default: ") ) );
117 } else {
118 setText( text().mid( 9 ) );
122 private:
123 bool m_default;
124 QAction* m_action;
125 Plasma::AbstractRunner* m_runner;
128 GenericItem::GenericItem(Plasma::Svg *renderer, Interface *qgv)
130 m_background = renderer;
131 m_qgv = qgv;
135 void GenericItem::setElement(const QString &element)
137 m_element = element;
138 m_background->resize(350, 101);
141 QRectF GenericItem::boundingRect() const
143 if (m_element.isEmpty()) {
144 return QRectF(0, 0, 0, 0);
146 // kDebug() << QRectF(0, 0, m_background->elementSize(m_element).width(), m_background->elementSize(m_element).height()) << endl;
147 // return QRectF(0, 0, m_background->elementSize(m_element).width(), m_background->elementSize(m_element).height());
148 QRectF paintRect;
149 if (m_element == "top-left") {
150 paintRect = QRectF(0, 0, 9, 50);
151 } else if (m_element == "top") {
152 paintRect = QRectF(0, 0, 332, 50);
153 } else if (m_element == "top-right") {
154 paintRect = QRectF(0, 0, 9, 50);
155 } else if (m_element == "separator") {
156 paintRect = QRectF(0, 0, 348, 1);
157 } else if (m_element == "bottom-left") {
158 paintRect = QRectF(0, 0, 9, 50);
159 } else if (m_element == "bottom") {
160 paintRect = QRectF(0, 0, 332, 50);
161 } else if (m_element == "bottom-right") {
162 paintRect = QRectF(0, 0, 9, 50);
164 return paintRect;
167 void GenericItem::paint(QPainter *painter,
168 const QStyleOptionGraphicsItem *option,
169 QWidget *widget)
171 QRectF paintRect;
172 if (m_element == "top-left") {
173 paintRect = QRectF(0, 0, 9, 50);
174 } else if (m_element == "top") {
175 paintRect = QRectF(0, 0, 332, 50);
176 } else if (m_element == "top-right") {
177 paintRect = QRectF(0, 0, 9, 50);
178 } else if (m_element == "separator") {
179 paintRect = QRectF(0, 0, 348, 1);
180 } else if (m_element == "bottom-left") {
181 paintRect = QRectF(0, 0, 9, 50);
182 } else if (m_element == "bottom") {
183 paintRect = QRectF(0, 0, 332, 50);
184 } else if (m_element == "bottom-right") {
185 paintRect = QRectF(0, 0, 9, 50);
187 m_background->paint(painter, paintRect, m_element);
191 // MainItem::MainItem()
192 // {
193 // m_background = new Plasma::Svg( "dialogs/krunner", this );
194 // m_background->setContentType(Plasma::Svg::ImageSet);
195 // // connect( m_background, SIGNAL(repaintNeeded()), this, SLOT(update()) );
196 // m_background->resize(KRUNNER_SIZE);
197 // }
199 // void MainItem::paint(QPainter *painter,
200 // const QStyleOptionGraphicsItem *option,
201 // QWidget *widget)
202 // {
203 // // m_background->paint( painter, QRectF(0, 0, 9, 50), "top-left" );
204 // // m_background->paint( painter, QRectF(9, 0, 332, 50), "top" );
205 // // m_background->paint( painter, QRectF(341, 0, 9, 50), "top-right" );
206 // // m_background->paint( painter, QRectF(1, 50, 348, 1), "separator" );
207 // // m_background->paint( painter, QRectF(0, 51, 9, 50), "bottom-left" );
208 // // m_background->paint( painter, QRectF(9, 51, 332, 50), "bottom" );
209 // // m_background->paint( painter, QRectF(341, 51, 9, 50), "bottom-right" );
210 // // m_background->paint( painter, 0, 0 );
211 // }
213 void PushIcon::setIcon(const QString &icon)
215 m_icon = icon;
218 void PushIcon::paint(QPainter *painter,
219 const QStyleOptionGraphicsItem *option,
220 QWidget *widget)
222 KIcon exec(m_icon);
223 painter->drawPixmap(0, 0, exec.pixmap(22, 22));
224 // m_background->paint( painter, QRectF(0, 0, 9, 50), "top-left" );
225 // m_background->paint( painter, QRectF(9, 0, 332, 50), "top" );
226 // m_background->paint( painter, QRectF(341, 0, 9, 50), "top-right" );
227 // m_background->paint( painter, QRectF(1, 50, 348, 1), "separator" );
228 // m_background->paint( painter, QRectF(0, 51, 9, 50), "bottom-left" );
229 // m_background->paint( painter, QRectF(9, 51, 332, 50), "bottom" );
230 // m_background->paint( painter, QRectF(341, 51, 9, 50), "bottom-right" );
231 // m_background->paint( painter, 0, 0 );
234 Interface::Interface(QWidget* parent)
235 : QGraphicsView( parent ),
236 // m_expander( 0 ),
237 m_defaultMatch( 0 )
239 m_expanded = false;
240 m_background = new Plasma::Svg( "dialogs/krunner", this );
241 m_background->setContentType(Plasma::Svg::ImageSet);
242 m_background->resize(350, 101);
243 connect( m_background, SIGNAL(repaintNeeded()), this, SLOT(update()) );
245 setWindowTitle( i18n("Run Command") );
247 connect( &m_searchTimer, SIGNAL(timeout()),
248 this, SLOT(fuzzySearch()) );
250 GenericItem *item = new GenericItem(m_background, this);
251 item->setElement("top-left");
252 GenericItem *top = new GenericItem(m_background, this);
253 top->setElement("top");
254 GenericItem *topright = new GenericItem(m_background, this);
255 topright->setElement("top-right");
256 GenericItem *separator = new GenericItem(m_background, this);
257 separator->setElement("separator");
258 GenericItem *bottomleft = new GenericItem(m_background, this);
259 bottomleft->setElement("bottom-left");
260 GenericItem *bottom = new GenericItem(m_background, this);
261 bottom->setElement("bottom");
262 GenericItem *bottomright = new GenericItem(m_background, this);
263 bottomright->setElement("bottom-right");
265 // MainItem *item = new MainItem;
266 Plasma::LineEdit *lineEdit = new Plasma::LineEdit;
267 m_toggleExpand = new PushIcon(this);
268 m_toggleExpand->setIcon("arrow-down");
269 PushIcon *close = new PushIcon(this);
270 close->setIcon("no");
272 QGraphicsScene *scene = new QGraphicsScene(this);
273 scene->setItemIndexMethod(QGraphicsScene::NoIndex);
274 scene->setSceneRect(0, 0, KRUNNER_SIZE);
275 setScene(scene);
276 setCacheMode(CacheBackground);
277 setRenderHint(QPainter::Antialiasing);
279 scene->addItem(item);
280 scene->addItem(top);
281 scene->addItem(topright);
282 scene->addItem(separator);
283 scene->addItem(bottomleft);
284 scene->addItem(bottom);
285 scene->addItem(bottomright);
286 scene->addItem(lineEdit);
287 scene->addItem(m_toggleExpand);
288 scene->addItem(close);
290 item->setPos(0, 0);
291 top->setPos(9, 0);
292 topright->setPos(341, 0);
293 separator->setPos(1, 50);
294 bottomleft->setPos(0, 51);
295 bottom->setPos(9, 51);
296 bottomright->setPos(341, 51);
297 m_toggleExpand->setPos(30, 16);
298 lineEdit->setPos(75, 15);
299 lineEdit->setZValue(12);
300 lineEdit->setTextWidth(200);
301 lineEdit->setDefaultText("Type something here please..."); //FIXME: the label doesn't
302 // really behaves correctly (try to write some more text in).
303 close->setPos(305, 16);
305 connect(close, SIGNAL(clicked()), this, SLOT(close()));
306 connect(m_toggleExpand, SIGNAL(clicked()), this, SLOT(expand()));
308 resize(KRUNNER_SIZE);
310 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
311 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
312 setFrameShape(QFrame::NoFrame);
313 new QShortcut( QKeySequence( Qt::Key_Escape ), this, SLOT(hide()) );
317 void Interface::resizeEvent( QResizeEvent *e)
319 QGraphicsView::resizeEvent( e );
320 QBitmap bitmap(350, 101);
321 bitmap.fill(Qt::color0);
322 QPainter p(&bitmap);
323 m_background->resize(350, 101);
324 m_background->paint( &p, QRectF(0, 0, 9, 50), "top-left" );
325 m_background->paint( &p, QRectF(9, 0, 332, 50), "top" );
326 m_background->paint( &p, QRectF(341, 0, 9, 50), "top-right" );
327 m_background->paint( &p, QRectF(1, 50, 348, 1), "separator" );
329 if (m_expanded) {
330 m_background->paint( &p, QRectF(1, 51, 348, 49), "separator" );
331 m_background->paint( &p, QRectF(0, 101, 9, 50), "bottom-left" );
332 m_background->paint( &p, QRectF(9, 101, 332, 50), "bottom" );
333 m_background->paint( &p, QRectF(341, 101, 9, 50), "bottom-right" );
334 } else {
335 m_background->paint( &p, QRectF(0, 51, 9, 50), "bottom-left" );
336 m_background->paint( &p, QRectF(9, 51, 332, 50), "bottom" );
337 m_background->paint( &p, QRectF(341, 51, 9, 50), "bottom-right" );
339 p.end();
340 setMask(bitmap);
343 Interface::~Interface()
347 void Interface::expand()
349 disconnect(m_toggleExpand, SIGNAL(clicked()), this, SLOT(expand()));
350 connect(m_toggleExpand, SIGNAL(clicked()), this, SLOT(collapse()));
351 kDebug() << "expanding..." << endl;
352 m_expanded = true;
353 resize(350, 151);
354 m_toggleExpand->setIcon("arrow-up");
357 void Interface::collapse()
359 disconnect(m_toggleExpand, SIGNAL(clicked()), this, SLOT(collapse()));
360 connect(m_toggleExpand, SIGNAL(clicked()), this, SLOT(expand()));
361 kDebug() << "collapsing..." << endl;
362 m_expanded = false;
363 resize(350, 101);
364 m_toggleExpand->setIcon("arrow-down");
367 void Interface::display( const QString& term)
369 kDebug() << "display() called, are we visible? " << isVisible() << endl;
370 // m_searchTerm->setFocus();
372 if ( !term.isEmpty() ) {
373 // m_searchTerm->setText( term );
376 KWindowSystem::setOnDesktop( winId(), KWindowSystem::currentDesktop() );
377 KDialog::centerOnScreen( this );
378 show();
379 KWindowSystem::forceActiveWindow( winId() );
381 kDebug() << "about to match now that we've shown " << isVisible() << endl;
383 match( term );
386 void Interface::switchUser()
388 Plasma::AbstractRunner *sessionrunner = 0;
389 foreach (Plasma::AbstractRunner* runner, m_runners) {
390 if (qstrcmp(runner->metaObject()->className(), "SessionRunner") == 0) {
391 sessionrunner = runner;
392 break;
396 if (!sessionrunner) {
397 kDebug() << "Could not find the Sessionrunner; not showing any sessions!" << endl;
398 return;
401 display();
402 // m_header->setText(i18n("Switch users"));
403 // m_header->setPixmap("user");
404 KActionCollection *matches = sessionrunner->matches("SESSIONS", 0, 0);
406 foreach (QAction *action, matches->actions()) {
407 bool makeDefault = !m_defaultMatch && action->isEnabled();
409 // SearchMatch *match = new SearchMatch(action, sessionrunner, m_matchList);
410 // m_searchMatches.append(match);
412 if (makeDefault) {
413 // m_defaultMatch = match;
414 m_defaultMatch->setDefault(true);
415 // m_runButton->setEnabled(true);
416 // m_optionsButton->setEnabled(sessionrunner->hasOptions());
420 if (!m_defaultMatch) {
421 // m_matchList->addItem(i18n("No desktop sessions available"));
425 void Interface::setWidgetPalettes()
427 // a nice palette to use with the widgets
428 QPalette widgetPalette = palette();
429 QColor headerBgColor = widgetPalette.color( QPalette::Active,
430 QPalette::Base );
431 headerBgColor.setAlpha( 200 );
432 widgetPalette.setColor( QPalette::Base, headerBgColor );
434 // m_header->setPalette( widgetPalette );
435 // m_searchTerm->setPalette( widgetPalette );
436 // m_matchList->setPalette( widgetPalette );
439 void Interface::resetInterface()
441 // m_header->setText(i18n("Enter the name of an application, location or search term below."));
442 // m_header->setPixmap("system-search");
443 // m_searchTerm->clear();
444 m_matches.clear();
445 m_searchMatches.clear();
446 // m_matchList->clear();
447 // m_runButton->setEnabled( false );
448 // m_optionsButton->setEnabled( false );
449 showOptions( false );
452 void Interface::showEvent( QShowEvent* e )
454 Q_UNUSED( e )
456 kDebug() << "show event" << endl;
457 QGraphicsView::showEvent( e );
460 void Interface::hideEvent( QHideEvent* e )
462 kDebug() << "hide event" << endl;
463 resetInterface();
464 e->accept();
467 void Interface::matchActivated(QListWidgetItem* item)
469 SearchMatch* match = dynamic_cast<SearchMatch*>(item);
470 // m_optionsButton->setEnabled( match && match->runner()->hasOptions() );
472 if ( match && match->actionEnabled() ) {
473 //kDebug() << "match activated! " << match->text() << endl;
474 match->activate();
475 hide();
479 void Interface::match(const QString& t)
481 m_searchTimer.stop();
483 m_defaultMatch = 0;
484 QString term = t.trimmed();
486 if ( term.isEmpty() ) {
487 resetInterface();
488 return;
491 QMap<Plasma::AbstractRunner*, SearchMatch*> matches;
493 int matchCount = 0;
495 // get the exact matches
496 foreach ( Plasma::AbstractRunner* runner, m_runners ) {
497 //kDebug() << "\trunner: " << runner->objectName() << endl;
498 QAction* exactMatch = runner->exactMatch( term ) ;
500 if ( exactMatch ) {
501 SearchMatch* match = 0;
502 bool makeDefault = !m_defaultMatch && exactMatch->isEnabled();
504 QMap<Plasma::AbstractRunner*, SearchMatch*>::iterator it = m_matches.find( runner );
505 if ( it != m_matches.end() ) {
506 match = it.value();
507 match->setAction( exactMatch );
508 matches[runner] = match;
509 m_matches.erase( it );
510 } else {
511 match = new SearchMatch( exactMatch, runner, 0 );
512 // m_matchList->insertItem( matchCount, match );
515 if ( makeDefault ) {
516 match->setDefault( true );
517 m_defaultMatch = match;
518 // m_optionsButton->setEnabled( runner->hasOptions() );
519 // m_runButton->setEnabled( true );
522 ++matchCount;
523 matches[runner] = match;
527 if ( !m_defaultMatch ) {
528 showOptions( false );
529 // m_runButton->setEnabled( false );
532 qDeleteAll(m_matches);
533 m_matches = matches;
534 m_searchTimer.start( 200 );
537 void Interface::fuzzySearch()
539 m_searchTimer.stop();
541 // TODO: we may want to stop this from flickering about as well,
542 // similar to match above
543 foreach ( SearchMatch* match, m_searchMatches ) {
544 delete match;
547 m_searchMatches.clear();
549 // QString term = m_searchTerm->text().trimmed();
551 // get the inexact matches
552 // foreach ( Plasma::AbstractRunner* runner, m_runners ) {
553 // KActionCollection* matches = runner->matches( term, 10, 0 );
554 //kDebug() << "\t\tturned up " << matches->actions().count() << " matches " << endl;
555 // foreach ( QAction* action, matches->actions() ) {
556 // bool makeDefault = !m_defaultMatch && action->isEnabled();
557 //kDebug() << "\t\t " << action << ": " << action->text() << " " << !m_defaultMatch << " " << action->isEnabled() << endl;
558 // SearchMatch* match = new SearchMatch( action, runner, m_matchList );
559 // m_searchMatches.append( match );
561 // if ( makeDefault ) {
562 // m_defaultMatch = match;
563 // m_defaultMatch->setDefault( true );
564 // m_runButton->setEnabled( true );
565 // m_optionsButton->setEnabled( runner->hasOptions() );
566 // }
567 // }
568 // }
571 void Interface::updateMatches()
573 //TODO: implement
576 void Interface::exec()
578 // SearchMatch* match = dynamic_cast<SearchMatch*>( m_matchList->currentItem() );
580 // if ( match && match->actionEnabled() ) {
581 // matchActivated( match );
582 // } else if ( m_defaultMatch ) {
583 // matchActivated( m_defaultMatch );
584 // }
587 void Interface::showOptions(bool show)
589 //TODO: in the case where we are no longer showing options
590 // should we have the runner delete it's options?
591 if ( show ) {
592 if ( !m_defaultMatch || !m_defaultMatch->runner()->hasOptions() ) {
593 // in this case, there is nothing to show
594 return;
597 // if ( !m_expander ) {
598 //kDebug() << "creating m_expander" << endl;
599 // m_expander = new CollapsibleWidget( this );
600 // connect( m_expander, SIGNAL( collapseCompleted() ),
601 // m_expander, SLOT( hide() ) );
602 // m_layout->insertWidget( 3, m_expander );
603 // }
605 //kDebug() << "set inner widget to " << m_defaultMatch->runner()->options() << endl;
606 // m_expander->setInnerWidget( m_defaultMatch->runner()->options() );
607 // m_expander->show();
608 // m_optionsButton->setText( i18n( "Hide Options" ) );
609 } else {
610 // m_optionsButton->setText( i18n( "Show Options" ) );
611 // resize( 400, 250 );
612 resize(KRUNNER_SIZE);
615 // if ( m_expander ) {
616 //TODO: we need to insert an element into the krunner dialog
617 // that is big enough for the options. this will prevent
618 // other items in the dialog from moving around and look
619 // more "natural"; it should appear as if a "drawer" is
620 // being pulled open, e.g. an expander.
621 // m_expander->setExpanded( show );
622 // }
623 // m_optionsButton->setChecked( show );
626 void Interface::setDefaultItem( QListWidgetItem* item )
628 if ( !item ) {
629 return;
632 if ( m_defaultMatch ) {
633 m_defaultMatch->setDefault( false );
636 m_defaultMatch = dynamic_cast<SearchMatch*>( item );
638 bool hasOptions = m_defaultMatch && m_defaultMatch->runner()->hasOptions();
639 // m_optionsButton->setEnabled( hasOptions );
641 // if ( m_expander && !hasOptions ) {
642 // m_expander->hide();
643 // }
646 #include "interface.moc"