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@…>, 13 years ago

Plane position updating works

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.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
684 self.beginBusy(xstr("connect_busy"))
685 self._statusbar.updateConnection(self._connecting, self._connected)
686
687 self._connecting = True
688 self._simulator.connect(self._flight.aircraft)
689
690 def startMonitoring(self):
691 """Start monitoring."""
692 if not self._monitoring:
693 self.simulator.startMonitoring()
694 self._monitoring = True
695
696 def stopMonitoring(self):
697 """Stop monitoring."""
698 if self._monitoring:
699 self.simulator.stopMonitoring()
700 self._monitoring = False
701
702 def _buildMenuBar(self, accelGroup):
703 """Build the main menu bar."""
704 menuBar = gtk.MenuBar()
705
706 fileMenuItem = gtk.MenuItem(xstr("menu_file"))
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)
713 quitMenuItem.set_label(xstr("menu_file_quit"))
714 quitMenuItem.add_accelerator("activate", accelGroup,
715 ord(xstr("menu_file_quit_key")),
716 CONTROL_MASK, ACCEL_VISIBLE)
717 quitMenuItem.connect("activate", self._quit)
718 fileMenu.append(quitMenuItem)
719
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)
733
734 viewMenuItem = gtk.MenuItem(xstr("menu_view"))
735 viewMenu = gtk.Menu()
736 viewMenuItem.set_submenu(viewMenu)
737 menuBar.append(viewMenuItem)
738
739 self._showMonitorMenuItem = gtk.CheckMenuItem()
740 self._showMonitorMenuItem.set_label(xstr("menu_view_monitor"))
741 self._showMonitorMenuItem.set_use_underline(True)
742 self._showMonitorMenuItem.set_active(False)
743 self._showMonitorMenuItem.add_accelerator("activate", accelGroup,
744 ord(xstr("menu_view_monitor_key")),
745 CONTROL_MASK, ACCEL_VISIBLE)
746 self._showMonitorMenuItem.connect("toggled", self._toggleMonitorWindow)
747 viewMenu.append(self._showMonitorMenuItem)
748
749 showDebugMenuItem = gtk.CheckMenuItem()
750 showDebugMenuItem.set_label(xstr("menu_view_debug"))
751 showDebugMenuItem.set_use_underline(True)
752 showDebugMenuItem.set_active(False)
753 showDebugMenuItem.add_accelerator("activate", accelGroup,
754 ord(xstr("menu_view_debug_key")),
755 CONTROL_MASK, ACCEL_VISIBLE)
756 showDebugMenuItem.connect("toggled", self._toggleDebugLog)
757 viewMenu.append(showDebugMenuItem)
758
759 return menuBar
760
761 def _toggleDebugLog(self, menuItem):
762 """Toggle the debug log."""
763 if menuItem.get_active():
764 label = gtk.Label(xstr("tab_debug_log"))
765 label.set_use_underline(True)
766 label.set_tooltip_text(xstr("tab_debug_log_tooltip"))
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)
778
779 logScroller = gtk.ScrolledWindow()
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)
790
791 logBox = gtk.VBox()
792 logBox.pack_start(logScroller, True, True, 0)
793 logBox.set_size_request(-1, 200)
794
795 alignment.add(logBox)
796
797 return (alignment, logView)
798
799 def _writeLog(self, msg, logView):
800 """Write the given message to the log."""
801 buffer = logView.get_buffer()
802 buffer.insert(buffer.get_end_iter(), msg)
803 logView.scroll_mark_onscreen(buffer.get_insert())
804
805 def _quit(self, what = None, force = False):
806 """Quit from the application."""
807 if force:
808 result=RESPONSETYPE_YES
809 else:
810 dialog = gtk.MessageDialog(parent = self._mainWindow,
811 type = MESSAGETYPE_QUESTION,
812 message_format = xstr("quit_question"))
813
814 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
815 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
816
817 dialog.set_title(WINDOW_TITLE_BASE)
818 result = dialog.run()
819 dialog.hide()
820
821 if result==RESPONSETYPE_YES:
822 self._statusIcon.destroy()
823 return gtk.main_quit()
824
825 def _notebookPageSwitch(self, notebook, page, page_num):
826 """Called when the current page of the notebook has changed."""
827 if page_num==0:
828 gobject.idle_add(self._wizard.grabDefault)
829 else:
830 self._mainWindow.set_default(None)
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.