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

« back to all changes in this revision

Viewing changes to plasma/generic/applets/notifications/ui/notifications.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
 *   applet.cpp                                                            *
 
3
 *                                                                         *
 
4
 *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
 
5
 *   Copyright (C) 2008 Sebastian Sauer                                    *
 
6
 *   Copyright (C) 2010 Marco Martin <notmart@gmail.com>                   *
 
7
 *                                                                         *
 
8
 *   This program is free software; you can redistribute it and/or modify  *
 
9
 *   it under the terms of the GNU General Public License as published by  *
 
10
 *   the Free Software Foundation; either version 2 of the License, or     *
 
11
 *   (at your option) any later version.                                   *
 
12
 *                                                                         *
 
13
 *   This program is distributed in the hope that it will be useful,       *
 
14
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
15
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
16
 *   GNU General Public License for more details.                          *
 
17
 *                                                                         *
 
18
 *   You should have received a copy of the GNU General Public License     *
 
19
 *   along with this program; if not, write to the                         *
 
20
 *   Free Software Foundation, Inc.,                                       *
 
21
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
 
22
 ***************************************************************************/
 
23
 
 
24
#include "notifications.h"
 
25
 
 
26
#include <QtGui/QApplication>
 
27
#include <QtGui/QGraphicsLayout>
 
28
#include <QtGui/QGraphicsLinearLayout>
 
29
#include <QtGui/QVBoxLayout>
 
30
#include <QtGui/QIcon>
 
31
#include <QtGui/QLabel>
 
32
#include <QtGui/QListWidget>
 
33
#include <QtGui/QTreeWidget>
 
34
#include <QtGui/QCheckBox>
 
35
#include <QtGui/QPainter>
 
36
#include <QtGui/QX11Info>
 
37
#include <QtCore/QProcess>
 
38
 
 
39
 
 
40
#include <KConfigDialog>
 
41
#include <KComboBox>
 
42
#include <KWindowSystem>
 
43
#include <KIconLoader>
 
44
 
 
45
#include <Solid/Device>
 
46
 
 
47
#include <plasma/extender.h>
 
48
#include <plasma/extenderitem.h>
 
49
#include <plasma/extendergroup.h>
 
50
#include <plasma/framesvg.h>
 
51
#include <plasma/widgets/label.h>
 
52
#include <plasma/theme.h>
 
53
#include <plasma/dataenginemanager.h>
 
54
#include <plasma/dataengine.h>
 
55
#include <Plasma/TabBar>
 
56
#include <Plasma/Animator>
 
57
#include <Plasma/Animation>
 
58
#include <Plasma/Containment>
 
59
#include <Plasma/Corona>
 
60
#include <Plasma/Dialog>
 
61
#include <Plasma/WindowEffects>
 
62
 
 
63
#include "config-notifications.h"
 
64
#ifdef HAVE_LIBXSS      // Idle detection.
 
65
#include <X11/Xlib.h>
 
66
#include <X11/Xutil.h>
 
67
#include <X11/extensions/scrnsaver.h>
 
68
#include <fixx11h.h>
 
69
#endif // HAVE_LIBXSS
 
70
 
 
71
#include "../core/notificationsmanager.h"
 
72
#include "../core/notification.h"
 
73
#include "../core/completedjobnotification.h"
 
74
#include "busywidget.h"
 
75
#include "jobwidget.h"
 
76
#include "jobtotalswidget.h"
 
77
#include "notificationgroup.h"
 
78
#include "notificationstack.h"
 
79
#include "stackdialog.h"
 
80
 
 
81
 
 
82
K_EXPORT_PLASMA_APPLET(notifications, Notifications)
 
83
 
 
84
 
 
85
Notifications::Notifications(QObject *parent, const QVariantList &arguments)
 
86
    : Plasma::PopupApplet(parent, arguments),
 
87
      m_jobSummaryWidget(0),
 
88
      m_autoHidePopup(true),
 
89
      m_notificationStack(0),
 
90
      m_notificationStackDialog(0),
 
