source: src/mlx/gui/gui.py@ 119:0185f1446770

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

The fleet is now retrieved centrally and is updated on the Gates page all the time

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