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

« back to all changes in this revision

Viewing changes to libs/taskmanager/taskgroup.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
 
 
3
Copyright 2008 Christian Mollekopf <chrigi_1@hotmail.com>
 
4
 
 
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:
 
11
 
 
12
The above copyright notice and this permission notice shall be included in
 
13
all copies or substantial portions of the Software.
 
14
 
 
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.
 
21
 
 
22
******************************************************************/
 
23
 
 
24
// Own
 
25
#include "taskgroup.h"
 
26
#include "taskmanager.h"
 
27
#include "taskitem.h"
 
28
#include "groupmanager.h"
 
29
 
 
30
// Qt
 
31
#include <QtGui/QColor>
 
32
#include <QtCore/QMimeData>
 
33
#include <QtCore/QTimer>
 
34
 
 
35
// KDE
 
36
#include <KDE/KDebug>
 
37
#include <KDE/KIcon>
 
38
#include <ksharedptr.h>
 
39
 
 
40
 
 
41
 
 
42
namespace TaskManager
 
43
{
 
44
 
 
45
 
 
46
class TaskGroup::Private
 
47
{
 
48
public:
 
49
    Private(TaskGroup *group)
 
50
        : q(group)
 
51
    {
 
52
    }
 
53
 
 
54
    void itemDestroyed(AbstractGroupableItem *item);
 
55
    void itemChanged(::TaskManager::TaskChanges changes);
 
56
    void signalRemovals();
 
57
 
 
58
    TaskGroup *q;
 
59
    QList<AbstractGroupableItem *> signalRemovalsFor;
 
60
    ItemList members;
 
61
    QString groupName;
 
62
    QColor groupColor;
 
63
    QIcon groupIcon;
 
64
    bool aboutToDie;
 
65
    GroupManager *groupingStrategy;
 
66
    bool persistentWithLauncher;
 
67
};
 
68
 
 
69
TaskGroup::TaskGroup(GroupManager *parent,const QString &name, const QColor &color)
 
70
:   AbstractGroupableItem(parent),
 
71
    d(new Private(this))
 
72
{
 
73
    d->groupingStrategy = parent;
 
74
    d->groupName = name;
 
75
    d->groupColor = color;
 
76
    d->groupIcon = KIcon("xorg");
 
77
    d->persistentWithLauncher = false;
 
78
 
 
79
    //kDebug() << "Group Created: Name: " << d->groupName << "Color: " << d->groupColor;
 
80
}
 
81
 
 
82
TaskGroup::TaskGroup(GroupManager *parent)
 
83
:   AbstractGroupableItem(parent),
 
84
    d(new Private(this))
 
85
{
 
86
    d->groupingStrategy = parent;
 
87
//    d->groupName = "default";
 
88
    d->groupColor = Qt::red;
 
89
    d->groupIcon = KIcon("xorg");
 
90
    d->persistentWithLauncher = false;
 
91
 
 
92
    //kDebug() << "Group Created: Name: " << d->groupName << "Color: " << d->groupColor;
 
93
}
 
94
 
 
95
 
 
96
TaskGroup::~TaskGroup()
 
97
{
 
98
    emit destroyed(this);
 
99
    //kDebug() << name();
 
100
    delete d;
 
101
}
 
102
 
 
103
WindowList TaskGroup::winIds() const
 
104
{
 
105
    kDebug() << name() << d->members.size();
 
106
    if (d->members.isEmpty()) {
 
107
        kDebug() << "empty group: " << name();
 
108
    }
 
109
    WindowList ids;
 
110
    foreach (AbstractGroupableItem *groupable, d->members) {
 
111
        ids+=groupable->winIds();
 
112
    }
 
113
    kDebug() << ids.size();
 
114
    return ids;
 
115
}
 
116
 
 
117
//TODO unused
 
118
WindowList TaskGroup::directMemberwinIds() const
 
119
{
 
120
    WindowList ids;
 
121
    foreach (AbstractGroupableItem *groupable, d->members) {
 
122
        if (!groupable->itemType() == GroupItemType) {
 
123
            ids+=groupable->winIds();
 
124
        }
 
125
    }
 
126
    return ids;
 
127
}
 
128
 
 
129
AbstractGroupableItem *TaskGroup::getMemberByWId(WId id)
 
130
{
 
131
    foreach (AbstractGroupableItem *groupable, d->members) {
 
132
        if (groupable->itemType() == GroupItemType) {
 
133
            AbstractGroupableItem *item = static_cast<TaskGroup*>(groupable)->getMemberByWId(id);
 
134
            if (item) {
 
135
                return item;
 
136
            }
 
137
        } else {
 
138
            if (groupable->winIds().isEmpty()) {
 
139
                continue;
 
140
            }
 
141
            if (groupable->winIds().values().first() == id) {
 
142
                return groupable;
 
143
            }
 
144
        }
 
145
    }
 
146
    //kDebug() << "item not found";
 
147
    return 0;
 
148
}
 
149
 
 
150
//including subgroups
 
151
int TaskGroup::totalSize()
 
152
{
 
153
    int size = 0;
 
154
    foreach (AbstractGroupableItem *groupable, d->members) {
 
155
        if (groupable->itemType() == GroupItemType) {
 
156
            size += static_cast<TaskGroup*>(groupable)->totalSize();
 
157
        } else {
 
158
            size++;
 
159
        }
 
160
    }
 
161
    return size;
 
162
}
 
163
 
 
164
void TaskGroup::add(AbstractGroupableItem *item)
 
165
{
 
166
/*    if (!item->itemType() == GroupItemType) {
 
167
        if ((dynamic_cast<TaskItem*>(item))->task()) {
 
168
            kDebug() << "Add item" << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
 
169
        }
 
170
        kDebug() << " to Group " << name();
 
171
    }
 
172
*/
 
173
    if (!item) {
 
174
        kDebug() << "invalid item";
 
175
        return;
 
176
    }
 
177
 
 
178
    if (d->members.contains(item)) {
 
179
        //kDebug() << "already in this group";
 
180
        return;
 
181
    }
 
182
 
 
183
    if (d->groupName.isEmpty()) {
 
184
        TaskItem *taskItem = qobject_cast<TaskItem*>(item);
 
185
        if (taskItem) {
 
186
            d->groupName = taskItem->task()->classClass();
 
187
        }
 
188
    }
 
189
 
 
190
    if (item->parentGroup()) {
 
191
        item->parentGroup()->remove(item);
 
192
    } else if (item->itemType() == GroupItemType) {
 
193
        TaskGroup *group = static_cast<TaskGroup*>(item);
 
194
        if (group) {
 
195
            foreach (AbstractGroupableItem *subItem, group->members()) {
 
196
                connect(subItem, SIGNAL(changed(::TaskManager::TaskChanges)),
 
197
                        item, SLOT(itemChanged(::TaskManager::TaskChanges)), Qt::UniqueConnection);
 
198
            }
 
199
        }
 
200
    }
 
201
 
 
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) {
 
208
                break;
 
209
            }
 
210
        }
 
