source: src/mlx/gui/gui.py@ 70:64fb5caf4cad

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

Implemented two-way navigation between the wizard pages.

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