source: src/mlx/gui/gui.py@ 71:2dba0ba6cd1b

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

Added the takeoff page.

File size: 34.0 KB
Line 
1# The main file for the GUI
2
3from statusicon import StatusIcon
4from statusbar import Statusbar
5from update import Updater
6from mlx.gui.common import *
7from mlx.gui.flight import Wizard
8
9import mlx.const as const
10import mlx.fs as fs
11import mlx.flight as flight
12import mlx.logger as logger
13import mlx.acft as acft
14import mlx.web as web
15
16import time
17import threading
18import sys
19
20acftTypes = [ ("Boeing 737-600", const.AIRCRAFT_B736),
21 ("Boeing 737-700", const.AIRCRAFT_B737),
22 ("Boeing 737-800", const.AIRCRAFT_B738),
23 ("Bombardier Dash 8-Q400", const.AIRCRAFT_DH8D),
24 ("Boeing 737-300", const.AIRCRAFT_B733),
25 ("Boeing 737-400", const.AIRCRAFT_B734),
26 ("Boeing 737-500", const.AIRCRAFT_B735),
27 ("Boeing 767-200", const.AIRCRAFT_B762),
28 ("Boeing 767-300", const.AIRCRAFT_B763),
29 ("Bombardier CRJ200", const.AIRCRAFT_CRJ2),
30 ("Fokker 70", const.AIRCRAFT_F70),
31 ("Lisunov Li-2", const.AIRCRAFT_DC3),
32 ("Tupolev Tu-134", const.AIRCRAFT_T134),
33 ("Tupolev Tu-154", const.AIRCRAFT_T154),
34 ("Yakovlev Yak-40", const.AIRCRAFT_YK40) ]
35
36class GUI(fs.ConnectionListener):
37 """The main GUI class."""
38 def __init__(self, programDirectory, config):
39 """Construct the GUI."""
40 gobject.threads_init()
41
42 self._programDirectory = programDirectory
43 self.config = config
44 self._connecting = False
45 self._reconnecting = False
46 self._connected = False
47 self._logger = logger.Logger(output = self)
48 self._flight = None
49 self._simulator = None
50 self._monitoring = False
51
52 self._stdioLock = threading.Lock()
53 self._stdioText = ""
54 self._stdioAfterNewLine = True
55
56 self.webHandler = web.Handler()
57 self.webHandler.start()
58
59 self.toRestart = False
60
61 def build(self, iconDirectory):
62 """Build the GUI."""
63
64 window = gtk.Window()
65 window.set_title("MAVA Logger X " + const.VERSION)
66 window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
67 window.connect("delete-event",
68 lambda a, b: self.hideMainWindow())
69 window.connect("window-state-event", self._handleMainWindowState)
70
71 mainVBox = gtk.VBox()
72 window.add(mainVBox)
73
74 notebook = gtk.Notebook()
75 mainVBox.add(notebook)
76
77 self._wizard = Wizard(self)
78 label = gtk.Label("_Flight")
79 label.set_use_underline(True)
80 label.set_tooltip_text("Flight wizard")
81 notebook.append_page(self._wizard, label)
82
83 dataVBox = gtk.VBox()
84 label = gtk.Label("_Data")
85 label.set_use_underline(True)
86 label.set_tooltip_text("FSUIPC data access")
87
88 if "USE_SCROLLEDDATA" in os.environ:
89 dataScrolledWindow = gtk.ScrolledWindow()
90 dataScrolledWindow.add_with_viewport(dataVBox)
91 notebook.append_page(dataScrolledWindow, label)
92 else:
93 notebook.append_page(dataVBox, label)
94
95 setupFrame = self._buildSetupFrame()
96 setupFrame.set_border_width(8)
97 dataVBox.pack_start(setupFrame, False, False, 0)
98
99 dataFrame = self._buildDataFrame()
100 dataFrame.set_border_width(8)
101 dataVBox.pack_start(dataFrame, False, False, 0)
102
103 logVBox = gtk.VBox()
104 label = gtk.Label("_Log")
105 label.set_use_underline(True)
106 label.set_tooltip_text("Flight log")
107 notebook.append_page(logVBox, label)
108
109 logFrame = self._buildLogFrame()
110 logFrame.set_border_width(8)
111 logVBox.pack_start(logFrame, True, True, 0)
112
113 mainVBox.pack_start(gtk.HSeparator(), False, False, 0)
114
115 self._statusbar = Statusbar()
116 mainVBox.pack_start(self._statusbar, False, False, 0)
117
118 notebook.connect("switch-page", self._notebookPageSwitch)
119
120 window.show_all()
121 self._wizard.grabDefault()
122
123 self._mainWindow = window
124
125 self._statusIcon = StatusIcon(iconDirectory, self)
126
127 self._busyCursor = gdk.Cursor(gdk.CursorType.WATCH if pygobject
128 else gdk.WATCH)
129
130 @property
131 def simulator(self):
132 """Get the simulator used by us."""
133 return self._simulator
134
135 @property
136 def flight(self):
137 """Get the flight being performed."""
138 return self._flight
139
140 def run(self):
141 """Run the GUI."""
142 if self.config.autoUpdate:
143 self._updater = Updater(self,
144 self._programDirectory,
145 self.config.updateURL,
146 self._mainWindow)
147 self._updater.start()
148
149 gtk.main()
150
151 if self._flight is not None:
152 simulator = self._flight.simulator
153 if self._monitoring:
154 simulator.stopMonitoring()
155 self._monitoring = False
156 simulator.disconnect()
157
158 def connected(self, fsType, descriptor):
159 """Called when we have connected to the simulator."""
160 self._connected = True
161 self._logger.untimedMessage("Connected to the simulator %s" % (descriptor,))
162 gobject.idle_add(self._handleConnected, fsType, descriptor)
163
164 def _handleConnected(self, fsType, descriptor):
165 """Called when the connection to the simulator has succeeded."""
166 self._statusbar.updateConnection(self._connecting, self._connected)
167 self.endBusy()
168 if not self._reconnecting:
169 self._wizard.connected(fsType, descriptor)
170 self._reconnecting = False
171
172 def connectionFailed(self):
173 """Called when the connection failed."""
174 self._logger.untimedMessage("Connection to the simulator failed")
175 gobject.idle_add(self._connectionFailed)
176
177 def _connectionFailed(self):
178 """Called when the connection failed."""
179 self.endBusy()
180 self._statusbar.updateConnection(self._connecting, self._connected)
181
182 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
183 message_format =
184 "Cannot connect to the simulator.",
185 parent = self._mainWindow)
186 dialog.format_secondary_markup("Rectify the situation, and press <b>Try again</b> "
187 "to try the connection again, "
188 "or <b>Cancel</b> to cancel the flight.")
189
190 dialog.add_button("_Cancel", 0)
191 dialog.add_button("_Try again", 1)
192 dialog.set_default_response(1)
193
194 result = dialog.run()
195 dialog.hide()
196 if result == 1:
197 self.beginBusy("Connecting to the simulator.")
198 self._simulator.reconnect()
199 else:
200 self._connecting = False
201 self._reconnecting = False
202 self._statusbar.updateConnection(self._connecting, self._connected)
203 self._wizard.connectionFailed()
204
205 def disconnected(self):
206 """Called when we have disconnected from the simulator."""
207 self._connected = False
208 self._logger.untimedMessage("Disconnected from the simulator")
209
210 gobject.idle_add(self._disconnected)
211
212 def _disconnected(self):
213 """Called when we have disconnected from the simulator unexpectedly."""
214 self._statusbar.updateConnection(self._connecting, self._connected)
215
216 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
217 message_format =
218 "The connection to the simulator failed unexpectedly.",
219 parent = self._mainWindow)
220 dialog.format_secondary_markup("If the simulator has crashed, restart it "
221 "and restore your flight as much as possible "
222 "to the state it was in before the crash.\n"
223 "Then press <b>Reconnect</b> to reconnect.\n\n"
224 "If you want to cancel the flight, press <b>Cancel</b>.")
225
226 dialog.add_button("_Cancel", 0)
227 dialog.add_button("_Reconnect", 1)
228 dialog.set_default_response(1)
229
230 result = dialog.run()
231 dialog.hide()
232 if result == 1:
233 self.beginBusy("Connecting to the simulator.")
234 self._reconnecting = True
235 self._simulator.reconnect()
236 else:
237 self._connecting = False
238 self._reconnecting = False
239 self._statusbar.updateConnection(self._connecting, self._connected)
240 self._wizard.disconnected()
241
242 def write(self, msg):
243 """Write the given message to the log."""
244 gobject.idle_add(self._writeLog, msg)
245
246 def check(self, flight, aircraft, logger, oldState, state):
247 """Update the data."""
248 gobject.idle_add(self._setData, state)
249
250 def resetFlightStatus(self):
251 """Reset the status of the flight."""
252 self._statusbar.resetFlightStatus()
253 self._statusIcon.resetFlightStatus()
254
255 def setStage(self, stage):
256 """Set the stage of the flight."""
257 gobject.idle_add(self._setStage, stage)
258
259 def _setStage(self, stage):
260 """Set the stage of the flight."""
261 self._statusbar.setStage(stage)
262 self._statusIcon.setStage(stage)
263
264 def setRating(self, rating):
265 """Set the rating of the flight."""
266 gobject.idle_add(self._setRating, rating)
267
268 def _setRating(self, rating):
269 """Set the rating of the flight."""
270 self._statusbar.setRating(rating)
271 self._statusIcon.setRating(rating)
272
273 def setNoGo(self, reason):
274 """Set the rating of the flight to No-Go with the given reason."""
275 gobject.idle_add(self._setNoGo, reason)
276
277 def _setNoGo(self, reason):
278 """Set the rating of the flight."""
279 self._statusbar.setNoGo(reason)
280 self._statusIcon.setNoGo(reason)
281
282 def _handleMainWindowState(self, window, event):
283 """Hande a change in the state of the window"""
284 iconified = gdk.WindowState.ICONIFIED if pygobject \
285 else gdk.WINDOW_STATE_ICONIFIED
286 if (event.changed_mask&iconified)!=0 and (event.new_window_state&iconified)!=0:
287 self.hideMainWindow(savePosition = False)
288
289 def hideMainWindow(self, savePosition = True):
290 """Hide the main window and save its position."""
291 if savePosition:
292 (self._mainWindowX, self._mainWindowY) = \
293 self._mainWindow.get_window().get_root_origin()
294 else:
295 self._mainWindowX = self._mainWindowY = None
296 self._mainWindow.hide()
297 self._statusIcon.mainWindowHidden()
298 return True
299
300 def showMainWindow(self):
301 """Show the main window at its former position."""
302 if self._mainWindowX is not None and self._mainWindowY is not None:
303 self._mainWindow.move(self._mainWindowX, self._mainWindowY)
304
305 self._mainWindow.show()
306 self._mainWindow.deiconify()
307
308 self._statusIcon.mainWindowShown()
309
310 def toggleMainWindow(self):
311 """Toggle the main window."""
312 if self._mainWindow.get_visible():
313 self.hideMainWindow()
314 else:
315 self.showMainWindow()
316
317 def restart(self):
318 """Quit and restart the application."""
319 self.toRestart = True
320 self._quit()
321
322 def flushStdIO(self):
323 """Flush any text to the standard error that could not be logged."""
324 if self._stdioText:
325 sys.__stderr__.write(self._stdioText)
326
327 def writeStdIO(self, text):
328 """Write the given text into standard I/O log."""
329 with self._stdioLock:
330 self._stdioText += text
331
332 gobject.idle_add(self._writeStdIO)
333
334 def beginBusy(self, message):
335 """Begin a period of background processing."""
336 self._mainWindow.get_window().set_cursor(self._busyCursor)
337 self._statusbar.updateBusyState(message)
338
339 def endBusy(self):
340 """End a period of background processing."""
341 self._mainWindow.get_window().set_cursor(None)
342 self._statusbar.updateBusyState(None)
343
344 def _writeStdIO(self):
345 """Perform the real writing."""
346 with self._stdioLock:
347 text = self._stdioText
348 self._stdioText = ""
349 if not text: return
350
351 lines = text.splitlines()
352 if text[-1]=="\n":
353 text = ""
354 else:
355 text = lines[-1]
356 lines = lines[:-1]
357
358 for line in lines:
359 if self._stdioAfterNewLine:
360 line = "[STDIO] " + line
361 self._writeLog(line + "\n")
362 self._stdioAfterNewLine = True
363
364 if text:
365 if self._stdioAfterNewLine:
366 text = "[STDIO] " + text
367 self._writeLog(text)
368 self._stdioAfterNewLine = False
369
370 def connectSimulator(self, aircraftType):
371 """Connect to the simulator for the first time."""
372 self._logger.reset()
373
374 self._flight = flight.Flight(self._logger, self)
375 self._flight.aircraftType = aircraftType
376 self._flight.aircraft = acft.Aircraft.create(self._flight)
377 self._flight.aircraft._checkers.append(self)
378
379 if self._simulator is None:
380 self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
381
382 self._flight.simulator = self._simulator
383
384 self.beginBusy("Connecting to the simulator...")
385 self._statusbar.updateConnection(self._connecting, self._connected)
386
387 self._connecting = True
388 self._simulator.connect(self._flight.aircraft)
389
390 def _connectToggled(self, button):
391 """Callback for the connection button."""
392 if self._connectButton.get_active():
393 acftListModel = self._acftList.get_model()
394 self.connectSimulator(acftListModel[self._acftList.get_active()][1])
395
396 self._flight.cruiseAltitude = self._flSpinButton.get_value_as_int() * 100
397
398 self._flight.zfw = self._zfwSpinButton.get_value_as_int()
399
400 self.startMonitoring()
401 else:
402 self.resetFlightStatus()
403 self._connecting = False
404 self._connected = False
405
406 self._simulator.stopMonitoring()
407 self._monitoring = False
408
409 self._simulator.disconnect()
410 self._flight = None
411
412 self._statusbar.updateConnection(self._connecting, self._connected)
413
414 def startMonitoring(self):
415 """Start monitoring."""
416 self._simulator.startMonitoring()
417 self._monitoring = True
418
419 def stopMonitoring(self):
420 """Stop monitoring."""
421 self._simulator.stoptMonitoring()
422 self._monitoring = False
423
424 def _buildSetupFrame(self):
425 """Build the setup frame."""
426 setupFrame = gtk.Frame(label = "Setup")
427
428 frameAlignment = gtk.Alignment(xalign = 0.5)
429
430 frameAlignment.set_padding(padding_top = 4, padding_bottom = 10,
431 padding_left = 16, padding_right = 16)
432
433 setupFrame.add(frameAlignment)
434
435 setupBox = gtk.HBox()
436 frameAlignment.add(setupBox)
437
438 # self._fs9Button = gtk.RadioButton(label = "FS9")
439 # self._fs9Button.set_tooltip_text("Use MS Flight Simulator 2004")
440 # setupBox.pack_start(self._fs9Button, False, False, 0)
441
442 # self._fsxButton = gtk.RadioButton(group = self._fs9Button, label = "FSX")
443 # self._fsxButton.set_tooltip_text("Use MS Flight Simulator X")
444 # setupBox.pack_start(self._fsxButton, False, False, 0)
445
446 # setupBox.pack_start(gtk.VSeparator(), False, False, 8)
447
448 alignment = gtk.Alignment(yalign = 0.5)
449 alignment.set_padding(padding_top = 0, padding_bottom = 0,
450 padding_left = 0, padding_right = 16)
451 alignment.add(gtk.Label("Aicraft:"))
452 setupBox.pack_start(alignment, False, False, 0)
453
454 acftListModel = gtk.ListStore(str, int)
455 for (name, type) in acftTypes:
456 acftListModel.append([name, type])
457
458 self._acftList = gtk.ComboBox(model = acftListModel)
459 renderer_text = gtk.CellRendererText()
460 self._acftList.pack_start(renderer_text, True)
461 self._acftList.add_attribute(renderer_text, "text", 0)
462 self._acftList.set_active(0)
463 self._acftList.set_tooltip_text("Select the type of the aircraft used for the flight.")
464
465 setupBox.pack_start(self._acftList, True, True, 0)
466
467 setupBox.pack_start(gtk.VSeparator(), False, False, 8)
468
469 alignment = gtk.Alignment(yalign = 0.5)
470 alignment.set_padding(padding_top = 0, padding_bottom = 0,
471 padding_left = 0, padding_right = 16)
472 alignment.add(gtk.Label("Cruise FL:"))
473 setupBox.pack_start(alignment, False, False, 0)
474
475 self._flSpinButton = gtk.SpinButton()
476 self._flSpinButton.set_increments(step = 10, page = 100)
477 self._flSpinButton.set_range(min = 0, max = 500)
478 self._flSpinButton.set_value(240)
479 self._flSpinButton.set_tooltip_text("The cruise flight level.")
480 self._flSpinButton.set_numeric(True)
481
482 setupBox.pack_start(self._flSpinButton, False, False, 0)
483
484 setupBox.pack_start(gtk.VSeparator(), False, False, 8)
485
486 alignment = gtk.Alignment(yalign = 0.5)
487 alignment.set_padding(padding_top = 0, padding_bottom = 0,
488 padding_left = 0, padding_right = 16)
489 alignment.add(gtk.Label("ZFW:"))
490 setupBox.pack_start(alignment, False, False, 0)
491
492 self._zfwSpinButton = gtk.SpinButton()
493 self._zfwSpinButton.set_increments(step = 100, page = 1000)
494 self._zfwSpinButton.set_range(min = 0, max = 500000)
495 self._zfwSpinButton.set_value(50000)
496 self._zfwSpinButton.set_tooltip_text("The Zero Fuel Weight for the flight in kgs")
497 self._zfwSpinButton.set_numeric(True)
498
499 setupBox.pack_start(self._zfwSpinButton, False, False, 0)
500
501 setupBox.pack_start(gtk.VSeparator(), False, False, 8)
502
503 self._connectButton = gtk.ToggleButton(label = "_Connect",
504 use_underline = True)
505 self._connectButton.set_tooltip_text("Push to connect to Flight Simulator and start a new flight.\n"
506 "Push again to disconnect from FS.")
507 self._connectButton.set_can_default(True)
508
509 self._connectButton.connect("toggled", self._connectToggled)
510
511 setupBox.pack_start(self._connectButton, False, False, 0)
512
513 setupBox.pack_start(gtk.VSeparator(), False, False, 8)
514
515 self._quitButton = gtk.Button(label = "_Quit", use_underline = True)
516 self._quitButton.set_tooltip_text("Quit the program.")
517
518 self._quitButton.connect("clicked", self._quit)
519
520 setupBox.pack_start(self._quitButton, False, False, 0)
521
522 return setupFrame
523
524 def _createLabeledEntry(self, label, width = 8, xalign = 1.0):
525 """Create a labeled entry.
526
527 Return a tuple consisting of:
528 - the box
529 - the entry."""
530
531 alignment = gtk.Alignment(xalign = 1.0, yalign = 0.5, xscale = 1.0)
532 alignment.set_padding(padding_top = 0, padding_bottom = 0,
533 padding_left = 0, padding_right = 16)
534 alignment.add(gtk.Label(label))
535
536 entry = gtk.Entry()
537 entry.set_editable(False)
538 entry.set_width_chars(width)
539 entry.set_max_length(width)
540 entry.set_alignment(xalign)
541
542 return (alignment, entry)
543
544 def _buildDataFrame(self):
545 """Build the frame for the data."""
546 dataFrame = gtk.Frame(label = "Data")
547
548 frameAlignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
549
550 frameAlignment.set_padding(padding_top = 4, padding_bottom = 10,
551 padding_left = 16, padding_right = 16)
552
553 table = gtk.Table(rows = 7, columns = 12)
554 table.set_homogeneous(False)
555 table.set_row_spacings(4)
556 table.set_col_spacings(8)
557
558 (label, self._timestamp) = self._createLabeledEntry("Time:")
559 table.attach(label, 0, 1, 0, 1)
560 table.attach(self._timestamp, 1, 2, 0, 1)
561
562 self._paused = gtk.Label("PAUSED")
563 table.attach(self._paused, 2, 4, 0, 1)
564
565 self._trickMode = gtk.Label("TRICKMODE")
566 table.attach(self._trickMode, 4, 6, 0, 1, xoptions = 0)
567
568 self._overspeed = gtk.Label("OVERSPEED")
569 table.attach(self._overspeed, 6, 8, 0, 1)
570
571 self._stalled = gtk.Label("STALLED")
572 table.attach(self._stalled, 8, 10, 0, 1)
573
574 self._onTheGround = gtk.Label("ONTHEGROUND")
575 table.attach(self._onTheGround, 10, 12, 0, 1)
576
577 (label, self._zfw) = self._createLabeledEntry("ZFW:", 6)
578 table.attach(label, 0, 1, 1, 2)
579 table.attach(self._zfw, 1, 2, 1, 2)
580
581 (label, self._grossWeight) = self._createLabeledEntry("Weight:", 6)
582 table.attach(label, 2, 3, 1, 2)
583 table.attach(self._grossWeight, 3, 4, 1, 2)
584
585 (label, self._heading) = self._createLabeledEntry("Heading:", 3)
586 table.attach(label, 4, 5, 1, 2)
587 table.attach(self._heading, 5, 6, 1, 2)
588
589 (label, self._pitch) = self._createLabeledEntry("Pitch:", 3)
590 table.attach(label, 6, 7, 1, 2)
591 table.attach(self._pitch, 7, 8, 1, 2)
592
593 (label, self._bank) = self._createLabeledEntry("Bank:", 3)
594 table.attach(label, 8, 9, 1, 2)
595 table.attach(self._bank, 9, 10, 1, 2)
596
597 (label, self._vs) = self._createLabeledEntry("VS:", 5)
598 table.attach(label, 10, 11, 1, 2)
599 table.attach(self._vs, 11, 12, 1, 2)
600
601 (label, self._ias) = self._createLabeledEntry("IAS:", 4)
602 table.attach(label, 0, 1, 2, 3)
603 table.attach(self._ias, 1, 2, 2, 3)
604
605 (label, self._mach) = self._createLabeledEntry("Mach:", 4)
606 table.attach(label, 2, 3, 2, 3)
607 table.attach(self._mach, 3, 4, 2, 3)
608
609 (label, self._groundSpeed) = self._createLabeledEntry("GS:", 4)
610 table.attach(label, 4, 5, 2, 3)
611 table.attach(self._groundSpeed, 5, 6, 2, 3)
612
613 (label, self._radioAltitude) = self._createLabeledEntry("Radio alt.:", 6)
614 table.attach(label, 6, 7, 2, 3)
615 table.attach(self._radioAltitude, 7, 8, 2, 3)
616
617 (label, self._altitude) = self._createLabeledEntry("Altitude:", 6)
618 table.attach(label, 8, 9, 2, 3)
619 table.attach(self._altitude, 9, 10, 2, 3)
620
621 (label, self._gLoad) = self._createLabeledEntry("G-Load:", 4)
622 table.attach(label, 10, 11, 2, 3)
623 table.attach(self._gLoad, 11, 12, 2, 3)
624
625 (label, self._flapsSet) = self._createLabeledEntry("Flaps set:", 2)
626 table.attach(label, 0, 1, 3, 4)
627 table.attach(self._flapsSet, 1, 2, 3, 4)
628
629 (label, self._flaps) = self._createLabeledEntry("Flaps:", 2)
630 table.attach(label, 2, 3, 3, 4)
631 table.attach(self._flaps, 3, 4, 3, 4)
632
633 (label, self._altimeter) = self._createLabeledEntry("Altimeter:", 4)
634 table.attach(label, 4, 5, 3, 4)
635 table.attach(self._altimeter, 5, 6, 3, 4)
636
637 (label, self._squawk) = self._createLabeledEntry("Squawk:", 4)
638 table.attach(label, 6, 7, 3, 4)
639 table.attach(self._squawk, 7, 8, 3, 4)
640
641 (label, self._nav1) = self._createLabeledEntry("NAV1:", 5)
642 table.attach(label, 8, 9, 3, 4)
643 table.attach(self._nav1, 9, 10, 3, 4)
644
645 (label, self._nav2) = self._createLabeledEntry("NAV2:", 5)
646 table.attach(label, 10, 11, 3, 4)
647 table.attach(self._nav2, 11, 12, 3, 4)
648
649 (label, self._fuel) = self._createLabeledEntry("Fuel:", 40, xalign = 0.0)
650 table.attach(label, 0, 1, 4, 5)
651 table.attach(self._fuel, 1, 4, 4, 5)
652
653 (label, self._n1) = self._createLabeledEntry("N1/RPM:", 20, xalign = 0.0)
654 table.attach(label, 4, 5, 4, 5)
655 table.attach(self._n1, 5, 8, 4, 5)
656
657 (label, self._reverser) = self._createLabeledEntry("Reverser:", 20, xalign = 0.0)
658 table.attach(label, 8, 9, 4, 5)
659 table.attach(self._reverser, 9, 12, 4, 5)
660
661 self._navLightsOn = gtk.Label("NAV")
662 table.attach(self._navLightsOn, 0, 1, 5, 6)
663
664 self._antiCollisionLightsOn = gtk.Label("ANTICOLLISION")
665 table.attach(self._antiCollisionLightsOn, 1, 3, 5, 6)
666
667 self._strobeLightsOn = gtk.Label("STROBE")
668 table.attach(self._strobeLightsOn, 3, 4, 5, 6)
669
670 self._landingLightsOn = gtk.Label("LANDING")
671 table.attach(self._landingLightsOn, 4, 5, 5, 6)
672
673 self._pitotHeatOn = gtk.Label("PITOT HEAT")
674 table.attach(self._pitotHeatOn, 5, 7, 5, 6)
675
676 self._parking = gtk.Label("PARKING")
677 table.attach(self._parking, 7, 8, 5, 6)
678
679 self._gearsDown = gtk.Label("GEARS DOWN")
680 table.attach(self._gearsDown, 8, 10, 5, 6)
681
682 self._spoilersArmed = gtk.Label("SPOILERS ARMED")
683 table.attach(self._spoilersArmed, 10, 12, 5, 6)
684
685 (label, self._spoilersExtension) = self._createLabeledEntry("Spoilers:", 3)
686 table.attach(label, 0, 1, 6, 7)
687 table.attach(self._spoilersExtension, 1, 2, 6, 7)
688
689 (label, self._windSpeed) = self._createLabeledEntry("Wind speed:", 3)
690 table.attach(label, 2, 3, 6, 7)
691 table.attach(self._windSpeed, 3, 4, 6, 7)
692
693 (label, self._windDirection) = self._createLabeledEntry("Wind from:", 3)
694 table.attach(label, 4, 5, 6, 7)
695 table.attach(self._windDirection, 5, 6, 6, 7)
696
697 frameAlignment.add(table)
698
699 dataFrame.add(frameAlignment)
700
701 self._setData()
702
703 return dataFrame
704
705 def _setData(self, aircraftState = None):
706 """Set the data.
707
708 If aircraftState is None, everything will be set to its default."""
709 if aircraftState is None:
710 self._timestamp.set_text("--:--:--")
711 self._paused.set_sensitive(False)
712 self._trickMode.set_sensitive(False)
713 self._overspeed.set_sensitive(False)
714 self._stalled.set_sensitive(False)
715 self._onTheGround.set_sensitive(False)
716 self._zfw.set_text("-")
717 self._grossWeight.set_text("-")
718 self._heading.set_text("-")
719 self._pitch.set_text("-")
720 self._bank.set_text("-")
721 self._vs.set_text("-")
722 self._ias.set_text("-")
723 self._mach.set_text("-")
724 self._groundSpeed.set_text("-")
725 self._radioAltitude.set_text("-")
726 self._altitude.set_text("-")
727 self._gLoad.set_text("-")
728 self._flapsSet.set_text("-")
729 self._flaps.set_text("-")
730 self._altimeter.set_text("-")
731 self._squawk.set_text("-")
732 self._nav1.set_text("-")
733 self._nav2.set_text("-")
734 self._fuel.set_text("-")
735 self._n1.set_text("-")
736 self._reverser.set_text("-")
737 self._navLightsOn.set_sensitive(False)
738 self._antiCollisionLightsOn.set_sensitive(False)
739 self._strobeLightsOn.set_sensitive(False)
740 self._landingLightsOn.set_sensitive(False)
741 self._pitotHeatOn.set_sensitive(False)
742 self._parking.set_sensitive(False)
743 self._gearsDown.set_sensitive(False)
744 self._spoilersArmed.set_sensitive(False)
745 self._spoilersExtension.set_text("-")
746 self._windSpeed.set_text("-")
747 self._windDirection.set_text("-")
748 else:
749 self._timestamp.set_text(time.strftime("%H:%M:%S",
750 time.gmtime(aircraftState.timestamp)))
751 self._paused.set_sensitive(aircraftState.paused)
752 self._trickMode.set_sensitive(aircraftState.trickMode)
753 self._overspeed.set_sensitive(aircraftState.overspeed)
754 self._stalled.set_sensitive(aircraftState.stalled)
755 self._onTheGround.set_sensitive(aircraftState.onTheGround)
756 self._zfw.set_text("%.0f" % (aircraftState.zfw,))
757 self._grossWeight.set_text("%.0f" % (aircraftState.grossWeight,))
758 self._heading.set_text("%03.0f" % (aircraftState.heading,))
759 self._pitch.set_text("%.0f" % (aircraftState.pitch,))
760 self._bank.set_text("%.0f" % (aircraftState.bank,))
761 self._vs.set_text("%.0f" % (aircraftState.vs,))
762 self._ias.set_text("%.0f" % (aircraftState.ias,))
763 self._mach.set_text("%.2f" % (aircraftState.mach,))
764 self._groundSpeed.set_text("%.0f" % (aircraftState.groundSpeed,))
765 self._radioAltitude.set_text("%.0f" % (aircraftState.radioAltitude,))
766 self._altitude.set_text("%.0f" % (aircraftState.altitude,))
767 self._gLoad.set_text("%.2f" % (aircraftState.gLoad,))
768 self._flapsSet.set_text("%.0f" % (aircraftState.flapsSet,))
769 self._flaps.set_text("%.0f" % (aircraftState.flaps,))
770 self._altimeter.set_text("%.0f" % (aircraftState.altimeter,))
771 self._squawk.set_text(aircraftState.squawk)
772 self._nav1.set_text(aircraftState.nav1)
773 self._nav2.set_text(aircraftState.nav2)
774
775 fuelStr = ""
776 for fuel in aircraftState.fuel:
777 if fuelStr: fuelStr += ", "
778 fuelStr += "%.0f" % (fuel,)
779 self._fuel.set_text(fuelStr)
780
781 if hasattr(aircraftState, "n1"):
782 n1Str = ""
783 for n1 in aircraftState.n1:
784 if n1Str: n1Str += ", "
785 n1Str += "%.0f" % (n1,)
786 elif hasattr(aircraftState, "rpm"):
787 n1Str = ""
788 for rpm in aircraftState.rpm:
789 if n1Str: n1Str += ", "
790 n1Str += "%.0f" % (rpm,)
791 else:
792 n1Str = "-"
793 self._n1.set_text(n1Str)
794
795 reverserStr = ""
796 for reverser in aircraftState.reverser:
797 if reverserStr: reverserStr += ", "
798 reverserStr += "ON" if reverser else "OFF"
799 self._reverser.set_text(reverserStr)
800
801 self._navLightsOn.set_sensitive(aircraftState.navLightsOn)
802 self._antiCollisionLightsOn.set_sensitive(aircraftState.antiCollisionLightsOn)
803 self._strobeLightsOn.set_sensitive(aircraftState.strobeLightsOn)
804 self._landingLightsOn.set_sensitive(aircraftState.landingLightsOn)
805 self._pitotHeatOn.set_sensitive(aircraftState.pitotHeatOn)
806 self._parking.set_sensitive(aircraftState.parking)
807 self._gearsDown.set_sensitive(aircraftState.gearsDown)
808 self._spoilersArmed.set_sensitive(aircraftState.spoilersArmed)
809 self._spoilersExtension.set_text("%.0f" % (aircraftState.spoilersExtension,))
810 self._windSpeed.set_text("%.0f" % (aircraftState.windSpeed,))
811 self._windDirection.set_text("%03.0f" % (aircraftState.windDirection,))
812
813 def _buildLogFrame(self):
814 """Build the frame for the log."""
815 logFrame = gtk.Frame(label = "Log")
816
817 frameAlignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
818
819 frameAlignment.set_padding(padding_top = 4, padding_bottom = 10,
820 padding_left = 16, padding_right = 16)
821
822 logFrame.add(frameAlignment)
823
824 logScroller = gtk.ScrolledWindow()
825 self._logView = gtk.TextView()
826 self._logView.set_editable(False)
827 logScroller.add(self._logView)
828
829 logBox = gtk.VBox()
830 logBox.pack_start(logScroller, True, True, 0)
831 logBox.set_size_request(-1, 200)
832
833 frameAlignment.add(logBox)
834
835 return logFrame
836
837 def _writeLog(self, msg):
838 """Write the given message to the log."""
839 buffer = self._logView.get_buffer()
840 buffer.insert(buffer.get_end_iter(), msg)
841 self._logView.scroll_mark_onscreen(buffer.get_insert())
842
843 def _quit(self, what = None):
844 """Quit from the application."""
845 self._statusIcon.destroy()
846 return gtk.main_quit()
847
848 def _notebookPageSwitch(self, notebook, page, page_num):
849 """Called when the current page of the notebook has changed."""
850 if page_num==0:
851 gobject.idle_add(self._wizard.grabDefault)
852 elif page_num==1:
853 gobject.idle_add(self._connectButton.grab_default)
854 else:
855 self._mainWindow.set_default(None)
856
857class TrackerStatusIcon(gtk.StatusIcon):
858 def __init__(self):
859 gtk.StatusIcon.__init__(self)
860 menu = '''
861 <ui>
862 <menubar name="Menubar">
863 <menu action="Menu">
864 <menuitem action="Search"/>
865 <menuitem action="Preferences"/>
866 <separator/>
867 <menuitem action="About"/>
868 </menu>
869 </menubar>
870 </ui>
871 '''
872 actions = [
873 ('Menu', None, 'Menu'),
874 ('Search', None, '_Search...', None, 'Search files with MetaTracker', self.on_activate),
875 ('Preferences', gtk.STOCK_PREFERENCES, '_Preferences...', None, 'Change MetaTracker preferences', self.on_preferences),
876 ('About', gtk.STOCK_ABOUT, '_About...', None, 'About MetaTracker', self.on_about)]
877 ag = gtk.ActionGroup('Actions')
878 ag.add_actions(actions)
879 self.manager = gtk.UIManager()
880 self.manager.insert_action_group(ag, 0)
881 self.manager.add_ui_from_string(menu)
882 self.menu = self.manager.get_widget('/Menubar/Menu/About').props.parent
883 search = self.manager.get_widget('/Menubar/Menu/Search')
884 search.get_children()[0].set_markup('<b>_Search...</b>')
885 search.get_children()[0].set_use_underline(True)
886 search.get_children()[0].set_use_markup(True)
887 #search.get_children()[1].set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
888 self.set_from_stock(gtk.STOCK_FIND)
889 self.set_tooltip('Tracker Desktop Search')
890 self.set_visible(True)
891 self.connect('activate', self.on_activate)
892 self.connect('popup-menu', self.on_popup_menu)
893
894 def on_activate(self, data):
895 os.spawnlpe(os.P_NOWAIT, 'tracker-search-tool', os.environ)
896
897 def on_popup_menu(self, status, button, time):
898 self.menu.popup(None, None, None, button, time)
899
900 def on_preferences(self, data):
901 print 'preferences'
902
903 def on_about(self, data):
904 dialog = gtk.AboutDialog()
905 dialog.set_name('Tracker')
906 dialog.set_version('0.5.0')
907 dialog.set_comments('A desktop indexing and search tool')
908 dialog.set_website('www.freedesktop.org/Tracker')
909 dialog.run()
910 dialog.destroy()
Note: See TracBrowser for help on using the repository browser.