211
    }
 
212
 
 
213
    item->setParentGroup(this);
 
214
    emit itemAboutToBeAdded(item, index);
 
215
    d->members.insert(index, item);
 
216
 
 
217
 
 
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)));
 
224
    }
 
225
 
 
226
    //For debug
 
227
   /* foreach (AbstractGroupableItem *item, d->members) {
 
228
        if (item->itemType() == GroupItemType) {
 
229
            kDebug() << (dynamic_cast<TaskGroup*>(item))->name();
 
230
        } else {
 
231
            kDebug() << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
 
232
        }
 
233
    }*/
 
234
    emit itemAdded(item);
 
235
}
 
236
 
 
237
void TaskGroup::Private::itemDestroyed(AbstractGroupableItem *item)
 
238
{
 
239
    emit q->itemAboutToBeRemoved(item);
 
240
    members.removeAll(item);
 
241
    signalRemovalsFor << item;
 
242
    QTimer::singleShot(0, q, SLOT(signalRemovals()));
 
243
}
 
244
 
 
245
void TaskGroup::Private::signalRemovals()
 
246
{
 
247
    // signal removals for is full of dangling pointers. do not use them!
 
248
    foreach (AbstractGroupableItem *item, signalRemovalsFor) {
 
249
        emit q->itemRemoved(item);
 
250
    }
 
251
 
 
252
    signalRemovalsFor.clear();
 
253
}
 
254
 
 
255
void TaskGroup::Private::itemChanged(::TaskManager::TaskChanges changes)
 
256
{
 
257
    if (changes & ::TaskManager::IconChanged) {
 
258
        emit q->checkIcon(q);
 
259
    }
 
260
 
 
261
    if (changes & StateChanged) {
 
262
        emit q->changed(StateChanged);
 
263
    }
 
264
}
 
265
 
 
266
void TaskGroup::remove(AbstractGroupableItem *item)
 
