~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/desktop/applets/kickoff/simpleapplet/simpleapplet.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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>
 
5
 
 
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.
 
10
 
 
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.
 
15
 
 
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.
 
20
*/
 
21
 
 
22
// Own
 
23
#include "simpleapplet/simpleapplet.h"
 
24
#include "simpleapplet/menuview.h"
 
25
 
 
26
// Qt
 
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>
 
39
 
 
40
// KDE Libs
 
41
#include <KActionCollection>
 
42
#include <KAuthorized>
 
43
#include <KBookmarkMenu>
 
44
#include <KCModuleInfo>
 
45
#include <KComboBox>
 
46
#include <KConfigDialog>
 
47
#include <KIcon>
 
48
#include <KIconButton>
 
49
#include <KIconLoader>
 
50
#include <KMenu>
 
51
#include <KProcess>
 
52
#include <KRun>
 
53
#include <KServiceTypeTrader>
 
54
#include <KToolInvocation>
 
55
#include <Solid/PowerManagement>
 
56
 
 
57
// KDE Base
 
58
#include <kworkspace/kworkspace.h>
 
59
 
 
60
// Plasma
 
61
#include <Plasma/IconWidget>
 
62
#include <Plasma/Containment>
 
63
#include <Plasma/ToolTipManager>
 
64
 
 
65
// Local
 
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"
 
76
 
 
77
#ifndef KDE_USE_FINAL
 
78
Q_DECLARE_METATYPE(QPersistentModelIndex)
 
79
#endif
 
80
 
 
81
/// @internal KBookmarkOwner specialization
 
82
class BookmarkOwner : public KBookmarkOwner
 
83
{
 
84
public:
 
85
    BookmarkOwner() : KBookmarkOwner() {}
 
86
    virtual bool enableOption(BookmarkOption) const {
 
87
        return false;
 
88
    }
 
89
    virtual bool supportsTabs() const {
 
90
        return false;
 
91
    }
 
92
    virtual void openBookmark(const KBookmark& b, Qt::MouseButtons, Qt::KeyboardModifiers) {
 
93
        new KRun(b.url(), (QWidget*)0);
 
94
    }
 
95
};
 
96
 
 
97
/// @internal d-pointer class
 
98
class MenuLauncherApplet::Private
 
