add more spacing
[personal-kdebase.git] / workspace / plasma / applets / systemtray / ui / applet.cpp
blob40acb8caef8968d1ae3dcd3203daf5e9b23f0e02
1 /***************************************************************************
2 * applet.cpp *
3 * *
4 * Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com> *
5 * Copyright (C) 2008 Sebastian Sauer *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
21 ***************************************************************************/
23 #include "applet.h"
24 #include "jobwidget.h"
25 #include "notificationwidget.h"
26 #include "taskarea.h"
28 #include <QtGui/QApplication>
29 #include <QtGui/QGraphicsLayout>
30 #include <QtGui/QVBoxLayout>
31 #include <QtGui/QIcon>
32 #include <QtGui/QLabel>
33 #include <QtGui/QListWidget>
34 #include <QtGui/QCheckBox>
35 #include <QtGui/QPainter>
37 #include <KActionSelector>
38 #include <KConfigDialog>
40 #include <Solid/Device>
42 #include <plasma/extender.h>
43 #include <plasma/extenderitem.h>
44 #include <plasma/framesvg.h>
45 #include <plasma/theme.h>
47 #include "../core/manager.h"
48 #include "../core/task.h"
49 #include "extendertask.h"
52 namespace SystemTray
55 K_EXPORT_PLASMA_APPLET(systemtray, Applet)
58 class Applet::Private
60 public:
61 Private(Applet *q)
62 : q(q),
63 taskArea(0),
64 configInterface(0),
65 notificationInterface(0),
66 background(0),
67 extenderTask(0)
69 if (!s_manager) {
70 s_manager = new SystemTray::Manager();
73 ++s_managerUsage;
76 ~Private()
78 --s_managerUsage;
79 if (s_managerUsage < 1) {
80 delete s_manager;
81 s_manager = 0;
82 s_managerUsage = 0;
86 void setTaskAreaGeometry();
88 Applet *q;
90 TaskArea *taskArea;
91 QPointer<KActionSelector> configInterface;
92 QPointer<QWidget> notificationInterface;
93 QCheckBox *showNotifications;
94 QCheckBox *showJobs;
96 Plasma::FrameSvg *background;
97 SystemTray::ExtenderTask *extenderTask;
98 static SystemTray::Manager *s_manager;
99 static int s_managerUsage;
102 Manager *Applet::Private::s_manager = 0;
103 int Applet::Private::s_managerUsage = 0;
105 Applet::Applet(QObject *parent, const QVariantList &arguments)
106 : Plasma::PopupApplet(parent, arguments),
107 d(new Private(this))
109 d->background = new Plasma::FrameSvg(this);
110 d->background->setImagePath("widgets/systemtray");
111 d->background->setCacheAllRenderedFrames(true);
112 d->taskArea = new TaskArea(this);
114 setPopupIcon(QIcon());
115 setPassivePopup(true);
116 setAspectRatioMode(Plasma::IgnoreAspectRatio);
117 setBackgroundHints(NoBackground);
118 setHasConfigurationInterface(true);
121 Applet::~Applet()
123 //destroy any item in the systray, since it doesn't make sense for not detached notifications
124 //and jobs to stay around after a plasma reboot
125 foreach (Plasma::ExtenderItem *item, extender()->attachedItems()) {
126 item->destroy();
129 delete d;
132 void Applet::init()
134 KConfigGroup cg = config();
135 QStringList hiddenTypes = cg.readEntry("hidden", QStringList());
137 d->setTaskAreaGeometry();
138 connect(Private::s_manager, SIGNAL(taskAdded(SystemTray::Task*)),
139 d->taskArea, SLOT(addTask(SystemTray::Task*)));
140 connect(Private::s_manager, SIGNAL(taskChanged(SystemTray::Task*)),
141 d->taskArea, SLOT(addTask(SystemTray::Task*)));
142 connect(Private::s_manager, SIGNAL(taskRemoved(SystemTray::Task*)),
143 d->taskArea, SLOT(removeTask(SystemTray::Task*)));
145 d->taskArea->setHiddenTypes(hiddenTypes);
146 connect(d->taskArea, SIGNAL(sizeHintChanged(Qt::SizeHint)),
147 this, SLOT(propogateSizeHintChange(Qt::SizeHint)));
149 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
150 this, SLOT(checkSizes()));
151 checkSizes();
153 d->taskArea->syncTasks(Private::s_manager->tasks());
155 extender()->setEmptyExtenderMessage(i18n("No notifications and no jobs"));
157 KConfigGroup globalCg = globalConfig();
158 if (globalCg.readEntry("ShowJobs", true)) {
159 Private::s_manager->registerJobProtocol();
160 connect(Private::s_manager, SIGNAL(jobAdded(SystemTray::Job*)),
161 this, SLOT(addJob(SystemTray::Job*)));
164 if (globalCg.readEntry("ShowNotifications", true)) {
165 Private::s_manager->registerNotificationProtocol();
166 connect(Private::s_manager, SIGNAL(notificationAdded(SystemTray::Notification*)),
167 this, SLOT(addNotification(SystemTray::Notification*)));
171 void Applet::constraintsEvent(Plasma::Constraints constraints)
173 setBackgroundHints(NoBackground);
174 if (constraints & Plasma::FormFactorConstraint) {
175 QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred);
176 policy.setHeightForWidth(true);
177 bool vertical = formFactor() == Plasma::Vertical;
179 if (!vertical) {
180 policy.setVerticalPolicy(QSizePolicy::Expanding);
181 } else {
182 policy.setHorizontalPolicy(QSizePolicy::Expanding);
185 setSizePolicy(policy);
186 d->taskArea->setSizePolicy(policy);
187 d->taskArea->setOrientation(vertical ? Qt::Vertical : Qt::Horizontal);
190 if (constraints & Plasma::SizeConstraint) {
191 checkSizes();
195 SystemTray::Manager *Applet::manager() const
197 return d->s_manager;
200 void Applet::setGeometry(const QRectF &rect)
202 Plasma::Applet::setGeometry(rect);
204 if (d->taskArea) {
205 d->setTaskAreaGeometry();
209 void Applet::checkSizes()
211 d->taskArea->checkSizes();
213 qreal leftMargin, topMargin, rightMargin, bottomMargin;
214 d->background->getMargins(leftMargin, topMargin, rightMargin, bottomMargin);
215 setContentsMargins(leftMargin, topMargin, rightMargin, bottomMargin);
217 QSizeF preferredSize = d->taskArea->effectiveSizeHint(Qt::PreferredSize);
218 preferredSize.setWidth(preferredSize.width() + leftMargin + rightMargin);
219 preferredSize.setHeight(preferredSize.height() + topMargin + bottomMargin);
220 setPreferredSize(preferredSize);
222 QSizeF actualSize = size();
223 Plasma::FormFactor f = formFactor();
225 if (f == Plasma::Horizontal) {
226 setMinimumSize(preferredSize.width(), 0);
227 } else if (f == Plasma::Vertical) {
228 setMinimumSize(0, preferredSize.height());
229 } else if (actualSize.width() < preferredSize.width() ||
230 actualSize.height() < preferredSize.height()) {
231 setMinimumSize(22, 22);
233 QSizeF constraint;
234 if (actualSize.width() > actualSize.height()) {
235 constraint = QSize(actualSize.width() - leftMargin - rightMargin, -1);
236 } else {
237 constraint = QSize(-1, actualSize.height() - topMargin - bottomMargin);
240 preferredSize = d->taskArea->effectiveSizeHint(Qt::PreferredSize, constraint);
241 preferredSize.setWidth(qMax(actualSize.width(), preferredSize.width()));
242 preferredSize.setHeight(qMax(actualSize.height(), preferredSize.height()));
244 resize(preferredSize);
249 void Applet::Private::setTaskAreaGeometry()
251 qreal leftMargin, topMargin, rightMargin, bottomMargin;
252 q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
254 QRectF taskAreaRect(q->rect());
255 taskAreaRect.moveLeft(leftMargin);
256 taskAreaRect.moveTop(topMargin);
257 taskAreaRect.setWidth(taskAreaRect.width() - leftMargin - rightMargin);
258 taskAreaRect.setHeight(taskAreaRect.height() - topMargin - bottomMargin);
260 taskArea->setGeometry(taskAreaRect);
263 void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
265 Q_UNUSED(option)
266 Q_UNUSED(contentsRect)
268 QRect normalRect = rect().toRect();
269 QRect lastRect(normalRect);
270 d->background->setElementPrefix("lastelements");
272 if (formFactor() == Plasma::Vertical) {
273 const int rightEasement = d->taskArea->rightEasement() + d->background->marginSize(Plasma::BottomMargin);
274 normalRect.setY(d->taskArea->leftEasement());
275 normalRect.setBottom(normalRect.bottom() - rightEasement);
277 lastRect.setY(normalRect.bottom() + 1);
278 lastRect.setHeight(rightEasement);
279 } else if (QApplication::layoutDirection() == Qt::RightToLeft) {
280 const int rightEasement = d->taskArea->rightEasement() + d->background->marginSize(Plasma::LeftMargin);
281 normalRect.setWidth(normalRect.width() - d->taskArea->leftEasement());
282 normalRect.setLeft(rightEasement);
284 lastRect.setWidth(rightEasement);
285 } else {
286 const int rightEasement = d->taskArea->rightEasement() + d->background->marginSize(Plasma::RightMargin);
287 normalRect.setX(d->taskArea->leftEasement());
288 normalRect.setWidth(normalRect.width() - rightEasement);
290 lastRect.setX(normalRect.right() + 1);
291 lastRect.setWidth(rightEasement);
294 QRect r = normalRect.united(lastRect);
296 painter->save();
298 d->background->setElementPrefix(QString());
299 d->background->resizeFrame(r.size());
300 if (d->taskArea->rightEasement() > 0) {
301 painter->setClipRect(normalRect);
303 d->background->paintFrame(painter, r, QRectF(QPointF(0, 0), r.size()));
305 if (d->taskArea->rightEasement() > 0) {
306 d->background->setElementPrefix("lastelements");
307 d->background->resizeFrame(r.size());
308 painter->setClipRect(lastRect);
309 d->background->paintFrame(painter, r, QRectF(QPointF(0, 0), r.size()));
312 painter->restore();
316 void Applet::propogateSizeHintChange(Qt::SizeHint which)
318 checkSizes();
319 emit sizeHintChanged(which);
323 void Applet::createConfigurationInterface(KConfigDialog *parent)
325 if (!d->configInterface) {
326 d->configInterface = new KActionSelector();
327 d->configInterface->setAvailableLabel(i18n("Visible icons:"));
328 d->configInterface->setSelectedLabel(i18n("Hidden icons:"));
329 d->configInterface->setShowUpDownButtons(false);
331 KConfigGroup globalCg = globalConfig();
332 d->notificationInterface = new QWidget();
334 QLabel *description = new QLabel(i18n("Select the types of application feedback that should "
335 "be integrated with the system tray:"), d->notificationInterface);
336 description->setWordWrap(true);
337 d->showJobs = new QCheckBox(i18n("Show Jobs"), d->notificationInterface);
338 d->showJobs->setChecked(globalCg.readEntry("ShowJobs", true));
339 d->showNotifications = new QCheckBox(i18n("Show Notifications"), d->notificationInterface);
340 d->showNotifications->setChecked(globalCg.readEntry("ShowNotifications", true));
342 QVBoxLayout *layout = new QVBoxLayout;
343 layout->addWidget(description);
344 layout->addWidget(d->showJobs);
345 layout->addWidget(d->showNotifications);
346 layout->addStretch();
347 d->notificationInterface->setLayout(layout);
349 connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
350 connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
352 parent->addPage(d->configInterface, i18n("Auto Hide"));
353 parent->addPage(d->notificationInterface, i18n("Notifications"));
356 QListWidget *visibleList = d->configInterface->availableListWidget();
357 QListWidget *hiddenList = d->configInterface->selectedListWidget();
359 visibleList->clear();
360 hiddenList->clear();
362 foreach (Task *task, Private::s_manager->tasks()) {
363 if (!task->isHideable()) {
364 continue;
367 QListWidgetItem *listItem = new QListWidgetItem();
368 listItem->setText(task->name());
369 listItem->setIcon(task->icon());
370 listItem->setData(Qt::UserRole, task->typeId());
372 if (d->taskArea->isHiddenType(task->typeId(), false)) {
373 hiddenList->addItem(listItem);
374 } else {
375 visibleList->addItem(listItem);
381 void Applet::configAccepted()
383 QStringList hiddenTypes;
385 QListWidget *hiddenList = d->configInterface->selectedListWidget();
386 for (int i = 0; i < hiddenList->count(); ++i) {
387 hiddenTypes << hiddenList->item(i)->data(Qt::UserRole).toString();
390 d->taskArea->setHiddenTypes(hiddenTypes);
391 d->taskArea->syncTasks(Private::s_manager->tasks());
393 KConfigGroup cg = config();
394 cg.writeEntry("hidden", hiddenTypes);
396 KConfigGroup globalCg = globalConfig();
397 globalCg.writeEntry("ShowJobs", d->showJobs->isChecked());
398 globalCg.writeEntry("ShowNotifications", d->showNotifications->isChecked());
400 disconnect(Private::s_manager, SIGNAL(jobAdded(SystemTray::Job*)),
401 this, SLOT(addJob(SystemTray::Job*)));
402 if (d->showJobs->isChecked()) {
403 Private::s_manager->registerJobProtocol();
404 connect(Private::s_manager, SIGNAL(jobAdded(SystemTray::Job*)),
405 this, SLOT(addJob(SystemTray::Job*)));
406 } else {
407 Private::s_manager->unregisterJobProtocol();
410 disconnect(Private::s_manager, SIGNAL(notificationAdded(SystemTray::Notification*)),
411 this, SLOT(addNotification(SystemTray::Notification*)));
412 if (d->showNotifications->isChecked()) {
413 Private::s_manager->registerNotificationProtocol();
414 connect(Private::s_manager, SIGNAL(notificationAdded(SystemTray::Notification*)),
415 this, SLOT(addNotification(SystemTray::Notification*)));
416 } else {
417 Private::s_manager->unregisterNotificationProtocol();
420 emit configNeedsSaving();
424 void Applet::addNotification(Notification *notification)
426 Plasma::ExtenderItem *extenderItem = new Plasma::ExtenderItem(extender());
427 extenderItem->config().writeEntry("type", "notification");
428 extenderItem->setWidget(new NotificationWidget(notification, extenderItem));
430 connect(extenderItem, SIGNAL(destroyed()), this, SLOT(hidePopupIfEmpty()));
432 showPopup();
435 void Applet::addJob(Job *job)
437 Plasma::ExtenderItem *extenderItem = new Plasma::ExtenderItem(extender());
438 extenderItem->config().writeEntry("type", "job");
439 extenderItem->setWidget(new JobWidget(job, extenderItem));
441 connect(extenderItem, SIGNAL(destroyed()), this, SLOT(hidePopupIfEmpty()));
443 showPopup(5000);
446 void Applet::initExtenderItem(Plasma::ExtenderItem *extenderItem)
448 if (extenderItem->config().readEntry("type", "") == "notification") {
449 extenderItem->setWidget(new NotificationWidget(0, extenderItem));
450 } else {
451 extenderItem->setWidget(new JobWidget(0, extenderItem));
455 void Applet::hidePopupIfEmpty()
457 if (d->extenderTask && extender()->attachedItems().isEmpty()) {
458 hidePopup();
460 // even though there is code to do this in popupEvent... we may need to delete
461 // here anyways because the popup may already be hidden, resultin gin no
462 // popupEvent
463 delete d->extenderTask;
464 d->extenderTask = 0;
468 void Applet::popupEvent(bool visibility)
470 kDebug() << visibility << extender()->attachedItems().isEmpty();
471 if (extender()->attachedItems().isEmpty()) {
472 delete d->extenderTask;
473 d->extenderTask = 0;
474 } else {
475 if (!d->extenderTask) {
476 d->extenderTask = new SystemTray::ExtenderTask(this);
477 d->extenderTask->setIcon("help-about");
480 Private::s_manager->addTask(d->extenderTask);
487 #include "applet.moc"