1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
'''
Task Coach - Your friendly task manager
Copyright (C) 2004-2014 Task Coach developers <developers@taskcoach.org>
Task Coach 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 3 of the License, or
(at your option) any later version.
Task Coach 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, see <http://www.gnu.org/licenses/>.
'''
import observer
import weakref
class Composite(object):
def __init__(self, children=None, parent=None):
super(Composite, self).__init__()
self.__parent = parent if parent is None else weakref.ref(parent)
self.__children = children or []
for child in self.__children:
child.setParent(self)
def __getstate__(self):
return dict(children=self.__children[:],
parent=self.parent())
def __setstate__(self, state):
self.__parent = None if state['parent'] is None else weakref.ref(state['parent'])
self.__children = state['children']
def __getcopystate__(self):
''' Return the information needed to create a copy as a dict. '''
try:
state = super(Composite, self).__getcopystate__()
except AttributeError:
state = dict()
state.update(dict(children=[child.copy() for child in self.__children],
parent=self.parent()))
return state
def parent(self):
return None if self.__parent is None else self.__parent()
def ancestors(self):
''' Return the parent, and its parent, etc., as a list. '''
parent = self.parent()
return parent.ancestors() + [parent] if parent else []
def family(self):
''' Return this object, its ancestors and all of its children
(recursively). '''
return self.ancestors() + [self] + self.children(recursive=True)
def setParent(self, parent):
self.__parent = None if parent is None else weakref.ref(parent)
def children(self, recursive=False):
# Warning: this must satisfy the same condition as
# allItemsSorted() below.
if recursive:
result = self.__children[:]
for child in self.__children:
result.extend(child.children(recursive=True))
return result
else:
return self.__children
def siblings(self, recursive=False):
parent = self.parent()
if parent:
result = [child for child in parent.children() if child != self]
if recursive:
for child in result[:]:
result.extend(child.children(recursive=True))
return result
else:
return []
def copy(self, *args, **kwargs):
kwargs['parent'] = self.parent()
kwargs['children'] = [child.copy() for child in self.children()]
return self.__class__(*args, **kwargs)
def newChild(self, *args, **kwargs):
kwargs['parent'] = self
return self.__class__(*args, **kwargs)
def addChild(self, child):
self.__children.append(child)
child.setParent(self)
def removeChild(self, child):
self.__children.remove(child)
# We don't reset the parent of the child, because that makes restoring
# the parent-child relationship easier.
class ObservableComposite(Composite):
@observer.eventSource
def __setstate__(self, state, event=None): # pylint: disable=W0221
oldChildren = set(self.children())
super(ObservableComposite, self).__setstate__(state)
newChildren = set(self.children())
childrenRemoved = oldChildren - newChildren
# pylint: disable=W0142
if childrenRemoved:
self.removeChildEvent(event, *childrenRemoved)
childrenAdded = newChildren - oldChildren
if childrenAdded:
self.addChildEvent(event, *childrenAdded)
@observer.eventSource
def addChild(self, child, event=None): # pylint: disable=W0221
super(ObservableComposite, self).addChild(child)
self.addChildEvent(event, child)
def addChildEvent(self, event, *children):
event.addSource(self, *children, **dict(type=self.addChildEventType()))
@classmethod
def addChildEventType(class_):
return 'composite(%s).child.add'%class_
@observer.eventSource
def removeChild(self, child, event=None): # pylint: disable=W0221
super(ObservableComposite, self).removeChild(child)
self.removeChildEvent(event, child)
def removeChildEvent(self, event, *children):
event.addSource(self, *children, **dict(type=self.removeChildEventType()))
@classmethod
def removeChildEventType(class_):
return 'composite(%s).child.remove'%class_
@classmethod
def modificationEventTypes(class_):
try:
eventTypes = super(ObservableComposite, class_).modificationEventTypes()
except AttributeError:
eventTypes = []
return eventTypes + [class_.addChildEventType(),
class_.removeChildEventType()]
class CompositeCollection(object):
def __init__(self, initList=None, *args, **kwargs):
super(CompositeCollection, self).__init__(*args, **kwargs)
self.extend(initList or [])
def append(self, composite, event=None):
return self.extend([composite], event=event)
@observer.eventSource
def extend(self, composites, event=None):
if not composites:
return
compositesAndAllChildren = self._compositesAndAllChildren(composites)
super(CompositeCollection, self).extend(compositesAndAllChildren,
event=event)
self._addCompositesToParent(composites, event)
def _compositesAndAllChildren(self, composites):
compositesAndAllChildren = set(composites)
for composite in composites:
compositesAndAllChildren |= set(composite.children(recursive=True))
return list(compositesAndAllChildren)
def _addCompositesToParent(self, composites, event):
for composite in composites:
parent = composite.parent()
if parent and parent in self and composite not in parent.children():
parent.addChild(composite, event=event)
def remove(self, composite, event=None):
return self.removeItems([composite], event=event) if composite in self else event
@observer.eventSource
def removeItems(self, composites, event=None):
if not composites:
return
compositesAndAllChildren = self._compositesAndAllChildren(composites)
super(CompositeCollection, self).removeItems(compositesAndAllChildren,
event=event)
self._removeCompositesFromParent(composites, event)
def _removeCompositesFromParent(self, composites, event):
for composite in composites:
parent = composite.parent()
if parent:
parent.removeChild(composite, event=event)
def rootItems(self):
return [composite for composite in self if composite.parent() is None or \
composite.parent() not in self]
def allItemsSorted(self):
"""Returns a list of items and their children, so that if B is
a child, direct or not, of A, then A will come first in the
list."""
result = []
for item in self.rootItems():
result.append(item)
result.extend(item.children(recursive=True))
return result
class CompositeSet(CompositeCollection, observer.ObservableSet):
pass
class CompositeList(CompositeCollection, observer.ObservableList):
pass
|