source: src/mlx/gui/gui.py@ 107:35310bf5309c

Last change on this file since 107:35310bf5309c was 107:35310bf5309c, checked in by István Váradi <ivaradi@…>, 12 years ago

Added support for internationalization and translated most of the flight wizard into Hungarian

File size: 23.7 KB
RevLine 
[28]1# The main file for the GUI
2
[29]3from statusicon import StatusIcon
[32]4from statusbar import Statusbar
[90]5from info import FlightInfo
[36]6from update import Updater
[29]7from mlx.gui.common import *
[42]8from mlx.gui.flight import Wizard
[77]9from mlx.gui.monitor import MonitorWindow
[28]10
11import mlx.const as const
12import mlx.fs as fs
13import mlx.flight as flight
14import mlx.logger as logger
15import mlx.acft as acft
[41]16import mlx.web as web
[107]17from mlx.i18n import xstr
[28]18
19import time
[38]20import threading
21import sys
[28]22
[77]23#------------------------------------------------------------------------------
24
[28]25class GUI(fs.ConnectionListener):
26 """The main GUI class."""
[96]27 @staticmethod
28 def _formatFlightLogLine(timeStr, line):
29 """Format the given line for flight logging."""
30 if timeStr is not None:
31 line = timeStr + ": " + line
32 return line + "\n"
33
[36]34 def __init__(self, programDirectory, config):
[28]35 """Construct the GUI."""
36 gobject.threads_init()
37
[36]38 self._programDirectory = programDirectory
[42]39 self.config = config
[28]40 self._connecting = False
[59]41 self._reconnecting = False
[28]42 self._connected = False
[96]43 self._logger = logger.Logger(self)
[28]44 self._flight = None
45 self._simulator = None
[59]46 self._monitoring = False
[38]47
48 self._stdioLock = threading.Lock()
49 self._stdioText = ""
[28]50
[41]51 self.webHandler = web.Handler()
52 self.webHandler.start()
53
[38]54 self.toRestart = False
55
[29]56 def build(self, iconDirectory):
[28]57 """Build the GUI."""
[29]58
[36]59 window = gtk.Window()
[105]60 window.set_title(WINDOW_TITLE_BASE)
[36]61 window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
62 window.connect("delete-event",
63 lambda a, b: self.hideMainWindow())
64 window.connect("window-state-event", self._handleMainWindowState)
[93]65 accelGroup = gtk.AccelGroup()
66 window.add_accel_group(accelGroup)
[28]67
68 mainVBox = gtk.VBox()
[36]69 window.add(mainVBox)
[28]70
[93]71 menuBar = self._buildMenuBar(accelGroup)
72 mainVBox.pack_start(menuBar, False, False, 0)
73
[92]74 self._notebook = gtk.Notebook()
[93]75 mainVBox.pack_start(self._notebook, True, True, 4)
[42]76
[46]77 self._wizard = Wizard(self)
[107]78 label = gtk.Label(xstr("tab_flight"))
[46]79 label.set_use_underline(True)
80 label.set_tooltip_text("Flight wizard")
[92]81 self._notebook.append_page(self._wizard, label)
[42]82
[90]83 self._flightInfo = FlightInfo(self)
[107]84 label = gtk.Label(xstr("tab_flight_info"))
[90]85 label.set_use_underline(True)
86 label.set_tooltip_text("Flight information")
[92]87 self._notebook.append_page(self._flightInfo, label)
[93]88 self._flightInfo.disable()
[90]89
[93]90 (logWidget, self._logView) = self._buildLogWidget()
[107]91 label = gtk.Label(xstr("tab_log"))
[46]92 label.set_use_underline(True)
[93]93 label.set_tooltip_text("The log of your flight that will be sent to the MAVA website")
94 self._notebook.append_page(logWidget, label)
95
96 (self._debugLogWidget, self._debugLogView) = self._buildLogWidget()
97 self._debugLogWidget.show_all()
[32]98
99 mainVBox.pack_start(gtk.HSeparator(), False, False, 0)
100
101 self._statusbar = Statusbar()
102 mainVBox.pack_start(self._statusbar, False, False, 0)
103
[92]104 self._notebook.connect("switch-page", self._notebookPageSwitch)
[46]105
[77]106 self._monitorWindow = MonitorWindow(self, iconDirectory)
[93]107 self._monitorWindow.add_accel_group(accelGroup)
[77]108 self._monitorWindowX = None
109 self._monitorWindowY = None
[93]110 self._selfToggling = False
[77]111
[46]112 window.show_all()
113 self._wizard.grabDefault()
[28]114
[36]115 self._mainWindow = window
[29]116
117 self._statusIcon = StatusIcon(iconDirectory, self)
[28]118
[49]119 self._busyCursor = gdk.Cursor(gdk.CursorType.WATCH if pygobject
120 else gdk.WATCH)
121
[59]122 @property
[105]123 def mainWindow(self):
124 """Get the main window of the GUI."""
125 return self._mainWindow
126
127 @property
[97]128 def logger(self):
129 """Get the logger used by us."""
130 return self._logger
131
132 @property
[59]133 def simulator(self):
134 """Get the simulator used by us."""
135 return self._simulator
136
[71]137 @property
138 def flight(self):
139 """Get the flight being performed."""
140 return self._flight
[84]141
142 @property
[97]143 def bookedFlight(self):
144 """Get the booked flight selected, if any."""
145 return self._wizard.bookedFlight
146
147 @property
148 def cargoWeight(self):
149 """Get the cargo weight."""
150 return self._wizard.cargoWeight
151
152 @property
[84]153 def zfw(self):
154 """Get Zero-Fuel Weight calculated for the current flight."""
155 return self._wizard.zfw
156
157 @property
[97]158 def filedCruiseAltitude(self):
159 """Get cruise altitude filed for the current flight."""
160 return self._wizard.filedCruiseAltitude
161
162 @property
[84]163 def cruiseAltitude(self):
[97]164 """Get cruise altitude set for the current flight."""
[84]165 return self._wizard.cruiseAltitude
[97]166
167 @property
168 def route(self):
169 """Get the flight route."""
170 return self._wizard.route
171
172 @property
173 def departureMETAR(self):
174 """Get the METAR of the deprature airport."""
175 return self._wizard.departureMETAR
[84]176
177 @property
[97]178 def arrivalMETAR(self):
179 """Get the METAR of the deprature airport."""
180 return self._wizard.arrivalMETAR
181
182 @property
183 def departureRunway(self):
184 """Get the name of the departure runway."""
185 return self._wizard.departureRunway
186
187 @property
188 def sid(self):
189 """Get the SID."""
190 return self._wizard.sid
191
192 @property
[84]193 def v1(self):
194 """Get the V1 speed calculated for the flight."""
195 return self._wizard.v1
196
197 @property
198 def vr(self):
199 """Get the Vr speed calculated for the flight."""
200 return self._wizard.vr
201
202 @property
203 def v2(self):
204 """Get the V2 speed calculated for the flight."""
205 return self._wizard.v2
[71]206
[86]207 @property
[97]208 def arrivalRunway(self):
209 """Get the arrival runway."""
210 return self._wizard.arrivalRunway
211
212 @property
213 def star(self):
214 """Get the STAR."""
215 return self._wizard.star
216
217 @property
218 def transition(self):
219 """Get the transition."""
220 return self._wizard.transition
221
222 @property
223 def approachType(self):
224 """Get the approach type."""
225 return self._wizard.approachType
226
227 @property
[86]228 def vref(self):
229 """Get the Vref speed calculated for the flight."""
230 return self._wizard.vref
231
[97]232 @property
233 def flightType(self):
234 """Get the flight type."""
235 return self._wizard.flightType
236
237 @property
238 def online(self):
239 """Get whether the flight was online or not."""
240 return self._wizard.online
241
242 @property
243 def comments(self):
244 """Get the comments."""
245 return self._flightInfo.comments
246
247 @property
248 def flightDefects(self):
249 """Get the flight defects."""
250 return self._flightInfo.flightDefects
251
[99]252 @property
253 def delayCodes(self):
254 """Get the delay codes."""
255 return self._flightInfo.delayCodes
256
[28]257 def run(self):
258 """Run the GUI."""
[42]259 if self.config.autoUpdate:
[38]260 self._updater = Updater(self,
261 self._programDirectory,
[42]262 self.config.updateURL,
[36]263 self._mainWindow)
264 self._updater.start()
265
[28]266 gtk.main()
[36]267
[91]268 self._disconnect()
[28]269
270 def connected(self, fsType, descriptor):
271 """Called when we have connected to the simulator."""
272 self._connected = True
273 self._logger.untimedMessage("Connected to the simulator %s" % (descriptor,))
[59]274 gobject.idle_add(self._handleConnected, fsType, descriptor)
275
276 def _handleConnected(self, fsType, descriptor):
277 """Called when the connection to the simulator has succeeded."""
278 self._statusbar.updateConnection(self._connecting, self._connected)
279 self.endBusy()
280 if not self._reconnecting:
281 self._wizard.connected(fsType, descriptor)
282 self._reconnecting = False
283
284 def connectionFailed(self):
285 """Called when the connection failed."""
286 self._logger.untimedMessage("Connection to the simulator failed")
287 gobject.idle_add(self._connectionFailed)
288
289 def _connectionFailed(self):
290 """Called when the connection failed."""
291 self.endBusy()
292 self._statusbar.updateConnection(self._connecting, self._connected)
293
[105]294 dialog = gtk.MessageDialog(parent = self._mainWindow,
295 type = MESSAGETYPE_ERROR,
[59]296 message_format =
[105]297 "Cannot connect to the simulator.")
298 dialog.set_title(WINDOW_TITLE_BASE)
[59]299 dialog.format_secondary_markup("Rectify the situation, and press <b>Try again</b> "
300 "to try the connection again, "
301 "or <b>Cancel</b> to cancel the flight.")
302
303 dialog.add_button("_Cancel", 0)
304 dialog.add_button("_Try again", 1)
305 dialog.set_default_response(1)
306
307 result = dialog.run()
308 dialog.hide()
309 if result == 1:
[107]310 self.beginBusy(xstr("connect_busy"))
[59]311 self._simulator.reconnect()
312 else:
[91]313 self.reset()
[28]314
315 def disconnected(self):
316 """Called when we have disconnected from the simulator."""
317 self._connected = False
318 self._logger.untimedMessage("Disconnected from the simulator")
[59]319
320 gobject.idle_add(self._disconnected)
321
322 def _disconnected(self):
323 """Called when we have disconnected from the simulator unexpectedly."""
324 self._statusbar.updateConnection(self._connecting, self._connected)
325
326 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
327 message_format =
328 "The connection to the simulator failed unexpectedly.",
329 parent = self._mainWindow)
[105]330 dialog.set_title(WINDOW_TITLE_BASE)
[59]331 dialog.format_secondary_markup("If the simulator has crashed, restart it "
332 "and restore your flight as much as possible "
[105]333 "to the state it was in before the crash. "
[59]334 "Then press <b>Reconnect</b> to reconnect.\n\n"
335 "If you want to cancel the flight, press <b>Cancel</b>.")
336
337 dialog.add_button("_Cancel", 0)
338 dialog.add_button("_Reconnect", 1)
339 dialog.set_default_response(1)
340
341 result = dialog.run()
342 dialog.hide()
343 if result == 1:
344 self.beginBusy("Connecting to the simulator.")
345 self._reconnecting = True
346 self._simulator.reconnect()
347 else:
[91]348 self.reset()
349
[93]350 def enableFlightInfo(self):
351 """Enable the flight info tab."""
352 self._flightInfo.enable()
353
[91]354 def reset(self):
355 """Reset the GUI."""
356 self._disconnect()
[92]357
[91]358 self._flightInfo.reset()
[93]359 self._flightInfo.disable()
[91]360 self.resetFlightStatus()
[28]361
[92]362 self._wizard.reset()
363 self._notebook.set_current_page(0)
364
365 self._logView.get_buffer().set_text("")
366
[91]367 def _disconnect(self):
368 """Disconnect from the simulator if connected."""
[92]369 self.stopMonitoring()
370
[91]371 if self._connected:
372 self._flight.simulator.disconnect()
373 self._connected = False
374
375 self._connecting = False
376 self._reconnecting = False
377 self._statusbar.updateConnection(False, False)
378
[96]379 def addFlightLogLine(self, timeStr, line):
380 """Write the given message line to the log."""
381 gobject.idle_add(self._writeLog,
382 GUI._formatFlightLogLine(timeStr, line),
383 self._logView)
384
385 def updateFlightLogLine(self, index, timeStr, line):
386 """Update the line with the given index."""
387 gobject.idle_add(self._updateFlightLogLine, index,
388 GUI._formatFlightLogLine(timeStr, line))
389
390 def _updateFlightLogLine(self, index, line):
391 """Replace the contents of the given line in the log."""
392 buffer = self._logView.get_buffer()
393 startIter = buffer.get_iter_at_line(index)
394 endIter = buffer.get_iter_at_line(index + 1)
395 buffer.delete(startIter, endIter)
396 buffer.insert(startIter, line)
397 self._logView.scroll_mark_onscreen(buffer.get_insert())
398
[28]399 def check(self, flight, aircraft, logger, oldState, state):
400 """Update the data."""
[77]401 gobject.idle_add(self._monitorWindow.setData, state)
[80]402 gobject.idle_add(self._statusbar.updateTime, state.timestamp)
[28]403
[31]404 def resetFlightStatus(self):
405 """Reset the status of the flight."""
[32]406 self._statusbar.resetFlightStatus()
[80]407 self._statusbar.updateTime()
[31]408 self._statusIcon.resetFlightStatus()
409
410 def setStage(self, stage):
411 """Set the stage of the flight."""
412 gobject.idle_add(self._setStage, stage)
413
414 def _setStage(self, stage):
415 """Set the stage of the flight."""
[32]416 self._statusbar.setStage(stage)
[31]417 self._statusIcon.setStage(stage)
[84]418 self._wizard.setStage(stage)
[88]419 if stage==const.STAGE_END:
[91]420 self._disconnect()
[31]421
422 def setRating(self, rating):
423 """Set the rating of the flight."""
424 gobject.idle_add(self._setRating, rating)
425
426 def _setRating(self, rating):
427 """Set the rating of the flight."""
[32]428 self._statusbar.setRating(rating)
[31]429 self._statusIcon.setRating(rating)
430
431 def setNoGo(self, reason):
432 """Set the rating of the flight to No-Go with the given reason."""
433 gobject.idle_add(self._setNoGo, reason)
434
435 def _setNoGo(self, reason):
436 """Set the rating of the flight."""
[32]437 self._statusbar.setNoGo(reason)
[31]438 self._statusIcon.setNoGo(reason)
439
[29]440 def _handleMainWindowState(self, window, event):
441 """Hande a change in the state of the window"""
442 iconified = gdk.WindowState.ICONIFIED if pygobject \
443 else gdk.WINDOW_STATE_ICONIFIED
444 if (event.changed_mask&iconified)!=0 and (event.new_window_state&iconified)!=0:
[35]445 self.hideMainWindow(savePosition = False)
[29]446
[35]447 def hideMainWindow(self, savePosition = True):
[29]448 """Hide the main window and save its position."""
[35]449 if savePosition:
450 (self._mainWindowX, self._mainWindowY) = \
451 self._mainWindow.get_window().get_root_origin()
452 else:
453 self._mainWindowX = self._mainWindowY = None
[29]454 self._mainWindow.hide()
455 self._statusIcon.mainWindowHidden()
456 return True
457
458 def showMainWindow(self):
459 """Show the main window at its former position."""
[35]460 if self._mainWindowX is not None and self._mainWindowY is not None:
461 self._mainWindow.move(self._mainWindowX, self._mainWindowY)
462
463 self._mainWindow.show()
[29]464 self._mainWindow.deiconify()
[35]465
[29]466 self._statusIcon.mainWindowShown()
467
468 def toggleMainWindow(self):
469 """Toggle the main window."""
470 if self._mainWindow.get_visible():
471 self.hideMainWindow()
472 else:
473 self.showMainWindow()
[36]474
[77]475 def hideMonitorWindow(self, savePosition = True):
476 """Hide the monitor window."""
477 if savePosition:
478 (self._monitorWindowX, self._monitorWindowY) = \
479 self._monitorWindow.get_window().get_root_origin()
480 else:
481 self._monitorWindowX = self._monitorWindowY = None
482 self._monitorWindow.hide()
483 self._statusIcon.monitorWindowHidden()
[93]484 if self._showMonitorMenuItem.get_active():
485 self._selfToggling = True
486 self._showMonitorMenuItem.set_active(False)
[77]487 return True
488
489 def showMonitorWindow(self):
490 """Show the monitor window."""
491 if self._monitorWindowX is not None and self._monitorWindowY is not None:
492 self._monitorWindow.move(self._monitorWindowX, self._monitorWindowY)
493 self._monitorWindow.show_all()
494 self._statusIcon.monitorWindowShown()
[93]495 if not self._showMonitorMenuItem.get_active():
496 self._selfToggling = True
497 self._showMonitorMenuItem.set_active(True)
498
499 def _toggleMonitorWindow(self, menuItem):
500 if self._selfToggling:
501 self._selfToggling = False
502 elif self._monitorWindow.get_visible():
503 self.hideMonitorWindow()
504 else:
505 self.showMonitorWindow()
[77]506
[38]507 def restart(self):
508 """Quit and restart the application."""
509 self.toRestart = True
[81]510 self._quit(force = True)
[38]511
512 def flushStdIO(self):
513 """Flush any text to the standard error that could not be logged."""
514 if self._stdioText:
515 sys.__stderr__.write(self._stdioText)
516
[36]517 def writeStdIO(self, text):
518 """Write the given text into standard I/O log."""
[38]519 with self._stdioLock:
520 self._stdioText += text
521
522 gobject.idle_add(self._writeStdIO)
[36]523
[49]524 def beginBusy(self, message):
525 """Begin a period of background processing."""
[93]526 self._wizard.set_sensitive(False)
[49]527 self._mainWindow.get_window().set_cursor(self._busyCursor)
528 self._statusbar.updateBusyState(message)
529
530 def endBusy(self):
531 """End a period of background processing."""
532 self._mainWindow.get_window().set_cursor(None)
[93]533 self._wizard.set_sensitive(True)
[49]534 self._statusbar.updateBusyState(None)
535
[38]536 def _writeStdIO(self):
[36]537 """Perform the real writing."""
[38]538 with self._stdioLock:
539 text = self._stdioText
540 self._stdioText = ""
541 if not text: return
542
[36]543 lines = text.splitlines()
544 if text[-1]=="\n":
545 text = ""
546 else:
547 text = lines[-1]
548 lines = lines[:-1]
549
550 for line in lines:
[96]551 #print >> sys.__stdout__, line
[93]552 self._writeLog(line + "\n", self._debugLogView)
[36]553
554 if text:
[96]555 #print >> sys.__stdout__, text,
[93]556 self._writeLog(text, self._debugLogView)
[51]557
[59]558 def connectSimulator(self, aircraftType):
559 """Connect to the simulator for the first time."""
560 self._logger.reset()
561
562 self._flight = flight.Flight(self._logger, self)
563 self._flight.aircraftType = aircraftType
564 self._flight.aircraft = acft.Aircraft.create(self._flight)
565 self._flight.aircraft._checkers.append(self)
566
567 if self._simulator is None:
568 self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
569
570 self._flight.simulator = self._simulator
571
[107]572 self.beginBusy(xstr("connect_busy"))
[59]573 self._statusbar.updateConnection(self._connecting, self._connected)
574
575 self._connecting = True
576 self._simulator.connect(self._flight.aircraft)
577
[70]578 def startMonitoring(self):
579 """Start monitoring."""
[88]580 if not self._monitoring:
581 self.simulator.startMonitoring()
582 self._monitoring = True
[70]583
584 def stopMonitoring(self):
585 """Stop monitoring."""
[88]586 if self._monitoring:
587 self.simulator.stopMonitoring()
588 self._monitoring = False
[70]589
[93]590 def _buildMenuBar(self, accelGroup):
591 """Build the main menu bar."""
592 menuBar = gtk.MenuBar()
593
594 fileMenuItem = gtk.MenuItem("File")
595 fileMenu = gtk.Menu()
596 fileMenuItem.set_submenu(fileMenu)
597 menuBar.append(fileMenuItem)
598
599 quitMenuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
600 quitMenuItem.set_use_stock(True)
601 quitMenuItem.add_accelerator("activate", accelGroup,
602 ord("q"), CONTROL_MASK,
603 ACCEL_VISIBLE)
604 quitMenuItem.connect("activate", self._quit)
605 fileMenu.append(quitMenuItem)
606
607
608 viewMenuItem = gtk.MenuItem("View")
609 viewMenu = gtk.Menu()
610 viewMenuItem.set_submenu(viewMenu)
611 menuBar.append(viewMenuItem)
[28]612
[93]613 self._showMonitorMenuItem = gtk.CheckMenuItem()
614 self._showMonitorMenuItem.set_label("Show _monitor window")
615 self._showMonitorMenuItem.set_use_underline(True)
616 self._showMonitorMenuItem.set_active(False)
617 self._showMonitorMenuItem.add_accelerator("activate", accelGroup,
618 ord("m"), CONTROL_MASK,
619 ACCEL_VISIBLE)
620 self._showMonitorMenuItem.connect("toggled", self._toggleMonitorWindow)
621 viewMenu.append(self._showMonitorMenuItem)
622
623 showDebugMenuItem = gtk.CheckMenuItem()
624 showDebugMenuItem.set_label("Show _debug log")
625 showDebugMenuItem.set_use_underline(True)
626 showDebugMenuItem.set_active(False)
627 showDebugMenuItem.add_accelerator("activate", accelGroup,
628 ord("d"), CONTROL_MASK,
629 ACCEL_VISIBLE)
630 showDebugMenuItem.connect("toggled", self._toggleDebugLog)
631 viewMenu.append(showDebugMenuItem)
[28]632
[93]633 return menuBar
[28]634
[93]635 def _toggleDebugLog(self, menuItem):
636 """Toggle the debug log."""
637 if menuItem.get_active():
[107]638 label = gtk.Label(xstr("tab_debug_log"))
[93]639 label.set_use_underline(True)
640 label.set_tooltip_text("Log with debugging information.")
641 self._debugLogPage = self._notebook.append_page(self._debugLogWidget, label)
642 self._notebook.set_current_page(self._debugLogPage)
643 else:
644 self._notebook.remove_page(self._debugLogPage)
645
646 def _buildLogWidget(self):
647 """Build the widget for the log."""
648 alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
649
650 alignment.set_padding(padding_top = 8, padding_bottom = 8,
651 padding_left = 16, padding_right = 16)
[28]652
653 logScroller = gtk.ScrolledWindow()
[93]654 # FIXME: these should be constants in common
655 logScroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
656 else gtk.POLICY_AUTOMATIC,
657 gtk.PolicyType.AUTOMATIC if pygobject
658 else gtk.POLICY_AUTOMATIC)
659 logScroller.set_shadow_type(gtk.ShadowType.IN if pygobject
660 else gtk.SHADOW_IN)
661 logView = gtk.TextView()
662 logView.set_editable(False)
663 logScroller.add(logView)
[28]664
665 logBox = gtk.VBox()
666 logBox.pack_start(logScroller, True, True, 0)
667 logBox.set_size_request(-1, 200)
668
[93]669 alignment.add(logBox)
[28]670
[93]671 return (alignment, logView)
[28]672
[93]673 def _writeLog(self, msg, logView):
[28]674 """Write the given message to the log."""
[93]675 buffer = logView.get_buffer()
[28]676 buffer.insert(buffer.get_end_iter(), msg)
[93]677 logView.scroll_mark_onscreen(buffer.get_insert())
[28]678
[81]679 def _quit(self, what = None, force = False):
[38]680 """Quit from the application."""
[81]681 if force:
682 result=RESPONSETYPE_YES
683 else:
[105]684 dialog = gtk.MessageDialog(parent = self._mainWindow,
685 type = MESSAGETYPE_QUESTION,
[81]686 buttons = BUTTONSTYPE_YES_NO,
687 message_format =
688 "Are you sure to quit the logger?")
[105]689 dialog.set_title(WINDOW_TITLE_BASE)
[81]690 result = dialog.run()
691 dialog.hide()
[76]692
693 if result==RESPONSETYPE_YES:
694 self._statusIcon.destroy()
695 return gtk.main_quit()
[38]696
[46]697 def _notebookPageSwitch(self, notebook, page, page_num):
698 """Called when the current page of the notebook has changed."""
699 if page_num==0:
[48]700 gobject.idle_add(self._wizard.grabDefault)
[46]701 else:
702 self._mainWindow.set_default(None)
Note: See TracBrowser for help on using the repository browser.