Package elisa :: Package core :: Package observers :: Module list
[hide private]
[frames] | no frames]

Source Code for Module elisa.core.observers.list

  1  # -*- coding: utf-8 -*- 
  2  # Elisa - Home multimedia server 
  3  # Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com). 
  4  # All rights reserved. 
  5  # 
  6  # This file is available under one of two license agreements. 
  7  # 
  8  # This file is licensed under the GPL version 3. 
  9  # See "LICENSE.GPL" in the root of this distribution including a special 
 10  # exception to use Elisa with Fluendo's plugins. 
 11  # 
 12  # The GPL part of Elisa is also available under a commercial licensing 
 13  # agreement from Fluendo. 
 14  # See "LICENSE.Elisa" in the root directory of this distribution package 
 15  # for details on that license. 
 16   
 17  """ 
 18  List for which changes are notified to observers 
 19  """ 
 20   
 21  import weakref 
 22   
 23  from elisa.core import log 
 24  from elisa.core.utils.threadsafe_list import ThreadsafeList 
 25  from elisa.core.observers.observable import Observable 
 26   
27 -class ListObservable(log.Loggable, ThreadsafeList):
28 """ 29 ListObservable implements an observable list. It has all the 30 functionalities of a normal L{list} and in addition informs all its 31 observers about any change to its content. 32 33 Its notification protocol is defined in L{ListObserver}. It is advised to 34 use a subclass of L{ListObserver} in order to observe an instance of 35 L{ListObservable}. 36 All the methods that do writing operations declare what message they send 37 to the observers in their documentation. 38 39 Notification messages are always sent to the observers after the actual 40 operation is done. 41 """ 42 43 # FIXME: this class should be made thread-safe. This will probably allow 44 # dropping the inheritance from ThreadsafeList.
45 - def __init__(self, *args, **kw):
46 super(ListObservable, self).__init__(*args, **kw) 47 self._observers = []
48
49 - def _send_message_to_observers(self, message, *args):
50 for weak_observer in self._observers: 51 observer = weak_observer() 52 if observer == None: 53 continue 54 else: 55 getattr(observer, message)(*args)
56
57 - def __hash__(self):
58 return log.Loggable.__hash__(self)
59
60 - def __repr__(self):
61 return "<ListObservable %r>" % ThreadsafeList.__repr__(self)
62
63 - def __eq__(self, other):
64 return id(self) == id(other)
65
66 - def __setitem__(self, key, value):
67 """ 68 Send the message 'modified' to the observers. 69 """ 70 if key < len(self) and key >= -len(self): 71 element = self[key] 72 if isinstance(element, Observable): 73 element.remove_observer(self) 74 ThreadsafeList.__setitem__(self, key, value) 75 76 self._send_message_to_observers("modified", key, value) 77 78 if isinstance(value, Observable): 79 value.add_observer(self)
80
81 - def __delitem__(self, key):
82 """ 83 Send the message 'removed' to the observers. 84 """ 85 if key < len(self) and key >= -len(self): 86 element = self[key] 87 if isinstance(element, Observable): 88 element.remove_observer(self) 89 ThreadsafeList.__delitem__(self, key) 90 91 self._send_message_to_observers("removed", [element], key)
92
93 - def append(self, element):
94 """ 95 Send the message 'inserted' to the observers. 96 """ 97 position = len(self) 98 ThreadsafeList.append(self, element) 99 100 self._send_message_to_observers("inserted", [element], position) 101 102 if isinstance(element, Observable): 103 element.add_observer(self)
104
105 - def extend(self, elements):
106 """ 107 Send the message 'inserted' to the observers. 108 """ 109 position = len(self) 110 ThreadsafeList.extend(self, elements) 111 112 self._send_message_to_observers("inserted", elements, position) 113 114 for element in elements: 115 if isinstance(element, Observable): 116 element.add_observer(self)
117
118 - def insert(self, position, element):
119 """ 120 Send the message 'inserted' to the observers. 121 """ 122 ThreadsafeList.insert(self, position, element) 123 124 self._send_message_to_observers("inserted", [element], position) 125 126 if isinstance(element, Observable): 127 element.add_observer(self)
128
129 - def pop(self, position=-1):
130 """ 131 Send the message 'removed' to the observers. 132 """ 133 element = ThreadsafeList.pop(self, position) 134 if isinstance(element, Observable): 135 element.remove_observer(self) 136 137 self._send_message_to_observers("removed", [element], position) 138 139 return element
140
141 - def remove(self, element):
142 """ 143 Send the message 'removed' to the observers. 144 """ 145 if isinstance(element, Observable): 146 element.remove_observer(self) 147 position = self.index(element) 148 ThreadsafeList.pop(self, position) 149 150 self._send_message_to_observers("removed", [element], position)
151
152 - def reverse(self):
153 """ 154 Send the message 'dirtied' to the observers. 155 """ 156 ThreadsafeList.reverse(self) 157 self._send_message_to_observers("dirtied")
158
159 - def sort(self, *args, **kwargs):
160 """ 161 Send the message 'dirtied' to the observers. 162 """ 163 ThreadsafeList.sort(self, *args, **kwargs) 164 self._send_message_to_observers("dirtied")
165
166 - def __iadd__(self, operand):
167 """ 168 Send the message 'inserted' to the observers. 169 """ 170 position = len(self) 171 result = ThreadsafeList.__iadd__(self, operand) 172 173 self._send_message_to_observers("inserted", operand, position) 174 175 for element in operand: 176 if isinstance(element, Observable): 177 element.add_observer(self) 178 179 return result
180
181 - def __imul__(self, coefficient):
182 """ 183 Send the message 'inserted' to the observers. 184 """ 185 # FIXME: is it copying the elements? 186 raise NotImplementedError 187 188 position = len(self) 189 result = ThreadsafeList.__imul__(self, coefficient) 190 elements = result[position:] 191 self._send_message_to_observers("inserted", elements, position) 192 return result
193
194 - def __setslice__(self, i, j, elements):
195 """ 196 Send successively the message 'removed' and the message 'inserted' to 197 the observers. 198 """ 199 removed_elements = self[i:j] 200 for element in removed_elements: 201 if isinstance(element, Observable): 202 element.remove_observer(self) 203 ThreadsafeList.__setslice__(self, i, j, elements) 204 205 self._send_message_to_observers("removed", removed_elements, i) 206 self._send_message_to_observers("inserted", elements, i) 207 208 for element in elements: 209 if isinstance(element, Observable): 210 element.add_observer(self)
211
212 - def __delslice__(self, i, j):
213 """ 214 Send the message 'removed' to the observers. 215 """ 216 removed_elements = self[i:j] 217 for element in removed_elements: 218 if isinstance(element, Observable): 219 element.remove_observer(self) 220 ThreadsafeList.__delslice__(self, i, j) 221 222 self._send_message_to_observers("removed", removed_elements, i)
223
224 - def add_observer(self, observer):
225 """Attach an observer which will then be notified of all the changes 226 applied to the observable. 227 228 @param observer: observer to attach 229 @type observer: L{elisa.core.observers.observer.Observer} 230 """ 231 self.debug("Adding observer %r", observer) 232 real_observers = [weak_observer() for weak_observer in self._observers] 233 if observer not in real_observers: 234 self._observers.append(weakref.ref(observer)) 235 else: 236 self.debug("Observer %r was already observing" % observer)
237
238 - def remove_observer(self, observer):
239 """Detach an observer which will not be notified anymore of changes 240 applied to the observable. 241 242 @param observer: observer to detach 243 @type observer: L{elisa.core.observers.observer.Observer} 244 """ 245 self.debug("Removing observer %r", observer) 246 refs = weakref.getweakrefs(observer) 247 for ref in refs: 248 try: 249 self._observers.remove(ref) 250 except ValueError: 251 pass 252 """ 253 # ignore the call if the observer was not known 254 self.debug("Observer %r was not observing", observer) 255 """
256
257 - def attribute_set(self, origin, key, old_value, new_value):
258 # notify the observers that some attribute of an element of the list 259 # has changed 260 position = self.index(origin) 261 self._send_message_to_observers("element_attribute_set", position, 262 key, old_value, new_value)
263 264
265 -class ListObserver(object):
266
267 - def inserted(self, elements, position):
268 """ 269 Message sent by a L{ListObservable} when new elements are inserted in 270 it. 271 272 @param elements: newly inserted elements 273 @type elements: list 274 @param position: index where the elements have been inserted at 275 @type position: int 276 """ 277 pass
278
279 - def removed(self, elements, position):
280 """ 281 Message sent by a L{ListObservable} when elements are removed from it. 282 283 @param elements: removed elements 284 @type elements: list 285 @param position: former index of the elements 286 @type position: int 287 """ 288 pass
289
290 - def modified(self, position, value):
291 """ 292 Message sent by a L{ListObservable} when one of its elements is 293 modified. 294 295 @param position: index of the modified element 296 @type position: int 297 @param value: new value of the element 298 @type value: object 299 """ 300 pass
301
302 - def dirtied(self):
303 """ 304 Message sent by a L{ListObservable} when it is completely changed. For 305 example, this happens after a reverse or a sort. 306 """ 307 pass
308
309 - def element_attribute_set(self, position, key, old_value, new_value):
310 """ 311 Message sent by a L{ListObservable} when an attribute of one of its 312 element is changed. 313 314 @param position: index of the element 315 @type position: int 316 @param key: modified attribute of the element 317 @type key: str 318 @param old_value: value of the attribute before the change 319 @type old_value: object 320 @param new_value: value of the attribute after the change 321 @type new_value: object 322 """ 323 pass
324 325 #if __name__ == "__main__": 326 # 327 # l = ListObservable() 328 # o = ListObserver() 329 # 330 # l.add_observer(o) 331 # 332 # print l 333 # l.append(3) 334 # print l 335 # l.extend([44, 4, 78, 18]) 336 # print l 337 # l.insert(0, 15) 338 # print l 339 # l.pop(0) 340 # print l 341 # l.remove(3) 342 # print l 343 # l.reverse() 344 # print l 345 # l.sort() 346 # print l 347 # l += [12, 29] 348 # print l 349 # l *= 4 350 # print l 351 # l[2] = 555 352 # print l 353 # del l[2] 354 # print l 355 # l[0:3] = [] 356 # print l 357 # del l[:] 358 # print l 359