not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / libs / taskmanager / strategies / manualgroupingstrategy.cpp
blob6c31adb3df28a34a587c753aef365b3c4210f5a6
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 ******************************************************************/
24 #include "manualgroupingstrategy.h"
26 #include <QAction>
28 #include <KDebug>
29 #include <KLocale>
31 #include "abstractgroupingstrategy.h"
32 #include "groupmanager.h"
33 #include "taskmanager.h"
36 namespace TaskManager
39 class ManualGroupingStrategy::Private
41 public:
42 Private()
43 : currentTemplate(0),
44 editableGroupProperties(AbstractGroupingStrategy::All),
45 tempItem(0),
46 tempGroup(0),
47 oldDesktop(TaskManager::self()->currentDesktop())
51 GroupManager *groupManager;
52 QHash<int, TaskGroupTemplate*> templateTrees;
53 TaskGroupTemplate* currentTemplate;
54 QList<TaskGroup*> protectedGroups;
55 AbstractGroupingStrategy::EditableGroupProperties editableGroupProperties;
56 AbstractGroupableItem *tempItem;
57 TaskGroup *tempGroup;
58 int oldDesktop;
63 ManualGroupingStrategy::ManualGroupingStrategy(GroupManager *groupManager)
64 :AbstractGroupingStrategy(groupManager),
65 d(new Private)
67 d->groupManager = groupManager;
68 setType(GroupManager::ManualGrouping);
71 ManualGroupingStrategy::~ManualGroupingStrategy()
73 delete d;
76 AbstractGroupingStrategy::EditableGroupProperties ManualGroupingStrategy::editableGroupProperties()
78 return d->editableGroupProperties;
81 QList<QAction*> ManualGroupingStrategy::strategyActions(QObject *parent, AbstractGroupableItem *item)
83 QList<QAction*> actionList;
85 if (item->isGrouped()) {
86 QAction *a = new QAction(i18n("Leave Group"), parent);
87 connect(a, SIGNAL(triggered()), this, SLOT(leaveGroup()));
88 actionList.append(a);
89 d->tempItem = item;
92 if (item->isGroupItem()) {
93 QAction *a = new QAction(i18n("Remove Group"), parent);
94 connect(a, SIGNAL(triggered()), this, SLOT(removeGroup()));
95 actionList.append(a);
96 d->tempGroup = dynamic_cast<TaskGroup*>(item);
99 return actionList;
102 void ManualGroupingStrategy::leaveGroup()
104 Q_ASSERT(d->tempItem);
105 if (d->tempItem->isGrouped()) {
106 d->tempItem->parentGroup()->parentGroup()->add(d->tempItem);
108 d->tempItem = 0;
111 void ManualGroupingStrategy::removeGroup()
113 Q_ASSERT(d->tempGroup);
114 if (d->tempGroup->parentGroup()) {
115 foreach (AbstractGroupableItem *item, d->tempGroup->members()) {
116 d->tempGroup->parentGroup()->add(item);
118 //Group gets automatically closed on empty signal
120 d->tempGroup = 0;
123 void ManualGroupingStrategy::unprotectGroup(TaskGroup *group)
125 //kDebug() << group->name() << d->protectedGroups.count(group);
126 d->protectedGroups.removeOne(group);
127 if (group->members().isEmpty()) {
128 closeGroup(group);//check if group is needed anymore
132 void ManualGroupingStrategy::protectGroup(TaskGroup *group)
134 //kDebug() << group->name();
135 d->protectedGroups.append(group);
138 //Check if the item was previously manually grouped
139 void ManualGroupingStrategy::handleItem(AbstractItemPtr item)
141 //kDebug();
142 if (d->currentTemplate) { //TODO this won't work over sessions because the task is identified by the pointer (maybe the name without the current status would work), one way would be to store the items per name if the session is closed and load them per name on startup but use the pointer otherwise because of changing names of browsers etc
143 TaskGroupTemplate *templateGroup = d->currentTemplate;
144 //kDebug() << templateGroup->name();
145 if (templateGroup->hasMember(item)) {
146 //kDebug() << "item found in template tree";
147 while(!templateGroup->hasDirectMember(item)) {//Create tree of groups if not already existing
148 //kDebug() << "Creating group tree";
149 TaskGroupTemplate *oldTemplateGroup = templateGroup;
150 AbstractGroupableItem *templateItem = templateGroup->directMember(item);
151 if (templateItem->isGroupItem()) {
152 templateGroup = dynamic_cast<TaskGroupTemplate*>(templateItem);
153 } else {
154 //kDebug() << "Error no template Found";
156 if (templateGroup->group()) {
157 oldTemplateGroup->group()->add(templateGroup->group()); //add group to parent Group
158 } else {
159 //kDebug();
160 d->groupManager->rootGroup()->add(item);
161 return;
165 //kDebug() << "Item added to group: " << templateGroup->name();
166 templateGroup->group()->add(item);
167 templateGroup->remove(item);
168 } else {
169 //kDebug() << "Item not in templates";
170 d->groupManager->rootGroup()->add(item);
172 } else {
173 d->groupManager->rootGroup()->add(item);
177 TaskGroupTemplate *ManualGroupingStrategy::createDuplication(TaskGroup *group)
179 TaskGroupTemplate *templateGroup = new TaskGroupTemplate(this, group);
180 return templateGroup;
184 void ManualGroupingStrategy::desktopChanged(int newDesktop)
186 //kDebug() << "old: " << d->oldDesktop << "new: " << newDesktop;
187 if (d->oldDesktop == newDesktop) {
188 return;
191 //Store the group under the current Desktop
192 if (d->currentTemplate) {
193 d->currentTemplate->clear();
195 //kDebug();
196 TaskGroupTemplate *group = createDuplication(d->groupManager->rootGroup());
197 d->templateTrees.insert(d->oldDesktop, group);
198 if (d->templateTrees.contains(newDesktop)) {
199 //kDebug() << "Template found";
200 d->currentTemplate = d->templateTrees.value(newDesktop);
201 connect (d->currentTemplate, SIGNAL(destroyed()), this, SLOT(resetCurrentTemplate()));
202 } else {
203 d->currentTemplate = 0;
205 d->oldDesktop = newDesktop;
209 //This function makes sure that if the rootGroup template already got deleted nobody tries to access it again
210 void ManualGroupingStrategy::resetCurrentTemplate()
212 //kDebug();
213 d->currentTemplate = 0;
216 //The group was moved to another desktop, we have to move it to the rootTree of newDesk
217 void ManualGroupingStrategy::groupChangedDesktop(int newDesktop)
219 //kDebug();
220 TaskGroup *group = qobject_cast<TaskGroup*>(sender());
221 if (!group) {
222 return;
224 if (newDesktop && (newDesktop != d->oldDesktop)) {
225 if (group->parentGroup()) {
226 group->parentGroup()->remove(group);
229 TaskGroupTemplate *templateGroup;
230 if (newDesktop) {
231 if (d->templateTrees.contains(newDesktop)) {
232 //kDebug() << "Template found";
233 templateGroup = d->templateTrees.value(newDesktop);
234 } else {
235 //kDebug() << "No Template found";
236 templateGroup = new TaskGroupTemplate(this, 0);
237 templateGroup->setGroup(d->groupManager->rootGroup());
238 d->templateTrees.insert(newDesktop, templateGroup);
240 //Add group to all existing desktops
241 } else {
242 for (int i = 1; i <= TaskManager::self()->numberOfDesktops(); i++) {
243 if (d->templateTrees.contains(newDesktop)) {
244 //kDebug() << "Template found";
245 templateGroup = d->templateTrees.value(newDesktop);
246 if (templateGroup->hasMember(group)) {
247 continue;
249 } else {
250 //kDebug() << "No Template found";
251 templateGroup = new TaskGroupTemplate(this, 0);
252 templateGroup->setGroup(d->groupManager->rootGroup());
253 d->templateTrees.insert(newDesktop, templateGroup);
255 templateGroup->add(createDuplication(group));
261 bool ManualGroupingStrategy::groupItems(ItemList items)
263 //kDebug();
264 TaskGroup *group = createGroup(items);
265 connect(group, SIGNAL(movedToDesktop(int)), this, SLOT(groupChangedDesktop(int)));
266 setName(nameSuggestions(group).first(), group);
267 setColor(colorSuggestions(group).first(), group);
268 setIcon(iconSuggestions(group).first(), group);
269 return true;
272 void ManualGroupingStrategy::closeGroup(TaskGroup *group)
274 //kDebug();
275 if (!d->protectedGroups.contains(group)) {
276 AbstractGroupingStrategy::closeGroup(group);
277 } else if (group->parentGroup()) {
278 group->parentGroup()->remove(group);
279 //kDebug() << "Group protected";
283 class TaskGroupTemplate::Private
285 public:
286 Private()
287 : group(0),
288 parentGroup(0),
289 groupingStrategy(0)
293 ItemList members;
294 QString name;
295 QColor color;
296 QIcon icon;
297 TaskGroup *group;
298 TaskGroupTemplate *parentGroup;
299 ManualGroupingStrategy *groupingStrategy;
303 TaskGroupTemplate::TaskGroupTemplate(ManualGroupingStrategy *parent, TaskGroup *group)
304 : AbstractGroupableItem(parent),
305 d(new Private)
307 connect(this, SIGNAL(unprotectGroup(TaskGroup *)), parent, SLOT(unprotectGroup(TaskGroup *)));
308 connect(this, SIGNAL(protectGroup(TaskGroup *)), parent, SLOT(protectGroup(TaskGroup *)));
309 if (group) {
310 d->name = group->name();
311 d->color = group->color();
312 d->icon = group->icon();
313 setGroup(group);
314 foreach (AbstractGroupableItem *item, group->members()) {
315 //We don't use TaskGroup::add because this would inform the tasks about the change of the group
316 //and we use the taskgroup just as a temporary container
317 if (item->isGroupItem()) {
318 //kDebug() << "GroupItem Duplication";
319 TaskGroupTemplate *createdDuplication = new TaskGroupTemplate(parent, dynamic_cast<TaskGroup*>(item));
320 add(createdDuplication);
321 } else {
322 add(item);
326 //kDebug() << "TemplateGroup Created: Name: " << d->name << "Color: " << d->color;
329 TaskGroupTemplate::~TaskGroupTemplate()
331 emit unprotectGroup(group());
332 emit destroyed(this);
333 //clear();
334 //kDebug() << name();
335 delete d;
338 TaskGroup *TaskGroupTemplate::group()
340 return d->group;
343 void TaskGroupTemplate::setGroup(TaskGroup *group)
345 if (d->group) {
346 emit unprotectGroup(group);
348 if (group) {
349 emit protectGroup(group);
351 d->group = group;
354 ItemList &TaskGroupTemplate::members() const
356 return d->members;
359 QIcon TaskGroupTemplate::icon() const
361 return d->icon;
364 QColor TaskGroupTemplate::color() const
366 return d->color;
369 QString TaskGroupTemplate::name() const
371 return d->name;
374 /** add item to group */
375 void TaskGroupTemplate::add(AbstractItemPtr item)
377 if (d->members.contains(item)) {
378 return;
380 d->members.append(item);
381 if (item->isGroupItem()) {
382 connect(item, SIGNAL(destroyed(AbstractGroupableItem *)), this, SLOT(itemDestroyed(AbstractGroupableItem *)));
383 (dynamic_cast<TaskGroupTemplate*>(item))->setParentGroup(this);
387 /** remove item from group */
388 void TaskGroupTemplate::remove(AbstractItemPtr item)
390 disconnect(item, 0, this, 0);
391 disconnect(this, 0, item, 0);
392 d->members.removeAll(item);
393 if (item->isGroupItem()) {
394 (dynamic_cast<TaskGroupTemplate*>(item))->setParentGroup(0);
396 if (d->members.isEmpty()) {
397 closeGroup();
401 /** Removes all tasks and groups from this group */
402 void TaskGroupTemplate::clear()
404 foreach(AbstractGroupableItem *item, d->members) {
405 Q_ASSERT(item);
406 if (item->isGroupItem()) {
407 TaskGroupTemplate* templateGroup = qobject_cast<TaskGroupTemplate*>(item);
408 Q_ASSERT(templateGroup);
409 templateGroup->clear();
410 } else {
411 remove(item);
415 /** Reparents all members and closes this group */
416 void TaskGroupTemplate::closeGroup()
418 if (parentGroup()) {
419 foreach(AbstractGroupableItem *item, d->members) {
420 Q_ASSERT(item);
421 remove(item);
422 parentGroup()->add(item);
424 } else {
425 foreach(AbstractGroupableItem *item, d->members) {
426 Q_ASSERT(item);
427 remove(item);
430 deleteLater();
434 TaskGroupTemplate *TaskGroupTemplate::parentGroup() const
436 return d->parentGroup;
439 void TaskGroupTemplate::setParentGroup(TaskGroupTemplate *group)
441 d->parentGroup = group;
444 void TaskGroupTemplate::addMimeData(QMimeData *mimeData) const
446 if (d->group) {
447 d->group->addMimeData(mimeData);
451 /** only true if item is in this group */
452 bool TaskGroupTemplate::hasDirectMember(AbstractItemPtr item) const
454 return d->members.contains(item);
457 /** true if item is in this or any sub group */
458 bool TaskGroupTemplate::hasMember(AbstractItemPtr item) const
460 //kDebug();
461 if (members().contains(item)) {
462 return true;
464 ItemList::const_iterator iterator = members().constBegin();
465 while (iterator != members().constEnd()) {
466 if ((*iterator)->isGroupItem()) {
467 if ((dynamic_cast<TaskGroupTemplate *>(*iterator))->hasMember(item)) { //look into group
468 return true;
471 ++iterator;
473 return false;
477 /** Returns Direct Member group if the passed item is in a subgroup */
478 AbstractItemPtr TaskGroupTemplate::directMember(AbstractItemPtr item) const
480 if (members().contains(item)) {
481 return item;
482 } else {
483 ItemList::const_iterator iterator = members().constBegin();
484 while (iterator != members().constEnd()) {
485 if ((*iterator)->isGroupItem()) {
486 if ((dynamic_cast<TaskGroupTemplate*>(*iterator))->hasMember(item)) {
487 //kDebug() << "item found";
488 return (*iterator);
491 ++iterator;
494 kDebug() << "item not found";
495 return AbstractItemPtr();
498 TaskGroupTemplate *TaskGroupTemplate::findParentGroup(AbstractItemPtr item) const
500 if (members().contains(item)) {
501 return const_cast<TaskGroupTemplate*>(this);
502 } else {
503 ItemList::const_iterator iterator = members().constBegin();
504 while (iterator != members().constEnd()) {
505 if ((*iterator)->isGroupItem()) {
506 TaskGroupTemplate *returnedGroup = (dynamic_cast<TaskGroupTemplate*>(*iterator))->findParentGroup(item);
507 if (returnedGroup) {
508 //kDebug() << "item found";
509 return returnedGroup;
512 ++iterator;
515 kDebug() << "item not found";
516 return 0;
519 void TaskGroupTemplate::itemDestroyed(AbstractGroupableItem *item)
521 if (!item) {
522 kDebug() << "Error";
523 return;
525 //kDebug() << d->group->name();
527 * The following code is needed in case one creates a group on desktop 1 with a task which is on multiple * * desktops. If this task gets closed on another desktop as last task in the group the empty group is still * stored in the template and therefore all attributes (name, color, ..) stay reserved
529 d->members.removeAll(item); // we can't use remove because the item was already deleted
530 disconnect(item, 0, this, 0);
531 disconnect(this, 0, item, 0);
532 if (members().isEmpty()) {
533 closeGroup();
537 }//namespace
539 #include "manualgroupingstrategy.moc"