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"
31 #include "abstractgroupingstrategy.h"
32 #include "groupmanager.h"
33 #include "taskmanager.h"
39 class ManualGroupingStrategy::Private
44 editableGroupProperties(AbstractGroupingStrategy::All
),
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
;
63 ManualGroupingStrategy::ManualGroupingStrategy(GroupManager
*groupManager
)
64 :AbstractGroupingStrategy(groupManager
),
67 d
->groupManager
= groupManager
;
68 setType(GroupManager::ManualGrouping
);
71 ManualGroupingStrategy::~ManualGroupingStrategy()
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()));
92 if (item
->isGroupItem()) {
93 QAction
*a
= new QAction(i18n("Remove Group"), parent
);
94 connect(a
, SIGNAL(triggered()), this, SLOT(removeGroup()));
96 d
->tempGroup
= dynamic_cast<TaskGroup
*>(item
);
102 void ManualGroupingStrategy::leaveGroup()
104 Q_ASSERT(d
->tempItem
);
105 if (d
->tempItem
->isGrouped()) {
106 d
->tempItem
->parentGroup()->parentGroup()->add(d
->tempItem
);
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
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
)
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
);
154 //kDebug() << "Error no template Found";
156 if (templateGroup
->group()) {
157 oldTemplateGroup
->group()->add(templateGroup
->group()); //add group to parent Group
160 d
->groupManager
->rootGroup()->add(item
);
165 //kDebug() << "Item added to group: " << templateGroup->name();
166 templateGroup
->group()->add(item
);
167 templateGroup
->remove(item
);
169 //kDebug() << "Item not in templates";
170 d
->groupManager
->rootGroup()->add(item
);
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
) {
191 //Store the group under the current Desktop
192 if (d
->currentTemplate
) {
193 d
->currentTemplate
->clear();
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()));
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()
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
)
220 TaskGroup
*group
= qobject_cast
<TaskGroup
*>(sender());
224 if (newDesktop
&& (newDesktop
!= d
->oldDesktop
)) {
225 if (group
->parentGroup()) {
226 group
->parentGroup()->remove(group
);
229 TaskGroupTemplate
*templateGroup
;
231 if (d
->templateTrees
.contains(newDesktop
)) {
232 //kDebug() << "Template found";
233 templateGroup
= d
->templateTrees
.value(newDesktop
);
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
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
)) {
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
)
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
);
272 void ManualGroupingStrategy::closeGroup(TaskGroup
*group
)
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
298 TaskGroupTemplate
*parentGroup
;
299 ManualGroupingStrategy
*groupingStrategy
;
303 TaskGroupTemplate::TaskGroupTemplate(ManualGroupingStrategy
*parent
, TaskGroup
*group
)
304 : AbstractGroupableItem(parent
),
307 connect(this, SIGNAL(unprotectGroup(TaskGroup
*)), parent
, SLOT(unprotectGroup(TaskGroup
*)));
308 connect(this, SIGNAL(protectGroup(TaskGroup
*)), parent
, SLOT(protectGroup(TaskGroup
*)));
310 d
->name
= group
->name();
311 d
->color
= group
->color();
312 d
->icon
= group
->icon();
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
);
326 //kDebug() << "TemplateGroup Created: Name: " << d->name << "Color: " << d->color;
329 TaskGroupTemplate::~TaskGroupTemplate()
331 emit
unprotectGroup(group());
332 emit
destroyed(this);
334 //kDebug() << name();
338 TaskGroup
*TaskGroupTemplate::group()
343 void TaskGroupTemplate::setGroup(TaskGroup
*group
)
346 emit
unprotectGroup(group
);
349 emit
protectGroup(group
);
354 ItemList
&TaskGroupTemplate::members() const
359 QIcon
TaskGroupTemplate::icon() const
364 QColor
TaskGroupTemplate::color() const
369 QString
TaskGroupTemplate::name() const
374 /** add item to group */
375 void TaskGroupTemplate::add(AbstractItemPtr item
)
377 if (d
->members
.contains(item
)) {
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()) {
401 /** Removes all tasks and groups from this group */
402 void TaskGroupTemplate::clear()
404 foreach(AbstractGroupableItem
*item
, d
->members
) {
406 if (item
->isGroupItem()) {
407 TaskGroupTemplate
* templateGroup
= qobject_cast
<TaskGroupTemplate
*>(item
);
408 Q_ASSERT(templateGroup
);
409 templateGroup
->clear();
415 /** Reparents all members and closes this group */
416 void TaskGroupTemplate::closeGroup()
419 foreach(AbstractGroupableItem
*item
, d
->members
) {
422 parentGroup()->add(item
);
425 foreach(AbstractGroupableItem
*item
, d
->members
) {
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
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
461 if (members().contains(item
)) {
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
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
)) {
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";
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);
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
);
508 //kDebug() << "item found";
509 return returnedGroup
;
515 kDebug() << "item not found";
519 void TaskGroupTemplate::itemDestroyed(AbstractGroupableItem
*item
)
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()) {
539 #include "manualgroupingstrategy.moc"