not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / applets / kickoff / ui / launcher.cpp
blob83ff18af656194ab10b5386ea93fff9d926ba7c8
1 /*
2 Copyright 2007 Robert Knight <robertknight@gmail.com>
3 Copyright 2007 Kevin Ottens <ervin@kde.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library 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 GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "ui/launcher.h"
23 // System
24 #include <unistd.h>
26 // Qt
27 #include <QApplication>
28 #include <QKeyEvent>
29 #include <QLabel>
30 #include <QMouseEvent>
31 #include <QPainter>
32 #include <QStackedWidget>
33 #include <QTabBar>
34 #include <QToolButton>
35 #include <QVBoxLayout>
36 #include <QStyleOptionSizeGrip>
38 // KDE
39 #include <KDebug>
40 #include <KLocalizedString>
41 #include <KIcon>
42 #include <KStandardDirs>
43 #include <kuser.h>
44 #include <Plasma/Theme>
45 #include <Plasma/Delegate>
46 #include <solid/device.h>
47 #include <solid/deviceinterface.h>
48 #include <KColorScheme>
50 // Local
51 #include "core/favoritesmodel.h"
52 #include "core/recentlyusedmodel.h"
53 #include "core/applicationmodel.h"
54 #include "core/leavemodel.h"
55 #include "core/itemhandlers.h"
56 #include "core/searchmodel.h"
57 #include "core/systemmodel.h"
59 #include "ui/itemdelegate.h"
60 #include "ui/brandingbutton.h"
61 #include "ui/contextmenufactory.h"
62 #include "ui/urlitemview.h"
63 #include "ui/flipscrollview.h"
64 #include "ui/searchbar.h"
65 #include "ui/tabbar.h"
66 #include "ui/contentareacap.h"
68 using namespace Kickoff;
70 class Launcher::Private
72 public:
73 Private(Launcher *launcher)
74 : q(launcher)
75 , applet(0)
76 , urlLauncher(new UrlItemLauncher(launcher))
77 , searchModel(0)
78 , leaveModel(0)
79 , searchBar(0)
80 , footer(0)
81 , contentAreaHeader(0)
82 , contentArea(0)
83 , contentAreaFooter(0)
84 , contentSwitcher(0)
85 , searchView(0)
86 , favoritesView(0)
87 , contextMenuFactory(0)
88 , autoHide(false)
89 , visibleItemCount(10)
90 , placement(Plasma::TopPosedLeftAlignedPopup)
91 , panelEdge(Plasma::BottomEdge) {
94 ~Private() {
97 enum TabOrder { NormalTabOrder, ReverseTabOrder };
99 void setupEventHandler(QAbstractItemView *view) {
100 view->viewport()->installEventFilter(q);
101 view->installEventFilter(q);
104 void addView(const QString& name, const QIcon& icon,
105 QAbstractItemModel *model = 0, QAbstractItemView *view = 0) {
106 view->setFrameStyle(QFrame::NoFrame);
107 // prevent the view from stealing focus from the search bar
108 view->setFocusPolicy(Qt::NoFocus);
109 view->setContextMenuPolicy(Qt::CustomContextMenu);
110 view->setSelectionMode(QAbstractItemView::SingleSelection);
111 view->setDragEnabled(true);
112 view->setAcceptDrops(true);
113 view->setDropIndicatorShown(true);
114 if (name == "Favorites") {
115 view->setDragDropMode(QAbstractItemView::DragDrop);
116 } else if(name == "Applications" || name == "Computer" ||
117 name == "Recently Used") {
118 view->setDragDropMode(QAbstractItemView::DragOnly);
120 view->setModel(model);
121 //view->setCurrentIndex(QModelIndex());
122 setupEventHandler(view);
124 connect(view, SIGNAL(customContextMenuRequested(QPoint)), q, SLOT(showViewContextMenu(QPoint)));
126 contentSwitcher->addTab(icon, name);
127 contentArea->addWidget(view);
130 void initTabs() {
131 // Favorites view
132 setupFavoritesView();
134 // All Programs view
135 setupAllProgramsView();
137 // System view
138 setupSystemView();
140 // Recently Used view
141 setupRecentView();
143 // Leave view
144 setupLeaveView();
146 // Search Bar
147 setupSearchView();
150 void setupLeaveView() {
151 leaveModel = new LeaveModel(q);
152 leaveModel->updateModel();
153 UrlItemView *view = new UrlItemView();
154 ItemDelegate *delegate = new ItemDelegate(q);
155 delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
156 delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
157 view->setItemDelegate(delegate);
158 view->setItemStateProvider(delegate);
159 addView(i18n("Leave"), KIcon("system-shutdown"), leaveModel, view);
162 void setupFavoritesView() {
163 FavoritesModel *model = new FavoritesModel(q);
164 UrlItemView *view = new UrlItemView();
165 ItemDelegate *delegate = new ItemDelegate(q);
166 delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
167 delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
168 view->setItemDelegate(delegate);
169 view->setItemStateProvider(delegate);
170 addView(i18n("Favorites"), KIcon("bookmarks"), model, view);
172 QAction *sortAscendingAction = new QAction(KIcon("view-sort-ascending"),
173 i18n("Sort Alphabetically (A to Z)"), q);
175 QAction *sortDescendingAction = new QAction(KIcon("view-sort-descending"),
176 i18n("Sort Alphabetically (Z to A)"), q);
179 connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), q, SLOT(focusFavoritesView()));
180 connect(sortAscendingAction, SIGNAL(triggered()), model, SLOT(sortFavoritesAscending()));
181 connect(sortDescendingAction, SIGNAL(triggered()), model, SLOT(sortFavoritesDescending()));
183 favoritesView = view;
184 QList<QAction*> actions;
185 actions << sortAscendingAction << sortDescendingAction;
186 contextMenuFactory->setViewActions(view, actions);
189 void setupAllProgramsView() {
190 ApplicationModel *applicationModel = new ApplicationModel(q);
191 applicationModel->setDuplicatePolicy(ApplicationModel::ShowLatestOnlyPolicy);
193 applicationView = new FlipScrollView();
194 ItemDelegate *delegate = new ItemDelegate(q);
195 delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
196 delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
197 applicationView->setItemDelegate(delegate);
199 addView(i18n("Applications"), KIcon("applications-other"),
200 applicationModel, applicationView);
203 void setupRecentView() {
204 RecentlyUsedModel *model = new RecentlyUsedModel(q);
205 UrlItemView *view = new UrlItemView();
206 ItemDelegate *delegate = new ItemDelegate(q);
207 delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
208 delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
209 view->setItemDelegate(delegate);
210 view->setItemStateProvider(delegate);
211 addView(i18n("Recently Used"), KIcon("document-open-recent"), model, view);
213 QAction *clearApplications = new QAction(KIcon("edit-clear-history"), i18n("Clear Recent Applications"), q);
214 QAction *clearDocuments = new QAction(KIcon("edit-clear-history"), i18n("Clear Recent Documents"), q);
216 connect(clearApplications, SIGNAL(triggered()), model, SLOT(clearRecentApplications()));
217 connect(clearDocuments, SIGNAL(triggered()), model, SLOT(clearRecentDocuments()));
219 contextMenuFactory->setViewActions(view, QList<QAction*>() << clearApplications << clearDocuments);
222 void setupSystemView() {
223 SystemModel *model = new SystemModel(q);
224 UrlItemView *view = new UrlItemView();
225 ItemDelegate *delegate = new ItemDelegate(q);
226 delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
227 delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
228 view->setItemDelegate(delegate);
229 view->setItemStateProvider(delegate);
231 addView(i18n("Computer"), systemIcon(), model, view);
234 void setupSearchView() {
235 searchModel = new SearchModel(q);
236 UrlItemView *view = new UrlItemView();
237 ItemDelegate *delegate = new ItemDelegate(q);
238 delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
239 delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
240 view->setItemDelegate(delegate);
241 view->setItemStateProvider(delegate);
242 view->setModel(searchModel);
243 view->setFrameStyle(QFrame::NoFrame);
244 // prevent view from stealing focus from the search bar
245 view->setFocusPolicy(Qt::NoFocus);
246 view->setDragEnabled(true);
247 setupEventHandler(view);
249 connect(searchModel, SIGNAL(resultsAvailable()), q, SLOT(resultsAvailable()));
251 connect(searchBar, SIGNAL(queryChanged(QString)), searchModel, SLOT(setQuery(QString)));
252 connect(searchBar, SIGNAL(queryChanged(QString)), q, SLOT(focusSearchView(QString)));
254 view->setContextMenuPolicy(Qt::CustomContextMenu);
255 connect(view, SIGNAL(customContextMenuRequested(QPoint)), q, SLOT(showViewContextMenu(QPoint)));
257 contentArea->addWidget(view);
258 searchView = view;
261 void registerUrlHandlers() {
262 UrlItemLauncher::addGlobalHandler(UrlItemLauncher::ExtensionHandler, "desktop", new ServiceItemHandler);
263 UrlItemLauncher::addGlobalHandler(UrlItemLauncher::ProtocolHandler, "leave", new LeaveItemHandler);
266 QIcon systemIcon() {
267 QList<Solid::Device> batteryList = Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString());
269 if (batteryList.isEmpty()) {
270 return KIcon("computer");
271 } else {
272 return KIcon("computer-laptop");
276 void setNorthLayout(TabOrder tabOrder) {
277 contentSwitcher->setShape(QTabBar::RoundedNorth);
278 QLayout * layout = q->layout();
279 delete layout;
280 layout = new QVBoxLayout();
281 layout->addWidget(contentSwitcher);
282 layout->addWidget(contentAreaHeader);
283 layout->addWidget(contentArea);
284 layout->addWidget(contentAreaFooter);
285 layout->addWidget(searchBar);
286 layout->addWidget(footer);
287 layout->setSpacing(0);
288 layout->setMargin(0);
289 q->setLayout(layout);
290 setTabOrder(tabOrder);
293 void setSouthLayout(TabOrder tabOrder) {
294 contentSwitcher->setShape(QTabBar::RoundedSouth);
295 QLayout * layout = q->layout();
296 delete layout;
297 layout = new QVBoxLayout();
298 layout->addWidget(footer);
299 layout->addWidget(searchBar);
300 layout->addWidget(contentAreaHeader);
301 layout->addWidget(contentArea);
302 layout->addWidget(contentAreaFooter);
303 layout->addWidget(contentSwitcher);
304 layout->setSpacing(0);
305 layout->setMargin(0);
306 q->setLayout(layout);
307 setTabOrder(tabOrder);
310 void setWestLayout(TabOrder tabOrder) {
311 contentSwitcher->setShape(QTabBar::RoundedWest);
312 QLayout * layout = q->layout();
313 delete layout;
314 layout = new QHBoxLayout();
315 layout->addWidget(contentSwitcher);
316 layout->addWidget(contentArea);
317 QBoxLayout * layout2 = new QVBoxLayout();
318 if (tabOrder == NormalTabOrder) {
319 layout2->addLayout(layout);
320 layout2->addWidget(searchBar);
321 layout2->addWidget(footer);
322 } else {
323 layout2->addWidget(footer);
324 layout2->addWidget(searchBar);
325 layout2->addLayout(layout);
327 layout->setSpacing(0);
328 layout->setMargin(0);
329 layout2->setSpacing(0);
330 layout2->setMargin(0);
331 q->setLayout(layout2);
332 setTabOrder(tabOrder);
335 void setEastLayout(TabOrder tabOrder) {
336 contentSwitcher->setShape(QTabBar::RoundedEast);
337 QLayout * layout = q->layout();
338 delete layout;
339 layout = new QHBoxLayout();
340 layout->addWidget(contentArea);
341 layout->addWidget(contentSwitcher);
342 QBoxLayout * layout2 = new QVBoxLayout();
343 if (tabOrder == NormalTabOrder) {
344 layout2->addLayout(layout);
345 layout2->addWidget(searchBar);
346 layout2->addWidget(footer);
347 } else {
348 layout2->addWidget(footer);
349 layout2->addWidget(searchBar);
350 layout2->addLayout(layout);
352 layout->setSpacing(0);
353 layout->setMargin(0);
354 layout2->setSpacing(0);
355 layout2->setMargin(0);
356 q->setLayout(layout2);
357 setTabOrder(tabOrder);
360 void setTabOrder(TabOrder newOrder) {
361 // identify current TabOrder, assumes favoritesView is first in normal order
362 TabOrder oldOrder;
363 if (contentArea->widget(0) == favoritesView) {
364 oldOrder = NormalTabOrder;
365 } else {
366 oldOrder = ReverseTabOrder;
368 if (newOrder == oldOrder) {
369 return;
371 // remove the and widgets and store their data in a separate structure
372 // remove this first so we can cleanly remove the widgets controlled by contentSwitcher
373 contentArea->removeWidget(searchView);
374 Q_ASSERT(contentArea->count() == contentSwitcher->count());
376 QList<WidgetTabData> removedTabs;
377 for (int i = contentSwitcher->count() - 1; i >= 0 ; i--) {
378 WidgetTabData wtd;
379 wtd.tabText = contentSwitcher->tabText(i);
380 wtd.tabToolTip = contentSwitcher->tabToolTip(i);
381 wtd.tabWhatsThis = contentSwitcher->tabWhatsThis(i);
382 wtd.tabIcon = contentSwitcher->tabIcon(i);
383 wtd.widget = contentArea->widget(i);
384 removedTabs.append(wtd);
386 contentSwitcher->removeTab(i);
387 contentArea->removeWidget(contentArea->widget(i));
389 // then reinsert them in reversed order
390 int i = 0;
391 foreach(const WidgetTabData &wtd, removedTabs) {
392 contentSwitcher->addTab(wtd.tabIcon, wtd.tabText);
393 contentSwitcher->setTabToolTip(i, wtd.tabToolTip);
394 contentSwitcher->setTabWhatsThis(i, wtd.tabWhatsThis);
395 contentArea->addWidget(wtd.widget);
396 ++i;
398 //finally replace the searchView
399 contentArea->addWidget(searchView);
402 struct WidgetTabData {
403 QString tabText;
404 QString tabToolTip;
405 QString tabWhatsThis;
406 QIcon tabIcon;
407 QWidget * widget;
410 Launcher * const q;
411 Plasma::Applet *applet;
412 UrlItemLauncher *urlLauncher;
413 SearchModel *searchModel;
414 LeaveModel *leaveModel;
415 SearchBar *searchBar;
416 QWidget *footer;
417 QLabel *userinfo;
418 ContentAreaCap *contentAreaHeader;
419 QStackedWidget *contentArea;
420 ContentAreaCap *contentAreaFooter;
421 TabBar *contentSwitcher;
422 FlipScrollView *applicationView;
423 QAbstractItemView *searchView;
424 QAbstractItemView *favoritesView;
425 ContextMenuFactory *contextMenuFactory;
426 bool autoHide;
427 int visibleItemCount;
428 Plasma::PopupPlacement placement;
429 Plasma::Location panelEdge;
432 Launcher::Launcher(QWidget *parent)
433 : QWidget(parent, Qt::Window)
434 , d(new Private(this))
436 init();
439 Launcher::Launcher(Plasma::Applet *applet)
440 : QWidget(0, Qt::Window)
441 , d(new Private(this))
443 init();
444 setApplet(applet);
447 void Launcher::init()
449 QVBoxLayout *layout = new QVBoxLayout;
450 layout->setSpacing(0);
451 layout->setMargin(0);
453 const int rightHeaderMargin = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
455 d->searchBar = new SearchBar(this);
456 if (layoutDirection() == Qt::LeftToRight) {
457 d->searchBar->setContentsMargins(0, 0, rightHeaderMargin, 0);
458 } else {
459 d->searchBar->setContentsMargins(rightHeaderMargin, 0, 0, 0);
461 d->searchBar->installEventFilter(this);
462 d->contentAreaHeader = new ContentAreaCap(this);
463 d->contentArea = new QStackedWidget(this);
464 bool flipCap = true;
465 d->contentAreaFooter = new ContentAreaCap(this, flipCap);
466 d->contentSwitcher = new TabBar(this);
467 d->contentSwitcher->installEventFilter(this);
468 d->contentSwitcher->setIconSize(QSize(48, 48));
469 d->contentSwitcher->setShape(QTabBar::RoundedSouth);
470 connect(d->contentSwitcher, SIGNAL(currentChanged(int)),
471 d->contentArea, SLOT(setCurrentIndex(int)));
472 d->contextMenuFactory = new ContextMenuFactory(this);
474 d->initTabs();
475 d->registerUrlHandlers();
477 // Add status information footer
478 d->footer = new QWidget;
480 char hostname[256];
481 hostname[0] = '\0';
482 if (!gethostname(hostname, sizeof(hostname))) {
483 hostname[sizeof(hostname)-1] = '\0';
485 KUser user;
486 QString fullName = user.property(KUser::FullName).toString();
487 QString labelText;
488 if (fullName.isEmpty()) {
489 labelText = i18nc("login name, hostname", "User <b>%1</b> on <b>%2</b>", user.loginName(), hostname);
490 } else {
491 labelText = i18nc("full name, login name, hostname", "<b>%1 (%2)</b> on <b>%3</b>", fullName, user.loginName(), hostname);
494 d->userinfo = new QLabel(labelText);
496 QToolButton *branding = new BrandingButton(this);
497 branding->setAutoRaise(false);
498 branding->setToolButtonStyle(Qt::ToolButtonIconOnly);
499 connect(branding, SIGNAL(clicked()), this, SIGNAL(aboutToHide()));
501 QHBoxLayout *brandingLayout = new QHBoxLayout;
502 brandingLayout->setMargin(3);
503 brandingLayout->addSpacing(ItemDelegate::ITEM_LEFT_MARGIN - 3);
504 brandingLayout->addWidget(d->userinfo);
505 brandingLayout->addStretch(2);
506 brandingLayout->addWidget(branding);
507 brandingLayout->addSpacing(rightHeaderMargin);
508 d->footer->setLayout(brandingLayout);
510 layout->addWidget(d->footer);
511 layout->addWidget(d->searchBar);
512 layout->addWidget(d->contentAreaHeader);
513 layout->addWidget(d->contentArea);
514 layout->addWidget(d->contentAreaFooter);
515 layout->addWidget(d->contentSwitcher);
517 setLayout(layout);
518 //setBackgroundRole(QPalette::AlternateBase);
519 //setAutoFillBackground(true);
521 updateThemedPalette();
522 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
523 this, SLOT(updateThemedPalette()));
526 void Launcher::updateThemedPalette()
528 QColor color = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
529 QPalette p = d->userinfo->palette();
530 p.setColor(QPalette::Normal, QPalette::WindowText, color);
531 p.setColor(QPalette::Inactive, QPalette::WindowText, color);
532 d->userinfo->setPalette(p);
535 QSize Launcher::minimumSizeHint() const
537 QSize size;
539 switch (d->panelEdge) {
540 case Plasma::LeftEdge:
541 case Plasma::RightEdge:
542 size.rheight() = d->searchBar->sizeHint().height() +
543 d->footer->sizeHint().height() +
544 qMax(d->favoritesView->sizeHintForRow(0) * 3 + ItemDelegate::HEADER_HEIGHT, d->contentSwitcher->sizeHint().height());
545 size.rwidth() = d->contentSwitcher->sizeHint().width() + d->favoritesView->sizeHint().width();
546 break;
547 case Plasma::TopEdge:
548 case Plasma::BottomEdge:
549 default:
550 size.rheight() = d->searchBar->sizeHint().height() +
551 d->contentSwitcher->sizeHint().height() + d->footer->sizeHint().height() +
552 d->favoritesView->sizeHintForRow(0) * 3 + ItemDelegate::HEADER_HEIGHT;
553 size.rwidth() = d->contentSwitcher->sizeHint().width();
554 break;
557 return size;
560 QSize Launcher::sizeHint() const
562 return QSize(minimumSizeHint().width(), 500);
565 void Launcher::setAutoHide(bool hide)
567 d->autoHide = hide;
570 bool Launcher::autoHide() const
572 return d->autoHide;
575 void Launcher::setSwitchTabsOnHover(bool switchOnHover)
577 d->contentSwitcher->setSwitchTabsOnHover(switchOnHover);
580 bool Launcher::switchTabsOnHover() const
582 return d->contentSwitcher->switchTabsOnHover();
585 void Launcher::setVisibleItemCount(int count)
587 d->visibleItemCount = count;
590 int Launcher::visibleItemCount() const
592 return d->visibleItemCount;
595 void Launcher::setApplet(Plasma::Applet *applet)
597 d->applet = applet;
598 d->contextMenuFactory->setApplet(applet);
600 KConfigGroup cg = applet->globalConfig();
601 setSwitchTabsOnHover(cg.readEntry("SwitchTabsOnHover", switchTabsOnHover()));
603 cg = applet->config();
604 setVisibleItemCount(cg.readEntry("VisibleItemsCount", visibleItemCount()));
607 void Launcher::reset()
609 d->contentSwitcher->setCurrentIndexWithoutAnimation(d->contentArea->indexOf(d->favoritesView));
610 d->contentArea->setCurrentWidget(d->favoritesView);
611 d->searchBar->clear();
612 d->applicationView->viewRoot();
613 d->leaveModel->updateModel();
616 Launcher::~Launcher()
618 delete d;
621 void Launcher::focusSearchView(const QString& query)
623 bool queryEmpty = query.isEmpty();
625 d->contentSwitcher->setVisible(queryEmpty);
627 if (!queryEmpty) {
628 d->contentArea->setCurrentWidget(d->searchView);
629 } else {
630 focusFavoritesView();
634 void Launcher::focusFavoritesView()
636 d->contentSwitcher->setCurrentIndex(d->contentArea->indexOf(d->favoritesView));
637 d->contentArea->setCurrentWidget(d->favoritesView);
640 bool Launcher::eventFilter(QObject *object, QEvent *event)
642 // deliver unhandled key presses from the search bar
643 // (mainly arrow keys, enter) to the active view
644 if ((object == d->contentSwitcher || object == d->searchBar) && event->type() == QEvent::KeyPress) {
645 // we want left/right to still nav the tabbar
646 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
647 if (keyEvent->modifiers() == Qt::NoModifier &&
648 (keyEvent->key() == Qt::Key_Left ||
649 keyEvent->key() == Qt::Key_Right)) {
650 if (object == d->contentSwitcher) {
651 return false;
652 } else {
653 QCoreApplication::sendEvent(d->contentSwitcher, event);
654 return true;
658 QAbstractItemView *activeView = qobject_cast<QAbstractItemView*>(d->contentArea->currentWidget());
659 if (activeView) {
660 QCoreApplication::sendEvent(activeView, event);
661 return true;
666 // the mouse events we are interested in are delivered to the viewport,
667 // other events are delivered to the view itself.
668 QAbstractItemView *view = qobject_cast<QAbstractItemView*>(object);
669 if (!view) {
670 view = qobject_cast<QAbstractItemView*>(object->parent());
673 if (view) {
674 QModelIndex openIndex;
675 if (event->type() == QEvent::MouseButtonRelease) {
676 QMouseEvent *mouseEvent = (QMouseEvent*)event;
677 const QModelIndex index = view->indexAt(mouseEvent->pos());
678 if (index.isValid() &&
679 index.model()->hasChildren(index) == false &&
680 mouseEvent->button() == Qt::LeftButton) {
681 openIndex = index;
683 } else if (event->type() == QEvent::KeyPress) {
684 QKeyEvent *keyEvent = (QKeyEvent*)event;
685 const QModelIndex index = view->currentIndex();
686 if (index.isValid() && index.model()->hasChildren(index) == false &&
687 (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)) {
688 openIndex = index;
691 if (openIndex.isValid()) {
692 d->urlLauncher->openItem(openIndex);
693 // Clear the search bar when enter was pressed
694 if (event->type() == QEvent::KeyPress) {
695 d->searchBar->clear();
697 if (d->autoHide) {
698 emit aboutToHide();
700 return true;
703 return QWidget::eventFilter(object, event);
706 void Launcher::showViewContextMenu(const QPoint& pos)
708 QAbstractItemView *view = qobject_cast<QAbstractItemView*>(sender());
709 if (view) {
710 d->contextMenuFactory->showContextMenu(view, pos);
714 void Launcher::hideEvent(QHideEvent *event)
716 Q_UNUSED(event)
717 reset();
720 void Launcher::keyPressEvent(QKeyEvent *event)
722 if (event->key() == Qt::Key_Escape) {
723 emit aboutToHide();
725 #if 0
726 // allow tab switching by pressing the left or right arrow keys
727 if (event->key() == Qt::Key_Left && d->contentSwitcher->currentIndex() > 0) {
728 d->contentSwitcher->setCurrentIndex(d->contentSwitcher->currentIndex() - 1);
729 } else if (event->key() == Qt::Key_Right &&
730 d->contentSwitcher->currentIndex() < d->contentSwitcher->count() - 1) {
731 d->contentSwitcher->setCurrentIndex(d->contentSwitcher->currentIndex() + 1);
733 #endif
736 void Launcher::showEvent(QShowEvent *e)
738 d->searchBar->setFocus();
740 QWidget::showEvent(e);
743 void Launcher::resultsAvailable()
745 const QModelIndex root = d->searchModel->index(0, 0);
746 d->searchView->setCurrentIndex(d->searchModel->index(0, 0, root));
749 void Launcher::setLauncherOrigin(const Plasma::PopupPlacement placement, Plasma::Location location)
751 if (d->placement != placement) {
752 d->placement = placement;
754 switch (placement) {
755 case Plasma::TopPosedRightAlignedPopup:
756 d->setSouthLayout(Private::ReverseTabOrder);
757 break;
758 case Plasma::LeftPosedTopAlignedPopup:
759 d->setEastLayout(Private::NormalTabOrder);
760 break;
761 case Plasma::LeftPosedBottomAlignedPopup:
762 d->setEastLayout(Private::ReverseTabOrder);
763 break;
764 case Plasma::BottomPosedLeftAlignedPopup:
765 d->setNorthLayout(Private::NormalTabOrder);
766 break;
767 case Plasma::BottomPosedRightAlignedPopup:
768 d->setNorthLayout(Private::ReverseTabOrder);
769 break;
770 case Plasma::RightPosedTopAlignedPopup:
771 d->setWestLayout(Private::NormalTabOrder);
772 break;
773 case Plasma::RightPosedBottomAlignedPopup:
774 d->setWestLayout(Private::ReverseTabOrder);
775 break;
776 case Plasma::TopPosedLeftAlignedPopup:
777 default:
778 d->setSouthLayout(Private::NormalTabOrder);
779 break;
782 d->panelEdge = location;
785 #include "launcher.moc"