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

« back to all changes in this revision

Viewing changes to plasma/generic/applets/notifications/ui/busywidget.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 (C) 2008, 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
 
3
 *   Copyright (C) 2010 Marco Martin <notmart@gmail.com>                   *
 
4
 *                                                                         *
 
5
 *   This program is free software; you can redistribute it and/or modify  *
 
6
 *   it under the terms of the GNU General Public License as published by  *
 
7
 *   the Free Software Foundation; either version 2 of the License, or     *
 
8
 *   (at your option) any later version.                                   *
 
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 General Public License     *
 
16
 *   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 "busywidget.h"
 
22
#include <fixx11h.h>
 
23
 
 
24
#include <QtGui/QPainter>
 
25
#include <QtGui/QTextOption>
 
26
#include <QtGui/QStyleOptionGraphicsItem>
 
27
#include <QtGui/QWidget> // QWIDGETSIZE_MAX
 
28
#include <QSequentialAnimationGroup>
 
29
 
 
30
#include <plasma/extender.h>
 
31
#include <plasma/extenderitem.h>
 
32
#include <plasma/extendergroup.h>
 
33
#include <plasma/popupapplet.h>
 
34
#include <plasma/tooltipmanager.h>
 
35
#include <plasma/theme.h>
 
36
#include <Plasma/Animation>
 
37
#include <Plasma/Animator>
 
38
 
 
39
#include <KIcon>
 
40
#include <KGlobalSettings>
 
41
 
 
42
#include "../core/notificationsmanager.h"
 
43
#include "../core/job.h"
 
44
#include "../core/notification.h"
 
45
#include "../core/completedjobnotification.h"
 
46
 
 
47
 
 
48
 
 
49
BusyWidget::BusyWidget(Plasma::PopupApplet *parent, const Manager *manager)
 
50
    : Plasma::BusyWidget(parent),
 
51
      m_icon("dialog-information"),
 
52
      m_state(Empty),
 
53
      m_svg(new Plasma::Svg(this)),
 
54
      m_systray(parent),
 
55
      m_manager(manager),
 
56
      m_total(0)
 
57
{
 
58
    setAcceptsHoverEvents(true);
 
59
    m_svg->setImagePath("icons/notification");
 
60
    m_svg->setContainsMultipleImages(true);
 
61
    setRunning(false);
 
62
 
 
63
    m_fadeInAnimation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
 
64
    m_fadeInAnimation->setTargetWidget(this);
 
65
    m_fadeInAnimation->setProperty("duration", 1000);
 
66
    m_fadeInAnimation->setProperty("targetPixmap", m_svg->pixmap("notification-active"));
 
67
 
 
68
    m_fadeOutAnimation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
 
69
    m_fadeOutAnimation->setTargetWidget(this);
 
70
    m_fadeOutAnimation->setProperty("duration", 1000);
 
71
    m_fadeOutAnimation->setProperty("startPixmap", m_svg->pixmap("notification-active"));
 
72
 
 
73
 
 
74
    m_fadeGroup = new QSequentialAnimationGroup(this);
 
75
    m_fadeGroup->addAnimation(m_fadeInAnimation);
 
76
    m_fadeGroup->addAnimation(m_fadeOutAnimation);
 
77
 
 
78
    connect(manager, SIGNAL(notificationAdded(Notification*)),
 
79
            this, SLOT(updateTask()));
 
80
    connect(manager, SIGNAL(notificationRemoved(Notification*)),
 
81
            this, SLOT(updateTask()));
 
82
    connect(manager, SIGNAL(notificationChanged(Notification*)),
 
83
            this, SLOT(updateTask()));
 
84
    connect(manager, SIGNAL(notificationExpired(Notification*)),
 
85
            this, SLOT(updateTask()));
 
86
    connect(manager, SIGNAL(jobAdded(Job*)),
 
87
            this, SLOT(updateTask()));
 
88
    connect(manager, SIGNAL(jobRemoved(Job*)),
 
89
            this, SLOT(updateTask()));
 
90
    connect(manager, SIGNAL(jobStateChanged(Job*)),
 
91
            this, SLOT(updateTask()));
 
92
 
 
93
    Plasma::Extender *extender = qobject_cast<Plasma::Extender *>(m_systray->graphicsWidget());
 
94
    if (extender) {
 
95
        connect(extender, SIGNAL(itemDetached(Plasma::ExtenderItem*)),
 
96
                this, SLOT(updateTask()));
 
97
    }
 
98
 
 
99
    updateTask();
 
100
}
 
101
 
 
102
void BusyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
 
