2
Copyright 2007 Robert Knight <robertknight@gmail.com>
3
Copyright 2008-2009 Sebastian Sauer <mail@dipe.org>
4
Copyright 2009 Christian Loose <christian.loose@kdemail.net>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License as published by the Free Software Foundation; either
9
version 2 of the License, or (at your option) any later version.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Library General Public License
17
along with this library; see the file COPYING.LIB. If not, write to
18
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301, USA.
23
#include "simpleapplet/simpleapplet.h"
24
#include "simpleapplet/menuview.h"
27
#include <QtGui/QLabel>
28
#include <QtGui/QCheckBox>
29
#include <QtGui/QSpinBox>
30
#include <QtGui/QGridLayout>
31
#include <QtGui/QGraphicsView>
32
#include <QtCore/QMetaObject>
33
#include <QtCore/QMetaEnum>
34
#include <QtCore/QWeakPointer>
35
#include <QtGui/QGraphicsLinearLayout>
36
#include <QtGui/QSpacerItem>
37
#include <QtGui/QListWidget>
38
#include <QtGui/QListWidgetItem>
41
#include <KActionCollection>
42
#include <KAuthorized>
43
#include <KBookmarkMenu>
44
#include <KCModuleInfo>
46
#include <KConfigDialog>
48
#include <KIconButton>
49
#include <KIconLoader>
53
#include <KServiceTypeTrader>
54
#include <KToolInvocation>
55
#include <Solid/PowerManagement>
58
#include <kworkspace/kworkspace.h>
61
#include <Plasma/IconWidget>
62
#include <Plasma/Containment>
63
#include <Plasma/ToolTipManager>
66
#include "core/itemhandlers.h"
67
#include "core/models.h"
68
#include "core/applicationmodel.h"
69
#include "core/favoritesmodel.h"
70
#include "core/systemmodel.h"
71
#include "core/recentlyusedmodel.h"
72
#include "core/recentapplications.h"
73
#include "core/leavemodel.h"
74
#include "core/urlitemlauncher.h"
75
#include "ui/contextmenufactory.h"
78
Q_DECLARE_METATYPE(QPersistentModelIndex)
81
/// @internal KBookmarkOwner specialization
82
class BookmarkOwner : public KBookmarkOwner
85
BookmarkOwner() : KBookmarkOwner() {}
86
virtual bool enableOption(BookmarkOption) const {
89
virtual bool supportsTabs() const {
92
virtual void openBookmark(const KBookmark& b, Qt::MouseButtons, Qt::KeyboardModifiers) {
93
new KRun(b.url(), (QWidget*)0);
97
/// @internal d-pointer class
98
class MenuLauncherApplet::Private
101
MenuLauncherApplet *q;
103
QWeakPointer<Kickoff::MenuView> menuview;
104
Plasma::IconWidget *icon;
106
QWeakPointer<Kickoff::UrlItemLauncher> launcher;
108
KActionCollection* bookmarkcollection;
109
BookmarkOwner* bookmarkowner;
110
KBookmarkMenu* bookmarkmenu;
112
QStringList viewtypes;//QList<MenuLauncherApplet::ViewType>
113
QString relativePath;
114
MenuLauncherApplet::FormatType formattype;
119
KIconButton *iconButton;
120
KComboBox *formatComboBox;
121
QSpinBox *recentApplicationsSpinBox;
122
QCheckBox *showMenuTitlesCheckBox;
124
QList<QAction*> actions;
126
Kickoff::ContextMenuFactory *contextMenuFactory;
128
bool delayedConfigLoad;
130
explicit Private(MenuLauncherApplet *q)
133
bookmarkcollection(0),
139
showMenuTitlesCheckBox(0),
141
contextMenuFactory(0)
147
delete bookmarkowner;
148
delete menuview.data();
151
void setMaxRecentApps(int num) {
152
maxRecentApps = qMax(0, num);
153
if (maxRecentApps > Kickoff::RecentApplications::self()->maximum()) {
154
Kickoff::RecentApplications::self()->setMaximum(maxRecentApps);
158
void addItem(KComboBox* combo, const QString& caption, int index, const QString& icon = QString())
160
if (icon.isEmpty()) {
161
combo->addItem(caption, index);
163
combo->addItem(KIcon(icon), caption, index);
167
void setCurrentItem(KComboBox* combo, int currentIndex)
169
for (int i = combo->count() - 1; i >= 0; --i) {
170
if (combo->itemData(i).toInt() == currentIndex) {
171
combo->setCurrentIndex(i);
175
if (combo->count() > 0)
176
combo->setCurrentIndex(0);
179
void addModel(QAbstractItemModel *model, ViewType viewtype, Kickoff::MenuView::ModelOptions options = Kickoff::MenuView::MergeFirstLevel, int formattype = -1)
181
Kickoff::MenuView* mainView = menuview.data();
182
Kickoff::MenuView* m = mainView;
183
if (viewtypes.count() > 1 || !m) {
184
m = new Kickoff::MenuView(mainView, viewText(viewtype), KIcon(viewIcon(viewtype)));
185
m->setFormatType((formattype >= 0 || !mainView) ? (Kickoff::MenuView::FormatType)formattype : mainView->formatType());
186
mainView->addMenu(m);
188
m->addModel(model, options);
191
QString viewText(MenuLauncherApplet::ViewType vt) const {
193
case Favorites: return i18n("Favorites");
194
case Bookmarks: return i18n("Bookmarks");
195
case Applications: return i18n("Applications");
196
case Computer: return i18n("Computer");
197
case RecentlyUsed: return i18n("Recently Used");
198
case RecentlyUsedApplications: return i18n("Recently Used Applications");
199
case RecentlyUsedDocuments: return i18n("Recently Used Documents");
200
case Settings: return i18n("System Settings");
201
case RunCommand: return i18n("Run Command...");
202
case SwitchUser: return i18n("Switch User");
203
case SaveSession: return i18n("Save Session");
204
case LockScreen: return i18n("Lock Screen");
205
case Standby: return i18nc("Puts the system on standby", "Standby");
206
case SuspendDisk: return i18n("Hibernate");
207
case SuspendRAM: return i18n("Sleep");
208
case Restart: return i18nc("Restart Computer", "Restart");
209
case Shutdown: return i18n("Shut down");
210
case Logout: return i18n("Log out");
211
case Leave: return i18n("Leave");
216
QString viewIcon(MenuLauncherApplet::ViewType vt) const {
218
case Favorites: return "bookmarks";
219
case Bookmarks: return "folder-bookmarks";
220
case Applications: return "applications-other";
221
case Computer: return "computer";
222
case RecentlyUsed: return "document-open-recent";
223
case RecentlyUsedApplications: return "document-open-recent";
224
case RecentlyUsedDocuments: return "document-open-recent";
225
case Settings: return "preferences-system";
226
case RunCommand: return "system-run";
227
case SwitchUser: return "system-switch-user";
228
case SaveSession: return "document-save";
229
case LockScreen: return "system-lock-screen";
230
case Standby: return "system-suspend";
231
case SuspendDisk: return "system-suspend-hibernate";
232
case SuspendRAM: return "system-suspend-hibernate";
233
case Restart: return "system-reboot";
234
case Shutdown: return "system-shutdown";
235
case Logout: return "system-log-out";
236
case Leave: return "system-shutdown";
241
MenuLauncherApplet::ViewType viewType(const QByteArray& type) const {
242
QMetaEnum e = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewType"));
243
return (MenuLauncherApplet::ViewType) e.keyToValue(type);
247
QByteArray viewType(MenuLauncherApplet::ViewType type) const {
248
QMetaEnum e = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewType"));
249
return e.valueToKey(types);
251
QList<MenuLauncherApplet::ViewType> viewTypes(const QStringList &types) const {
252
QList<MenuLauncherApplet::ViewType> l;
253
foreach(QString t, types) l << viewType(t.toUtf());
256
QStringList viewTypes(const QList<MenuLauncherApplet::ViewType> &types) const {
258
foreach(MenuLauncherApplet::ViewType t, types) l << viewType(t);
263
void updateTooltip() {
265
foreach(const QString &vtname, viewtypes)
266
names << viewText(viewType(vtname.toUtf8()));
267
Plasma::ToolTipContent data(i18n("Application Launcher Menu"), names.join(", "), icon->icon());
268
Plasma::ToolTipManager::self()->setContent(q, data);
272
MenuLauncherApplet::MenuLauncherApplet(QObject *parent, const QVariantList &args)
273
: Plasma::Applet(parent, args),
276
KGlobal::locale()->insertCatalog("plasma_applet_launcher");
278
setAspectRatioMode(Plasma::ConstrainedSquare);
279
setHasConfigurationInterface(true);
280
setBackgroundHints(NoBackground);
282
resize(IconSize(KIconLoader::Desktop) * 2, IconSize(KIconLoader::Desktop) * 2);
284
d->icon = new Plasma::IconWidget(QString(), this);
285
d->icon->setFlag(ItemIsMovable, false);
286
connect(d->icon, SIGNAL(pressed(bool)), this, SLOT(showMenu(bool)));
287
connect(this, SIGNAL(activate()), this, SLOT(toggleMenu()));
289
d->delayedConfigLoad = false;
290
switch(args.count()) {
291
case 2: { //Use submenu paths
292
d->viewtypes << "Applications";
293
d->relativePath = args.value(0).toString();
294
d->iconname = args.value(1).toString();
297
case 1: { //Check for delayed config (switch from Kickoff)
298
d->delayedConfigLoad = true;
299
//Do not "break;", as we may need the default views configuration
300
//(if SimpleLauncher was never used before)
302
default: { //Default configuration
303
d->viewtypes << "RecentlyUsedApplications" << "Applications" << "Favorites";
304
if (KAuthorized::authorize("run_command")) {
305
d->viewtypes << "RunCommand";
307
d->viewtypes << "Leave";
308
d->iconname = "start-here-kde";
311
d->formattype = NameDescription;
313
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
314
layout->setContentsMargins(0, 0, 0, 0);
315
layout->setSpacing(0);
316
layout->addItem(d->icon);
318
d->contextMenuFactory = new Kickoff::ContextMenuFactory(this);
319
d->contextMenuFactory->setApplet(this);
322
MenuLauncherApplet::~MenuLauncherApplet()
327
void MenuLauncherApplet::init()
329
bool receivedArgs = false;
330
if (!d->relativePath.isEmpty()) {
334
Q_ASSERT(! d->switcher);
335
d->switcher = new QAction(i18n("Switch to Application Launcher Style"), this);
336
d->actions.append(d->switcher);
337
connect(d->switcher, SIGNAL(triggered(bool)), this, SLOT(switchMenuStyle()));
341
Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ExtensionHandler, "desktop", new Kickoff::ServiceItemHandler);
342
Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ProtocolHandler, "leave", new Kickoff::LeaveItemHandler);
344
if (KService::serviceByStorageId("kde4-kmenuedit.desktop") && KAuthorized::authorize("action/menuedit")) {
345
QAction* menueditor = new QAction(i18n("Edit Applications..."), this);
346
d->actions.append(menueditor);
347
connect(menueditor, SIGNAL(triggered(bool)), this, SLOT(startMenuEditor()));
351
KConfigGroup cg = config();
352
cg.writeEntry("relativePath", d->relativePath);
353
cg.writeEntry("icon", d->iconname);
354
emit configNeedsSaving();
357
connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
358
this, SLOT(iconSizeChanged(int)));
361
void MenuLauncherApplet::constraintsEvent(Plasma::Constraints constraints)
363
setBackgroundHints(NoBackground);
364
if (constraints & Plasma::FormFactorConstraint) {
365
if (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter) {
366
//FIXME set correct minimum size
367
//setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Desktop)));
369
//setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Small)));
373
if ((constraints & Plasma::ImmutableConstraint) && d->switcher) {
374
d->switcher->setVisible(immutability() == Plasma::Mutable);
378
void MenuLauncherApplet::switchMenuStyle()
381
Plasma::Applet *launcher = containment()->addApplet("launcher", QVariantList(), geometry());
382
//Copy all the config items to the simple launcher
383
QMetaObject::invokeMethod(launcher, "saveConfigurationFromSimpleLauncher",
384
Qt::DirectConnection, Q_ARG(KConfigGroup, config()),
385
Q_ARG(KConfigGroup, globalConfig()));
387
//Switch shortcuts with the new launcher to avoid losing it
388
KShortcut currentShortcut = globalShortcut();
389
setGlobalShortcut(KShortcut());
390
launcher->setGlobalShortcut(currentShortcut);
395
void MenuLauncherApplet::startMenuEditor()
397
KProcess::execute("kmenuedit");
400
void MenuLauncherApplet::customContextMenuRequested(QMenu* menu, const QPoint& pos)
406
// there are 2 possible cases
407
// 1) An an actual action is active - menu is the menu containing the action wanted
408
// 2) either a submenu is active, but none of its actions are active. menu is the submenu,
409
// not the menu containing the submenu
410
QAction* menuAction = menu->activeAction();
411
if (menuAction) { // case 1)
412
const QPersistentModelIndex index = menuAction->data().value<QPersistentModelIndex>();
413
d->contextMenuFactory->showContextMenu(0, index, pos);
415
menuAction = menu->menuAction();
417
const QPersistentModelIndex index = menuAction->data().value<QPersistentModelIndex>();
418
d->contextMenuFactory->showContextMenu(0, index, pos);
423
void MenuLauncherApplet::createConfigurationInterface(KConfigDialog *parent)
426
d->recentApplicationsSpinBox = 0;
427
if (d->relativePath.isEmpty()) {
428
QWidget *viewpage = new QWidget(parent);
429
QVBoxLayout *l = new QVBoxLayout(viewpage);
431
viewpage->setLayout(l);
432
d->view = new QListWidget(viewpage);
433
d->view->resize(300,500);
434
l->addWidget(d->view);
436
QMetaEnum vte = metaObject()->enumerator(metaObject()->indexOfEnumerator("ViewType"));
437
for(int i = 0; i < vte.keyCount(); ++i) {
438
ViewType vt = (ViewType) vte.value(i);
439
const QByteArray vtname = vte.key(i);
440
QListWidgetItem *item = new QListWidgetItem(KIcon(d->viewIcon(vt)), d->viewText(vt), d->view);
441
item->setCheckState(d->viewtypes.contains(vtname) ? Qt::Checked : Qt::Unchecked);
442
item->setData(Qt::UserRole, vtname);
443
d->view->addItem(item);
445
parent->addPage(viewpage, i18n("View"), "view-list-details");
448
QWidget *p = new QWidget(parent);
449
QGridLayout *grid = new QGridLayout(p);
452
QLabel *iconLabel = new QLabel(i18n("Icon:"), p);
453
grid->addWidget(iconLabel, 0, 0, Qt::AlignRight);
454
d->iconButton = new KIconButton(p);
455
d->iconButton->setIcon(d->icon->icon());
456
iconLabel->setBuddy(d->iconButton);
457
grid->addWidget(d->iconButton, 0, 1);
459
QLabel *formatLabel = new QLabel(i18nc("@label:listbox How to present applications in a KMenu-like menu", "Format:"), p);
460
grid->addWidget(formatLabel, 1, 0, Qt::AlignRight);
461
d->formatComboBox = new KComboBox(p);
462
formatLabel->setBuddy(d->formatComboBox);
463
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Only"), MenuLauncherApplet::Name);
464
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description Only"), MenuLauncherApplet::Description);
465
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Description"), MenuLauncherApplet::NameDescription);
466
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description (Name)"), MenuLauncherApplet::DescriptionName);
467
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name - Description"), MenuLauncherApplet::NameDashDescription);
468
d->setCurrentItem(d->formatComboBox, d->formattype);
469
grid->addWidget(d->formatComboBox, 1, 1);
471
if (d->relativePath.isEmpty()) {
472
QLabel *recentLabel = new QLabel(i18n("Recently used applications:"), p);
473
grid->addWidget(recentLabel, 2, 0, Qt::AlignRight);
474
d->recentApplicationsSpinBox = new QSpinBox(p);
475
d->recentApplicationsSpinBox->setMaximum(10);
476
d->recentApplicationsSpinBox->setMinimum(0);
477
d->recentApplicationsSpinBox->setValue(d->maxRecentApps);
478
recentLabel->setBuddy(d->recentApplicationsSpinBox);
479
grid->addWidget(d->recentApplicationsSpinBox, 2, 1);
482
QLabel *showMenuTitlesLabel = new QLabel(i18n("Show menu titles:"), p);
483
grid->addWidget(showMenuTitlesLabel, 3, 0, Qt::AlignRight);
484
d->showMenuTitlesCheckBox = new QCheckBox(p);
485
d->showMenuTitlesCheckBox->setChecked(d->showMenuTitles);
486
grid->addWidget(d->showMenuTitlesCheckBox, 3, 1);
488
grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 4, 0, 1, 3);
489
parent->addPage(p, i18n("Options"), "configure");
491
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
492
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
493
connect(d->iconButton, SIGNAL(iconChanged(QString)), parent, SLOT(settingsModified()));
494
connect(d->formatComboBox, SIGNAL(currentIndexChanged(QString)), parent, SLOT(settingsModified()));
495
connect(d->recentApplicationsSpinBox, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
496
connect(d->showMenuTitlesCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
497
connect(d->view, SIGNAL(currentTextChanged(QString)), parent, SLOT(settingsModified()));
500
void MenuLauncherApplet::configAccepted()
502
bool needssaving = false;
503
KConfigGroup cg = config();
506
QStringList viewtypes;
507
for(int i = 0; i < d->view->count(); ++i) {
508
QListWidgetItem *item = d->view->item(i);
509
QByteArray vtname = item->data(Qt::UserRole).toByteArray();
510
if(item->checkState() == Qt::Checked)
512
if( !needssaving && ((item->checkState() == Qt::Checked && ! d->viewtypes.contains(vtname)) || (item->checkState() == Qt::Unchecked && d->viewtypes.contains(vtname))) )
516
d->viewtypes = viewtypes;
518
cg.writeEntry("views", d->viewtypes);
519
cg.deleteEntry("view"); // "view" was from <KDE4.3, we are using "views" now
523
const QString iconname = d->iconButton->icon();
524
if (! iconname.isEmpty()) {
526
d->icon->setIcon(KIcon(iconname));
528
cg.writeEntry("icon", iconname);
531
const int ft = d->formatComboBox->itemData(d->formatComboBox->currentIndex()).toInt();
532
if (ft != d->formattype) {
534
d->formattype = (MenuLauncherApplet::FormatType) ft;
535
QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
536
cg.writeEntry("format", QByteArray(e.valueToKey(d->formattype)));
539
if (d->recentApplicationsSpinBox) {
540
const int maxRecentApps = d->recentApplicationsSpinBox->value();
541
if (maxRecentApps != d->maxRecentApps) {
543
d->setMaxRecentApps(maxRecentApps);
544
cg.writeEntry("maxRecentApps", maxRecentApps);
548
const bool showMenuTitles = d->showMenuTitlesCheckBox->isChecked();
549
if (showMenuTitles != d->showMenuTitles) {
551
d->showMenuTitles = showMenuTitles;
552
cg.writeEntry("showMenuTitles", showMenuTitles);
557
emit configNeedsSaving();
559
d->menuview.data()->deleteLater();
564
inline int weightOfService( const KService::Ptr service )
566
QVariant tmp = service->property("X-KDE-Weight", QVariant::Int);
567
return (tmp.isValid() ? tmp.toInt() : 100);
569
inline bool sortServiceItemsByWeight(const KService::Ptr left, const KService::Ptr right)
571
return weightOfService(left) < weightOfService(right);
573
KService::List sortServices(KService::List list)
575
qSort(list.begin(), list.end(), sortServiceItemsByWeight);
579
void MenuLauncherApplet::toggleMenu()
581
showMenu(!d->menuview || !d->menuview.data()->isVisible());
584
void MenuLauncherApplet::showMenu(bool pressed)
586
if (!pressed || d->viewtypes.count()<=0) {
588
d->menuview.data()->deleteLater();
595
d->icon->setPressed();
598
Kickoff::MenuView *menuview = new Kickoff::MenuView();
599
d->menuview = menuview;
600
menuview->setAttribute(Qt::WA_DeleteOnClose);
601
menuview->setFormatType( (Kickoff::MenuView::FormatType) d->formattype );
602
menuview->setContextMenuPolicy(Qt::CustomContextMenu);
603
connect(menuview, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*)));
604
connect(menuview, SIGNAL(aboutToHide()), this, SLOT(menuHiding()));
605
connect(menuview, SIGNAL(customContextMenuRequested(QMenu*, const QPoint&)),
606
this, SLOT(customContextMenuRequested(QMenu*, const QPoint&)));
607
//connect(menuview, SIGNAL(afterBeingHidden()), menuview, SLOT(deleteLater()));
609
//Kickoff::MenuView::ModelOptions options = d->viewtypes.count() < 2 ? Kickoff::MenuView::MergeFirstLevel : Kickoff::MenuView::None;
610
foreach(const QString &vtname, d->viewtypes) {
611
if(vtname == "Applications") {
612
Kickoff::ApplicationModel *appModel = new Kickoff::ApplicationModel(menuview, true /*allow separators*/);
614
appModel->setNameDisplayOrder(Kickoff::NameBeforeDescription);
616
appModel->setDuplicatePolicy(Kickoff::ApplicationModel::ShowLatestOnlyPolicy);
617
if (d->formattype == Name || d->formattype == NameDescription || d->formattype == NameDashDescription)
618
appModel->setPrimaryNamePolicy(Kickoff::ApplicationModel::AppNamePrimary);
619
appModel->setSystemApplicationPolicy(Kickoff::ApplicationModel::ShowApplicationAndSystemPolicy);
621
menuview->addModel(appModel, Kickoff::MenuView::None, d->relativePath);
623
if (d->relativePath.isEmpty()) {
624
if (d->showMenuTitles) {
625
menuview->setModelTitleVisible(appModel, true);
626
menuview->addTitle(i18n("Actions"));
628
menuview->addSeparator();
631
} else if(vtname == "Favorites") {
632
d->addModel(new Kickoff::FavoritesModel(menuview), Favorites);
633
} else if(vtname == "Computer") {
634
d->addModel(new Kickoff::SystemModel(menuview), Computer);
635
} else if(vtname == "RecentlyUsed") {
636
d->addModel(new Kickoff::RecentlyUsedModel(menuview), RecentlyUsed);
637
} else if(vtname == "RecentlyUsedApplications") {
638
if (d->maxRecentApps > 0) {
639
Kickoff::RecentlyUsedModel *recentModel = new Kickoff::RecentlyUsedModel(menuview, Kickoff::RecentlyUsedModel::ApplicationsOnly, d->maxRecentApps);
640
menuview->addModel(recentModel, Kickoff::MenuView::MergeFirstLevel);
642
if (d->showMenuTitles) {
643
menuview->setModelTitleVisible(recentModel, true);
645
menuview->addSeparator();
648
} else if(vtname == "RecentlyUsedDocuments") {
649
Kickoff::RecentlyUsedModel *recentModel = new Kickoff::RecentlyUsedModel(menuview, Kickoff::RecentlyUsedModel::DocumentsOnly);
650
menuview->addModel(recentModel, Kickoff::MenuView::MergeFirstLevel);
652
if (d->showMenuTitles) {
653
menuview->setModelTitleVisible(recentModel, true);
655
menuview->addSeparator();
657
} else if(vtname == "Bookmarks") {
658
KMenu* menu = menuview;
659
if(d->viewtypes.count() > 1) {
660
menu = new KMenu(d->viewText(Bookmarks), menuview);
661
menu->setIcon(KIcon(d->viewIcon(Bookmarks)));
662
menuview->addMenu(menu);
664
KBookmarkManager* mgr = KBookmarkManager::userBookmarksManager();
665
if (! d->bookmarkcollection) {
666
d->bookmarkcollection = new KActionCollection(this);
667
d->bookmarkowner = new BookmarkOwner();
669
delete d->bookmarkmenu;
670
d->bookmarkmenu = new KBookmarkMenu(mgr, d->bookmarkowner, menu, d->bookmarkcollection);
671
} else if(vtname == "Settings") {
672
KMenu* parentmenu = menuview;
673
if(d->viewtypes.count() > 1) {
674
parentmenu = new KMenu(d->viewText(Settings), menuview);
675
parentmenu->setIcon(KIcon(d->viewIcon(Settings)));
676
menuview->addMenu(parentmenu);
678
QMap<QString, KMenu*> menus;
679
foreach(const KService::Ptr &rootentry, sortServices(KServiceTypeTrader::self()->query("SystemSettingsCategory", "(not exist [X-KDE-System-Settings-Parent-Category]) or [X-KDE-System-Settings-Parent-Category]==''"))) {
680
parentmenu->addTitle(rootentry->name().replace('&',"&&"));
681
const QString rootcategory = rootentry->property("X-KDE-System-Settings-Category").toString();
682
foreach(const KService::Ptr &entry, sortServices(KServiceTypeTrader::self()->query("SystemSettingsCategory", QString("[X-KDE-System-Settings-Parent-Category]=='%1'").arg(rootcategory)))) {
683
KMenu* menu = new KMenu(entry->name().replace('&',"&&"), parentmenu);
684
menu->setIcon(KIcon(entry->icon()));
685
parentmenu->addMenu(menu);
686
const QString category = entry->property("X-KDE-System-Settings-Category").toString();
687
menus[category] = menu;
690
QMap<QString, QList<KService::Ptr> > modules;
691
foreach(const KService::Ptr &entry, sortServices(KServiceTypeTrader::self()->query("KCModule"))) {
692
const QString category = entry->property("X-KDE-System-Settings-Parent-Category").toString();
693
if(! category.isEmpty() && ! entry->noDisplay())
694
modules[category] << entry;
696
foreach(const QString& category, modules.keys()) {
697
QString menucategory = category;
698
KService::Ptr subcategory = KService::Ptr();
699
while(! menucategory.isEmpty() && ! menus.contains(menucategory)) {
700
KService::List services = KServiceTypeTrader::self()->query("SystemSettingsCategory", QString("[X-KDE-System-Settings-Category]=='%1'").arg(menucategory));
701
//Q_ASSERT(services.count() > 0); //if that happens then we miss the desktop-file defining the category
702
//Q_ASSERT(services.count() < 2); //if that happens then we have more then one desktop-file defining the same category
703
if(services.count() < 1) {
704
menucategory.clear();
706
subcategory = services[0];
707
menucategory = subcategory->property("X-KDE-System-Settings-Parent-Category").toString();
710
if(menucategory.isEmpty()) continue; //skip the category
711
KMenu* m = menus[menucategory];
712
if(! subcategory.isNull())
713
m->addTitle(subcategory->name().replace('&',"&&"));
714
foreach(const KService::Ptr &entry, modules[category]) {
715
KCModuleInfo module(entry->entryPath());
716
m->addAction(KIcon(module.icon()), module.moduleName().replace('&',"&&"))->setData(KUrl("kcm:/" + entry->entryPath()));
719
} else if(vtname == "RunCommand") {
720
if (KAuthorized::authorize("run_command")) {
721
menuview->addAction(KIcon(d->viewIcon(RunCommand)), d->viewText(RunCommand))->setData(KUrl("leave:/run"));
723
} else if(vtname == "SwitchUser") {
724
menuview->addAction(KIcon(d->viewIcon(SwitchUser)), d->viewText(SwitchUser))->setData(KUrl("leave:/switch"));
725
} else if(vtname == "SaveSession") {
726
KConfigGroup c(KSharedConfig::openConfig("ksmserverrc", KConfig::NoGlobals), "General");
727
if (c.readEntry("loginMode") == "restoreSavedSession")
728
menuview->addAction(KIcon(d->viewIcon(SaveSession)), d->viewText(SaveSession))->setData(KUrl("leave:/savesession"));
729
} else if(vtname == "LockScreen") {
730
menuview->addAction(KIcon(d->viewIcon(LockScreen)), d->viewText(LockScreen))->setData(KUrl("leave:/lock"));
731
} else if(vtname == "Logout") {
732
menuview->addAction(KIcon(d->viewIcon(Logout)), d->viewText(Logout))->setData(KUrl("leave:/logout"));
733
} else if(vtname == "Leave") {
734
Kickoff::LeaveModel *leavemodel = new Kickoff::LeaveModel(menuview);
735
leavemodel->updateModel();
736
d->addModel(leavemodel, Leave, Kickoff::MenuView::MergeFirstLevel, Kickoff::MenuView::Name);
739
QSet< Solid::PowerManagement::SleepState > spdMethods = Solid::PowerManagement::supportedSleepStates();
740
if (vtname == "Standby") {
741
if (spdMethods.contains(Solid::PowerManagement::StandbyState))
742
menuview->addAction(KIcon(d->viewIcon(Standby)), d->viewText(Standby))->setData(KUrl("leave:/standby"));
743
} else if(vtname == "SuspendDisk") {
744
if (spdMethods.contains(Solid::PowerManagement::HibernateState))
745
menuview->addAction(KIcon(d->viewIcon(SuspendDisk)), d->viewText(SuspendDisk))->setData(KUrl("leave:/suspenddisk"));
746
} else if(vtname == "SuspendRAM") {
747
if (spdMethods.contains(Solid::PowerManagement::SuspendState))
748
menuview->addAction(KIcon(d->viewIcon(SuspendRAM)), d->viewText(SuspendRAM))->setData(KUrl("leave:/suspendram"));
749
} else if(vtname == "Restart") {
750
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeReboot))
751
menuview->addAction(KIcon(d->viewIcon(Restart)), d->viewText(Restart))->setData(KUrl("leave:/restart"));
752
} else if(vtname == "Shutdown") {
753
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeHalt))
754
menuview->addAction(KIcon(d->viewIcon(Shutdown)), d->viewText(Shutdown))->setData(KUrl("leave:/shutdown"));
761
Plasma::ToolTipManager::self()->hide(this);
762
setStatus(Plasma::NeedsAttentionStatus);
763
d->menuview.data()->popup(popupPosition(d->menuview.data()->sizeHint()));
766
void MenuLauncherApplet::menuHiding()
768
d->icon->setUnpressed();
769
setStatus(Plasma::PassiveStatus);
772
void MenuLauncherApplet::actionTriggered(QAction *action)
774
const KUrl url = action->data().value<KUrl>();
775
if (url.scheme() == "leave") {
777
d->launcher = new Kickoff::UrlItemLauncher(d->menuview.data());
780
d->launcher.data()->openUrl(url.url());
783
if (url.scheme() == "kcm") {
784
KToolInvocation::kdeinitExec("kcmshell4", QStringList() << url.fileName());
787
for (QWidget* w = action->parentWidget(); w; w = w->parentWidget()) {
788
if (Kickoff::MenuView *view = dynamic_cast<Kickoff::MenuView*>(w)) {
789
view->actionTriggered(action);
795
QList<QAction*> MenuLauncherApplet::contextualActions()
800
void MenuLauncherApplet::iconSizeChanged(int group)
802
if (group == KIconLoader::Desktop || group == KIconLoader::Panel) {
807
QSizeF MenuLauncherApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
809
if (which == Qt::PreferredSize) {
812
switch (formFactor()) {
814
case Plasma::MediaCenter:
815
iconSize = IconSize(KIconLoader::Desktop);
818
case Plasma::Horizontal:
819
case Plasma::Vertical:
820
iconSize = IconSize(KIconLoader::Panel);
824
return QSizeF(iconSize, iconSize);
827
return Plasma::Applet::sizeHint(which, constraint);
831
void MenuLauncherApplet::saveConfigurationFromKickoff(const KConfigGroup & configGroup, const KConfigGroup & globalConfigGroup)
833
//Copy configuration values
834
KConfigGroup cg = config();
835
configGroup.copyTo(&cg);
837
KConfigGroup gcg = globalConfig();
838
globalConfigGroup.copyTo(&gcg);
841
emit configNeedsSaving();
844
void MenuLauncherApplet::configChanged()
846
KConfigGroup cg = config();
848
const QStringList viewtypes = cg.readEntry("views", QStringList());
849
if(viewtypes.isEmpty()) { // backward-compatibility to <KDE4.3
850
QByteArray oldview = cg.readEntry("view", QByteArray());
851
if (!oldview.isEmpty() && oldview != "Combined") {
852
d->viewtypes = QStringList() << oldview;
853
d->iconname = d->viewIcon(d->viewType(oldview));
854
} // else we use the default d->viewtypes
856
d->viewtypes = viewtypes;
859
QMetaEnum fte = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
860
QByteArray ftb = cg.readEntry("format", QByteArray(fte.valueToKey(d->formattype)));
861
d->formattype = (MenuLauncherApplet::FormatType) fte.keyToValue(ftb);
863
d->setMaxRecentApps(cg.readEntry("maxRecentApps", qMin(5, Kickoff::RecentApplications::self()->maximum())));
864
d->showMenuTitles = cg.readEntry("showMenuTitles", false);
866
d->icon->setIcon(KIcon(cg.readEntry("icon", d->iconname)));
868
d->relativePath = cg.readEntry("relativePath", d->relativePath);
869
if (!d->relativePath.isEmpty()) {
870
d->viewtypes.clear();
871
d->viewtypes << "Applications";
876
constraintsEvent(Plasma::ImmutableConstraint);
879
#include "simpleapplet.moc"