1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 from muntjac.data.container \
17 import IOrdered, IItemSetChangeNotifier, IPropertySetChangeNotifier,\
18 IItemSetChangeListener, IPropertySetChangeListener, IItemSetChangeEvent,\
19 IPropertySetChangeEvent
20
21
24 """A wrapper class for adding external ordering to containers not
25 implementing the L{IOrdered} interface.
26
27 If the wrapped container is changed directly (that is, not through the
28 wrapper), and does not implement Container.ItemSetChangeNotifier and/or
29 PropertySetChangeNotifier the hierarchy information must be updated with
30 the L{updateOrderWrapper} method.
31
32 @author: Vaadin Ltd.
33 @author: Richard Lincoln
34 @version: 1.1.2
35 """
36
38 """Constructs a new ordered wrapper for an existing Container. Works even if
39 the to-be-wrapped container already implements the Container.Ordered
40 interface.
41
42 @param toBeWrapped
43 the container whose contents need to be ordered.
44 """
45
46 self._container = toBeWrapped
47
48
49
50 self._next = None
51
52
53
54 self._prev = None
55
56
57 self._first = None
58
59
60 self._last = None
61
62
63
64
65 self._ordered = False
66
67
68
69
70 self._lastKnownSize = -1
71
72 self._ordered = isinstance(self._container, IOrdered)
73
74
75 if self._container is None:
76 raise ValueError, 'Null can not be wrapped'
77
78
79 self.updateOrderWrapper()
80
81
83 """Removes the specified Item from the wrapper's internal hierarchy
84 structure.
85
86 Note : The Item is not removed from the underlying Container.
87
88 @param idd:
89 the ID of the Item to be removed from the ordering.
90 """
91 if idd is not None:
92 pid = self._prev.get(idd)
93 nid = self._next.get(idd)
94 if self._first == idd:
95 self._first = nid
96 if self._last == idd:
97 self._first = pid
98 if nid is not None:
99 self._prev[nid] = pid
100 if pid is not None:
101 self._next[pid] = nid
102 del self._next[idd]
103 del self._prev[idd]
104
105
107 """Registers the specified Item to the last position in the wrapper's
108 internal ordering. The underlying container is not modified.
109
110 @param idd
111 the ID of the Item to be added to the ordering.
112 ---
113 Registers the specified Item after the specified itemId in the wrapper's
114 internal ordering. The underlying container is not modified. Given item
115 idd must be in the container, or must be null.
116
117 @param idd
118 the ID of the Item to be added to the ordering.
119 @param previousItemId
120 the Id of the previous item.
121 """
122
123
124 if previousItemId == None:
125 if self._last is not None:
126 self._next[self._last] = idd
127 self._prev[idd] = self._last
128 self._last = idd
129 else:
130 self._first = self._last = idd
131 else:
132 if (self._last == previousItemId) or (self._last is None):
133 self.addToOrderWrapper(idd)
134 elif previousItemId is None:
135 self._next[idd] = self._first
136 self._prev[self._first] = idd
137 self._first = idd
138 else:
139 self._prev[idd] = previousItemId
140 self._next[idd] = self._next[previousItemId]
141 self._prev[self._next.get(previousItemId)] = idd
142 self._next[previousItemId] = idd
143
144
146 """Updates the wrapper's internal ordering information to include all
147 Items in the underlying container.
148
149 Note: If the contents of the wrapped container change without the
150 wrapper's knowledge, this method needs to be called to update the
151 ordering information of the Items.
152 """
153
154 if not self._ordered:
155 ids = self._container.getItemIds()
156
157 if (self._next is None or self._first is None
158 or self._last is None or self._prev is not None):
159 self._first = None
160 self._last = None
161 self._next = dict()
162 self._prev = dict()
163
164
165 for idd in self._next:
166 if not self._container.containsId(idd):
167 self.removeFromOrderWrapper(idd)
168
169
170 for idd in ids:
171 if idd not in self._next:
172 self.addToOrderWrapper(idd)
173
174
176
177 if self._ordered:
178 return self._container.firstItemId()
179 return self._first
180
181
183
184 if self._ordered:
185 return self._container.isFirstId(itemId)
186 return self._first is not None and self._first == itemId
187
188
190
191 if self._ordered:
192 return self._container.isLastId(itemId)
193 return self._last is not None and self._last == itemId
194
195
197
198 if self._ordered:
199 return self._container.lastItemId()
200 return self._last
201
202
204
205 if self._ordered:
206 return self._container.nextItemId(itemId)
207
208 if itemId is None:
209 return None
210
211 return self._next.get(itemId)
212
213
215 if self._ordered:
216 return self._container.prevItemId(itemId)
217
218 if itemId is None:
219 return None
220
221 return self._prev.get(itemId)
222
223
225 """Registers a new Property to all Items in the Container.
226
227 @param propertyId:
228 the ID of the new Property.
229 @param typ:
230 the Data type of the new Property.
231 @param defaultValue:
232 the value all created Properties are initialized to.
233 @return: C{True} if the operation succeeded, C{False} if not
234 """
235 return self._container.addContainerProperty(propertyId, typ,
236 defaultValue)
237
238
240 """Creates a new Item into the Container, assigns it an automatic ID,
241 and adds it to the ordering. Alternatively, registers a new Item by
242 its ID to the underlying container and to the ordering.
243
244 @param itemId:
245 the ID of the Item to be created.
246 @return:
247 C{None} if the operation failed
248 @raise NotImplementedError:
249 if the addItem is not supported.
250 """
251 if itemId is None:
252 idd = self._container.addItem()
253 if not self._ordered and (idd is not None):
254 self.addToOrderWrapper(idd)
255 return idd
256 else:
257 item = self._container.addItem(itemId)
258 if not self._ordered and (item is not None):
259 self.addToOrderWrapper(itemId)
260 return item
261
262
264 """Removes all items from the underlying container and from the
265 ordering.
266
267 @return: C{True} if the operation succeeded, otherwise C{False}
268 @raise NotImplementedError:
269 if the removeAllItems is not supported.
270 """
271 success = self._container.removeAllItems()
272 if (not self._ordered) and success:
273 self._first = self._last = None
274 self._next.clear()
275 self._prev.clear()
276 return success
277
278
280 """Removes an Item specified by the itemId from the underlying
281 container and from the ordering.
282
283 @param itemId:
284 the ID of the Item to be removed.
285 @return: C{True} if the operation succeeded, C{False} if not
286 @raise NotImplementedError:
287 if the removeItem is not supported.
288 """
289 success = self._container.removeItem(itemId)
290 if not self._ordered and success:
291 self.removeFromOrderWrapper(itemId)
292 return success
293
294
296 """Removes the specified Property from the underlying container and
297 from the ordering.
298
299 Note: The Property will be removed from all the Items in the Container.
300
301 @param propertyId:
302 the ID of the Property to remove.
303 @return: C{True} if the operation succeeded, C{False} if not
304 @raise NotImplementedError:
305 if the removeContainerProperty is not supported.
306 """
307 return self._container.removeContainerProperty(propertyId)
308
309
313
314
316
317 return self._container.getItem(itemId)
318
319
323
324
329
330
334
335
337
338
339 return self._container.getType(propertyId)
340
341
343
344 newSize = len(self._container)
345 if (self._lastKnownSize != -1 and newSize != self._lastKnownSize
346 and not isinstance(self._container, IItemSetChangeNotifier)):
347
348
349 self.updateOrderWrapper()
350 self._lastKnownSize = newSize
351 return newSize
352
353
356
357
359 if (isinstance(listener, IItemSetChangeListener) and
360 (iface is None or issubclass(iface, IItemSetChangeListener))):
361
362 if isinstance(self._container, IItemSetChangeNotifier):
363 pl = PiggybackListener(listener, self)
364 self._container.addListener(pl, IItemSetChangeListener)
365
366 if (isinstance(listener, IPropertySetChangeListener) and
367 (iface is None or
368 issubclass(iface, IPropertySetChangeListener))):
369
370 if isinstance(self._container, IPropertySetChangeNotifier):
371 pl = PiggybackListener(listener, self)
372 self._container.addListener(pl, IPropertySetChangeListener)
373
374
375 - def addCallback(self, callback, eventType=None, *args):
376 if eventType is None:
377 eventType = callback._eventType
378
379 if issubclass(eventType, IItemSetChangeEvent):
380
381 if isinstance(self._container, IItemSetChangeNotifier):
382 pl = PiggybackListener(callback, self, *args)
383 self._container.addListener(pl, IItemSetChangeListener)
384
385 elif issubclass(eventType, IPropertySetChangeEvent):
386
387 if isinstance(self._container, IPropertySetChangeNotifier):
388 pl = PiggybackListener(callback, self, *args)
389 self._container.addListener(pl, IPropertySetChangeListener)
390
391 else:
392 super(ContainerOrderedWrapper, self).addCallback(callback,
393 eventType, *args)
394
395
397 if (isinstance(listener, IItemSetChangeListener) and
398 (iface is None or issubclass(iface, IItemSetChangeListener))):
399
400 if isinstance(self._container, IItemSetChangeNotifier):
401 pl = PiggybackListener(listener, self)
402 self._container.removeListener(pl, IItemSetChangeListener)
403
404
405 if (isinstance(listener, IPropertySetChangeListener) and
406 (iface is None or issubclass(iface, IPropertySetChangeListener))):
407
408 if isinstance(self._container, IPropertySetChangeNotifier):
409 pl = PiggybackListener(listener, self)
410 self._container.removeListener(pl, IPropertySetChangeListener)
411
412
414 if eventType is None:
415 eventType = callback._eventType
416
417 if issubclass(eventType, IItemSetChangeEvent):
418
419 if isinstance(self._container, IItemSetChangeNotifier):
420 pl = PiggybackListener(callback, self)
421 self._container.removeListener(pl, IItemSetChangeListener)
422
423 elif issubclass(eventType, IPropertySetChangeEvent):
424
425 if isinstance(self._container, IPropertySetChangeNotifier):
426 pl = PiggybackListener(callback, self)
427 self._container.removeListener(pl, IPropertySetChangeListener)
428
429 else:
430 super(ContainerOrderedWrapper, self).removeCallback(callback,
431 eventType)
432
433
435
436
437 if newItemId == None:
438 if ((previousItemId is not None)
439 and not self.containsId(previousItemId)):
440 return None
441
442
443 idd = self._container.addItem()
444
445
446 if not self._ordered and idd is not None:
447 self.addToOrderWrapper(idd, previousItemId)
448
449 return idd
450 else:
451 if ((previousItemId is not None)
452 and not self.containsId(previousItemId)):
453 return None
454
455
456 item = self._container.addItem(newItemId)
457
458
459 if not self._ordered and item is not None:
460 self.addToOrderWrapper(newItemId, previousItemId)
461
462 return item
463
464
466 """This listener 'piggybacks' on the real listener in order to update the
467 wrapper when needed. It proxies __eq__() and __hash__() to the real
468 listener so that the correct listener gets removed.
469 """
470
471 - def __init__(self, realListener, wrapper, *args):
472 self._listener = realListener
473 self._wrapper = wrapper
474 self._args = args
475
476
483
484
491
492
494 return ((obj == self._listener)
495 or (obj is not None and obj == self._listener))
496
497
499 return hash(self._listener)
500