99
{
 
100
public:
 
101
    MenuLauncherApplet *q;
 
102
 
 
103
    QWeakPointer<Kickoff::MenuView> menuview;
 
104
    Plasma::IconWidget *icon;
 
105
    QString iconname;
 
106
    QWeakPointer<Kickoff::UrlItemLauncher> launcher;
 
107
 
 
108
    KActionCollection* bookmarkcollection;
 
109
    BookmarkOwner* bookmarkowner;
 
110
    KBookmarkMenu* bookmarkmenu;
 
111
 
 
112
    QStringList viewtypes;//QList<MenuLauncherApplet::ViewType>
 
113
    QString relativePath;
 
114
    MenuLauncherApplet::FormatType formattype;
 
115
    int maxRecentApps;
 
116
    bool showMenuTitles;
 
117
 
 
118
    QListWidget *view;
 
119
    KIconButton *iconButton;
 
120
    KComboBox *formatComboBox;
 
121
    QSpinBox *recentApplicationsSpinBox;
 
122
    QCheckBox *showMenuTitlesCheckBox;
 
123
 
 
124
    QList<QAction*> actions;
 
125
    QAction* switcher;
 
126
    Kickoff::ContextMenuFactory *contextMenuFactory;
 
127
 
 
128
    bool delayedConfigLoad;
 
129
 
 
130
    explicit Private(MenuLauncherApplet *q)
 
131
            : q(q),
 
132
              icon(0),
 
133
              bookmarkcollection(0),
 
134
              bookmarkowner(0),
 
135
              bookmarkmenu(0),
 
136
              view(0),
 
137
              iconButton(0),
 
138
              formatComboBox(0),
 
139
              showMenuTitlesCheckBox(0),
 
140
              switcher(0),
 
141
              contextMenuFactory(0)
 
142
    {}
 
143
 
 
144
    ~Private()
 
145
    {
 
146
        delete bookmarkmenu;
 
147
        delete bookmarkowner;
 
148
        delete menuview.data();
 
149
    }
 
150
 
 
151
    void setMaxRecentApps(int num) {
 
152
        maxRecentApps = qMax(0, num);
 
153
        if (maxRecentApps > Kickoff::RecentApplications::self()->maximum()) {
 
154
            Kickoff::RecentApplications::self()->setMaximum(maxRecentApps);
 
155
        }
 
156
    }
 
157
 
 
158
    void addItem(KComboBox* combo, const QString& caption, int index, const QString& icon = QString())
 
159
    {
 
160
        if (icon.isEmpty()) {
 
161
            combo->addItem(caption, index);
 
162
        } else {
 
163
            combo->addItem(KIcon(icon), caption, index);
 
164
        }
 
165
    }
 
166
 
 
167
    void setCurrentItem(KComboBox* combo, int currentIndex)
 
168
    {
 
169
        for (int i = combo->count() - 1; i >= 0; --i) {
 
170
            if (combo->itemData(i).toInt() == currentIndex) {
 
171
                combo->setCurrentIndex(i);
 
172
                return;
 
173
            }
 
174
        }
 
175
        if (combo->count() > 0)
 
176
            combo->setCurrentIndex(0);
 
177
    }
 
178
 
 
179
    void addModel(QAbstractItemModel *model, ViewType viewtype, Kickoff::MenuView::ModelOptions options = Kickoff::MenuView::MergeFirstLevel, int formattype = -1)
 
180
    {
 
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);
 
187
        }
 
188
        m->addModel(model, options);
 
189
    }
 
190
 
 
191
    QString viewText(MenuLauncherApplet::ViewType vt) const {
 
192
        switch (vt) {
 
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");
 
212
        }
 
213
        return QString();
 
214
    }
 
215
 
 
216
    QString viewIcon(MenuLauncherApplet::ViewType vt) const {
 
217
        switch (vt) {
 
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";
 
237
        }
 
238
        return QString();
 
239
    }
 
240
 
 
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);
 
244
    }
 
245
 
 
246
    /*
 
247
    QByteArray viewType(MenuLauncherApplet::ViewType type) const {
 
248
        QMetaEnum e = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewType"));
 
249
        return e.valueToKey(types);
 
250
    }
 
251
    QList<MenuLauncherApplet::ViewType> viewTypes(const QStringList &types) const {
 
252
        QList<MenuLauncherApplet::ViewType> l;
 
253
        foreach(QString t, types) l << viewType(t.toUtf());
 
254
        return l;
 
255
    }
 
256
    QStringList viewTypes(const QList<MenuLauncherApplet::ViewType> &types) const {
 
257
        QStringList l;
 
258
        foreach(MenuLauncherApplet::ViewType t, types) l << viewType(t);
 
259
        return l;
 
260
    }
 
261
    */
 
262
 
 
263
    void updateTooltip() {
 
264
        QStringList names;
 
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);
 
269
    }
 
270
};
 
271
 
 
272
MenuLauncherApplet::MenuLauncherApplet(QObject *parent, const QVariantList &args)
 
273
        : Plasma::Applet(parent, args),
 
274
        d(new Private(this))
 
275
{
 
276
    KGlobal::locale()->insertCatalog("plasma_applet_launcher");
 
277
 
 
278
    setAspectRatioMode(Plasma::ConstrainedSquare);
 
279
    setHasConfigurationInterface(true);
 
280
    setBackgroundHints(NoBackground);
 
281
 
 
282
    resize(IconSize(KIconLoader::Desktop) * 2, IconSize(KIconLoader::Desktop) * 2);
 
283
 
 
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()));
 
288
 
 
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();
 
295
            break;
 
