source: src/mlx/gui/gui.py@ 133:dcbe33497899

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

The general message sending works and the most important messages are sent

File size: 28.7 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 fs.sendMessage(const.MESSAGETYPE_INFORMATION,
301 "Welcome to MAVA Logger X " + const.VERSION)
302 gobject.idle_add(self._handleConnected, fsType, descriptor)
303
304 def _handleConnected(self, fsType, descriptor):
305 """Called when the connection to the simulator has succeeded."""
306 self._statusbar.updateConnection(self._connecting, self._connected)
307 self.endBusy()
308 if not self._reconnecting:
309 self._wizard.connected(fsType, descriptor)
310 self._reconnecting = False
311
312 def connectionFailed(self):
313 """Called when the connection failed."""
314 self._logger.untimedMessage("Connection to the simulator failed")
315 gobject.idle_add(self._connectionFailed)
316
317 def _connectionFailed(self):
318 """Called when the connection failed."""
319 self.endBusy()
320 self._statusbar.updateConnection(self._connecting, self._connected)
321
322 dialog = gtk.MessageDialog(parent = self._mainWindow,
323 type = MESSAGETYPE_ERROR,
324 message_format = xstr("conn_failed"))
325
326 dialog.set_title(WINDOW_TITLE_BASE)
327 dialog.format_secondary_markup(xstr("conn_failed_sec"))
328
329 dialog.add_button(xstr("button_cancel"), 0)
330 dialog.add_button(xstr("button_tryagain"), 1)
331 dialog.set_default_response(1)
332
333 result = dialog.run()
334 dialog.hide()
335 if result == 1:
336 self.beginBusy(xstr("connect_busy"))
337 self._simulator.reconnect()
338 else:
339 self.reset()
340
341 def disconnected(self):
342 """Called when we have disconnected from the simulator."""
343 self._connected = False
344 self._logger.untimedMessage("Disconnected from the simulator")
345
346 gobject.idle_add(self._disconnected)
347
348 def _disconnected(self):
349 """Called when we have disconnected from the simulator unexpectedly."""
350 self._statusbar.updateConnection(self._connecting, self._connected)
351
352 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
353 message_format = xstr("conn_broken"),
354 parent = self._mainWindow)
355 dialog.set_title(WINDOW_TITLE_BASE)
356 dialog.format_secondary_markup(xstr("conn_broken_sec"))
357
358 dialog.add_button(xstr("button_cancel"), 0)
359 dialog.add_button(xstr("button_reconnect"), 1)
360 dialog.set_default_response(1)
361
362 result = dialog.run()
363 dialog.hide()
364 if result == 1:
365 self.beginBusy(xstr("connect_busy"))
366 self._reconnecting = True
367 self._simulator.reconnect()
368 else:
369 self.reset()
370
371 def enableFlightInfo(self):
372 """Enable the flight info tab."""
373 self._flightInfo.enable()
374
375 def reset(self):
376 """Reset the GUI."""
377 self._disconnect()
378
379 self._flightInfo.reset()
380 self._flightInfo.disable()
381 self.resetFlightStatus()
382
383 self._weightHelp.reset()
384 self._weightHelp.disable()
385 self._wizard.reset()
386 self._notebook.set_current_page(0)
387
388 self._logView.get_buffer().set_text("")
389
390 def _disconnect(self):
391 """Disconnect from the simulator if connected."""
392 self.stopMonitoring()
393
394 if self._connected:
395 self._flight.simulator.disconnect()
396 self._connected = False
397
398 self._connecting = False
399 self._reconnecting = False
400 self._statusbar.updateConnection(False, False)
401 self._weightHelp.disable()
402
403 def addFlightLogLine(self, timeStr, line):
404 """Write the given message line to the log."""
405 gobject.idle_add(self._writeLog,
406 GUI._formatFlightLogLine(timeStr, line),
407 self._logView)
408
409 def updateFlightLogLine(self, index, timeStr, line):
410 """Update the line with the given index."""
411 gobject.idle_add(self._updateFlightLogLine, index,
412 GUI._formatFlightLogLine(timeStr, line))
413
414 def _updateFlightLogLine(self, index, line):
415 """Replace the contents of the given line in the log."""
416 buffer = self._logView.get_buffer()
417 startIter = buffer.get_iter_at_line(index)
418 endIter = buffer.get_iter_at_line(index + 1)
419 buffer.delete(startIter, endIter)
420 buffer.insert(startIter, line)
421 self._logView.scroll_mark_onscreen(buffer.get_insert())
422
423 def check(self, flight, aircraft, logger, oldState, state):
424 """Update the data."""
425 gobject.idle_add(self._monitorWindow.setData, state)
426 gobject.idle_add(self._statusbar.updateTime, state.timestamp)
427
428 def resetFlightStatus(self):
429 """Reset the status of the flight."""
430 self._statusbar.resetFlightStatus()
431 self._statusbar.updateTime()
432 self._statusIcon.resetFlightStatus()
433
434 def setStage(self, stage):
435 """Set the stage of the flight."""
436 gobject.idle_add(self._setStage, stage)
437
438 def _setStage(self, stage):
439 """Set the stage of the flight."""
440 self._statusbar.setStage(stage)
441 self._statusIcon.setStage(stage)
442 self._wizard.setStage(stage)
443 if stage==const.STAGE_END:
444 self._disconnect()
445
446 def setRating(self, rating):
447 """Set the rating of the flight."""
448 gobject.idle_add(self._setRating, rating)
449
450 def _setRating(self, rating):
451 """Set the rating of the flight."""
452 self._statusbar.setRating(rating)
453 self._statusIcon.setRating(rating)
454
455 def setNoGo(self, reason):
456 """Set the rating of the flight to No-Go with the given reason."""
457 gobject.idle_add(self._setNoGo, reason)
458
459 def _setNoGo(self, reason):
460 """Set the rating of the flight."""
461 self._statusbar.setNoGo(reason)
462 self._statusIcon.setNoGo(reason)
463
464 def _handleMainWindowState(self, window, event):
465 """Hande a change in the state of the window"""
466 iconified = gdk.WindowState.ICONIFIED if pygobject \
467 else gdk.WINDOW_STATE_ICONIFIED
468 if (event.changed_mask&iconified)!=0 and (event.new_window_state&iconified)!=0:
469 self.hideMainWindow(savePosition = False)
470
471 def hideMainWindow(self, savePosition = True):
472 """Hide the main window and save its position."""
473 if savePosition:
474 (self._mainWindowX, self._mainWindowY) = \
475 self._mainWindow.get_window().get_root_origin()
476 else:
477 self._mainWindowX = self._mainWindowY = None
478 self._mainWindow.hide()
479 self._statusIcon.mainWindowHidden()
480 return True
481
482 def showMainWindow(self):
483 """Show the main window at its former position."""
484 if self._mainWindowX is not None and self._mainWindowY is not None:
485 self._mainWindow.move(self._mainWindowX, self._mainWindowY)
486
487 self._mainWindow.show()
488 self._mainWindow.deiconify()
489
490 self._statusIcon.mainWindowShown()
491
492 def toggleMainWindow(self):
493 """Toggle the main window."""
494 if self._mainWindow.get_visible():
495 self.hideMainWindow()
496 else:
497 self.showMainWindow()
498
499 def hideMonitorWindow(self, savePosition = True):
500 """Hide the monitor window."""
501 if savePosition:
502 (self._monitorWindowX, self._monitorWindowY) = \
503 self._monitorWindow.get_window().get_root_origin()
504 else:
505 self._monitorWindowX = self._monitorWindowY = None
506 self._monitorWindow.hide()
507 self._statusIcon.monitorWindowHidden()
508 if self._showMonitorMenuItem.get_active():
509 self._selfToggling = True
510 self._showMonitorMenuItem.set_active(False)
511 return True
512
513 def showMonitorWindow(self):
514 """Show the monitor window."""
515 if self._monitorWindowX is not None and self._monitorWindowY is not None:
516 self._monitorWindow.move(self._monitorWindowX, self._monitorWindowY)
517 self._monitorWindow.show_all()
518 self._statusIcon.monitorWindowShown()
519 if not self._showMonitorMenuItem.get_active():
520 self._selfToggling = True
521 self._showMonitorMenuItem.set_active(True)
522
523 def _toggleMonitorWindow(self, menuItem):
524 if self._selfToggling:
525 self._selfToggling = False
526 elif self._monitorWindow.get_visible():
527 self.hideMonitorWindow()
528 else:
529 self.showMonitorWindow()
530
531 def restart(self):
532 """Quit and restart the application."""
533 self.toRestart = True
534 self._quit(force = True)
535
536 def flushStdIO(self):
537 """Flush any text to the standard error that could not be logged."""
538 if self._stdioText:
539 sys.__stderr__.write(self._stdioText)
540
541 def writeStdIO(self, text):
542 """Write the given text into standard I/O log."""
543 with self._stdioLock:
544 self._stdioText += text
545
546 gobject.idle_add(self._writeStdIO)
547
548 def beginBusy(self, message):
549 """Begin a period of background processing."""
550 self._wizard.set_sensitive(False)
551 self._weightHelp.set_sensitive(False)
552 self._mainWindow.get_window().set_cursor(self._busyCursor)
553 self._statusbar.updateBusyState(message)
554
555 def endBusy(self):
556 """End a period of background processing."""
557 self._mainWindow.get_window().set_cursor(None)
558 self._weightHelp.set_sensitive(True)
559 self._wizard.set_sensitive(True)
560 self._statusbar.updateBusyState(None)
561
562 def initializeWeightHelp(self):
563 """Initialize the weight help tab."""
564 self._weightHelp.reset()
565 self._weightHelp.enable()
566
567 def getFleet(self, callback = None, force = False):
568 """Get the fleet.
569
570 If force is False, and we already have a fleet retrieved,
571 that one will be used."""
572 if self._fleet is None or force:
573 self._fleetCallback = callback
574 self.beginBusy(xstr("fleet_busy"))
575 self.webHandler.getFleet(self._fleetResultCallback)
576 else:
577 callback(self._fleet)
578
579 def _fleetResultCallback(self, returned, result):
580 """Called when the fleet has been queried."""
581 gobject.idle_add(self._handleFleetResult, returned, result)
582
583 def _handleFleetResult(self, returned, result):
584 """Handle the fleet result."""
585 self.endBusy()
586 if returned:
587 self._fleet = result.fleet
588 else:
589 self._fleet = None
590
591 dialog = gtk.MessageDialog(parent = self.mainWindow,
592 type = MESSAGETYPE_ERROR,
593 message_format = xstr("fleet_failed"))
594 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
595 dialog.set_title(WINDOW_TITLE_BASE)
596 dialog.run()
597 dialog.hide()
598
599 callback = self._fleetCallback
600 self._fleetCallback = None
601 if callback is not None:
602 callback(self._fleet)
603 self._fleetGateStatus.handleFleet(self._fleet)
604
605 def updatePlane(self, tailNumber, status,
606 gateNumber = None, callback = None):
607 """Update the status of the given plane."""
608 self.beginBusy(xstr("fleet_update_busy"))
609
610 self._updatePlaneCallback = callback
611
612 self._updatePlaneTailNumber = tailNumber
613 self._updatePlaneStatus = status
614 self._updatePlaneGateNumber = gateNumber
615
616 self.webHandler.updatePlane(self._updatePlaneResultCallback,
617 tailNumber, status, gateNumber)
618
619 def _updatePlaneResultCallback(self, returned, result):
620 """Called when the status of a plane has been updated."""
621 gobject.idle_add(self._handleUpdatePlaneResult, returned, result)
622
623 def _handleUpdatePlaneResult(self, returned, result):
624 """Handle the plane update result."""
625 self.endBusy()
626 if returned:
627 success = result.success
628 if success:
629 if self._fleet is not None:
630 self._fleet.updatePlane(self._updatePlaneTailNumber,
631 self._updatePlaneStatus,
632 self._updatePlaneGateNumber)
633 self._fleetGateStatus.handleFleet(self._fleet)
634 else:
635 dialog = gtk.MessageDialog(parent = self.mainWindow,
636 type = MESSAGETYPE_ERROR,
637 message_format = xstr("fleet_update_failed"))
638 dialog.add_button(xstr("button_ok"), RESPONSETYPE_ACCEPT)
639 dialog.set_title(WINDOW_TITLE_BASE)
640 dialog.run()
641 dialog.hide()
642
643 success = None
644
645 callback = self._updatePlaneCallback
646 self._updatePlaneCallback = None
647 if callback is not None:
648 callback(success)
649
650 def _writeStdIO(self):
651 """Perform the real writing."""
652 with self._stdioLock:
653 text = self._stdioText
654 self._stdioText = ""
655 if not text: return
656
657 lines = text.splitlines()
658 if text[-1]=="\n":
659 text = ""
660 else:
661 text = lines[-1]
662 lines = lines[:-1]
663
664 for line in lines:
665 #print >> sys.__stdout__, line
666 self._writeLog(line + "\n", self._debugLogView)
667
668 if text:
669 #print >> sys.__stdout__, text,
670 self._writeLog(text, self._debugLogView)
671
672 def connectSimulator(self, aircraftType):
673 """Connect to the simulator for the first time."""
674 self._logger.reset()
675
676 self._flight = flight.Flight(self._logger, self)
677 self._flight.flareTimeFromFS = self.config.flareTimeFromFS
678 self._flight.aircraftType = aircraftType
679 self._flight.aircraft = acft.Aircraft.create(self._flight)
680 self._flight.aircraft._checkers.append(self)
681
682 if self._simulator is None:
683 self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
684 fs.setupMessageSending(self.config, self._simulator)
685
686 self._flight.simulator = self._simulator
687
688 self.beginBusy(xstr("connect_busy"))
689 self._statusbar.updateConnection(self._connecting, self._connected)
690
691 self._connecting = True
692 self._simulator.connect(self._flight.aircraft)
693
694 def startMonitoring(self):
695 """Start monitoring."""
696 if not self._monitoring:
697 self.simulator.startMonitoring()
698 self._monitoring = True
699
700 def stopMonitoring(self):
701 """Stop monitoring."""
702 if self._monitoring:
703 self.simulator.stopMonitoring()
704 self._monitoring = False
705
706 def _buildMenuBar(self, accelGroup):
707 """Build the main menu bar."""
708 menuBar = gtk.MenuBar()
709
710 fileMenuItem = gtk.MenuItem(xstr("menu_file"))
711 fileMenu = gtk.Menu()
712 fileMenuItem.set_submenu(fileMenu)
713 menuBar.append(fileMenuItem)
714
715 quitMenuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
716 quitMenuItem.set_use_stock(True)
717 quitMenuItem.set_label(xstr("menu_file_quit"))
718 quitMenuItem.add_accelerator("activate", accelGroup,
719 ord(xstr("menu_file_quit_key")),
720 CONTROL_MASK, ACCEL_VISIBLE)
721 quitMenuItem.connect("activate", self._quit)
722 fileMenu.append(quitMenuItem)
723
724 toolsMenuItem = gtk.MenuItem(xstr("menu_tools"))
725 toolsMenu = gtk.Menu()
726 toolsMenuItem.set_submenu(toolsMenu)
727 menuBar.append(toolsMenuItem)
728
729 prefsMenuItem = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
730 prefsMenuItem.set_use_stock(True)
731 prefsMenuItem.set_label(xstr("menu_tools_prefs"))
732 prefsMenuItem.add_accelerator("activate", accelGroup,
733 ord(xstr("menu_tools_prefs_key")),
734 CONTROL_MASK, ACCEL_VISIBLE)
735 prefsMenuItem.connect("activate", self._editPreferences)
736 toolsMenu.append(prefsMenuItem)
737
738 viewMenuItem = gtk.MenuItem(xstr("menu_view"))
739 viewMenu = gtk.Menu()
740 viewMenuItem.set_submenu(viewMenu)
741 menuBar.append(viewMenuItem)
742
743 self._showMonitorMenuItem = gtk.CheckMenuItem()
744 self._showMonitorMenuItem.set_label(xstr("menu_view_monitor"))
745 self._showMonitorMenuItem.set_use_underline(True)
746 self._showMonitorMenuItem.set_active(False)
747 self._showMonitorMenuItem.add_accelerator("activate", accelGroup,
748 ord(xstr("menu_view_monitor_key")),
749 CONTROL_MASK, ACCEL_VISIBLE)
750 self._showMonitorMenuItem.connect("toggled", self._toggleMonitorWindow)
751 viewMenu.append(self._showMonitorMenuItem)
752
753 showDebugMenuItem = gtk.CheckMenuItem()
754 showDebugMenuItem.set_label(xstr("menu_view_debug"))
755 showDebugMenuItem.set_use_underline(True)
756 showDebugMenuItem.set_active(False)
757 showDebugMenuItem.add_accelerator("activate", accelGroup,
758 ord(xstr("menu_view_debug_key")),
759 CONTROL_MASK, ACCEL_VISIBLE)
760 showDebugMenuItem.connect("toggled", self._toggleDebugLog)
761 viewMenu.append(showDebugMenuItem)
762
763 return menuBar
764
765 def _toggleDebugLog(self, menuItem):
766 """Toggle the debug log."""
767 if menuItem.get_active():
768 label = gtk.Label(xstr("tab_debug_log"))
769 label.set_use_underline(True)
770 label.set_tooltip_text(xstr("tab_debug_log_tooltip"))
771 self._debugLogPage = self._notebook.append_page(self._debugLogWidget, label)
772 self._notebook.set_current_page(self._debugLogPage)
773 else:
774 self._notebook.remove_page(self._debugLogPage)
775
776 def _buildLogWidget(self):
777 """Build the widget for the log."""
778 alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
779
780 alignment.set_padding(padding_top = 8, padding_bottom = 8,
781 padding_left = 16, padding_right = 16)
782
783 logScroller = gtk.ScrolledWindow()
784 # FIXME: these should be constants in common
785 logScroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
786 else gtk.POLICY_AUTOMATIC,
787 gtk.PolicyType.AUTOMATIC if pygobject
788 else gtk.POLICY_AUTOMATIC)
789 logScroller.set_shadow_type(gtk.ShadowType.IN if pygobject
790 else gtk.SHADOW_IN)
791 logView = gtk.TextView()
792 logView.set_editable(False)
793 logScroller.add(logView)
794
795 logBox = gtk.VBox()
796 logBox.pack_start(logScroller, True, True, 0)
797 logBox.set_size_request(-1, 200)
798
799 alignment.add(logBox)
800
801 return (alignment, logView)
802
803 def _writeLog(self, msg, logView):
804 """Write the given message to the log."""
805 buffer = logView.get_buffer()
806 buffer.insert(buffer.get_end_iter(), msg)
807 logView.scroll_mark_onscreen(buffer.get_insert())
808
809 def _quit(self, what = None, force = False):
810 """Quit from the application."""
811 if force:
812 result=RESPONSETYPE_YES
813 else:
814 dialog = gtk.MessageDialog(parent = self._mainWindow,
815 type = MESSAGETYPE_QUESTION,
816 message_format = xstr("quit_question"))
817
818 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
819 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
820
821 dialog.set_title(WINDOW_TITLE_BASE)
822 result = dialog.run()
823 dialog.hide()
824
825 if result==RESPONSETYPE_YES:
826 self._statusIcon.destroy()
827 return gtk.main_quit()
828
829 def _notebookPageSwitch(self, notebook, page, page_num):
830 """Called when the current page of the notebook has changed."""
831 if page_num==0:
832 gobject.idle_add(self._wizard.grabDefault)
833 else:
834 self._mainWindow.set_default(None)
835
836 def _editPreferences(self, menuItem):
837 """Callback for editing the preferences."""
838 self._preferences.run(self.config)
Note: See TracBrowser for help on using the repository browser.