use config callbacks from instantiated dialog in wizard screens
[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, KEY_LEFT, KEY_RIGHT, KEY_DELETE, KEY_BACKSPACE
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):
49         def createSummary(self):
50                         print "WizardCreateSummary"
51                         return WizardSummary
52
53         class parseWizard(ContentHandler):
54                 def __init__(self, wizard):
55                         self.isPointsElement, self.isReboundsElement = 0, 0
56                         self.wizard = wizard
57                         self.currContent = ""
58                         self.lastStep = 0       
59
60                 def startElement(self, name, attrs):
61                         #print "startElement", name
62                         self.currContent = name
63                         if (name == "step"):
64                                 self.lastStep += 1
65                                 if attrs.has_key('id'):
66                                         id = str(attrs.get('id'))
67                                 else:
68                                         id = ""
69                                 #print "id:", 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
83                                 if attrs.has_key('timeoutstep'):
84                                         timeoutstep = str(attrs.get('timeoutstep'))
85                                 else:
86                                         timeoutstep = ''
87                                 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}
88                         elif (name == "text"):
89                                 self.wizard[self.lastStep]["text"] = string.replace(str(attrs.get('value')), "\\n", "\n")
90                         elif (name == "displaytext"):
91                                 self.wizard[self.lastStep]["displaytext"] = string.replace(str(attrs.get('value')), "\\n", "\n")
92                         elif (name == "list"):
93                                 if (attrs.has_key('type')):
94                                         if attrs["type"] == "dynamic":
95                                                 self.wizard[self.lastStep]["dynamiclist"] = attrs.get("source")
96                                         #self.wizard[self.lastStep]["list"].append(("Hallo", "test"))
97                                 if (attrs.has_key("evaluation")):
98                                         #print "evaluation"
99                                         self.wizard[self.lastStep]["listevaluation"] = attrs.get("evaluation")
100                                 if (attrs.has_key("onselect")):
101                                         self.wizard[self.lastStep]["onselect"] = attrs.get("onselect")                  
102                         elif (name == "listentry"):
103                                 self.wizard[self.lastStep]["list"].append((str(attrs.get('caption')), str(attrs.get('step'))))
104                         elif (name == "config"):
105                                 type = str(attrs.get('type'))
106                                 self.wizard[self.lastStep]["config"]["type"] = type
107                                 if type == "ConfigList" or type == "standalone":
108                                         try:
109                                                 exec "from Screens." + str(attrs.get('module')) + " import *"
110                                         except:
111                                                 exec "from " + str(attrs.get('module')) + " import *"
112                                 
113                                         self.wizard[self.lastStep]["config"]["screen"] = eval(str(attrs.get('screen')))
114                                         if (attrs.has_key('args')):
115                                                 #print "has args"
116                                                 self.wizard[self.lastStep]["config"]["args"] = str(attrs.get('args'))
117                                 elif type == "dynamic":
118                                         self.wizard[self.lastStep]["config"]["source"] = str(attrs.get('source'))
119                                         if (attrs.has_key('evaluation')):
120                                                 self.wizard[self.lastStep]["config"]["evaluation"] = str(attrs.get('evaluation'))
121                         elif (name == "code"):
122                                 if attrs.has_key('pos') and str(attrs.get('pos')) == "after":
123                                         self.codeafter = True
124                                 else:
125                                         self.codeafter = False
126                         elif (name == "condition"):
127                                 pass
128                         
129                 def endElement(self, name):
130                         self.currContent = ""
131                         if name == 'code':
132                                 if self.codeafter:
133                                         self.wizard[self.lastStep]["codeafter"] = self.wizard[self.lastStep]["codeafter"].strip()
134                                 else:
135                                         self.wizard[self.lastStep]["code"] = self.wizard[self.lastStep]["code"].strip()
136                         elif name == 'condition':
137                                 self.wizard[self.lastStep]["condition"] = self.wizard[self.lastStep]["condition"].strip()
138                         elif name == 'step':
139                                 #print "Step number", self.lastStep, ":", self.wizard[self.lastStep]
140                                 pass
141                                                                 
142                 def characters(self, ch):
143                         if self.currContent == "code":
144                                 if self.codeafter:
145                                         self.wizard[self.lastStep]["codeafter"] = self.wizard[self.lastStep]["codeafter"] + ch
146                                 else:
147                                         self.wizard[self.lastStep]["code"] = self.wizard[self.lastStep]["code"] + ch
148                         elif self.currContent == "condition":
149                                  self.wizard[self.lastStep]["condition"] = self.wizard[self.lastStep]["condition"] + ch
150
151         def __init__(self, session, showSteps = True, showStepSlider = True, showList = True, showConfig = True):
152                 Screen.__init__(self, session)
153
154                 self.stepHistory = []
155
156                 self.wizard = {}
157                 parser = make_parser()
158                 if not isinstance(self.xmlfile, list):
159                         self.xmlfile = [self.xmlfile]
160                 print "Reading ", self.xmlfile
161                 wizardHandler = self.parseWizard(self.wizard)
162                 parser.setContentHandler(wizardHandler)
163                 for xmlfile in self.xmlfile:
164                         if xmlfile[0] != '/':
165                                 parser.parse('/usr/share/enigma2/' + xmlfile)
166                         else:
167                                 parser.parse(xmlfile)
168
169                 self.showSteps = showSteps
170                 self.showStepSlider = showStepSlider
171                 self.showList = showList
172                 self.showConfig = showConfig
173
174                 self.numSteps = len(self.wizard)
175                 self.currStep = self.getStepWithID("start") + 1
176                 
177                 self.timeoutTimer = eTimer()
178                 self.timeoutTimer.callback.append(self.timeoutCounterFired)
179
180                 self["text"] = Label()
181
182                 if showConfig:
183                         self["config"] = ConfigList([], session = session)
184
185                 if self.showSteps:
186                         self["step"] = Label()
187                 
188                 if self.showStepSlider:
189                         self["stepslider"] = Slider(1, self.numSteps)
190                 
191                 if self.showList:
192                         self.list = []
193                         self["list"] = List(self.list, enableWrapAround = True)
194                         self["list"].onSelectionChanged.append(self.selChanged)
195                         #self["list"] = MenuList(self.list, enableWrapAround = True)
196
197                 self.onShown.append(self.updateValues)
198
199                 self.configInstance = None
200                 
201                 self.lcdCallbacks = []
202                 
203                 self.disableKeys = False
204                 
205                 self["actions"] = NumberActionMap(["WizardActions", "NumberActions", "ColorActions", "SetupActions"],
206                 {
207                         "ok": self.ok,
208                         "back": self.back,
209                         "left": self.left,
210                         "right": self.right,
211                         "up": self.up,
212                         "down": self.down,
213                         "red": self.red,
214                         "green": self.green,
215                         "yellow": self.yellow,
216                         "blue":self.blue,
217                         "deleteBackward": self.deleteBackward,
218                         "deleteForward": self.deleteForward,
219                         "1": self.keyNumberGlobal,
220                         "2": self.keyNumberGlobal,
221                         "3": self.keyNumberGlobal,
222                         "4": self.keyNumberGlobal,
223                         "5": self.keyNumberGlobal,
224                         "6": self.keyNumberGlobal,
225                         "7": self.keyNumberGlobal,
226                         "8": self.keyNumberGlobal,
227                         "9": self.keyNumberGlobal,
228                         "0": self.keyNumberGlobal
229                 }, -1)
230                 
231         def red(self):
232                 print "red"
233                 pass
234
235         def green(self):
236                 print "green"
237                 pass
238         
239         def yellow(self):
240                 print "yellow"
241                 pass
242         
243         def blue(self):
244                 print "blue"
245                 pass
246         
247         def deleteForward(self):
248                 self.resetCounter()
249                 if (self.wizard[self.currStep]["config"]["screen"] != None):
250                         self.configInstance.keyDelete()
251                 elif (self.wizard[self.currStep]["config"]["type"] == "dynamic"):
252                         self["config"].handleKey(KEY_DELETE)
253                 print "deleteForward"
254
255         def deleteBackward(self):
256                 self.resetCounter()
257                 if (self.wizard[self.currStep]["config"]["screen"] != None):
258                         self.configInstance.keyBackspace()
259                 elif (self.wizard[self.currStep]["config"]["type"] == "dynamic"):
260                         self["config"].handleKey(KEY_BACKSPACE)
261                 print "deleteBackward"
262         
263         def setLCDTextCallback(self, callback):
264                 self.lcdCallbacks.append(callback)
265
266         def back(self):
267                 if self.disableKeys:
268                         return
269                 print "getting back..."
270                 print "stepHistory:", self.stepHistory
271                 if len(self.stepHistory) > 1:
272                         self.currStep = self.stepHistory[-2]
273                         self.stepHistory = self.stepHistory[:-2]
274                 if self.currStep < 1:
275                         self.currStep = 1
276                 print "currStep:", self.currStep
277                 print "new stepHistory:", self.stepHistory
278                 self.updateValues()
279                 print "after updateValues stepHistory:", self.stepHistory
280                 
281         def markDone(self):
282                 pass
283         
284         def getStepWithID(self, id):
285                 print "getStepWithID:", id
286                 count = 0
287                 for x in self.wizard.keys():
288                         if self.wizard[x]["id"] == id:
289                                 print "result:", count
290                                 return count
291                         count += 1
292                 print "result: nothing"
293                 return 0
294
295         def finished(self, gotoStep = None, *args, **kwargs):
296                 print "finished"
297                 currStep = self.currStep
298
299                 if self.updateValues not in self.onShown:
300                         self.onShown.append(self.updateValues)
301                         
302                 if self.showConfig:
303                         if self.wizard[currStep]["config"]["type"] == "dynamic":
304                                 eval("self." + self.wizard[currStep]["config"]["evaluation"])()
305
306                 if self.showList:
307                         if (len(self.wizard[currStep]["evaluatedlist"]) > 0):
308                                 print "current:", self["list"].current
309                                 nextStep = self["list"].current[1]
310                                 if (self.wizard[currStep].has_key("listevaluation")):
311                                         exec("self." + self.wizard[self.currStep]["listevaluation"] + "('" + nextStep + "')")
312                                 else:
313                                         self.currStep = self.getStepWithID(nextStep)
314
315                 if ((currStep == self.numSteps and self.wizard[currStep]["nextstep"] is None) or self.wizard[currStep]["id"] == "end"): # wizard finished
316                         print "wizard finished"
317                         self.markDone()
318                         self.close()
319                 else:
320                         self.runCode(self.wizard[currStep]["codeafter"])
321                         if self.wizard[currStep]["nextstep"] is not None:
322                                 self.currStep = self.getStepWithID(self.wizard[currStep]["nextstep"])
323                         if gotoStep is not None:
324                                 self.currStep = self.getStepWithID(gotoStep)
325                         self.currStep += 1
326                         self.updateValues()
327
328                 print "Now: " + str(self.currStep)
329
330
331         def ok(self):
332                 print "OK"
333                 if self.disableKeys:
334                         return
335                 currStep = self.currStep
336                 
337                 if self.showConfig:
338                         if (self.wizard[currStep]["config"]["screen"] != None):
339                                 # TODO: don't die, if no run() is available
340                                 # there was a try/except here, but i can't see a reason
341                                 # for this. If there is one, please do a more specific check
342                                 # and/or a comment in which situation there is no run()
343                                 if callable(getattr(self.configInstance, "runAsync", None)):
344                                         self.onShown.remove(self.updateValues)
345                                         self.configInstance.runAsync(self.finished)
346                                         return
347                                 else:
348                                         self.configInstance.run()
349                 self.finished()
350
351         def keyNumberGlobal(self, number):
352                 if (self.wizard[self.currStep]["config"]["screen"] != None):
353                         self.configInstance.keyNumberGlobal(number)
354                 
355         def left(self):
356                 self.resetCounter()
357                 if (self.wizard[self.currStep]["config"]["screen"] != None):
358                         self.configInstance.keyLeft()
359                 elif (self.wizard[self.currStep]["config"]["type"] == "dynamic"):
360                         self["config"].handleKey(KEY_LEFT)
361                 print "left"
362         
363         def right(self):
364                 self.resetCounter()
365                 if (self.wizard[self.currStep]["config"]["screen"] != None):
366                         self.configInstance.keyRight()
367                 elif (self.wizard[self.currStep]["config"]["type"] == "dynamic"):
368                         self["config"].handleKey(KEY_RIGHT)     
369                 print "right"
370
371         def up(self):
372                 self.resetCounter()
373                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None  or self.wizard[self.currStep]["config"]["type"] == "dynamic"):
374                                 self["config"].instance.moveSelection(self["config"].instance.moveUp)
375                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
376                         self["list"].selectPrevious()
377                         if self.wizard[self.currStep].has_key("onselect"):
378                                 print "current:", self["list"].current
379                                 self.selection = self["list"].current[-1]
380                                 #self.selection = self.wizard[self.currStep]["evaluatedlist"][self["list"].l.getCurrentSelectionIndex()][1]
381                                 exec("self." + self.wizard[self.currStep]["onselect"] + "()")
382                 print "up"
383                 
384         def down(self):
385                 self.resetCounter()
386                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None  or self.wizard[self.currStep]["config"]["type"] == "dynamic"):
387                         self["config"].instance.moveSelection(self["config"].instance.moveDown)
388                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
389                         #self["list"].instance.moveSelection(self["list"].instance.moveDown)
390                         self["list"].selectNext()
391                         if self.wizard[self.currStep].has_key("onselect"):
392                                 print "current:", self["list"].current
393                                 #self.selection = self.wizard[self.currStep]["evaluatedlist"][self["list"].l.getCurrentSelectionIndex()][1]
394                                 #exec("self." + self.wizard[self.currStep]["onselect"] + "()")
395                                 self.selection = self["list"].current[-1]
396                                 #self.selection = self.wizard[self.currStep]["evaluatedlist"][self["list"].l.getCurrentSelectionIndex()][1]
397                                 exec("self." + self.wizard[self.currStep]["onselect"] + "()")
398                 print "down"
399                 
400         def selChanged(self):
401                 self.resetCounter()
402                 
403                 if (self.showConfig and self.wizard[self.currStep]["config"]["screen"] != None):
404                         self["config"].instance.moveSelection(self["config"].instance.moveUp)
405                 elif (self.showList and len(self.wizard[self.currStep]["evaluatedlist"]) > 0):
406                         if self.wizard[self.currStep].has_key("onselect"):
407                                 self.selection = self["list"].current[-1]
408                                 print "self.selection:", self.selection
409                                 exec("self." + self.wizard[self.currStep]["onselect"] + "()")
410                 
411         def resetCounter(self):
412                 self.timeoutCounter = self.wizard[self.currStep]["timeout"]
413                 
414         def runCode(self, code):
415                 if code != "":
416                         print "code", code
417                         exec(code)
418                         
419         def getTranslation(self, text):
420                 return _(text)
421                         
422         def updateText(self, firstset = False):
423                 text = self.getTranslation(self.wizard[self.currStep]["text"])
424                 if text.find("[timeout]") != -1:
425                         text = text.replace("[timeout]", str(self.timeoutCounter))
426                         self["text"].setText(text)
427                 else:
428                         if firstset:
429                                 self["text"].setText(text)
430                 
431         def updateValues(self):
432                 print "Updating values in step " + str(self.currStep)
433                 # calling a step which doesn't exist can only happen if the condition in the last step is not fulfilled
434                 # if a non-existing step is called, end the wizard 
435                 if self.currStep > len(self.wizard):
436                         self.markDone()
437                         self.close()
438                         return
439
440                 self.timeoutTimer.stop()
441                 
442                 if self.configInstance is not None:
443                         # remove callbacks
444                         self.configInstance["config"].onSelectionChanged = []
445                         del self.configInstance["config"]
446                         self.configInstance.doClose()
447                         self.configInstance = None
448                 
449                 self.condition = True
450                 exec (self.wizard[self.currStep]["condition"])
451                 if self.condition:
452                         if len(self.stepHistory) == 0 or self.stepHistory[-1] != self.currStep:
453                                 self.stepHistory.append(self.currStep)
454                         print "wizard step:", self.wizard[self.currStep]
455                         
456                         if self.showSteps:
457                                 self["step"].setText(self.getTranslation("Step ") + str(self.currStep) + "/" + str(self.numSteps))
458                         if self.showStepSlider:
459                                 self["stepslider"].setValue(self.currStep)
460                 
461                         if self.wizard[self.currStep]["timeout"] is not None:
462                                 self.resetCounter() 
463                                 self.timeoutTimer.start(1000)
464                         
465                         print "wizard text", self.getTranslation(self.wizard[self.currStep]["text"])
466                         self.updateText(firstset = True)
467                         if self.wizard[self.currStep].has_key("displaytext"):
468                                 displaytext = self.wizard[self.currStep]["displaytext"]
469                                 print "set LCD text"
470                                 for x in self.lcdCallbacks:
471                                         x(displaytext)
472                                 
473                         self.runCode(self.wizard[self.currStep]["code"])
474                         
475                         if self.showList:
476                                 print "showing list,", self.currStep
477                                 for renderer in self.renderer:
478                                         rootrenderer = renderer
479                                         while renderer.source is not None:
480                                                 print "self.list:", self["list"]
481                                                 if renderer.source is self["list"]:
482                                                         print "setZPosition"
483                                                         rootrenderer.instance.setZPosition(1)
484                                                 renderer = renderer.source
485                                                 
486                                 #self["list"].instance.setZPosition(1)
487                                 self.list = []
488                                 if (self.wizard[self.currStep].has_key("dynamiclist")):
489                                         print "dynamic list, calling",  self.wizard[self.currStep]["dynamiclist"]
490                                         newlist = eval("self." + self.wizard[self.currStep]["dynamiclist"] + "()")
491                                         #self.wizard[self.currStep]["evaluatedlist"] = []
492                                         for entry in newlist:
493                                                 #self.wizard[self.currStep]["evaluatedlist"].append(entry)
494                                                 self.list.append(entry)
495                                         #del self.wizard[self.currStep]["dynamiclist"]
496                                 if (len(self.wizard[self.currStep]["list"]) > 0):
497                                         #self["list"].instance.setZPosition(2)
498                                         for x in self.wizard[self.currStep]["list"]:
499                                                 self.list.append((self.getTranslation(x[0]), x[1]))
500                                 self.wizard[self.currStep]["evaluatedlist"] = self.list
501                                 self["list"].list = self.list
502                                 self["list"].index = 0
503                         else:
504                                 self["list"].hide()
505         
506                         if self.showConfig:
507                                 print "showing config"
508                                 self["config"].instance.setZPosition(1)
509                                 if self.wizard[self.currStep]["config"]["type"] == "dynamic":
510                                                 print "config type is dynamic"
511                                                 self["config"].instance.setZPosition(2)
512                                                 self["config"].l.setList(eval("self." + self.wizard[self.currStep]["config"]["source"])())
513                                 elif (self.wizard[self.currStep]["config"]["screen"] != None):
514                                         if self.wizard[self.currStep]["config"]["type"] == "standalone":
515                                                 print "Type is standalone"
516                                                 self.session.openWithCallback(self.ok, self.wizard[self.currStep]["config"]["screen"])
517                                         else:
518                                                 self["config"].instance.setZPosition(2)
519                                                 print "wizard screen", self.wizard[self.currStep]["config"]["screen"]
520                                                 if self.wizard[self.currStep]["config"]["args"] == None:
521                                                         self.configInstance = self.session.instantiateDialog(self.wizard[self.currStep]["config"]["screen"])
522                                                 else:
523                                                         self.configInstance = self.session.instantiateDialog(self.wizard[self.currStep]["config"]["screen"], eval(self.wizard[self.currStep]["config"]["args"]))
524                                                 self["config"].l.setList(self.configInstance["config"].list)
525                                                 callbacks = self.configInstance["config"].onSelectionChanged
526                                                 self.configInstance["config"].destroy()
527                                                 print "clearConfigList", self.configInstance["config"], self["config"] 
528                                                 self.configInstance["config"] = self["config"]
529                                                 self.configInstance["config"].onSelectionChanged = callbacks
530                                                 print "clearConfigList", self.configInstance["config"], self["config"]
531                                 else:
532                                         self["config"].l.setList([])
533                         else:
534                                 if self.has_key("config"):
535                                         self["config"].hide()
536                 else: # condition false
537                                 self.currStep += 1
538                                 self.updateValues()
539                                 
540         def timeoutCounterFired(self):
541                 self.timeoutCounter -= 1
542                 print "timeoutCounter:", self.timeoutCounter
543                 if self.timeoutCounter == 0:
544                         if self.wizard[self.currStep]["timeoutaction"] == "selectnext":
545                                 print "selection next item"
546                                 self.down()
547                         else:
548                                 if self.wizard[self.currStep]["timeoutaction"] == "changestep":
549                                         self.finished(gotoStep = self.wizard[self.currStep]["timeoutstep"])
550                 self.updateText()
551
552 class WizardManager:
553         def __init__(self):
554                 self.wizards = []
555         
556         def registerWizard(self, wizard, precondition, priority = 0):
557                 self.wizards.append((wizard, precondition, priority))
558         
559         def getWizards(self):
560                 list = []
561                 for x in self.wizards:
562                         if x[1] == 1: # precondition
563                                 list.append((x[2], x[0]))
564                 return list
565
566 wizardManager = WizardManager()