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