add proof-of-concept web interface
[enigma2.git] / lib / python / Plugins / Extensions / WebInterface / webif.py
1 #
2 # OK, this is more a proof of concept
3 # things to improve:
4 #  - nicer code
5 #  - screens need to be defined somehow else. 
6 #    I don't know how, yet. Probably each in an own file.
7 #  - more components, like the channellist
8 #  - better error handling
9 #  - use namespace parser
10
11 from Screens.Screen import Screen
12 from Tools.Import import my_import
13
14 # for our testscreen
15 from Screens.InfoBarGenerics import InfoBarServiceName, InfoBarEvent
16 from Components.Sources.Clock import Clock
17
18 from xml.sax import make_parser
19 from xml.sax.handler import ContentHandler, feature_namespaces
20 from twisted.python import util
21 import sys
22 import time
23
24 # prototype of the new web frontend template system.
25
26 # a test screen
27 class TestScreen(InfoBarServiceName, InfoBarEvent, Screen):
28         def __init__(self, session):
29                 Screen.__init__(self, session)
30                 InfoBarServiceName.__init__(self)
31                 InfoBarEvent.__init__(self)
32                 self["CurrentTime"] = Clock()
33
34 # turns .text into __str__ 
35 class Element:
36         def __init__(self, source):
37                 self.source = source
38
39         def __str__(self):
40                 return self.source.text
41
42 # a to-be-filled list item
43 class ListItem:
44         def __init__(self, name):
45                 self.name = name
46
47 # the performant 'listfiller'-engine (plfe)
48 class ListFiller(object):
49         def __init__(self, arg):
50                 self.template = arg
51                 
52         def getText(self):
53                 l = self.source.list
54                 lut = self.source.lut
55                 
56                 # now build a ["string", 1, "string", 2]-styled list, with indices into the 
57                 # list to avoid lookup of item name for each entry
58                 lutlist = []
59                 for element in self.template:
60                         if isinstance(element, str):
61                                 lutlist.append(element)
62                         elif isinstance(element, ListItem):
63                                 lutlist.append(lut[element.name])
64                 
65                 # now, for the huge list, do:
66                 res = ""
67                 for item in l:
68                         for element in lutlist:
69                                 if isinstance(element, str):
70                                         res += element
71                                 else:
72                                         res += str(item[element])
73                 # (this will be done in c++ later!)
74                 return res
75                 
76         text = property(getText)
77
78 class webifHandler(ContentHandler):
79         def __init__(self, session):
80                 self.res = [ ]
81                 self.mode = 0
82                 self.screen = None
83                 self.session = session
84         
85         def startElement(self, name, attrs):
86                 if name == "e2:screen":
87                         self.screen = eval(attrs["name"])(self.session) # fixme
88                         return
89         
90                 if name[:3] == "e2:":
91                         self.mode += 1
92                 
93                 tag = "<" + name + ''.join([' ' + key + '="' + val + '"' for (key, val) in attrs.items()]) + ">"
94                 tag = tag.encode("UTF-8")
95                 
96                 if self.mode == 0:
97                         self.res.append(tag)
98                 elif self.mode == 1: # expect "<e2:element>"
99                         assert name == "e2:element", "found %s instead of e2:element" % name
100                         self.source = self.screen[attrs["source"]]
101                 elif self.mode == 2: # expect "<e2:convert>"
102                         if name[:3] == "e2:":
103                                 assert name == "e2:convert"
104                                 
105                                 ctype = attrs["type"]
106                                 if ctype[:4] == "web:": # for now
107                                         self.converter = eval(ctype[4:])
108                                 else:
109                                         self.converter = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype)
110                                 self.sub = [ ]
111                         else:
112                                 self.sub.append(tag)
113                 elif self.mode == 3:
114                         assert name == "e2:item", "found %s instead of e2:item!" % name
115                         self.sub.append(ListItem(attrs["name"]))
116
117         def endElement(self, name):
118                 if name == "e2:screen":
119                         self.screen = None
120                         return
121
122                 tag = "</" + name + ">"
123                 if self.mode == 0:
124                         self.res.append(tag)
125                 elif self.mode == 2 and name[:3] != "e2:":
126                         self.sub.append(tag)
127                 elif self.mode == 2: # closed 'convert' -> sub
128                         self.sub = lreduce(self.sub)
129                         if len(self.sub) == 1:
130                                 self.sub = self.sub[0]
131                         c = self.converter(self.sub)
132                         c.connect(self.source)
133                         self.source = c
134                         
135                         del self.sub
136                 elif self.mode == 1: # closed 'element'
137                         self.res.append(Element(self.source))
138                         del self.source
139
140                 if name[:3] == "e2:":
141                         self.mode -= 1
142
143         def processingInstruction(self, target, data):
144                 self.res.append('<?' + target + ' ' + data + '>')
145         
146         def characters(self, ch):
147                 ch = ch.encode("UTF-8")
148                 if self.mode == 0:
149                         self.res.append(ch)
150                 elif self.mode == 2:
151                         self.sub.append(ch)
152         
153         def startEntity(self, name):
154                 self.res.append('&' + name + ';');
155
156 def lreduce(list):
157         # ouch, can be made better
158         res = [ ]
159         string = None
160         for x in list:
161                 if isinstance(x, str) or isinstance(x, unicode):
162                         x = x.encode("UTF-8")
163                         if string is None:
164                                 string = x
165                         else:
166                                 string += x
167                 else:
168                         if string is not None:
169                                 res.append(string)
170                                 string = None
171                         res.append(x)
172         if string is not None:
173                 res.append(string)
174                 string = None
175         return res
176
177 def renderPage(stream, req, session):
178         handler = webifHandler(session)
179         parser = make_parser()
180         parser.setFeature(feature_namespaces, 0)
181         parser.setContentHandler(handler)
182         parser.parse(open(util.sibpath(__file__, 'test.xml'))) # currently fixed
183         for x in lreduce(handler.res):
184                 stream.write(str(x))
185         stream.finish() # must be done, unless we "callLater"