00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "groupmanager.h"
00025
00026 #include <QList>
00027 #include <KDebug>
00028 #include <QTimer>
00029 #include <QUuid>
00030
00031 #include "abstractsortingstrategy.h"
00032 #include "startup.h"
00033 #include "task.h"
00034 #include "taskitem.h"
00035 #include "taskgroup.h"
00036 #include "taskmanager.h"
00037 #include "strategies/alphasortingstrategy.h"
00038 #include "strategies/desktopsortingstrategy.h"
00039 #include "strategies/programgroupingstrategy.h"
00040 #include "strategies/manualgroupingstrategy.h"
00041 #include "strategies/manualsortingstrategy.h"
00042
00043 namespace TaskManager
00044 {
00045
00046 class GroupManagerPrivate
00047 {
00048 public:
00049 GroupManagerPrivate(GroupManager *manager)
00050 : q(manager),
00051 rootGroup(0),
00052 sortingStrategy(GroupManager::NoSorting),
00053 groupingStrategy(GroupManager::NoGrouping),
00054 lastGroupingStrategy(GroupManager::NoGrouping),
00055 abstractGroupingStrategy(0),
00056 abstractSortingStrategy(0),
00057 currentScreen(-1),
00058 groupIsFullLimit(0),
00059 showOnlyCurrentDesktop(false),
00060 showOnlyCurrentScreen(false),
00061 showOnlyMinimized(false),
00062 onlyGroupWhenFull(false),
00063 changingGroupingStragegy(false)
00064 {
00065 }
00066
00068 void reloadTasks();
00069
00073 void currentDesktopChanged(int);
00074 void taskChanged(TaskPtr, ::TaskManager::TaskChanges);
00075
00076 void checkScreenChange();
00077
00078 void itemDestroyed();
00079 void checkIfFull();
00080
00081 GroupManager *q;
00082 QHash<TaskPtr, TaskItem*> itemList;
00083 QHash<StartupPtr, TaskItem*> startupList;
00084 TaskGroup *rootGroup;
00085 GroupManager::TaskSortingStrategy sortingStrategy;
00086 GroupManager::TaskGroupingStrategy groupingStrategy;
00087 GroupManager::TaskGroupingStrategy lastGroupingStrategy;
00088 AbstractGroupingStrategy *abstractGroupingStrategy;
00089 AbstractSortingStrategy *abstractSortingStrategy;
00090 int currentScreen;
00091 QTimer screenTimer;
00092 QList<TaskPtr> geometryTasks;
00093 int groupIsFullLimit;
00094 bool showOnlyCurrentDesktop : 1;
00095 bool showOnlyCurrentScreen : 1;
00096 bool showOnlyMinimized : 1;
00097 bool onlyGroupWhenFull : 1;
00098 bool changingGroupingStragegy : 1;
00099 QUuid configToken;
00100 };
00101
00102
00103
00104
00105 GroupManager::GroupManager(QObject *parent)
00106 : QObject(parent),
00107 d(new GroupManagerPrivate(this))
00108 {
00109 connect(TaskManager::self(), SIGNAL(taskAdded(TaskPtr)), this, SLOT(add(TaskPtr)));
00110 connect(TaskManager::self(), SIGNAL(taskRemoved(TaskPtr)), this, SLOT(remove(TaskPtr)));
00111 connect(TaskManager::self(), SIGNAL(startupAdded(StartupPtr)), this, SLOT(add(StartupPtr)));
00112 connect(TaskManager::self(), SIGNAL(startupRemoved(StartupPtr)), this, SLOT(remove(StartupPtr)));
00113 d->rootGroup = new TaskGroup(this, "RootGroup", Qt::transparent);
00114
00115 d->screenTimer.setSingleShot(true);
00116 d->screenTimer.setInterval(100);
00117 connect(&d->screenTimer, SIGNAL(timeout()), this, SLOT(checkScreenChange()));
00118 }
00119
00120 GroupManager::~GroupManager()
00121 {
00122 TaskManager::TaskManager::self()->setTrackGeometry(false, d->configToken);
00123 delete d->abstractSortingStrategy;
00124 delete d->abstractGroupingStrategy;
00125 delete d->rootGroup;
00126 delete d;
00127 }
00128
00129 void GroupManagerPrivate::reloadTasks()
00130 {
00131
00132
00133 QList <TaskPtr> taskList = TaskManager::self()->tasks().values();
00134 foreach (const TaskPtr& task, taskList) {
00135 if (!q->add(task)) {
00136 q->remove(task);
00137 }
00138 taskList.removeAll(task);
00139 }
00140
00141 foreach (const TaskPtr& task, taskList) {
00142 q->remove(task);
00143 }
00144
00145 emit q->reload();
00146 }
00147
00148 void GroupManager::add(StartupPtr task)
00149 {
00150
00151 TaskItem *item;
00152 if (!d->startupList.contains(task)) {
00153 item = new TaskItem(this, task);
00154 d->startupList.insert(task, item);
00155 d->rootGroup->add(item);
00156 }
00157 }
00158
00159 void GroupManager::remove(StartupPtr task)
00160 {
00161
00162 if (!d->startupList.contains(task)) {
00163 kDebug() << "invalid startup task";
00164 return;
00165 }
00166
00167 AbstractItemPtr item = d->startupList.take(task);
00168 if (item->parentGroup()) {
00169 item->parentGroup()->remove(item);
00170 }
00171
00172 emit itemRemoved(item);
00173 }
00174
00175 bool GroupManager::add(TaskPtr task)
00176 {
00177
00178
00179
00180
00181
00182
00183 if (!task->showInTaskbar()) {
00184
00185 return false;
00186 }
00187
00188 if (showOnlyCurrentScreen() && !task->isOnScreen(d->currentScreen)) {
00189
00190 return false;
00191 }
00192
00193
00194 if (!task->demandsAttention()) {
00195
00196
00197 if (showOnlyCurrentDesktop() && !task->isOnCurrentDesktop()) {
00198
00199
00200 return false;
00201 }
00202
00203 if (showOnlyMinimized() && !task->isMinimized()) {
00204
00205 return false;
00206 }
00207
00208 NET::WindowType type = task->info().windowType(NET::NormalMask | NET::DialogMask |
00209 NET::OverrideMask | NET::UtilityMask);
00210 if (type == NET::Utility) {
00211
00212 return false;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 }
00229
00230
00231 TaskItem *item = 0;
00232 if (!d->itemList.contains(task)) {
00233
00234 QMutableHashIterator<StartupPtr, TaskItem*> it(d->startupList);
00235 while (it.hasNext()) {
00236 it.next();
00237 if (it.key()->matchesWindow(task->window())) {
00238
00239 item = it.value();
00240 item->setTaskPointer(task);
00241 it.remove();
00242 break;
00243 }
00244 }
00245
00246 if (!item) {
00247 item = new TaskItem(this, task);
00248 }
00249
00250 connect(item, SIGNAL(destroyed()), this, SLOT(itemDestroyed()));
00251 d->itemList.insert(task, item);
00252 } else {
00253 item = d->itemList.value(task);
00254 }
00255
00256
00257 if (d->abstractGroupingStrategy && !task->demandsAttention()) {
00258 d->abstractGroupingStrategy->handleItem(item);
00259 } else {
00260 d->rootGroup->add(item);
00261 }
00262
00263 return true;
00264 }
00265
00266
00267 void GroupManager::remove(TaskPtr task)
00268 {
00269
00270 if (!d->geometryTasks.isEmpty()) {
00271 d->geometryTasks.removeAll(task);
00272 }
00273
00274 TaskItem *item = d->itemList.value(task);
00275 if (!item) {
00276
00277
00278
00279 return;
00280 }
00281
00282 if (item->parentGroup()) {
00283 item->parentGroup()->remove(item);
00284 }
00285
00286 emit itemRemoved(item);
00287
00288 }
00289
00290 void GroupManagerPrivate::itemDestroyed()
00291 {
00292 TaskItem *taskItem = qobject_cast<TaskItem*>(q->sender());
00293 TaskItem *item = itemList.take(itemList.key(taskItem));
00294 if (!item) {
00295 kDebug() << "invalid item";
00296 return;
00297 }
00298 QObject::disconnect(item, 0, q, 0);
00299 }
00300
00301
00302 bool GroupManager::manualGroupingRequest(AbstractGroupableItem* item, TaskGroup* groupItem)
00303 {
00304
00305 if (d->abstractGroupingStrategy) {
00306 return d->abstractGroupingStrategy->addItemToGroup(item, groupItem);
00307
00308
00309
00310
00311
00312 }
00313 return false;
00314 }
00315
00316 bool GroupManager::manualGroupingRequest(ItemList items)
00317 {
00318
00319 if (d->abstractGroupingStrategy) {
00320
00321 if (d->abstractGroupingStrategy->type() == ManualGrouping) {
00322
00323 return (qobject_cast<ManualGroupingStrategy*>(d->abstractGroupingStrategy))->groupItems(items);
00324 }
00325 }
00326 return false;
00327 }
00328
00329 bool GroupManager::manualSortingRequest(AbstractGroupableItem* taskItem, int newIndex)
00330 {
00331
00332 if (d->abstractSortingStrategy) {
00333 if (d->abstractSortingStrategy->type() == ManualSorting) {
00334 return (qobject_cast<ManualSortingStrategy*>(d->abstractSortingStrategy))->moveItem(taskItem, newIndex);
00335 }
00336 }
00337 return false;
00338 }
00339
00340
00341 GroupPtr GroupManager::rootGroup() const
00342 {
00343 return d->rootGroup;
00344 }
00345
00346
00347 void GroupManagerPrivate::currentDesktopChanged(int newDesktop)
00348 {
00349
00350 if (!showOnlyCurrentDesktop) {
00351 return;
00352 }
00353
00354 if (abstractSortingStrategy) {
00355 abstractSortingStrategy->desktopChanged(newDesktop);
00356 }
00357
00358 if (abstractGroupingStrategy) {
00359 abstractGroupingStrategy->desktopChanged(newDesktop);
00360 }
00361
00362 reloadTasks();
00363 }
00364
00365
00366 void GroupManagerPrivate::taskChanged(TaskPtr task, ::TaskManager::TaskChanges changes)
00367 {
00368
00369 bool takeAction = false;
00370 bool show = true;
00371
00372 if (showOnlyCurrentDesktop && changes & ::TaskManager::DesktopChanged) {
00373 takeAction = true;
00374 show = task->isOnCurrentDesktop();
00375
00376 }
00377
00378 if (showOnlyMinimized && changes & ::TaskManager::StateChanged) {
00379
00380 takeAction = true;
00381 show = task->isMinimized();
00382 }
00383
00384 if (changes & ::TaskManager::GeometryChanged) {
00385 if (!geometryTasks.contains(task)) {
00386 geometryTasks.append(task);
00387 }
00388
00389 if (!screenTimer.isActive()) {
00390 screenTimer.start();
00391 }
00392 }
00393
00394
00395 if (changes & ::TaskManager::StateChanged && task->demandsAttention()) {
00396 takeAction = true;
00397 show = true;
00398 }
00399
00400 if (!takeAction) {
00401 return;
00402 }
00403
00404 if (show) {
00405
00406 q->add(task);
00407 } else {
00408
00409 q->remove(task);
00410 }
00411 }
00412
00413 void GroupManager::setScreen(int screen)
00414 {
00415
00416 d->currentScreen = screen;
00417 }
00418
00419
00420 void GroupManagerPrivate::checkScreenChange()
00421 {
00422
00423 foreach (const TaskPtr &task, geometryTasks) {
00424 if (task->isOnScreen(currentScreen)) {
00425 q->add(task);
00426 } else {
00427 q->remove(task);
00428 }
00429 }
00430
00431 geometryTasks.clear();
00432 }
00433
00434
00435 void GroupManager::reconnect()
00436 {
00437
00438 disconnect(TaskManager::self(), SIGNAL(desktopChanged(int)),
00439 this, SLOT(currentDesktopChanged(int)));
00440 disconnect(TaskManager::self(), SIGNAL(windowChanged(TaskPtr,::TaskManager::TaskChanges)),
00441 this, SLOT(taskChanged(TaskPtr,::TaskManager::TaskChanges)));
00442
00443 if (d->showOnlyCurrentDesktop || d->showOnlyMinimized || d->showOnlyCurrentScreen) {
00444
00445 if (d->showOnlyCurrentDesktop) {
00446 connect(TaskManager::TaskManager::self(), SIGNAL(desktopChanged(int)),
00447 this, SLOT(currentDesktopChanged(int)));
00448 }
00449
00450 connect(TaskManager::self(), SIGNAL(windowChanged(TaskPtr,::TaskManager::TaskChanges)),
00451 this, SLOT(taskChanged(TaskPtr,::TaskManager::TaskChanges)));
00452 }
00453
00454 TaskManager::TaskManager::self()->setTrackGeometry(d->showOnlyCurrentScreen, d->configToken);
00455
00456 if (!d->showOnlyCurrentScreen) {
00457 d->geometryTasks.clear();
00458 }
00459
00460 d->reloadTasks();
00461 }
00462
00463
00464 bool GroupManager::onlyGroupWhenFull() const
00465 {
00466 return d->onlyGroupWhenFull;
00467 }
00468
00469 void GroupManager::setOnlyGroupWhenFull(bool state)
00470 {
00471
00472 if (d->onlyGroupWhenFull == state) {
00473 return;
00474 }
00475
00476 d->onlyGroupWhenFull = state;
00477
00478 if (state) {
00479 connect(d->rootGroup, SIGNAL(itemAdded(AbstractItemPtr)), this, SLOT(checkIfFull()));
00480 connect(d->rootGroup, SIGNAL(itemRemoved(AbstractItemPtr)), this, SLOT(checkIfFull()));
00481 d->checkIfFull();
00482 } else {
00483 disconnect(d->rootGroup, SIGNAL(itemAdded(AbstractItemPtr)), this, SLOT(checkIfFull()));
00484 disconnect(d->rootGroup, SIGNAL(itemRemoved(AbstractItemPtr)), this, SLOT(checkIfFull()));
00485 }
00486 }
00487
00488 void GroupManager::setFullLimit(int limit)
00489 {
00490
00491 d->groupIsFullLimit = limit;
00492 if (d->onlyGroupWhenFull) {
00493 d->checkIfFull();
00494 }
00495 }
00496
00497 void GroupManagerPrivate::checkIfFull()
00498 {
00499
00500 if (!onlyGroupWhenFull || groupingStrategy != GroupManager::ProgramGrouping) {
00501 return;
00502 }
00503
00504 if (itemList.size() >= groupIsFullLimit) {
00505 if (!abstractGroupingStrategy) {
00506 q->setGroupingStrategy(GroupManager::ProgramGrouping);
00507 }
00508 } else if (abstractGroupingStrategy) {
00509 q->setGroupingStrategy(GroupManager::NoGrouping);
00510
00511 groupingStrategy = GroupManager::ProgramGrouping;
00512 }
00513 }
00514
00515 bool GroupManager::showOnlyCurrentScreen() const
00516 {
00517 return d->showOnlyCurrentScreen;
00518 }
00519
00520 void GroupManager::setShowOnlyCurrentScreen(bool showOnlyCurrentScreen)
00521 {
00522 d->showOnlyCurrentScreen = showOnlyCurrentScreen;
00523 }
00524
00525 bool GroupManager::showOnlyCurrentDesktop() const
00526 {
00527 return d->showOnlyCurrentDesktop;
00528 }
00529
00530 void GroupManager::setShowOnlyCurrentDesktop(bool showOnlyCurrentDesktop)
00531 {
00532 d->showOnlyCurrentDesktop = showOnlyCurrentDesktop;
00533 }
00534
00535 bool GroupManager::showOnlyMinimized() const
00536 {
00537 return d->showOnlyMinimized;
00538 }
00539
00540 void GroupManager::setShowOnlyMinimized(bool showOnlyMinimized)
00541 {
00542 d->showOnlyMinimized = showOnlyMinimized;
00543 }
00544
00545 GroupManager::TaskSortingStrategy GroupManager::sortingStrategy() const
00546 {
00547 return d->sortingStrategy;
00548 }
00549
00550 AbstractSortingStrategy* GroupManager::taskSorter() const
00551 {
00552 return d->abstractSortingStrategy;
00553 }
00554
00555 void GroupManager::setSortingStrategy(TaskSortingStrategy sortOrder)
00556 {
00557
00558
00559 if (d->abstractSortingStrategy) {
00560 if (d->abstractSortingStrategy->type() == sortOrder){
00561 return;
00562 } else {
00563 d->abstractSortingStrategy->deleteLater();
00564 }
00565 }
00566
00567 switch (sortOrder) {
00568 case NoSorting:
00569 d->abstractSortingStrategy = 0;
00570 break;
00571 case ManualSorting:
00572 d->abstractSortingStrategy = new ManualSortingStrategy(this);
00573 d->abstractSortingStrategy->handleGroup(d->rootGroup);
00574 break;
00575
00576 case AlphaSorting:
00577 d->abstractSortingStrategy = new AlphaSortingStrategy(this);
00578 d->abstractSortingStrategy->handleGroup(d->rootGroup);
00579 break;
00580
00581 case DesktopSorting:
00582 d->abstractSortingStrategy = new DesktopSortingStrategy(this);
00583 d->abstractSortingStrategy->handleGroup(d->rootGroup);
00584 break;
00585
00586 default:
00587 kDebug() << "Invalid Strategy";
00588 d->abstractSortingStrategy = 0;
00589 }
00590
00591 d->sortingStrategy = sortOrder;
00592 d->reloadTasks();
00593 }
00594
00595 GroupManager::TaskGroupingStrategy GroupManager::groupingStrategy() const
00596 {
00597 return d->groupingStrategy;
00598 }
00599
00600 AbstractGroupingStrategy* GroupManager::taskGrouper() const
00601 {
00602 return d->abstractGroupingStrategy;
00603 }
00604
00605 void GroupManager::setGroupingStrategy(TaskGroupingStrategy strategy)
00606 {
00607 if (d->changingGroupingStragegy ||
00608 (d->abstractGroupingStrategy && d->abstractGroupingStrategy->type() == strategy)) {
00609 return;
00610 }
00611
00612 d->changingGroupingStragegy = true;
00613
00614
00615 if (d->onlyGroupWhenFull) {
00616 disconnect(d->rootGroup, SIGNAL(itemAdded(AbstractItemPtr)), this, SLOT(checkIfFull()));
00617 disconnect(d->rootGroup, SIGNAL(itemRemoved(AbstractItemPtr)), this, SLOT(checkIfFull()));
00618 }
00619
00620 delete d->abstractGroupingStrategy;
00621 d->abstractGroupingStrategy = 0;
00622
00623 switch (strategy) {
00624 case NoGrouping:
00625 d->abstractGroupingStrategy = 0;
00626 break;
00627 case ManualGrouping:
00628 d->abstractGroupingStrategy = new ManualGroupingStrategy(this);
00629 break;
00630
00631 case ProgramGrouping:
00632 d->abstractGroupingStrategy = new ProgramGroupingStrategy(this);
00633 break;
00634
00635 default:
00636 kDebug() << "Strategy not implemented";
00637 d->abstractGroupingStrategy = 0;
00638 }
00639
00640 d->groupingStrategy = strategy;
00641
00642 if (d->groupingStrategy) {
00643 connect(d->abstractGroupingStrategy, SIGNAL(groupRemoved(TaskGroup*)),
00644 this, SIGNAL(groupRemoved(TaskGroup*)));
00645 }
00646
00647 d->reloadTasks();
00648
00649 if (d->onlyGroupWhenFull) {
00650 connect(d->rootGroup, SIGNAL(itemAdded(AbstractItemPtr)), this, SLOT(checkIfFull()));
00651 connect(d->rootGroup, SIGNAL(itemRemoved(AbstractItemPtr)), this, SLOT(checkIfFull()));
00652 }
00653
00654 d->changingGroupingStragegy = false;
00655 }
00656
00657 }
00658
00659 #include "groupmanager.moc"
00660