source: src/mlx/gui/flight.py@ 139:839016dcd0d1

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

Implemented ACARS sending

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