chiark / gitweb /
Merge upstream, fixed conflicts, showing complete toolbar at bottom of preview
[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 util 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.putPreference('steps_per_e', '865.888')\r
101                         profile.putProfileSetting('nozzle_size', '0.4')\r
102                         profile.putProfileSetting('machine_center_x', '100')\r
103                         profile.putProfileSetting('machine_center_y', '100')\r
104                 else:\r
105                         profile.putPreference('machine_width', '80')\r
106                         profile.putPreference('machine_depth', '80')\r
107                         profile.putPreference('machine_height', '60')\r
108                         profile.putProfileSetting('nozzle_size', '0.5')\r
109                         profile.putProfileSetting('machine_center_x', '40')\r
110                         profile.putProfileSetting('machine_center_y', '40')\r
111                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)\r
112 \r
113 class FirmwareUpgradePage(InfoPage):\r
114         def __init__(self, parent):\r
115                 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")\r
116                 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
117                 self.AddHiddenSeperator()\r
118                 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')\r
119                 self.AddHiddenSeperator()\r
120                 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
121                 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')\r
122                 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)\r
123                 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
124                 self.AddHiddenSeperator()\r
125                 self.AddText('Do not upgrade to this firmware if:')\r
126                 self.AddText('* You have an older machine based on ATMega1280')\r
127                 self.AddText('* Using an LCD panel')\r
128                 self.AddText('* Have other changes in the firmware')\r
129                 button = self.AddButton('Goto this page for a custom firmware')\r
130                 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)\r
131         \r
132         def AllowNext(self):\r
133                 return False\r
134         \r
135         def OnUpgradeClick(self, e):\r
136                 if machineCom.InstallFirmware(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../firmware/default.hex")):\r
137                         self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
138                 \r
139         def OnSkipClick(self, e):\r
140                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
141         \r
142         def OnUrlClick(self, e):\r
143                 webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')\r
144 \r
145 class UltimakerCheckupPage(InfoPage):\r
146         def __init__(self, parent):\r
147                 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")\r
148                 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
149                 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')\r
150                 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)\r
151                 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
152                 self.AddSeperator();\r
153                 self.checkPanel = None\r
154         \r
155         def AllowNext(self):\r
156                 return False\r
157         \r
158         def OnSkipClick(self, e):\r
159                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
160         \r
161         def OnCheckClick(self, e):\r
162                 if self.checkPanel != None:\r
163                         self.checkPanel.Destroy()\r
164                 self.checkPanel = wx.Panel(self)\r
165                 self.checkPanel.SetSizer(wx.BoxSizer(wx.VERTICAL))\r
166                 self.GetSizer().Add(self.checkPanel, 0, wx.LEFT|wx.RIGHT, 5)\r
167                 threading.Thread(target=self.OnRun).start()\r
168 \r
169         def AddProgressText(self, info):\r
170                 text = wx.StaticText(self.checkPanel, -1, info)\r
171                 self.checkPanel.GetSizer().Add(text, 0)\r
172                 self.checkPanel.Layout()\r
173                 self.Layout()\r
174         \r
175         def OnRun(self):\r
176                 wx.CallAfter(self.AddProgressText, "Connecting to machine...")\r
177                 self.comm = machineCom.MachineCom()\r
178 \r
179                 wx.CallAfter(self.AddProgressText, "Checking start message...")\r
180                 if self.DoCommCommandWithTimeout(None, 'start') == False:\r
181                         wx.CallAfter(self.AddProgressText, "Error: Missing start message.")\r
182                         self.comm.close()\r
183                         return\r
184                         \r
185                 wx.CallAfter(self.AddProgressText, "Disabling step motors...")\r
186                 if self.DoCommCommandWithTimeout('M84') == False:\r
187                         wx.CallAfter(self.AddProgressText, "Error: Missing reply to Deactivate steppers (M84).")\r
188                         wx.CallAfter(self.AddProgressText, "Possible cause: Temperature MIN/MAX.\nCheck temperature sensor connections.")\r
189                         self.comm.close()\r
190                         return\r
191 \r
192                 if self.DoCommCommandWithTimeout("M104 S0") == False:\r
193                         wx.CallAfter(self.AddProgressText, "Failed to set temperature")\r
194                         self.comm.close()\r
195                         return\r
196 \r
197                 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
198                 \r
199                 idleTemp = self.readTemp()\r
200                 if idleTemp > 40:\r
201                         wx.CallAfter(self.AddProgressText, "Waiting for head to cool down before temperature test...")\r
202                         while idleTemp > 40:\r
203                                 idleTemp = self.readTemp()\r
204                                 time.sleep(1)\r
205                 \r
206                 wx.CallAfter(self.AddProgressText, "Checking heater and temperature sensor...")\r
207                 wx.CallAfter(self.AddProgressText, "(This takes about 30 seconds)")\r
208                 if self.DoCommCommandWithTimeout("M104 S100") == False:\r
209                         wx.CallAfter(self.AddProgressText, "Failed to set temperature")\r
210                         self.comm.close()\r
211                         return\r
212                 \r
213                 time.sleep(25)\r
214                 tempInc = self.readTemp() - idleTemp\r
215                 \r
216                 if self.DoCommCommandWithTimeout("M104 S0") == False:\r
217                         wx.CallAfter(self.AddProgressText, "Failed to set temperature")\r
218                         self.comm.close()\r
219                         return\r
220                 \r
221                 if tempInc < 15:\r
222                         wx.CallAfter(self.AddProgressText, "Your temperature sensor or heater is not working!")\r
223                         self.comm.close()\r
224                         return\r
225                 wx.CallAfter(self.AddProgressText, "Heater and temperature sensor working\nWarning: head might still be hot!")\r
226 \r
227                 wx.CallAfter(self.AddProgressText, "Checking endstops")\r
228                 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
229                         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
230                         self.comm.close()\r
231                         return\r
232                 wx.CallAfter(self.AddProgressText, "Please press the X end switch in the front left corner.")\r
233                 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
234                         wx.CallAfter(self.AddProgressText, "Failed to check the x_min endstop!")\r
235                         self.comm.close()\r
236                         return\r
237                 wx.CallAfter(self.AddProgressText, "Please press the X end switch in the front right corner.")\r
238                 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
239                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
240                         self.comm.close()\r
241                         return\r
242                 wx.CallAfter(self.AddProgressText, "Please press the Y end switch in the front left corner.")\r
243                 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
244                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
245                         self.comm.close()\r
246                         return\r
247                 wx.CallAfter(self.AddProgressText, "Please press the Y end switch in the back left corner.")\r
248                 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
249                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
250                         self.comm.close()\r
251                         return\r
252                 wx.CallAfter(self.AddProgressText, "Please press the Z end switch in the top.")\r
253                 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
254                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
255                         self.comm.close()\r
256                         return\r
257                 wx.CallAfter(self.AddProgressText, "Please press the Z end switch in the bottom.")\r
258                 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
259                         wx.CallAfter(self.AddProgressText, "Failed to check the x_max endstop!")\r
260                         self.comm.close()\r
261                         return\r
262                 wx.CallAfter(self.AddProgressText, "End stops are working.")\r
263 \r
264                 wx.CallAfter(self.AddProgressText, "Done!")\r
265                 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)\r
266                 self.comm.close()\r
267                 \r
268         def readTemp(self):\r
269                 line = self.DoCommCommandWithTimeout("M105", "ok T:")\r
270                 if line == False:\r
271                         return -1\r
272                 return int(re.search('T:([0-9]*)', line).group(1))\r
273         \r
274         def DoCommCommandAndWaitForReply(self, cmd, replyStart, reply):\r
275                 while True:\r
276                         ret = self.DoCommCommandWithTimeout(cmd, replyStart)\r
277                         if ret == reply:\r
278                                 return True\r
279                         if ret == False:\r
280                                 return False\r
281                         time.sleep(1)\r
282         \r
283         def DoCommCommandWithTimeout(self, cmd = None, replyStart = 'ok'):\r
284                 if cmd != None:\r
285                         self.comm.sendCommand(cmd)\r
286                 t = threading.Timer(5, self.OnSerialTimeout)\r
287                 t.start()\r
288                 while True:\r
289                         line = self.comm.readline()\r
290                         if line == '':\r
291                                 self.comm.close()\r
292                                 return False\r
293                         if line.startswith(replyStart):\r
294                                 break\r
295                 t.cancel()\r
296                 return line.rstrip()\r
297         \r
298         def OnSerialTimeout(self):\r
299                 self.comm.close()\r
300 \r
301 class UltimakerCalibrationPage(InfoPage):\r
302         def __init__(self, parent):\r
303                 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")\r
304                 \r
305                 self.AddText("Your Ultimaker requires some calibration.");\r
306                 self.AddText("This calibration is needed for a proper extrusion amount.");\r
307                 self.AddSeperator()\r
308                 self.AddText("The following values are needed:");\r
309                 self.AddText("* Diameter of filament");\r
310                 self.AddText("* Number of steps per mm of filament extrusion");\r
311                 self.AddSeperator()\r
312                 self.AddText("The better you have calibrated these values, the better your prints\nwill become.");\r
313                 self.AddSeperator()\r
314                 self.AddText("First we need the diameter of your filament:");\r
315                 self.filamentDiameter = wx.TextCtrl(self, -1, profile.getProfileSetting('filament_diameter'))\r
316                 self.GetSizer().Add(self.filamentDiameter, 0, wx.LEFT, 5)\r
317                 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
318                 self.AddText("Note: This value can be changed later at any time.");\r
319 \r
320         def StoreData(self):\r
321                 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())\r
322 \r
323 class UltimakerCalibrateStepsPerEPage(InfoPage):\r
324         def __init__(self, parent):\r
325                 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")\r
326                 \r
327                 self.AddText("Calibrating the Steps Per E requires some manual actions.")\r
328                 self.AddText("First remove any filament from your machine.")\r
329                 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")\r
330                 self.AddText("We'll push the filament 100mm")\r
331                 self.extrudeButton = self.AddButton("Extrude 100mm filament")\r
332                 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")\r
333                 p = wx.Panel(self)\r
334                 p.SetSizer(wx.BoxSizer(wx.HORIZONTAL))\r
335                 self.lengthInput = wx.TextCtrl(p, -1, '100')\r
336                 p.GetSizer().Add(self.lengthInput, 0, wx.RIGHT, 8)\r
337                 self.saveLengthButton = wx.Button(p, -1, 'Save')\r
338                 p.GetSizer().Add(self.saveLengthButton, 0)\r
339                 self.GetSizer().Add(p, 0, wx.LEFT, 5)\r
340                 self.AddText("This results in the following steps per E:")\r
341                 self.stepsPerEInput = wx.TextCtrl(self, -1, profile.getPreference('steps_per_e'))\r
342                 self.GetSizer().Add(self.stepsPerEInput, 0, wx.LEFT, 5)\r
343                 self.AddText("You can repeat these steps to get better calibration.")\r
344                 self.AddSeperator()\r
345                 self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")\r
346                 self.heatButton = self.AddButton("Heatup for filament removal")\r
347                 \r
348                 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)\r
349                 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)\r
350                 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)\r
351         \r
352         def OnSaveLengthClick(self, e):\r
353                 currentEValue = float(self.stepsPerEInput.GetValue())\r
354                 realExtrudeLength = float(self.lengthInput.GetValue())\r
355                 newEValue = currentEValue * 100 / realExtrudeLength\r
356                 self.stepsPerEInput.SetValue(str(newEValue))\r
357                 self.lengthInput.SetValue("100")\r
358         \r
359         def OnExtrudeClick(self, e):\r
360                 threading.Thread(target=self.OnExtrudeRun).start()\r
361 \r
362         def OnExtrudeRun(self):\r
363                 self.heatButton.Enable(False)\r
364                 self.extrudeButton.Enable(False)\r
365                 currentEValue = float(self.stepsPerEInput.GetValue())\r
366                 self.comm = machineCom.MachineCom()\r
367                 while True:\r
368                         line = self.comm.readline()\r
369                         if line == '':\r
370                                 return\r
371                         if line.startswith('start'):\r
372                                 break\r
373                 self.sendGCommand('M302') #Disable cold extrusion protection\r
374                 self.sendGCommand("M92 E%f" % (currentEValue));\r
375                 self.sendGCommand("G92 E0");\r
376                 self.sendGCommand("G1 E100 F600");\r
377                 time.sleep(15)\r
378                 self.comm.close()\r
379                 self.extrudeButton.Enable()\r
380                 self.heatButton.Enable()\r
381 \r
382         def OnHeatClick(self, e):\r
383                 threading.Thread(target=self.OnHeatRun).start()\r
384         \r
385         def OnHeatRun(self):\r
386                 self.comm = machineCom.MachineCom()\r
387                 while True:\r
388                         line = self.comm.readline()\r
389                         if line == '':\r
390                                 return\r
391                         if line.startswith('start'):\r
392                                 break\r
393                 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.\r
394                 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
395                 self.sendGCommand('M104 S0')\r
396                 time.sleep(1)\r
397                 self.comm.close()\r
398         \r
399         def sendGCommand(self, cmd):\r
400                 self.comm.sendCommand(cmd) #Disable cold extrusion protection\r
401                 while True:\r
402                         line = self.comm.readline()\r
403                         if line == '':\r
404                                 return\r
405                         if line.startswith('ok'):\r
406                                 break\r
407         \r
408         def StoreData(self):\r
409                 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())\r
410 \r
411 class configWizard(wx.wizard.Wizard):\r
412         def __init__(self):\r
413                 super(configWizard, self).__init__(None, -1, "Configuration Wizard")\r
414                 \r
415                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)\r
416                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)\r
417 \r
418                 self.firstInfoPage = FirstInfoPage(self)\r
419                 self.machineSelectPage = MachineSelectPage(self)\r
420                 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)\r
421                 self.ultimakerCheckupPage = UltimakerCheckupPage(self)\r
422                 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)\r
423                 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)\r
424                 self.repRapInfoPage = RepRapInfoPage(self)\r
425 \r
426                 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)\r
427                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)\r
428                 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)\r
429                 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)\r
430                 wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)\r
431                 \r
432                 self.FitToPage(self.firstInfoPage)\r
433                 self.GetPageAreaSizer().Add(self.firstInfoPage)\r
434                 \r
435                 self.RunWizard(self.firstInfoPage)\r
436                 self.Destroy()\r
437 \r
438         def OnPageChanging(self, e):\r
439                 e.GetPage().StoreData()\r
440 \r
441         def OnPageChanged(self, e):\r
442                 if e.GetPage().AllowNext():\r
443                         self.FindWindowById(wx.ID_FORWARD).Enable() \r
444                 else:\r
445                         self.FindWindowById(wx.ID_FORWARD).Disable() \r
446                 self.FindWindowById(wx.ID_BACKWARD).Disable() \r