chiark / gitweb /
Move SF into its own directory, to seperate SF and Cura. Rename newui to gui.
[cura.git] / Cura / gui / configWizard.py
1 from __future__ import absolute_import\r
2 import __init__\r
3 \r
4 import wx, os, platform, types, webbrowser, threading, time, re\r
5 import wx.wizard\r
6 \r
7 from gui import machineCom\r
8 from gui import profile\r
9 \r
10 class InfoPage(wx.wizard.WizardPageSimple):\r
11         def __init__(self, parent, title):\r
12                 wx.wizard.WizardPageSimple.__init__(self, parent)\r
13 \r
14                 sizer = wx.BoxSizer(wx.VERTICAL)\r
15                 self.sizer = sizer\r
16                 self.SetSizer(sizer)\r
17 \r
18                 title = wx.StaticText(self, -1, title)\r
19                 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))\r
20                 sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)\r
21                 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)\r
22         \r
23         def AddText(self,info):\r
24                 text = wx.StaticText(self, -1, info)\r
25                 self.GetSizer().Add(text, 0, wx.LEFT|wx.RIGHT, 5)\r
26                 return text\r
27         \r
28         def AddSeperator(self):\r
29                 self.GetSizer().Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)\r
30         \r
31         def AddHiddenSeperator(self):\r
32                 self.AddText('')\r
33         \r
34         def AddRadioButton(self, label, style = 0):\r
35                 radio = wx.RadioButton(self, -1, label, style=style)\r
36                 self.GetSizer().Add(radio, 0, wx.EXPAND|wx.ALL, 5)\r
37                 return radio\r
38         \r
39         def AddButton(self, label):\r
40                 button = wx.Button(self, -1, label)\r
41                 self.GetSizer().Add(button, 0, wx.LEFT, 5)\r
42                 return button\r
43         \r
44         def AddDualButton(self, label1, label2):\r
45                 p = wx.Panel(self)\r
46                 p.SetSizer(wx.BoxSizer(wx.HORIZONTAL))\r
47                 button1 = wx.Button(p, -1, label1)\r
48                 p.GetSizer().Add(button1, 0, wx.RIGHT, 8)\r
49                 button2 = wx.Button(p, -1, label2)\r
50                 p.GetSizer().Add(button2, 0)\r
51                 self.GetSizer().Add(p, 0, wx.LEFT, 5)\r
52                 return button1, button2\r
53         \r
54         def AllowNext(self):\r
55                 return True\r
56         \r
57         def StoreData(self):\r
58                 pass\r
59 \r
60 class FirstInfoPage(InfoPage):\r
61         def __init__(self, parent):\r
62                 super(FirstInfoPage, self).__init__(parent, "First time run wizard")\r
63                 self.AddText('Welcome, and thanks for trying Cura!')\r
64                 self.AddSeperator()\r
65                 self.AddText('This wizard will help you with the following steps:')\r
66                 self.AddText('* Configure Cura for your machine')\r
67                 self.AddText('* Upgrade your firmware')\r
68                 self.AddText('* Calibrate your machine')\r
69                 #self.AddText('* Do your first print')\r
70 \r
71 class RepRapInfoPage(InfoPage):\r
72         def __init__(self, parent):\r
73                 super(RepRapInfoPage, self).__init__(parent, "RepRap information")\r
74                 self.AddText('Sorry, but this wizard will not help you with\nconfiguring and calibrating your RepRap.')\r
75                 self.AddSeperator()\r
76                 self.AddText('You will have to manually install Marlin or Sprinter firmware\nand configure Cura.')\r
77 \r
78 class MachineSelectPage(InfoPage):\r
79         def __init__(self, parent):\r
80                 super(MachineSelectPage, self).__init__(parent, "Select your machine")\r
81                 self.AddText('What kind of machine do you have:')\r
82 \r
83                 self.UltimakerRadio = self.AddRadioButton("Ultimaker", style=wx.RB_GROUP)\r
84                 self.UltimakerRadio.SetValue(True)\r
85                 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)\r
86                 self.OtherRadio = self.AddRadioButton("Other (Ex: RepRap)")\r
87                 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)\r
88                 \r
89         def OnUltimakerSelect(self, e):\r
90                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)\r
91                 \r
92         def OnOtherSelect(self, e):\r
93                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)\r
94         \r
95         def StoreData(self):\r
96                 if self.UltimakerRadio.GetValue():\r
97                         profile.putPreference('machine_width', '205')\r
98                         profile.putPreference('machine_depth', '205')\r
99                         profile.putPreference('machine_height', '200')\r
100                         profile.putProfileSetting('nozzle_size', '0.4')\r
101                         profile.putProfileSetting('machine_center_x', '100')\r
102                         profile.putProfileSetting('machine_center_y', '100')\r
103                 else:\r
104                         profile.putPreference('machine_width', '80')\r
105                         profile.putPreference('machine_depth', '80')\r
106                         profile.putPreference('machine_height', '60')\r
107                         profile.putProfileSetting('nozzle_size', '0.5')\r
108                         profile.putProfileSetting('machine_center_x', '40')\r
109                         profile.putProfileSetting('machine_center_y', '40')\r
110                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)\r
111 \r
112 class FirmwareUpgradePage(InfoPage):\r
113         def __init__(self, parent):\r
114                 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")\r
115                 self.AddText('Firmware is the piece of software running directly on your 3D printer.\nThis firmware controls the step motors, regulates the temperature\nand ultimately makes your printer work.')\r
116                 self.AddHiddenSeperator()\r
117                 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')\r
118                 self.AddHiddenSeperator()\r
119                 self.AddText('Cura requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now.')\r
120                 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')\r
121                 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)\r
122                 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
123                 self.AddHiddenSeperator()\r
124                 self.AddText('Do not upgrade to this firmware if:')\r
125                 self.AddText('* You have an older machine based on ATMega1280')\r
126                 self.AddText('* Using an LCD panel')\r
127                 self.AddText('* Have other changes in the firmware')\r
128                 button = self.AddButton('Goto this page for a custom firmware')\r
129                 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)\r
130         \r
131         def AllowNext(self):\r
132                 return False\r
133         \r
134         def OnUpgradeClick(self, e):\r
135                 if machineCom.InstallFirmware(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../firmware/default.hex")):\r
136                         self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
137                 \r
138         def OnSkipClick(self, e):\r
139                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
140         \r
141         def OnUrlClick(self, e):\r
142                 webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')\r
143 \r
144 class UltimakerCheckupPage(InfoPage):\r
145         def __init__(self, parent):\r
146                 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")\r
147                 self.AddText('It is a good idea to do a few sanity checks now on your Ultimaker.\nYou can skip these if you know your machine is functional.')\r
148                 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')\r
149                 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)\r
150                 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
151                 self.AddSeperator();\r
152                 self.checkPanel = None\r
153         \r
154         def AllowNext(self):\r
155                 return False\r
156         \r
157         def OnSkipClick(self, e):\r
158                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
159         \r
160         def OnCheckClick(self, e):\r
161                 if self.checkPanel != None:\r
162                         self.checkPanel.Destroy()\r
163                 self.checkPanel = wx.Panel(self)\r
164                 self.checkPanel.SetSizer(wx.BoxSizer(wx.VERTICAL))\r
165                 self.GetSizer().Add(self.checkPanel, 0, wx.LEFT|wx.RIGHT, 5)\r
166                 threading.Thread(target=self.OnRun).start()\r
167 \r
168         def AddProgressText(self, info):\r
169                 text = wx.StaticText(self.checkPanel, -1, info)\r
170                 self.checkPanel.GetSizer().Add(text, 0)\r
171                 self.checkPanel.Layout()\r
172                 self.Layout()\r
173         \r
174         def OnRun(self):\r
175                 wx.CallAfter(self.AddProgressText, "Connecting to machine...")\r
176                 self.comm = machineCom.MachineCom()\r
177 \r
178                 wx.CallAfter(self.AddProgressText, "Checking start message...")\r
179                 if self.DoCommCommandWithTimeout(None, 'start') == False:\r
180                         wx.CallAfter(self.AddProgressText, "Error: Missing start message.")\r
181                         self.comm.close()\r
182                         return\r
183                         \r
184                 wx.CallAfter(self.AddProgressText, "Disabling step motors...")\r
185                 if self.DoCommCommandWithTimeout('M84') == False:\r
186                         wx.CallAfter(self.AddProgressText, "Error: Missing reply to Deactivate steppers (M84).")\r
187                         wx.CallAfter(self.AddProgressText, "Possible cause: Temperature MIN/MAX.\nCheck temperature sensor connections.")\r
188                         self.comm.close()\r
189                         return\r
190 \r
191                 if self.DoCommCommandWithTimeout("M104 S0") == False:\r
192                         wx.CallAfter(self.AddProgressText, "Failed to set temperature")\r
193                         self.comm.close()\r
194                         return\r
195 \r
196                 wx.MessageBox('Please move the printer head to the center of the machine\nalso move the platform so it is not at the highest or lowest position,\nand make sure the machine is powered on.', 'Machine check', wx.OK | wx.ICON_INFORMATION)\r
197                 \r
198                 idleTemp = self.readTemp()\r
199                 if idleTemp > 40:\r
200                         wx.CallAfter(self.AddProgressText, "Waiting for head to cool down before temperature test...")\r
201                         while idleTemp > 40:\r
202                                 idleTemp = self.readTemp()\r
203                                 time.sleep(1)\r
204                 \r
205                 wx.CallAfter(self.AddProgressText, "Checking heater and temperature sensor...")\r
206                 wx.CallAfter(self.AddProgressText, "(This takes about 30 seconds)")\r
207                 if self.DoCommCommandWithTimeout("M104 S100") == False:\r
208                         wx.CallAfter(self.AddProgressText, "Failed to set temperature")\r
209                         self.comm.close()\r
210                         return\r
211                 \r
212                 time.sleep(25)\r
213                 tempInc = self.readTemp() - idleTemp\r
214                 \r
215                 if self.DoCommCommandWithTimeout("M104 S0") == False:\r
216                         wx.CallAfter(self.AddProgressText, "Failed to set temperature")\r
217                         self.comm.close()\r
218                         return\r
219                 \r
220                 if tempInc < 15:\r
221                         wx.CallAfter(self.AddProgressText, "Your temperature sensor or heater is not working!")\r
222                         self.comm.close()\r
223                         return\r
224                 wx.CallAfter(self.AddProgressText, "Heater and temperature sensor working\nWarning: head might still be hot!")\r
225 \r
226                 wx.CallAfter(self.AddProgressText, "Checking endstops")\r
227                 if self.DoCommCommandWithTimeout('M119', 'x_min') != "x_min:L x_max:L y_min:L y_max:L z_min:L z_max:L":\r
228                         wx.CallAfter(self.AddProgressText, "Error: There is a problem in your endstops!\nOne of them seems to be pressed while it shouldn't\ncheck the cable connections and the switches themselfs.")\r
229                         self.comm.close()\r
230                         return\r
231                 wx.CallAfter(self.AddProgressText, "Please press the X end switch in the front left corner.")\r
232                 if not self.DoCommCommandAndWaitForReply('M119', 'x_min', "x_min:H x_max:L y_min:L y_max:L z_min:L z_max:L"):\r
233                         wx.CallAfter(self.AddProgressText, "Failed to check the x_min endstop!")\r
234                         self.comm.close()\r
235                         return\r
236                 wx.CallAfter(self.AddProgressText, "Please press the X end switch in the front right corner.")\r
237                 if not self.DoCommCommandAndWaitForReply('M119', 'x_min', "x_min:L x_max:H y_min:L y_max:L z_min:L z_max:L"):\r
238                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
239                         self.comm.close()\r
240                         return\r
241                 wx.CallAfter(self.AddProgressText, "Please press the Y end switch in the front left corner.")\r
242                 if not self.DoCommCommandAndWaitForReply('M119', 'x_min', "x_min:L x_max:L y_min:H y_max:L z_min:L z_max:L"):\r
243                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
244                         self.comm.close()\r
245                         return\r
246                 wx.CallAfter(self.AddProgressText, "Please press the Y end switch in the back left corner.")\r
247                 if not self.DoCommCommandAndWaitForReply('M119', 'x_min', "x_min:L x_max:L y_min:L y_max:H z_min:L z_max:L"):\r
248                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
249                         self.comm.close()\r
250                         return\r
251                 wx.CallAfter(self.AddProgressText, "Please press the Z end switch in the top.")\r
252                 if not self.DoCommCommandAndWaitForReply('M119', 'x_min', "x_min:L x_max:L y_min:L y_max:L z_min:H z_max:L"):\r
253                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
254                         self.comm.close()\r
255                         return\r
256                 wx.CallAfter(self.AddProgressText, "Please press the Z end switch in the bottom.")\r
257                 if not self.DoCommCommandAndWaitForReply('M119', 'x_min', "x_min:L x_max:L y_min:L y_max:L z_min:L z_max:H"):\r
258                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
259                         self.comm.close()\r
260                         return\r
261                 wx.CallAfter(self.AddProgressText, "End stops are working.")\r
262 \r
263                 wx.CallAfter(self.AddProgressText, "Done!")\r
264                 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)\r
265                 self.comm.close()\r
266                 \r
267         def readTemp(self):\r
268                 line = self.DoCommCommandWithTimeout("M105", "ok T:")\r
269                 if line == False:\r
270                         return -1\r
271                 return int(re.search('T:([0-9]*)', line).group(1))\r
272         \r
273         def DoCommCommandAndWaitForReply(self, cmd, replyStart, reply):\r
274                 while True:\r
275                         ret = self.DoCommCommandWithTimeout(cmd, replyStart)\r
276                         if ret == reply:\r
277                                 return True\r
278                         if ret == False:\r
279                                 return False\r
280                         time.sleep(1)\r
281         \r
282         def DoCommCommandWithTimeout(self, cmd = None, replyStart = 'ok'):\r
283                 if cmd != None:\r
284                         self.comm.sendCommand(cmd)\r
285                 t = threading.Timer(5, self.OnSerialTimeout)\r
286                 t.start()\r
287                 while True:\r
288                         line = self.comm.readline()\r
289                         if line == '':\r
290                                 self.comm.close()\r
291                                 return False\r
292                         if line.startswith(replyStart):\r
293                                 break\r
294                 t.cancel()\r
295                 return line.rstrip()\r
296         \r
297         def OnSerialTimeout(self):\r
298                 self.comm.close()\r
299 \r
300 class UltimakerCalibrationPage(InfoPage):\r
301         def __init__(self, parent):\r
302                 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")\r
303                 \r
304                 self.AddText("Your Ultimaker requires some calibration.");\r
305                 self.AddText("This calibration is needed for a proper extrusion amount.");\r
306                 self.AddSeperator()\r
307                 self.AddText("The following values are needed:");\r
308                 self.AddText("* Diameter of filament");\r
309                 self.AddText("* Number of steps per mm of filament extrusion");\r
310                 self.AddSeperator()\r
311                 self.AddText("The better you have calibrated these values, the better your prints\nwill become.");\r
312                 self.AddSeperator()\r
313                 self.AddText("First we need the diameter of your filament:");\r
314                 self.filamentDiameter = wx.TextCtrl(self, -1, profile.getProfileSetting('filament_diameter'))\r
315                 self.GetSizer().Add(self.filamentDiameter, 0, wx.LEFT, 5)\r
316                 self.AddText("If you do not own digital Calipers that can measure\nat least 2 digits then use 2.89mm.\nWhich is the average diameter of most filament.");\r
317                 self.AddText("Note: This value can be changed later at any time.");\r
318 \r
319         def StoreData(self):\r
320                 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())\r
321 \r
322 class UltimakerCalibrateStepsPerEPage(InfoPage):\r
323         def __init__(self, parent):\r
324                 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")\r
325                 \r
326                 self.AddText("Calibrating the Steps Per E requires some manual actions.")\r
327                 self.AddText("First remove any filament from your machine.")\r
328                 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")\r
329                 self.AddText("We'll push the filament 100mm")\r
330                 self.extrudeButton = self.AddButton("Extrude 100mm filament")\r
331                 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")\r
332                 p = wx.Panel(self)\r
333                 p.SetSizer(wx.BoxSizer(wx.HORIZONTAL))\r
334                 self.lengthInput = wx.TextCtrl(p, -1, '100')\r
335                 p.GetSizer().Add(self.lengthInput, 0, wx.RIGHT, 8)\r
336                 self.saveLengthButton = wx.Button(p, -1, 'Save')\r
337                 p.GetSizer().Add(self.saveLengthButton, 0)\r
338                 self.GetSizer().Add(p, 0, wx.LEFT, 5)\r
339                 self.AddText("This results in the following steps per E:")\r
340                 self.stepsPerEInput = wx.TextCtrl(self, -1, profile.getPreference('steps_per_e'))\r
341                 self.GetSizer().Add(self.stepsPerEInput, 0, wx.LEFT, 5)\r
342                 self.AddText("You can repeat these steps to get better calibration.")\r
343                 self.AddSeperator()\r
344                 self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")\r
345                 self.heatButton = self.AddButton("Heatup for filament removal")\r
346                 \r
347                 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)\r
348                 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)\r
349                 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)\r
350         \r
351         def OnSaveLengthClick(self, e):\r
352                 currentEValue = float(self.stepsPerEInput.GetValue())\r
353                 realExtrudeLength = float(self.lengthInput.GetValue())\r
354                 newEValue = currentEValue * 100 / realExtrudeLength\r
355                 self.stepsPerEInput.SetValue(str(newEValue))\r
356                 self.lengthInput.SetValue("100")\r
357         \r
358         def OnExtrudeClick(self, e):\r
359                 threading.Thread(target=self.OnExtrudeRun).start()\r
360 \r
361         def OnExtrudeRun(self):\r
362                 self.heatButton.Enable(False)\r
363                 self.extrudeButton.Enable(False)\r
364                 currentEValue = float(self.stepsPerEInput.GetValue())\r
365                 self.comm = machineCom.MachineCom()\r
366                 while True:\r
367                         line = self.comm.readline()\r
368                         if line == '':\r
369                                 return\r
370                         if line.startswith('start'):\r
371                                 break\r
372                 self.sendGCommand('M302') #Disable cold extrusion protection\r
373                 self.sendGCommand("M92 E%f" % (currentEValue));\r
374                 self.sendGCommand("G92 E0");\r
375                 self.sendGCommand("G1 E100 F600");\r
376                 time.sleep(15)\r
377                 self.comm.close()\r
378                 self.extrudeButton.Enable()\r
379                 self.heatButton.Enable()\r
380 \r
381         def OnHeatClick(self, e):\r
382                 threading.Thread(target=self.OnHeatRun).start()\r
383         \r
384         def OnHeatRun(self):\r
385                 self.comm = machineCom.MachineCom()\r
386                 while True:\r
387                         line = self.comm.readline()\r
388                         if line == '':\r
389                                 return\r
390                         if line.startswith('start'):\r
391                                 break\r
392                 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.\r
393                 wx.MessageBox('Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)', 'Machine heatup', wx.OK | wx.ICON_INFORMATION)\r
394                 self.sendGCommand('M104 S0')\r
395                 time.sleep(1)\r
396                 self.comm.close()\r
397         \r
398         def sendGCommand(self, cmd):\r
399                 self.comm.sendCommand(cmd) #Disable cold extrusion protection\r
400                 while True:\r
401                         line = self.comm.readline()\r
402                         if line == '':\r
403                                 return\r
404                         if line.startswith('ok'):\r
405                                 break\r
406         \r
407         def StoreData(self):\r
408                 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())\r
409 \r
410 class configWizard(wx.wizard.Wizard):\r
411         def __init__(self):\r
412                 super(configWizard, self).__init__(None, -1, "Configuration Wizard")\r
413                 \r
414                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)\r
415                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)\r
416 \r
417                 self.firstInfoPage = FirstInfoPage(self)\r
418                 self.machineSelectPage = MachineSelectPage(self)\r
419                 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)\r
420                 self.ultimakerCheckupPage = UltimakerCheckupPage(self)\r
421                 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)\r
422                 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)\r
423                 self.repRapInfoPage = RepRapInfoPage(self)\r
424 \r
425                 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)\r
426                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)\r
427                 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)\r
428                 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)\r
429                 wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)\r
430                 \r
431                 self.FitToPage(self.firstInfoPage)\r
432                 self.GetPageAreaSizer().Add(self.firstInfoPage)\r
433                 \r
434                 self.RunWizard(self.firstInfoPage)\r
435                 self.Destroy()\r
436 \r
437         def OnPageChanging(self, e):\r
438                 e.GetPage().StoreData()\r
439 \r
440         def OnPageChanged(self, e):\r
441                 if e.GetPage().AllowNext():\r
442                         self.FindWindowById(wx.ID_FORWARD).Enable() \r
443                 else:\r
444                         self.FindWindowById(wx.ID_FORWARD).Disable() \r
445                 self.FindWindowById(wx.ID_BACKWARD).Disable() \r