add more spacing
[personal-kdebase.git] / workspace / plasma / applets / kickoff / simpleapplet / simpleapplet.cpp
blobe2e068a9936327d40255b07bf61bbe57512800c3
1 /*
2 Copyright 2007 Robert Knight <robertknight@gmail.com>
3 Copyright 2008 Sebastian Sauer <mail@dipe.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 // Own
22 #include "simpleapplet/simpleapplet.h"
23 #include "simpleapplet/menuview.h"
25 // Qt
26 #include <QtGui/QLabel>
27 #include <QtGui/QComboBox>
28 #include <QtGui/QSpinBox>
29 #include <QtGui/QGridLayout>
30 #include <QtGui/QGraphicsView>
31 #include <QtCore/QMetaObject>
32 #include <QtCore/QMetaEnum>
33 #include <QtCore/QPointer>
34 #include <QtGui/QGraphicsLinearLayout>
35 #include <QtGui/QSpacerItem>
37 // KDE
38 #include <KIcon>
39 #include <KConfigDialog>
40 #include <KMenu>
41 #include <KProcess>
42 #include <KActionCollection>
43 #include <KBookmarkMenu>
44 #include <KRun>
46 // Plasma
47 #include <Plasma/IconWidget>
48 #include <Plasma/Containment>
49 #include <Plasma/ToolTipManager>
51 // Local
52 #include "core/itemhandlers.h"
53 #include "core/models.h"
54 #include "core/applicationmodel.h"
55 #include "core/favoritesmodel.h"
56 #include "core/systemmodel.h"
57 #include "core/recentlyusedmodel.h"
58 #include "core/recentapplications.h"
59 #include "core/leavemodel.h"
60 #include "core/urlitemlauncher.h"
62 class BookmarkOwner : public KBookmarkOwner
64 public:
65 BookmarkOwner() : KBookmarkOwner() {}
66 virtual bool enableOption(BookmarkOption) const {
67 return false;
69 virtual bool supportsTabs() const {
70 return false;
72 virtual void openBookmark(const KBookmark& b, Qt::MouseButtons, Qt::KeyboardModifiers) {
73 new KRun(b.url(), (QWidget*)0);
77 /// @internal d-pointer class
78 class MenuLauncherApplet::Private
80 public:
81 QPointer<Kickoff::MenuView> menuview;
82 Plasma::IconWidget *icon;
83 QPointer<Kickoff::UrlItemLauncher> launcher;
85 KActionCollection* collection;
86 BookmarkOwner* bookmarkowner;
87 KBookmarkMenu* bookmarkmenu;
89 MenuLauncherApplet::ViewType viewtype;
90 MenuLauncherApplet::FormatType formattype;
91 int maxRecentApps;
93 QComboBox *viewComboBox;
94 QComboBox *formatComboBox;
95 QSpinBox *recentApplicationsSpinBox;
97 QList<QAction*> actions;
98 QAction* switcher;
100 Private()
101 : menuview(0),
102 icon(0),
103 launcher(0),
104 collection(0),
105 bookmarkowner(0),
106 bookmarkmenu(0),
107 viewComboBox(0),
108 formatComboBox(0),
109 switcher(0) {}
110 ~Private() {
111 delete bookmarkmenu;
112 delete bookmarkowner;
113 delete menuview;
116 void setMaxRecentApps(int num) {
117 maxRecentApps = qMax(0, num);
118 if (maxRecentApps > Kickoff::RecentApplications::self()->maximum()) {
119 Kickoff::RecentApplications::self()->setMaximum(maxRecentApps);
123 void addItem(QComboBox* combo, const QString& caption, int index, const QString& icon = QString()) {
124 if (icon.isEmpty()) {
125 combo->addItem(caption, index);
126 } else {
127 combo->addItem(KIcon(icon), caption, index);
131 void setCurrentItem(QComboBox* combo, int currentIndex) {
132 for (int i = combo->count() - 1; i >= 0; --i) {
133 if (combo->itemData(i).toInt() == currentIndex) {
134 combo->setCurrentIndex(i);
135 return;
138 if (combo->count() > 0) {
139 combo->setCurrentIndex(0);
143 Kickoff::MenuView *createMenuView(QAbstractItemModel *model = 0) {
144 Kickoff::MenuView *view = new Kickoff::MenuView(menuview);
145 view->setFormatType((Kickoff::MenuView::FormatType) formattype);
146 if (model) {
147 view->setModel(model);
149 return view;
152 void addMenu(Kickoff::MenuView *view, bool mergeFirstLevel) {
153 QList<QAction*> actions = view->actions();
154 foreach(QAction *action, actions) {
155 if (action->menu() && mergeFirstLevel) {
156 QMetaObject::invokeMethod(action->menu(), "aboutToShow"); //fetch the children
157 if (actions.count() > 1 && action->menu()->actions().count() > 0) {
158 menuview->addTitle(action->text());
160 foreach(QAction *a, action->menu()->actions()) {
161 a->setVisible(a->menu() || ! view->indexForAction(a).data(Kickoff::UrlRole).isNull());
162 menuview->addAction(a);
164 } else {
165 action->setVisible(action->menu() || ! view->indexForAction(action).data(Kickoff::UrlRole).isNull());
166 menuview->addAction(action);
170 // if the model asks us for a reset we can't do much except to invalidate our
171 // menuview to be able to rebuild it what is needed to prevent dealing with
172 // invalid items.
173 // the problem here is, that if the menu is currently displayed, it will just
174 // close itself what is evil++ but still better than crashes. anyway, the
175 // right(TM) solution would be to introduce logic to update the content of the
176 // menu even on a reset.
177 connect(view->model(), SIGNAL(modelReset()), menuview, SLOT(deleteLater()));
180 QString viewIcon() {
181 switch (viewtype) {
182 case Combined:
183 return "start-here-kde";
184 case Favorites:
185 return "bookmarks";
186 case Bookmarks:
187 return "folder-bookmarks";
188 case Applications:
189 return "applications-other";
190 case Computer:
191 return "computer";
192 case RecentlyUsed:
193 return "document-open-recent";
194 case Leave:
195 return "application-exit";
197 return QString();
203 MenuLauncherApplet::MenuLauncherApplet(QObject *parent, const QVariantList &args)
204 : Plasma::Applet(parent, args),
205 d(new Private)
207 KGlobal::locale()->insertCatalog("plasma_applet_launcher");
209 setHasConfigurationInterface(true);
210 setBackgroundHints(NoBackground);
212 resize(IconSize(KIconLoader::Desktop) * 2, IconSize(KIconLoader::Desktop) * 2);
214 d->icon = new Plasma::IconWidget(QString(), this);
215 d->icon->setFlag(ItemIsMovable, false);
216 connect(d->icon, SIGNAL(pressed(bool)), this, SLOT(toggleMenu(bool)));
217 connect(this, SIGNAL(activate()), this, SLOT(toggleMenu()));
219 d->viewtype = Combined;
220 d->formattype = NameDescription;
223 MenuLauncherApplet::~MenuLauncherApplet()
225 delete d;
228 void MenuLauncherApplet::init()
230 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
231 layout->setContentsMargins(0, 0, 0, 0);
232 layout->setSpacing(0);
234 layout->addItem(d->icon);
236 KConfigGroup cg = config();
238 QMetaEnum vte = metaObject()->enumerator(metaObject()->indexOfEnumerator("ViewType"));
239 QByteArray vtb = cg.readEntry("view", QByteArray(vte.valueToKey(d->viewtype)));
240 d->viewtype = (MenuLauncherApplet::ViewType) vte.keyToValue(vtb);
242 QMetaEnum fte = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
243 QByteArray ftb = cg.readEntry("format", QByteArray(fte.valueToKey(d->formattype)));
244 d->formattype = (MenuLauncherApplet::FormatType) fte.keyToValue(ftb);
246 d->setMaxRecentApps(cg.readEntry("maxRecentApps", qMin(5, Kickoff::RecentApplications::self()->maximum())));
248 d->icon->setIcon(KIcon(d->viewIcon()));
249 //d->icon->setIcon(KIcon(cg.readEntry("icon","start-here-kde")));
250 //setMinimumContentSize(d->icon->iconSize()); //setSize(d->icon->iconSize())
252 setAspectRatioMode(Plasma::ConstrainedSquare);
254 Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ExtensionHandler, "desktop", new Kickoff::ServiceItemHandler);
255 Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ProtocolHandler, "leave", new Kickoff::LeaveItemHandler);
257 if (KService::serviceByStorageId("kde4-kmenuedit.desktop")) {
258 QAction* menueditor = new QAction(i18n("Menu Editor"), this);
259 d->actions.append(menueditor);
260 connect(menueditor, SIGNAL(triggered(bool)), this, SLOT(startMenuEditor()));
263 Q_ASSERT(! d->switcher);
264 d->switcher = new QAction(i18n("Switch to Kickoff Menu Style"), this);
265 d->actions.append(d->switcher);
266 connect(d->switcher, SIGNAL(triggered(bool)), this, SLOT(switchMenuStyle()));
268 constraintsEvent(Plasma::ImmutableConstraint);
271 void MenuLauncherApplet::constraintsEvent(Plasma::Constraints constraints)
273 setBackgroundHints(NoBackground);
274 if (constraints & Plasma::FormFactorConstraint) {
275 if (formFactor() == Plasma::Planar ||
276 formFactor() == Plasma::MediaCenter) {
277 //FIXME set correct minimum size
278 //setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Desktop)));
279 } else {
280 //setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Small)));
284 if ((constraints & Plasma::ImmutableConstraint) && d->switcher) {
285 d->switcher->setVisible(immutability() == Plasma::Mutable);
289 void MenuLauncherApplet::switchMenuStyle()
291 if (containment()) {
292 containment()->addApplet("launcher", QVariantList(), geometry());
293 destroy();
297 void MenuLauncherApplet::startMenuEditor()
299 KProcess::execute("kmenuedit");
302 void MenuLauncherApplet::createConfigurationInterface(KConfigDialog *parent)
304 QWidget *p = new QWidget(parent);
305 QGridLayout *l = new QGridLayout(p);
306 p->setLayout(l);
308 QLabel *viewLabel = new QLabel(i18nc("@label:listbox Which category of items to view in a KMenu-like menu", "View:"), p);
309 l->addWidget(viewLabel, 0, 0, Qt::AlignRight);
310 d->viewComboBox = new QComboBox(p);
311 viewLabel->setBuddy(d->viewComboBox);
312 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Standard"), MenuLauncherApplet::Combined, "start-here-kde");
313 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Favorites"), MenuLauncherApplet::Favorites, "bookmarks");
314 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Bookmarks"), MenuLauncherApplet::Bookmarks, "folder-bookmarks");
315 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Applications"), MenuLauncherApplet::Applications, "applications-other");
316 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Computer"), MenuLauncherApplet::Computer, "computer");
317 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Recently Used"), MenuLauncherApplet::RecentlyUsed, "document-open-recent");
318 d->addItem(d->viewComboBox, i18nc("@item:inlistbox View:", "Leave"), MenuLauncherApplet::Leave, "application-exit");
319 l->addWidget(d->viewComboBox, 0, 1);
321 QLabel *formatLabel = new QLabel(i18nc("@label:listbox How to present applications in a KMenu-like menu", "Format:"), p);
322 l->addWidget(formatLabel, 1, 0, Qt::AlignRight);
323 d->formatComboBox = new QComboBox(p);
324 formatLabel->setBuddy(d->formatComboBox);
325 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Only"), MenuLauncherApplet::Name);
326 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description Only"), MenuLauncherApplet::Description);
327 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Description"), MenuLauncherApplet::NameDescription);
328 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description (Name)"), MenuLauncherApplet::DescriptionName);
329 d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name - Description"), MenuLauncherApplet::NameDashDescription);
330 l->addWidget(d->formatComboBox, 1, 1);
332 QLabel *recentLabel = new QLabel(i18n("Recent Applications:"), p);
333 l->addWidget(recentLabel, 2, 0, Qt::AlignRight);
334 d->recentApplicationsSpinBox = new QSpinBox(p);
335 d->recentApplicationsSpinBox->setMaximum(10);
336 d->recentApplicationsSpinBox->setMinimum(0);
337 d->recentApplicationsSpinBox->setValue(d->maxRecentApps);
338 recentLabel->setBuddy(d->recentApplicationsSpinBox);
339 l->addWidget(d->recentApplicationsSpinBox, 2, 1);
341 l->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 3, 0, 1, 2);
342 l->setColumnStretch(1, 1);
344 d->setCurrentItem(d->viewComboBox, d->viewtype);
345 d->setCurrentItem(d->formatComboBox, d->formattype);
347 connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
348 connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
349 parent->addPage(p, i18n("General"), icon());
352 void MenuLauncherApplet::configAccepted()
354 bool needssaving = false;
355 KConfigGroup cg = config();
357 const int vt = d->viewComboBox->itemData(d->viewComboBox->currentIndex()).toInt();
358 if (vt != d->viewtype) {
359 d->viewtype = (MenuLauncherApplet::ViewType) vt;
360 needssaving = true;
362 QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("ViewType"));
363 cg.writeEntry("view", QByteArray(e.valueToKey(d->viewtype)));
365 d->icon->setIcon(KIcon(d->viewIcon()));
366 d->icon->update();
369 const int ft = d->formatComboBox->itemData(d->formatComboBox->currentIndex()).toInt();
370 if (ft != d->formattype) {
371 d->formattype = (MenuLauncherApplet::FormatType) ft;
372 needssaving = true;
374 QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
375 cg.writeEntry("format", QByteArray(e.valueToKey(d->formattype)));
378 const int maxRecentApps = d->recentApplicationsSpinBox->value();
379 if (maxRecentApps != d->maxRecentApps) {
380 needssaving = true;
381 d->setMaxRecentApps(maxRecentApps);
382 cg.writeEntry("maxRecentApps", maxRecentApps);
385 if (needssaving) {
386 emit configNeedsSaving();
388 delete d->menuview;
389 d->menuview = 0;
393 void MenuLauncherApplet::toggleMenu(bool pressed)
395 if (pressed) {
396 toggleMenu();
400 void MenuLauncherApplet::toggleMenu()
402 if (!d->menuview) {
403 d->menuview = new Kickoff::MenuView();
404 connect(d->menuview, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*)));
405 connect(d->menuview, SIGNAL(aboutToHide()), d->icon, SLOT(setUnpressed()));
406 connect(d->menuview, SIGNAL(aboutToHide()), d->menuview, SLOT(deleteLater()));
408 switch (d->viewtype) {
409 case Combined: {
410 //if (Kickoff::RecentApplications::self()->recentApplications().size() > 0) {
411 if (d->maxRecentApps > 0) {
412 d->menuview->addTitle(i18n("Recently Used Applications"));
413 Kickoff::RecentlyUsedModel* recentlymodel = new Kickoff::RecentlyUsedModel(d->menuview, Kickoff::RecentlyUsedModel::ApplicationsOnly, d->maxRecentApps);
414 Kickoff::MenuView *recentlyview = d->createMenuView(recentlymodel);
415 d->addMenu(recentlyview, true);
418 d->menuview->addTitle(i18n("All Applications"));
419 Kickoff::ApplicationModel *appModel = new Kickoff::ApplicationModel(d->menuview);
420 appModel->setDuplicatePolicy(Kickoff::ApplicationModel::ShowLatestOnlyPolicy);
421 appModel->setSystemApplicationPolicy(Kickoff::ApplicationModel::ShowApplicationAndSystemPolicy);
422 Kickoff::MenuView *appview = d->createMenuView(appModel);
423 d->addMenu(appview, false);
425 d->menuview->addSeparator();
426 Kickoff::MenuView *favview = d->createMenuView(new Kickoff::FavoritesModel(d->menuview));
427 d->addMenu(favview, false);
429 d->menuview->addTitle(i18n("Actions"));
430 QAction *runaction = d->menuview->addAction(KIcon("system-run"), i18n("Run Command..."));
431 runaction->setData(KUrl("leave:/run"));
432 d->menuview->addSeparator();
433 QAction *switchaction = d->menuview->addAction(KIcon("system-switch-user"), i18n("Switch User"));
434 switchaction->setData(KUrl("leave:/switch"));
435 QAction *lockaction = d->menuview->addAction(KIcon("system-lock-screen"), i18n("Lock Screen"));
436 lockaction->setData(KUrl("leave:/lock"));
437 QAction *logoutaction = d->menuview->addAction(KIcon("system-shutdown"), i18n("Leave..."));
438 logoutaction->setData(KUrl("leave:/logout"));
440 break;
441 case Favorites: {
442 Kickoff::MenuView *favview = d->createMenuView(new Kickoff::FavoritesModel(d->menuview));
443 d->addMenu(favview, true);
445 break;
446 case Applications: {
447 Kickoff::ApplicationModel *appModel = new Kickoff::ApplicationModel(d->menuview);
448 appModel->setDuplicatePolicy(Kickoff::ApplicationModel::ShowLatestOnlyPolicy);
449 Kickoff::MenuView *appview = d->createMenuView(appModel);
450 d->addMenu(appview, false);
452 break;
453 case Computer: {
454 Kickoff::MenuView *systemview = d->createMenuView(new Kickoff::SystemModel(d->menuview));
455 d->addMenu(systemview, true);
457 break;
458 case RecentlyUsed: {
459 Kickoff::MenuView *recentlyview = d->createMenuView(new Kickoff::RecentlyUsedModel(d->menuview));
460 d->addMenu(recentlyview, true);
462 break;
463 case Bookmarks: {
464 KBookmarkManager* mgr = KBookmarkManager::userBookmarksManager();
465 if (! d->collection) {
466 d->collection = new KActionCollection(this);
467 d->bookmarkowner = new BookmarkOwner();
469 delete d->bookmarkmenu;
470 d->bookmarkmenu = new KBookmarkMenu(mgr, d->bookmarkowner, d->menuview, d->collection);
472 break;
473 case Leave: {
474 Kickoff::MenuView *leaveview = d->createMenuView(new Kickoff::LeaveModel(d->menuview));
475 d->addMenu(leaveview, true);
477 break;
481 d->menuview->setAttribute(Qt::WA_DeleteOnClose);
482 d->menuview->popup(popupPosition(d->menuview->sizeHint()));
483 d->icon->setPressed();
486 void MenuLauncherApplet::actionTriggered(QAction *action)
488 KUrl url = action->data().value<KUrl>();
489 if (url.scheme() == "leave") {
490 if (! d->launcher) {
491 d->launcher = new Kickoff::UrlItemLauncher(d->menuview);
493 d->launcher->openUrl(url.url());
494 return;
496 for (QWidget* w = action->parentWidget(); w; w = w->parentWidget()) {
497 if (Kickoff::MenuView *view = dynamic_cast<Kickoff::MenuView*>(w)) {
498 view->actionTriggered(action);
499 break;
504 QList<QAction*> MenuLauncherApplet::contextualActions()
506 return d->actions;
510 #include "simpleapplet.moc"