91
      m_standaloneJobSummaryWidget(0),
 
92
      m_standaloneJobSummaryDialog(0),
 
93
      m_busyWidget(0)
 
94
{
 
95
    m_manager = new Manager(this);
 
96
 
 
97
    setPopupIcon(QIcon());
 
98
    setPassivePopup(true);
 
99
    setAspectRatioMode(Plasma::IgnoreAspectRatio);
 
100
    setBackgroundHints(NoBackground);
 
101
    setHasConfigurationInterface(true);
 
102
    setMinimumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
 
103
}
 
104
 
 
105
Notifications::~Notifications()
 
106
{
 
107
    // stop listening to the manager
 
108
    disconnect(m_manager, 0, this, 0);
 
109
    if (m_notificationStackDialog) {
 
110
        disconnect(m_notificationStackDialog, 0, this, 0);
 
111
    }
 
112
 
 
113
    foreach (Notification *notification, m_manager->notifications()) {
 
114
        // we don't want a destroyed managed after the destruction of manager
 
115
        disconnect(notification, 0, this, 0);
 
116
    }
 
117
 
 
118
    //has to be deleted before the manager because it will access it
 
119
    delete m_busyWidget;
 
120
    delete m_notificationStackDialog;
 
121
    delete m_standaloneJobSummaryDialog;
 
122
}
 
123
 
 
124
void Notifications::init()
 
125
{
 
126
    extender()->setEmptyExtenderMessage(i18n("No notifications and no jobs"));
 
127
 
 
128
    m_busyWidget = new BusyWidget(this, m_manager);
 
129
    connect(m_busyWidget, SIGNAL(clicked()), this, SLOT(togglePopup()));
 
130
    QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(this);
 
131
    setContentsMargins(0, 0, 0, 0);
 
132
    lay->setContentsMargins(0, 0, 0, 0);
 
133
    lay->addItem(m_busyWidget);
 
134
 
 
135
    configChanged();
 
136
    setStatus(Plasma::ActiveStatus);
 
137
}
 
138
 
 
139
void Notifications::configChanged()
 
140
{
 
141
    KConfigGroup cg = config();
 
142
 
 
143
    m_autoHidePopup = cg.readEntry("AutoHidePopup", true);
 
144
    if (m_notificationStackDialog) {
 
145
        m_notificationStackDialog->setAutoHide(m_autoHidePopup);
 
146
    }
 
147
 
 
148
    if (cg.readEntry("ShowJobs", true)) {
 
149
        createJobGroups();
 
150
 
 
151
        m_manager->registerJobProtocol();
 
152
        connect(m_manager, SIGNAL(jobAdded(Job*)),
 
153
                this, SLOT(addJob(Job*)), Qt::UniqueConnection);
 
154
        connect(m_manager, SIGNAL(jobRemoved(Job*)),
 
155
                this, SLOT(finishJob(Job*)), Qt::UniqueConnection);
 
156
    } else {
 
157
        delete extender()->group("jobGroup");
 
158
        m_manager->unregisterJobProtocol();
 
159
        disconnect(m_manager, SIGNAL(jobAdded(Job*)),
 
160
                   this, SLOT(addJob(Job*)));
 
161
        disconnect(m_manager, SIGNAL(jobRemoved(Job*)),
 
162
                   this, SLOT(finishJob(Job*)));
 
163
    }
 
164
 
 
165
    if (cg.readEntry("ShowNotifications", true)) {
 
166
        m_manager->registerNotificationProtocol();
 
167
        connect(m_manager, SIGNAL(notificationAdded(Notification*)),
 
168
                this, SLOT(addNotification(Notification*)), Qt::UniqueConnection);
 
169
    } else {
 
170
        m_manager->unregisterNotificationProtocol();
 
171
        disconnect(m_manager, SIGNAL(notificationAdded(Notification*)),
 
172
                   this, SLOT(addNotification(Notification*)));
 
173
    }
 
174
}
 
175
 
 
176
void Notifications::syncNotificationBarNeeded()
 
