source: src/mlx/gui/gui.py@ 130:f3b2a892af5a

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

Plane position updating works

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