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