177
{
 
178
    if (!m_manager) {
 
179
        return;
 
180
    }
 
181
 
 
182
    if (m_manager->notifications().count() > 0) {
 
183
        if (!extender()->item("notifications")) {
 
184
            m_notificationGroup = new NotificationGroup(extender());
 
185
        }
 
186
    } else if (extender()->item("notifications")) {
 
187
        //don't let him in the config file
 
188
        extender()->item("notifications")->destroy();
 
189
    }
 
190
}
 
191
 
 
192
 
 
193
Manager *Notifications::manager() const
 
194
{
 
195
    return m_manager;
 
196
}
 
197
 
 
198
void Notifications::createConfigurationInterface(KConfigDialog *parent)
 
199
{
 
200
    if (!m_notificationInterface) {
 
201
        KConfigGroup cg = config();
 
202
        m_notificationInterface = new QWidget();
 
203
 
 
204
        m_notificationUi.setupUi(m_notificationInterface.data());
 
205
 
 
206
        m_notificationUi.showJobs->setChecked(cg.readEntry("ShowJobs", true));
 
207
        m_notificationUi.showNotifications->setChecked(cg.readEntry("ShowNotifications", true));
 
208
 
 
209
        m_notificationUi.autoHide->setChecked(config().readEntry("AutoHidePopup", true));
 
210
 
 
211
        connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
 
212
        connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
 
213
 
 
214
        parent->addPage(m_notificationInterface.data(), i18n("Information"),
 
215
                        "preferences-desktop-notification",
 
216
                        i18n("Choose which information to show"));
 
217
 
 
218
        connect(m_notificationUi.showNotifications, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
 
219
        connect(m_notificationUi.showJobs, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
 
220
        connect(m_notificationUi.autoHide, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
 
221
    }
 
222
}
 
223
 
 
224
void Notifications::configAccepted()
 
225
{
 
226
    //TODO put in a single page
 
227
    //cg.writeEntry("AutoHidePopup", m_autoHideUi.autoHide->isChecked());
 
228
 
 
229
    KConfigGroup cg = config();
 
230
    cg.writeEntry("ShowJobs", m_notificationUi.showJobs->isChecked());
 
231
    cg.writeEntry("ShowNotifications", m_notificationUi.showNotifications->isChecked());
 
232
    cg.writeEntry("AutoHidePopup", m_notificationUi.autoHide->isChecked());
 
233
 
 
234
    emit configNeedsSaving();
 
235
}
 
236
 
 
237
void Notifications::addNotification(Notification *notification)
 
238
{
 
239
    syncNotificationBarNeeded();
 
240
 
 
241
    //At this point we are sure the pointer is valid
 
242
    m_notificationGroup.data()->addNotification(notification);
 
243
 
 
244
 
 
245
    if (isPopupShowing()) {
 
246
        return;
 
247
    }
 
248
 
 
249
    if (!m_notificationStack) {
 
250
        m_notificationStack = new NotificationStack(this);
 
251
        if (containment() && containment()->corona()) {
 
252
            containment()->corona()->addOffscreenWidget(m_notificationStack);
 
253
        }
 
254
        m_notificationStackDialog = new StackDialog;
 
255
        m_notificationStackDialog->setNotificationStack(m_notificationStack);
 
256
        m_notificationStackDialog->setApplet(this);
 
257
        connect(m_notificationStack, SIGNAL(stackEmpty()), m_notificationStackDialog, SLOT(hide()));
 
258
        connect(m_notificationStack, SIGNAL(showRequested()), m_notificationStackDialog, SLOT(show()));
 
259
        m_notificationStackDialog->setAutoHide(m_autoHidePopup);
 
260
 
 
261
        if (m_standaloneJobSummaryDialog) {
 
262
            m_notificationStackDialog->setWindowToTile(m_standaloneJobSummaryDialog);
 
263
        }
 
264
    }
 
265
 
 
266
 
 
267
    m_notificationStack->addNotification(notification);
 
268
    m_notificationStackDialog->syncToGraphicsWidget();
 
269
 
 
270
    if (containment() && containment()->corona()) {
 
271
        if (!m_notificationStackDialog->isVisible()) {
 
272
            m_notificationStack->setCurrentNotification(notification);
 
273
        }
 
274
 
 
275
        KWindowSystem::setOnAllDesktops(m_notificationStackDialog->winId(), true);
 
276
        m_notificationStackDialog->show();
 
277
    }
 
278
 
 
279
    Plasma::Animation *pulse = Plasma::Animator::create(Plasma::Animator::PulseAnimation, m_busyWidget);
 
280
    pulse->setTargetWidget(m_busyWidget);
 
281
    pulse->start(QAbstractAnimation::DeleteWhenStopped);
 
282
}
 
283
 
 
284
void Notifications::addJob(Job *job)
 
285
{
 
286
    Plasma::ExtenderGroup *group = extender()->group("jobGroup");
 
287
 
 
288
    Plasma::ExtenderItem *extenderItem = new Plasma::ExtenderItem(extender());
 
289
    extenderItem->setTransient(true);
 
290
    extenderItem->config().writeEntry("type", "job");
 
291
    extenderItem->setWidget(new JobWidget(job, extenderItem));
 
292
 
 
293
    extenderItem->setGroup(group);
 
294
 
 
295
    if (group) {
 
296
        group->setCollapsed(group->items().count() < 2);
 
297
    }
 
298
 
 
299
    if (isPopupShowing()) {
 
300
        return;
 
301
    }
 
302
 
 
303
    //show the tiny standalone overview
 
304
    if (!m_standaloneJobSummaryWidget) {
 
305
        m_standaloneJobSummaryDialog = new Plasma::Dialog();
 
306
        KWindowSystem::setType(m_standaloneJobSummaryDialog->winId(), NET::Dock);
 
307
        if (m_notificationStackDialog) {
 
308
            m_notificationStackDialog->setWindowToTile(m_standaloneJobSummaryDialog);
 
309
        }
 
310
 
 
311
        m_standaloneJobSummaryWidget = new JobTotalsWidget(m_manager->jobTotals(), this);
 
312
        if (containment() && containment()->corona()) {
 
313
            containment()->corona()->addOffscreenWidget(m_standaloneJobSummaryWidget);
 
314
        }
 
315
        m_standaloneJobSummaryDialog->setGraphicsWidget(m_standaloneJobSummaryWidget);
 
316
        //FIXME:sizing hack and layout issues..
 
317
        m_standaloneJobSummaryWidget->resize(m_standaloneJobSummaryWidget->size().width(), 32);
 
318
        m_standaloneJobSummaryWidget->setMaximumHeight(32);
 
319
        m_standaloneJobSummaryWidget->setMinimumHeight(32);
 
320
        m_standaloneJobSummaryWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
321
    }
 
322
 
 
323
    m_standaloneJobSummaryDialog->syncToGraphicsWidget();
 
324
    KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::KeepBelow);
 
325
 
 
326
    if (containment() && containment()->corona()) {
 
327
        m_standaloneJobSummaryDialog->move(containment()->corona()->popupPosition(this, m_standaloneJobSummaryDialog->size()));
 
328
        m_standaloneJobSummaryDialog->show();
 
329
        Plasma::WindowEffects::slideWindow(m_standaloneJobSummaryDialog, location());
 
330
 
 
331
        KWindowSystem::setOnAllDesktops(m_standaloneJobSummaryDialog->winId(), true);
 
332
        KWindowSystem::clearState(m_standaloneJobSummaryDialog->winId(), NET::KeepAbove|NET::StaysOnTop);
 
333
 
 
334
        KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::SkipTaskbar|NET::SkipPager);
 
335
        KWindowSystem::raiseWindow(m_standaloneJobSummaryDialog->winId());
 
336
        KWindowSystem::setOnAllDesktops(m_standaloneJobSummaryDialog->winId(), true);
 
337
    }
 
338
}
 
339
 
 
340
void Notifications::initExtenderItem(Plasma::ExtenderItem *extenderItem)
 
341
{
 
342
    if (extenderItem->name() == "jobGroup") {
 
343
        m_jobSummaryWidget = new JobTotalsWidget(m_manager->jobTotals(), extenderItem);
 
344
        extenderItem->setWidget(m_jobSummaryWidget);
 
345
        Plasma::ExtenderGroup *group = qobject_cast<Plasma::ExtenderGroup*>(extenderItem);
 
346
        if (group) {
 
347
            extenderItem->setCollapsed(!group->isGroupCollapsed());
 
348
        }
 
349
        return;
 
350
    }
 
351
 
 
352
    if (extenderItem->config().readEntry("type", QString()) == "job") {
 
353
        extenderItem->setWidget(new JobWidget(0, extenderItem));
 
354
    } else {
 
355
        //unknown type, this should never happen
 
356
        extenderItem->destroy();
 
357
    }
 
358
 
 
359
}
 
360
 
 
361
void Notifications::popupEvent(bool show)
 
362
{
 
363
    //decide about showing the tiny progressbar or not
 
364
    if (m_standaloneJobSummaryDialog) {
 
365
        if (show || !m_manager->jobs().isEmpty()) {
 
366
            if (!show) {
 
367
                KWindowSystem::raiseWindow(m_standaloneJobSummaryDialog->winId());
 
368
                KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::SkipTaskbar|NET::SkipPager);
 
369
                KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::KeepBelow);
 
370
            } else {
 
371
                m_standaloneJobSummaryDialog->hide();
 
372
            }
 
373
        }
 
374
    }
 
