source: src/mlx/gui/gui.py@ 142:4fe5a65e7c37

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

Eliminated the annoying background of the fuel tank figures

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