296
        }
 
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)
 
301
        }
 
302
        default: { //Default configuration
 
303
            d->viewtypes << "RecentlyUsedApplications" << "Applications" << "Favorites";
 
304
            if (KAuthorized::authorize("run_command")) {
 
305
                d->viewtypes << "RunCommand";
 
306
            }
 
307
            d->viewtypes << "Leave";
 
308
            d->iconname = "start-here-kde";
 
309
        }
 
310
    }
 
311
    d->formattype = NameDescription;
 
312
 
 
313
    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
 
314
    layout->setContentsMargins(0, 0, 0, 0);
 
315
    layout->setSpacing(0);
 
316
    layout->addItem(d->icon);
 
317
 
 
318
    d->contextMenuFactory = new Kickoff::ContextMenuFactory(this);
 
319
    d->contextMenuFactory->setApplet(this);
 
320
}
 
321
 
 
322
MenuLauncherApplet::~MenuLauncherApplet()
 
323
{
 
324
    delete d;
 
325
}
 
326
 
 
327
void MenuLauncherApplet::init()
 
328
{
 
329
    bool receivedArgs = false;
 
330
    if (!d->relativePath.isEmpty()) {
 
331
        receivedArgs = true;
 
332
    }
 
333
 
 
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()));
 
338
 
 
339
    configChanged();
 
340
 
 
341
    Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ExtensionHandler, "desktop", new Kickoff::ServiceItemHandler);
 
342
    Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ProtocolHandler, "leave", new Kickoff::LeaveItemHandler);
 
343
 
 
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()));
 
348
    }
 
349
 
 
350
    if (receivedArgs) {
 
351
        KConfigGroup cg = config();
 
352
        cg.writeEntry("relativePath", d->relativePath);
 
353
        cg.writeEntry("icon", d->iconname);
 
354
        emit configNeedsSaving();
 
355
    }
 
356
 
 
357
    connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
 
358
        this, SLOT(iconSizeChanged(int)));
 
359
}
 
360
 
 
361
void MenuLauncherApplet::constraintsEvent(Plasma::Constraints constraints)
 
362
{
 
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)));
 
368
        } else {
 
369
            //setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Small)));
 
370
        }
 
371
    }
 
372
 
 
373
    if ((constraints & Plasma::ImmutableConstraint) && d->switcher) {
 
374
        d->switcher->setVisible(immutability() == Plasma::Mutable);
 
375
    }
 
376
}
 
377
 
 
378
void MenuLauncherApplet::switchMenuStyle()
 
379
{
 
380
    if (containment()) {
 
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()));
 
386
 
 
387
        //Switch shortcuts with the new launcher to avoid losing it
 
388
        KShortcut currentShortcut = globalShortcut();
 
389
        setGlobalShortcut(KShortcut());
 
390
        launcher->setGlobalShortcut(currentShortcut);
 
391
        destroy();
 
392
    }
 
393
}
 
394
 
 
395
void MenuLauncherApplet::startMenuEditor()
 
396
{
 
397
    KProcess::execute("kmenuedit");
 
398
}
 
399
 
 
400
void MenuLauncherApplet::customContextMenuRequested(QMenu* menu, const QPoint& pos)
 
401
{
 
402
    if (!menu) {
 
403
        return;
 
404
    }
 
405
 
 
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);
 
414
    } else { // case 2)
 
415
        menuAction = menu->menuAction();
 
416
        if (menuAction) {
 
417
            const QPersistentModelIndex index = menuAction->data().value<QPersistentModelIndex>();
 
418
            d->contextMenuFactory->showContextMenu(0, index, pos);
 
419
        }
 
420
    }
 
421
}
 
422
 
 
423
void MenuLauncherApplet::createConfigurationInterface(KConfigDialog *parent)
 