375
 
 
376
    if (m_notificationStackDialog && show) {
 
377
        m_notificationStackDialog->hide();
 
378
    }
 
379
 
 
380
    Plasma::ExtenderGroup * jobGroup = extender()->group("jobGroup");
 
381
    if (!jobGroup) {
 
382
        return;
 
383
    }
 
384
 
 
385
    foreach (Plasma::ExtenderItem *item, jobGroup->items()) {
 
386
        JobWidget *job = dynamic_cast<JobWidget *>(item->widget());
 
387
        if (job) {
 
388
            job->poppedUp(show);
 
389
        }
 
390
    }
 
391
}
 
392
 
 
393
void Notifications::finishJob(Job *job)
 
394
{
 
395
    //finished all jobs? hide the mini progressbar
 
396
    if (m_standaloneJobSummaryDialog && m_manager->jobs().isEmpty()) {
 
397
        m_standaloneJobSummaryDialog->hide();
 
398
    }
 
399
 
 
400
    //create a fake notification
 
401
    CompletedJobNotification *notification = new CompletedJobNotification(this);
 
402
    notification->setJob(job);
 
403
    m_manager->addNotification(notification);
 
404
 
 
405
    Plasma::ExtenderGroup *group = extender()->group("jobGroup");
 
406
    if (group) {
 
407
        // < 3 because the second still hasn't been removed from the extendergroup
 
408
        group->setCollapsed(!group->isGroupCollapsed() && group->items().count() < 3);
 
409
    }
 
410
}
 
411
 
 
412
void Notifications::open(const QString &url)
 
413
{
 
414
    //kDebug() << "open " << url;
 
415
    QProcess::startDetached("kde-open", QStringList() << url);
 
416
}
 
417
 
 
418
void Notifications::createJobGroups()
 
419
{
 
420
    if (!extender()->hasItem("jobGroup")) {
 
421
        Plasma::ExtenderGroup *extenderGroup = new Plasma::ExtenderGroup(extender());
 
422
        extenderGroup->setName("jobGroup");
 
423
        initExtenderItem(extenderGroup);
 
424
        extenderGroup->setAutoHide(true);
 
425
    } else if (extender()->group("jobGroup")) {
 
426
        extender()->group("jobGroup")->setAutoHide(true);
 
427
    }
 
428
}
 
429
 
 
430
 
 
431
#include "notifications.moc"