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

« back to all changes in this revision

Viewing changes to plasma/desktop/shell/activitymanager/activityicon.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 2010 Chani Armitage <chani@kde.org>
 
3
 *   Copyright 2010 Ivan Cukic <ivan.cukic(at)kde.org>
 
4
 *
 
5
 *   This program is free software; you can redistribute it and/or modify
 
6
 *   it under the terms of the GNU Library/Lesser General Public License
 
7
 *   version 2, or (at your option) any later version, as published by the
 
8
 *   Free Software Foundation
 
9
 *
 
10
 *   This program 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
 
13
 *   GNU General Public License for more details
 
14
 *
 
15
 *   You should have received a copy of the GNU Library/Lesser General Public
 
16
 *   License along with this program; if not, write to the
 
17
 *   Free Software Foundation, Inc.,
 
18
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
19
 */
 
20
 
 
21
#include "activityicon.h"
 
22
 
 
23
#include "activity.h"
 
24
#include "activitycontrols.h"
 
25
#include "desktopcorona.h"
 
26
#include "plasmaapp.h"
 
27
 
 
28
#include <QGraphicsLinearLayout>
 
29
#include <QGraphicsSceneMouseEvent>
 
30
#include <QGraphicsGridLayout>
 
31
#include <QPainter>
 
32
#include <QCursor>
 
33
#include <QSizePolicy>
 
34
 
 
35
#include <KIconLoader>
 
36
#include <KIcon>
 
37
#include <KStandardDirs>
 
38
#include <KGlobalSettings>
 
39
 
 
40
#include <Plasma/Label>
 
41
#include <Plasma/PushButton>
 
42
#include <Plasma/LineEdit>
 
43
#include <Plasma/IconWidget>
 
44
#include <Plasma/Package>
 
45
 
 
46
#include <scripting/layouttemplatepackagestructure.h>
 
47
#include "scripting/desktopscriptengine.h"
 
48
 
 
49
#define REMOVE_ICON KIcon("edit-delete")
 
50
#define STOP_ICON KIcon("media-playback-stop")
 
51
#define START_ICON KIcon("media-playback-start")
 
52
#define CONFIGURE_ICON KIcon("configure")
 
53
 
 
54
class ActivityActionWidget: public QGraphicsWidget {
 
55
public:
 
56
    ActivityActionWidget(ActivityIcon * parent, const QString & slot,
 
57
            const KIcon & icon, const QString & tooltip, const QSize & size = QSize(16, 16))
 
58
        : QGraphicsWidget(parent), m_parent(parent), m_slot(slot), m_iconSize(size), m_icon(icon)
 
59
    {
 
60
        setToolTip(tooltip);
 
61
        setMinimumSize(m_iconSize);
 
62
        setPreferredSize(m_iconSize);
 
63
        setMaximumSize(m_iconSize);
 
64
 
 
65
        setGeometry(0, 0, m_iconSize.width(), m_iconSize.height());
 
66
        setZValue(1);
 
67
    }
 
68
 
 
69
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
 
70
    {
 
71
        QGraphicsWidget::paint(painter, option, widget);
 
72
        painter->drawPixmap(0, 0, m_icon.pixmap(m_iconSize));
 
73
    }
 
74
 
 
75
    void mousePressEvent(QGraphicsSceneMouseEvent * event)
 
76
    {
 
77
        QGraphicsWidget::mouseReleaseEvent(event);
 
78
 
 
79
        if (event->button() != Qt::LeftButton)
 
80
            return;
 
81
 
 
82
        QMetaObject::invokeMethod(m_parent, m_slot.toAscii());
 
83
 
 
84
        event->accept();
 
85
    }
 
86
 
 
87
    ActivityIcon * m_parent;
 
88
    QString m_slot;
 
89
    QSize m_iconSize;
 
90
    KIcon m_icon;
 
91
 
 
92
};
 