424
{
 
425
    d->view = 0;
 
426
    d->recentApplicationsSpinBox = 0;
 
427
    if (d->relativePath.isEmpty()) {
 
428
        QWidget *viewpage = new QWidget(parent);
 
429
        QVBoxLayout *l = new QVBoxLayout(viewpage);
 
430
        l->setMargin(0);
 
431
        viewpage->setLayout(l);
 
432
        d->view = new QListWidget(viewpage);
 
433
        d->view->resize(300,500);
 
434
        l->addWidget(d->view);
 
435
 
 
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);
 
444
        }
 
445
        parent->addPage(viewpage, i18n("View"), "view-list-details");
 
446
    }
 
447
 
 
448
    QWidget *p = new QWidget(parent);
 
449
    QGridLayout *grid = new QGridLayout(p);
 
450
    grid->setMargin(0);
 
451
 
 
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);
 
458
 
 
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);
 
470
 
 
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);
 
480
    }
 
481
 
 
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);
 
487
 
 
488
    grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 4, 0, 1, 3);
 
489
    parent->addPage(p, i18n("Options"), "configure");
 
490
 
 
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()));    
 
498
}
 
499
 
 
500
void MenuLauncherApplet::configAccepted()
 
501
{
 
502
    bool needssaving = false;
 
503
    KConfigGroup cg = config();
 
504
 
 
505
    if (d->view) {
 
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)
 
511
                viewtypes << vtname;
 
512
            if( !needssaving && ((item->checkState() == Qt::Checked && ! d->viewtypes.contains(vtname)) || (item->checkState() == Qt::Unchecked && d->viewtypes.contains(vtname))) )
 
513
                needssaving = true;
 
514
        }
 
515
        if(needssaving) {
 
516
            d->viewtypes = viewtypes;
 
517
            d->updateTooltip();
 
518
            cg.writeEntry("views", d->viewtypes);
 
519
            cg.deleteEntry("view"); // "view" was from <KDE4.3, we are using "views" now
 
520
        }
 
521
    }
 
522
 
 
523
    const QString iconname = d->iconButton->icon();
 
524
    if (! iconname.isEmpty()) {
 
525
        needssaving = true;
 
526
        d->icon->setIcon(KIcon(iconname));
 
527
        d->updateTooltip();
 
528
        cg.writeEntry("icon", iconname);
 
529
    }
 
530
 
 
531
    const int ft = d->formatComboBox->itemData(d->formatComboBox->currentIndex()).toInt();
 
532
    if (ft != d->formattype) {
 
533
        needssaving = true;
 
534
        d->formattype = (MenuLauncherApplet::FormatType) ft;
 
535
        QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
 
536
        cg.writeEntry("format", QByteArray(e.valueToKey(d->formattype)));
 
537
    }
 
538
 
 
539
    if (d->recentApplicationsSpinBox) {
 
540
        const int maxRecentApps = d->recentApplicationsSpinBox->value();
 
541
        if (maxRecentApps != d->maxRecentApps) {
 
542
            needssaving = true;
 
543
            d->setMaxRecentApps(maxRecentApps);
 
544
            cg.writeEntry("maxRecentApps", maxRecentApps);
 
545
        }
 
546
    }
 
547
 
 
548
    const bool showMenuTitles = d->showMenuTitlesCheckBox->isChecked();
 
549
    if (showMenuTitles != d->showMenuTitles) {
 
550
        needssaving = true;
 
551
        d->showMenuTitles = showMenuTitles;
 
552
        cg.writeEntry("showMenuTitles", showMenuTitles);
 
553
    }
 
554
 
 
555
    if (needssaving) {
 
556
        d->updateTooltip();
 
557
        emit configNeedsSaving();
 
558
        if (d->menuview) {
 
559
            d->menuview.data()->deleteLater();
 
560
        }
 
561
    }
 
562
}
 
563
 
 
564
inline int weightOfService( const KService::Ptr service )
 
565
{
 
566
    QVariant tmp = service->property("X-KDE-Weight", QVariant::Int);
 
567
    return (tmp.isValid() ? tmp.toInt() : 100);
 
568
}
 
