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