Allow playback of VCD (Video CD) and SVCD
[enigma2.git] / lib / python / Components / Element.py
1 from Tools.CList import CList
2
3 # down                       up
4 # Render Converter Converter Source
5
6 # a bidirectional connection
7
8 def cached(f):
9         name = f.__name__
10         def wrapper(self):
11                 cache = self.cache
12                 if cache is None:
13                         return f(self)
14                 if name not in cache:
15                         cache[name] = (True, f(self))
16                 return cache[name][1]
17         return wrapper
18
19 class Element(object):
20         CHANGED_DEFAULT = 0   # initial "pull" state
21         CHANGED_ALL = 1       # really everything changed
22         CHANGED_CLEAR = 2     # we're expecting a real update soon. don't bother polling NOW, but clear data.
23         CHANGED_SPECIFIC = 3  # second tuple will specify what exactly changed
24         CHANGED_POLL = 4      # a timer expired
25
26         def __init__(self):
27                 self.downstream_elements = CList()
28                 self.master = None
29                 self.source = None
30                 self.__suspended = True
31                 self.cache = None
32
33         def connectDownstream(self, downstream):
34                 self.downstream_elements.append(downstream)
35                 if self.master is None:
36                         self.master = downstream
37         
38         def connectUpstream(self, upstream):
39                 assert self.source is None
40                 self.source = upstream
41                 self.changed((self.CHANGED_DEFAULT,))
42         
43         def connect(self, upstream):
44                 self.connectUpstream(upstream)
45                 upstream.connectDownstream(self)
46
47         # we disconnect from down to up
48         def disconnectAll(self):
49                 # we should not disconnect from upstream if
50                 # there are still elements depending on us.
51                 assert len(self.downstream_elements) == 0, "there are still downstream elements left"
52
53                 # Sources don't have a source themselves. don't do anything here.
54                 if self.source is not None:
55                         self.source.disconnectDownstream(self)
56                         # sources are owned by the Screen, so don't destroy them here.
57                         self.destroy()
58
59         def disconnectDownstream(self, downstream):
60                 self.downstream_elements.remove(downstream)
61                 if self.master == downstream:
62                         self.master = None
63                 
64                 if len(self.downstream_elements) == 0:
65                         self.disconnectAll()
66
67         # default action: push downstream
68         def changed(self, *args, **kwargs):
69                 self.cache = { }
70                 self.downstream_elements.changed(*args, **kwargs)
71                 self.cache = None
72
73         def reconnectUpstream(self, new_upstream):
74                 assert self.source is not None
75                 self.source = new_upstream
76
77         def setSuspend(self, suspended):
78                 changed = self.__suspended != suspended
79                 if not self.__suspended and suspended:
80                         self.doSuspend(1)
81                 elif self.__suspended and not suspended:
82                         self.doSuspend(0)
83                         
84                 self.__suspended = suspended
85                 if self.source is not None and changed:
86                         self.source.checkSuspend()
87         
88         suspended = property(lambda self: self.__suspended, setSuspend)
89         
90         def checkSuspend(self):
91                 self.suspended = reduce(lambda x, y: x and y.__suspended, self.downstream_elements, True)
92
93         def doSuspend(self, suspend):
94                 pass
95
96         def destroy(self):
97                 pass