1 /***************************************************************************
4 * Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com> *
5 * Copyright (C) 2008 Sebastian Sauer *
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. *
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. *
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 ***************************************************************************/
24 #include "jobwidget.h"
25 #include "notificationwidget.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"
55 K_EXPORT_PLASMA_APPLET(systemtray
, Applet
)
65 notificationInterface(0),
70 s_manager
= new SystemTray::Manager();
79 if (s_managerUsage
< 1) {
86 void setTaskAreaGeometry();
91 QPointer
<KActionSelector
> configInterface
;
92 QPointer
<QWidget
> notificationInterface
;
93 QCheckBox
*showNotifications
;
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
),
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);
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()) {
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()));
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
;
180 policy
.setVerticalPolicy(QSizePolicy::Expanding
);
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
) {
195 SystemTray::Manager
*Applet::manager() const
200 void Applet::setGeometry(const QRectF
&rect
)
202 Plasma::Applet::setGeometry(rect
);
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);
234 if (actualSize
.width() > actualSize
.height()) {
235 constraint
= QSize(actualSize
.width() - leftMargin
- rightMargin
, -1);
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
)
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
);
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
);
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()));
316 void Applet::propogateSizeHintChange(Qt::SizeHint which
)
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();
362 foreach (Task
*task
, Private::s_manager
->tasks()) {
363 if (!task
->isHideable()) {
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
);
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
*)));
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
*)));
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()));
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()));
446 void Applet::initExtenderItem(Plasma::ExtenderItem
*extenderItem
)
448 if (extenderItem
->config().readEntry("type", "") == "notification") {
449 extenderItem
->setWidget(new NotificationWidget(0, extenderItem
));
451 extenderItem
->setWidget(new JobWidget(0, extenderItem
));
455 void Applet::hidePopupIfEmpty()
457 if (d
->extenderTask
&& extender()->attachedItems().isEmpty()) {
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
463 delete d
->extenderTask
;
468 void Applet::popupEvent(bool visibility
)
470 kDebug() << visibility
<< extender()->attachedItems().isEmpty();
471 if (extender()->attachedItems().isEmpty()) {
472 delete d
->extenderTask
;
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"