569
inline bool sortServiceItemsByWeight(const KService::Ptr left, const KService::Ptr right)
 
570
{
 
571
    return weightOfService(left) < weightOfService(right);
 
572
}
 
573
KService::List sortServices(KService::List list)
 
574
{
 
575
    qSort(list.begin(), list.end(), sortServiceItemsByWeight);
 
576
    return list;
 
577
}
 
578
 
 
579
void MenuLauncherApplet::toggleMenu()
 
580
{
 
581
    showMenu(!d->menuview || !d->menuview.data()->isVisible());
 
582
}
 
583
 
 
584
void MenuLauncherApplet::showMenu(bool pressed)
 
585
{
 
586
    if (!pressed || d->viewtypes.count()<=0) {
 
587
        if (d->menuview) {
 
588
            d->menuview.data()->deleteLater();
 
589
            d->menuview.clear();
 
590
        }
 
591
 
 
592
        return;
 
593
    }
 
594
 
 
595
    d->icon->setPressed();
 
596
 
 
597
    if (!d->menuview) {
 
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()));
 
608
 
 
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*/);
 
613
 
 
614
                appModel->setNameDisplayOrder(Kickoff::NameBeforeDescription);
 
615
 
 
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);
 
620
 
 
621
                menuview->addModel(appModel, Kickoff::MenuView::None, d->relativePath);
 
622
 
 
623
                if (d->relativePath.isEmpty()) {
 
624
                    if (d->showMenuTitles) {
 
625
                        menuview->setModelTitleVisible(appModel, true);
 
626
                        menuview->addTitle(i18n("Actions"));
 
627
                    } else {
 
628
                        menuview->addSeparator();
 
629
                    }
 
630
                }
 
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);
 
641
 
 
642
                    if (d->showMenuTitles) {
 
643
                        menuview->setModelTitleVisible(recentModel, true);
 
644
                    } else {
 
645
                        menuview->addSeparator();
 
646
                    }
 
647
                }
 
648
            } else if(vtname == "RecentlyUsedDocuments") {
 
649
                Kickoff::RecentlyUsedModel *recentModel = new Kickoff::RecentlyUsedModel(menuview, Kickoff::RecentlyUsedModel::DocumentsOnly);
 
650
                menuview->addModel(recentModel, Kickoff::MenuView::MergeFirstLevel);
 
651
 
 
652
                if (d->showMenuTitles) {
 
653
                    menuview->setModelTitleVisible(recentModel, true);
 
654
                } else {
 
655
                    menuview->addSeparator();
 
656
                }
 
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);
 
663
                }
 
664
                KBookmarkManager* mgr = KBookmarkManager::userBookmarksManager();
 
665
                if (! d->bookmarkcollection) {
 
666
                    d->bookmarkcollection = new KActionCollection(this);
 
667
                    d->bookmarkowner = new BookmarkOwner();
 
668
                }
 
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);
 
677
                }
 
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;
 
688
                    }
 
689
                }
 
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;
 
695
                }
 
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();
 
705
                        } else {
 
706
                            subcategory = services[0];
 
707
                            menucategory = subcategory->property("X-KDE-System-Settings-Parent-Category").toString();
 
708
                        }
 
709
                    }
 
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()));
 
717
                    }
 
718
                }
 
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"));
 
722
                }
 
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);
 
737
            } else {
 
738
#ifndef Q_WS_WIN
 
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"));
 
755
                }
 
756
#endif
 
757
            }
 
758
        }
 
759
    }
 
760
 
 
761
    Plasma::ToolTipManager::self()->hide(this);
 
762
    setStatus(Plasma::NeedsAttentionStatus);
 
763
    d->menuview.data()->popup(popupPosition(d->menuview.data()->sizeHint()));
 
764
}
 
765
 
 
766
void MenuLauncherApplet::menuHiding()
 
767
{
 
768
    d->icon->setUnpressed();
 
769
    setStatus(Plasma::PassiveStatus);
 
770
}
 
