source: src/mlx/gui/gui.py@ 41:19b2001e4478

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

Added the code to log in to the MAVA website and download the flights.

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