93
 
 
94
ActivityIcon::ActivityIcon(const QString &id)
 
95
    : AbstractIcon(0),
 
96
      m_buttonStop(0),
 
97
      m_buttonRemove(0),
 
98
      m_buttonStart(0),
 
99
      m_buttonConfigure(0),
 
100
      m_closable(false),
 
101
      m_inlineWidgetAnim(0)
 
102
{
 
103
    DesktopCorona *c = qobject_cast<DesktopCorona*>(PlasmaApp::self()->corona());
 
104
    m_activity = c->activity(id);
 
105
 
 
106
    updateButtons();
 
107
 
 
108
    connect(this, SIGNAL(clicked(Plasma::AbstractIcon*)), m_activity, SLOT(activate()));
 
109
    connect(m_activity, SIGNAL(stateChanged()), this, SLOT(updateButtons()));
 
110
    connect(m_activity, SIGNAL(infoChanged()), this, SLOT(updateContents()));
 
111
    connect(m_activity, SIGNAL(currentStatusChanged()), this, SLOT(currentStatusChanged()));
 
112
    setName(m_activity->name());
 
113
    currentStatusChanged();
 
114
 
 
115
    setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
 
116
}
 
117
 
 
118
ActivityIcon::ActivityIcon(const QString &name, const QString &icon, const QString &plugin)
 
119
    : AbstractIcon(0),
 
120
      m_buttonStop(0),
 
121
      m_buttonRemove(0),
 
122
      m_buttonStart(0),
 
123
      m_buttonConfigure(0),
 
124
      m_icon(icon),
 
125
      m_iconName(icon), 
 
126
      m_pluginName(plugin),
 
127
      m_closable(false),
 
128
      m_activity(0),
 
129
      m_inlineWidgetAnim(0)
 
130
{
 
131
    DesktopCorona *c = qobject_cast<DesktopCorona*>(PlasmaApp::self()->corona());
 
132
 
 
133
    updateButtons();
 
134
 
 
135
    connect(this, SIGNAL(clicked(Plasma::AbstractIcon*)),
 
136
            this, SLOT(createActivity(Plasma::AbstractIcon*)));
 
137
    setName(name);
 
138
    currentStatusChanged();
 
139
 
 
140
    setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
 
141
}
 
142
 
 
143
void ActivityIcon::createActivity(Plasma::AbstractIcon * icon)
 
144
{
 
145
    KService::Ptr service = KService::serviceByStorageId(m_pluginName);
 
146
 
 
147
    KPluginInfo info(service);
 
148
    Plasma::PackageStructure::Ptr structure(new WorkspaceScripting::LayoutTemplatePackageStructure);
 
149
 
 
150
    const QString path = KStandardDirs::locate("data", structure->defaultPackageRoot() + '/' + info.pluginName() + '/');
 
151
    if (!path.isEmpty()) {
 
152
        Plasma::Package package(path, structure);
 
153
        const QString scriptFile = package.filePath("mainscript");
 
154
        const QStringList startupApps = service->property("X-Plasma-ContainmentLayout-ExecuteOnCreation", QVariant::StringList).toStringList();
 
155
 
 
156
        if (!scriptFile.isEmpty() || !startupApps.isEmpty()) {
 
157
            PlasmaApp::self()->createActivityFromScript(
 
158
                scriptFile,
 
159
                name(),
 
160
                m_iconName,
 
161
                startupApps
 
162
            );
 
163
        }
 
164
 
 
165
 
 
166
        KConfig config("plasma-desktoprc");
 
167
        KConfigGroup group(&config, "ActivityManager HiddenTemplates");
 
168
 
 
169
        group.writeEntry(m_pluginName, true);
 
170
        group.sync();
 
171
 
 
172
        emit requestsRemoval(false);
 
173
    }
 
174
}
 
175
 
 
176
ActivityIcon::~ActivityIcon()
 
177
{
 
178
}
 
