Audio/AudioControl: Lots of fixes
[audiocontrol.git] / Node.py
1 """A Node is an object which autmatically manages it's owner(s).
2
3 A Node should alweys be stored in attribute members declared as
4 NodeReference or as member of a NodeMap or NodeList."""
5
6
7 import weakref
8
9 class Node(object):
10
11     def __init__(self):
12         self._owners = []
13
14     def _addOwner(self,owner):
15         self._owners.append(weakref.ref(owner,self._delRef))
16
17     def _delOwner(self,owner):
18         for i in range(len(self._owners)):
19             if self._owners[i]() is owner:
20                 del self._owners[i]
21                 return
22
23     def _delRef(self,ref):
24         for i in range(len(self._owners)):
25             if self._owners[i] is ref:
26                 del self._owners[i]
27                 return
28
29     def _owners(self):
30         return ( x() for x in self._owners )
31
32     def _owner(self):
33         if self._owners and self._owners[0]() is not None:
34             return self._owners[0]()
35         return None
36
37     owners = property(_owners, None, None, None)
38     owner = property(_owner, None, None, None)
39
40 id_index = 0
41 def _make_id():
42     global id_index
43     id_index += 1
44     return '__node_elt_%d' % id_index
45
46 def NodeReference(id=None):
47     if id is None : id = _make_id()
48     return property(lambda self, id=id: getattr(self,id,None),
49                     lambda self, node, id=id: _NodeReference_set(self,node,id),
50                     None,
51                     None)
52
53 def _NodeReference_set(self, node, id):
54     old = getattr(self,id,None)
55     if old is not None : old._delOwner(self)
56     setattr(self,id,node)
57     if node is not None : node._addOwner(self)
58
59
60 class _NodeMap(dict):
61
62     def __init__(self, owner):
63         dict.__init__(self)
64         self._owner = weakref.ref(owner)
65
66     def __setitem__(self, key, node):
67         try: v = self[key]
68         except KeyError: pass
69         else: v._delOwner(self._owner())
70         dict.__setitem__(self, key, node)
71         node._addOwner(self._owner())
72
73     def __delitem__(self, key):
74         try: v = self[key]
75         except KeyError: pass
76         else: v._delOwner(self._owner())
77         dict.__delitem__(self,key)
78
79     def clear(self):
80         owner = self._owner()
81         for v in self.itervalues() : v._delOwner(owner)
82         dict.clear(self)
83
84     def setdefault(self, key, node):
85         if not self.has_key(key) : self[key] = node
86
87     def pop(self, key):
88         v = self[key]
89         del self[key]
90         return v
91
92     def popitem(self):
93         try: k = self.iterkeys().next()
94         except StopIteration: raise KeyError, 'popitem(): dictionary is empty'
95         return (k, self.pop(k))
96
97     def update(self, *args, **kws):
98         for k,v in dict(*args,**kws).iteritems() : self[k] = v
99
100 def NodeMap(id=None):
101     if id is None : id = _make_id()
102     return property(lambda self, id=id : _NodeMap_get(self, id),
103                     lambda self, elts, id=id : _NodeMap_set(self, elts, id),
104                     None)
105
106 def _NodeMap_get(self, id):
107     if not hasattr(self, id) : setattr(self, id, _NodeMap(self))
108     return getattr(self, id)
109
110 def _NodeMap_set(self, elts, id):
111     if hasattr(self, id) : getattr(self, id).clear()
112     else                 : setattr(self, id, _NodeMap(self))
113     getattr(self, id).update(elts)
114     
115
116 class _NodeList(list):
117
118     def __init__(self, owner):
119         list.__init__(self)
120         self._owner = weakref.ref(owner)
121
122     def __setitem__(self, index, node):
123         if type(index) is not slice:
124             self[index] # throw IndexError if index invalid
125             index = slice(index,index+1,None)
126             node = [ node ]
127         owner = self._owner()
128         for i in range(*index.indices(len(self))) : self[i]._delOwner(owner)
129         try:
130             list.__setitem__(self, index, node)
131         except ValueError:
132             for i in range(*index.indices(len(self))) : self[i]._addOwner(owner)
133             raise
134         else:
135             for n in node : n._addOwner(owner)
136
137     def __delitem__(self, index):
138         if type(index) is not slice:
139             self[index] # throw IndexError if index invalid
140             index = slice(index,index+1,None)
141         self.__setitem__(index,[])
142
143     def __setslice__(self, i, j, seq):
144         self[max(0, i):max(0, j):] = seq
145
146     def __delslice__(self, i, j):
147         del self[max(0, i):max(0, j):]
148
149     def append(self, node):
150         self[len(self):len(self)] = [node]
151
152     def extend(self, nodes):
153         self[len(self):len(self)] = nodes
154
155     def insert(self, index, node):
156         self[index:index] = [node]
157
158     def pop(self, index=None):
159         if index is None : index = len(self)-1
160         x = self[index]
161         del self[index]
162         return x
163
164     def remove(self, node):
165         del self[self.index(node)]
166
167 def NodeList(id=None):
168     if id is None : id = _make_id()
169     return property(lambda self, id=id : _NodeList_get(self, id),
170                     lambda self, elts, id=id : _NodeList_set(self, elts, id),
171                     None)
172
173 def _NodeList_get(self, id):
174     if not hasattr(self, id) : setattr(self, id, _NodeList(self))
175     return getattr(self, id)
176
177 def _NodeList_set(self, elts, id):
178     if hasattr(self, id) : del getattr(self, id)[:]
179     else                 : setattr(self, id, _NodeList(self))
180     getattr(self, id).extend(elts)