• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Applets

launcher.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007 Robert Knight <robertknight@gmail.com>
00003     Copyright 2007 Kevin Ottens <ervin@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "ui/launcher.h"
00022 
00023 // System
00024 #include <unistd.h>
00025 
00026 // Qt
00027 #include <QApplication>
00028 #include <QDesktopWidget>
00029 #include <QKeyEvent>
00030 #include <QLabel>
00031 #include <QMouseEvent>
00032 #include <QPainter>
00033 #include <QStackedWidget>
00034 #include <QTabBar>
00035 #include <QToolButton>
00036 #include <QVBoxLayout>
00037 #include <QStyleOptionSizeGrip>
00038 
00039 // KDE
00040 #include <KDebug>
00041 #include <KLocalizedString>
00042 #include <KIcon>
00043 #include <KStandardDirs>
00044 #include <ktoolinvocation.h>
00045 #include <kuser.h>
00046 #include <plasma/theme.h>
00047 #include <plasma/delegate.h>
00048 #include <solid/device.h>
00049 #include <solid/deviceinterface.h>
00050 #include <KColorScheme>
00051 
00052 // Local
00053 #include "core/favoritesmodel.h"
00054 #include "core/recentlyusedmodel.h"
00055 #include "core/applicationmodel.h"
00056 #include "core/leavemodel.h"
00057 #include "core/itemhandlers.h"
00058 #include "core/searchmodel.h"
00059 #include "core/systemmodel.h"
00060 
00061 #include "ui/itemdelegate.h"
00062 #include "ui/brandingbutton.h"
00063 #include "ui/contextmenufactory.h"
00064 #include "ui/urlitemview.h"
00065 #include "ui/flipscrollview.h"
00066 #include "ui/searchbar.h"
00067 #include "ui/tabbar.h"
00068 
00069 using namespace Kickoff;
00070 
00071 class Launcher::Private
00072 {
00073 public:
00074     class ResizeHandle;
00075     enum CompassDirection { North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest };
00076 
00077     Private(Launcher *launcher)
00078         : q(launcher)
00079         , applet(0)
00080         , urlLauncher(new UrlItemLauncher(launcher))
00081         , resizeHandle(0)
00082         , searchModel(0)
00083         , searchBar(0)
00084         , footer(0)
00085         , contentArea(0)
00086         , contentSwitcher(0)
00087         , searchView(0)
00088         , favoritesView(0)
00089         , contextMenuFactory(0)
00090         , autoHide(false)
00091         , visibleItemCount(10)
00092         , launcherOrigin(QPoint(-1, -1))
00093         , isResizing(false)
00094         , resizePlacement( NorthEast )
00095         , panelEdge( Plasma::LeftEdge )
00096     {
00097     }
00098     ~Private()
00099     {
00100     }
00101 
00102     enum TabOrder { NormalTabOrder, ReverseTabOrder };
00103 
00104     void setupEventHandler(QAbstractItemView *view)
00105     {
00106         view->viewport()->installEventFilter(q);
00107         view->installEventFilter(q);
00108     }
00109 
00110     void addView(const QString& name, const QIcon& icon,
00111                  QAbstractItemModel *model = 0, QAbstractItemView *view = 0)
00112     {
00113         view->setFrameStyle(QFrame::NoFrame);
00114         // prevent the view from stealing focus from the search bar
00115         view->setFocusPolicy(Qt::NoFocus);
00116         view->setContextMenuPolicy(Qt::CustomContextMenu);
00117         view->setSelectionMode(QAbstractItemView::SingleSelection);
00118         view->setDragEnabled(true);
00119         view->setAcceptDrops(true);
00120         view->setDropIndicatorShown(true);
00121         view->setDragDropMode(QAbstractItemView::InternalMove);
00122         view->setModel(model);
00123         //view->setCurrentIndex(QModelIndex());
00124         setupEventHandler(view);
00125 
00126         connect(view, SIGNAL(customContextMenuRequested(QPoint)), q, SLOT(showViewContextMenu(QPoint)));
00127 
00128         contentSwitcher->addTab(icon, name);
00129         contentArea->addWidget(view);
00130     }
00131 
00132     void initTabs()
00133     {
00134         // Favorites view
00135         setupFavoritesView();
00136 
00137         // All Programs view
00138         setupAllProgramsView();
00139 
00140         // System view
00141         setupSystemView();
00142 
00143         // Recently Used view
00144         setupRecentView();
00145 
00146         // Leave view
00147         setupLeaveView();
00148 
00149         // Search Bar
00150         setupSearchView();
00151     }
00152 
00153     void setupLeaveView()
00154     {
00155         LeaveModel *model = new LeaveModel(q);
00156         UrlItemView *view = new UrlItemView;
00157         ItemDelegate *delegate = new ItemDelegate(q);
00158         delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
00159         delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00160         view->setItemDelegate(delegate);
00161         view->setItemStateProvider(delegate);
00162         addView(i18n("Leave"), KIcon("system-shutdown"), model, view);
00163     }
00164 
00165     void setupFavoritesView()
00166     {
00167         FavoritesModel *model = new FavoritesModel(q);
00168         UrlItemView *view = new UrlItemView;
00169         ItemDelegate *delegate = new ItemDelegate(q);
00170         delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
00171         delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00172         view->setItemDelegate(delegate);
00173         view->setItemStateProvider(delegate);
00174         addView(i18n("Favorites"), KIcon("bookmarks"), model, view);
00175 
00176         connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), q, SLOT(focusFavoritesView()));
00177 
00178         favoritesView = view;
00179     }
00180 
00181     void setupAllProgramsView()
00182     {
00183         ApplicationModel *applicationModel = new ApplicationModel(q);
00184         applicationModel->setDuplicatePolicy(ApplicationModel::ShowLatestOnlyPolicy);
00185 
00186         applicationView = new FlipScrollView();
00187         ItemDelegate *delegate = new ItemDelegate(q);
00188         delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
00189         delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00190         applicationView->setItemDelegate(delegate);
00191 
00192         addView(i18n("Applications"), KIcon("applications-other"),
00193                     applicationModel, applicationView);
00194     }
00195 
00196     void setupRecentView()
00197     {
00198         RecentlyUsedModel *model = new RecentlyUsedModel(q);
00199         UrlItemView *view = new UrlItemView;
00200         ItemDelegate *delegate = new ItemDelegate(q);
00201         delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
00202         delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00203         view->setItemDelegate(delegate);
00204         view->setItemStateProvider(delegate);
00205         addView(i18n("Recently Used"), KIcon("document-open-recent"), model, view);
00206 
00207         QAction *clearApplications = new QAction(KIcon("edit-clear-history"), i18n("Clear Recent Applications"), q);
00208         QAction *clearDocuments = new QAction(KIcon("edit-clear-history"), i18n("Clear Recent Documents"), q);
00209 
00210         connect(clearApplications, SIGNAL(triggered()), model, SLOT(clearRecentApplications()));
00211         connect(clearDocuments, SIGNAL(triggered()), model, SLOT(clearRecentDocuments()));
00212 
00213         contextMenuFactory->setViewActions(view, QList<QAction*>() << clearApplications << clearDocuments);
00214     }
00215 
00216     void setupSystemView()
00217     {
00218         SystemModel *model = new SystemModel(q);
00219         UrlItemView *view = new UrlItemView;
00220         ItemDelegate *delegate = new ItemDelegate(q);
00221         delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
00222         delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00223         view->setItemDelegate(delegate);
00224         view->setItemStateProvider(delegate);
00225 
00226         addView(i18n("Computer"), systemIcon(), model, view);
00227     }
00228 
00229     void setupSearchView()
00230     {
00231         searchModel = new SearchModel(q);
00232         UrlItemView *view = new UrlItemView;
00233         ItemDelegate *delegate = new ItemDelegate(q);
00234         delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, SubTitleRole);
00235         delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00236         view->setItemDelegate(delegate);
00237         view->setItemStateProvider(delegate);
00238         view->setModel(searchModel);
00239         view->setFrameStyle(QFrame::NoFrame);
00240         // prevent view from stealing focus from the search bar
00241         view->setFocusPolicy(Qt::NoFocus);
00242         view->setDragEnabled(true);
00243         setupEventHandler(view);
00244 
00245         connect(searchModel, SIGNAL(resultsAvailable()), q, SLOT(resultsAvailable()));
00246 
00247         connect(searchBar, SIGNAL(queryChanged(QString)), searchModel, SLOT(setQuery(QString)));
00248         connect(searchBar, SIGNAL(queryChanged(QString)), q, SLOT(focusSearchView(QString)));
00249 
00250         view->setContextMenuPolicy(Qt::CustomContextMenu);
00251         connect(view, SIGNAL(customContextMenuRequested(QPoint)), q, SLOT(showViewContextMenu(QPoint)));
00252 
00253         contentArea->addWidget(view);
00254         searchView = view;
00255     }
00256 
00257     void registerUrlHandlers()
00258     {
00259         UrlItemLauncher::addGlobalHandler(UrlItemLauncher::ExtensionHandler, "desktop", new ServiceItemHandler);
00260         UrlItemLauncher::addGlobalHandler(UrlItemLauncher::ProtocolHandler, "leave", new LeaveItemHandler);
00261     }
00262 
00263     QIcon systemIcon()
00264     {
00265        QList<Solid::Device> batteryList = Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString());
00266 
00267        if (batteryList.isEmpty()) {
00268           return KIcon("computer");
00269        } else {
00270           return KIcon("computer-laptop");
00271        }
00272     }
00273 
00274     void setNorthLayout(TabOrder tabOrder)
00275     {
00276         contentSwitcher->setShape( QTabBar::RoundedNorth );
00277         QLayout * layout = q->layout();
00278         delete layout;
00279         layout = new QVBoxLayout();
00280         layout->addWidget(contentSwitcher);
00281         layout->addWidget(contentArea);
00282         layout->addWidget(searchBar);
00283         layout->addWidget(footer);
00284         layout->setSpacing(0);
00285         layout->setMargin(0);
00286         q->setLayout(layout);
00287         setTabOrder( tabOrder );
00288     }
00289 
00290     void setSouthLayout(TabOrder tabOrder)
00291     {
00292         contentSwitcher->setShape( QTabBar::RoundedSouth );
00293         QLayout * layout = q->layout();
00294         delete layout;
00295         layout = new QVBoxLayout();
00296         layout->addWidget(footer);
00297         layout->addWidget(searchBar);
00298         layout->addWidget(contentArea);
00299         layout->addWidget(contentSwitcher);
00300         layout->setSpacing(0);
00301         layout->setMargin(0);
00302         q->setLayout(layout);
00303         setTabOrder( tabOrder );
00304     }
00305 
00306     void setWestLayout(TabOrder tabOrder)
00307     {
00308         contentSwitcher->setShape( QTabBar::RoundedWest );
00309         QLayout * layout = q->layout();
00310         delete layout;
00311         layout = new QHBoxLayout();
00312         layout->addWidget(contentSwitcher);
00313         layout->addWidget(contentArea);
00314         QBoxLayout * layout2 = new QVBoxLayout();
00315         if ( tabOrder == NormalTabOrder ) {
00316             layout2->addLayout(layout);
00317             layout2->addWidget(searchBar);
00318             layout2->addWidget(footer);
00319         } else {
00320             layout2->addWidget(footer);
00321             layout2->addWidget(searchBar);
00322             layout2->addLayout(layout);
00323         }
00324         layout->setSpacing(0);
00325         layout->setMargin(0);
00326         layout2->setSpacing(0);
00327         layout2->setMargin(0);
00328         q->setLayout(layout2);
00329         setTabOrder( tabOrder );
00330     }
00331 
00332     void setEastLayout(TabOrder tabOrder)
00333     {
00334         contentSwitcher->setShape( QTabBar::RoundedEast );
00335         QLayout * layout = q->layout();
00336         delete layout;
00337         layout = new QHBoxLayout();
00338         layout->addWidget(contentArea);
00339         layout->addWidget(contentSwitcher);
00340         QBoxLayout * layout2 = new QVBoxLayout();
00341         if ( tabOrder == NormalTabOrder ) {
00342             layout2->addLayout(layout);
00343             layout2->addWidget(searchBar);
00344             layout2->addWidget(footer);
00345         } else {
00346             layout2->addWidget(footer);
00347             layout2->addWidget(searchBar);
00348             layout2->addLayout(layout);
00349         }
00350         layout->setSpacing(0);
00351         layout->setMargin(0);
00352         layout2->setSpacing(0);
00353         layout2->setMargin(0);
00354         q->setLayout(layout2);
00355         setTabOrder(tabOrder);
00356     }
00357 
00358     void setTabOrder(TabOrder newOrder)
00359     {
00360         // identify current TabOrder, assumes favoritesView is first in normal order
00361         TabOrder oldOrder;
00362         if ( contentArea->widget( 0 ) == favoritesView  ) {
00363             oldOrder = NormalTabOrder;
00364         } else {
00365             oldOrder = ReverseTabOrder;
00366         }
00367         if ( newOrder == oldOrder ) {
00368             return;
00369         }
00370         // remove the and widgets and store their data in a separate structure
00371         // remove this first so we can cleanly remove the widgets controlled by contentSwitcher
00372         contentArea->removeWidget( searchView );
00373         Q_ASSERT( contentArea->count() == contentSwitcher->count() );
00374 
00375         QList<WidgetTabData> removedTabs;
00376         for ( int i = contentSwitcher->count() - 1; i >= 0 ; i-- ) {
00377             WidgetTabData wtd;
00378             wtd.tabText = contentSwitcher->tabText( i );
00379             wtd.tabToolTip = contentSwitcher->tabToolTip( i );
00380             wtd.tabWhatsThis = contentSwitcher->tabWhatsThis( i );
00381             wtd.tabIcon = contentSwitcher->tabIcon( i );
00382             wtd.widget = contentArea->widget( i );
00383             removedTabs.append( wtd );
00384 
00385             contentSwitcher->removeTab( i );
00386             contentArea->removeWidget( contentArea->widget( i ) );
00387         }
00388         // then reinsert them in reversed order
00389         int i = 0;
00390         foreach (const WidgetTabData &wtd, removedTabs) {
00391             contentSwitcher->addTab( wtd.tabIcon, wtd.tabText );
00392             contentSwitcher->setTabToolTip( i, wtd.tabToolTip );
00393             contentSwitcher->setTabWhatsThis( i, wtd.tabWhatsThis );
00394             contentArea->addWidget( wtd.widget );
00395             ++i;
00396         }
00397         //finally replace the searchView
00398         contentArea->addWidget( searchView );
00399     }
00400 
00401     inline void adjustResizeHandlePosition();
00402 
00403     struct WidgetTabData
00404     {
00405         QString tabText;
00406         QString tabToolTip;
00407         QString tabWhatsThis;
00408         QIcon tabIcon;
00409         QWidget * widget;
00410     };
00411     Launcher * const q;
00412     Plasma::Applet *applet;
00413     UrlItemLauncher *urlLauncher;
00414     ResizeHandle *resizeHandle;
00415     SearchModel *searchModel;
00416     SearchBar *searchBar;
00417     QWidget *footer;
00418     QStackedWidget *contentArea;
00419     TabBar *contentSwitcher;
00420     FlipScrollView *applicationView;
00421     QAbstractItemView *searchView;
00422     QAbstractItemView *favoritesView;
00423     ContextMenuFactory *contextMenuFactory;
00424     bool autoHide;
00425     int visibleItemCount;
00426     QPoint launcherOrigin;
00427     bool isResizing;
00428     CompassDirection resizePlacement;
00429     Plasma::Location panelEdge;
00430 };
00431 
00432 class Launcher::Private::ResizeHandle
00433     : public QWidget
00434 {
00435 public:
00436     ResizeHandle(QWidget *parent = 0)
00437         : QWidget(parent),
00438           m_placement(NorthEast)
00439     {
00440     }
00441 
00442     ~ResizeHandle()
00443     {
00444     }
00445 
00446     void setPlacement(CompassDirection dir)
00447     {
00448         m_placement = dir;
00449         switch (m_placement) {
00450             case NorthEast:
00451             default:
00452                 setCursor(Qt::SizeBDiagCursor);
00453                 break;
00454             case SouthEast:
00455                 setCursor(Qt::SizeFDiagCursor);
00456                 break;
00457             case SouthWest:
00458                 setCursor(Qt::SizeBDiagCursor);
00459                 break;
00460             case NorthWest:
00461                 setCursor(Qt::SizeFDiagCursor);
00462                 break;
00463         }
00464     }
00465 
00466 protected:
00467     void paintEvent(QPaintEvent *event)
00468     {
00469         QPainter p(this);
00470         QStyleOptionSizeGrip opt;
00471         opt.initFrom(this);
00472         switch (m_placement) {
00473             case NorthEast:
00474             default:
00475                 opt.corner = Qt::TopRightCorner;
00476                 break;
00477             case SouthEast:
00478                 opt.corner = Qt::BottomRightCorner;
00479                 break;
00480             case SouthWest:
00481                 opt.corner = Qt::BottomLeftCorner;
00482                 break;
00483             case NorthWest:
00484                 opt.corner = Qt::TopLeftCorner;
00485                 break;
00486         }
00487         style()->drawControl(QStyle::CE_SizeGrip, &opt, &p);
00488         p.end();
00489     }
00490 
00491 private:
00492     CompassDirection m_placement;
00493 };
00494 
00495 void Launcher::Private::adjustResizeHandlePosition()
00496 {
00497     const int margin = 1;
00498     switch (resizePlacement) {
00499         case NorthEast:
00500             resizeHandle->move(q->width()-resizeHandle->width() - margin,
00501                                margin);
00502             break;
00503         case SouthEast:
00504             resizeHandle->move(q->width()-resizeHandle->width() - margin,
00505                                q->height()-resizeHandle->height() - margin);
00506             break;
00507         case SouthWest:
00508             resizeHandle->move(margin, q->height()-resizeHandle->height() - margin);
00509             break;
00510         case NorthWest:
00511             resizeHandle->move(margin, margin);
00512             break;
00513         default:
00514             break;
00515     }
00516 
00517     resizeHandle->setPlacement(resizePlacement);
00518 }
00519 
00520 Launcher::Launcher(QWidget *parent)
00521     : QWidget(parent, Qt::Window)
00522     , d(new Private(this))
00523 {
00524     init();
00525 }
00526 
00527 Launcher::Launcher(Plasma::Applet *applet)
00528     : QWidget(0, Qt::Window)
00529     , d(new Private(this))
00530 {
00531     init();
00532     setApplet(applet);
00533 }
00534 
00535 void Launcher::init()
00536 {
00537     QVBoxLayout *layout = new QVBoxLayout;
00538     layout->setSpacing(0);
00539     layout->setMargin(0);
00540 
00541     const int rightHeaderMargin = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
00542 
00543     d->searchBar = new SearchBar(this);
00544     if (layoutDirection() == Qt::LeftToRight) {
00545         d->searchBar->setContentsMargins(0, 0, rightHeaderMargin, 0);
00546     } else {
00547         d->searchBar->setContentsMargins(rightHeaderMargin, 0, 0, 0);
00548     }
00549     d->searchBar->installEventFilter(this);
00550     d->contentArea = new QStackedWidget(this);
00551     d->contentSwitcher = new TabBar(this);
00552     d->contentSwitcher->installEventFilter(this);
00553     d->contentSwitcher->setIconSize(QSize(48,48));
00554     d->contentSwitcher->setShape(QTabBar::RoundedSouth);
00555     connect(d->contentSwitcher, SIGNAL(currentChanged(int)),
00556             d->contentArea, SLOT(setCurrentIndex(int)) );
00557     d->contextMenuFactory = new ContextMenuFactory(this);
00558 
00559     d->initTabs();
00560     d->registerUrlHandlers();
00561 
00562     // Add status information footer
00563     d->footer = new QWidget;
00564 
00565     char hostname[256];
00566     hostname[0] = '\0';
00567     if (!gethostname( hostname, sizeof(hostname) )) {
00568        hostname[sizeof(hostname)-1] = '\0';
00569     }
00570     QLabel *userinfo = new QLabel(i18n("User&nbsp;<b>%1</b>&nbsp;on&nbsp;<b>%2</b>", KUser().loginName(), hostname));
00571     QPalette palette;
00572     palette.setColor( QPalette::Foreground, KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText).color() );
00573     userinfo->setPalette( palette );
00574 
00575     QToolButton *branding = new BrandingButton(this);
00576     branding->setAutoRaise(false);
00577     branding->setToolButtonStyle(Qt::ToolButtonIconOnly);
00578     connect( branding, SIGNAL(clicked()), SLOT(openHomepage()));
00579 
00580     d->resizeHandle = new Private::ResizeHandle(this);
00581     d->resizeHandle->setFixedSize(16, 16);
00582     d->resizeHandle->setCursor(Qt::SizeBDiagCursor);
00583     setMouseTracking(true);
00584 
00585     QHBoxLayout *brandingLayout = new QHBoxLayout;
00586     brandingLayout->setMargin(3);
00587     brandingLayout->addSpacing(ItemDelegate::ITEM_LEFT_MARGIN - 3);
00588     brandingLayout->addWidget(userinfo);
00589     brandingLayout->addStretch(2);
00590     brandingLayout->addWidget(branding);
00591     brandingLayout->addSpacing(rightHeaderMargin);
00592     d->footer->setLayout(brandingLayout);
00593 
00594     layout->addWidget(d->footer);
00595     layout->addWidget(d->searchBar);
00596     layout->addWidget(d->contentArea);
00597     layout->addWidget(d->contentSwitcher);
00598 
00599     setLayout(layout);
00600     setBackgroundRole(QPalette::AlternateBase);
00601     setAutoFillBackground(true);
00602     d->resizePlacement = Private::NorthEast;
00603 }
00604 
00605 QSize Launcher::minimumSizeHint() const
00606 {
00607     QSize size = QWidget::sizeHint();
00608 
00609     // the extra 2 pixels are to make room for the content margins; see moveEvent
00610     const int CONTENT_MARGIN_WIDTH = 2;
00611 
00612     size.rwidth() += CONTENT_MARGIN_WIDTH;
00613 
00614     switch ( d->panelEdge ) {
00615         case Plasma::LeftEdge:
00616         case Plasma::RightEdge:
00617             size.rheight() = d->searchBar->sizeHint().height() +
00618                      d->footer->sizeHint().height() +
00619                      qMax( d->favoritesView->sizeHintForRow(0)*3 + ItemDelegate::HEADER_HEIGHT, d->contentSwitcher->sizeHint().height() );
00620             break;
00621         case Plasma::TopEdge:
00622         case Plasma::BottomEdge:
00623         default:
00624             size.rheight() = d->searchBar->sizeHint().height() +
00625                      d->contentSwitcher->sizeHint().height() + d->footer->sizeHint().height() +
00626                      d->favoritesView->sizeHintForRow(0)*3 + ItemDelegate::HEADER_HEIGHT;
00627             break;
00628     }
00629     return size;
00630 }
00631 
00632 QSize Launcher::sizeHint() const
00633 {
00634     KConfigGroup sizeGroup;
00635     if (d->applet) {
00636        sizeGroup = d->applet->config();
00637     } else {
00638        sizeGroup = componentData().config()->group("Size");
00639     }
00640     const int width = qMin(sizeGroup.readEntry("Width", 0), QApplication::desktop()->screen()->width()-50);
00641     const int height = qMin(sizeGroup.readEntry("Height", 0), QApplication::desktop()->screen()->height()-50);
00642     QSize wanted(width, height);
00643     bool isDefault = wanted.isNull();
00644     wanted = wanted.expandedTo(minimumSizeHint());
00645     if (isDefault) {
00646        wanted.setHeight( wanted.height() + ( d->favoritesView->sizeHintForRow(0) * (d->visibleItemCount - 3) ) );
00647     }
00648 
00649     return wanted;
00650 }
00651 
00652 void Launcher::setAutoHide(bool hide)
00653 {
00654     d->autoHide = hide;
00655 }
00656 
00657 bool Launcher::autoHide() const
00658 {
00659     return d->autoHide;
00660 }
00661 
00662 void Launcher::setSwitchTabsOnHover(bool switchOnHover)
00663 {
00664     d->contentSwitcher->setSwitchTabsOnHover(switchOnHover);
00665 }
00666 
00667 bool Launcher::switchTabsOnHover() const
00668 {
00669     return d->contentSwitcher->switchTabsOnHover();
00670 }
00671 
00672 void Launcher::setVisibleItemCount(int count)
00673 {
00674     d->visibleItemCount = count;
00675 }
00676 
00677 int Launcher::visibleItemCount() const
00678 {
00679     return d->visibleItemCount;
00680 }
00681 
00682 void Launcher::setApplet(Plasma::Applet *applet)
00683 {
00684     d->applet = applet;
00685     d->contextMenuFactory->setApplet(applet);
00686 
00687     KConfigGroup cg = applet->config();
00688     setSwitchTabsOnHover(cg.readEntry("SwitchTabsOnHover", switchTabsOnHover()));
00689     setVisibleItemCount(cg.readEntry("VisibleItemsCount", visibleItemCount()));
00690 }
00691 
00692 void Launcher::reset()
00693 {
00694     d->contentSwitcher->setCurrentIndexWithoutAnimation(d->contentArea->indexOf(d->favoritesView));
00695     d->contentArea->setCurrentWidget(d->favoritesView);
00696     d->searchBar->clear();
00697     d->applicationView->viewRoot();
00698 }
00699 
00700 Launcher::~Launcher()
00701 {
00702     delete d;
00703 }
00704 
00705 void Launcher::focusSearchView(const QString& query)
00706 {
00707     bool queryEmpty = query.isEmpty();
00708 
00709     d->contentSwitcher->setVisible(queryEmpty);
00710 
00711     if (!queryEmpty) {
00712         d->contentArea->setCurrentWidget(d->searchView);
00713     } else {
00714         focusFavoritesView();
00715     }
00716 }
00717 
00718 void Launcher::focusFavoritesView()
00719 {
00720     d->contentSwitcher->setCurrentIndex(d->contentArea->indexOf(d->favoritesView));
00721     d->contentArea->setCurrentWidget(d->favoritesView);
00722 }
00723 
00724 bool Launcher::eventFilter(QObject *object, QEvent *event)
00725 {
00726     // deliver unhandled key presses from the search bar
00727     // (mainly arrow keys, enter) to the active view
00728     if ((object == d->contentSwitcher || object == d->searchBar) && event->type() == QEvent::KeyPress) {
00729             // we want left/right to still nav the tabbar
00730         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
00731         if (keyEvent->modifiers() == Qt::NoModifier &&
00732             (keyEvent->key() == Qt::Key_Left ||
00733              keyEvent->key() == Qt::Key_Right)) {
00734             if (object == d->contentSwitcher) {
00735                 return false;
00736             } else {
00737                 QCoreApplication::sendEvent(d->contentSwitcher, event);
00738                 return true;
00739             }
00740         }
00741 
00742         QAbstractItemView *activeView = qobject_cast<QAbstractItemView*>(d->contentArea->currentWidget());
00743         if (activeView) {
00744             QCoreApplication::sendEvent(activeView, event);
00745             return true;
00746         }
00747     }
00748 
00749 
00750     // the mouse events we are interested in are delivered to the viewport,
00751     // other events are delivered to the view itself.
00752     QAbstractItemView *view = qobject_cast<QAbstractItemView*>(object);
00753     if(!view) {
00754         view = qobject_cast<QAbstractItemView*>(object->parent());
00755     }
00756 
00757     if (view) {
00758         QModelIndex openIndex;
00759         if (event->type() == QEvent::MouseButtonRelease) {
00760             QMouseEvent *mouseEvent = (QMouseEvent*)event;
00761             const QModelIndex index = view->indexAt(mouseEvent->pos());
00762             if (index.isValid() &&
00763                 index.model()->hasChildren(index) == false &&
00764                 mouseEvent->button() == Qt::LeftButton) {
00765                 openIndex = index;
00766             }
00767         } else if (event->type() == QEvent::KeyPress) {
00768             QKeyEvent *keyEvent = (QKeyEvent*)event;
00769             const QModelIndex index = view->currentIndex();
00770             if (index.isValid() && index.model()->hasChildren(index) == false &&
00771                 (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)) {
00772                 openIndex = index;
00773             }
00774         }
00775         if (openIndex.isValid()) {
00776             d->urlLauncher->openItem(openIndex);
00777             // Clear the search bar when enter was pressed
00778             if (event->type() == QEvent::KeyPress) {
00779                 d->searchBar->clear();
00780             }
00781             if (d->autoHide) {
00782                 hide();
00783             }
00784             return true;
00785         }
00786     }
00787     return QWidget::eventFilter(object, event);
00788 }
00789 
00790 void Launcher::showViewContextMenu(const QPoint& pos)
00791 {
00792     QAbstractItemView *view = qobject_cast<QAbstractItemView*>(sender());
00793     if (view) {
00794         d->contextMenuFactory->showContextMenu(view, d->contentArea->mapFromParent(pos));
00795     }
00796 }
00797 
00798 void Launcher::keyPressEvent(QKeyEvent *event)
00799 {
00800     if (event->key() == Qt::Key_Escape) {
00801         hide();
00802     }
00803 #if 0
00804     // allow tab switching by pressing the left or right arrow keys
00805     if (event->key() == Qt::Key_Left && d->contentSwitcher->currentIndex() > 0) {
00806         d->contentSwitcher->setCurrentIndex(d->contentSwitcher->currentIndex()-1);
00807     } else if (event->key() == Qt::Key_Right &&
00808         d->contentSwitcher->currentIndex() < d->contentSwitcher->count()-1) {
00809         d->contentSwitcher->setCurrentIndex(d->contentSwitcher->currentIndex()+1);
00810     }
00811 #endif
00812 }
00813 
00814 void Launcher::moveEvent(QMoveEvent *e)
00815 {
00816     // focus the search bar ready for typing
00817     int leftMargin = 1;
00818     int rightMargin = 1;
00819     int topMargin = 1;
00820     int bottomMargin = 1;
00821 
00822     QRect r(QApplication::desktop()->screenGeometry(this));
00823     QRect g(geometry());
00824 
00825     if (g.left() == r.left()) {
00826         leftMargin = 0;
00827     }
00828 
00829     if (g.right() == r.right()) {
00830         rightMargin = 0;
00831     }
00832 
00833     if (g.top() == r.top()) {
00834         topMargin = 0;
00835     }
00836 
00837     if (g.bottom() == r.bottom()) {
00838         bottomMargin = 0;
00839     }
00840 
00841     setContentsMargins(leftMargin, rightMargin, topMargin, rightMargin);
00842     QWidget::moveEvent(e);
00843 }
00844 
00845 void Launcher::showEvent(QShowEvent *e)
00846 {
00847     d->searchBar->setFocus();
00848     d->resizeHandle->raise();
00849     QWidget::showEvent(e);
00850 }
00851 
00852 void Launcher::hideEvent(QHideEvent *e)
00853 {
00854     emit aboutToHide();
00855     QWidget::hideEvent(e);
00856 }
00857 
00858 void Launcher::paintEvent(QPaintEvent*)
00859 {
00860     // TODO - Draw a pretty background here
00861     QPainter p(this);
00862     p.setPen(QPen(palette().mid(), 0));
00863     p.drawRect(rect().adjusted(0, 0, -1, -1));
00864 }
00865 
00866 void Launcher::openHomepage()
00867 { 
00868     hide();
00869     KToolInvocation::invokeBrowser("http://www.kde.org/");
00870 }
00871 
00872 void Launcher::resultsAvailable()
00873 {
00874     const QModelIndex root = d->searchModel->index(0, 0);
00875     d->searchView->setCurrentIndex(d->searchModel->index(0, 0, root));
00876 }
00877 
00878 void Launcher::setLauncherOrigin( QPoint origin, Plasma::Location location )
00879 {
00880 /* 8 interesting positions for the menu to popup, depending where
00881  * the launcher and panel it is on are sited:
00882  *
00883  * K3PANELPANELPANEL4K
00884  * 2                 5
00885  * P                 P
00886  * A                 A
00887  * N                 N
00888  * E                 E
00889  * L                 L
00890  * 1                 6
00891  * K8PANELPANELPANEL7K
00892  *
00893  * Position determines optimum layout according to Fitt's Law:
00894  * Assumption 1: The hardcoded tab order defines a desirable priority order
00895  * Goal 1: TabBar perpendicular to direction of mouse travel from launcher to target, to prevent
00896  * mousing over non-target tabs and potential unnecessary tab switches
00897  * Goal 2 the movie: Tabs are ordered by decreasing priority along the mouse travel vector away
00898  * from the launcher
00899  * Constraint: The search widget is different to the tabs and footer is of lowest priority so 
00900  * these should always be situated furthest away from the origin
00901  *
00902  * | Position | TabLayout | TabOrder   | rx | ry
00903  * |    1     |  South    | left2right | =  | -
00904  * |    2     |  North    | l2r        | =  | +
00905  * |    3     |  West     | top2bottom | +  | =
00906  * |    4     |  East     | t2b        | -  | =
00907  * |    5     |  North    | r2l        | -  | +
00908  * |    6     |  South    | r2l        | -  | -
00909  * |    7     |  East     | b2t        | -  | -
00910  * |    8     |  West     | b2t        | +  | +
00911  */
00912     if (d->launcherOrigin == origin && d->panelEdge == location) {
00913         return;
00914     }
00915     d->launcherOrigin = origin;
00916     d->panelEdge = location;
00917     QPoint relativePosition = pos() - d->launcherOrigin;
00918     int rx = relativePosition.x();
00919     int ry = relativePosition.y();
00920     if ( rx < 0 ) {
00921         if ( ry < 0 ) {
00922             if ( location == Plasma::RightEdge ) {
00923                 // Position 7
00924                 kDebug() << "menu position " << 7;
00925                 d->resizePlacement = Private::NorthWest;
00926                 d->setEastLayout( Private::ReverseTabOrder );
00927             } else { // Plasma::BottomEdge
00928                 // Position 6
00929                 kDebug() << "menu position " << 6;
00930                 d->resizePlacement = Private::NorthWest;
00931                 d->setSouthLayout( Private::ReverseTabOrder );
00932             }
00933         } else if ( ry == 0 ) {
00934             // Position 4
00935             kDebug() << "menu position " << 4;
00936             d->resizePlacement = Private::SouthWest;
00937             d->setEastLayout( Private::NormalTabOrder );
00938         } else {
00939             // Position 5
00940             kDebug() << "menu position " << 5;
00941             d->resizePlacement = Private::SouthWest;
00942             d->setNorthLayout( Private::ReverseTabOrder );
00943         }
00944     } else if ( rx == 0 ) {
00945         if ( ry < 0 ) {
00946             // Position 1
00947             kDebug() << "menu position " << 1;
00948             d->resizePlacement = Private::NorthEast;
00949             d->setSouthLayout( Private::NormalTabOrder );
00950         } else {
00951             // Position 2
00952             kDebug() << "menu position " << 2;
00953             d->resizePlacement = Private::SouthEast;
00954             d->setNorthLayout( Private::NormalTabOrder );
00955         }
00956     } else { // rx > 0
00957         if ( ry == 0 ) {
00958             // Position 3
00959             kDebug() << "menu position " << 3;
00960             d->resizePlacement = Private::SouthEast;
00961             d->setWestLayout( Private::NormalTabOrder );
00962         } else { //ry > 0
00963             // Position 8
00964             kDebug() << "menu position " << 8;
00965             d->resizePlacement = Private::NorthEast;
00966             d->setWestLayout( Private::ReverseTabOrder );
00967         }
00968     }
00969     d->adjustResizeHandlePosition();
00970 }
00971 
00972 QPoint Launcher::launcherOrigin() const
00973 {
00974     return d->launcherOrigin;
00975 }
00976 
00977 void Launcher::resizeEvent(QResizeEvent *e)
00978 {
00979     d->adjustResizeHandlePosition();
00980     QWidget::resizeEvent(e);
00981 }
00982 
00983 void Launcher::mousePressEvent(QMouseEvent *e)
00984 {
00985     if ( d->resizeHandle->geometry().contains( e->pos() ) ) {
00986         d->isResizing = true;
00987     }
00988     QWidget::mousePressEvent(e);
00989 }
00990 
00991 void Launcher::mouseReleaseEvent(QMouseEvent *e)
00992 {
00993     if (d->isResizing) {
00994        d->isResizing = false;
00995        KConfigGroup sizeGroup;
00996        if (d->applet) {
00997           sizeGroup = d->applet->config();
00998        } else {
00999           sizeGroup = componentData().config()->group("Size");
01000        }
01001        sizeGroup.writeEntry("Height", height());
01002        sizeGroup.writeEntry("Width", width());
01003        emit configNeedsSaving();
01004     }
01005     QWidget::mouseReleaseEvent(e);
01006 }
01007 
01008 void Launcher::mouseMoveEvent(QMouseEvent *e)
01009 {
01010     /* I'm not sure what the magic 10 below is for, if you do, please comment - Will */
01011     if ( hasMouseTracking() && d->isResizing ) {
01012         int newX, newY, newWidth, newHeight;
01013         kDebug() << "x: " << x() << " y: " << y();
01014         kDebug() << "width: " << width() << " height: " << height();
01015         kDebug() << "e-x: " << e->x() << " e->y: " << e->y();
01016         switch (d->resizePlacement) {
01017             case Private::NorthEast:
01018                 newWidth = qMax( e->x(), minimumSizeHint().width() );
01019                 newHeight = qMax( height() - e->y(), minimumSizeHint().height()/* + 10*/ );
01020                 newX = x();
01021                 newY = y() + height() - newHeight;
01022                 kDebug() << "Foot of menu to newY + newHeight";
01023                 kDebug() << "= " << newY << " + " << newHeight << " = " << (newY + newHeight);
01024                 break;
01025             case Private::SouthEast:
01026                 newWidth = qMax( e->x(), minimumSizeHint().width() );
01027                 newHeight = qMax( e->y(), minimumSizeHint().height()/* + 10*/ );
01028                 newX = x();
01029                 newY = y();
01030                 break;
01031             case Private::SouthWest:
01032                 newWidth = qMax( width() - e->x(), minimumSizeHint().width() );
01033                 newHeight = qMax( e->y(), minimumSizeHint().height()/* + 10*/ );
01034                 newX = x() + width() - newWidth;
01035                 newY = y();
01036                 break;
01037             case Private::NorthWest:
01038                 newWidth = qMax( width() - e->x(), minimumSizeHint().width() );
01039                 newHeight = qMax( height() - e->y(), minimumSizeHint().height()/* + 10*/ );
01040                 newX = x() + width() - newWidth;
01041                 newY = y() + height() - newHeight;
01042                 kDebug() << "Foot of menu to newY + newHeight";
01043                 kDebug() << "= " << newY << " + " << newHeight << " = " << (newY + newHeight);
01044                 break;
01045             default:
01046                 break;
01047         }
01048         kDebug() << "newX: " << newX << "newY: " << newY << "newW: " << newWidth << "newH: " << newHeight;
01049         setGeometry( newX, newY, newWidth, newHeight);
01050     }
01051     QWidget::mouseMoveEvent(e);
01052 }
01053 
01054 #include "launcher.moc"
01055 

Applets

Skip menu "Applets"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal