00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "simpleapplet/simpleapplet.h"
00023 #include "simpleapplet/menuview.h"
00024
00025
00026 #include <QtGui/QLabel>
00027 #include <QtGui/QComboBox>
00028 #include <QtGui/QSpinBox>
00029 #include <QtGui/QGridLayout>
00030 #include <QtGui/QGraphicsView>
00031 #include <QtCore/QMetaObject>
00032 #include <QtCore/QMetaEnum>
00033 #include <QtCore/QPointer>
00034 #include <QtGui/QGraphicsLinearLayout>
00035 #include <QtGui/QSpacerItem>
00036
00037
00038 #include <KIcon>
00039 #include <KConfigDialog>
00040 #include <KMenu>
00041 #include <KProcess>
00042 #include <KActionCollection>
00043 #include <KBookmarkMenu>
00044 #include <KRun>
00045
00046
00047 #include <Plasma/IconWidget>
00048 #include <Plasma/Containment>
00049 #include <Plasma/ToolTipManager>
00050
00051
00052 #include "core/itemhandlers.h"
00053 #include "core/models.h"
00054 #include "core/applicationmodel.h"
00055 #include "core/favoritesmodel.h"
00056 #include "core/systemmodel.h"
00057 #include "core/recentlyusedmodel.h"
00058 #include "core/recentapplications.h"
00059 #include "core/leavemodel.h"
00060 #include "core/urlitemlauncher.h"
00061
00062 class BookmarkOwner : public KBookmarkOwner
00063 {
00064 public:
00065 BookmarkOwner() : KBookmarkOwner() {}
00066 virtual bool enableOption(BookmarkOption) const {
00067 return false;
00068 }
00069 virtual bool supportsTabs() const {
00070 return false;
00071 }
00072 virtual void openBookmark(const KBookmark& b, Qt::MouseButtons, Qt::KeyboardModifiers) {
00073 new KRun(b.url(), (QWidget*)0);
00074 }
00075 };
00076
00078 class MenuLauncherApplet::Private
00079 {
00080 public:
00081 QPointer<Kickoff::MenuView> menuview;
00082 Plasma::IconWidget *icon;
00083 QPointer<Kickoff::UrlItemLauncher> launcher;
00084
00085 KActionCollection* collection;
00086 BookmarkOwner* bookmarkowner;
00087 KBookmarkMenu* bookmarkmenu;
00088
00089 MenuLauncherApplet::ViewType viewtype;
00090 MenuLauncherApplet::FormatType formattype;
00091 int maxRecentApps;
00092
00093 QComboBox *viewComboBox;
00094 QComboBox *formatComboBox;
00095 QSpinBox *recentApplicationsSpinBox;
00096
00097 QList<QAction*> actions;
00098 QAction* switcher;
00099
00100 Private()
00101 : menuview(0),
00102 icon(0),
00103 launcher(0),
00104 collection(0),
00105 bookmarkowner(0),
00106 bookmarkmenu(0),
00107 viewComboBox(0),
00108 formatComboBox(0),
00109 switcher(0) {}
00110 ~Private() {
00111 delete bookmarkmenu;
00112 delete bookmarkowner;
00113 delete menuview;
00114 }
00115
00116 void setMaxRecentApps(int num) {
00117 maxRecentApps = qMax(0, num);
00118 if (maxRecentApps > Kickoff::RecentApplications::self()->maximum()) {
00119 Kickoff::RecentApplications::self()->setMaximum(maxRecentApps);
00120 }
00121 }
00122
00123 void addItem(QComboBox* combo, const QString& caption, int index, const QString& icon = QString()) {
00124 if (icon.isEmpty()) {
00125 combo->addItem(caption, index);
00126 } else {
00127 combo->addItem(KIcon(icon), caption, index);
00128 }
00129 }
00130
00131 void setCurrentItem(QComboBox* combo, int currentIndex) {
00132 for (int i = combo->count() - 1; i >= 0; --i) {
00133 if (combo->itemData(i).toInt() == currentIndex) {
00134 combo->setCurrentIndex(i);
00135 return;
00136 }
00137 }
00138 if (combo->count() > 0) {
00139 combo->setCurrentIndex(0);
00140 }
00141 }
00142
00143 Kickoff::MenuView *createMenuView(QAbstractItemModel *model = 0) {
00144 Kickoff::MenuView *view = new Kickoff::MenuView(menuview);
00145 view->setFormatType((Kickoff::MenuView::FormatType) formattype);
00146 if (model) {
00147 view->setModel(model);
00148 }
00149 return view;
00150 }
00151
00152 void addMenu(Kickoff::MenuView *view, bool mergeFirstLevel) {
00153 QList<QAction*> actions = view->actions();
00154 foreach(QAction *action, actions) {
00155 if (action->menu() && mergeFirstLevel) {
00156 QMetaObject::invokeMethod(action->menu(), "aboutToShow");
00157 if (actions.count() > 1 && action->menu()->actions().count() > 0) {
00158 menuview->addTitle(action->text());
00159 }
00160 foreach(QAction *a, action->menu()->actions()) {
00161 a->setVisible(a->menu() || ! view->indexForAction(a).data(Kickoff::UrlRole).isNull());
00162 menuview->addAction(a);
00163 }
00164 } else {
00165 action->setVisible(action->menu() || ! view->indexForAction(action).data(Kickoff::UrlRole).isNull());
00166 menuview->addAction(action);
00167 }
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177 connect(view->model(), SIGNAL(modelReset()), menuview, SLOT(deleteLater()));
00178 }
00179
00180 QString viewIcon() {
00181 switch (viewtype) {
00182 case Combined:
00183 return "start-here-kde";
00184 case Favorites:
00185 return "bookmarks";
00186 case Bookmarks:
00187 return "folder-bookmarks";
00188 case Applications:
00189 return "applications-other";
00190 case Computer:
00191 return "computer";
00192 case RecentlyUsed:
00193 return "document-open-recent";
00194 case Leave:
00195 return "application-exit";
00196 }
00197 return QString();
00198 }
00199
00200
00201 };
00202
00203 MenuLauncherApplet::MenuLauncherApplet(QObject *parent, const QVariantList &args)
00204 : Plasma::Applet(parent, args),
00205 d(new Private)
00206 {
00207 KGlobal::locale()->insertCatalog("plasma_applet_launcher");
00208
00209 setHasConfigurationInterface(true);
00210 setBackgroundHints(NoBackground);
00211
00212 resize(IconSize(KIconLoader::Desktop) * 2, IconSize(KIconLoader::Desktop) * 2);
00213
00214 d->icon = new Plasma::IconWidget(QString(), this);
00215 d->icon->setFlag(ItemIsMovable, false);
00216 connect(d->icon, SIGNAL(pressed(bool)), this, SLOT(toggleMenu(bool)));
00217 connect(this, SIGNAL(activate()), this, SLOT(toggleMenu()));
00218
00219 d->viewtype = Combined;
00220 d->formattype = NameDescription;
00221 }
00222
00223 MenuLauncherApplet::~MenuLauncherApplet()
00224 {
00225 delete d;
00226 }
00227
00228 void MenuLauncherApplet::init()
00229 {
00230 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
00231 layout->setContentsMargins(0, 0, 0, 0);
00232 layout->setSpacing(0);
00233
00234 layout->addItem(d->icon);
00235
00236 KConfigGroup cg = config();
00237
00238 QMetaEnum vte = metaObject()->enumerator(metaObject()->indexOfEnumerator("ViewType"));
00239 QByteArray vtb = cg.readEntry("view", QByteArray(vte.valueToKey(d->viewtype)));
00240 d->viewtype = (MenuLauncherApplet::ViewType) vte.keyToValue(vtb);
00241
00242 QMetaEnum fte = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
00243 QByteArray ftb = cg.readEntry("format", QByteArray(fte.valueToKey(d->formattype)));
00244 d->formattype = (MenuLauncherApplet::FormatType) fte.keyToValue(ftb);
00245
00246 d->setMaxRecentApps(cg.readEntry("maxRecentApps", qMin(5, Kickoff::RecentApplications::self()->maximum())));
00247
00248 d->icon->setIcon(KIcon(d->viewIcon()));
00249
00250
00251
00252 setAspectRatioMode(Plasma::ConstrainedSquare);
00253
00254 Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ExtensionHandler, "desktop", new Kickoff::ServiceItemHandler);
00255 Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ProtocolHandler, "leave", new Kickoff::LeaveItemHandler);
00256
00257 if (KService::serviceByStorageId("kde4-kmenuedit.desktop")) {
00258 QAction* menueditor = new QAction(i18n("Menu Editor"), this);
00259 d->actions.append(menueditor);
00260 connect(menueditor, SIGNAL(triggered(bool)), this, SLOT(startMenuEditor()));
00261 }
00262
00263 Q_ASSERT(! d->switcher);
00264 d->switcher = new QAction(i18n("Switch to Kickoff Menu Style"), this);
00265 d->actions.append(d->switcher);
00266 connect(d->switcher, SIGNAL(triggered(bool)), this, SLOT(switchMenuStyle()));
00267
00268 constraintsEvent(Plasma::ImmutableConstraint);
00269 }
00270
00271 void MenuLauncherApplet::constraintsEvent(Plasma::Constraints constraints)
00272 {
00273 setBackgroundHints(NoBackground);
00274 if (constraints & Plasma::FormFactorConstraint) {
00275 if (formFactor() == Plasma::Planar ||
00276 formFactor() == Plasma::MediaCenter) {
00277
00278
00279 } else {
00280
00281 }
00282 }
00283
00284 if ((constraints & Plasma::ImmutableConstraint) && d->switcher) {
00285 d->switcher->setVisible(immutability() == Plasma::Mutable);
00286 }
00287 }
00288
00289 void MenuLauncherApplet::switchMenuStyle()
00290 {
00291 if (containment()) {
00292 containment()->addApplet("launcher", QVariantList(), geometry());
00293 destroy();
00294 }
00295 }
00296
00297 void MenuLauncherApplet::startMenuEditor()
00298 {
00299 KProcess::execute("kmenuedit");
00300 }
00301
00302 void MenuLauncherApplet::createConfigurationInterface(KConfigDialog *parent)
00303 {
00304 QWidget *p = new QWidget(parent);
00305 QGridLayout *l = new QGridLayout(p);
00306 p->setLayout(l);
00307
00308 QLabel *viewLabel = new QLabel(i18nc("@label:listbox Which category of items to view in a KMenu-like menu", "View:"), p);
00309 l->addWidget(viewLabel, 0, 0, Qt::AlignRight);
00310 d->viewComboBox = new QComboBox(p);
00311 viewLabel->setBuddy(d->viewComboBox);
00312 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Standard"), MenuLauncherApplet::Combined, "start-here-kde");
00313 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Favorites"), MenuLauncherApplet::Favorites, "bookmarks");
00314 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Bookmarks"), MenuLauncherApplet::Bookmarks, "folder-bookmarks");
00315 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Applications"), MenuLauncherApplet::Applications, "applications-other");
00316 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Computer"), MenuLauncherApplet::Computer, "computer");
00317 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Recently Used"), MenuLauncherApplet::RecentlyUsed, "document-open-recent");
00318 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Leave"), MenuLauncherApplet::Leave, "application-exit");
00319 l->addWidget(d->viewComboBox, 0, 1);
00320
00321 QLabel *formatLabel = new QLabel(i18nc("@label:listbox How to present applications in a KMenu-like menu", "Format:"), p);
00322 l->addWidget(formatLabel, 1, 0, Qt::AlignRight);
00323 d->formatComboBox = new QComboBox(p);
00324 formatLabel->setBuddy(d->formatComboBox);
00325 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Only"), MenuLauncherApplet::Name);
00326 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description Only"), MenuLauncherApplet::Description);
00327 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Description"), MenuLauncherApplet::NameDescription);
00328 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description (Name)"), MenuLauncherApplet::DescriptionName);
00329 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name - Description"), MenuLauncherApplet::NameDashDescription);
00330 l->addWidget(d->formatComboBox, 1, 1);
00331
00332 QLabel *recentLabel = new QLabel(i18n("Recent Applications:"), p);
00333 l->addWidget(recentLabel, 2, 0, Qt::AlignRight);
00334 d->recentApplicationsSpinBox = new QSpinBox(p);
00335 d->recentApplicationsSpinBox->setMaximum(10);
00336 d->recentApplicationsSpinBox->setMinimum(0);
00337 d->recentApplicationsSpinBox->setValue(d->maxRecentApps);
00338 recentLabel->setBuddy(d->recentApplicationsSpinBox);
00339 l->addWidget(d->recentApplicationsSpinBox, 2, 1);
00340
00341 l->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 3, 0, 1, 2);
00342 l->setColumnStretch(1, 1);
00343
00344 d->setCurrentItem(d->viewComboBox, d->viewtype);
00345 d->setCurrentItem(d->formatComboBox, d->formattype);
00346
00347 connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00348 connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00349 parent->addPage(p, i18n("General"), icon());
00350 }
00351
00352 void MenuLauncherApplet::configAccepted()
00353 {
00354 bool needssaving = false;
00355 KConfigGroup cg = config();
00356
00357 const int vt = d->viewComboBox->itemData(d->viewComboBox->currentIndex()).toInt();
00358 if (vt != d->viewtype) {
00359 d->viewtype = (MenuLauncherApplet::ViewType) vt;
00360 needssaving = true;
00361
00362 QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("ViewType"));
00363 cg.writeEntry("view", QByteArray(e.valueToKey(d->viewtype)));
00364
00365 d->icon->setIcon(KIcon(d->viewIcon()));
00366 d->icon->update();
00367 }
00368
00369 const int ft = d->formatComboBox->itemData(d->formatComboBox->currentIndex()).toInt();
00370 if (ft != d->formattype) {
00371 d->formattype = (MenuLauncherApplet::FormatType) ft;
00372 needssaving = true;
00373
00374 QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
00375 cg.writeEntry("format", QByteArray(e.valueToKey(d->formattype)));
00376 }
00377
00378 const int maxRecentApps = d->recentApplicationsSpinBox->value();
00379 if (maxRecentApps != d->maxRecentApps) {
00380 needssaving = true;
00381 d->setMaxRecentApps(maxRecentApps);
00382 cg.writeEntry("maxRecentApps", maxRecentApps);
00383 }
00384
00385 if (needssaving) {
00386 emit configNeedsSaving();
00387
00388 delete d->menuview;
00389 d->menuview = 0;
00390 }
00391 }
00392
00393 void MenuLauncherApplet::toggleMenu(bool pressed)
00394 {
00395 if (pressed) {
00396 toggleMenu();
00397 }
00398 }
00399
00400 void MenuLauncherApplet::toggleMenu()
00401 {
00402 if (!d->menuview) {
00403 d->menuview = new Kickoff::MenuView();
00404 connect(d->menuview, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*)));
00405 connect(d->menuview, SIGNAL(aboutToHide()), d->icon, SLOT(setUnpressed()));
00406 connect(d->menuview, SIGNAL(aboutToHide()), d->menuview, SLOT(deleteLater()));
00407
00408 switch (d->viewtype) {
00409 case Combined: {
00410
00411 if (d->maxRecentApps > 0) {
00412 d->menuview->addTitle(i18n("Recently Used Applications"));
00413 Kickoff::RecentlyUsedModel* recentlymodel = new Kickoff::RecentlyUsedModel(d->menuview, Kickoff::RecentlyUsedModel::ApplicationsOnly, d->maxRecentApps);
00414 Kickoff::MenuView *recentlyview = d->createMenuView(recentlymodel);
00415 d->addMenu(recentlyview, true);
00416 }
00417
00418 d->menuview->addTitle(i18n("All Applications"));
00419 Kickoff::ApplicationModel *appModel = new Kickoff::ApplicationModel(d->menuview);
00420 appModel->setDuplicatePolicy(Kickoff::ApplicationModel::ShowLatestOnlyPolicy);
00421 appModel->setSystemApplicationPolicy(Kickoff::ApplicationModel::ShowApplicationAndSystemPolicy);
00422 Kickoff::MenuView *appview = d->createMenuView(appModel);
00423 d->addMenu(appview, false);
00424
00425 d->menuview->addSeparator();
00426 Kickoff::MenuView *favview = d->createMenuView(new Kickoff::FavoritesModel(d->menuview));
00427 d->addMenu(favview, false);
00428
00429 d->menuview->addTitle(i18n("Actions"));
00430 QAction *runaction = d->menuview->addAction(KIcon("system-run"), i18n("Run Command..."));
00431 runaction->setData(KUrl("leave:/run"));
00432 d->menuview->addSeparator();
00433 QAction *switchaction = d->menuview->addAction(KIcon("system-switch-user"), i18n("Switch User"));
00434 switchaction->setData(KUrl("leave:/switch"));
00435 QAction *lockaction = d->menuview->addAction(KIcon("system-lock-screen"), i18n("Lock Screen"));
00436 lockaction->setData(KUrl("leave:/lock"));
00437 QAction *logoutaction = d->menuview->addAction(KIcon("system-shutdown"), i18n("Leave..."));
00438 logoutaction->setData(KUrl("leave:/logout"));
00439 }
00440 break;
00441 case Favorites: {
00442 Kickoff::MenuView *favview = d->createMenuView(new Kickoff::FavoritesModel(d->menuview));
00443 d->addMenu(favview, true);
00444 }
00445 break;
00446 case Applications: {
00447 Kickoff::ApplicationModel *appModel = new Kickoff::ApplicationModel(d->menuview);
00448 appModel->setDuplicatePolicy(Kickoff::ApplicationModel::ShowLatestOnlyPolicy);
00449 Kickoff::MenuView *appview = d->createMenuView(appModel);
00450 d->addMenu(appview, false);
00451 }
00452 break;
00453 case Computer: {
00454 Kickoff::MenuView *systemview = d->createMenuView(new Kickoff::SystemModel(d->menuview));
00455 d->addMenu(systemview, true);
00456 }
00457 break;
00458 case RecentlyUsed: {
00459 Kickoff::MenuView *recentlyview = d->createMenuView(new Kickoff::RecentlyUsedModel(d->menuview));
00460 d->addMenu(recentlyview, true);
00461 }
00462 break;
00463 case Bookmarks: {
00464 KBookmarkManager* mgr = KBookmarkManager::userBookmarksManager();
00465 if (! d->collection) {
00466 d->collection = new KActionCollection(this);
00467 d->bookmarkowner = new BookmarkOwner();
00468 }
00469 delete d->bookmarkmenu;
00470 d->bookmarkmenu = new KBookmarkMenu(mgr, d->bookmarkowner, d->menuview, d->collection);
00471 }
00472 break;
00473 case Leave: {
00474 Kickoff::MenuView *leaveview = d->createMenuView(new Kickoff::LeaveModel(d->menuview));
00475 d->addMenu(leaveview, true);
00476 }
00477 break;
00478 }
00479 }
00480
00481 d->menuview->setAttribute(Qt::WA_DeleteOnClose);
00482 d->menuview->popup(popupPosition(d->menuview->sizeHint()));
00483 d->icon->setPressed();
00484 }
00485
00486 void MenuLauncherApplet::actionTriggered(QAction *action)
00487 {
00488 KUrl url = action->data().value<KUrl>();
00489 if (url.scheme() == "leave") {
00490 if (! d->launcher) {
00491 d->launcher = new Kickoff::UrlItemLauncher(d->menuview);
00492 }
00493 d->launcher->openUrl(url.url());
00494 return;
00495 }
00496 for (QWidget* w = action->parentWidget(); w; w = w->parentWidget()) {
00497 if (Kickoff::MenuView *view = dynamic_cast<Kickoff::MenuView*>(w)) {
00498 view->actionTriggered(action);
00499 break;
00500 }
00501 }
00502 }
00503
00504 QList<QAction*> MenuLauncherApplet::contextualActions()
00505 {
00506 return d->actions;
00507 }
00508
00509
00510 #include "simpleapplet.moc"