1
/*****************************************************************
3
Copyright 2008 Christian Mollekopf <chrigi_1@hotmail.com>
5
Permission is hereby granted, free of charge, to any person obtaining a copy
6
of this software and associated documentation files (the "Software"), to deal
7
in the Software without restriction, including without limitation the rights
8
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
copies of the Software, and to permit persons to whom the Software is
10
furnished to do so, subject to the following conditions:
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
******************************************************************/
25
#include "taskgroup.h"
26
#include "taskmanager.h"
28
#include "groupmanager.h"
31
#include <QtGui/QColor>
32
#include <QtCore/QMimeData>
33
#include <QtCore/QTimer>
38
#include <ksharedptr.h>
46
class TaskGroup::Private
49
Private(TaskGroup *group)
54
void itemDestroyed(AbstractGroupableItem *item);
55
void itemChanged(::TaskManager::TaskChanges changes);
56
void signalRemovals();
59
QList<AbstractGroupableItem *> signalRemovalsFor;
65
GroupManager *groupingStrategy;
66
bool persistentWithLauncher;
69
TaskGroup::TaskGroup(GroupManager *parent,const QString &name, const QColor &color)
70
: AbstractGroupableItem(parent),
73
d->groupingStrategy = parent;
75
d->groupColor = color;
76
d->groupIcon = KIcon("xorg");
77
d->persistentWithLauncher = false;
79
//kDebug() << "Group Created: Name: " << d->groupName << "Color: " << d->groupColor;
82
TaskGroup::TaskGroup(GroupManager *parent)
83
: AbstractGroupableItem(parent),
86
d->groupingStrategy = parent;
87
// d->groupName = "default";
88
d->groupColor = Qt::red;
89
d->groupIcon = KIcon("xorg");
90
d->persistentWithLauncher = false;
92
//kDebug() << "Group Created: Name: " << d->groupName << "Color: " << d->groupColor;
96
TaskGroup::~TaskGroup()
103
WindowList TaskGroup::winIds() const
105
kDebug() << name() << d->members.size();
106
if (d->members.isEmpty()) {
107
kDebug() << "empty group: " << name();
110
foreach (AbstractGroupableItem *groupable, d->members) {
111
ids+=groupable->winIds();
113
kDebug() << ids.size();
118
WindowList TaskGroup::directMemberwinIds() const
121
foreach (AbstractGroupableItem *groupable, d->members) {
122
if (!groupable->itemType() == GroupItemType) {
123
ids+=groupable->winIds();
129
AbstractGroupableItem *TaskGroup::getMemberByWId(WId id)
131
foreach (AbstractGroupableItem *groupable, d->members) {
132
if (groupable->itemType() == GroupItemType) {
133
AbstractGroupableItem *item = static_cast<TaskGroup*>(groupable)->getMemberByWId(id);
138
if (groupable->winIds().isEmpty()) {
141
if (groupable->winIds().values().first() == id) {
146
//kDebug() << "item not found";
150
//including subgroups
151
int TaskGroup::totalSize()
154
foreach (AbstractGroupableItem *groupable, d->members) {
155
if (groupable->itemType() == GroupItemType) {
156
size += static_cast<TaskGroup*>(groupable)->totalSize();
164
void TaskGroup::add(AbstractGroupableItem *item)
166
/* if (!item->itemType() == GroupItemType) {
167
if ((dynamic_cast<TaskItem*>(item))->task()) {
168
kDebug() << "Add item" << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
170
kDebug() << " to Group " << name();
174
kDebug() << "invalid item";
178
if (d->members.contains(item)) {
179
//kDebug() << "already in this group";
183
if (d->groupName.isEmpty()) {
184
TaskItem *taskItem = qobject_cast<TaskItem*>(item);
186
d->groupName = taskItem->task()->classClass();
190
if (item->parentGroup()) {
191
item->parentGroup()->remove(item);
192
} else if (item->itemType() == GroupItemType) {
193
TaskGroup *group = static_cast<TaskGroup*>(item);
195
foreach (AbstractGroupableItem *subItem, group->members()) {
196
connect(subItem, SIGNAL(changed(::TaskManager::TaskChanges)),
197
item, SLOT(itemChanged(::TaskManager::TaskChanges)), Qt::UniqueConnection);
202
int index = d->members.count();
203
if (item->itemType() == LauncherItemType) {
204
// insert launchers together at the head of the list, but still
205
// in the order they appear
206
for (index = 0; index < d->members.count(); ++index) {
207
if (d->members.at(index)->itemType() != LauncherItemType) {
213
item->setParentGroup(this);
214
emit itemAboutToBeAdded(item, index);
215
d->members.insert(index, item);
218
connect(item, SIGNAL(destroyed(AbstractGroupableItem*)),
219
this, SLOT(itemDestroyed(AbstractGroupableItem*)));
220
//if the item will gain a parent those connections will be added by the if up there
221
if (!isRootGroup()) {
222
connect(item, SIGNAL(changed(::TaskManager::TaskChanges)),
223
this, SLOT(itemChanged(::TaskManager::TaskChanges)));
227
/* foreach (AbstractGroupableItem *item, d->members) {
228
if (item->itemType() == GroupItemType) {
229
kDebug() << (dynamic_cast<TaskGroup*>(item))->name();
231
kDebug() << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
234
emit itemAdded(item);
237
void TaskGroup::Private::itemDestroyed(AbstractGroupableItem *item)
239
emit q->itemAboutToBeRemoved(item);
240
members.removeAll(item);
241
signalRemovalsFor << item;
242
QTimer::singleShot(0, q, SLOT(signalRemovals()));
245
void TaskGroup::Private::signalRemovals()
247
// signal removals for is full of dangling pointers. do not use them!
248
foreach (AbstractGroupableItem *item, signalRemovalsFor) {
249
emit q->itemRemoved(item);
252
signalRemovalsFor.clear();
255
void TaskGroup::Private::itemChanged(::TaskManager::TaskChanges changes)
257
if (changes & ::TaskManager::IconChanged) {
258
emit q->checkIcon(q);
261
if (changes & StateChanged) {
262
emit q->changed(StateChanged);
266
void TaskGroup::remove(AbstractGroupableItem *item)
271
if (item->itemType() == GroupItemType) {
272
kDebug() << "Remove group" << (dynamic_cast<TaskGroup*>(item))->name();
273
} else if ((dynamic_cast<TaskItem*>(item))->task()) {
274
kDebug() << "Remove item" << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
276
kDebug() << "from Group: " << name();
279
/* kDebug() << "GroupMembers: ";
280
foreach (AbstractGroupableItem *item, d->members) {
281
if (item->itemType() == GroupItemType) {
282
kDebug() << (dynamic_cast<TaskGroup*>(item))->name();
284
kDebug() << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
288
if (!d->members.contains(item)) {
289
kDebug() << "couldn't find item";
293
emit itemAboutToBeRemoved(item);
294
disconnect(item, 0, this, 0);
296
d->members.removeAll(item);
297
item->setParentGroup(0);
298
/*if(d->members.isEmpty()){
302
emit itemRemoved(item);
305
ItemList TaskGroup::members() const
310
void TaskGroup::setColor(const QColor &color)
312
d->groupColor = color;
313
emit changed(ColorChanged);
316
QColor TaskGroup::color() const
318
return d->groupColor;
321
QString TaskGroup::name() const
326
void TaskGroup::setName(const QString &newName)
328
d->groupName = newName;
329
emit changed(NameChanged);
332
QIcon TaskGroup::icon() const
337
void TaskGroup::setIcon(const QIcon &newIcon)
339
d->groupIcon = newIcon;
340
emit changed(IconChanged);
343
ItemType TaskGroup::itemType() const
345
return GroupItemType;
348
bool TaskGroup::isGroupItem() const
353
bool TaskGroup::isPersistentWithLauncher() const
355
return d->persistentWithLauncher;
358
void TaskGroup::setPersistentWithLauncher(bool persistentWithLauncher)
360
d->persistentWithLauncher = persistentWithLauncher;
363
bool TaskGroup::isRootGroup() const
365
return !parentGroup();
368
/** only true if item is in this group */
369
bool TaskGroup::hasDirectMember(AbstractGroupableItem *item) const
371
return d->members.contains(item);
374
/** true if item is in this or any sub group */
375
bool TaskGroup::hasMember(AbstractGroupableItem *item) const
378
TaskGroup *group = item->parentGroup();
383
group = group->parentGroup();
388
/** Returns Direct Member group if the passed item is in a subgroup */
389
AbstractGroupableItem *TaskGroup::directMember(AbstractGroupableItem *item) const
391
AbstractGroupableItem *tempItem = item;
393
if (d->members.contains(item)) {
396
tempItem = tempItem->parentGroup();
399
kDebug() << "item not found";
403
void TaskGroup::setShaded(bool state)
405
foreach (AbstractGroupableItem *item, d->members) {
406
item->setShaded(state);
410
void TaskGroup::toggleShaded()
412
setShaded(!isShaded());
415
bool TaskGroup::isShaded() const
417
foreach (AbstractGroupableItem *item, d->members) {
418
if (!item->isShaded()) {
425
void TaskGroup::toDesktop(int desk)
427
foreach (AbstractGroupableItem *item, d->members) {
428
item->toDesktop(desk);
430
emit movedToDesktop(desk);
433
bool TaskGroup::isOnCurrentDesktop() const
435
foreach (AbstractGroupableItem *item, d->members) {
436
if (!item->isOnCurrentDesktop()) {
443
void TaskGroup::addMimeData(QMimeData *mimeData) const
445
//kDebug() << d->members.count();
446
if (d->members.isEmpty()) {
451
WindowList ids = winIds();
452
int count = ids.count();
453
data.resize(sizeof(int) + sizeof(WId) * count);
454
memcpy(data.data(), &count, sizeof(int));
456
foreach (WId id, ids) {
457
//kDebug() << "adding" << id;
458
memcpy(data.data() + sizeof(int) + sizeof(WId) * i, &id, sizeof(WId));
462
//kDebug() << "done:" << data.size() << count;
463
mimeData->setData(Task::groupMimetype(), data);
466
KUrl TaskGroup::launcherUrl() const
468
// Strategy: try to return the first non-group item's launcherUrl,
469
// failing that, try to return the launcherUrl of the first group
471
foreach (AbstractGroupableItem *item, d->members) {
472
if (item->itemType() != GroupItemType) {
473
return item->launcherUrl();
477
if (d->members.isEmpty()) {
481
return d->members.first()->launcherUrl();
484
bool TaskGroup::isOnAllDesktops() const
486
foreach (AbstractGroupableItem *item, d->members) {
487
if (!item->isOnAllDesktops()) {
494
//return 0 if tasks are on different desktops or on all dektops
495
int TaskGroup::desktop() const
497
if (d->members.isEmpty()) {
501
if (KWindowSystem::numberOfDesktops() < 2) {
505
int desk = d->members.first()->desktop();
506
foreach (AbstractGroupableItem *item, d->members) {
507
if (item->desktop() != desk) {
514
void TaskGroup::setMaximized(bool state)
516
foreach (AbstractGroupableItem *item, d->members) {
517
item->setMaximized(state);
521
void TaskGroup::toggleMaximized()
523
setMaximized(!isMaximized());
526
bool TaskGroup::isMaximized() const
528
foreach (AbstractGroupableItem *item, d->members) {
529
if (!item->isMaximized()) {
536
void TaskGroup::setMinimized(bool state)
538
foreach (AbstractGroupableItem *item, d->members) {
539
item->setMinimized(state);
543
void TaskGroup::toggleMinimized()
545
setMinimized(!isMinimized());
548
bool TaskGroup::isMinimized() const
550
foreach (AbstractGroupableItem *item, d->members) {
551
if (!item->isMinimized()) {
558
void TaskGroup::setFullScreen(bool state)
560
foreach (AbstractGroupableItem *item, d->members) {
561
item->setFullScreen(state);
565
void TaskGroup::toggleFullScreen()
567
setFullScreen(!isFullScreen());
570
bool TaskGroup::isFullScreen() const
572
foreach (AbstractGroupableItem *item, d->members) {
573
if (!item->isFullScreen()) {
580
void TaskGroup::setKeptBelowOthers(bool state)
582
foreach (AbstractGroupableItem *item, d->members) {
583
item->setKeptBelowOthers(state);
587
void TaskGroup::toggleKeptBelowOthers()
589
setKeptBelowOthers(!isKeptBelowOthers());
592
bool TaskGroup::isKeptBelowOthers() const
594
foreach (AbstractGroupableItem *item, d->members) {
595
if (!item->isKeptBelowOthers()) {
602
void TaskGroup::setAlwaysOnTop(bool state)
604
foreach (AbstractGroupableItem *item, d->members) {
605
item->setAlwaysOnTop(state);
609
void TaskGroup::toggleAlwaysOnTop()
611
setAlwaysOnTop(!isAlwaysOnTop());
614
bool TaskGroup::isAlwaysOnTop() const
616
foreach (AbstractGroupableItem *item, d->members) {
617
if (!item->isAlwaysOnTop()) {
624
bool TaskGroup::isActionSupported(NET::Action action) const
626
if (KWindowSystem::allowedActionsSupported()) {
627
foreach (AbstractGroupableItem *item, d->members) {
628
if (!item->isActionSupported(action)) {
637
void TaskGroup::close()
639
foreach (AbstractGroupableItem *item, d->members) {
644
bool TaskGroup::isActive() const
646
foreach (AbstractGroupableItem *item, d->members) {
647
if (item->isActive()) {
655
bool TaskGroup::demandsAttention() const
657
foreach (AbstractGroupableItem *item, d->members) {
658
if (item->demandsAttention()) {
666
bool TaskGroup::moveItem(int oldIndex, int newIndex)
668
//kDebug() << oldIndex << newIndex;
669
if ((d->members.count() <= newIndex) || (newIndex < 0) ||
670
(d->members.count() <= oldIndex || oldIndex < 0)) {
671
kDebug() << "index out of bounds";
675
AbstractGroupableItem *item = d->members.at(oldIndex);
676
emit itemAboutToMove(item, oldIndex, newIndex);
677
d->members.move(oldIndex, newIndex);
678
emit itemPositionChanged(item);
682
} // TaskManager namespace
684
#include "taskgroup.moc"