1
/***************************************************************************
4
* Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com> *
6
* This program is free software; you can redistribute it and/or modify *
7
* it under the terms of the GNU General Public License as published by *
8
* the Free Software Foundation; either version 2 of the License, or *
9
* (at your option) any later version. *
11
* This program is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU General Public License for more details. *
16
* You should have received a copy of the GNU General Public License *
17
* along with this program; if not, write to the *
18
* Free Software Foundation, Inc., *
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
20
***************************************************************************/
24
#include <QtCore/QSet>
25
#include <QtCore/QTimer>
26
#include <QtGui/QApplication>
27
#include <QtGui/QGraphicsGridLayout>
28
#include <QtGui/QGraphicsLinearLayout>
29
#include <QtGui/QWidget> // QWIDGETSIZE_MAX
30
#include <QtGui/QGraphicsScene>
31
#include <QGraphicsSceneMouseEvent>
34
#include <KIconLoader>
36
#include <Plasma/Containment>
37
#include <Plasma/IconWidget>
38
#include <Plasma/ItemBackground>
39
#include <Plasma/Label>
40
#include <Plasma/ToolTipManager>
42
#include "../core/manager.h"
43
#include "../core/task.h"
46
#include "compactlayout.h"
47
#include "taskarea_p.h"
52
class TaskArea::Private
55
Private(SystemTray::Applet *h)
58
topLayout(new QGraphicsLinearLayout(Qt::Horizontal)),
59
firstTasksLayout(new CompactLayout()),
60
normalTasksLayout(new CompactLayout()),
61
lastTasksLayout(new CompactLayout()),
62
location(Plasma::BottomEdge),
63
sizeHintChanged(false)
67
bool isTaskProperlyPlaced(Task *task, QGraphicsWidget *widget)
69
//kDebug() << "========" << task->name() << "==========";
70
//kDebug() << " " << task->hidden() << Task::NotHidden << task->category() << host->shownCategories().contains(task->category());
71
if (task->hidden() == Task::NotHidden && host->shownCategories().contains(task->category())) {
72
//kDebug() << " " << task->order() << firstTasksLayout->containsItem(widget) << lastTasksLayout->containsItem(widget) << normalTasksLayout->containsItem(widget);
73
if (task->order() == SystemTray::Task::First && firstTasksLayout->containsItem(widget)) {
75
} else if (task->order() == SystemTray::Task::Last && lastTasksLayout->containsItem(widget)) {
77
} else if (task->order() == SystemTray::Task::Normal && normalTasksLayout->containsItem(widget) ) {
78
if (taskCategories.contains(task) && taskCategories.value(task) == task->category()) {
81
taskCategories[task] = task->category();
90
SystemTray::Applet *host;
91
Plasma::IconWidget *unhider;
92
QGraphicsLinearLayout *topLayout;
93
CompactLayout *firstTasksLayout;
94
CompactLayout *normalTasksLayout;
95
QHash<Task *, Task::Category> taskCategories;
96
QHash<QGraphicsWidget *, SystemTray::Task*> taskForWidget;
97
CompactLayout *lastTasksLayout;
98
QGraphicsWidget *hiddenTasksWidget;
99
QGraphicsGridLayout *hiddenTasksLayout;
100
Plasma::Location location;
101
Plasma::ItemBackground *itemBackground;
102
QTimer *hiddenRelayoutTimer;
103
bool sizeHintChanged;
105
QSet<QString> hiddenTypes;
106
QSet<QString> alwaysShownTypes;
107
QHash<SystemTray::Task*, HiddenTaskLabel *> hiddenTasks;
111
TaskArea::TaskArea(SystemTray::Applet *parent)
112
: QGraphicsWidget(parent),
113
d(new Private(parent))
115
d->itemBackground = new Plasma::ItemBackground;
116
setLayout(d->topLayout);
117
d->topLayout->addItem(d->firstTasksLayout);
118
d->topLayout->addItem(d->normalTasksLayout);
119
d->topLayout->addItem(d->lastTasksLayout);
120
d->topLayout->setContentsMargins(0, 0, 0, 0);
121
d->topLayout->setSpacing(5);
123
d->hiddenTasksWidget = new QGraphicsWidget(this);
124
d->hiddenTasksLayout = new QGraphicsGridLayout(d->hiddenTasksWidget);
125
d->hiddenTasksLayout->setHorizontalSpacing(0);
127
d->hiddenRelayoutTimer = new QTimer(this);
128
d->hiddenRelayoutTimer->setSingleShot(true);
129
connect(d->hiddenRelayoutTimer, SIGNAL(timeout()), this, SLOT(relayoutHiddenTasks()));
133
TaskArea::~TaskArea()
135
delete d->firstTasksLayout;
136
delete d->normalTasksLayout;
137
delete d->lastTasksLayout;
138
delete d->itemBackground;
142
QGraphicsWidget *TaskArea::hiddenTasksWidget() const
144
return d->hiddenTasksWidget;
147
void TaskArea::setHiddenTypes(const QStringList &hiddenTypes)
149
d->hiddenTypes = QSet<QString>::fromList(hiddenTypes);
152
QStringList TaskArea::hiddenTypes() const
154
return d->hiddenTypes.toList();
157
void TaskArea::setAlwaysShownTypes(const QStringList &alwaysShownTypes)
159
d->alwaysShownTypes.clear();
161
foreach (const QString &type, alwaysShownTypes) {
162
if (!d->hiddenTypes.contains(type)) {
163
d->alwaysShownTypes.insert(type);
168
QStringList TaskArea::alwaysShownTypes() const
170
return d->alwaysShownTypes.toList();
173
void TaskArea::syncTasks(const QList<SystemTray::Task*> &tasks)
175
bool changedPositioning = false;
176
foreach (Task *task, tasks) {
177
//kDebug() << "checking" << task->name() << task->typeId() << d->alwaysShownTypes;
178
changedPositioning = addWidgetForTask(task) || changedPositioning;
181
if (checkUnhideTool() || changedPositioning) {
182
d->topLayout->invalidate();
183
emit sizeHintChanged(Qt::PreferredSize);
187
void TaskArea::addTask(Task *task)
189
bool changedPositioning = addWidgetForTask(task);
190
if (checkUnhideTool() || changedPositioning) {
191
d->topLayout->invalidate();
192
emit sizeHintChanged(Qt::PreferredSize);
196
void TaskArea::checkVisibility(Task *task)
198
if (d->hiddenTypes.contains(task->typeId())) {
199
task->setHidden(task->hidden() | Task::UserHidden);
200
} else if (d->alwaysShownTypes.contains(task->typeId())) {
201
task->setHidden(task->hidden() & ~Task::UserHidden);
202
task->setHidden(task->hidden() & ~Task::AutoHidden);
203
} else if (task->hidden() & Task::UserHidden) {
204
task->setHidden(task->hidden() & ~Task::UserHidden);
206
task->resetHiddenStatus();
210
bool TaskArea::removeFromHiddenArea(SystemTray::Task *task)
212
if (!d->hiddenTasks.contains(task)) {
216
QGraphicsWidget *widget = task->widget(d->host, false);
217
QGraphicsWidget *taskLabel = d->hiddenTasks.value(task);
220
for (int i = 0; i < d->hiddenTasksLayout->count(); ++i) {
221
if (d->hiddenTasksLayout->itemAt(i) == widget) {
222
d->hiddenTasksLayout->removeAt(i);
229
disconnect(task, 0, taskLabel, 0);
230
for (int i = 0; i < d->hiddenTasksLayout->count(); ++i) {
231
if (d->hiddenTasksLayout->itemAt(i) == taskLabel) {
232
d->hiddenTasksLayout->removeAt(i);
236
taskLabel->deleteLater();
240
d->hiddenTasks.remove(task);
241
d->hiddenRelayoutTimer->start(250);
245
bool TaskArea::addWidgetForTask(SystemTray::Task *task)
247
//kDebug() << "adding task" << task->name();
248
if (!task->isEmbeddable(d->host)) {
249
//kDebug() << "task is not embeddable, so FAIL" << task->name();
254
checkVisibility(task);
255
QGraphicsWidget *widget = task->widget(d->host);
258
//kDebug() << "embeddable, but we received no widget?!";
262
//check if it's not necessary to move the icon
263
if (d->isTaskProperlyPlaced(task, widget)) {
264
//kDebug() << "widget is properly placed";
268
//kDebug() << "widget already exists, trying to reposition it";
269
d->firstTasksLayout->removeItem(widget);
270
d->normalTasksLayout->removeItem(widget);
271
d->lastTasksLayout->removeItem(widget);
272
if (d->firstTasksLayout->count() == 0) {
273
d->topLayout->removeItem(d->firstTasksLayout);
276
//If the applet doesn't want to show FDO tasks, remove (not just hide) any of them
277
//if the dbus icon has a category that the applet doesn't want to show remove it
278
if (!d->host->shownCategories().contains(task->category()) && !qobject_cast<Plasma::Applet *>(widget)) {
279
removeFromHiddenArea(task);
280
task->abandon(d->host);
284
d->taskForWidget.insert(widget, task);
286
// keep track of the hidden tasks
287
// needs to be done because if a task is added multiple times (like when coming out of sleep)
288
// it may be autohidden for a while until the final one which will not be hidden
289
// therefore we need a way to track the hidden tasks
290
// if the task appears in the hidden list, then we know there are hidden tasks
291
if (task->hidden() == Task::NotHidden) {
292
if (removeFromHiddenArea(task)) {
293
widget->setParentItem(this);
296
// hiddent task, so make sure it's handled
297
if (!d->hiddenTasks.contains(task)) {
298
HiddenTaskLabel *hiddenLabel = new HiddenTaskLabel(widget, task->name(), d->itemBackground, d->host, d->hiddenTasksWidget);
299
connect(task, SIGNAL(changed(SystemTray::Task*)), hiddenLabel, SLOT(taskChanged(SystemTray::Task*)));
300
d->hiddenTasks.insert(task, hiddenLabel);
302
const int row = d->hiddenTasksLayout->rowCount();
303
widget->setParentItem(d->hiddenTasksWidget);
304
//kDebug() << "putting" << task->name() << widget << "into" << row;
305
QFontMetrics fm(font());
306
d->hiddenTasksLayout->setRowFixedHeight(row, qMax(24, fm.height()));
307
d->hiddenTasksLayout->addItem(widget, row, 0);
308
d->hiddenTasksLayout->addItem(hiddenLabel, row, 1);
309
adjustHiddentTasksWidget();
317
if (task->hidden() == Task::NotHidden) {
318
widget->setParentItem(this);
319
//not really pretty, but for consistency attempts to put the notifications applet always in the same position
320
if (task->typeId() == "notifications") {
321
if (d->firstTasksLayout->count() == 0) {
322
d->topLayout->insertItem(0, d->firstTasksLayout);
325
d->firstTasksLayout->insertItem(0, widget);
326
} else if (task->order() == SystemTray::Task::First) {
327
if (d->firstTasksLayout->count() == 0) {
328
d->topLayout->insertItem(0, d->firstTasksLayout);
331
d->firstTasksLayout->addItem(widget);
332
} else if (task->order() == SystemTray::Task::Normal) {
333
int insertIndex = -1;
334
for (int i = 0; i < d->normalTasksLayout->count(); ++i) {
335
QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(d->normalTasksLayout->itemAt(i));
336
Task *otherTask = d->taskForWidget.value(widget);
338
if (task->category() == Task::UnknownCategory) {
341
} else if (otherTask && task->category() <= otherTask->category()) {
347
if (insertIndex == -1) {
348
insertIndex = d->normalTasksLayout->count();
351
d->normalTasksLayout->insertItem(insertIndex, widget);
353
d->lastTasksLayout->insertItem(0, widget);
355
d->sizeHintChanged = true;
360
//the applet could have to be repainted due to easement change
361
QTimer::singleShot(0, this, SLOT(delayedAppletUpdate()));
365
void TaskArea::delayedAppletUpdate()
368
if (d->sizeHintChanged) {
369
emit sizeHintChanged(Qt::PreferredSize);
370
d->sizeHintChanged = false;
374
void TaskArea::removeTask(Task *task)
376
bool sizeChanged = removeFromHiddenArea(task);
378
QGraphicsWidget *widget = task->widget(d->host, false);
380
//try to remove from all three layouts, one will succeed
381
d->firstTasksLayout->removeItem(widget);
382
if (d->firstTasksLayout->count() == 0) {
383
d->topLayout->removeItem(d->firstTasksLayout);
385
d->normalTasksLayout->removeItem(widget);
386
d->lastTasksLayout->removeItem(widget);
387
if (d->lastTasksLayout->count() == 0) {
388
d->topLayout->removeItem(d->lastTasksLayout);
390
d->taskForWidget.remove(widget);
391
d->taskCategories.remove(task);
393
d->topLayout->invalidate();
398
emit sizeHintChanged(Qt::PreferredSize);
403
void TaskArea::relayoutHiddenTasks()
405
for (int i = 0; i < d->hiddenTasksLayout->count(); ++i) {
406
d->hiddenTasksLayout->removeAt(i);
409
for (int i = 0; i < d->hiddenTasksLayout->rowCount(); ++i) {
410
d->hiddenTasksLayout->setRowFixedHeight(i, 0);
413
QHash<SystemTray::Task*, HiddenTaskLabel *>::const_iterator i = d->hiddenTasks.constBegin();
415
while (i != d->hiddenTasks.constEnd()) {
416
d->hiddenTasksLayout->addItem(i.key()->widget(d->host), row, 0);
417
d->hiddenTasksLayout->addItem(i.value(), row, 1);
418
d->hiddenTasksLayout->setRowFixedHeight(row, 24);
423
adjustHiddentTasksWidget();
426
void TaskArea::adjustHiddentTasksWidget()
428
d->hiddenTasksLayout->invalidate();
429
d->hiddenTasksWidget->resize(d->hiddenTasksWidget->effectiveSizeHint(Qt::PreferredSize));
432
int TaskArea::leftEasement() const
434
if (d->firstTasksLayout->count() > 0) {
435
// d->firstTasksLayout->invalidate();
436
// d->firstTasksLayout->updateGeometry();
437
QGraphicsLayoutItem *item = d->firstTasksLayout->itemAt(d->firstTasksLayout->count() - 1);
439
if (d->topLayout->orientation() == Qt::Vertical) {
440
return item->geometry().bottom() + d->topLayout->spacing()/2;
441
} else if (QApplication::layoutDirection() == Qt::RightToLeft) {
442
return size().width() - item->geometry().left() + d->topLayout->spacing()/2;
444
return item->geometry().right() + d->topLayout->spacing()/2;
451
int TaskArea::rightEasement() const
453
if (d->lastTasksLayout->count() > 0) {
454
// d->lastTasksLayout->invalidate();
455
// d->lastTasksLayout->updateGeometry();
456
QGraphicsLayoutItem *item = d->lastTasksLayout->itemAt(0);
458
if (d->topLayout->orientation() == Qt::Vertical) {
459
return size().height() - item->geometry().top() + d->topLayout->spacing()/2;
460
} else if (QApplication::layoutDirection() == Qt::RightToLeft) {
461
return item->geometry().right() + d->topLayout->spacing()/2;
463
return size().width() - item->geometry().left() + d->topLayout->spacing()/2;
470
void TaskArea::setOrientation(Qt::Orientation o)
472
d->topLayout->setOrientation(o);
474
updateUnhideToolIcon();
476
syncTasks(d->host->manager()->tasks());
479
void TaskArea::updateUnhideToolIcon()
485
d->unhider->setPreferredIconSize(QSize(16,16));
486
if (d->topLayout->orientation() == Qt::Horizontal) {
487
d->unhider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
489
d->unhider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
492
const bool showing = d->host->isPopupShowing();
493
Plasma::ToolTipContent data;
495
data.setSubText(i18n("Hide icons"));
497
data.setSubText(i18n("Show hidden icons"));
499
Plasma::ToolTipManager::self()->setContent(d->unhider, data);
501
switch(d->location) {
502
case Plasma::LeftEdge:
504
d->unhider->setSvg("widgets/arrows", "left-arrow");
506
d->unhider->setSvg("widgets/arrows", "right-arrow");
509
case Plasma::RightEdge:
511
d->unhider->setSvg("widgets/arrows", "right-arrow");
513
d->unhider->setSvg("widgets/arrows", "left-arrow");
516
case Plasma::TopEdge:
518
d->unhider->setSvg("widgets/arrows", "up-arrow");
520
d->unhider->setSvg("widgets/arrows", "down-arrow");
523
case Plasma::BottomEdge:
526
d->unhider->setSvg("widgets/arrows", "down-arrow");
528
d->unhider->setSvg("widgets/arrows", "up-arrow");
533
bool TaskArea::checkUnhideTool()
535
if (d->hiddenTasks.isEmpty()) {
537
// hide the show tool
538
d->topLayout->removeItem(d->unhider);
539
d->unhider->deleteLater();
543
} else if (!d->unhider) {
544
d->unhider = new Plasma::IconWidget(this);
545
updateUnhideToolIcon();
547
d->topLayout->addItem(d->unhider);
548
connect(d->unhider, SIGNAL(clicked()), this, SIGNAL(toggleHiddenItems()));
555
void TaskArea::setLocation(Plasma::Location location)
557
d->location = location;
558
updateUnhideToolIcon();
563
#include "taskarea.moc"
564
#include "taskarea_p.moc"