179
 
 
180
QPixmap ActivityIcon::pixmap(const QSize &size)
 
181
{
 
182
    if (m_activity) {
 
183
        return m_activity->pixmap(size);
 
184
    } else {
 
185
        return m_icon.pixmap(size);
 
186
    }
 
187
}
 
188
 
 
189
QMimeData* ActivityIcon::mimeData()
 
190
{
 
191
    //TODO: how shall we use d&d?
 
192
    return 0;
 
193
}
 
194
 
 
195
class MakeRoomAnimation : public QAbstractAnimation
 
196
{
 
197
public:
 
198
    MakeRoomAnimation(ActivityIcon *icon, qreal addedWidth, QObject *parent)
 
199
        : QAbstractAnimation(parent),
 
200
          m_icon(icon),
 
201
          m_addWidth(addedWidth)
 
202
    {
 
203
        m_startSize = icon->geometry().size();
 
204
        m_icon->getContentsMargins(0, 0, &m_startRightMargin, 0);
 
205
    }
 
206
 
 
207
    int duration() const
 
208
    {
 
209
        return 100;
 
210
    }
 
211
 
 
212
    void updateCurrentTime(int currentTime)
 
213
    {
 
214
        const qreal delta = currentTime / (float) duration();
 
215
 
 
216
        m_icon->setPreferredSize(m_startSize + QSizeF(m_addWidth * delta, 0));
 
217
 
 
218
        qreal left, top, right, bottom;
 
219
        m_icon->getContentsMargins(&left, &top, &right, &bottom);
 
220
 
 
221
        right = m_startRightMargin + m_addWidth * delta;
 
222
 
 
223
        m_icon->setContentsMargins(left, top, right, bottom);
 
224
    }
 
225
 
 
226
private:
 
227
    ActivityIcon * m_icon;
 
228
    QSizeF m_startSize;
 
229
    qreal m_addWidth;
 
230
    qreal m_startRightMargin;
 
231
};
 
232
 
 
233
void ActivityIcon::showInlineWidget(ActivityControls * w)
 
234
{
 
235
    hideInlineWidget(true);
 
236
 
 
237
    connect(w, SIGNAL(closed()), this, SLOT(hideInlineWidget()));
 
238
 
 
239
    w->setMaximumSize(QSize(0, size().height()));
 
240
    w->adjustSize();
 
241
    w->setPos(contentsRect().topRight() + QPoint(4, 0));
 
242
    w->setZValue(2);
 
243
 
 
244
    m_inlineWidget = w;
 
245
    QTimer::singleShot(0, this, SLOT(startInlineAnim()));
 
246
}
 
247
 
 
248
void ActivityIcon::showRemovalConfirmation()
 
249
{
 
250
    ActivityControls * w = new ActivityRemovalConfirmation(this);
 
251
 
 
252
    if (m_activity)
 
253
        connect(w, SIGNAL(removalConfirmed()), m_activity, SLOT(remove()));
 
254
    else
 
255
        connect(w, SIGNAL(removalConfirmed()), this, SLOT(hideTemplate()));
 
256
 
 
257
    showInlineWidget(w);
 
258
}
 
259
 
 
260
void ActivityIcon::showConfiguration()
 
261
{
 
262
    if (m_activity)
 
263
        showInlineWidget(new ActivityConfiguration(this, m_activity));
 
264
}
 
265
 
 
266
void ActivityIcon::startInlineAnim()
 
267
{
 
268
    QGraphicsWidget * w = m_inlineWidget.data();
 
269
    //kDebug() << "Booh yah!" << w;
 
270
    if (!w) {
 
271
        return;
 
272
    }
 
273
 
 
274
    //kDebug() << w->preferredSize() << w->layout()->preferredSize();
 
275
    if (!m_inlineWidgetAnim) {
 
276
        m_inlineWidgetAnim = new MakeRoomAnimation(this, w->layout()->preferredSize().width() + 4, this);
 
277
        connect(m_inlineWidgetAnim, SIGNAL(finished()), this, SLOT(makeInlineWidgetVisible()));
 
278
    }
 
279
 
 
280
    m_inlineWidgetAnim->start();
 
281
}
 