267
{
 
268
    Q_ASSERT(item);
 
269
 
 
270
    /*
 
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();
 
275
    }
 
276
    kDebug() << "from Group: " << name();
 
277
    */
 
278
 
 
279
   /* kDebug() << "GroupMembers: ";
 
280
    foreach (AbstractGroupableItem *item, d->members) {
 
281
        if (item->itemType() == GroupItemType) {
 
282
            kDebug() << (dynamic_cast<TaskGroup*>(item))->name();
 
283
        } else {
 
284
            kDebug() << (dynamic_cast<TaskItem*>(item))->task()->visibleName();
 
285
        }
 
286
    }*/
 
287
 
 
288
    if (!d->members.contains(item)) {
 
289
        kDebug() << "couldn't find item";
 
290
        return;
 
291
    }
 
292
 
 
293
    emit itemAboutToBeRemoved(item);
 
294
    disconnect(item, 0, this, 0);
 
295
 
 
296
    d->members.removeAll(item);
 
297
    item->setParentGroup(0);
 
298
    /*if(d->members.isEmpty()){
 
299
        kDebug() << "empty";
 
300
        emit empty(this);
 
301
    }*/
 
302
    emit itemRemoved(item);
 
303
}
 
304
 
 
305
ItemList TaskGroup::members() const
 
306
{
 
307
    return d->members;
 
308
}
 
309
 
 
310
void TaskGroup::setColor(const QColor &color)
 
311
{
 
312
    d->groupColor = color;
 
313
    emit changed(ColorChanged);
 
314
}
 
315
 
 
316
QColor TaskGroup::color() const
 
317
{
 
318
    return d->groupColor;
 
319
}
 
320
 
 
321
QString TaskGroup::name() const
 
322
{
 
323
    return d->groupName;
 
324
}
 
325
 
 
326
void TaskGroup::setName(const QString &newName)
 
327
{
 
328
    d->groupName = newName;
 
329
    emit changed(NameChanged);
 
330
}
 
331
 
 
332
QIcon TaskGroup::icon() const
 
333
{
 
334
    return d->groupIcon;
 
335
}
 
336
 
 
337
void TaskGroup::setIcon(const QIcon &newIcon)
 
338
{
 
339
    d->groupIcon = newIcon;
 
340
    emit changed(IconChanged);
 
341
}
 
342
 
 
343
ItemType TaskGroup::itemType() const
 
344
{
 
345
    return GroupItemType;
 
346
}
 
347
 
 
348
bool TaskGroup::isGroupItem() const
 
349
{
 
350
    return true;
 
351
}
 
352
 
 
353
bool TaskGroup::isPersistentWithLauncher() const
 
354
{
 
355
    return d->persistentWithLauncher;
 
356
}
 
357
 
 
358
void TaskGroup::setPersistentWithLauncher(bool persistentWithLauncher)
 
359
{
 
360
    d->persistentWithLauncher = persistentWithLauncher;
 
361
}
 
362
 
 
363
bool TaskGroup::isRootGroup() const
 
364
{
 
365
    return !parentGroup();
 
366
}
 
367
 
 
368
/** only true if item is in this group */
 
369
bool TaskGroup::hasDirectMember(AbstractGroupableItem *item) const
 
370
{
 
371
    return d->members.contains(item);
 
372
}
 
373
 
 
374
/** true if item is in this or any sub group */
 
375
bool TaskGroup::hasMember(AbstractGroupableItem *item) const
 
376
{
 
377
    //kDebug();
 
378
    TaskGroup *group = item->parentGroup();
 
379
    while (group) {
 
380
        if (group == this) {
 
381
            return true;
 
382
        }
 
383
        group = group->parentGroup();
 
384
    }
 
385
    return false;
 
386
}
 
387
 
 
388
/** Returns Direct Member group if the passed item is in a subgroup */
 
389
AbstractGroupableItem *TaskGroup::directMember(AbstractGroupableItem *item) const
 
390
{
 
391
    AbstractGroupableItem *tempItem = item;
 
392
    while (tempItem) {
 
393
        if (d->members.contains(item)) {
 
394
            return item;
 
395
        }
 
396
        tempItem = tempItem->parentGroup();
 
397
    }
 
398
 
 
399
    kDebug() << "item not found";
 
400
    return 0;
 
401
}
 
402
 
 
403
void TaskGroup::setShaded(bool state)
 
404
{
 
405
    foreach (AbstractGroupableItem *item, d->members) {
 
406
        item->setShaded(state);
 
407
    }
 
408
}
 
