source: src/mlx/gui/flight.py@ 106:5d81096406c0

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

The METAR of the arrival airport is downloaded in the landing stage.

File size: 85.7 KB
RevLine 
[42]1# The flight handling "wizard"
2
3from mlx.gui.common import *
4
[51]5import mlx.const as const
6import mlx.fs as fs
[60]7from mlx.checks import PayloadChecker
[89]8import mlx.util as util
[97]9from mlx.pirep import PIREP
[51]10
[61]11import datetime
12import time
13
[78]14#------------------------------------------------------------------------------
15
16acftTypeNames = { const.AIRCRAFT_B736: "Boeing 737-600",
17 const.AIRCRAFT_B737: "Boeing 737-700",
18 const.AIRCRAFT_B738: "Boeing 737-800",
19 const.AIRCRAFT_DH8D: "Bombardier Dash 8-Q400",
20 const.AIRCRAFT_B733: "Boeing 737-300",
21 const.AIRCRAFT_B734: "Boeing 737-400",
22 const.AIRCRAFT_B735: "Boeing 737-500",
23 const.AIRCRAFT_B762: "Boeing 767-200",
24 const.AIRCRAFT_B763: "Boeing 767-300",
25 const.AIRCRAFT_CRJ2: "Bombardier CRJ200",
26 const.AIRCRAFT_F70: "Fokker 70",
27 const.AIRCRAFT_DC3: "Lisunov Li-2",
28 const.AIRCRAFT_T134: "Tupolev Tu-134",
29 const.AIRCRAFT_T154: "Tupolev Tu-154",
30 const.AIRCRAFT_YK40: "Yakovlev Yak-40" }
31
[42]32#-----------------------------------------------------------------------------
33
[44]34class Page(gtk.Alignment):
[42]35 """A page in the flight wizard."""
[94]36 def __init__(self, wizard, title, help, completedHelp = None):
[42]37 """Construct the page."""
[44]38 super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
39 xscale = 1.0, yscale = 1.0)
40 self.set_padding(padding_top = 4, padding_bottom = 4,
41 padding_left = 12, padding_right = 12)
42
43 frame = gtk.Frame()
44 self.add(frame)
45
46 style = self.get_style() if pygobject else self.rc_get_style()
47
48 self._vbox = gtk.VBox()
[48]49 self._vbox.set_homogeneous(False)
[44]50 frame.add(self._vbox)
51
52 eventBox = gtk.EventBox()
53 eventBox.modify_bg(0, style.bg[3])
54
55 alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
56
57 label = gtk.Label(title)
58 label.modify_fg(0, style.fg[3])
59 label.modify_font(pango.FontDescription("bold 24"))
60 alignment.set_padding(padding_top = 4, padding_bottom = 4,
61 padding_left = 6, padding_right = 0)
62
63 alignment.add(label)
64 eventBox.add(alignment)
65
66 self._vbox.pack_start(eventBox, False, False, 0)
67
[79]68 mainBox = gtk.VBox()
[48]69
70 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
71 xscale = 1.0, yscale = 1.0)
72 alignment.set_padding(padding_top = 16, padding_bottom = 16,
73 padding_left = 16, padding_right = 16)
[79]74 alignment.add(mainBox)
[48]75 self._vbox.pack_start(alignment, True, True, 0)
76
77 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
[94]78 xscale = 0.0, yscale = 0.0)
[50]79 alignment.set_padding(padding_top = 0, padding_bottom = 16,
80 padding_left = 0, padding_right = 0)
[48]81
[94]82 self._help = help
83 self._completedHelp = completedHelp
84
85 if self._completedHelp is None or \
86 len(help.splitlines())>=len(completedHelp.splitlines()):
87 longerHelp = help
88 else:
89 longerHelp = completedHelp
90
91 self._helpLabel = gtk.Label(completedHelp)
92 # FIXME: should be a constant in common
93 self._helpLabel.set_justify(gtk.Justification.CENTER if pygobject
94 else gtk.JUSTIFY_CENTER)
95 self._helpLabel.set_use_markup(True)
96 alignment.add(self._helpLabel)
[79]97 mainBox.pack_start(alignment, False, False, 0)
[44]98
99 self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
[48]100 xscale = 1.0, yscale = 1.0)
[79]101 mainBox.pack_start(self._mainAlignment, True, True, 0)
[48]102
103 buttonAlignment = gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
[44]104 buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
105 padding_left = 16, padding_right = 16)
106
[70]107 self._buttonBox = gtk.HBox()
108 self._buttonBox.set_homogeneous(False)
[46]109 self._defaultButton = None
[44]110 buttonAlignment.add(self._buttonBox)
111
112 self._vbox.pack_start(buttonAlignment, False, False, 0)
113
[42]114 self._wizard = wizard
115
[94]116 self._completed = False
[70]117 self._fromPage = None
118
[44]119 def setMainWidget(self, widget):
120 """Set the given widget as the main one."""
121 self._mainAlignment.add(widget)
122
[46]123 def addButton(self, label, default = False):
[44]124 """Add a button with the given label.
125
126 Return the button object created."""
127 button = gtk.Button(label)
[70]128 self._buttonBox.pack_start(button, False, False, 4)
[48]129 button.set_use_underline(True)
[46]130 if default:
131 button.set_can_default(True)
132 self._defaultButton = button
[44]133 return button
134
[94]135 def initialize(self):
136 """Initialize the page.
137
138 It sets up the primary help, and calls the activate() function."""
139 self._helpLabel.set_markup(self._help)
140 self._helpLabel.set_sensitive(True)
141 self.activate()
142
[48]143 def activate(self):
144 """Called when this page becomes active.
145
146 This default implementation does nothing."""
147 pass
148
[94]149 def complete(self):
150 """Called when the page is completed.
151
152 It greys out/changes the help text and then calls finalize()."""
153 self.finalize()
154 if self._completedHelp is None:
155 self._helpLabel.set_sensitive(False)
156 else:
157 self._helpLabel.set_markup(self._completedHelp)
158 self._completed = True
159
[70]160 def finalize(self):
161 """Called when the page is finalized."""
162 pass
163
[46]164 def grabDefault(self):
165 """If the page has a default button, make it the default one."""
166 if self._defaultButton is not None:
167 self._defaultButton.grab_default()
[67]168
169 def reset(self):
170 """Reset the page if the wizard is reset."""
[94]171 self._completed = False
[70]172 self._fromPage = None
173
174 def goBack(self):
175 """Go to the page we were invoked from."""
176 assert self._fromPage is not None
177
178 self._wizard.setCurrentPage(self._fromPage, finalize = False)
[46]179
[42]180#-----------------------------------------------------------------------------
181
182class LoginPage(Page):
183 """The login page."""
184 def __init__(self, wizard):
185 """Construct the login page."""
[44]186 help = "Enter your MAVA pilot's ID and password to\n" \
187 "log in to the MAVA website and download\n" \
188 "your booked flights."
189 super(LoginPage, self).__init__(wizard, "Login", help)
[42]190
[48]191 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
192 xscale = 0.0, yscale = 0.0)
193
[45]194 table = gtk.Table(2, 3)
[42]195 table.set_row_spacings(4)
196 table.set_col_spacings(32)
[48]197 alignment.add(table)
198 self.setMainWidget(alignment)
[42]199
200 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[45]201 label = gtk.Label("Pilot _ID:")
202 label.set_use_underline(True)
203 labelAlignment.add(label)
[42]204 table.attach(labelAlignment, 0, 1, 0, 1)
205
206 self._pilotID = gtk.Entry()
207 self._pilotID.connect("changed", self._setLoginButton)
[45]208 self._pilotID.set_tooltip_text("Enter your MAVA pilot's ID. This "
209 "usually starts with a "
210 "'P' followed by 3 digits.")
[42]211 table.attach(self._pilotID, 1, 2, 0, 1)
[45]212 label.set_mnemonic_widget(self._pilotID)
[42]213
214 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[45]215 label = gtk.Label("_Password:")
216 label.set_use_underline(True)
217 labelAlignment.add(label)
[42]218 table.attach(labelAlignment, 0, 1, 1, 2)
219
220 self._password = gtk.Entry()
221 self._password.set_visibility(False)
222 self._password.connect("changed", self._setLoginButton)
[45]223 self._password.set_tooltip_text("Enter the password for your pilot's ID")
[42]224 table.attach(self._password, 1, 2, 1, 2)
[45]225 label.set_mnemonic_widget(self._password)
[42]226
[45]227 self._rememberButton = gtk.CheckButton("_Remember password")
228 self._rememberButton.set_use_underline(True)
229 self._rememberButton.set_tooltip_text("If checked, your password will "
230 "be stored, so that you should "
231 "not have to enter it every time. "
232 "Note, however, that the password "
233 "is stored as text, and anybody "
234 "who can access your files will "
235 "be able to read it.")
236 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
237
[46]238 self._loginButton = self.addButton("_Login", default = True)
[42]239 self._loginButton.set_sensitive(False)
240 self._loginButton.connect("clicked", self._loginClicked)
[92]241 self._loginButton.set_tooltip_text("Click to log in.")
242
243 def activate(self):
244 """Activate the page."""
[42]245 config = self._wizard.gui.config
246 self._pilotID.set_text(config.pilotID)
247 self._password.set_text(config.password)
[45]248 self._rememberButton.set_active(config.rememberPassword)
[42]249
250 def _setLoginButton(self, entry):
251 """Set the login button's sensitivity.
252
253 The button is sensitive only if both the pilot ID and the password
254 fields contain values."""
255 self._loginButton.set_sensitive(self._pilotID.get_text()!="" and
256 self._password.get_text()!="")
257
258 def _loginClicked(self, button):
259 """Called when the login button was clicked."""
[70]260 self._loginButton.set_sensitive(False)
261 gui = self._wizard.gui
262 gui.beginBusy("Logging in...")
263 gui.webHandler.login(self._loginResultCallback,
264 self._pilotID.get_text(),
265 self._password.get_text())
[42]266
267 def _loginResultCallback(self, returned, result):
268 """The login result callback, called in the web handler's thread."""
269 gobject.idle_add(self._handleLoginResult, returned, result)
270
271 def _handleLoginResult(self, returned, result):
272 """Handle the login result."""
[49]273 self._wizard.gui.endBusy()
[70]274 self._loginButton.set_sensitive(True)
[42]275 if returned:
276 if result.loggedIn:
277 config = self._wizard.gui.config
[45]278
[42]279 config.pilotID = self._pilotID.get_text()
[45]280
281 rememberPassword = self._rememberButton.get_active()
282 config.password = self._password.get_text() if rememberPassword \
283 else ""
284
285 config.rememberPassword = rememberPassword
286
[43]287 config.save()
[48]288 self._wizard._loginResult = result
[42]289 self._wizard.nextPage()
290 else:
[105]291 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
292 type = MESSAGETYPE_ERROR,
[42]293 buttons = BUTTONSTYPE_OK,
294 message_format =
295 "Invalid pilot's ID or password.")
[105]296 dialog.set_title(WINDOW_TITLE_BASE)
[42]297 dialog.format_secondary_markup("Check the ID and try to reenter"
298 " the password.")
299 dialog.run()
300 dialog.hide()
301 else:
[105]302 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
303 type = MESSAGETYPE_ERROR,
[42]304 buttons = BUTTONSTYPE_OK,
305 message_format =
306 "Failed to connect to the MAVA website.")
[105]307 dialog.set_title(WINDOW_TITLE_BASE)
[42]308 dialog.format_secondary_markup("Try again in a few minutes.")
309 dialog.run()
310 dialog.hide()
311
312#-----------------------------------------------------------------------------
313
314class FlightSelectionPage(Page):
315 """The page to select the flight."""
316 def __init__(self, wizard):
317 """Construct the flight selection page."""
[94]318 help = "Select the flight you want to perform."
319 completedHelp = "You have selected the flight highlighted below."
[44]320 super(FlightSelectionPage, self).__init__(wizard, "Flight selection",
[94]321 help, completedHelp = completedHelp)
[48]322
323
324 self._listStore = gtk.ListStore(str, str, str, str)
325 self._flightList = gtk.TreeView(self._listStore)
326 column = gtk.TreeViewColumn("Flight no.", gtk.CellRendererText(),
327 text = 1)
328 column.set_expand(True)
329 self._flightList.append_column(column)
330 column = gtk.TreeViewColumn("Departure time [UTC]", gtk.CellRendererText(),
331 text = 0)
332 column.set_expand(True)
333 self._flightList.append_column(column)
334 column = gtk.TreeViewColumn("From", gtk.CellRendererText(),
335 text = 2)
336 column.set_expand(True)
337 self._flightList.append_column(column)
338 column = gtk.TreeViewColumn("To", gtk.CellRendererText(),
339 text = 3)
340 column.set_expand(True)
341 self._flightList.append_column(column)
342
343 flightSelection = self._flightList.get_selection()
344 flightSelection.connect("changed", self._selectionChanged)
345
346 scrolledWindow = gtk.ScrolledWindow()
347 scrolledWindow.add(self._flightList)
348 scrolledWindow.set_size_request(400, -1)
349 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
350 else gtk.POLICY_AUTOMATIC,
[69]351 gtk.PolicyType.AUTOMATIC if pygobject
352 else gtk.POLICY_AUTOMATIC)
[62]353 scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
354 else gtk.SHADOW_IN)
[48]355
356 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
357 alignment.add(scrolledWindow)
358
359 self.setMainWidget(alignment)
360
361 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
362 self._button.set_use_stock(True)
363 self._button.set_sensitive(False)
[51]364 self._button.connect("clicked", self._forwardClicked)
[48]365
366 def activate(self):
367 """Fill the flight list."""
[70]368 self._flightList.set_sensitive(True)
369 self._listStore.clear()
370 for flight in self._wizard.loginResult.flights:
371 self._listStore.append([str(flight.departureTime),
372 flight.callsign,
373 flight.departureICAO,
374 flight.arrivalICAO])
375
376 def finalize(self):
377 """Finalize the page."""
378 self._flightList.set_sensitive(False)
[48]379
380 def _selectionChanged(self, selection):
381 """Called when the selection is changed."""
382 self._button.set_sensitive(selection.count_selected_rows()==1)
[42]383
[51]384 def _forwardClicked(self, button):
385 """Called when the forward button was clicked."""
[94]386 if self._completed:
[70]387 self._wizard.jumpPage(self._nextDistance, finalize = False)
388 else:
389 selection = self._flightList.get_selection()
390 (listStore, iter) = selection.get_selected()
391 path = listStore.get_path(iter)
392 [index] = path.get_indices() if pygobject else path
[51]393
[70]394 flight = self._wizard.loginResult.flights[index]
395 self._wizard._bookedFlight = flight
[93]396 # FIXME: with PyGObject this call causes error messages to
397 # appear on the standard output
398 self._wizard.gui.enableFlightInfo()
[51]399
[70]400 self._updateDepartureGate()
[51]401
402 def _updateDepartureGate(self):
403 """Update the departure gate for the booked flight."""
404 flight = self._wizard._bookedFlight
405 if flight.departureICAO=="LHBP":
406 self._wizard._getFleet(self._fleetRetrieved)
407 else:
[70]408 self._nextDistance = 2
[51]409 self._wizard.jumpPage(2)
410
411 def _fleetRetrieved(self, fleet):
412 """Called when the fleet has been retrieved."""
413 if fleet is None:
[70]414 self._nextDistance = 2
[51]415 self._wizard.jumpPage(2)
416 else:
417 plane = fleet[self._wizard._bookedFlight.tailNumber]
418 if plane is None:
[70]419 self._nextDistance = 2
[51]420 self._wizard.jumpPage(2)
[70]421 elif plane.gateNumber is not None and \
422 not fleet.isGateConflicting(plane):
[51]423 self._wizard._departureGate = plane.gateNumber
[70]424 self._nextDistance = 2
[51]425 self._wizard.jumpPage(2)
426 else:
[70]427 self._nextDistance = 1
[51]428 self._wizard.nextPage()
429
430#-----------------------------------------------------------------------------
431
432class GateSelectionPage(Page):
433 """Page to select a free gate at LHBP.
434
435 This page should be displayed only if we have fleet information!."""
436 def __init__(self, wizard):
437 """Construct the gate selection page."""
438 help = "The airplane's gate position is invalid.\n\n" \
439 "Select the gate from which you\n" \
440 "would like to begin the flight."
441 super(GateSelectionPage, self).__init__(wizard,
442 "LHBP gate selection",
443 help)
444
445 self._listStore = gtk.ListStore(str)
446 self._gateList = gtk.TreeView(self._listStore)
447 column = gtk.TreeViewColumn(None, gtk.CellRendererText(),
448 text = 0)
449 column.set_expand(True)
450 self._gateList.append_column(column)
451 self._gateList.set_headers_visible(False)
452
453 gateSelection = self._gateList.get_selection()
454 gateSelection.connect("changed", self._selectionChanged)
455
456 scrolledWindow = gtk.ScrolledWindow()
457 scrolledWindow.add(self._gateList)
458 scrolledWindow.set_size_request(50, -1)
459 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
460 else gtk.POLICY_AUTOMATIC,
[69]461 gtk.PolicyType.AUTOMATIC if pygobject
462 else gtk.POLICY_AUTOMATIC)
[62]463 scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
464 else gtk.SHADOW_IN)
[51]465
466 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
467 alignment.add(scrolledWindow)
468
469 self.setMainWidget(alignment)
470
[73]471 button = self.addButton(gtk.STOCK_GO_BACK)
472 button.set_use_stock(True)
473 button.connect("clicked", self._backClicked)
474
[51]475 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
476 self._button.set_use_stock(True)
477 self._button.set_sensitive(False)
478 self._button.connect("clicked", self._forwardClicked)
479
480 def activate(self):
481 """Fill the gate list."""
482 self._listStore.clear()
[70]483 self._gateList.set_sensitive(True)
[51]484 occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
485 for gateNumber in const.lhbpGateNumbers:
486 if gateNumber not in occupiedGateNumbers:
487 self._listStore.append([gateNumber])
488
[70]489 def finalize(self):
490 """Finalize the page."""
491 self._gateList.set_sensitive(False)
492
[51]493 def _selectionChanged(self, selection):
494 """Called when the selection is changed."""
495 self._button.set_sensitive(selection.count_selected_rows()==1)
496
[73]497 def _backClicked(self, button):
498 """Called when the Back button is pressed."""
499 self.goBack()
500
[51]501 def _forwardClicked(self, button):
502 """Called when the forward button is clicked."""
[94]503 if not self._completed:
[70]504 selection = self._gateList.get_selection()
505 (listStore, iter) = selection.get_selected()
506 (gateNumber,) = listStore.get(iter, 0)
[51]507
[70]508 self._wizard._departureGate = gateNumber
[51]509
[70]510 #self._wizard._updatePlane(self._planeUpdated,
511 # self._wizard._bookedFlight.tailNumber,
512 # const.PLANE_HOME,
513 # gateNumber)
514
[58]515 self._wizard.nextPage()
[51]516
517 def _planeUpdated(self, success):
518 """Callback for the plane updating call."""
519 if success is None or success:
520 self._wizard.nextPage()
521 else:
[105]522 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
523 type = MESSAGETYPE_ERROR,
[51]524 buttons = BUTTONSTYPE_OK,
525 message_format = "Gate conflict detected again")
[105]526 dialog.set_title(WINDOW_TITLE_BASE)
[51]527 dialog.format_secondary_markup("Try to select a different gate.")
528 dialog.run()
529 dialog.hide()
530
531 self._wizard._getFleet(self._fleetRetrieved)
532
533 def _fleetRetrieved(self, fleet):
534 """Called when the fleet has been retrieved."""
535 if fleet is None:
536 self._wizard.nextPage()
537 else:
538 self.activate()
539
540#-----------------------------------------------------------------------------
541
542class ConnectPage(Page):
543 """Page which displays the departure airport and gate (if at LHBP)."""
544 def __init__(self, wizard):
545 """Construct the connect page."""
[78]546 help = "Load the aircraft below into the simulator and park it\n" \
547 "at the given airport, at the gate below, if present.\n\n" \
[51]548 "Then press the Connect button to connect to the simulator."
[94]549 completedHelp = "The basic data of your flight can be read below."
[51]550 super(ConnectPage, self).__init__(wizard,
551 "Connect to the simulator",
[94]552 help, completedHelp = completedHelp)
[51]553
554 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
555 xscale = 0.0, yscale = 0.0)
556
[78]557 table = gtk.Table(5, 2)
[51]558 table.set_row_spacings(4)
559 table.set_col_spacings(16)
560 table.set_homogeneous(True)
561 alignment.add(table)
562 self.setMainWidget(alignment)
563
564 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[78]565 label = gtk.Label("Flight number:")
[51]566 labelAlignment.add(label)
567 table.attach(labelAlignment, 0, 1, 0, 1)
568
569 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
[78]570 self._flightNumber = gtk.Label()
[82]571 self._flightNumber.set_width_chars(7)
[78]572 self._flightNumber.set_alignment(0.0, 0.5)
573 labelAlignment.add(self._flightNumber)
574 table.attach(labelAlignment, 1, 2, 0, 1)
575
576 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
577 label = gtk.Label("Aircraft:")
578 labelAlignment.add(label)
579 table.attach(labelAlignment, 0, 1, 1, 2)
580
581 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
582 self._aircraft = gtk.Label()
583 self._aircraft.set_width_chars(25)
584 self._aircraft.set_alignment(0.0, 0.5)
585 labelAlignment.add(self._aircraft)
586 table.attach(labelAlignment, 1, 2, 1, 2)
587
588 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
589 label = gtk.Label("Tail number:")
590 labelAlignment.add(label)
591 table.attach(labelAlignment, 0, 1, 2, 3)
592
593 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
594 self._tailNumber = gtk.Label()
[80]595 self._tailNumber.set_width_chars(10)
[78]596 self._tailNumber.set_alignment(0.0, 0.5)
597 labelAlignment.add(self._tailNumber)
598 table.attach(labelAlignment, 1, 2, 2, 3)
599
600 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
601 label = gtk.Label("Airport:")
602 labelAlignment.add(label)
603 table.attach(labelAlignment, 0, 1, 3, 4)
604
605 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
[51]606 self._departureICAO = gtk.Label()
[80]607 self._departureICAO.set_width_chars(6)
[51]608 self._departureICAO.set_alignment(0.0, 0.5)
609 labelAlignment.add(self._departureICAO)
[78]610 table.attach(labelAlignment, 1, 2, 3, 4)
[51]611
612 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
613 label = gtk.Label("Gate:")
614 labelAlignment.add(label)
[78]615 table.attach(labelAlignment, 0, 1, 4, 5)
[51]616
617 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
618 self._departureGate = gtk.Label()
619 self._departureGate.set_width_chars(5)
620 self._departureGate.set_alignment(0.0, 0.5)
621 labelAlignment.add(self._departureGate)
[78]622 table.attach(labelAlignment, 1, 2, 4, 5)
[51]623
[70]624 button = self.addButton(gtk.STOCK_GO_BACK)
625 button.set_use_stock(True)
626 button.connect("clicked", self._backClicked)
627
[51]628 self._button = self.addButton("_Connect", default = True)
629 self._button.set_use_underline(True)
[70]630 self._clickedID = self._button.connect("clicked", self._connectClicked)
[51]631
632 def activate(self):
[60]633 """Setup the departure information."""
[70]634 self._button.set_label("_Connect")
635 self._button.set_use_underline(True)
636 self._button.disconnect(self._clickedID)
637 self._clickedID = self._button.connect("clicked", self._connectClicked)
[78]638
639 bookedFlight = self._wizard._bookedFlight
640
641 self._flightNumber.set_markup("<b>" + bookedFlight.callsign + "</b>")
642
643 aircraftType = acftTypeNames[bookedFlight.aircraftType]
644 self._aircraft.set_markup("<b>" + aircraftType + "</b>")
[70]645
[78]646 self._tailNumber.set_markup("<b>" + bookedFlight.tailNumber + "</b>")
647
648 icao = bookedFlight.departureICAO
[51]649 self._departureICAO.set_markup("<b>" + icao + "</b>")
650 gate = self._wizard._departureGate
651 if gate!="-":
652 gate = "<b>" + gate + "</b>"
653 self._departureGate.set_markup(gate)
654
[70]655 def finalize(self):
656 """Finalize the page."""
657 self._button.set_label(gtk.STOCK_GO_FORWARD)
658 self._button.set_use_stock(True)
659 self._button.disconnect(self._clickedID)
660 self._clickedID = self._button.connect("clicked", self._forwardClicked)
661
662 def _backClicked(self, button):
663 """Called when the Back button is pressed."""
664 self.goBack()
665
[51]666 def _connectClicked(self, button):
667 """Called when the Connect button is pressed."""
668 self._wizard._connectSimulator()
669
[70]670 def _forwardClicked(self, button):
671 """Called when the Forward button is pressed."""
672 self._wizard.nextPage()
673
[42]674#-----------------------------------------------------------------------------
675
[59]676class PayloadPage(Page):
677 """Page to allow setting up the payload."""
678 def __init__(self, wizard):
679 """Construct the page."""
680 help = "The briefing contains the weights below.\n" \
[60]681 "Setup the cargo weight here and the payload weight in the simulator.\n\n" \
682 "You can also check here what the simulator reports as ZFW."
[94]683 completedHelp = "You can see the weights in the briefing\n" \
684 "and the cargo weight you have selected below.\n\n" \
685 "You can also query the ZFW reported by the simulator."
686 super(PayloadPage, self).__init__(wizard, "Payload", help,
687 completedHelp = completedHelp)
[59]688
[60]689 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
690 xscale = 0.0, yscale = 0.0)
691
692 table = gtk.Table(7, 3)
693 table.set_row_spacings(4)
694 table.set_col_spacings(16)
695 table.set_homogeneous(False)
696 alignment.add(table)
697 self.setMainWidget(alignment)
698
699 label = gtk.Label("Crew:")
700 label.set_alignment(0.0, 0.5)
701 table.attach(label, 0, 1, 0, 1)
702
703 self._numCrew = gtk.Label()
704 self._numCrew.set_width_chars(6)
705 self._numCrew.set_alignment(1.0, 0.5)
706 table.attach(self._numCrew, 1, 2, 0, 1)
707
708 label = gtk.Label("Passengers:")
709 label.set_alignment(0.0, 0.5)
710 table.attach(label, 0, 1, 1, 2)
711
712 self._numPassengers = gtk.Label()
713 self._numPassengers.set_width_chars(6)
714 self._numPassengers.set_alignment(1.0, 0.5)
715 table.attach(self._numPassengers, 1, 2, 1, 2)
716
717 label = gtk.Label("Baggage:")
718 label.set_alignment(0.0, 0.5)
719 table.attach(label, 0, 1, 2, 3)
720
721 self._bagWeight = gtk.Label()
722 self._bagWeight.set_width_chars(6)
723 self._bagWeight.set_alignment(1.0, 0.5)
724 table.attach(self._bagWeight, 1, 2, 2, 3)
725
726 table.attach(gtk.Label("kg"), 2, 3, 2, 3)
727
728 label = gtk.Label("_Cargo:")
729 label.set_use_underline(True)
730 label.set_alignment(0.0, 0.5)
731 table.attach(label, 0, 1, 3, 4)
732
[84]733 self._cargoWeight = IntegerEntry(defaultValue = 0)
[60]734 self._cargoWeight.set_width_chars(6)
[84]735 self._cargoWeight.connect("integer-changed", self._cargoWeightChanged)
[60]736 self._cargoWeight.set_tooltip_text("The weight of the cargo for your flight.")
737 table.attach(self._cargoWeight, 1, 2, 3, 4)
738 label.set_mnemonic_widget(self._cargoWeight)
739
740 table.attach(gtk.Label("kg"), 2, 3, 3, 4)
741
742 label = gtk.Label("Mail:")
743 label.set_alignment(0.0, 0.5)
744 table.attach(label, 0, 1, 4, 5)
745
746 self._mailWeight = gtk.Label()
747 self._mailWeight.set_width_chars(6)
748 self._mailWeight.set_alignment(1.0, 0.5)
749 table.attach(self._mailWeight, 1, 2, 4, 5)
750
751 table.attach(gtk.Label("kg"), 2, 3, 4, 5)
752
753 label = gtk.Label("<b>Calculated ZFW:</b>")
754 label.set_alignment(0.0, 0.5)
755 label.set_use_markup(True)
756 table.attach(label, 0, 1, 5, 6)
757
758 self._calculatedZFW = gtk.Label()
759 self._calculatedZFW.set_width_chars(6)
760 self._calculatedZFW.set_alignment(1.0, 0.5)
761 table.attach(self._calculatedZFW, 1, 2, 5, 6)
762
763 table.attach(gtk.Label("kg"), 2, 3, 5, 6)
764
[70]765 self._zfwButton = gtk.Button("_ZFW from FS:")
766 self._zfwButton.set_use_underline(True)
767 self._zfwButton.connect("clicked", self._zfwRequested)
768 table.attach(self._zfwButton, 0, 1, 6, 7)
[60]769
770 self._simulatorZFW = gtk.Label("-")
771 self._simulatorZFW.set_width_chars(6)
772 self._simulatorZFW.set_alignment(1.0, 0.5)
773 table.attach(self._simulatorZFW, 1, 2, 6, 7)
774 self._simulatorZFWValue = None
775
776 table.attach(gtk.Label("kg"), 2, 3, 6, 7)
777
[70]778 self._backButton = self.addButton(gtk.STOCK_GO_BACK)
779 self._backButton.set_use_stock(True)
780 self._backButton.connect("clicked", self._backClicked)
781
[60]782 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
783 self._button.set_use_stock(True)
784 self._button.connect("clicked", self._forwardClicked)
785
[97]786 @property
787 def cargoWeight(self):
788 """Get the cargo weight entered."""
789 return self._cargoWeight.get_int()
790
[60]791 def activate(self):
792 """Setup the information."""
793 bookedFlight = self._wizard._bookedFlight
794 self._numCrew.set_text(str(bookedFlight.numCrew))
795 self._numPassengers.set_text(str(bookedFlight.numPassengers))
796 self._bagWeight.set_text(str(bookedFlight.bagWeight))
[84]797 self._cargoWeight.set_int(bookedFlight.cargoWeight)
[70]798 self._cargoWeight.set_sensitive(True)
[60]799 self._mailWeight.set_text(str(bookedFlight.mailWeight))
[92]800 self._simulatorZFW.set_text("-")
801 self._simulatorZFWValue = None
[70]802 self._zfwButton.set_sensitive(True)
[60]803 self._updateCalculatedZFW()
[59]804
[70]805 def finalize(self):
806 """Finalize the payload page."""
807 self._cargoWeight.set_sensitive(False)
808
[84]809 def calculateZFW(self):
[60]810 """Calculate the ZFW value."""
811 zfw = self._wizard.gui._flight.aircraft.dow
812 bookedFlight = self._wizard._bookedFlight
813 zfw += (bookedFlight.numCrew + bookedFlight.numPassengers) * 82
814 zfw += bookedFlight.bagWeight
[84]815 zfw += self._cargoWeight.get_int()
[60]816 zfw += bookedFlight.mailWeight
817 return zfw
818
819 def _updateCalculatedZFW(self):
820 """Update the calculated ZFW"""
[84]821 zfw = self.calculateZFW()
[60]822
823 markupBegin = "<b>"
824 markupEnd = "</b>"
825 if self._simulatorZFWValue is not None and \
826 PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
827 markupBegin += '<span foreground="red">'
828 markupEnd = "</span>" + markupEnd
829 self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
830
[84]831 def _cargoWeightChanged(self, entry, weight):
[60]832 """Called when the cargo weight has changed."""
833 self._updateCalculatedZFW()
834
[59]835 def _zfwRequested(self, button):
836 """Called when the ZFW is requested from the simulator."""
[70]837 self._zfwButton.set_sensitive(False)
838 self._backButton.set_sensitive(False)
839 self._button.set_sensitive(False)
840 gui = self._wizard.gui
841 gui.beginBusy("Querying ZFW...")
842 gui.simulator.requestZFW(self._handleZFW)
[59]843
844 def _handleZFW(self, zfw):
845 """Called when the ZFW value is retrieved."""
[60]846 gobject.idle_add(self._processZFW, zfw)
[59]847
[60]848 def _processZFW(self, zfw):
849 """Process the given ZFW value received from the simulator."""
[61]850 self._wizard.gui.endBusy()
[70]851 self._zfwButton.set_sensitive(True)
852 self._backButton.set_sensitive(True)
853 self._button.set_sensitive(True)
[60]854 self._simulatorZFWValue = zfw
855 self._simulatorZFW.set_text("%.0f" % (zfw,))
856 self._updateCalculatedZFW()
857
858 def _forwardClicked(self, button):
859 """Called when the forward button is clicked."""
860 self._wizard.nextPage()
[70]861
862 def _backClicked(self, button):
863 """Called when the Back button is pressed."""
864 self.goBack()
[60]865
[59]866#-----------------------------------------------------------------------------
867
[61]868class TimePage(Page):
869 """Page displaying the departure and arrival times and allows querying the
870 current time from the flight simulator."""
871 def __init__(self, wizard):
872 help = "The departure and arrival times are displayed below in UTC.\n\n" \
873 "You can also query the current UTC time from the simulator.\n" \
874 "Ensure that you have enough time to properly prepare for the flight."
[94]875 completedHelp = "The departure and arrival times are displayed below in UTC.\n\n" \
876 "You can also query the current UTC time from the simulator.\n"
877 super(TimePage, self).__init__(wizard, "Time", help,
878 completedHelp = completedHelp)
[61]879
880 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
881 xscale = 0.0, yscale = 0.0)
882
883 table = gtk.Table(3, 2)
884 table.set_row_spacings(4)
885 table.set_col_spacings(16)
886 table.set_homogeneous(False)
887 alignment.add(table)
888 self.setMainWidget(alignment)
889
890 label = gtk.Label("Departure:")
891 label.set_alignment(0.0, 0.5)
892 table.attach(label, 0, 1, 0, 1)
893
894 self._departure = gtk.Label()
895 self._departure.set_alignment(0.0, 0.5)
896 table.attach(self._departure, 1, 2, 0, 1)
897
898 label = gtk.Label("Arrival:")
899 label.set_alignment(0.0, 0.5)
900 table.attach(label, 0, 1, 1, 2)
901
902 self._arrival = gtk.Label()
903 self._arrival.set_alignment(0.0, 0.5)
904 table.attach(self._arrival, 1, 2, 1, 2)
905
[70]906 self._timeButton = gtk.Button("_Time from FS:")
907 self._timeButton.set_use_underline(True)
908 self._timeButton.connect("clicked", self._timeRequested)
909 table.attach(self._timeButton, 0, 1, 2, 3)
[61]910
911 self._simulatorTime = gtk.Label("-")
912 self._simulatorTime.set_alignment(0.0, 0.5)
913 table.attach(self._simulatorTime, 1, 2, 2, 3)
914
[70]915 self._backButton = self.addButton(gtk.STOCK_GO_BACK)
916 self._backButton.set_use_stock(True)
917 self._backButton.connect("clicked", self._backClicked)
918
[61]919 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
920 self._button.set_use_stock(True)
921 self._button.connect("clicked", self._forwardClicked)
922
923 def activate(self):
924 """Activate the page."""
[70]925 self._timeButton.set_sensitive(True)
[61]926 bookedFlight = self._wizard._bookedFlight
927 self._departure.set_text(str(bookedFlight.departureTime.time()))
928 self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
[92]929 self._simulatorTime.set_text("-")
[61]930
931 def _timeRequested(self, button):
932 """Request the time from the simulator."""
[70]933 self._timeButton.set_sensitive(False)
934 self._backButton.set_sensitive(False)
935 self._button.set_sensitive(False)
[61]936 self._wizard.gui.beginBusy("Querying time...")
937 self._wizard.gui.simulator.requestTime(self._handleTime)
938
939 def _handleTime(self, timestamp):
940 """Handle the result of a time retrieval."""
941 gobject.idle_add(self._processTime, timestamp)
942
943 def _processTime(self, timestamp):
944 """Process the given time."""
945 self._wizard.gui.endBusy()
[70]946 self._timeButton.set_sensitive(True)
947 self._backButton.set_sensitive(True)
948 self._button.set_sensitive(True)
[61]949 tm = time.gmtime(timestamp)
950 t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
951 self._simulatorTime.set_text(str(t))
952
953 ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
954 dt = self._wizard._bookedFlight.departureTime.time()
955 dts = dt.hour * 3600 + dt.minute * 60 + dt.second
956 diff = dts-ts
957
958 markupBegin = ""
959 markupEnd = ""
960 if diff < 0:
961 markupBegin = '<b><span foreground="red">'
962 markupEnd = '</span></b>'
963 elif diff < 3*60 or diff > 30*60:
964 markupBegin = '<b><span foreground="orange">'
965 markupEnd = '</span></b>'
966
967 self._departure.set_markup(markupBegin + str(dt) + markupEnd)
968
[70]969 def _backClicked(self, button):
970 """Called when the Back button is pressed."""
971 self.goBack()
972
[61]973 def _forwardClicked(self, button):
974 """Called when the forward button is clicked."""
975 self._wizard.nextPage()
976
977#-----------------------------------------------------------------------------
978
[62]979class RoutePage(Page):
980 """The page containing the route and the flight level."""
981 def __init__(self, wizard):
982 help = "Set your cruise flight level below, and\n" \
983 "if necessary, edit the flight plan."
[94]984 completedHelp = "If necessary, you can modify the cruise level and\n" \
985 "the flight plan below during flight.\n" \
986 "If so, please, add a comment on why " \
987 "the modification became necessary."
988 super(RoutePage, self).__init__(wizard, "Route", help,
989 completedHelp = completedHelp)
[62]990
991 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
992 xscale = 0.0, yscale = 0.0)
993
994 mainBox = gtk.VBox()
995 alignment.add(mainBox)
996 self.setMainWidget(alignment)
997
998 levelBox = gtk.HBox()
999
1000 label = gtk.Label("_Cruise level")
1001 label.set_use_underline(True)
1002 levelBox.pack_start(label, True, True, 0)
1003
1004 self._cruiseLevel = gtk.SpinButton()
1005 self._cruiseLevel.set_increments(step = 10, page = 100)
1006 self._cruiseLevel.set_range(min = 50, max = 500)
1007 self._cruiseLevel.set_tooltip_text("The cruise flight level.")
1008 self._cruiseLevel.set_numeric(True)
1009 self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
[97]1010 label.set_mnemonic_widget(self._cruiseLevel)
1011 self._filedCruiseLevel = 240
[62]1012
1013 levelBox.pack_start(self._cruiseLevel, False, False, 8)
1014
1015 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1016 xscale = 0.0, yscale = 0.0)
1017 alignment.add(levelBox)
1018
1019 mainBox.pack_start(alignment, False, False, 0)
1020
1021
1022 routeBox = gtk.VBox()
1023
1024 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1025 xscale = 0.0, yscale = 0.0)
1026 label = gtk.Label("_Route")
1027 label.set_use_underline(True)
1028 alignment.add(label)
1029 routeBox.pack_start(alignment, True, True, 0)
1030
1031 routeWindow = gtk.ScrolledWindow()
1032 routeWindow.set_size_request(400, 80)
1033 routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
1034 else gtk.SHADOW_IN)
[69]1035 routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1036 else gtk.POLICY_AUTOMATIC,
1037 gtk.PolicyType.AUTOMATIC if pygobject
1038 else gtk.POLICY_AUTOMATIC)
[62]1039
1040 self._route = gtk.TextView()
1041 self._route.set_tooltip_text("The planned flight route.")
1042 self._route.get_buffer().connect("changed", self._routeChanged)
1043 routeWindow.add(self._route)
1044
1045 label.set_mnemonic_widget(self._route)
1046 routeBox.pack_start(routeWindow, True, True, 0)
1047
1048 mainBox.pack_start(routeBox, True, True, 8)
1049
[70]1050 self._backButton = self.addButton(gtk.STOCK_GO_BACK)
1051 self._backButton.set_use_stock(True)
1052 self._backButton.connect("clicked", self._backClicked)
1053
[62]1054 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
1055 self._button.set_use_stock(True)
1056 self._button.connect("clicked", self._forwardClicked)
1057
[84]1058 @property
[97]1059 def filedCruiseLevel(self):
1060 """Get the filed cruise level."""
1061 return self._filedCruiseLevel
1062
1063 @property
[84]1064 def cruiseLevel(self):
1065 """Get the cruise level."""
1066 return self._cruiseLevel.get_value_as_int()
1067
[97]1068 @property
1069 def route(self):
1070 """Get the route."""
1071 return self._getRoute()
1072
[62]1073 def activate(self):
1074 """Setup the route from the booked flight."""
[92]1075 self._cruiseLevel.set_value(240)
[97]1076 self._filedCruiseLevel = 240
[62]1077 self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
1078 self._updateForwardButton()
1079
1080 def _getRoute(self):
1081 """Get the text of the route."""
1082 buffer = self._route.get_buffer()
1083 return buffer.get_text(buffer.get_start_iter(),
1084 buffer.get_end_iter(), True)
1085
1086 def _updateForwardButton(self):
1087 """Update the sensitivity of the forward button."""
1088 self._button.set_sensitive(self._cruiseLevel.get_value_as_int()>=50 and \
[68]1089 self._getRoute()!="")
[62]1090
1091 def _cruiseLevelChanged(self, spinButton):
1092 """Called when the cruise level has changed."""
1093 self._updateForwardButton()
1094
1095 def _routeChanged(self, textBuffer):
1096 """Called when the route has changed."""
1097 self._updateForwardButton()
1098
[70]1099 def _backClicked(self, button):
1100 """Called when the Back button is pressed."""
1101 self.goBack()
1102
[62]1103 def _forwardClicked(self, button):
1104 """Called when the Forward button is clicked."""
[94]1105 if self._completed:
[70]1106 self._wizard.nextPage()
1107 else:
1108 bookedFlight = self._wizard._bookedFlight
[97]1109 self._filedCruiseLevel = self.cruiseLevel
[70]1110 self._wizard.gui.beginBusy("Downloading NOTAMs...")
1111 self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
1112 bookedFlight.departureICAO,
1113 bookedFlight.arrivalICAO)
[64]1114
1115 def _notamsCallback(self, returned, result):
1116 """Callback for the NOTAMs."""
1117 gobject.idle_add(self._handleNOTAMs, returned, result)
1118
1119 def _handleNOTAMs(self, returned, result):
1120 """Handle the NOTAMs."""
1121 if returned:
1122 self._wizard._departureNOTAMs = result.departureNOTAMs
1123 self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
[67]1124 else:
1125 self._wizard._departureNOTAMs = None
1126 self._wizard._arrivalNOTAMs = None
[64]1127
[67]1128 bookedFlight = self._wizard._bookedFlight
1129 self._wizard.gui.beginBusy("Downloading METARs...")
1130 self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
1131 [bookedFlight.departureICAO,
1132 bookedFlight.arrivalICAO])
1133
1134 def _metarsCallback(self, returned, result):
1135 """Callback for the METARs."""
1136 gobject.idle_add(self._handleMETARs, returned, result)
1137
1138 def _handleMETARs(self, returned, result):
1139 """Handle the METARs."""
1140 self._wizard._departureMETAR = None
1141 self._wizard._arrivalMETAR = None
1142 bookedFlight = self._wizard._bookedFlight
1143 if returned:
1144 if bookedFlight.departureICAO in result.metars:
1145 self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
1146 if bookedFlight.arrivalICAO in result.metars:
1147 self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
1148
1149 self._wizard.gui.endBusy()
[70]1150 self._backButton.set_sensitive(True)
1151 self._button.set_sensitive(True)
[62]1152 self._wizard.nextPage()
1153
1154#-----------------------------------------------------------------------------
1155
[67]1156class BriefingPage(Page):
1157 """Page for the briefing."""
1158 def __init__(self, wizard, departure):
1159 """Construct the briefing page."""
1160 self._departure = departure
1161
[69]1162 title = "Briefing (%d/2): %s" % (1 if departure else 2,
1163 "departure" if departure
1164 else "arrival")
[67]1165
[94]1166 help = "Read carefully the NOTAMs and METAR below.\n\n" \
1167 "You can edit the METAR if your simulator or network\n" \
1168 "provides different weather."
1169 completedHelp = "If your simulator or network provides a different\n" \
1170 "weather, you can edit the METAR below."
1171 super(BriefingPage, self).__init__(wizard, title, help,
1172 completedHelp = completedHelp)
[64]1173
1174 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1175 xscale = 1.0, yscale = 1.0)
1176
1177 mainBox = gtk.VBox()
1178 alignment.add(mainBox)
1179 self.setMainWidget(alignment)
1180
[67]1181 self._notamsFrame = gtk.Frame()
1182 self._notamsFrame.set_label("LHBP NOTAMs")
[64]1183 scrolledWindow = gtk.ScrolledWindow()
[67]1184 scrolledWindow.set_size_request(-1, 128)
[94]1185 # FIXME: these constants should be in common
[69]1186 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1187 else gtk.POLICY_AUTOMATIC,
1188 gtk.PolicyType.AUTOMATIC if pygobject
1189 else gtk.POLICY_AUTOMATIC)
[67]1190 self._notams = gtk.TextView()
1191 self._notams.set_editable(False)
1192 self._notams.set_accepts_tab(False)
1193 self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
1194 scrolledWindow.add(self._notams)
1195 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1196 xscale = 1.0, yscale = 1.0)
1197 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1198 padding_left = 0, padding_right = 0)
1199 alignment.add(scrolledWindow)
1200 self._notamsFrame.add(alignment)
1201 mainBox.pack_start(self._notamsFrame, True, True, 4)
1202
1203 self._metarFrame = gtk.Frame()
1204 self._metarFrame.set_label("LHBP METAR")
1205 scrolledWindow = gtk.ScrolledWindow()
1206 scrolledWindow.set_size_request(-1, 32)
[69]1207 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1208 else gtk.POLICY_AUTOMATIC,
1209 gtk.PolicyType.AUTOMATIC if pygobject
1210 else gtk.POLICY_AUTOMATIC)
[67]1211 self._metar = gtk.TextView()
1212 self._metar.set_accepts_tab(False)
1213 self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
[106]1214 self._metar.get_buffer().connect("changed", self._metarChanged)
[67]1215 scrolledWindow.add(self._metar)
1216 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1217 xscale = 1.0, yscale = 1.0)
1218 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1219 padding_left = 0, padding_right = 0)
1220 alignment.add(scrolledWindow)
1221 self._metarFrame.add(alignment)
1222 mainBox.pack_start(self._metarFrame, True, True, 4)
[106]1223 self.metarEdited = False
[64]1224
[70]1225 button = self.addButton(gtk.STOCK_GO_BACK)
1226 button.set_use_stock(True)
1227 button.connect("clicked", self._backClicked)
1228
[64]1229 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
1230 self._button.set_use_stock(True)
1231 self._button.connect("clicked", self._forwardClicked)
1232
[97]1233 @property
1234 def metar(self):
1235 """Get the METAR on the page."""
1236 buffer = self._metar.get_buffer()
1237 return buffer.get_text(buffer.get_start_iter(),
1238 buffer.get_end_iter(), True)
1239
[106]1240 def setMETAR(self, metar):
1241 """Set the metar."""
1242 self._metar.get_buffer().set_text(metar)
1243 self.metarEdited = False
1244
[64]1245 def activate(self):
1246 """Activate the page."""
[70]1247 if not self._departure:
1248 self._button.set_label("I have read the briefing and am ready to fly!")
1249 self._button.set_use_stock(False)
1250
1251 bookedFlight = self._wizard._bookedFlight
[67]1252
[70]1253 icao = bookedFlight.departureICAO if self._departure \
1254 else bookedFlight.arrivalICAO
1255 notams = self._wizard._departureNOTAMs if self._departure \
1256 else self._wizard._arrivalNOTAMs
1257 metar = self._wizard._departureMETAR if self._departure \
1258 else self._wizard._arrivalMETAR
[64]1259
[70]1260 self._notamsFrame.set_label(icao + " NOTAMs")
1261 buffer = self._notams.get_buffer()
1262 if notams is None:
1263 buffer.set_text("Could not download NOTAMs")
[92]1264 elif not notams:
1265 buffer.set_text("Could not download NOTAM for this airport")
[70]1266 else:
1267 s = ""
1268 for notam in notams:
1269 s += str(notam.begin)
1270 if notam.end is not None:
1271 s += " - " + str(notam.end)
1272 elif notam.permanent:
1273 s += " - PERMANENT"
1274 s += "\n"
1275 if notam.repeatCycle:
1276 s += "Repeat cycle: " + notam.repeatCycle + "\n"
1277 s += notam.notice + "\n"
1278 s += "-------------------- * --------------------\n"
1279 buffer.set_text(s)
[67]1280
[70]1281 self._metarFrame.set_label(icao + " METAR")
1282 buffer = self._metar.get_buffer()
1283 if metar is None:
1284 buffer.set_text("Could not download METAR")
1285 else:
1286 buffer.set_text(metar)
[67]1287
[106]1288 self.metarEdited = False
1289
[70]1290 def _backClicked(self, button):
1291 """Called when the Back button is pressed."""
1292 self.goBack()
1293
[67]1294 def _forwardClicked(self, button):
[64]1295 """Called when the forward button is clicked."""
[70]1296 if not self._departure:
[94]1297 if not self._completed:
[70]1298 self._wizard.gui.startMonitoring()
[86]1299 self._button.set_use_stock(True)
1300 self._button.set_label(gtk.STOCK_GO_FORWARD)
[94]1301 self.complete()
[71]1302
1303 self._wizard.nextPage()
1304
[106]1305 def _metarChanged(self, buffer):
1306 """Called when the METAR has changed."""
1307 self.metarEdited = True
1308 self._button.set_sensitive(buffer.get_text(buffer.get_start_iter(),
1309 buffer.get_end_iter(),
1310 True)!="")
1311
[71]1312#-----------------------------------------------------------------------------
1313
1314class TakeoffPage(Page):
1315 """Page for entering the takeoff data."""
1316 def __init__(self, wizard):
1317 """Construct the takeoff page."""
1318 help = "Enter the runway and SID used, as well as the speeds."
[94]1319 completedHelp = "The runway, SID and takeoff speeds logged can be seen below."
[71]1320
[94]1321 super(TakeoffPage, self).__init__(wizard, "Takeoff", help,
1322 completedHelp = completedHelp)
[71]1323
[101]1324 self._forwardAllowed = False
1325
[71]1326 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1327 xscale = 0.0, yscale = 0.0)
1328
[84]1329 table = gtk.Table(5, 4)
[71]1330 table.set_row_spacings(4)
1331 table.set_col_spacings(16)
1332 table.set_homogeneous(False)
1333 alignment.add(table)
1334 self.setMainWidget(alignment)
1335
1336 label = gtk.Label("Run_way:")
1337 label.set_use_underline(True)
1338 label.set_alignment(0.0, 0.5)
1339 table.attach(label, 0, 1, 0, 1)
1340
1341 self._runway = gtk.Entry()
1342 self._runway.set_width_chars(10)
1343 self._runway.set_tooltip_text("The runway the takeoff is performed from.")
[101]1344 self._runway.connect("changed", self._valueChanged)
[84]1345 table.attach(self._runway, 1, 3, 0, 1)
[71]1346 label.set_mnemonic_widget(self._runway)
1347
1348 label = gtk.Label("_SID:")
1349 label.set_use_underline(True)
1350 label.set_alignment(0.0, 0.5)
1351 table.attach(label, 0, 1, 1, 2)
1352
1353 self._sid = gtk.Entry()
1354 self._sid.set_width_chars(10)
[75]1355 self._sid.set_tooltip_text("The name of the Standard Instrument Deparature procedure followed.")
[101]1356 self._sid.connect("changed", self._valueChanged)
[84]1357 table.attach(self._sid, 1, 3, 1, 2)
[71]1358 label.set_mnemonic_widget(self._sid)
1359
1360 label = gtk.Label("V<sub>_1</sub>:")
1361 label.set_use_markup(True)
1362 label.set_use_underline(True)
1363 label.set_alignment(0.0, 0.5)
1364 table.attach(label, 0, 1, 2, 3)
1365
[84]1366 self._v1 = IntegerEntry()
[86]1367 self._v1.set_width_chars(4)
[71]1368 self._v1.set_tooltip_markup("The takeoff decision speed in knots.")
[101]1369 self._v1.connect("integer-changed", self._valueChanged)
[84]1370 table.attach(self._v1, 2, 3, 2, 3)
[71]1371 label.set_mnemonic_widget(self._v1)
1372
[84]1373 table.attach(gtk.Label("knots"), 3, 4, 2, 3)
[71]1374
[86]1375 label = gtk.Label("V<sub>_R</sub>:")
[71]1376 label.set_use_markup(True)
1377 label.set_use_underline(True)
1378 label.set_alignment(0.0, 0.5)
1379 table.attach(label, 0, 1, 3, 4)
1380
[84]1381 self._vr = IntegerEntry()
[86]1382 self._vr.set_width_chars(4)
[71]1383 self._vr.set_tooltip_markup("The takeoff rotation speed in knots.")
[101]1384 self._vr.connect("integer-changed", self._valueChanged)
[84]1385 table.attach(self._vr, 2, 3, 3, 4)
[71]1386 label.set_mnemonic_widget(self._vr)
1387
[84]1388 table.attach(gtk.Label("knots"), 3, 4, 3, 4)
[71]1389
1390 label = gtk.Label("V<sub>_2</sub>:")
1391 label.set_use_markup(True)
1392 label.set_use_underline(True)
1393 label.set_alignment(0.0, 0.5)
1394 table.attach(label, 0, 1, 4, 5)
1395
[84]1396 self._v2 = IntegerEntry()
[86]1397 self._v2.set_width_chars(4)
[71]1398 self._v2.set_tooltip_markup("The takeoff safety speed in knots.")
[101]1399 self._v2.connect("integer-changed", self._valueChanged)
[84]1400 table.attach(self._v2, 2, 3, 4, 5)
[71]1401 label.set_mnemonic_widget(self._v2)
1402
[84]1403 table.attach(gtk.Label("knots"), 3, 4, 4, 5)
[71]1404
1405 button = self.addButton(gtk.STOCK_GO_BACK)
1406 button.set_use_stock(True)
1407 button.connect("clicked", self._backClicked)
1408
1409 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
1410 self._button.set_use_stock(True)
1411 self._button.connect("clicked", self._forwardClicked)
1412
[84]1413 @property
[97]1414 def runway(self):
1415 """Get the runway."""
1416 return self._runway.get_text()
1417
1418 @property
1419 def sid(self):
1420 """Get the SID."""
1421 return self._sid.get_text()
1422
1423 @property
[84]1424 def v1(self):
1425 """Get the v1 speed."""
1426 return self._v1.get_int()
1427
1428 @property
1429 def vr(self):
1430 """Get the vr speed."""
1431 return self._vr.get_int()
1432
1433 @property
1434 def v2(self):
1435 """Get the v2 speed."""
1436 return self._v2.get_int()
1437
[71]1438 def activate(self):
1439 """Activate the page."""
[72]1440 self._runway.set_text("")
[71]1441 self._runway.set_sensitive(True)
[72]1442 self._sid.set_text("")
[71]1443 self._sid.set_sensitive(True)
[84]1444 self._v1.set_int(None)
[71]1445 self._v1.set_sensitive(True)
[86]1446 self._vr.set_int(None)
[71]1447 self._vr.set_sensitive(True)
[86]1448 self._v2.set_int(None)
[71]1449 self._v2.set_sensitive(True)
[84]1450 self._button.set_sensitive(False)
[71]1451
[101]1452 def finalize(self):
1453 """Finalize the page."""
[71]1454 self._runway.set_sensitive(False)
1455 self._sid.set_sensitive(False)
1456 self._v1.set_sensitive(False)
1457 self._vr.set_sensitive(False)
1458 self._v2.set_sensitive(False)
[101]1459 self._wizard.gui.flight.aircraft.updateV1R2()
1460
1461 def allowForward(self):
1462 """Allow going to the next page."""
1463 self._forwardAllowed = True
1464 self._updateForwardButton()
1465
1466 def _updateForwardButton(self):
1467 """Update the sensitivity of the forward button based on some conditions."""
1468 sensitive = self._forwardAllowed and \
1469 self._runway.get_text()!="" and \
1470 self._sid.get_text()!="" and \
1471 self.v1 is not None and \
1472 self.vr is not None and \
1473 self.v2 is not None and \
1474 self.v1 <= self.vr and \
1475 self.vr <= self.v2
1476 self._button.set_sensitive(sensitive)
1477
1478 def _valueChanged(self, widget, arg = None):
1479 """Called when the value of some widget has changed."""
1480 self._updateForwardButton()
[84]1481
[71]1482 def _backClicked(self, button):
1483 """Called when the Back button is pressed."""
1484 self.goBack()
1485
1486 def _forwardClicked(self, button):
1487 """Called when the forward button is clicked."""
[75]1488 self._wizard.nextPage()
1489
1490#-----------------------------------------------------------------------------
1491
1492class LandingPage(Page):
1493 """Page for entering landing data."""
1494 def __init__(self, wizard):
1495 """Construct the landing page."""
1496 help = "Enter the STAR and/or transition, runway,\n" \
[86]1497 "approach type and V<sub>Ref</sub> used."
[94]1498 completedHelp = "The STAR and/or transition, runway, approach\n" \
1499 "type and V<sub>Ref</sub> logged can be seen below."
[75]1500
[94]1501 super(LandingPage, self).__init__(wizard, "Landing", help,
1502 completedHelp = completedHelp)
[75]1503
[88]1504 self._flightEnded = False
1505
[75]1506 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1507 xscale = 0.0, yscale = 0.0)
1508
[86]1509 table = gtk.Table(5, 5)
[75]1510 table.set_row_spacings(4)
1511 table.set_col_spacings(16)
1512 table.set_homogeneous(False)
1513 alignment.add(table)
1514 self.setMainWidget(alignment)
1515
1516 self._starButton = gtk.CheckButton()
1517 self._starButton.connect("clicked", self._starButtonClicked)
1518 table.attach(self._starButton, 0, 1, 0, 1)
1519
1520 label = gtk.Label("_STAR:")
1521 label.set_use_underline(True)
1522 label.set_alignment(0.0, 0.5)
1523 table.attach(label, 1, 2, 0, 1)
1524
1525 self._star = gtk.Entry()
1526 self._star.set_width_chars(10)
1527 self._star.set_tooltip_text("The name of Standard Terminal Arrival Route followed.")
1528 self._star.connect("changed", self._updateForwardButton)
1529 self._star.set_sensitive(False)
[86]1530 table.attach(self._star, 2, 4, 0, 1)
[75]1531 label.set_mnemonic_widget(self._starButton)
1532
1533 self._transitionButton = gtk.CheckButton()
1534 self._transitionButton.connect("clicked", self._transitionButtonClicked)
1535 table.attach(self._transitionButton, 0, 1, 1, 2)
1536
1537 label = gtk.Label("_Transition:")
1538 label.set_use_underline(True)
1539 label.set_alignment(0.0, 0.5)
1540 table.attach(label, 1, 2, 1, 2)
1541
1542 self._transition = gtk.Entry()
1543 self._transition.set_width_chars(10)
1544 self._transition.set_tooltip_text("The name of transition executed or VECTORS if vectored by ATC.")
1545 self._transition.connect("changed", self._updateForwardButton)
1546 self._transition.set_sensitive(False)
[86]1547 table.attach(self._transition, 2, 4, 1, 2)
[75]1548 label.set_mnemonic_widget(self._transitionButton)
1549
1550 label = gtk.Label("Run_way:")
1551 label.set_use_underline(True)
1552 label.set_alignment(0.0, 0.5)
1553 table.attach(label, 1, 2, 2, 3)
1554
1555 self._runway = gtk.Entry()
1556 self._runway.set_width_chars(10)
1557 self._runway.set_tooltip_text("The runway the landing is performed on.")
1558 self._runway.connect("changed", self._updateForwardButton)
[86]1559 table.attach(self._runway, 2, 4, 2, 3)
[75]1560 label.set_mnemonic_widget(self._runway)
1561
1562 label = gtk.Label("_Approach type:")
1563 label.set_use_underline(True)
1564 label.set_alignment(0.0, 0.5)
1565 table.attach(label, 1, 2, 3, 4)
1566
1567 self._approachType = gtk.Entry()
1568 self._approachType.set_width_chars(10)
1569 self._approachType.set_tooltip_text("The type of the approach, e.g. ILS or VISUAL.")
[76]1570 self._approachType.connect("changed", self._updateForwardButton)
[86]1571 table.attach(self._approachType, 2, 4, 3, 4)
[75]1572 label.set_mnemonic_widget(self._approachType)
1573
[86]1574 label = gtk.Label("V<sub>_Ref</sub>:")
[75]1575 label.set_use_markup(True)
1576 label.set_use_underline(True)
1577 label.set_alignment(0.0, 0.5)
1578 table.attach(label, 1, 2, 5, 6)
1579
[86]1580 self._vref = IntegerEntry()
1581 self._vref.set_width_chars(5)
[75]1582 self._vref.set_tooltip_markup("The approach reference speed in knots.")
[86]1583 self._vref.connect("integer-changed", self._vrefChanged)
1584 table.attach(self._vref, 3, 4, 5, 6)
[75]1585 label.set_mnemonic_widget(self._vref)
1586
[86]1587 table.attach(gtk.Label("knots"), 4, 5, 5, 6)
[75]1588
1589 button = self.addButton(gtk.STOCK_GO_BACK)
1590 button.set_use_stock(True)
1591 button.connect("clicked", self._backClicked)
1592
1593 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
1594 self._button.set_use_stock(True)
1595 self._button.connect("clicked", self._forwardClicked)
1596
[76]1597 # These are needed for correct size calculations
1598 self._starButton.set_active(True)
1599 self._transitionButton.set_active(True)
1600
[86]1601 @property
[97]1602 def star(self):
1603 """Get the STAR or None if none entered."""
1604 return self._star.get_text() if self._starButton.get_active() else None
1605
1606 @property
1607 def transition(self):
1608 """Get the transition or None if none entered."""
1609 return self._transition.get_text() \
1610 if self._transitionButton.get_active() else None
1611
1612 @property
1613 def approachType(self):
1614 """Get the approach type."""
1615 return self._approachType.get_text()
1616
1617 @property
1618 def runway(self):
1619 """Get the runway."""
1620 return self._runway.get_text()
1621
1622 @property
[86]1623 def vref(self):
1624 """Return the landing reference speed."""
1625 return self._vref.get_int()
1626
[75]1627 def activate(self):
1628 """Called when the page is activated."""
1629 self._starButton.set_sensitive(True)
1630 self._starButton.set_active(False)
1631 self._star.set_text("")
1632
1633 self._transitionButton.set_sensitive(True)
1634 self._transitionButton.set_active(False)
1635 self._transition.set_text("")
1636
1637 self._runway.set_text("")
1638 self._runway.set_sensitive(True)
1639
1640 self._approachType.set_text("")
1641 self._approachType.set_sensitive(True)
1642
[86]1643 self._vref.set_int(None)
[75]1644 self._vref.set_sensitive(True)
1645
1646 self._updateForwardButton()
1647
[88]1648 def flightEnded(self):
1649 """Called when the flight has ended."""
1650 self._flightEnded = True
1651 self._updateForwardButton()
1652
[75]1653 def finalize(self):
1654 """Finalize the page."""
1655 self._starButton.set_sensitive(False)
1656 self._star.set_sensitive(False)
1657
1658 self._transitionButton.set_sensitive(False)
1659 self._transition.set_sensitive(False)
1660
1661 self._runway.set_sensitive(False)
1662
1663 self._approachType.set_sensitive(False)
1664
1665 self._vref.set_sensitive(False)
[96]1666 self._wizard.gui.flight.aircraft.updateVRef()
[89]1667 # FIXME: Perhaps a separate initialize() call which would set up
[96]1668 # defaults? -> use reset()
[89]1669 self._flightEnded = False
[75]1670
1671 def _starButtonClicked(self, button):
1672 """Called when the STAR button is clicked."""
1673 active = button.get_active()
1674 self._star.set_sensitive(active)
1675 if active:
1676 self._star.grab_focus()
1677 self._updateForwardButton()
1678
1679 def _transitionButtonClicked(self, button):
1680 """Called when the Transition button is clicked."""
1681 active = button.get_active()
1682 self._transition.set_sensitive(active)
1683 if active:
1684 self._transition.grab_focus()
[86]1685 self._updateForwardButton()
[75]1686
1687 def _updateForwardButton(self, widget = None):
1688 """Update the sensitivity of the forward button."""
[88]1689 sensitive = self._flightEnded and \
1690 (self._starButton.get_active() or \
[75]1691 self._transitionButton.get_active()) and \
1692 (self._star.get_text()!="" or
1693 not self._starButton.get_active()) and \
1694 (self._transition.get_text()!="" or
1695 not self._transitionButton.get_active()) and \
1696 self._runway.get_text()!="" and \
[86]1697 self._approachType.get_text()!="" and \
1698 self.vref is not None
[75]1699 self._button.set_sensitive(sensitive)
1700
[86]1701 def _vrefChanged(self, widget, value):
1702 """Called when the Vref has changed."""
1703 self._updateForwardButton()
1704
[75]1705 def _backClicked(self, button):
1706 """Called when the Back button is pressed."""
1707 self.goBack()
1708
1709 def _forwardClicked(self, button):
1710 """Called when the forward button is clicked."""
[89]1711 self._wizard.nextPage()
1712
1713#-----------------------------------------------------------------------------
1714
1715class FinishPage(Page):
1716 """Flight finish page."""
[97]1717 _flightTypes = [ ("scheduled", const.FLIGHTTYPE_SCHEDULED),
1718 ("old-timer", const.FLIGHTTYPE_OLDTIMER),
1719 ("VIP", const.FLIGHTTYPE_VIP),
1720 ("charter", const.FLIGHTTYPE_CHARTER) ]
1721
[89]1722 def __init__(self, wizard):
1723 """Construct the finish page."""
1724 help = "There are some statistics about your flight below.\n\n" \
1725 "Review the data, also on earlier pages, and if you are\n" \
1726 "satisfied, you can save or send your PIREP."
1727
1728 super(FinishPage, self).__init__(wizard, "Finish", help)
1729
1730 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1731 xscale = 0.0, yscale = 0.0)
1732
[96]1733 table = gtk.Table(7, 2)
[89]1734 table.set_row_spacings(4)
1735 table.set_col_spacings(16)
[96]1736 table.set_homogeneous(False)
[89]1737 alignment.add(table)
1738 self.setMainWidget(alignment)
1739
1740 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1741 label = gtk.Label("Flight rating:")
1742 labelAlignment.add(label)
1743 table.attach(labelAlignment, 0, 1, 0, 1)
1744
1745 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1746 self._flightRating = gtk.Label()
1747 self._flightRating.set_width_chars(7)
1748 self._flightRating.set_alignment(0.0, 0.5)
1749 self._flightRating.set_use_markup(True)
1750 labelAlignment.add(self._flightRating)
1751 table.attach(labelAlignment, 1, 2, 0, 1)
1752
1753 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1754 label = gtk.Label("Flight time:")
1755 labelAlignment.add(label)
1756 table.attach(labelAlignment, 0, 1, 1, 2)
1757
1758 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1759 self._flightTime = gtk.Label()
1760 self._flightTime.set_width_chars(10)
1761 self._flightTime.set_alignment(0.0, 0.5)
1762 self._flightTime.set_use_markup(True)
1763 labelAlignment.add(self._flightTime)
1764 table.attach(labelAlignment, 1, 2, 1, 2)
1765
1766 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1767 label = gtk.Label("Block time:")
1768 labelAlignment.add(label)
1769 table.attach(labelAlignment, 0, 1, 2, 3)
1770
1771 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1772 self._blockTime = gtk.Label()
1773 self._blockTime.set_width_chars(10)
1774 self._blockTime.set_alignment(0.0, 0.5)
1775 self._blockTime.set_use_markup(True)
1776 labelAlignment.add(self._blockTime)
1777 table.attach(labelAlignment, 1, 2, 2, 3)
1778
1779 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1780 label = gtk.Label("Distance flown:")
1781 labelAlignment.add(label)
1782 table.attach(labelAlignment, 0, 1, 3, 4)
1783
1784 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1785 self._distanceFlown = gtk.Label()
1786 self._distanceFlown.set_width_chars(10)
1787 self._distanceFlown.set_alignment(0.0, 0.5)
1788 self._distanceFlown.set_use_markup(True)
1789 labelAlignment.add(self._distanceFlown)
1790 table.attach(labelAlignment, 1, 2, 3, 4)
1791
1792 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1793 label = gtk.Label("Fuel used:")
1794 labelAlignment.add(label)
1795 table.attach(labelAlignment, 0, 1, 4, 5)
1796
1797 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1798 self._fuelUsed = gtk.Label()
1799 self._fuelUsed.set_width_chars(10)
1800 self._fuelUsed.set_alignment(0.0, 0.5)
1801 self._fuelUsed.set_use_markup(True)
1802 labelAlignment.add(self._fuelUsed)
1803 table.attach(labelAlignment, 1, 2, 4, 5)
1804
[96]1805 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1806 label = gtk.Label("_Type:")
1807 label.set_use_underline(True)
1808 labelAlignment.add(label)
1809 table.attach(labelAlignment, 0, 1, 5, 6)
1810
1811 flightTypeModel = gtk.ListStore(str, int)
[97]1812 for (name, type) in FinishPage._flightTypes:
1813 flightTypeModel.append([name, type])
[96]1814
1815 self._flightType = gtk.ComboBox(model = flightTypeModel)
1816 renderer = gtk.CellRendererText()
1817 self._flightType.pack_start(renderer, True)
1818 self._flightType.add_attribute(renderer, "text", 0)
1819 self._flightType.set_tooltip_text("Select the type of the flight.")
1820 self._flightType.set_active(0)
1821 self._flightType.connect("changed", self._flightTypeChanged)
1822 flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1823 flightTypeAlignment.add(self._flightType)
1824 table.attach(flightTypeAlignment, 1, 2, 5, 6)
1825 label.set_mnemonic_widget(self._flightType)
1826
1827 self._onlineFlight = gtk.CheckButton("_Online flight")
1828 self._onlineFlight.set_use_underline(True)
1829 self._onlineFlight.set_tooltip_text("Check if your flight was online, uncheck otherwise.")
1830 onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1831 onlineFlightAlignment.add(self._onlineFlight)
1832 table.attach(onlineFlightAlignment, 1, 2, 6, 7)
1833
[94]1834 button = self.addButton(gtk.STOCK_GO_BACK)
1835 button.set_use_stock(True)
1836 button.connect("clicked", self._backClicked)
1837
[89]1838 self._saveButton = self.addButton("S_ave PIREP...")
1839 self._saveButton.set_use_underline(True)
[94]1840 self._saveButton.set_sensitive(False)
[89]1841 #self._saveButton.connect("clicked", self._saveClicked)
1842
1843 self._sendButton = self.addButton("_Send PIREP...", True)
1844 self._sendButton.set_use_underline(True)
[94]1845 self._sendButton.set_sensitive(False)
[97]1846 self._sendButton.connect("clicked", self._sendClicked)
1847
1848 @property
1849 def flightType(self):
1850 """Get the flight type."""
1851 index = self._flightType.get_active()
1852 return None if index<0 else self._flightType.get_model()[index][1]
1853
1854 @property
1855 def online(self):
1856 """Get whether the flight was an online flight or not."""
1857 return self._onlineFlight.get_active()
[89]1858
1859 def activate(self):
1860 """Activate the page."""
1861 flight = self._wizard.gui._flight
1862 rating = flight.logger.getRating()
1863 if rating<0:
1864 self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
1865 else:
1866 self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
1867
1868 flightLength = flight.flightTimeEnd - flight.flightTimeStart
1869 self._flightTime.set_markup("<b>%s</b>" % \
1870 (util.getTimeIntervalString(flightLength),))
1871
1872 blockLength = flight.blockTimeEnd - flight.blockTimeStart
1873 self._blockTime.set_markup("<b>%s</b>" % \
1874 (util.getTimeIntervalString(blockLength),))
1875
1876 self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
1877 (flight.flownDistance,))
1878
1879 self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
[102]1880 (flight.startFuel - flight.endFuel,))
[64]1881
[96]1882 self._flightType.set_active(-1)
1883 self._onlineFlight.set_active(True)
1884
[94]1885 def _backClicked(self, button):
1886 """Called when the Back button is pressed."""
1887 self.goBack()
[96]1888
1889 def _flightTypeChanged(self, comboBox):
1890 """Called when the flight type has changed."""
1891 index = self._flightType.get_active()
1892 flightTypeIsValid = index>=0
[97]1893 #self._saveButton.set_sensitive(flightTypeIsValid)
[96]1894 self._sendButton.set_sensitive(flightTypeIsValid)
[97]1895
1896 def _sendClicked(self, button):
1897 """Called when the Send button is clicked."""
1898 pirep = PIREP(self._wizard.gui)
1899 gui = self._wizard.gui
1900 gui.beginBusy("Sending PIREP...")
1901 gui.webHandler.sendPIREP(self._pirepSentCallback, pirep)
1902
1903 def _pirepSentCallback(self, returned, result):
1904 """Callback for the PIREP sending result."""
1905 gobject.idle_add(self._handlePIREPSent, returned, result)
1906
1907 def _handlePIREPSent(self, returned, result):
1908 """Callback for the PIREP sending result."""
1909 self._wizard.gui.endBusy()
1910 secondaryMarkup = None
1911 type = MESSAGETYPE_ERROR
1912 if returned:
1913 if result.success:
1914 type = MESSAGETYPE_INFO
1915 messageFormat = "The PIREP was sent successfully."
[105]1916 secondaryMarkup = "Await the thorough scrutiny by our fearless PIREP correctors! :)"
[97]1917 elif result.alreadyFlown:
1918 messageFormat = "The PIREP for this flight has already been sent!"
1919 secondaryMarkup = "You may clear the old PIREP on the MAVA website."
1920 elif result.notAvailable:
1921 messageFormat = "This flight is not available anymore!"
1922 else:
1923 messageFormat = "The MAVA website returned with an unknown error."
1924 secondaryMarkup = "See the debug log for more information."
1925 else:
1926 print "PIREP sending failed", result
1927 messageFormat = "Could not send the PIREP to the MAVA website."
1928 secondaryMarkup = "This can be a network problem, in which case\n" \
1929 "you may try again later. Or it can be a bug;\n" \
1930 "see the debug log for more information."
1931
[105]1932 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
1933 type = type, buttons = BUTTONSTYPE_OK,
[97]1934 message_format = messageFormat)
[105]1935 dialog.set_title(WINDOW_TITLE_BASE)
[97]1936 if secondaryMarkup is not None:
1937 dialog.format_secondary_markup(secondaryMarkup)
1938
1939 dialog.run()
1940 dialog.hide()
[94]1941
[64]1942#-----------------------------------------------------------------------------
1943
[42]1944class Wizard(gtk.VBox):
1945 """The flight wizard."""
1946 def __init__(self, gui):
1947 """Construct the wizard."""
1948 super(Wizard, self).__init__()
1949
1950 self.gui = gui
1951
1952 self._pages = []
1953 self._currentPage = None
1954
1955 self._pages.append(LoginPage(self))
1956 self._pages.append(FlightSelectionPage(self))
[51]1957 self._pages.append(GateSelectionPage(self))
1958 self._pages.append(ConnectPage(self))
[84]1959 self._payloadPage = PayloadPage(self)
1960 self._pages.append(self._payloadPage)
[61]1961 self._pages.append(TimePage(self))
[84]1962 self._routePage = RoutePage(self)
1963 self._pages.append(self._routePage)
[97]1964 self._departureBriefingPage = BriefingPage(self, True)
1965 self._pages.append(self._departureBriefingPage)
1966 self._arrivalBriefingPage = BriefingPage(self, False)
1967 self._pages.append(self._arrivalBriefingPage)
[84]1968 self._takeoffPage = TakeoffPage(self)
1969 self._pages.append(self._takeoffPage)
[86]1970 self._landingPage = LandingPage(self)
1971 self._pages.append(self._landingPage)
[97]1972 self._finishPage = FinishPage(self)
1973 self._pages.append(self._finishPage)
[67]1974
[51]1975 maxWidth = 0
1976 maxHeight = 0
1977 for page in self._pages:
1978 page.show_all()
1979 pageSizeRequest = page.size_request()
1980 width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
1981 height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
1982 maxWidth = max(maxWidth, width)
1983 maxHeight = max(maxHeight, height)
1984 maxWidth += 16
1985 maxHeight += 32
1986 self.set_size_request(maxWidth, maxHeight)
1987
[59]1988 self._initialize()
[51]1989
[48]1990 @property
1991 def loginResult(self):
1992 """Get the login result."""
1993 return self._loginResult
1994
[70]1995 def setCurrentPage(self, index, finalize = False):
[42]1996 """Set the current page to the one with the given index."""
1997 assert index < len(self._pages)
[70]1998
1999 fromPage = self._currentPage
2000 if fromPage is not None:
2001 page = self._pages[fromPage]
[94]2002 if finalize and not page._completed:
2003 page.complete()
[70]2004 self.remove(page)
[42]2005
2006 self._currentPage = index
[70]2007 page = self._pages[index]
2008 self.add(page)
2009 if page._fromPage is None:
2010 page._fromPage = fromPage
[94]2011 page.initialize()
[42]2012 self.show_all()
[72]2013 if fromPage is not None:
2014 self.grabDefault()
[42]2015
[84]2016 @property
[97]2017 def bookedFlight(self):
2018 """Get the booked flight selected."""
2019 return self._bookedFlight
2020
2021 @property
2022 def cargoWeight(self):
2023 """Get the calculated ZFW value."""
2024 return self._payloadPage.cargoWeight
2025
2026 @property
[84]2027 def zfw(self):
2028 """Get the calculated ZFW value."""
2029 return 0 if self._bookedFlight is None \
2030 else self._payloadPage.calculateZFW()
2031
2032 @property
[97]2033 def filedCruiseAltitude(self):
2034 """Get the filed cruise altitude."""
2035 return self._routePage.filedCruiseLevel * 100
2036
2037 @property
[84]2038 def cruiseAltitude(self):
2039 """Get the cruise altitude."""
2040 return self._routePage.cruiseLevel * 100
2041
2042 @property
[97]2043 def route(self):
2044 """Get the route."""
2045 return self._routePage.route
2046
2047 @property
2048 def departureMETAR(self):
2049 """Get the METAR of the departure airport."""
2050 return self._departureBriefingPage.metar
2051
2052 @property
2053 def arrivalMETAR(self):
2054 """Get the METAR of the arrival airport."""
2055 return self._arrivalBriefingPage.metar
2056
2057 @property
2058 def departureRunway(self):
2059 """Get the departure runway."""
2060 return self._takeoffPage.runway
2061
2062 @property
2063 def sid(self):
2064 """Get the SID."""
2065 return self._takeoffPage.sid
2066
2067 @property
[84]2068 def v1(self):
2069 """Get the V1 speed."""
[86]2070 return self._takeoffPage.v1
[84]2071
2072 @property
2073 def vr(self):
2074 """Get the Vr speed."""
[86]2075 return self._takeoffPage.vr
[84]2076
2077 @property
2078 def v2(self):
2079 """Get the V2 speed."""
[86]2080 return self._takeoffPage.v2
2081
2082 @property
[97]2083 def arrivalRunway(self):
2084 """Get the arrival runway."""
2085 return self._landingPage.runway
2086
2087 @property
2088 def star(self):
2089 """Get the STAR."""
2090 return self._landingPage.star
2091
2092 @property
2093 def transition(self):
2094 """Get the transition."""
2095 return self._landingPage.transition
2096
2097 @property
2098 def approachType(self):
2099 """Get the approach type."""
2100 return self._landingPage.approachType
2101
2102 @property
[86]2103 def vref(self):
2104 """Get the Vref speed."""
2105 return self._landingPage.vref
[84]2106
[97]2107 @property
2108 def flightType(self):
2109 """Get the flight type."""
2110 return self._finishPage.flightType
2111
2112 @property
2113 def online(self):
2114 """Get whether the flight was online or not."""
2115 return self._finishPage.online
2116
[70]2117 def nextPage(self, finalize = True):
[42]2118 """Go to the next page."""
[70]2119 self.jumpPage(1, finalize)
[51]2120
[70]2121 def jumpPage(self, count, finalize = True):
[51]2122 """Go to the page which is 'count' pages after the current one."""
[70]2123 self.setCurrentPage(self._currentPage + count, finalize = finalize)
[46]2124
2125 def grabDefault(self):
2126 """Make the default button of the current page the default."""
2127 self._pages[self._currentPage].grabDefault()
[51]2128
[59]2129 def connected(self, fsType, descriptor):
2130 """Called when the connection could be made to the simulator."""
2131 self.nextPage()
2132
[91]2133 def reset(self):
2134 """Resets the wizard to go back to the login page."""
[59]2135 self._initialize()
2136
[84]2137 def setStage(self, stage):
2138 """Set the flight stage to the given one."""
2139 if stage==const.STAGE_TAKEOFF:
[101]2140 self._takeoffPage.allowForward()
[106]2141 elif stage==const.STAGE_LANDING:
2142 if not self._arrivalBriefingPage.metarEdited:
2143 print "Downloading arrival METAR again"
2144 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
2145 [self._bookedFlight.arrivalICAO])
2146
2147 self._takeoffPage.allowForward()
[88]2148 elif stage==const.STAGE_END:
2149 self._landingPage.flightEnded()
[84]2150
[59]2151 def _initialize(self):
2152 """Initialize the wizard."""
2153 self._fleet = None
2154 self._fleetCallback = None
2155 self._updatePlaneCallback = None
2156
2157 self._loginResult = None
2158 self._bookedFlight = None
2159 self._departureGate = "-"
[64]2160 self._departureNOTAMs = None
[67]2161 self._departureMETAR = None
[64]2162 self._arrivalNOTAMs = None
[67]2163 self._arrivalMETAR = None
2164
2165 for page in self._pages:
2166 page.reset()
[62]2167
[59]2168 self.setCurrentPage(0)
2169
[51]2170 def _getFleet(self, callback, force = False):
2171 """Get the fleet, if needed.
2172
2173 callback is function that will be called, when the feet is retrieved,
2174 or the retrieval fails. It should have a single argument that will
2175 receive the fleet object on success, None otherwise.
2176 """
2177 if self._fleet is not None and not force:
2178 callback(self._fleet)
2179
2180 self.gui.beginBusy("Retrieving fleet...")
2181 self._fleetCallback = callback
2182 self.gui.webHandler.getFleet(self._fleetResultCallback)
2183
2184 def _fleetResultCallback(self, returned, result):
2185 """Called when the fleet has been queried."""
2186 gobject.idle_add(self._handleFleetResult, returned, result)
2187
2188 def _handleFleetResult(self, returned, result):
2189 """Handle the fleet result."""
2190 self.gui.endBusy()
2191 if returned:
2192 self._fleet = result.fleet
2193 else:
2194 self._fleet = None
2195
[105]2196 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
2197 type = MESSAGETYPE_ERROR,
[51]2198 buttons = BUTTONSTYPE_OK,
2199 message_format =
2200 "Failed to retrieve the information on "
2201 "the fleet.")
[105]2202 dialog.set_title(WINDOW_TITLE_BASE)
[51]2203 dialog.run()
2204 dialog.hide()
2205
2206 self._fleetCallback(self._fleet)
2207
2208 def _updatePlane(self, callback, tailNumber, status, gateNumber = None):
2209 """Update the given plane's gate information."""
2210 self.gui.beginBusy("Updating plane status...")
2211 self._updatePlaneCallback = callback
2212 self.gui.webHandler.updatePlane(self._updatePlaneResultCallback,
2213 tailNumber, status, gateNumber)
2214
2215 def _updatePlaneResultCallback(self, returned, result):
2216 """Callback for the plane updating operation."""
2217 gobject.idle_add(self._handleUpdatePlaneResult, returned, result)
2218
2219 def _handleUpdatePlaneResult(self, returned, result):
2220 """Handle the result of a plane update operation."""
2221 self.gui.endBusy()
2222 if returned:
2223 success = result.success
2224 else:
2225 success = None
2226
[105]2227 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
2228 type = MESSAGETYPE_ERROR,
[51]2229 buttons = BUTTONSTYPE_OK,
2230 message_format =
2231 "Failed to update the statuis of "
2232 "the airplane.")
[105]2233 dialog.set_title(WINDOW_TITLE_BASE)
[51]2234 dialog.run()
2235 dialog.hide()
2236
2237 self._updatePlaneCallback(success)
2238
2239 def _connectSimulator(self):
2240 """Connect to the simulator."""
[59]2241 self.gui.connectSimulator(self._bookedFlight.aircraftType)
[106]2242
2243 def _arrivalMETARCallback(self, returned, result):
2244 """Called when the METAR of the arrival airport is retrieved."""
2245 gobject.idle_add(self._handleArrivalMETAR, returned, result)
2246
2247 def _handleArrivalMETAR(self, returned, result):
2248 """Called when the METAR of the arrival airport is retrieved."""
2249 icao = self._bookedFlight.arrivalICAO
2250 if returned and icao in result.metars:
2251 metar = result.metars[icao]
2252 if metar!="":
2253 self._arrivalBriefingPage.setMETAR(metar)
[42]2254
2255#-----------------------------------------------------------------------------
2256
Note: See TracBrowser for help on using the repository browser.