source: src/mlx/gui/gui.py@ 128:e14fcd9d9215

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

Various small fixes

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