409
 
 
410
void TaskGroup::toggleShaded()
 
411
{
 
412
    setShaded(!isShaded());
 
413
}
 
414
 
 
415
bool TaskGroup::isShaded() const
 
416
{
 
417
    foreach (AbstractGroupableItem *item, d->members) {
 
418
        if (!item->isShaded()) {
 
419
            return false;
 
420
        }
 
421
    }
 
422
    return true;
 
423
}
 
424
 
 
425
void TaskGroup::toDesktop(int desk)
 
426
{
 
427
    foreach (AbstractGroupableItem *item, d->members) {
 
428
        item->toDesktop(desk);
 
429
    }
 
430
    emit movedToDesktop(desk);
 
431
}
 
432
 
 
433
bool TaskGroup::isOnCurrentDesktop() const
 
434
{
 
435
    foreach (AbstractGroupableItem *item, d->members) {
 
436
        if (!item->isOnCurrentDesktop()) {
 
437
            return false;
 
438
        }
 
439
    }
 
440
    return true;
 
441
}
 
442
 
 
443
void TaskGroup::addMimeData(QMimeData *mimeData) const
 
444
{
 
445
    //kDebug() << d->members.count();
 
446
    if (d->members.isEmpty()) {
 
447
        return;
 
448
    }
 
449
 
 
450
    QByteArray data;
 
451
    WindowList ids = winIds();
 
452
    int count = ids.count();
 
453
    data.resize(sizeof(int) + sizeof(WId) * count);
 
454
    memcpy(data.data(), &count, sizeof(int));
 
455
    int i = 0;
 
456
    foreach (WId id, ids) {
 
457
        //kDebug() << "adding" << id;
 
458
        memcpy(data.data() + sizeof(int) + sizeof(WId) * i, &id, sizeof(WId));
 
459
        ++i;
 
460
    }
 
461
 
 
462
    //kDebug() << "done:" << data.size() << count;
 
463
    mimeData->setData(Task::groupMimetype(), data);
 
464
}
 
465
 
 
466
KUrl TaskGroup::launcherUrl() const
 
467
{
 
468
    // Strategy: try to return the first non-group item's launcherUrl,
 
469
    // failing that, try to return the  launcherUrl of the first group
 
470
    // if any
 
471
    foreach (AbstractGroupableItem *item, d->members) {
 
472
        if (item->itemType() != GroupItemType) {
 
473
            return item->launcherUrl();
 
474
        }
 
475
    }
 
476
 
 
477
    if (d->members.isEmpty()) {
 
478
        return KUrl();
 
479
    }
 
480
 
 
481
    return d->members.first()->launcherUrl();
 
482
}
 
483
 
 
484
bool TaskGroup::isOnAllDesktops() const
 
485
{
 
486
    foreach (AbstractGroupableItem *item, d->members) {
 
487
        if (!item->isOnAllDesktops()) {
 
488
            return false;
 
489
        }
 
490
    }
 
491
    return true;
 
492
}
 
493
 
 
494
//return 0 if tasks are on different desktops or on all dektops
 
495
int TaskGroup::desktop() const
 
496
{
 
497
    if (d->members.isEmpty()) {
 
498
        return 0;
 
499
    }
 
500
 
 
501
    if (KWindowSystem::numberOfDesktops() < 2) {
 
502
        return 0;
 
503
    }
 
504
 
 
505
    int desk = d->members.first()->desktop();
 
506
    foreach (AbstractGroupableItem *item, d->members) {
 
507
        if (item->desktop() != desk) {
 
508
            return 0;
 
509
        }
 
510
    }
 
511
    return desk;
 
512
}
 
513
 
 
514
void TaskGroup::setMaximized(bool state)
 
515
{
 
516
    foreach (AbstractGroupableItem *item, d->members) {
 
517
        item->setMaximized(state);
 
518
    }
 
519
}
 
520
 
 
521
void TaskGroup::toggleMaximized()
 
522
{
 
523
    setMaximized(!isMaximized());
 
524
}
 
525
 
 
526
bool TaskGroup::isMaximized() const
 
527
{
 
528
    foreach (AbstractGroupableItem *item, d->members) {
 
529
        if (!item->isMaximized()) {
 
530
            return false;
 
531
        }
 
532
    }
 
533
    return true;
 
534
}
 
535
 
 
536
void TaskGroup::setMinimized(bool state)
 
537
{
 
538
    foreach (AbstractGroupableItem *item, d->members) {
 
539
        item->setMinimized(state);
 
540
    }
 
541
}
 
