2f76e3b10d016353d82eee7f371e375ec991a396
[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"].selectPrevious()
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                         self["list"].selectNext()
303                         if self.wizard[self.currStep].has_key("onselect"):
304                                 print "current:", self["list"].current
305                                 #self.selection = self.wizard[self.currStep]["evaluatedlist"][self["list"].l.getCurrentSelectionIndex()][1]
306                                 #exec("self." + self.wizard[self.currStep]["onselect"] + "()")
307                 print "down"
308                 
309         def selChanged(self):
310                 self.resetCounter()
311                 
312                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None):
313                                 self["config"].instance.moveSelection(self["config"].instance.moveUp)
314                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
315                         if self.wizard[self.currStep].has_key("onselect"):
316                                 self.selection = self["list"].current[1]
317                                 print "self.selection:", self.selection
318                                 exec("self." + self.wizard[self.currStep]["onselect"] + "()")
319                 
320         def resetCounter(self):
321                 self.timeoutCounter = self.wizard[self.currStep]["timeout"]
322                 
323         def runCode(self, code):
324                 if code != "":
325                         print "code", code
326                         exec(code)
327                         
328         def updateText(self, firstset = False):
329                 text = _(self.wizard[self.currStep]["text"])
330                 if text.find("[timeout]") != -1:
331                         text = text.replace("[timeout]", str(self.timeoutCounter))
332                         self["text"].setText(text)
333                 else:
334                         if firstset:
335                                 self["text"].setText(text)
336                 
337         def updateValues(self):
338                 print "Updating values in step " + str(self.currStep)
339                 self.timeoutTimer.stop()
340                 
341                 self.stepHistory.append(self.currStep)
342                 
343                 if self.configInstance is not None:
344                         del self.configInstance["config"]
345                         self.configInstance.doClose()
346                         self.configInstance = None
347                 
348                 self.condition = True
349                 exec (self.wizard[self.currStep]["condition"])
350                 if self.condition:
351                         print "wizard step:", self.wizard[self.currStep]
352                         
353                         if self.showSteps:
354                                 self["step"].setText(_("Step ") + str(self.currStep) + "/" + str(self.numSteps))
355                         if self.showStepSlider:
356                                 self["stepslider"].setValue(self.currStep)
357                 
358                         if self.wizard[self.currStep]["timeout"] is not None:
359                                 self.resetCounter() 
360                                 self.timeoutTimer.start(1000)
361                         
362                         print "wizard text", _(self.wizard[self.currStep]["text"])
363                         self.updateText(firstset = True)
364                         if self.wizard[self.currStep].has_key("displaytext"):
365                                 displaytext = self.wizard[self.currStep]["displaytext"]
366                                 print "set LCD text"
367                                 for x in self.lcdCallbacks:
368                                         x(displaytext)
369                                 
370                         self.runCode(self.wizard[self.currStep]["code"])
371                         
372                         if self.showList:
373                                 print "showing list,", self.currStep
374                                 for renderer in self.renderer:
375                                         rootrenderer = renderer
376                                         while renderer.source is not None:
377                                                 print "self.list:", self["list"]
378                                                 if renderer.source is self["list"]:
379                                                         print "setZPosition"
380                                                         rootrenderer.instance.setZPosition(1)
381                                                 renderer = renderer.source
382                                                 
383                                 #self["list"].instance.setZPosition(1)
384                                 self.list = []
385                                 if (self.wizard[self.currStep].has_key("dynamiclist")):
386                                         print "dynamic list, calling",  self.wizard[self.currStep]["dynamiclist"]
387                                         newlist = eval("self." + self.wizard[self.currStep]["dynamiclist"] + "()")
388                                         #self.wizard[self.currStep]["evaluatedlist"] = []
389                                         for entry in newlist:
390                                                 #self.wizard[self.currStep]["evaluatedlist"].append(entry)
391                                                 self.list.append(entry)
392                                         #del self.wizard[self.currStep]["dynamiclist"]
393                                 if (len(self.wizard[self.currStep]["list"]) > 0):
394                                         #self["list"].instance.setZPosition(2)
395                                         for x in self.wizard[self.currStep]["list"]:
396                                                 self.list.append((_(x[0]), x[1]))
397                                 self.wizard[self.currStep]["evaluatedlist"] = self.list
398                                 self["list"].list = self.list
399                                 self["list"].index = 0
400                         else:
401                                 self["list"].hide()
402         
403                         if self.showConfig:
404                                 self["config"].instance.setZPosition(1)
405                                 if (self.wizard[self.currStep]["config"]["screen"] != None):
406                                         if self.wizard[self.currStep]["config"]["type"] == "standalone":
407                                                 print "Type is standalone"
408                                                 self.session.openWithCallback(self.ok, self.wizard[self.currStep]["config"]["screen"])
409                                         else:
410                                                 self["config"].instance.setZPosition(2)
411                                                 print "wizard screen", self.wizard[self.currStep]["config"]["screen"]
412                                                 if self.wizard[self.currStep]["config"]["args"] == None:
413                                                         self.configInstance = self.session.instantiateDialog(self.wizard[self.currStep]["config"]["screen"])
414                                                 else:
415                                                         self.configInstance = self.session.instantiateDialog(self.wizard[self.currStep]["config"]["screen"], eval(self.wizard[self.currStep]["config"]["args"]))
416                                                 self["config"].l.setList(self.configInstance["config"].list)
417                                                 self.configInstance["config"].destroy()
418                                                 self.configInstance["config"] = self["config"]
419                                 else:
420                                         self["config"].l.setList([])
421                         else:
422                                 self["config"].hide()
423                 else: # condition false
424                                 self.currStep += 1
425                                 self.updateValues()
426                                 
427         def timeoutCounterFired(self):
428                 self.timeoutCounter -= 1
429                 print "timeoutCounter:", self.timeoutCounter
430                 if self.timeoutCounter == 0:
431                         if self.wizard[self.currStep]["timeoutaction"] == "selectnext":
432                                 print "selection next item"
433                                 self.down()
434                 self.updateText()
435
436 class WizardManager:
437         def __init__(self):
438                 self.wizards = []
439         
440         def registerWizard(self, wizard, precondition):
441                 self.wizards.append((wizard, precondition))
442         
443         def getWizards(self):
444                 list = []
445                 for x in self.wizards:
446                         if x[1] == 1: # precondition
447                                 list.append(x[0])
448                 return list
449
450 wizardManager = WizardManager()