103
{
 
104
    QRectF iconRect(0, 0, qMin(size().width(), size().height()), qMin(size().width(), size().height()));
 
105
    iconRect.moveCenter(boundingRect().center());
 
106
 
 
107
    if (m_state == Running) {
 
108
        const int arcStart = 90*16;
 
109
        const int arcEnd = -(360*(qreal)m_manager->jobTotals()->percentage()/100)*16;
 
110
 
 
111
        Plasma::BusyWidget::paint(painter, option, widget);
 
112
 
 
113
        //kDebug() << arcStart << arcEnd;
 
114
 
 
115
        QPixmap activePixmap(iconRect.size().toSize());
 
116
        activePixmap.fill(Qt::transparent);
 
117
        QPixmap inActivePixmap(iconRect.size().toSize());
 
118
        inActivePixmap.fill(Qt::transparent);
 
119
        QRect pieRect(QPoint(0, 0), activePixmap.size()*2);
 
120
        pieRect.moveCenter(activePixmap.rect().center());
 
121
 
 
122
        QPainter p(&activePixmap);
 
123
        p.setPen(Qt::NoPen);
 
124
        p.setBrush(Qt::black);
 
125
        p.setCompositionMode(QPainter::CompositionMode_Source);
 
126
        p.drawPie(pieRect, arcStart, arcEnd);
 
127
        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
 
128
        m_svg->paint(&p, QRectF(QPointF(0, 0), iconRect.size()), "notification-progress-active");
 
129
        p.end();
 
130
 
 
131
        p.begin(&inActivePixmap);
 
132
        p.setPen(Qt::NoPen);
 
133
        p.setBrush(Qt::black);
 
134
        p.setCompositionMode(QPainter::CompositionMode_Source);
 
135
        p.drawPie(pieRect, arcStart, (360*16)+arcEnd);
 
136
        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
 
137
        m_svg->paint(&p, QRectF(QPointF(0, 0), iconRect.size()), "notification-progress-inactive");
 
138
        p.end();
 
139
 
 
140
        painter->drawPixmap(iconRect.topLeft().toPoint(), activePixmap);
 
141
        painter->drawPixmap(iconRect.topLeft().toPoint(), inActivePixmap);
 
142
 
 
143
        Plasma::BusyWidget::paint(painter, option, widget);
 
144
 
 
145
    } else if (m_state == Empty && m_manager->notifications().count() > 0) {
 
146
        m_svg->paint(painter, iconRect, "notification-inactive");
 
147
    } else if (m_state == Empty && m_manager->notifications().count() == 0) {
 
148
        m_svg->paint(painter, iconRect, "notification-disabled");
 
149
    } else {
 
150
        // m_state ==  Info
 
151
        m_svg->paint(painter, iconRect, "notification-empty");
 
152
        QFont font(KGlobalSettings::smallestReadableFont());
 
153
        painter->setFont(font);
 
154
        QRectF r = rect();
 
155
 
 
156
        painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
 
157
 
 
158
        const QFontMetrics fm(font);
 
159
        const QSize textSize = fm.boundingRect(label()).size();
 
160
        const bool textFits = textSize.width() <= r.width() && textSize.height() <= r.height();
 
161
        if (m_svg && m_svg->hasElement(expanderElement())) {
 
162
            QSizeF arrowSize(m_svg->elementSize(expanderElement()));
 
163
            QRectF arrowRect(r.center() - QPointF(arrowSize.width() / 2, arrowSize.height() + fm.xHeight() / 2), arrowSize);
 
164
            m_svg->paint(painter, arrowRect, expanderElement());
 
165
 
 
166
            r.setTop(arrowRect.bottom());
 
167
 
 
168
            if (textFits) {
 
169
                painter->drawText(r, Qt::AlignHCenter|Qt::AlignTop, label());
 
170
            }
 
171
        } else if (textFits) {
 
172
            painter->drawText(r, Qt::AlignCenter, label());
 
173
        }
 
174
    }
 
175
 
 
176
    if (m_fadeInAnimation->state() == QAbstractAnimation::Running) {
 
177
        QPixmap pix = m_fadeInAnimation->property("currentPixmap").value<QPixmap>();
 
178
        painter->drawPixmap(iconRect, pix, pix.rect());
 
179
    } else if (m_fadeOutAnimation->state() == QAbstractAnimation::Running) {
 
180
        QPixmap pix = m_fadeOutAnimation->property("currentPixmap").value<QPixmap>();
 
181
        painter->drawPixmap(iconRect, pix, pix.rect());
 
182
    }
 
183
}
 
184
 
 
185
void BusyWidget::resizeEvent(QGraphicsSceneResizeEvent *)
 
