source: src/mlx/gui/gui.py@ 131:822f47eec5a8

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

Added option to take the flare time from the simulator

File size: 28.5 KB
Line 
1# The main file for the GUI
2
3from statusicon import StatusIcon
4from statusbar import Statusbar
5from info import FlightInfo
6from update import Updater
7from mlx.gui.common import *
8from mlx.gui.flight import Wizard
9from mlx.gui.monitor import MonitorWindow
10from mlx.gui.weighthelp import WeightHelp
11from mlx.gui.gates import FleetGateStatus
12from mlx.gui.prefs import Preferences
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
19import mlx.web as web
20from mlx.i18n import xstr
21
22import time
23import threading
24import sys
25
26#------------------------------------------------------------------------------
27
28class GUI(fs.ConnectionListener):
29 """The main GUI class."""
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
37 def __init__(self, programDirectory, config):
38 """Construct the GUI."""
39 gobject.threads_init()
40
41 self._programDirectory = programDirectory
42 self.config = config
43 self._connecting = False
44 self._reconnecting = False
45 self._connected = False
46 self._logger = logger.Logger(self)
47 self._flight = None
48 self._simulator = None
49 self._monitoring = False
50
51 self._fleet = None
52
53 self._fleetCallback = None
54
55 self._updatePlaneCallback = None
56 self._updatePlaneTailNumber = None
57 self._updatePlaneStatus = None
58 self._updatePlaneGateNumber = None
59
60 self._stdioLock = threading.Lock()
61 self._stdioText = ""
62
63 self.webHandler = web.Handler()
64 self.webHandler.start()
65
66 self.toRestart = False
67
68 def build(self, iconDirectory):
69 """Build the GUI."""
70
71 self._mainWindow = window = gtk.Window()
72 window.set_title(WINDOW_TITLE_BASE)
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)
77 accelGroup = gtk.AccelGroup()
78 window.add_accel_group(accelGroup)
79
80 mainVBox = gtk.VBox()
81 window.add(mainVBox)
82
83 self._preferences = Preferences(self)
84
85 menuBar = self._buildMenuBar(accelGroup)
86 mainVBox.pack_start(menuBar, False, False, 0)
87
88 self._notebook = gtk.Notebook()
89 mainVBox.pack_start(self._notebook, True, True, 4)
90
91 self._wizard = Wizard(self)
92 label = gtk.Label(xstr("tab_flight"))
93 label.set_use_underline(True)
94 label.set_tooltip_text(xstr("tab_flight_tooltip"))
95 self._notebook.append_page(self._wizard, label)
96
97 self._flightInfo = FlightInfo(self)
98 label = gtk.Label(xstr("tab_flight_info"))
99 label.set_use_underline(True)
100 label.set_tooltip_text(xstr("tab_flight_info_tooltip"))
101 self._notebook.append_page(self._flightInfo, label)
102 self._flightInfo.disable()
103
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
110 (logWidget, self._logView) = self._buildLogWidget()
111 label = gtk.Label(xstr("tab_log"))
112 label.set_use_underline(True)
113 label.set_tooltip_text(xstr("tab_log_tooltip"))
114 self._notebook.append_page(logWidget, label)
115
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
122 (self._debugLogWidget, self._debugLogView) = self._buildLogWidget()
123 self._debugLogWidget.show_all()
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
130 self._notebook.connect("switch-page", self._notebookPageSwitch)
131
132 self._monitorWindow = MonitorWindow(self, iconDirectory)
133 self._monitorWindow.add_accel_group(accelGroup)
134 self._monitorWindowX = None
135 self._monitorWindowY = None
136 self._selfToggling = False
137
138 window.show_all()
139 self._wizard.grabDefault()
140 self._weightHelp.reset()
141 self._weightHelp.disable()
142
143 self._statusIcon = StatusIcon(iconDirectory, self)
144
145 self._busyCursor = gdk.Cursor(gdk.CursorType.WATCH if pygobject
146 else gdk.WATCH)
147
148 @property
149 def mainWindow(self):
150 """Get the main window of the GUI."""
151 return self._mainWindow
152
153 @property
154 def logger(self):
155 """Get the logger used by us."""
156 return self._logger
157
158 @property
159 def simulator(self):
160 """Get the simulator used by us."""
161 return self._simulator
162
163 @property
164 def flight(self):
165 """Get the flight being performed."""
166 return self._flight
167
168 @property
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
179 def zfw(self):
180 """Get Zero-Fuel Weight calculated for the current flight."""
181 return self._wizard.zfw
182
183 @property
184 def filedCruiseAltitude(self):
185 """Get cruise altitude filed for the current flight."""
186 return self._wizard.filedCruiseAltitude
187
188 @property
189 def cruiseAltitude(self):
190 """Get cruise altitude set for the current flight."""
191 return self._wizard.cruiseAltitude
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
202
203 @property
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
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
232
233 @property
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
254 def vref(self):
255 """Get the Vref speed calculated for the flight."""
256 return self._wizard.vref
257
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
278 @property
279 def delayCodes(self):
280 """Get the delay codes."""
281 return self._flightInfo.delayCodes
282
283 def run(self):
284 """Run the GUI."""
285 if self.config.autoUpdate:
286 self._updater = Updater(self,
287 self._programDirectory,
288 self.config.updateURL,
289 self._mainWindow)
290 self._updater.start()
291
292 gtk.main()
293
294 self._disconnect()
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,))
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
320 dialog = gtk.MessageDialog(parent = self._mainWindow,
321 type = MESSAGETYPE_ERROR,
322 message_format = xstr("conn_failed"))
323
324 dialog.set_title(WINDOW_TITLE_BASE)
325 dialog.format_secondary_markup(xstr("conn_failed_sec"))
326
327 dialog.add_button(xstr("button_cancel"), 0)
328 dialog.add_button(xstr("button_tryagain"), 1)
329 dialog.set_default_response(1)
330
331 result = dialog.run()
332 dialog.hide()
333 if result == 1:
334 self.beginBusy(xstr("connect_busy"))
335 self._simulator.reconnect()
336 else:
337 self.reset()
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")
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,
351 message_format = xstr("conn_broken"),
352 parent = self._mainWindow)
353 dialog.set_title(WINDOW_TITLE_BASE)
354 dialog.format_secondary_markup(xstr("conn_broken_sec"))
355
356 dialog.add_button(xstr("button_cancel"), 0)
357 dialog.add_button(xstr("button_reconnect"), 1)
358 dialog.set_default_response(1)
359
360 result = dialog.run()
361 dialog.hide()
362 if result == 1:
363 self.beginBusy(xstr("connect_busy"))
364 self._reconnecting = True
365 self._simulator.reconnect()
366 else:
367 self.reset()
368
369 def enableFlightInfo(self):
370 """Enable the flight info tab."""
371 self._flightInfo.enable()
372
373 def reset(self):
374 """Reset the GUI."""
375 self._disconnect()
376
377 self._flightInfo.reset()
378 self._flightInfo.disable()
379 self.resetFlightStatus()
380
381 self._weightHelp.reset()
382 self._weightHelp.disable()
383 self._wizard.reset()
384 self._notebook.set_current_page(0)
385
386 self._logView.get_buffer().set_text("")
387
388 def _disconnect(self):
389 """Disconnect from the simulator if connected."""
390 self.stopMonitoring()
391
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)
399 self._weightHelp.disable()
400
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
421 def check(self, flight, aircraft, logger, oldState, state):
422 """Update the data."""
423 gobject.idle_add(self._monitorWindow.setData, state)
424 gobject.idle_add(self._statusbar.updateTime, state.timestamp)
425
426 def resetFlightStatus(self):
427 """Reset the status of the flight."""
428 self._statusbar.resetFlightStatus()
429 self._statusbar.updateTime()
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."""
438 self._statusbar.setStage(stage)
439 self._statusIcon.setStage(stage)
440 self._wizard.setStage(stage)
441 if stage==const.STAGE_END:
442 self._disconnect()
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."""
450 self._statusbar.setRating(rating)
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."""
459 self._statusbar.setNoGo(reason)
460 self._statusIcon.setNoGo(reason)
461
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:
467 self.hideMainWindow(savePosition = False)
468
469 def hideMainWindow(self, savePosition = True):
470 """Hide the main window and save its position."""
471 if savePosition:
472 (self._mainWindowX, self._mainWindowY) = \
473 self._mainWindow.get_window().get_root_origin()
474 else:
475 self._mainWindowX = self._mainWindowY = None
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."""
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()
486 self._mainWindow.deiconify()
487
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()
496
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()
506 if self._showMonitorMenuItem.get_active():
507 self._selfToggling = True
508 self._showMonitorMenuItem.set_active(False)
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()
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()
528
529 def restart(self):
530 """Quit and restart the application."""
531 self.toRestart = True
532 self._quit(force = True)
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
539 def writeStdIO(self, text):
540 """Write the given text into standard I/O log."""
541 with self._stdioLock:
542 self._stdioText += text
543
544 gobject.idle_add(self._writeStdIO)
545
546 def beginBusy(self, message):
547 """Begin a period of background processing."""
548 self._wizard.set_sensitive(False)
549 self._weightHelp.set_sensitive(False)
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)
556 self._weightHelp.set_sensitive(True)
557 self._wizard.set_sensitive(True)
558 self._statusbar.updateBusyState(None)
559
560 def initializeWeightHelp(self):
561 """Initialize the weight help tab."""
562 self._weightHelp.reset()
563 self._weightHelp.enable()
564
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
589 dialog = gtk.MessageDialog(parent = self.mainWindow,
590 type = MESSAGETYPE_ERROR,
591 message_format = xstr("fleet_failed"))
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"))
636 dialog.add_button(xstr("button_ok"), RESPONSETYPE_ACCEPT)
637 dialog.set_title(WINDOW_TITLE_BASE)
638 dialog.run()
639 dialog.hide()
640
641 success = None
642
643 callback = self._updatePlaneCallback
644 self._updatePlaneCallback = None
645 if callback is not None:
646 callback(success)
647
648 def _writeStdIO(self):
649 """Perform the real writing."""
650 with self._stdioLock:
651 text = self._stdioText
652 self._stdioText = ""
653 if not text: return
654
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:
663 #print >> sys.__stdout__, line
664 self._writeLog(line + "\n", self._debugLogView)
665
666 if text:
667 #print >> sys.__stdout__, text,
668 self._writeLog(text, self._debugLogView)
669
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.flareTimeFromFS = self.config.flareTimeFromFS
676 self._flight.aircraftType = aircraftType
677 self._flight.aircraft = acft.Aircraft.create(self._flight)
678 self._flight.aircraft._checkers.append(self)
679
680 if self._simulator is None:
681 self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
682
683 self._flight.simulator = self._simulator
684
685 self.beginBusy(xstr("connect_busy"))
686 self._statusbar.updateConnection(self._connecting, self._connected)
687
688 self._connecting = True
689 self._simulator.connect(self._flight.aircraft)
690
691 def startMonitoring(self):
692 """Start monitoring."""
693 if not self._monitoring:
694 self.simulator.startMonitoring()
695 self._monitoring = True
696
697 def stopMonitoring(self):
698 """Stop monitoring."""
699 if self._monitoring:
700 self.simulator.stopMonitoring()
701 self._monitoring = False
702
703 def _buildMenuBar(self, accelGroup):
704 """Build the main menu bar."""
705 menuBar = gtk.MenuBar()
706
707 fileMenuItem = gtk.MenuItem(xstr("menu_file"))
708 fileMenu = gtk.Menu()
709 fileMenuItem.set_submenu(fileMenu)
710 menuBar.append(fileMenuItem)
711
712 quitMenuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
713 quitMenuItem.set_use_stock(True)
714 quitMenuItem.set_label(xstr("menu_file_quit"))
715 quitMenuItem.add_accelerator("activate", accelGroup,
716 ord(xstr("menu_file_quit_key")),
717 CONTROL_MASK, ACCEL_VISIBLE)
718 quitMenuItem.connect("activate", self._quit)
719 fileMenu.append(quitMenuItem)
720
721 toolsMenuItem = gtk.MenuItem(xstr("menu_tools"))
722 toolsMenu = gtk.Menu()
723 toolsMenuItem.set_submenu(toolsMenu)
724 menuBar.append(toolsMenuItem)
725
726 prefsMenuItem = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
727 prefsMenuItem.set_use_stock(True)
728 prefsMenuItem.set_label(xstr("menu_tools_prefs"))
729 prefsMenuItem.add_accelerator("activate", accelGroup,
730 ord(xstr("menu_tools_prefs_key")),
731 CONTROL_MASK, ACCEL_VISIBLE)
732 prefsMenuItem.connect("activate", self._editPreferences)
733 toolsMenu.append(prefsMenuItem)
734
735 viewMenuItem = gtk.MenuItem(xstr("menu_view"))
736 viewMenu = gtk.Menu()
737 viewMenuItem.set_submenu(viewMenu)
738 menuBar.append(viewMenuItem)
739
740 self._showMonitorMenuItem = gtk.CheckMenuItem()
741 self._showMonitorMenuItem.set_label(xstr("menu_view_monitor"))
742 self._showMonitorMenuItem.set_use_underline(True)
743 self._showMonitorMenuItem.set_active(False)
744 self._showMonitorMenuItem.add_accelerator("activate", accelGroup,
745 ord(xstr("menu_view_monitor_key")),
746 CONTROL_MASK, ACCEL_VISIBLE)
747 self._showMonitorMenuItem.connect("toggled", self._toggleMonitorWindow)
748 viewMenu.append(self._showMonitorMenuItem)
749
750 showDebugMenuItem = gtk.CheckMenuItem()
751 showDebugMenuItem.set_label(xstr("menu_view_debug"))
752 showDebugMenuItem.set_use_underline(True)
753 showDebugMenuItem.set_active(False)
754 showDebugMenuItem.add_accelerator("activate", accelGroup,
755 ord(xstr("menu_view_debug_key")),
756 CONTROL_MASK, ACCEL_VISIBLE)
757 showDebugMenuItem.connect("toggled", self._toggleDebugLog)
758 viewMenu.append(showDebugMenuItem)
759
760 return menuBar
761
762 def _toggleDebugLog(self, menuItem):
763 """Toggle the debug log."""
764 if menuItem.get_active():
765 label = gtk.Label(xstr("tab_debug_log"))
766 label.set_use_underline(True)
767 label.set_tooltip_text(xstr("tab_debug_log_tooltip"))
768 self._debugLogPage = self._notebook.append_page(self._debugLogWidget, label)
769 self._notebook.set_current_page(self._debugLogPage)
770 else:
771 self._notebook.remove_page(self._debugLogPage)
772
773 def _buildLogWidget(self):
774 """Build the widget for the log."""
775 alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
776
777 alignment.set_padding(padding_top = 8, padding_bottom = 8,
778 padding_left = 16, padding_right = 16)
779
780 logScroller = gtk.ScrolledWindow()
781 # FIXME: these should be constants in common
782 logScroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
783 else gtk.POLICY_AUTOMATIC,
784 gtk.PolicyType.AUTOMATIC if pygobject
785 else gtk.POLICY_AUTOMATIC)
786 logScroller.set_shadow_type(gtk.ShadowType.IN if pygobject
787 else gtk.SHADOW_IN)
788 logView = gtk.TextView()
789 logView.set_editable(False)
790 logScroller.add(logView)
791
792 logBox = gtk.VBox()
793 logBox.pack_start(logScroller, True, True, 0)
794 logBox.set_size_request(-1, 200)
795
796 alignment.add(logBox)
797
798 return (alignment, logView)
799
800 def _writeLog(self, msg, logView):
801 """Write the given message to the log."""
802 buffer = logView.get_buffer()
803 buffer.insert(buffer.get_end_iter(), msg)
804 logView.scroll_mark_onscreen(buffer.get_insert())
805
806 def _quit(self, what = None, force = False):
807 """Quit from the application."""
808 if force:
809 result=RESPONSETYPE_YES
810 else:
811 dialog = gtk.MessageDialog(parent = self._mainWindow,
812 type = MESSAGETYPE_QUESTION,
813 message_format = xstr("quit_question"))
814
815 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
816 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
817
818 dialog.set_title(WINDOW_TITLE_BASE)
819 result = dialog.run()
820 dialog.hide()
821
822 if result==RESPONSETYPE_YES:
823 self._statusIcon.destroy()
824 return gtk.main_quit()
825
826 def _notebookPageSwitch(self, notebook, page, page_num):
827 """Called when the current page of the notebook has changed."""
828 if page_num==0:
829 gobject.idle_add(self._wizard.grabDefault)
830 else:
831 self._mainWindow.set_default(None)
832
833 def _editPreferences(self, menuItem):
834 """Callback for editing the preferences."""
835 self._preferences.run(self.config)
Note: See TracBrowser for help on using the repository browser.