282
 
 
283
void ActivityIcon::hideInlineWidget(bool aboutToShowAnother)
 
284
{
 
285
    if (m_inlineWidget) {
 
286
        m_inlineWidget.data()->deleteLater();
 
287
        m_inlineWidget.data()->hide();
 
288
    }
 
289
 
 
290
    if (m_inlineWidgetAnim && !aboutToShowAnother) {
 
291
        m_inlineWidgetAnim->setDirection(QAbstractAnimation::Backward);
 
292
        if (m_inlineWidgetAnim->state() != QAbstractAnimation::Running) {
 
293
            m_inlineWidgetAnim->start(QAbstractAnimation::DeleteWhenStopped);
 
294
            m_inlineWidgetAnim = 0;
 
295
        }
 
296
    }
 
297
}
 
298
 
 
299
void ActivityIcon::makeInlineWidgetVisible()
 
300
{
 
301
    if (m_inlineWidget) {
 
302
        m_inlineWidget.data()->show();
 
303
    }
 
304
}
 
305
 
 
306
void ActivityIcon::setClosable(bool closable)
 
307
{
 
308
    if (closable == m_closable) {
 
309
        return;
 
310
    }
 
311
 
 
312
    m_closable = closable;
 
313
    updateButtons();
 
314
}
 
315
 
 
316
Activity* ActivityIcon::activity()
 
317
{
 
318
    return m_activity;
 
319
}
 
320
 
 
321
void ActivityIcon::activityRemoved()
 
322
{
 
323
    m_activity = 0;
 
324
    deleteLater();
 
325
}
 
326
 
 
327
void ActivityIcon::setGeometry(const QRectF & geometry)
 
328
{
 
329
    Plasma::AbstractIcon::setGeometry(geometry);
 
330
    updateLayout();
 
331
}
 
332
 
 
333
void ActivityIcon::updateLayout()
 
334
{
 
335
    QRectF rect = contentsRect();
 
336
 
 
337
    rect.adjust(
 
338
            (rect.width() - iconSize()) / 2,
 
339
            rect.height() - iconSize(),
 
340
            - (rect.width() - iconSize()) / 2,
 
341
            0
 
342
            );
 
343
 
 
344
    if (m_buttonStop) {
 
345
        m_buttonStop->setGeometry(QRectF(
 
346
            rect.topRight() - QPointF(m_buttonStop->m_iconSize.width(), 0),
 
347
            m_buttonStop->m_iconSize
 
348
        ));
 
349
    }
 
350
 
 
351
    if (m_buttonRemove) {
 
352
        m_buttonRemove->setGeometry(QRectF(
 
353
            rect.topRight() - QPointF(m_buttonRemove->m_iconSize.width(), 0),
 
354
            m_buttonRemove->m_iconSize
 
355
        ));
 
356
    }
 
357
 
 
358
    if (m_buttonConfigure) {
 
359
        m_buttonConfigure->setGeometry(QRectF(
 
360
            rect.bottomRight() - QPointF(m_buttonConfigure->m_iconSize.width(), m_buttonConfigure->m_iconSize.height()),
 
361
            m_buttonConfigure->m_iconSize
 
362
        ));
 
363
    }
 
364
 
 
365
    if (m_buttonStart) {
 
366
        m_buttonStart->setGeometry(QRectF(
 
367
            rect.center() - QPointF(m_buttonStart->m_iconSize.width() / 2, m_buttonStart->m_iconSize.height() / 2),
 
368
            m_buttonStart->m_iconSize
 
369
        ));
 
370
    }
 
371
}
 
372
 
 
373
void ActivityIcon::updateButtons()
 