771
 
 
772
void MenuLauncherApplet::actionTriggered(QAction *action)
 
773
{
 
774
    const KUrl url = action->data().value<KUrl>();
 
775
    if (url.scheme() == "leave") {
 
776
        if (!d->launcher) {
 
777
            d->launcher = new Kickoff::UrlItemLauncher(d->menuview.data());
 
778
        }
 
779
 
 
780
        d->launcher.data()->openUrl(url.url());
 
781
        return;
 
782
    }
 
783
    if (url.scheme() == "kcm") {
 
784
        KToolInvocation::kdeinitExec("kcmshell4",  QStringList() << url.fileName());
 
785
        return;
 
786
    }
 
787
    for (QWidget* w = action->parentWidget(); w; w = w->parentWidget()) {
 
788
        if (Kickoff::MenuView *view = dynamic_cast<Kickoff::MenuView*>(w)) {
 
789
            view->actionTriggered(action);
 
790
            break;
 
791
        }
 
792
    }
 
793
}
 
794
 
 
795
QList<QAction*> MenuLauncherApplet::contextualActions()
 
796
{
 
797
    return d->actions;
 
798
}
 
799
 
 
800
void MenuLauncherApplet::iconSizeChanged(int group)
 
801
{
 
802
    if (group == KIconLoader::Desktop || group == KIconLoader::Panel) {
 
803
        updateGeometry();
 
804
    }
 
805
}
 
806
 
 
807
QSizeF MenuLauncherApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
 
808
{
 
809
    if (which == Qt::PreferredSize) {
 
810
        int iconSize;
 
811
 
 
812
        switch (formFactor()) {
 
813
            case Plasma::Planar:
 
814
            case Plasma::MediaCenter:
 
815
                iconSize = IconSize(KIconLoader::Desktop);
 
816
                break;
 
817
 
 
818
            case Plasma::Horizontal:
 
819
            case Plasma::Vertical:
 
820
                iconSize = IconSize(KIconLoader::Panel);
 
821
                break;
 
822
        }
 
823
 
 
824
        return QSizeF(iconSize, iconSize);
 
825
    }
 
826
 
 
827
    return Plasma::Applet::sizeHint(which, constraint);
 
828
}
 
829
 
 
830
 
 
831
void MenuLauncherApplet::saveConfigurationFromKickoff(const KConfigGroup & configGroup, const KConfigGroup & globalConfigGroup)
 
832
{
 
833
    //Copy configuration values
 
834
    KConfigGroup cg = config();
 
835
    configGroup.copyTo(&cg);
 
836
 
 
837
    KConfigGroup gcg = globalConfig();
 
838
    globalConfigGroup.copyTo(&gcg);
 
839
 
 
840
    configChanged();
 
841
    emit configNeedsSaving();
 
842
}
 
843
 
 
844
void MenuLauncherApplet::configChanged()
 
845
{
 
846
    KConfigGroup cg = config();
 
847
 
 
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
 
855
    } else {
 
856
        d->viewtypes = viewtypes;
 
857
    }
 
858
 
 
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);
 
862
 
 
863
    d->setMaxRecentApps(cg.readEntry("maxRecentApps", qMin(5, Kickoff::RecentApplications::self()->maximum())));
 
864
    d->showMenuTitles = cg.readEntry("showMenuTitles", false);
 
865
 
 
866
    d->icon->setIcon(KIcon(cg.readEntry("icon", d->iconname)));
 
867
 
 
868
    d->relativePath = cg.readEntry("relativePath", d->relativePath);
 
869
    if (!d->relativePath.isEmpty()) {
 
870
        d->viewtypes.clear();
 
871
        d->viewtypes << "Applications";
 
872
    }
 
873
 
 
874
    d->updateTooltip();
 
875
 
 
876
    constraintsEvent(Plasma::ImmutableConstraint);
 
877
}
 
878
 
 
879
#include "simpleapplet.moc"