186
{
 
187
    //regenerate pixmaps
 
188
    m_svg->resize(contentsRect().size());
 
189
    m_fadeInAnimation->setProperty("targetPixmap", m_svg->pixmap("notification-active"));
 
190
    m_fadeOutAnimation->setProperty("startPixmap", m_svg->pixmap("notification-active"));
 
191
    m_svg->resize();
 
192
}
 
193
 
 
194
void BusyWidget::setState(State state)
 
195
{
 
196
    if (m_state == state) {
 
197
        return;
 
198
    }
 
199
 
 
200
    m_state = state;
 
201
    setRunning(m_state == Running);
 
202
    update();
 
203
}
 
204
 
 
205
QString BusyWidget::expanderElement() const
 
206
{
 
207
    switch (m_systray->location()) {
 
208
        case Plasma::TopEdge:
 
209
            return "expander-top";
 
210
        case Plasma::RightEdge:
 
211
            return "expander-right";
 
212
        case Plasma::LeftEdge:
 
213
            return "expander-left";
 
214
        case Plasma::BottomEdge:
 
215
        default:
 
216
            return "expander-bottom";
 
217
    }
 
218
}
 
219
 
 
220
void BusyWidget::updateTask()
 
221
{
 
222
    int runningJobs = 0;
 
223
    int pausedJobs = 0;
 
224
    int completedJobs = 0;
 
225
    foreach (const Job *job, m_manager->jobs()) {
 
226
        switch (job->state()) {
 
227
            case Job::Running:
 
228
                ++runningJobs;
 
229
                break;
 
230
            case Job::Suspended:
 
231
                ++pausedJobs;
 
232
                break;
 
233
            default:
 
234
                break;
 
235
        }
 
236
    }
 
237
 
 
238
    int total = m_manager->jobs().count();
 
239
 
 
240
    foreach (Notification *notification, m_manager->notifications()) {
 
241
        if (qobject_cast<CompletedJobNotification *>(notification)) {
 
242
            ++completedJobs;
 
243
        } else if (!notification->isExpired()) {
 
244
            ++total;
 
245
        }
 
246
    }
 
247
 
 
248
    total += completedJobs;
 
249
 
 
250
 
 
251
    if (!(total + m_manager->notifications().count())) {
 
252
        m_systray->hidePopup();
 
253
    }
 
254
 
 
255
    if (total > m_total) {
 
256
        m_fadeGroup->start();
 
257
    }
 
258
    m_total = total;
 
259
 
 
260
    if (!total) {
 
261
        setState(BusyWidget::Empty);
 
262
        setLabel(QString());
 
263
    } else if (runningJobs) {
 
264
        setState(BusyWidget::Running);
 
265
        setLabel(QString("%1").arg(QString::number(total)));
 
266
    } else {
 
267
        setState(BusyWidget::Info);
 
268
        setLabel(QString::number(total));
 
269
    }
 
270
 
 
271
    //make a nice plasma tooltip
 
272
    QString tooltipContent;
 
273
    if (runningJobs > 0) {
 
274
        tooltipContent += i18np("%1 running job", "%1 running jobs", runningJobs);
 
275
        if (pausedJobs > 0 || completedJobs > 0 || !m_manager->notifications().isEmpty()) {
 
276
            tooltipContent += "<br>";
 
277
        }
 
278
    }
 
279
 
 
280
    if (pausedJobs > 0) {
 
281
        tooltipContent += i18np("%1 suspended job", "%1 suspended jobs", pausedJobs);
 
282
        if (completedJobs > 0 || !m_manager->notifications().isEmpty()) {
 
283
            tooltipContent += "<br>";
 
284
        }
 
285
    }
 
286
 
 
287
    if (completedJobs > 0) {
 
288
        tooltipContent += i18np("%1 completed job", "%1 completed jobs", completedJobs);
 
289
        if (!m_manager->notifications().isEmpty()) {
 
290
            tooltipContent += "<br>";
 
291
        }
 
292
    }
 
293
 
 
294
    if (!m_manager->notifications().isEmpty()) {
 
295
        tooltipContent += i18np("%1 notification", "%1 notifications",
 
296
                                m_manager->notifications().count());
 
297
    }
 
298
 
 
299
    if (tooltipContent.isEmpty()) {
 
300
        tooltipContent = i18n("No active jobs or notifications");
 
301
    }
 
302
 
 
303
    Plasma::ToolTipContent data(i18n("Notifications and jobs"),
 
304
                                tooltipContent,
 
305
                                KIcon("help-about"));
 
306
    Plasma::ToolTipManager::self()->setContent(this, data);
 
307
}
 
308
 
 
309
 
 
310
#include "busywidget.moc"