From bc05aad5a4d3a0a153f388f45078d65f3f67c3eb Mon Sep 17 00:00:00 2001 From: helmutm Date: Wed, 10 Aug 2005 18:58:00 +0000 Subject: [PATCH] use OOSet and separate Relation objects for subtask relations git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@537 fd906abe-77d9-0310-91a1-e0d9ade77398 --- browser/configureFive.zcml | 75 ++++++++++++++++++++++++++++++++++++++ interfaces.py | 28 +++++++++++++- relation.py | 47 ++++++++++++++++++++++++ task.py | 41 +++++++++++++++------ tests/test_task.py | 1 + 5 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 browser/configureFive.zcml create mode 100644 relation.py diff --git a/browser/configureFive.zcml b/browser/configureFive.zcml new file mode 100644 index 0000000..cc85c29 --- /dev/null +++ b/browser/configureFive.zcml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interfaces.py b/interfaces.py index 89de6c8..bc5a657 100644 --- a/interfaces.py +++ b/interfaces.py @@ -28,6 +28,33 @@ from zope.app.container.interfaces import IOrderedContainer from zope.schema import Text, TextLine, List, Object, Int +class IRelations(Interface): + """ Holds a set of relations (more precisely: ends of relations). + A simple implementation is to just use an IOSet. + """ + + def add(relation): + """ Add a relation. + relationClass is the class that should be used for the relation + object; it should have a default setting, e.g. Relation. + """ + + def remove(relation): + """ + """ + + +class IRelation(Interface): + """ Represents a relation from one object to another. + """ + source = Object(Interface, + title=u'Source Object', + description=u"Object that is the source of the relation") + target = Object(Interface, + title=u'Target Object', + description=u"Object that is the target of the relation") + + class IResourceConstraint(Interface): """ A ResourceConstraint governs which Resource objects may be allocated to a Task object. @@ -244,4 +271,3 @@ class IResource(IOrderedContainer): source task types given. """ - diff --git a/relation.py b/relation.py new file mode 100644 index 0000000..91843fa --- /dev/null +++ b/relation.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2004 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +relation classes implementation. + +$Id$ +""" + +from BTrees.OOBTree import OOSet +from zope.interface import implements +from zope.app import zapi + +from interfaces import IRelation, IRelations + + +class Relation(object): + + implements(IRelation) + + def __init__(self, source, target): + self._source = source + self._target = target + + +class Relations(OOSet): + + implements(IRelations) + + def add(self, relation, **kw): + self.insert(relation) + diff --git a/task.py b/task.py index fe55d1a..0986cf2 100644 --- a/task.py +++ b/task.py @@ -27,11 +27,24 @@ from zope.app.container.ordered import OrderedContainer from zope.app.copypastemove import ObjectCopier from zope.app import zapi +from relation import Relation, Relations from resource import Resource from interfaces import ITask from copy import copy + +class ResourceAllocation(Relation): + """ A relation that represents an allocation of a resource + to a task. + """ + + +class ResourceAllocations(Relations): + """ A set of resource allocations. + """ + + class Task(OrderedContainer): implements(ITask) @@ -43,24 +56,27 @@ class Task(OrderedContainer): def __init__(self): OrderedContainer.__init__(self) - self._subtasks = [] - self._parentTasks = [] + self._subtasks = Relations() + self._parentTasks = Relations() self._resourceAllocs = {} self.resourceConstraints = [] # subtasks: def getSubtasks(self, taskTypes=None): - st = self._subtasks + st = [ r._target for r in self._subtasks ] st.sort(lambda x,y: x.priority < y.priority and -1 or 1) return tuple(st) def getParentTasks(self, taskTypes=None): - return tuple(self._parentTasks) + pt = [ r._source for r in self._parentTasks ] + return tuple(pt) def assignSubtask(self, task): - self._subtasks = self._subtasks + [task] - task._parentTasks = task._parentTasks + [self] + if task not in self.getSubtasks(): + rel = Relation(self, task) + self._subtasks.add(rel) + task._parentTasks.add(rel) def createSubtask(self, taskType=None, container=None, name=None): container = container or zapi.getParent(self) @@ -71,8 +87,10 @@ class Task(OrderedContainer): return task def deassignSubtask(self, task): - self._subtasks.remove(task) - task._parentTasks.remove(self) + hits = [ r for r in self._subtasks if r._target == task ] + if hits: + self._subtasks.remove(hits[0]) + task._parentTasks.remove(hits[0]) # resource allocations: @@ -172,10 +190,11 @@ class Task(OrderedContainer): newName = self._createTaskName(targetContainer) newTask = copy(self) targetContainer[newName] = newTask - newTask._subtasks = [] - for st in self.getSubtasks(): + subtasks = self.getSubtasks() + newTask._subtasks.clear() + for st in subtasks: newSt = st.copyTask(targetContainer) - newSt._parentTasks.remove(self) + newSt._parentTasks.clear() newTask.assignSubtask(newSt) return newTask diff --git a/tests/test_task.py b/tests/test_task.py index dd9bc9f..453c702 100755 --- a/tests/test_task.py +++ b/tests/test_task.py @@ -234,6 +234,7 @@ class TestTaskCopy(unittest.TestCase): ts1.allocateResource(r1) t2 = t1.copyTask() self.failIf(t1 is t2, 't1 and t2 are still the same') + self.assertEquals(1, len(t1.getSubtasks())) st2 = t2.getSubtasks() self.assertEquals(1, len(st2)) ts2 = st2[0]