a lot of new wizard functionality
[enigma2.git] / lib / python / Screens / Wizard.py
1 from Screen import Screen
2
3 import string
4
5 from Screens.HelpMenu import HelpableScreen
6 from Components.config import config
7 from Components.Label import Label
8 from Components.Slider import Slider
9 from Components.ActionMap import NumberActionMap
10 from Components.MenuList import MenuList
11 from Components.ConfigList import ConfigList
12 from Components.Sources.List import List
13
14 from enigma import eTimer
15
16 from xml.sax import make_parser
17 from xml.sax.handler import ContentHandler
18
19 class WizardSummary(Screen):
20         skin = """
21         <screen position="0,0" size="132,64">
22                 <widget name="text" position="6,4" size="120,42" font="Regular;14" />
23                 <widget source="parent.list" render="Label" position="6,25" size="120,21" font="Regular;16">
24                         <convert type="StringListSelection" />
25                 </widget>
26         </screen>"""
27         
28         def __init__(self, session, parent):
29                 Screen.__init__(self, session, parent)
30                 
31                 #names = parent.skinName
32                 #if not isinstance(names, list):
33                         #names = [names]
34 #                       
35                 #self.skinName = [x + "_summary" for x in names ]
36                 #self.skinName.append("Wizard")
37                 #print "*************+++++++++++++++++****************++++++++++******************* WizardSummary", self.skinName
38                         #
39                 self["text"] = Label("")
40                 self.onShow.append(self.setCallback)
41                 
42         def setCallback(self):
43                 self.parent.setLCDTextCallback(self.setText)
44                 
45         def setText(self, text):
46                 self["text"].setText(text)
47
48 class Wizard(Screen, HelpableScreen):
49
50         class parseWizard(ContentHandler):
51                 def __init__(self, wizard):
52                         self.isPointsElement, self.isReboundsElement = 0, 0
53                         self.wizard = wizard
54                         self.currContent = ""
55                         self.lastStep = 0
56                         
57                 def createSummary(self):
58                         print "WizardCreateSummary"
59                         return WizardSummary
60                 
61                 def startElement(self, name, attrs):
62                         print "startElement", name
63                         self.currContent = name
64                         if (name == "step"):
65                                 self.lastStep += 1
66                                 if attrs.has_key('id'):
67                                         id = str(attrs.get('id'))
68                                 else:
69                                         id = ""
70                                 if attrs.has_key('nextstep'):
71                                         nextstep = str(attrs.get('nextstep'))
72                                 else:
73                                         nextstep = None
74                                 if attrs.has_key('timeout'):
75                                         timeout = int(attrs.get('timeout'))
76                                 else:
77                                         timeout = None
78                                 if attrs.has_key('timeoutaction'):
79                                         timeoutaction = str(attrs.get('timeoutaction'))
80                                 else:
81                                         timeoutaction = 'nextpage'
82                                 self.wizard[self.lastStep] = {"id": id, "condition": "", "text": "", "timeout": timeout, "timeoutaction": timeoutaction, "list": [], "config": {"screen": None, "args": None, "type": "" }, "code": "", "codeafter": "", "nextstep": nextstep}
83                         elif (name == "text"):
84                                 self.wizard[self.lastStep]["text"] = string.replace(str(attrs.get('value')), "\\n", "\n")
85                         elif (name == "displaytext"):
86                                 self.wizard[self.lastStep]["displaytext"] = string.replace(str(attrs.get('value')), "\\n", "\n")
87                         elif (name == "list"):
88                                 if (attrs.has_key('type')):
89                                         self.wizard[self.lastStep]["dynamiclist"] = attrs.get("source")
90                                         #self.wizard[self.lastStep]["list"].append(("Hallo", "test"))
91                                 if (attrs.has_key("evaluation")):
92                                         self.wizard[self.lastStep]["listevaluation"] = attrs.get("evaluation")
93                                 if (attrs.has_key("onselect")):
94                                         self.wizard[self.lastStep]["onselect"] = attrs.get("onselect")                  
95                         elif (name == "listentry"):
96                                 self.wizard[self.lastStep]["list"].append((str(attrs.get('caption')), str(attrs.get('step'))))
97                         elif (name == "config"):
98                                 exec "from Screens." + str(attrs.get('module')) + " import *"
99                                 self.wizard[self.lastStep]["config"]["screen"] = eval(str(attrs.get('screen')))
100                                 if (attrs.has_key('args')):
101                                         print "has args"
102                                         self.wizard[self.lastStep]["config"]["args"] = str(attrs.get('args'))
103                                 self.wizard[self.lastStep]["config"]["type"] = str(attrs.get('type'))
104                         elif (name == "code"):
105                                 if attrs.has_key('pos') and str(attrs.get('pos')) == "after":
106                                         self.codeafter = True
107                                 else:
108                                         self.codeafter = False
109                         elif (name == "condition"):
110                                 pass
111                 def endElement(self, name):
112                         self.currContent = ""
113                         if name == 'code':
114                                 if self.codeafter:
115                                         self.wizard[self.lastStep]["codeafter"] = self.wizard[self.lastStep]["codeafter"].strip()
116                                 else:
117                                         self.wizard[self.lastStep]["code"] = self.wizard[self.lastStep]["code"].strip()
118                         elif name == 'condition':
119                                 self.wizard[self.lastStep]["condition"] = self.wizard[self.lastStep]["condition"].strip()
120                                                                 
121                 def characters(self, ch):
122                         if self.currContent == "code":
123                                 if self.codeafter:
124                                         self.wizard[self.lastStep]["codeafter"] = self.wizard[self.lastStep]["codeafter"] + ch
125                                 else:
126                                         self.wizard[self.lastStep]["code"] = self.wizard[self.lastStep]["code"] + ch
127                         elif self.currContent == "condition":
128                                  self.wizard[self.lastStep]["condition"] = self.wizard[self.lastStep]["condition"] + ch
129
130         def __init__(self, session, showSteps = True, showStepSlider = True, showList = True, showConfig = True):
131                 Screen.__init__(self, session)
132                 HelpableScreen.__init__(self)
133
134                 self.stepHistory = []
135
136                 self.wizard = {}
137                 parser = make_parser()
138                 print "Reading " + self.xmlfile
139                 wizardHandler = self.parseWizard(self.wizard)
140                 parser.setContentHandler(wizardHandler)
141                 if self.xmlfile[0] != '/':
142                         parser.parse('/usr/share/enigma2/' + self.xmlfile)
143                 else:
144                         parser.parse(self.xmlfile)
145
146                 self.showSteps = showSteps
147                 self.showStepSlider = showStepSlider
148                 self.showList = showList
149                 self.showConfig = showConfig
150
151                 self.numSteps = len(self.wizard)
152                 self.currStep = 1
153                 
154                 self.timeoutTimer = eTimer()
155                 self.timeoutTimer.timeout.get().append(self.timeoutCounterFired)
156
157                 self["text"] = Label()
158
159                 if showConfig:
160                         self["config"] = ConfigList([])
161
162                 if self.showSteps:
163                         self["step"] = Label()
164                 
165                 if self.showStepSlider:
166                         self["stepslider"] = Slider(1, self.numSteps)
167                 
168                 if self.showList:
169                         self.list = []
170                         self["list"] = List(self.list, enableWrapAround = True)
171                         self["list"].onSelectionChanged.append(self.selChanged)
172                         #self["list"] = MenuList(self.list, enableWrapAround = True)
173
174                 self.onShown.append(self.updateValues)
175
176                 self.configInstance = None
177                 
178                 self.lcdCallbacks = []
179                 
180                 self["actions"] = NumberActionMap(["WizardActions", "NumberActions"],
181                 {
182                         "ok": self.ok,
183                         "back": self.back,
184                         "left": self.left,
185                         "right": self.right,
186                         #"up": self.up,
187                         #"down": self.down,
188                         "1": self.keyNumberGlobal,
189                         "2": self.keyNumberGlobal,
190                         "3": self.keyNumberGlobal,
191                         "4": self.keyNumberGlobal,
192                         "5": self.keyNumberGlobal,
193                         "6": self.keyNumberGlobal,
194                         "7": self.keyNumberGlobal,
195                         "8": self.keyNumberGlobal,
196                         "9": self.keyNumberGlobal,
197                         "0": self.keyNumberGlobal
198                 }, -1)
199
200         def setLCDTextCallback(self, callback):
201                 self.lcdCallbacks.append(callback)
202
203         def back(self):
204                 if len(self.stepHistory) > 1:
205                         self.currStep = self.stepHistory[-2]
206                         self.stepHistory = self.stepHistory[:-2]
207                 if self.currStep < 1:
208                         self.currStep = 1
209                 self.updateValues()
210                 
211         def markDone(self):
212                 pass
213         
214         def getStepWithID(self, id):
215                 count = 0
216                 for x in self.wizard:
217                         if self.wizard[x]["id"] == id:
218                                 return count
219                         count += 1
220                 return 0
221
222         def finished(self, *args, **kwargs):
223                 print "finished"
224                 currStep = self.currStep
225
226                 if self.updateValues not in self.onShown:
227                         self.onShown.append(self.updateValues)
228
229                 if self.showList:
230                         if (len(self.wizard[currStep]["evaluatedlist"]) > 0):
231                                 print "current:", self["list"].current
232                                 nextStep = self["list"].current[1]
233                                 if (self.wizard[currStep].has_key("listevaluation")):
234                                         exec("self." + self.wizard[self.currStep]["listevaluation"] + "('" + nextStep + "')")
235                                 else:
236                                         self.currStep = self.getStepWithID(nextStep)
237
238                 if (currStep == self.numSteps): # wizard finished
239                         self.markDone()
240                         self.close()
241                 else:
242                         self.runCode(self.wizard[currStep]["codeafter"])
243                         if self.wizard[currStep]["nextstep"] is not None:
244                                 self.currStep = self.getStepWithID(self.wizard[currStep]["nextstep"])
245                         self.currStep += 1
246                         self.updateValues()
247
248                 print "Now: " + str(self.currStep)
249
250
251         def ok(self):
252                 print "OK"
253                 currStep = self.currStep
254                 
255                 if self.showConfig:
256                         if (self.wizard[currStep]["config"]["screen"] != None):
257                                 # TODO: don't die, if no run() is available
258                                 # there was a try/except here, but i can't see a reason
259                                 # for this. If there is one, please do a more specific check
260                                 # and/or a comment in which situation there is no run()
261                                 if callable(getattr(self.configInstance, "runAsync", None)):
262                                         self.onShown.remove(self.updateValues)
263                                         self.configInstance.runAsync(self.finished)
264                                         return
265                                 else:
266                                         self.configInstance.run()
267                 self.finished()
268
269         def keyNumberGlobal(self, number):
270                 if (self.wizard[self.currStep]["config"]["screen"] != None):
271                         self.configInstance.keyNumberGlobal(number)
272                 
273         def left(self):
274                 self.resetCounter()
275                 if (self.wizard[self.currStep]["config"]["screen"] != None):
276                         self.configInstance.keyLeft()
277                 print "left"
278         
279         def right(self):
280                 self.resetCounter()
281                 if (self.wizard[self.currStep]["config"]["screen"] != None):
282                         self.configInstance.keyRight()
283                 print "right"
284
285         def up(self):
286                 self.resetCounter()
287                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None):
288                                 self["config"].instance.moveSelection(self["config"].instance.moveUp)
289                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
290                         self["list"].instance.moveSelection(self["list"].instance.moveUp)
291                         if self.wizard[self.currStep].has_key("onselect"):
292                                 self.selection = self.wizard[self.currStep]["evaluatedlist"][self["list"].l.getCurrentSelectionIndex()][1]
293                                 exec("self." + self.wizard[self.currStep]["onselect"] + "()")
294                 print "up"
295                 
296         def down(self):
297                 self.resetCounter()
298                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None):
299                         self["config"].instance.moveSelection(self["config"].instance.moveDown)
300                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
301                         #self["list"].instance.moveSelection(self["list"].instance.moveDown)
302                         if self["list"].index + 1 >= self["list"].count():
303                                 self["list"].index = 0
304                         else:
305                                 self["list"].index += 1
306                         if self.wizard[self.currStep].has_key("onselect"):
307                                 print "current:", self["list"].current
308                                 #self.selection = self.wizard[self.currStep]["evaluatedlist"][self["list"].l.getCurrentSelectionIndex()][1]
309                                 #exec("self." + self.wizard[self.currStep]["onselect"] + "()")
310                 print "down"
311                 
312         def selChanged(self):
313                 self.resetCounter()
314                 
315                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None):
316                                 self["config"].instance.moveSelection(self["config"].instance.moveUp)
317                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
318                         if self.wizard[self.currStep].has_key("onselect"):
319                                 self.selection = self["list"].current[1]
320                                 print "self.selection:", self.selection
321                                 exec("self." + self.wizard[self.currStep]["onselect"] + "()")
322                 
323         def resetCounter(self):
324                 self.timeoutCounter = self.wizard[self.currStep]["timeout"]
325                 
326         def runCode(self, code):
327                 if code != "":
328                         print "code", code
329                         exec(code)
330                         
331         def updateText(self, firstset = False):
332                 text = _(self.wizard[self.currStep]["text"])
333                 if text.find("[timeout]") != -1:
334                         text = text.replace("[timeout]", str(self.timeoutCounter))
335                         self["text"].setText(text)
336                 else:
337                         if firstset:
338                                 self["text"].setText(text)
339                 
340         def updateValues(self):
341                 print "Updating values in step " + str(self.currStep)
342                 self.timeoutTimer.stop()
343                 
344                 self.stepHistory.append(self.currStep)
345                 
346                 if self.configInstance is not None:
347                         del self.configInstance["config"]
348                         self.configInstance.doClose()
349                         self.configInstance = None
350                 
351                 self.condition = True
352                 exec (self.wizard[self.currStep]["condition"])
353                 if self.condition:
354                         print "wizard step:", self.wizard[self.currStep]
355                         
356                         if self.showSteps:
357                                 self["step"].setText(_("Step ") + str(self.currStep) + "/" + str(self.numSteps))
358                         if self.showStepSlider:
359                                 self["stepslider"].setValue(self.currStep)
360                 
361                         if self.wizard[self.currStep]["timeout"] is not None:
362                                 self.resetCounter() 
363                                 self.timeoutTimer.start(1000)
364                         
365                         print "wizard text", _(self.wizard[self.currStep]["text"])
366                         self.updateText(firstset = True)
367                         if self.wizard[self.currStep].has_key("displaytext"):
368                                 displaytext = self.wizard[self.currStep]["displaytext"]
369                                 print "set LCD text"
370                                 for x in self.lcdCallbacks:
371                                         x(displaytext)
372                                 
373                         self.runCode(self.wizard[self.currStep]["code"])
374                         
375                         if self.showList:
376                                 print "showing list,", self.currStep
377                                 for renderer in self.renderer:
378                                         rootrenderer = renderer
379                                         while renderer.source is not None:
380                                                 print "self.list:", self["list"]
381                                                 if renderer.source is self["list"]:
382                                                         print "setZPosition"
383                                                         rootrenderer.instance.setZPosition(1)
384                                                 renderer = renderer.source
385                                                 
386                                 #self["list"].instance.setZPosition(1)
387                                 self.list = []
388                                 if (self.wizard[self.currStep].has_key("dynamiclist")):
389                                         print "dynamic list, calling",  self.wizard[self.currStep]["dynamiclist"]
390                                         newlist = eval("self." + self.wizard[self.currStep]["dynamiclist"] + "()")
391                                         #self.wizard[self.currStep]["evaluatedlist"] = []
392                                         for entry in newlist:
393                                                 #self.wizard[self.currStep]["evaluatedlist"].append(entry)
394                                                 self.list.append(entry)
395                                         #del self.wizard[self.currStep]["dynamiclist"]
396                                 if (len(self.wizard[self.currStep]["list"]) > 0):
397                                         #self["list"].instance.setZPosition(2)
398                                         for x in self.wizard[self.currStep]["list"]:
399                                                 self.list.append((_(x[0]), x[1]))
400                                 self.wizard[self.currStep]["evaluatedlist"] = self.list
401                                 self["list"].list = self.list
402                                 self["list"].index = 0
403         
404                         if self.showConfig:
405                                 self["config"].instance.setZPosition(1)
406                                 if (self.wizard[self.currStep]["config"]["screen"] != None):
407                                         if self.wizard[self.currStep]["config"]["type"] == "standalone":
408                                                 print "Type is standalone"
409                                                 self.session.openWithCallback(self.ok, self.wizard[self.currStep]["config"]["screen"])
410                                         else:
411                                                 self["config"].instance.setZPosition(2)
412                                                 print "wizard screen", self.wizard[self.currStep]["config"]["screen"]
413                                                 if self.wizard[self.currStep]["config"]["args"] == None:
414                                                         self.configInstance = self.session.instantiateDialog(self.wizard[self.currStep]["config"]["screen"])
415                                                 else:
416                                                         self.configInstance = self.session.instantiateDialog(self.wizard[self.currStep]["config"]["screen"], eval(self.wizard[self.currStep]["config"]["args"]))
417                                                 self["config"].l.setList(self.configInstance["config"].list)
418                                                 self.configInstance["config"].destroy()
419                                                 self.configInstance["config"] = self["config"]
420                                 else:
421                                         self["config"].l.setList([])
422                 else: # condition false
423                                 self.currStep += 1
424                                 self.updateValues()
425                                 
426         def timeoutCounterFired(self):
427                 self.timeoutCounter -= 1
428                 print "timeoutCounter:", self.timeoutCounter
429                 if self.timeoutCounter == 0:
430                         if self.wizard[self.currStep]["timeoutaction"] == "selectnext":
431                                 print "selection next item"
432                                 self.down()
433                 self.updateText()
434
435 class WizardManager:
436         def __init__(self):
437                 self.wizards = []
438         
439         def registerWizard(self, wizard, precondition):
440                 self.wizards.append((wizard, precondition))
441         
442         def getWizards(self):
443                 list = []
444                 for x in self.wizards:
445                         if x[1] == 1: # precondition
446                                 list.append(x[0])
447                 return list
448
449 wizardManager = WizardManager()