374
{
 
375
    if (m_activity) {
 
376
 
 
377
        if (!m_buttonConfigure) {
 
378
            m_buttonConfigure = new ActivityActionWidget(this, "showConfiguration", CONFIGURE_ICON, i18n("Configure activity"));
 
379
        }
 
380
 
 
381
        #define DESTROY_ACTIVITY_ACTION_WIDIGET(A) \
 
382
        if (A) {                               \
 
383
            A->hide();                         \
 
384
            A->deleteLater();                  \
 
385
            A = 0;                             \
 
386
        }
 
387
 
 
388
        switch (m_activity->state()) {
 
389
            case KActivityInfo::Running:
 
390
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonStart);
 
391
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonRemove);
 
392
 
 
393
                if (m_closable) {
 
394
                    if (!m_buttonStop) {
 
395
                        m_buttonStop = new ActivityActionWidget(this, "stopActivity", STOP_ICON, i18n("Stop activity"));
 
396
                    }
 
397
                } else {
 
398
                    DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonStop);
 
399
                }
 
400
                break;
 
401
 
 
402
            case KActivityInfo::Stopped:
 
403
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonStop);
 
404
 
 
405
                if (!m_buttonRemove) {
 
406
                    m_buttonRemove = new ActivityActionWidget(this, "showRemovalConfirmation", REMOVE_ICON, i18n("Stop activity"));
 
407
                }
 
408
 
 
409
                if (!m_buttonStart) {
 
410
                    m_buttonStart = new ActivityActionWidget(this, "startActivity", START_ICON, i18n("Start activity"), QSize(32, 32));
 
411
                }
 
412
                break;
 
413
 
 
414
            case KActivityInfo::Invalid:
 
415
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonConfigure);
 
416
                // no break
 
417
 
 
418
            default: //transitioning or invalid: don't let the user mess with it
 
419
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonStart);
 
420
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonRemove);
 
421
                DESTROY_ACTIVITY_ACTION_WIDIGET(m_buttonStop);
 
422
        }
 
423
 
 
424
        #undef DESTROY_ACTIVITY_ACTION_WIDIGET
 
425
 
 
426
    } else {
 
427
        if (!m_buttonRemove) {
 
428
            m_buttonRemove = new ActivityActionWidget(this, "showRemovalConfirmation", REMOVE_ICON, i18n("Stop activity"));
 
429
        }
 
430
    }
 
431
 
 
432
    updateLayout();
 
433
}
 
434
 
 
435
void ActivityIcon::stopActivity()
 
436
{
 
437
    if (m_activity) {
 
438
        m_activity->close();
 
439
    }
 
440
}
 
441
 
 
442
void ActivityIcon::startActivity()
 
443
{
 
444
    emit clicked(this);
 
445
}
 
446
 
 
447
void ActivityIcon::updateContents()
 
448
{
 
449
    if (m_activity)
 
450
        setName(m_activity->name());
 
451
    update();
 
452
}
 
453
 
 
454
void ActivityIcon::currentStatusChanged()
 
455
{
 
456
    if (m_activity)
 
457
        setSelected(m_activity->isCurrent());
 
458
}
 
459
 
 
460
void ActivityIcon::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
 
461
{
 
462
    if (m_inlineWidget && m_inlineWidget.data()->hidesContents()) {
 
463
        paintBackground(painter, option, widget);
 
464
        return;
 
465
    }
 
466
 
 
467
    AbstractIcon::paint(painter, option, widget);
 
468
}
 
469
 
 
470
void ActivityIcon::hideTemplate()
 
471
{
 
472
    KConfig config("plasma-desktoprc");
 
473
    KConfigGroup group(&config, "ActivityManager HiddenTemplates");
 
474
 
 
475
    group.writeEntry(m_pluginName, true);
 
476
    group.sync();
 
477
 
 
478
    emit requestsRemoval(true);
 
479
}
 
480
 
 
481
#include "activityicon.moc"
 
482