542
 
 
543
void TaskGroup::toggleMinimized()
 
544
{
 
545
    setMinimized(!isMinimized());
 
546
}
 
547
 
 
548
bool TaskGroup::isMinimized() const
 
549
{
 
550
    foreach (AbstractGroupableItem *item, d->members) {
 
551
        if (!item->isMinimized()) {
 
552
            return false;
 
553
        }
 
554
    }
 
555
    return true;
 
556
}
 
557
 
 
558
void TaskGroup::setFullScreen(bool state)
 
559
{
 
560
    foreach (AbstractGroupableItem *item, d->members) {
 
561
        item->setFullScreen(state);
 
562
    }
 
563
}
 
564
 
 
565
void TaskGroup::toggleFullScreen()
 
566
{
 
567
    setFullScreen(!isFullScreen());
 
568
}
 
569
 
 
570
bool TaskGroup::isFullScreen() const
 
571
{
 
572
    foreach (AbstractGroupableItem *item, d->members) {
 
573
        if (!item->isFullScreen()) {
 
574
            return false;
 
575
        }
 
576
    }
 
577
    return true;
 
578
}
 
579
 
 
580
void TaskGroup::setKeptBelowOthers(bool state)
 
581
{
 
582
    foreach (AbstractGroupableItem *item, d->members) {
 
583
        item->setKeptBelowOthers(state);
 
584
    }
 
585
}
 
586
 
 
587
void TaskGroup::toggleKeptBelowOthers()
 
588
{
 
589
    setKeptBelowOthers(!isKeptBelowOthers());
 
590
}
 
591
 
 
592
bool TaskGroup::isKeptBelowOthers() const
 
593
{
 
594
    foreach (AbstractGroupableItem *item, d->members) {
 
595
        if (!item->isKeptBelowOthers()) {
 
596
            return false;
 
597
        }
 
598
    }
 
599
    return true;
 
600
}
 
601
 
 
602
void TaskGroup::setAlwaysOnTop(bool state)
 
603
{
 
604
    foreach (AbstractGroupableItem *item, d->members) {
 
605
        item->setAlwaysOnTop(state);
 
606
    }
 
607
}
 
608
 
 
609
void TaskGroup::toggleAlwaysOnTop()
 
610
{
 
611
    setAlwaysOnTop(!isAlwaysOnTop());
 
612
}
 
613
 
 
614
bool TaskGroup::isAlwaysOnTop() const
 
615
{
 
616
    foreach (AbstractGroupableItem *item, d->members) {
 
617
        if (!item->isAlwaysOnTop()) {
 
618
            return false;
 
619
        }
 
620
    }
 
621
    return true;
 
622
}
 
623
 
 
624
bool TaskGroup::isActionSupported(NET::Action action) const
 
625
{
 
626
    if (KWindowSystem::allowedActionsSupported()) {
 
627
        foreach (AbstractGroupableItem *item, d->members) {
 
628
            if (!item->isActionSupported(action)) {
 
629
                return false;
 
630
            }
 
631
        }
 
632
        return true;
 
633
    }
 
634
    return false;
 
635
}
 
636
 
 
637
void TaskGroup::close()
 
638
{
 
639
    foreach (AbstractGroupableItem *item, d->members) {
 
640
        item->close();
 
641
    }
 
642
}
 
643
 
 
644
bool TaskGroup::isActive() const
 
645
{
 
646
    foreach (AbstractGroupableItem *item, d->members) {
 
647
        if (item->isActive()) {
 
648
            return true;
 
649
        }
 
650
    }
 
651
 
 
652
    return false;
 
653
}
 
654
 
 
655
bool TaskGroup::demandsAttention() const
 
656
{
 
657
    foreach (AbstractGroupableItem *item, d->members) {
 
658
        if (item->demandsAttention()) {
 
659
            return true;
 
660
        }
 
661
    }
 
662
 
 
663
    return false;
 
664
}
 
665
 
 
666
bool TaskGroup::moveItem(int oldIndex, int newIndex)
 
667
{
 
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";
 
672
        return false;
 
673
    }
 
674
 
 
675
    AbstractGroupableItem *item = d->members.at(oldIndex);
 
676
    emit itemAboutToMove(item, oldIndex, newIndex);
 
677
    d->members.move(oldIndex, newIndex);
 
678
    emit itemPositionChanged(item);
 
679
    return true;
 
680
}
 
681
 
 
682
} // TaskManager namespace
 
683
 
 
684
#include "taskgroup.moc"