source: src/mlx/gui/flight.py@ 584:d3f929e0eb3b

Last change on this file since 584:d3f929e0eb3b was 584:d3f929e0eb3b, checked in by István Váradi <ivaradi@…>, 9 years ago

If the METAR cannot be downloaded, the Next button cannot be pressed until the METAR is provided (re #235)

File size: 143.4 KB
RevLine 
[42]1
2from mlx.gui.common import *
3
[51]4import mlx.const as const
5import mlx.fs as fs
[141]6import mlx.acft as acft
[383]7from mlx.flight import Flight
[60]8from mlx.checks import PayloadChecker
[89]9import mlx.util as util
[97]10from mlx.pirep import PIREP
[107]11from mlx.i18n import xstr
[170]12from mlx.sound import startSound
[184]13import mlx.web as web
[51]14
[61]15import datetime
16import time
[393]17import os
[61]18
[42]19#-----------------------------------------------------------------------------
20
[300]21## @package mlx.gui.flight
22#
23# The flight "wizard".
24#
25# This module implements the main tab of the application, the flight
26# wizard. The wizard consists of \ref Page "pages", that come one after the
27# other. As some pages might be skipped, the pages dynamically store the index
28# of the previous page so that going back to it is simpler. The \ref
29# Page.activate "activate" function is called before a page is first shown
30# during a flight. This function should initialize the page's controls and fill
31# it with initial data. When a page is left for the first time, its \ref
32# Page.finalize "finalize" function is called. It should set those controls
33# insensitive, that will not be available if the user comes back to this page.
34#
35# Each page has a title at the top displayed in inverted colors and a big
36# font. There is a help text below it centered, that shortly describes what is
37# expected on the page. There can be two help texts: one shown when the page is
38# first displayed during a flight, another shown when the user goes back to the
39# page. The main content area is below this, also centered. Finally, there are
40# some buttons at the bottom on the right. As some buttons occur very
41# frequently, there are functions to add them (\ref Page.addCancelFlightButton
42# "addCancelFlightButton", \ref Page.addPreviousButton "addPreviousButton" and
43# \ref Page.addNextButton "addNextButton".
44#
45# The \ref Wizard class is the main class to collect the pages. It also stores
46# some data passed from one page to another and provides properties to access
47# data items set via the wizard pages.
48
49#-----------------------------------------------------------------------------
50
[44]51class Page(gtk.Alignment):
[42]52 """A page in the flight wizard."""
[94]53 def __init__(self, wizard, title, help, completedHelp = None):
[42]54 """Construct the page."""
[44]55 super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
56 xscale = 1.0, yscale = 1.0)
57 self.set_padding(padding_top = 4, padding_bottom = 4,
58 padding_left = 12, padding_right = 12)
59
60 frame = gtk.Frame()
61 self.add(frame)
62
63 self._vbox = gtk.VBox()
[48]64 self._vbox.set_homogeneous(False)
[44]65 frame.add(self._vbox)
66
67 eventBox = gtk.EventBox()
68
69 alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
[347]70
[201]71 titleLabel = gtk.Label(title)
72 titleLabel.modify_font(pango.FontDescription("bold 24"))
[44]73 alignment.set_padding(padding_top = 4, padding_bottom = 4,
74 padding_left = 6, padding_right = 0)
[347]75
[201]76 alignment.add(titleLabel)
[44]77 eventBox.add(alignment)
[347]78
[44]79 self._vbox.pack_start(eventBox, False, False, 0)
80
[201]81 self._titleEventBox = eventBox
82 self._titleLabel = titleLabel
83
[347]84 mainBox = gtk.VBox()
[48]85
86 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
[347]87 xscale = 1.0, yscale = 1.0)
[48]88 alignment.set_padding(padding_top = 16, padding_bottom = 16,
89 padding_left = 16, padding_right = 16)
[79]90 alignment.add(mainBox)
[48]91 self._vbox.pack_start(alignment, True, True, 0)
[347]92
[48]93 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
[94]94 xscale = 0.0, yscale = 0.0)
[50]95 alignment.set_padding(padding_top = 0, padding_bottom = 16,
96 padding_left = 0, padding_right = 0)
[48]97
[94]98 self._help = help
99 self._completedHelp = completedHelp
100
101 if self._completedHelp is None or \
102 len(help.splitlines())>=len(completedHelp.splitlines()):
103 longerHelp = help
104 else:
105 longerHelp = completedHelp
[347]106
[556]107 self._helpLabel = gtk.Label(longerHelp)
[94]108 # FIXME: should be a constant in common
109 self._helpLabel.set_justify(gtk.Justification.CENTER if pygobject
110 else gtk.JUSTIFY_CENTER)
111 self._helpLabel.set_use_markup(True)
112 alignment.add(self._helpLabel)
[79]113 mainBox.pack_start(alignment, False, False, 0)
[44]114
115 self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
[48]116 xscale = 1.0, yscale = 1.0)
[79]117 mainBox.pack_start(self._mainAlignment, True, True, 0)
[347]118
[48]119 buttonAlignment = gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
[44]120 buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
121 padding_left = 16, padding_right = 16)
122
[70]123 self._buttonBox = gtk.HBox()
124 self._buttonBox.set_homogeneous(False)
[46]125 self._defaultButton = None
[44]126 buttonAlignment.add(self._buttonBox)
127
128 self._vbox.pack_start(buttonAlignment, False, False, 0)
129
[42]130 self._wizard = wizard
131
[275]132 self._cancelFlightButton = None
133
[94]134 self._completed = False
[70]135 self._fromPage = None
136
[44]137 def setMainWidget(self, widget):
138 """Set the given widget as the main one."""
139 self._mainAlignment.add(widget)
140
[107]141 def addButton(self, label, default = False, sensitive = True,
[208]142 tooltip = None, clicked = None, padding = 4):
[44]143 """Add a button with the given label.
144
145 Return the button object created."""
146 button = gtk.Button(label)
[208]147 self._buttonBox.pack_start(button, False, False, padding)
[48]148 button.set_use_underline(True)
[46]149 if default:
150 button.set_can_default(True)
151 self._defaultButton = button
[107]152 button.set_sensitive(sensitive)
153 if tooltip is not None:
154 button.set_tooltip_text(tooltip)
155 if clicked is not None:
156 button.connect("clicked", clicked)
[44]157 return button
158
[208]159 def addCancelFlightButton(self):
160 """Add the 'Cancel flight' button to the page."""
[275]161 self._cancelFlightButton = \
162 self.addButton(xstr("button_cancelFlight"),
163 sensitive = True,
164 tooltip = xstr("button_cancelFlight_tooltip"),
165 clicked = self._cancelFlight,
166 padding = 16)
167 return self._cancelFlightButton
[208]168
[107]169 def addPreviousButton(self, sensitive = True, clicked = None):
170 """Add the 'Next' button to the page."""
171 return self.addButton(xstr("button_previous"),
172 sensitive = sensitive,
173 tooltip = xstr("button_previous_tooltip"),
174 clicked = clicked)
175
176 def addNextButton(self, default = True, sensitive = True,
177 clicked = None):
178 """Add the 'Next' button to the page."""
179 return self.addButton(xstr("button_next"),
180 default = default,
181 sensitive = sensitive,
182 tooltip = xstr("button_next_tooltip"),
183 clicked = clicked)
184
[201]185 def setStyle(self):
186 """Set the styles of some of the items on the page."""
[413]187 if pygobject:
188 context = self.get_style_context()
189 color = context.get_background_color(gtk.StateFlags.SELECTED)
190 self._titleEventBox.modify_bg(0, color.to_color())
191 color = context.get_color(gtk.StateFlags.SELECTED)
192 self._titleLabel.modify_fg(0, color.to_color())
193 else:
194 style = self.rc_get_style()
195 self._titleEventBox.modify_bg(0, style.bg[3])
196 self._titleLabel.modify_fg(0, style.fg[3])
[347]197
[94]198 def initialize(self):
199 """Initialize the page.
200
201 It sets up the primary help, and calls the activate() function."""
202 self._helpLabel.set_markup(self._help)
203 self._helpLabel.set_sensitive(True)
204 self.activate()
205
[48]206 def activate(self):
207 """Called when this page becomes active.
208
209 This default implementation does nothing."""
210 pass
211
[563]212 def setHelp(self, help):
213 """Set the help string."""
214 self._help = help
215 if not self._completed:
216 self._helpLabel.set_markup(self._help)
217 self._helpLabel.set_sensitive(True)
218
[94]219 def complete(self):
220 """Called when the page is completed.
221
222 It greys out/changes the help text and then calls finalize()."""
223 self.finalize()
224 if self._completedHelp is None:
225 self._helpLabel.set_sensitive(False)
226 else:
227 self._helpLabel.set_markup(self._completedHelp)
228 self._completed = True
229
[70]230 def finalize(self):
231 """Called when the page is finalized."""
232 pass
233
[46]234 def grabDefault(self):
235 """If the page has a default button, make it the default one."""
236 if self._defaultButton is not None:
237 self._defaultButton.grab_default()
[67]238
239 def reset(self):
240 """Reset the page if the wizard is reset."""
[94]241 self._completed = False
[70]242 self._fromPage = None
[275]243 if self._cancelFlightButton is not None:
244 self._cancelFlightButton.set_sensitive(True)
[70]245
246 def goBack(self):
247 """Go to the page we were invoked from."""
248 assert self._fromPage is not None
[347]249
[70]250 self._wizard.setCurrentPage(self._fromPage, finalize = False)
[208]251
[275]252 def flightEnded(self):
253 """Called when the flight has ended.
254
255 This default implementation disables the cancel flight button."""
256 if self._cancelFlightButton is not None:
257 self._cancelFlightButton.set_sensitive(False)
258
[208]259 def _cancelFlight(self, button):
260 """Called when the Cancel flight button is clicked."""
261 self._wizard.gui.cancelFlight()
[347]262
[42]263#-----------------------------------------------------------------------------
264
265class LoginPage(Page):
266 """The login page."""
267 def __init__(self, wizard):
268 """Construct the login page."""
[107]269 super(LoginPage, self).__init__(wizard, xstr("login"),
270 xstr("loginHelp"))
[42]271
[48]272 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
273 xscale = 0.0, yscale = 0.0)
[139]274
[184]275 table = gtk.Table(4, 2)
[42]276 table.set_row_spacings(4)
277 table.set_col_spacings(32)
[48]278 alignment.add(table)
279 self.setMainWidget(alignment)
[42]280
[107]281 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
282 xscale = 0.0, yscale = 0.0)
283 label = gtk.Label(xstr("label_pilotID"))
[45]284 label.set_use_underline(True)
285 labelAlignment.add(label)
[42]286 table.attach(labelAlignment, 0, 1, 0, 1)
287
288 self._pilotID = gtk.Entry()
[578]289 self._pilotID.connect("changed", self._pilotIDChanged)
[107]290 self._pilotID.set_tooltip_text(xstr("login_pilotID_tooltip"))
[42]291 table.attach(self._pilotID, 1, 2, 0, 1)
[45]292 label.set_mnemonic_widget(self._pilotID)
[42]293
[107]294 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
295 xscale = 0.0, yscale = 0.0)
296 label = gtk.Label(xstr("label_password"))
[45]297 label.set_use_underline(True)
298 labelAlignment.add(label)
[42]299 table.attach(labelAlignment, 0, 1, 1, 2)
300
301 self._password = gtk.Entry()
302 self._password.set_visibility(False)
[184]303 self._password.connect("changed", self._setControls)
[107]304 self._password.set_tooltip_text(xstr("login_password_tooltip"))
[42]305 table.attach(self._password, 1, 2, 1, 2)
[45]306 label.set_mnemonic_widget(self._password)
[42]307
[107]308 self._rememberButton = gtk.CheckButton(xstr("remember_password"))
[45]309 self._rememberButton.set_use_underline(True)
[107]310 self._rememberButton.set_tooltip_text(xstr("login_remember_tooltip"))
[45]311 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
312
[184]313 self._entranceExam = gtk.CheckButton(xstr("login_entranceExam"))
314 self._entranceExam.set_use_underline(True)
315 self._entranceExam.set_tooltip_text(xstr("login_entranceExam_tooltip"))
316 self._entranceExam.connect("toggled", self._setControls)
317 table.attach(self._entranceExam, 1, 2, 3, 4, ypadding = 12)
318
[215]319 self.addButton(xstr("button_offline"),
320 clicked = self._offlineClicked,
321 tooltip = xstr("button_offline_tooltip"))
322
[107]323 self._loginButton = self.addButton(xstr("button_login"), default = True)
[42]324 self._loginButton.connect("clicked", self._loginClicked)
[184]325 self._loginButton.set_tooltip_text(xstr("login_button_tooltip"))
326
327
328 @property
329 def entranceExam(self):
330 """Get whether an entrance exam is being performed."""
331 return self._entranceExam.get_active() and \
332 self._pilotID.get_text()!=""
[92]333
[215]334 @property
335 def pilotID(self):
336 """Get the pilot ID, if given."""
337 return self._pilotID.get_text()
338
[92]339 def activate(self):
340 """Activate the page."""
[42]341 config = self._wizard.gui.config
342 self._pilotID.set_text(config.pilotID)
343 self._password.set_text(config.password)
[45]344 self._rememberButton.set_active(config.rememberPassword)
[347]345 self._setControls(None)
[184]346
[578]347 def _pilotIDChanged(self, entry):
348 """Called when the pilot ID has changed.
349
350 It sets the text to upper-case and calls _setControls to update other
351 stuff."""
352 entry.set_text(entry.get_text().upper())
353 self._setControls(entry)
354
[184]355 def _setControls(self, entry = None):
356 """Set the sensitivity of the various controls.
357
358 The login button is sensitive only if both the pilot ID and the
359 password fields contain values.
360
361 The password field is sensitive only, if the entrance exam checkbox is
362 not selected.
363
364 The remember password checkbox is sensitive only, if the password field
365 contains text.
366
[208]367 The entrance exam checkbox is sensitive only, if the pilot ID is not
[184]368 empty."""
369 pilotID = self._pilotID.get_text()
370 password = self._password.get_text()
371 entranceExam = self._entranceExam.get_active()
372 self._password.set_sensitive(not entranceExam)
373 self._rememberButton.set_sensitive(password!="" and not entranceExam)
374 self._entranceExam.set_sensitive(pilotID!="")
375 self._loginButton.set_sensitive(pilotID!="" and
376 (password!="" or entranceExam))
[42]377
[215]378 def _offlineClicked(self, button):
379 """Called when the offline button was clicked."""
[402]380 print "mlx.flight.LoginPage: offline flight selected"
[215]381 self._wizard.nextPage()
382
[42]383 def _loginClicked(self, button):
384 """Called when the login button was clicked."""
[435]385 print "mlx.flight.LoginPage: logging in"
[208]386 self._wizard.login(self._handleLoginResult,
387 self._pilotID.get_text(),
388 self._password.get_text(),
389 self.entranceExam)
[42]390
391 def _handleLoginResult(self, returned, result):
392 """Handle the login result."""
[70]393 self._loginButton.set_sensitive(True)
[208]394 if returned and result.loggedIn:
395 config = self._wizard.gui.config
396
397 config.pilotID = self._pilotID.get_text()
398
[347]399 rememberPassword = self._rememberButton.get_active()
[208]400 config.password = result.password if rememberPassword else ""
401
402 config.rememberPassword = rememberPassword
403
404 config.save()
405 self._wizard.nextPage()
[42]406
407#-----------------------------------------------------------------------------
408
409class FlightSelectionPage(Page):
410 """The page to select the flight."""
411 def __init__(self, wizard):
412 """Construct the flight selection page."""
[347]413 help = xstr("flightsel_help")
[107]414 completedHelp = xstr("flightsel_chelp")
415 super(FlightSelectionPage, self).__init__(wizard, xstr("flightsel_title"),
[94]416 help, completedHelp = completedHelp)
[48]417
418
419 self._listStore = gtk.ListStore(str, str, str, str)
420 self._flightList = gtk.TreeView(self._listStore)
[107]421 column = gtk.TreeViewColumn(xstr("flightsel_no"), gtk.CellRendererText(),
[48]422 text = 1)
423 column.set_expand(True)
424 self._flightList.append_column(column)
[107]425 column = gtk.TreeViewColumn(xstr("flightsel_deptime"), gtk.CellRendererText(),
[48]426 text = 0)
427 column.set_expand(True)
428 self._flightList.append_column(column)
[107]429 column = gtk.TreeViewColumn(xstr("flightsel_from"), gtk.CellRendererText(),
[48]430 text = 2)
431 column.set_expand(True)
432 self._flightList.append_column(column)
[107]433 column = gtk.TreeViewColumn(xstr("flightsel_to"), gtk.CellRendererText(),
[48]434 text = 3)
435 column.set_expand(True)
436 self._flightList.append_column(column)
[277]437 self._flightList.connect("row-activated", self._rowActivated)
438 self._flightList.connect("button-press-event", self._listButtonPressed)
439
440 self._flightListPopupMenu = None
[48]441
442 flightSelection = self._flightList.get_selection()
[347]443 flightSelection.connect("changed", self._selectionChanged)
[48]444
445 scrolledWindow = gtk.ScrolledWindow()
446 scrolledWindow.add(self._flightList)
447 scrolledWindow.set_size_request(400, -1)
[118]448 # FIXME: these should be constants in common.py
[48]449 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
450 else gtk.POLICY_AUTOMATIC,
[69]451 gtk.PolicyType.AUTOMATIC if pygobject
452 else gtk.POLICY_AUTOMATIC)
[62]453 scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
454 else gtk.SHADOW_IN)
[48]455
456 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
457 alignment.add(scrolledWindow)
458
459 self.setMainWidget(alignment)
460
[214]461 self._saveButton = self.addButton(xstr("flightsel_save"),
462 sensitive = False,
463 clicked = self._saveClicked,
464 tooltip = xstr("flightsel_save_tooltip"))
465 self._saveDialog = None
466
[208]467 self._refreshButton = self.addButton(xstr("flightsel_refresh"),
468 sensitive = True,
469 clicked = self._refreshClicked,
470 tooltip = xstr("flightsel_refresh_tooltip"))
471
[184]472 self._loadButton = self.addButton(xstr("flightsel_load"),
473 sensitive = True,
474 tooltip = xstr("flightsel_load_tooltip"))
475 self._loadButton.connect("clicked", self._loadButtonClicked)
476 self._loadDialog = None
[347]477
[107]478 self._button = self.addNextButton(sensitive = False,
479 clicked = self._forwardClicked)
[48]480
[184]481 self._flights = []
482
[48]483 def activate(self):
484 """Fill the flight list."""
[70]485 self._flightList.set_sensitive(True)
[208]486 self._loadButton.set_sensitive(True)
[216]487 self._refreshButton.set_sensitive(self._wizard.loggedIn)
[208]488 self._buildFlights()
[347]489
[208]490 def finalize(self):
491 """Finalize the page."""
492 self._flightList.set_sensitive(False)
493 self._loadButton.set_sensitive(False)
494 self._refreshButton.set_sensitive(False)
495
496 def _buildFlights(self):
497 """Rebuild the flights from the login result."""
[184]498 self._flights = []
[70]499 self._listStore.clear()
[215]500 if self._wizard.loggedIn:
501 for flight in self._wizard.loginResult.flights:
502 self._addFlight(flight)
[48]503
[184]504 def _addFlight(self, flight):
505 """Add the given file to the list of flights."""
506 self._flights.append(flight)
507 self._listStore.append([str(flight.departureTime),
508 flight.callsign,
509 flight.departureICAO,
510 flight.arrivalICAO])
511
[214]512 def _saveClicked(self, button):
513 """Called when the Save flight button is clicked."""
[277]514 self._saveSelected()
515
516 def _saveSelected(self):
517 """Save the selected flight."""
[214]518 flight = self._getSelectedFlight()
519 date = flight.departureTime.date()
520 name = "%04d-%02d-%02d %s %s-%s.vaflight" % \
521 (date.year, date.month, date.day, flight.callsign,
522 flight.departureICAO, flight.arrivalICAO)
523
524 dialog = self._getSaveDialog()
525 dialog.set_current_name(name)
526 dialog.show_all()
527 response = dialog.run()
528 dialog.hide()
529
530 if response==RESPONSETYPE_OK:
[233]531 fileName = text2unicode(dialog.get_filename())
[214]532 print "Saving", fileName
533 try:
534 with open(fileName, "wt") as f:
535 flight.writeIntoFile(f)
536 except Exception, e:
[401]537 print "Failed to save flight:", util.utf2unicode(str(e))
[214]538 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
539 type = MESSAGETYPE_ERROR,
540 message_format =
541 xstr("flightsel_save_failed"))
542 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
543 dialog.set_title(WINDOW_TITLE_BASE)
544 secondary = xstr("flightsel_save_failed_sec")
545 dialog.format_secondary_markup(secondary)
546 dialog.run()
547 dialog.hide()
[347]548
[208]549 def _refreshClicked(self, button):
550 """Called when the refresh button is clicked."""
551 self._wizard.reloadFlights(self._refreshCallback)
552
553 def _refreshCallback(self, returned, result):
554 """Callback for the refresh."""
555 if returned and result.loggedIn:
556 self._buildFlights()
557
[48]558 def _selectionChanged(self, selection):
559 """Called when the selection is changed."""
[214]560 selected = selection.count_selected_rows()==1
561 self._saveButton.set_sensitive(selected)
562 self._button.set_sensitive(selected)
[42]563
[184]564 def _loadButtonClicked(self, loadButton):
565 """Called when the load a flight button is clicked."""
566 dialog = self._getLoadDialog()
567 dialog.show_all()
568 response = dialog.run()
569 dialog.hide()
570
571 if response==RESPONSETYPE_OK:
[233]572 fileName = text2unicode(dialog.get_filename())
[184]573 print "Loading", fileName
574 bookedFlight = web.BookedFlight()
575 try:
576 with open(fileName, "rt") as f:
577 bookedFlight.readFromFile(f)
[347]578 self._addFlight(bookedFlight)
[184]579 except Exception, e:
[401]580 print "Failed to load flight:", util.utf2unicode(str(e))
[184]581 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
582 type = MESSAGETYPE_ERROR,
583 message_format =
584 xstr("flightsel_load_failed"))
585 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
586 dialog.set_title(WINDOW_TITLE_BASE)
587 secondary = xstr("flightsel_load_failed_sec")
588 dialog.format_secondary_markup(secondary)
589 dialog.run()
[347]590 dialog.hide()
591
[51]592 def _forwardClicked(self, button):
593 """Called when the forward button was clicked."""
[94]594 if self._completed:
[70]595 self._wizard.jumpPage(self._nextDistance, finalize = False)
596 else:
[277]597 self._flightSelected()
598
599 def _rowActivated(self, flightList, path, column):
600 """Called when a row is activated."""
601 if not self._completed:
602 self._flightSelected()
603
604 def _flightSelected(self):
605 """Called when a flight has been selected."""
606 flight = self._getSelectedFlight()
607 self._wizard._bookedFlight = flight
[436]608 self._wizard.gui.enableFlightInfo(flight.aircraftType)
[347]609
[277]610 self._updateDepartureGate()
[214]611
612 def _getSelectedFlight(self):
613 """Get the currently selected flight."""
614 selection = self._flightList.get_selection()
615 (listStore, iter) = selection.get_selected()
616 path = listStore.get_path(iter)
617 [index] = path.get_indices() if pygobject else path
[347]618
[214]619 return self._flights[index]
[277]620
621 def _listButtonPressed(self, widget, event):
622 """Called when a mouse button is pressed on the flight list."""
623 if event.type!=EVENT_BUTTON_PRESS or event.button!=3:
624 return
625
626 (path, _, _, _) = self._flightList.get_path_at_pos(int(event.x),
627 int(event.y))
628 selection = self._flightList.get_selection()
629 selection.unselect_all()
630 selection.select_path(path)
631
632 menu = self._getListPopupMenu()
633 if pygobject:
634 menu.popup(None, None, None, None, event.button, event.time)
635 else:
636 menu.popup(None, None, None, event.button, event.time)
[347]637
[51]638 def _updateDepartureGate(self):
639 """Update the departure gate for the booked flight."""
640 flight = self._wizard._bookedFlight
[184]641 if self._wizard.gui.config.onlineGateSystem and \
[215]642 self._wizard.loggedIn and not self._wizard.entranceExam:
[136]643 if flight.departureICAO=="LHBP":
644 self._wizard.getFleet(self._fleetRetrieved)
645 else:
646 self._wizard.updatePlane(self._planeUpdated,
647 flight.tailNumber,
648 const.PLANE_AWAY)
[51]649 else:
[136]650 self._nextDistance = 2
651 self._wizard.jumpPage(2)
[347]652
[51]653 def _fleetRetrieved(self, fleet):
654 """Called when the fleet has been retrieved."""
655 if fleet is None:
[70]656 self._nextDistance = 2
[51]657 self._wizard.jumpPage(2)
658 else:
659 plane = fleet[self._wizard._bookedFlight.tailNumber]
660 if plane is None:
[70]661 self._nextDistance = 2
[51]662 self._wizard.jumpPage(2)
[70]663 elif plane.gateNumber is not None and \
664 not fleet.isGateConflicting(plane):
[51]665 self._wizard._departureGate = plane.gateNumber
[70]666 self._nextDistance = 2
[51]667 self._wizard.jumpPage(2)
668 else:
[70]669 self._nextDistance = 1
[51]670 self._wizard.nextPage()
[130]671
672 def _planeUpdated(self, success):
673 """Callback for the plane updating."""
674 self._nextDistance = 2
675 self._wizard.jumpPage(2)
[184]676
[214]677 def _getSaveDialog(self):
678 """Get the dialog to load a flight file."""
679 if self._saveDialog is not None:
680 return self._saveDialog
[347]681
[214]682 gui = self._wizard.gui
683 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
684 xstr("flightsel_save_title"),
685 action = FILE_CHOOSER_ACTION_SAVE,
686 buttons = (gtk.STOCK_CANCEL,
687 RESPONSETYPE_CANCEL,
688 gtk.STOCK_OK, RESPONSETYPE_OK),
689 parent = gui.mainWindow)
[347]690 dialog.set_modal(True)
[214]691 dialog.set_do_overwrite_confirmation(True)
692
693 filter = gtk.FileFilter()
694 filter.set_name(xstr("flightsel_filter_flights"))
695 filter.add_pattern("*.vaflight")
696 dialog.add_filter(filter)
[347]697
[214]698 filter = gtk.FileFilter()
699 filter.set_name(xstr("file_filter_all"))
700 filter.add_pattern("*.*")
701 dialog.add_filter(filter)
702
703 self._saveDialog = dialog
[347]704
705 return dialog
706
[184]707 def _getLoadDialog(self):
708 """Get the dialog to load a flight file."""
709 if self._loadDialog is not None:
710 return self._loadDialog
[347]711
[184]712 gui = self._wizard.gui
713 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
714 xstr("flightsel_load_title"),
715 action = FILE_CHOOSER_ACTION_OPEN,
716 buttons = (gtk.STOCK_CANCEL,
717 RESPONSETYPE_CANCEL,
718 gtk.STOCK_OK, RESPONSETYPE_OK),
719 parent = gui.mainWindow)
[347]720 dialog.set_modal(True)
[184]721
722 filter = gtk.FileFilter()
723 filter.set_name(xstr("flightsel_filter_flights"))
724 filter.add_pattern("*.vaflight")
725 dialog.add_filter(filter)
[347]726
[184]727 filter = gtk.FileFilter()
728 filter.set_name(xstr("file_filter_all"))
729 filter.add_pattern("*.*")
730 dialog.add_filter(filter)
731
732 self._loadDialog = dialog
[347]733
734 return dialog
[277]735
736 def _getListPopupMenu(self):
737 """Get the flight list popup menu."""
738 if self._flightListPopupMenu is None:
739 menu = gtk.Menu()
740
741 menuItem = gtk.MenuItem()
742 menuItem.set_label(xstr("flightsel_popup_select"))
743 menuItem.set_use_underline(True)
744 menuItem.connect("activate", self._popupSelect)
745 menuItem.show()
746
747 menu.append(menuItem)
[347]748
[277]749 menuItem = gtk.MenuItem()
750 menuItem.set_label(xstr("flightsel_popup_save"))
751 menuItem.set_use_underline(True)
752 menuItem.connect("activate", self._popupSave)
753 menuItem.show()
754
755 menu.append(menuItem)
756
757 self._flightListPopupMenu = menu
758
759 return self._flightListPopupMenu
760
761 def _popupSelect(self, menuItem):
762 """Called when the Select menu item is activated in the popup menu."""
763 if not self._completed:
764 self._flightSelected()
[347]765
[277]766 def _popupSave(self, menuItem):
767 """Called when the Save menu item is activated in the popup menu."""
768 if not self._completed:
769 self._saveSelected()
[347]770
[51]771#-----------------------------------------------------------------------------
772
773class GateSelectionPage(Page):
774 """Page to select a free gate at LHBP.
775 This page should be displayed only if we have fleet information!."""
776 def __init__(self, wizard):
777 """Construct the gate selection page."""
[107]778 super(GateSelectionPage, self).__init__(wizard, xstr("gatesel_title"),
779 xstr("gatesel_help"))
[347]780
[51]781 self._listStore = gtk.ListStore(str)
782 self._gateList = gtk.TreeView(self._listStore)
783 column = gtk.TreeViewColumn(None, gtk.CellRendererText(),
784 text = 0)
785 column.set_expand(True)
786 self._gateList.append_column(column)
787 self._gateList.set_headers_visible(False)
[278]788 self._gateList.connect("row-activated", self._rowActivated)
[51]789
790 gateSelection = self._gateList.get_selection()
791 gateSelection.connect("changed", self._selectionChanged)
792
793 scrolledWindow = gtk.ScrolledWindow()
794 scrolledWindow.add(self._gateList)
795 scrolledWindow.set_size_request(50, -1)
796 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
797 else gtk.POLICY_AUTOMATIC,
[69]798 gtk.PolicyType.AUTOMATIC if pygobject
799 else gtk.POLICY_AUTOMATIC)
[62]800 scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
801 else gtk.SHADOW_IN)
[51]802
803 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
804 alignment.add(scrolledWindow)
805
[347]806 self.setMainWidget(alignment)
[51]807
[208]808 self.addCancelFlightButton()
809
[107]810 self.addPreviousButton(clicked = self._backClicked)
[347]811
[107]812 self._button = self.addNextButton(sensitive = False,
813 clicked = self._forwardClicked)
[51]814
815 def activate(self):
816 """Fill the gate list."""
817 self._listStore.clear()
[70]818 self._gateList.set_sensitive(True)
[51]819 occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
820 for gateNumber in const.lhbpGateNumbers:
821 if gateNumber not in occupiedGateNumbers:
822 self._listStore.append([gateNumber])
823
[70]824 def finalize(self):
825 """Finalize the page."""
826 self._gateList.set_sensitive(False)
827
[51]828 def _selectionChanged(self, selection):
829 """Called when the selection is changed."""
830 self._button.set_sensitive(selection.count_selected_rows()==1)
831
[73]832 def _backClicked(self, button):
833 """Called when the Back button is pressed."""
834 self.goBack()
835
[51]836 def _forwardClicked(self, button):
837 """Called when the forward button is clicked."""
[94]838 if not self._completed:
[278]839 self._gateSelected()
[130]840 else:
841 self._wizard.nextPage()
[51]842
[278]843 def _rowActivated(self, flightList, path, column):
844 """Called when a row is activated."""
845 if not self._completed:
846 self._gateSelected()
847
848 def _gateSelected(self):
849 """Called when a gate has been selected."""
850 selection = self._gateList.get_selection()
851 (listStore, iter) = selection.get_selected()
852 (gateNumber,) = listStore.get(iter, 0)
853
854 self._wizard._departureGate = gateNumber
855
856 self._wizard.updatePlane(self._planeUpdated,
857 self._wizard._bookedFlight.tailNumber,
[347]858 const.PLANE_HOME, gateNumber)
[278]859
[51]860 def _planeUpdated(self, success):
861 """Callback for the plane updating call."""
862 if success is None or success:
863 self._wizard.nextPage()
864 else:
[105]865 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
866 type = MESSAGETYPE_ERROR,
[107]867 message_format = xstr("gatesel_conflict"))
[124]868 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
[105]869 dialog.set_title(WINDOW_TITLE_BASE)
[107]870 dialog.format_secondary_markup(xstr("gatesel_conflict_sec"))
[51]871 dialog.run()
872 dialog.hide()
873
[126]874 self._wizard.getFleet(self._fleetRetrieved)
[51]875
876 def _fleetRetrieved(self, fleet):
877 """Called when the fleet has been retrieved."""
878 if fleet is None:
879 self._wizard.nextPage()
880 else:
881 self.activate()
[347]882
[51]883#-----------------------------------------------------------------------------
884
885class ConnectPage(Page):
886 """Page which displays the departure airport and gate (if at LHBP)."""
887 def __init__(self, wizard):
888 """Construct the connect page."""
[78]889 help = "Load the aircraft below into the simulator and park it\n" \
890 "at the given airport, at the gate below, if present.\n\n" \
[51]891 "Then press the Connect button to connect to the simulator."
[94]892 completedHelp = "The basic data of your flight can be read below."
[107]893 super(ConnectPage, self).__init__(wizard, xstr("connect_title"),
894 xstr("connect_help"),
895 completedHelp = xstr("connect_chelp"))
[347]896
[501]897 self._selectSimulator = os.name=="nt" or "FORCE_SELECT_SIM" in os.environ
898
[51]899 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
900 xscale = 0.0, yscale = 0.0)
901
[501]902 table = gtk.Table(7 if self._selectSimulator else 5, 2)
[51]903 table.set_row_spacings(4)
904 table.set_col_spacings(16)
905 table.set_homogeneous(True)
906 alignment.add(table)
907 self.setMainWidget(alignment)
908
909 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]910 label = gtk.Label(xstr("connect_flightno"))
[51]911 labelAlignment.add(label)
912 table.attach(labelAlignment, 0, 1, 0, 1)
913
914 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
[78]915 self._flightNumber = gtk.Label()
[191]916 self._flightNumber.set_width_chars(9)
[78]917 self._flightNumber.set_alignment(0.0, 0.5)
918 labelAlignment.add(self._flightNumber)
919 table.attach(labelAlignment, 1, 2, 0, 1)
920
921 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]922 label = gtk.Label(xstr("connect_acft"))
[78]923 labelAlignment.add(label)
924 table.attach(labelAlignment, 0, 1, 1, 2)
925
926 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
927 self._aircraft = gtk.Label()
928 self._aircraft.set_width_chars(25)
929 self._aircraft.set_alignment(0.0, 0.5)
930 labelAlignment.add(self._aircraft)
931 table.attach(labelAlignment, 1, 2, 1, 2)
932
933 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]934 label = gtk.Label(xstr("connect_tailno"))
[78]935 labelAlignment.add(label)
936 table.attach(labelAlignment, 0, 1, 2, 3)
937
938 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
939 self._tailNumber = gtk.Label()
[80]940 self._tailNumber.set_width_chars(10)
[78]941 self._tailNumber.set_alignment(0.0, 0.5)
942 labelAlignment.add(self._tailNumber)
943 table.attach(labelAlignment, 1, 2, 2, 3)
944
945 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]946 label = gtk.Label(xstr("connect_airport"))
[78]947 labelAlignment.add(label)
948 table.attach(labelAlignment, 0, 1, 3, 4)
949
950 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
[51]951 self._departureICAO = gtk.Label()
[80]952 self._departureICAO.set_width_chars(6)
[51]953 self._departureICAO.set_alignment(0.0, 0.5)
954 labelAlignment.add(self._departureICAO)
[78]955 table.attach(labelAlignment, 1, 2, 3, 4)
[51]956
957 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]958 label = gtk.Label(xstr("connect_gate"))
[51]959 labelAlignment.add(label)
[78]960 table.attach(labelAlignment, 0, 1, 4, 5)
[51]961
962 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
963 self._departureGate = gtk.Label()
964 self._departureGate.set_width_chars(5)
965 self._departureGate.set_alignment(0.0, 0.5)
966 labelAlignment.add(self._departureGate)
[78]967 table.attach(labelAlignment, 1, 2, 4, 5)
[51]968
[501]969 if self._selectSimulator:
970 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0, yalign=0.5)
971 label = gtk.Label(xstr("connect_sim"))
972 labelAlignment.add(label)
973 table.attach(labelAlignment, 0, 1, 5, 7)
974
975 selectAlignment = gtk.Alignment(xalign=0.0, xscale=0.0, yalign=0.5)
976
977 selectBox = gtk.HBox()
978 if pygobject:
979 self._selectMSFS = \
980 gtk.RadioButton.new_with_mnemonic_from_widget(None,
981 xstr("connect_sim_msfs"))
982 else:
983 self._selectMSFS = gtk.RadioButton(None,
984 xstr("connect_sim_msfs"))
985
986 selectBox.pack_start(self._selectMSFS, False, False, 0);
987
988 if pygobject:
989 self._selectXPlane = \
990 gtk.RadioButton.new_with_mnemonic_from_widget(self._selectMSFS,
991 xstr("connect_sim_xplane"))
992 else:
993 self._selectXPlane = gtk.RadioButton(self._selectMSFS,
994 xstr("connect_sim_xplane"))
995
996 selectBox.pack_start(self._selectXPlane, False, False, 8);
997
998 selectAlignment.add(selectBox)
999 table.attach(selectAlignment, 1, 2, 5, 7)
1000
1001
[208]1002 self.addCancelFlightButton()
1003
[107]1004 self.addPreviousButton(clicked = self._backClicked)
[70]1005
[107]1006 self._button = self.addButton(xstr("button_connect"), default = True,
1007 tooltip = xstr("button_connect_tooltip"))
[70]1008 self._clickedID = self._button.connect("clicked", self._connectClicked)
[51]1009
1010 def activate(self):
[60]1011 """Setup the departure information."""
[107]1012 self._button.set_label(xstr("button_connect"))
[70]1013 self._button.set_use_underline(True)
[107]1014 self._button.set_tooltip_text(xstr("button_connect_tooltip"))
[70]1015 self._button.disconnect(self._clickedID)
1016 self._clickedID = self._button.connect("clicked", self._connectClicked)
[78]1017
1018 bookedFlight = self._wizard._bookedFlight
1019
1020 self._flightNumber.set_markup("<b>" + bookedFlight.callsign + "</b>")
1021
[191]1022 aircraftType = aircraftNames[bookedFlight.aircraftType]
[78]1023 self._aircraft.set_markup("<b>" + aircraftType + "</b>")
[347]1024
[78]1025 self._tailNumber.set_markup("<b>" + bookedFlight.tailNumber + "</b>")
1026
1027 icao = bookedFlight.departureICAO
[51]1028 self._departureICAO.set_markup("<b>" + icao + "</b>")
1029 gate = self._wizard._departureGate
1030 if gate!="-":
1031 gate = "<b>" + gate + "</b>"
1032 self._departureGate.set_markup(gate)
1033
[501]1034 if self._selectSimulator:
[503]1035 config = self._wizard.gui.config
1036 self._selectMSFS.set_active(config.defaultMSFS)
1037 self._selectXPlane.set_active(not config.defaultMSFS)
[501]1038
[70]1039 def finalize(self):
1040 """Finalize the page."""
[107]1041 self._button.set_label(xstr("button_next"))
1042 self._button.set_use_underline(True)
1043 self._button.set_tooltip_text(xstr("button_next_tooltip"))
[70]1044 self._button.disconnect(self._clickedID)
1045 self._clickedID = self._button.connect("clicked", self._forwardClicked)
1046
1047 def _backClicked(self, button):
1048 """Called when the Back button is pressed."""
1049 self.goBack()
1050
[51]1051 def _connectClicked(self, button):
1052 """Called when the Connect button is pressed."""
[501]1053 if self._selectSimulator:
1054 simulatorType = const.SIM_MSFS9 if self._selectMSFS.get_active() \
1055 else const.SIM_XPLANE10
1056 else:
1057 simulatorType = const.SIM_MSFS9 if os.name=="nt" \
[503]1058 else const.SIM_XPLANE10
1059
1060 config = self._wizard.gui.config
1061 config.defaultMSFS = simulatorType == const.SIM_MSFS9
1062 config.save()
1063
[501]1064 self._wizard._connectSimulator(simulatorType)
[51]1065
[70]1066 def _forwardClicked(self, button):
1067 """Called when the Forward button is pressed."""
1068 self._wizard.nextPage()
1069
[42]1070#-----------------------------------------------------------------------------
1071
[59]1072class PayloadPage(Page):
1073 """Page to allow setting up the payload."""
1074 def __init__(self, wizard):
1075 """Construct the page."""
[107]1076 super(PayloadPage, self).__init__(wizard, xstr("payload_title"),
1077 xstr("payload_help"),
1078 completedHelp = xstr("payload_chelp"))
[59]1079
[60]1080 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1081 xscale = 0.0, yscale = 0.0)
1082
1083 table = gtk.Table(7, 3)
1084 table.set_row_spacings(4)
1085 table.set_col_spacings(16)
1086 table.set_homogeneous(False)
1087 alignment.add(table)
1088 self.setMainWidget(alignment)
1089
[107]1090 label = gtk.Label(xstr("payload_crew"))
[309]1091 label.set_use_underline(True)
[60]1092 label.set_alignment(0.0, 0.5)
1093 table.attach(label, 0, 1, 0, 1)
1094
[303]1095 self._numCrew = IntegerEntry(defaultValue = 0)
[60]1096 self._numCrew.set_width_chars(6)
[303]1097 self._numCrew.connect("integer-changed", self._weightChanged)
1098 self._numCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
[60]1099 table.attach(self._numCrew, 1, 2, 0, 1)
[303]1100 label.set_mnemonic_widget(self._numCrew)
[347]1101
[107]1102 label = gtk.Label(xstr("payload_pax"))
[309]1103 label.set_use_underline(True)
[60]1104 label.set_alignment(0.0, 0.5)
1105 table.attach(label, 0, 1, 1, 2)
1106
[347]1107 self._numPassengers = IntegerEntry(defaultValue = 0)
[60]1108 self._numPassengers.set_width_chars(6)
[303]1109 self._numPassengers.connect("integer-changed", self._weightChanged)
1110 self._numPassengers.set_tooltip_text(xstr("payload_pax_tooltip"))
[60]1111 table.attach(self._numPassengers, 1, 2, 1, 2)
[303]1112 label.set_mnemonic_widget(self._numPassengers)
[347]1113
[107]1114 label = gtk.Label(xstr("payload_bag"))
[309]1115 label.set_use_underline(True)
[60]1116 label.set_alignment(0.0, 0.5)
1117 table.attach(label, 0, 1, 2, 3)
1118
[303]1119 self._bagWeight = IntegerEntry(defaultValue = 0)
[60]1120 self._bagWeight.set_width_chars(6)
[303]1121 self._bagWeight.connect("integer-changed", self._weightChanged)
1122 self._bagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
[60]1123 table.attach(self._bagWeight, 1, 2, 2, 3)
[303]1124 label.set_mnemonic_widget(self._bagWeight)
[60]1125
1126 table.attach(gtk.Label("kg"), 2, 3, 2, 3)
[347]1127
[107]1128 label = gtk.Label(xstr("payload_cargo"))
[60]1129 label.set_use_underline(True)
1130 label.set_alignment(0.0, 0.5)
1131 table.attach(label, 0, 1, 3, 4)
1132
[84]1133 self._cargoWeight = IntegerEntry(defaultValue = 0)
[60]1134 self._cargoWeight.set_width_chars(6)
[303]1135 self._cargoWeight.connect("integer-changed", self._weightChanged)
[107]1136 self._cargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
[60]1137 table.attach(self._cargoWeight, 1, 2, 3, 4)
1138 label.set_mnemonic_widget(self._cargoWeight)
1139
1140 table.attach(gtk.Label("kg"), 2, 3, 3, 4)
[347]1141
[107]1142 label = gtk.Label(xstr("payload_mail"))
[309]1143 label.set_use_underline(True)
[60]1144 label.set_alignment(0.0, 0.5)
1145 table.attach(label, 0, 1, 4, 5)
1146
[303]1147 self._mailWeight = IntegerEntry(defaultValue = 0)
[60]1148 self._mailWeight.set_width_chars(6)
[303]1149 self._mailWeight.connect("integer-changed", self._weightChanged)
1150 self._mailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
[60]1151 table.attach(self._mailWeight, 1, 2, 4, 5)
[303]1152 label.set_mnemonic_widget(self._mailWeight)
[60]1153
1154 table.attach(gtk.Label("kg"), 2, 3, 4, 5)
[347]1155
[107]1156 label = gtk.Label("<b>" + xstr("payload_zfw") + "</b>")
[60]1157 label.set_alignment(0.0, 0.5)
1158 label.set_use_markup(True)
1159 table.attach(label, 0, 1, 5, 6)
1160
1161 self._calculatedZFW = gtk.Label()
1162 self._calculatedZFW.set_width_chars(6)
1163 self._calculatedZFW.set_alignment(1.0, 0.5)
1164 table.attach(self._calculatedZFW, 1, 2, 5, 6)
1165
1166 table.attach(gtk.Label("kg"), 2, 3, 5, 6)
1167
[107]1168 self._zfwButton = gtk.Button(xstr("payload_fszfw"))
[70]1169 self._zfwButton.set_use_underline(True)
1170 self._zfwButton.connect("clicked", self._zfwRequested)
[107]1171 self._zfwButton.set_tooltip_text(xstr("payload_fszfw_tooltip"))
[70]1172 table.attach(self._zfwButton, 0, 1, 6, 7)
[60]1173
1174 self._simulatorZFW = gtk.Label("-")
1175 self._simulatorZFW.set_width_chars(6)
1176 self._simulatorZFW.set_alignment(1.0, 0.5)
1177 table.attach(self._simulatorZFW, 1, 2, 6, 7)
1178 self._simulatorZFWValue = None
1179
1180 table.attach(gtk.Label("kg"), 2, 3, 6, 7)
1181
[208]1182 self.addCancelFlightButton()
[107]1183 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1184 self._button = self.addNextButton(clicked = self._forwardClicked)
[60]1185
[97]1186 @property
[303]1187 def numCrew(self):
1188 """The number of the crew members on the flight."""
1189 return self._numCrew.get_int()
[347]1190
[303]1191 @property
1192 def numPassengers(self):
1193 """The number of the passengers on the flight."""
1194 return self._numPassengers.get_int()
[347]1195
[303]1196 @property
1197 def bagWeight(self):
1198 """Get the bag weight entered."""
1199 return self._bagWeight.get_int()
1200
1201 @property
[97]1202 def cargoWeight(self):
1203 """Get the cargo weight entered."""
1204 return self._cargoWeight.get_int()
1205
[303]1206 @property
1207 def mailWeight(self):
1208 """Get the bag weight entered."""
1209 return self._mailWeight.get_int()
1210
[60]1211 def activate(self):
1212 """Setup the information."""
1213 bookedFlight = self._wizard._bookedFlight
[303]1214
1215 self._numCrew.set_int(bookedFlight.numCrew)
1216 self._numCrew.set_sensitive(True)
1217 self._numPassengers.set_int(bookedFlight.numPassengers)
1218 self._numPassengers.set_sensitive(True)
1219
1220 self._bagWeight.set_int(bookedFlight.bagWeight)
1221 self._bagWeight.set_sensitive(True)
[84]1222 self._cargoWeight.set_int(bookedFlight.cargoWeight)
[70]1223 self._cargoWeight.set_sensitive(True)
[303]1224 self._mailWeight.set_int(bookedFlight.mailWeight)
1225 self._mailWeight.set_sensitive(True)
[347]1226
[92]1227 self._simulatorZFW.set_text("-")
1228 self._simulatorZFWValue = None
[70]1229 self._zfwButton.set_sensitive(True)
[60]1230 self._updateCalculatedZFW()
[59]1231
[70]1232 def finalize(self):
1233 """Finalize the payload page."""
[303]1234 self._numCrew.set_sensitive(False)
1235 self._numPassengers.set_sensitive(False)
1236 self._bagWeight.set_sensitive(False)
[70]1237 self._cargoWeight.set_sensitive(False)
[303]1238 self._mailWeight.set_sensitive(False)
[117]1239 self._wizard.gui.initializeWeightHelp()
[70]1240
[84]1241 def calculateZFW(self):
[60]1242 """Calculate the ZFW value."""
1243 zfw = self._wizard.gui._flight.aircraft.dow
[303]1244 zfw += (self._numCrew.get_int() + self._numPassengers.get_int()) * 82
1245 zfw += self._bagWeight.get_int()
[84]1246 zfw += self._cargoWeight.get_int()
[303]1247 zfw += self._mailWeight.get_int()
[60]1248 return zfw
[347]1249
[60]1250 def _updateCalculatedZFW(self):
1251 """Update the calculated ZFW"""
[84]1252 zfw = self.calculateZFW()
[60]1253
1254 markupBegin = "<b>"
1255 markupEnd = "</b>"
1256 if self._simulatorZFWValue is not None and \
1257 PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
1258 markupBegin += '<span foreground="red">'
1259 markupEnd = "</span>" + markupEnd
1260 self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
1261
[303]1262 def _weightChanged(self, entry, weight):
1263 """Called when one of the weight values or humanm counts has changed."""
[60]1264 self._updateCalculatedZFW()
[347]1265
[59]1266 def _zfwRequested(self, button):
1267 """Called when the ZFW is requested from the simulator."""
[70]1268 self._zfwButton.set_sensitive(False)
1269 self._backButton.set_sensitive(False)
1270 self._button.set_sensitive(False)
1271 gui = self._wizard.gui
[107]1272 gui.beginBusy(xstr("payload_zfw_busy"))
[70]1273 gui.simulator.requestZFW(self._handleZFW)
[59]1274
1275 def _handleZFW(self, zfw):
1276 """Called when the ZFW value is retrieved."""
[60]1277 gobject.idle_add(self._processZFW, zfw)
[59]1278
[60]1279 def _processZFW(self, zfw):
1280 """Process the given ZFW value received from the simulator."""
[61]1281 self._wizard.gui.endBusy()
[70]1282 self._zfwButton.set_sensitive(True)
1283 self._backButton.set_sensitive(True)
1284 self._button.set_sensitive(True)
[60]1285 self._simulatorZFWValue = zfw
1286 self._simulatorZFW.set_text("%.0f" % (zfw,))
1287 self._updateCalculatedZFW()
1288
1289 def _forwardClicked(self, button):
1290 """Called when the forward button is clicked."""
1291 self._wizard.nextPage()
[70]1292
1293 def _backClicked(self, button):
1294 """Called when the Back button is pressed."""
1295 self.goBack()
[347]1296
[59]1297#-----------------------------------------------------------------------------
1298
[61]1299class TimePage(Page):
1300 """Page displaying the departure and arrival times and allows querying the
1301 current time from the flight simulator."""
1302 def __init__(self, wizard):
[107]1303 super(TimePage, self).__init__(wizard, xstr("time_title"),
1304 xstr("time_help"),
1305 completedHelp = xstr("time_chelp"))
[61]1306
1307 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1308 xscale = 0.0, yscale = 0.0)
1309
1310 table = gtk.Table(3, 2)
1311 table.set_row_spacings(4)
1312 table.set_col_spacings(16)
1313 table.set_homogeneous(False)
1314 alignment.add(table)
1315 self.setMainWidget(alignment)
1316
[107]1317 label = gtk.Label(xstr("time_departure"))
[61]1318 label.set_alignment(0.0, 0.5)
1319 table.attach(label, 0, 1, 0, 1)
1320
1321 self._departure = gtk.Label()
1322 self._departure.set_alignment(0.0, 0.5)
1323 table.attach(self._departure, 1, 2, 0, 1)
[347]1324
[107]1325 label = gtk.Label(xstr("time_arrival"))
[61]1326 label.set_alignment(0.0, 0.5)
1327 table.attach(label, 0, 1, 1, 2)
1328
1329 self._arrival = gtk.Label()
1330 self._arrival.set_alignment(0.0, 0.5)
1331 table.attach(self._arrival, 1, 2, 1, 2)
1332
[107]1333 self._timeButton = gtk.Button(xstr("time_fs"))
[70]1334 self._timeButton.set_use_underline(True)
[107]1335 self._timeButton.set_tooltip_text(xstr("time_fs_tooltip"))
[70]1336 self._timeButton.connect("clicked", self._timeRequested)
1337 table.attach(self._timeButton, 0, 1, 2, 3)
[61]1338
1339 self._simulatorTime = gtk.Label("-")
1340 self._simulatorTime.set_alignment(0.0, 0.5)
1341 table.attach(self._simulatorTime, 1, 2, 2, 3)
1342
[208]1343 self.addCancelFlightButton()
1344
[107]1345 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1346 self._button = self.addNextButton(clicked = self._forwardClicked)
[61]1347
1348 def activate(self):
1349 """Activate the page."""
[70]1350 self._timeButton.set_sensitive(True)
[61]1351 bookedFlight = self._wizard._bookedFlight
1352 self._departure.set_text(str(bookedFlight.departureTime.time()))
1353 self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
[92]1354 self._simulatorTime.set_text("-")
[61]1355
1356 def _timeRequested(self, button):
1357 """Request the time from the simulator."""
[70]1358 self._timeButton.set_sensitive(False)
1359 self._backButton.set_sensitive(False)
1360 self._button.set_sensitive(False)
[107]1361 self._wizard.gui.beginBusy(xstr("time_busy"))
[61]1362 self._wizard.gui.simulator.requestTime(self._handleTime)
1363
1364 def _handleTime(self, timestamp):
1365 """Handle the result of a time retrieval."""
1366 gobject.idle_add(self._processTime, timestamp)
1367
1368 def _processTime(self, timestamp):
1369 """Process the given time."""
1370 self._wizard.gui.endBusy()
[70]1371 self._timeButton.set_sensitive(True)
1372 self._backButton.set_sensitive(True)
1373 self._button.set_sensitive(True)
[61]1374 tm = time.gmtime(timestamp)
1375 t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
1376 self._simulatorTime.set_text(str(t))
1377
1378 ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
1379 dt = self._wizard._bookedFlight.departureTime.time()
1380 dts = dt.hour * 3600 + dt.minute * 60 + dt.second
1381 diff = dts-ts
1382
1383 markupBegin = ""
1384 markupEnd = ""
1385 if diff < 0:
1386 markupBegin = '<b><span foreground="red">'
1387 markupEnd = '</span></b>'
1388 elif diff < 3*60 or diff > 30*60:
1389 markupBegin = '<b><span foreground="orange">'
1390 markupEnd = '</span></b>'
1391
1392 self._departure.set_markup(markupBegin + str(dt) + markupEnd)
1393
[70]1394 def _backClicked(self, button):
1395 """Called when the Back button is pressed."""
1396 self.goBack()
[347]1397
[61]1398 def _forwardClicked(self, button):
1399 """Called when the forward button is clicked."""
[141]1400 if not self._completed:
1401 gui = self._wizard.gui
1402 gui.beginBusy(xstr("fuel_get_busy"))
[347]1403
[274]1404 gui.simulator.getFuel(self._handleFuel)
[141]1405 else:
1406 self._wizard.nextPage()
1407
1408 def _handleFuel(self, fuelData):
1409 """Callback for the fuel query operation."""
1410 gobject.idle_add(self._processFuel, fuelData)
1411
1412 def _processFuel(self, fuelData):
1413 """Process the given fuel data."""
1414 self._wizard.gui.endBusy()
1415 self._wizard._fuelData = fuelData
[61]1416 self._wizard.nextPage()
[347]1417
[61]1418#-----------------------------------------------------------------------------
1419
[141]1420class FuelTank(gtk.VBox):
1421 """Widget for the fuel tank."""
1422 def __init__(self, fuelTank, name, capacity, currentWeight):
1423 """Construct the widget for the tank with the given name."""
1424 super(FuelTank, self).__init__()
1425
[146]1426 self._enabled = True
[141]1427 self.fuelTank = fuelTank
1428 self.capacity = capacity
1429 self.currentWeight = currentWeight
1430 self.expectedWeight = currentWeight
1431
1432 label = gtk.Label("<b>" + name + "</b>")
1433 label.set_use_markup(True)
[145]1434 label.set_use_underline(True)
[141]1435 label.set_justify(JUSTIFY_CENTER)
1436 label.set_alignment(0.5, 1.0)
1437 self.pack_start(label, False, False, 4)
1438
[142]1439 self._tankFigure = gtk.EventBox()
[141]1440 self._tankFigure.set_size_request(38, -1)
[142]1441 self._tankFigure.set_visible_window(False)
[144]1442 self._tankFigure.set_tooltip_markup(xstr("fuel_tank_tooltip"))
[141]1443
1444 if pygobject:
1445 self._tankFigure.connect("draw", self._drawTankFigure)
1446 else:
1447 self._tankFigure.connect("expose_event", self._drawTankFigure)
[144]1448 self._tankFigure.connect("button_press_event", self._buttonPressed)
1449 self._tankFigure.connect("motion_notify_event", self._motionNotify)
1450 self._tankFigure.connect("scroll-event", self._scrolled)
[347]1451
[141]1452 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1453 xscale = 0.0, yscale = 1.0)
[142]1454 alignment.add(self._tankFigure)
[141]1455
1456 self.pack_start(alignment, True, True, 4)
1457
1458 self._expectedButton = gtk.SpinButton()
1459 self._expectedButton.set_numeric(True)
1460 self._expectedButton.set_range(0, self.capacity)
1461 self._expectedButton.set_increments(10, 100)
1462 self._expectedButton.set_value(currentWeight)
1463 self._expectedButton.set_alignment(1.0)
1464 self._expectedButton.set_width_chars(5)
1465 self._expectedButton.connect("value-changed", self._expectedChanged)
1466
[145]1467 label.set_mnemonic_widget(self._expectedButton)
1468
[141]1469 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1470 xscale = 0.0, yscale = 1.0)
[347]1471 alignment.add(self._expectedButton)
[141]1472 self.pack_start(alignment, False, False, 4)
1473
1474 def setCurrent(self, currentWeight):
1475 """Set the current weight."""
1476 self.currentWeight = currentWeight
1477 self._redraw()
1478
1479 def isCorrect(self):
1480 """Determine if the contents of the fuel tank are as expected"""
1481 return abs(self.expectedWeight - self.currentWeight)<=1
1482
1483 def disable(self):
1484 """Disable the fuel tank."""
1485 self._expectedButton.set_sensitive(False)
[146]1486 self._enabled = False
[141]1487
1488 def _redraw(self):
1489 """Redraw the tank figure."""
1490 self._tankFigure.queue_draw()
1491
[142]1492 def _drawTankFigure(self, tankFigure, eventOrContext):
[141]1493 """Draw the tank figure."""
1494 triangleSize = 5
[142]1495
1496 context = eventOrContext if pygobject else tankFigure.window.cairo_create()
1497 (xOffset, yOffset) = (0, 0) if pygobject \
1498 else (tankFigure.allocation.x, tankFigure.allocation.y)
[347]1499
[142]1500 width = tankFigure.get_allocated_width() if pygobject \
1501 else tankFigure.allocation.width
1502 height = tankFigure.get_allocated_height() if pygobject \
1503 else tankFigure.allocation.height
[141]1504
1505 rectangleX0 = triangleSize
1506 rectangleY0 = triangleSize
1507 rectangleX1 = width - 1 - triangleSize
1508 rectangleY1 = height - 1 - triangleSize
1509 rectangleLineWidth = 2.0
1510
1511 context.set_source_rgb(0.0, 0.0, 0.0)
1512 context.set_line_width(rectangleLineWidth)
[142]1513 context.rectangle(xOffset + rectangleX0 + rectangleLineWidth/2,
1514 yOffset + rectangleY0 + rectangleLineWidth/2,
[141]1515 rectangleX1 - rectangleX0 - rectangleLineWidth,
1516 rectangleY1 - rectangleY0 - rectangleLineWidth)
1517 context.stroke()
1518
1519 rectangleInnerLeft = rectangleX0 + rectangleLineWidth
1520 rectangleInnerRight = rectangleX1 - rectangleLineWidth
[144]1521 self._rectangleInnerTop = rectangleInnerTop = rectangleY0 + rectangleLineWidth
1522 self._rectangleInnerBottom = rectangleInnerBottom = rectangleY1 - rectangleLineWidth
[141]1523
1524 rectangleInnerWidth = rectangleInnerRight - rectangleInnerLeft
1525 rectangleInnerHeight = rectangleInnerBottom - rectangleInnerTop
1526
1527 context.set_source_rgb(1.0, 0.9, 0.6)
1528 currentHeight = self.currentWeight * rectangleInnerHeight / self.capacity
1529 currentX = rectangleInnerTop + rectangleInnerHeight - currentHeight
[142]1530 context.rectangle(xOffset + rectangleInnerLeft,
1531 yOffset + rectangleInnerTop +
1532 rectangleInnerHeight - currentHeight,
[141]1533 rectangleInnerWidth, currentHeight)
1534 context.fill()
1535
1536 expectedHeight = self.expectedWeight * rectangleInnerHeight / self.capacity
1537 expectedY = rectangleInnerTop + rectangleInnerHeight - expectedHeight
1538
1539 context.set_line_width(1.5)
1540 context.set_source_rgb(0.0, 0.85, 0.85)
[142]1541 context.move_to(xOffset + rectangleX0, yOffset + expectedY)
1542 context.line_to(xOffset + rectangleX1, yOffset + expectedY)
[141]1543 context.stroke()
1544
1545 context.set_line_width(0.0)
[142]1546 context.move_to(xOffset + 0, yOffset + expectedY - triangleSize)
1547 context.line_to(xOffset + 0, yOffset + expectedY + triangleSize)
1548 context.line_to(xOffset + rectangleX0 + 1, yOffset + expectedY)
1549 context.line_to(xOffset + 0, yOffset + expectedY - triangleSize)
[141]1550 context.fill()
1551
1552 context.set_line_width(0.0)
[142]1553 context.move_to(xOffset + width, yOffset + expectedY - triangleSize)
1554 context.line_to(xOffset + width, yOffset + expectedY + triangleSize)
1555 context.line_to(xOffset + rectangleX1 - 1, yOffset + expectedY)
1556 context.line_to(xOffset + width, yOffset + expectedY - triangleSize)
[141]1557 context.fill()
1558
[142]1559 return True
1560
[144]1561 def _setExpectedFromY(self, y):
1562 """Set the expected weight from the given Y-coordinate."""
1563 level = (self._rectangleInnerBottom - y) / \
1564 (self._rectangleInnerBottom - self._rectangleInnerTop)
1565 level = min(1.0, max(0.0, level))
1566 self._expectedButton.set_value(level * self.capacity)
[347]1567
[144]1568 def _buttonPressed(self, tankFigure, event):
1569 """Called when a button is pressed in the figure.
1570
1571 The expected level will be set there."""
[146]1572 if self._enabled and event.button==1:
[144]1573 self._setExpectedFromY(event.y)
[347]1574
[144]1575 def _motionNotify(self, tankFigure, event):
1576 """Called when the mouse pointer moves within the area of a tank figure."""
[347]1577 if self._enabled and event.state==BUTTON1_MASK:
[144]1578 self._setExpectedFromY(event.y)
1579
1580 def _scrolled(self, tankFigure, event):
1581 """Called when a scroll event is received."""
[146]1582 if self._enabled:
1583 increment = 1 if event.state==CONTROL_MASK \
1584 else 100 if event.state==SHIFT_MASK \
1585 else 10 if event.state==0 else 0
1586 if increment!=0:
1587 if event.direction==SCROLL_DOWN:
1588 increment *= -1
1589 self._expectedButton.spin(SPIN_USER_DEFINED, increment)
[347]1590
[141]1591 def _expectedChanged(self, spinButton):
1592 """Called when the expected value has changed."""
1593 self.expectedWeight = spinButton.get_value_as_int()
[347]1594 self._redraw()
[141]1595
1596#-----------------------------------------------------------------------------
1597
1598class FuelPage(Page):
1599 """The page containing the fuel tank filling."""
1600 _pumpStep = 0.02
[347]1601
[141]1602 def __init__(self, wizard):
1603 """Construct the page."""
1604 super(FuelPage, self).__init__(wizard, xstr("fuel_title"),
1605 xstr("fuel_help"),
1606 completedHelp = xstr("fuel_chelp"))
1607
1608 self._fuelTanks = []
1609 self._fuelTable = None
1610 self._fuelAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1611 xscale = 0.0, yscale = 1.0)
1612 self.setMainWidget(self._fuelAlignment)
1613
[274]1614 tankData = [(tank, 2500, 3900) for tank in acft.mostFuelTanks]
1615 self._setupTanks(tankData)
[141]1616
[208]1617 self.addCancelFlightButton()
1618
[141]1619 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1620 self._button = self.addNextButton(clicked = self._forwardClicked)
1621
1622 self._pumpIndex = 0
1623
[145]1624 def activate(self):
1625 """Activate the page."""
[274]1626 self._setupTanks(self._wizard._fuelData)
[141]1627
1628 def finalize(self):
1629 """Finalize the page."""
1630 for fuelTank in self._fuelTanks:
1631 fuelTank.disable()
1632
1633 def _backClicked(self, button):
1634 """Called when the Back button is pressed."""
1635 self.goBack()
[347]1636
[141]1637 def _forwardClicked(self, button):
1638 """Called when the forward button is clicked."""
1639 if not self._completed:
1640 self._pumpIndex = 0
1641 self._wizard.gui.beginBusy(xstr("fuel_pump_busy"))
1642 self._pump()
1643 else:
[347]1644 self._wizard.nextPage()
[141]1645
[274]1646 def _setupTanks(self, tankData):
[141]1647 """Setup the tanks for the given data."""
[274]1648 numTanks = len(tankData)
[141]1649 if self._fuelTable is not None:
1650 self._fuelAlignment.remove(self._fuelTable)
1651
1652 self._fuelTanks = []
1653 self._fuelTable = gtk.Table(numTanks, 1)
1654 self._fuelTable.set_col_spacings(16)
[274]1655 index = 0
1656 for (tank, current, capacity) in tankData:
[141]1657 fuelTank = FuelTank(tank,
1658 xstr("fuel_tank_" +
1659 const.fuelTank2string(tank)),
1660 capacity, current)
[274]1661 self._fuelTable.attach(fuelTank, index, index+1, 0, 1)
[141]1662 self._fuelTanks.append(fuelTank)
[274]1663 index += 1
[347]1664
[141]1665 self._fuelAlignment.add(self._fuelTable)
1666 self.show_all()
1667
1668 def _pump(self):
1669 """Perform one step of pumping.
1670
1671 It is checked, if the current tank's contents are of the right
1672 quantity. If not, it is filled one step further to the desired
1673 contents. Otherwise the next tank is started. If all tanks are are
1674 filled, the next page is selected."""
1675 numTanks = len(self._fuelTanks)
1676
1677 fuelTank = None
1678 while self._pumpIndex < numTanks:
1679 fuelTank = self._fuelTanks[self._pumpIndex]
1680 if fuelTank.isCorrect():
1681 self._pumpIndex += 1
1682 fuelTank = None
1683 else:
1684 break
1685
1686 if fuelTank is None:
1687 self._wizard.gui.endBusy()
1688 self._wizard.nextPage()
1689 else:
1690 currentLevel = fuelTank.currentWeight / fuelTank.capacity
1691 expectedLevel = fuelTank.expectedWeight / fuelTank.capacity
1692 if currentLevel<expectedLevel:
1693 currentLevel += FuelPage._pumpStep
1694 if currentLevel>expectedLevel: currentLevel = expectedLevel
1695 else:
1696 currentLevel -= FuelPage._pumpStep
1697 if currentLevel<expectedLevel: currentLevel = expectedLevel
1698 fuelTank.setCurrent(currentLevel * fuelTank.capacity)
1699 self._wizard.gui.simulator.setFuelLevel([(fuelTank.fuelTank,
1700 currentLevel)])
1701 gobject.timeout_add(50, self._pump)
[347]1702
[141]1703#-----------------------------------------------------------------------------
1704
[62]1705class RoutePage(Page):
1706 """The page containing the route and the flight level."""
1707 def __init__(self, wizard):
[141]1708 """Construct the page."""
[107]1709 super(RoutePage, self).__init__(wizard, xstr("route_title"),
1710 xstr("route_help"),
1711 completedHelp = xstr("route_chelp"))
[62]1712
1713 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1714 xscale = 0.0, yscale = 0.0)
1715
1716 mainBox = gtk.VBox()
1717 alignment.add(mainBox)
1718 self.setMainWidget(alignment)
1719
1720 levelBox = gtk.HBox()
1721
[107]1722 label = gtk.Label(xstr("route_level"))
[62]1723 label.set_use_underline(True)
1724 levelBox.pack_start(label, True, True, 0)
1725
1726 self._cruiseLevel = gtk.SpinButton()
1727 self._cruiseLevel.set_increments(step = 10, page = 100)
[554]1728 self._cruiseLevel.set_range(min = 0, max = 500)
[107]1729 self._cruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
[62]1730 self._cruiseLevel.set_numeric(True)
1731 self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
[97]1732 label.set_mnemonic_widget(self._cruiseLevel)
[62]1733
1734 levelBox.pack_start(self._cruiseLevel, False, False, 8)
1735
1736 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1737 xscale = 0.0, yscale = 0.0)
1738 alignment.add(levelBox)
1739
1740 mainBox.pack_start(alignment, False, False, 0)
1741
1742
1743 routeBox = gtk.VBox()
1744
1745 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1746 xscale = 0.0, yscale = 0.0)
[107]1747 label = gtk.Label(xstr("route_route"))
[62]1748 label.set_use_underline(True)
1749 alignment.add(label)
1750 routeBox.pack_start(alignment, True, True, 0)
1751
1752 routeWindow = gtk.ScrolledWindow()
1753 routeWindow.set_size_request(400, 80)
1754 routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
1755 else gtk.SHADOW_IN)
[69]1756 routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1757 else gtk.POLICY_AUTOMATIC,
1758 gtk.PolicyType.AUTOMATIC if pygobject
1759 else gtk.POLICY_AUTOMATIC)
[62]1760
[138]1761 self._uppercasingRoute = False
1762
[62]1763 self._route = gtk.TextView()
[107]1764 self._route.set_tooltip_text(xstr("route_route_tooltip"))
[138]1765 self._route.set_wrap_mode(WRAP_WORD)
[62]1766 self._route.get_buffer().connect("changed", self._routeChanged)
[138]1767 self._route.get_buffer().connect_after("insert-text", self._routeInserted)
[62]1768 routeWindow.add(self._route)
1769
1770 label.set_mnemonic_widget(self._route)
[347]1771 routeBox.pack_start(routeWindow, True, True, 0)
[62]1772
1773 mainBox.pack_start(routeBox, True, True, 8)
1774
[208]1775 self.addCancelFlightButton()
1776
[347]1777 self._backButton = self.addPreviousButton(clicked = self._backClicked)
[107]1778 self._button = self.addNextButton(clicked = self._forwardClicked)
[62]1779
[84]1780 @property
[97]1781 def filedCruiseLevel(self):
1782 """Get the filed cruise level."""
[84]1783 return self._cruiseLevel.get_value_as_int()
1784
[97]1785 @property
1786 def route(self):
1787 """Get the route."""
1788 return self._getRoute()
1789
[62]1790 def activate(self):
1791 """Setup the route from the booked flight."""
[554]1792 self._cruiseLevel.set_value(0)
1793 self._cruiseLevel.set_text("")
[62]1794 self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
1795 self._updateForwardButton()
1796
1797 def _getRoute(self):
1798 """Get the text of the route."""
1799 buffer = self._route.get_buffer()
1800 return buffer.get_text(buffer.get_start_iter(),
1801 buffer.get_end_iter(), True)
1802
1803 def _updateForwardButton(self):
1804 """Update the sensitivity of the forward button."""
1805 self._button.set_sensitive(self._cruiseLevel.get_value_as_int()>=50 and \
[68]1806 self._getRoute()!="")
[347]1807
[62]1808 def _cruiseLevelChanged(self, spinButton):
1809 """Called when the cruise level has changed."""
1810 self._updateForwardButton()
1811
1812 def _routeChanged(self, textBuffer):
1813 """Called when the route has changed."""
[138]1814 if not self._uppercasingRoute:
1815 self._updateForwardButton()
1816
1817 def _routeInserted(self, textBuffer, iter, text, length):
1818 """Called when new characters are inserted into the route.
1819
1820 It uppercases all characters."""
1821 if not self._uppercasingRoute:
1822 self._uppercasingRoute = True
1823
1824 iter1 = iter.copy()
1825 iter1.backward_chars(length)
1826 textBuffer.delete(iter, iter1)
1827
1828 textBuffer.insert(iter, text.upper())
1829
1830 self._uppercasingRoute = False
[62]1831
[70]1832 def _backClicked(self, button):
1833 """Called when the Back button is pressed."""
1834 self.goBack()
[347]1835
[62]1836 def _forwardClicked(self, button):
1837 """Called when the Forward button is clicked."""
[94]1838 if self._completed:
[70]1839 self._wizard.nextPage()
1840 else:
1841 bookedFlight = self._wizard._bookedFlight
[107]1842 self._wizard.gui.beginBusy(xstr("route_down_notams"))
[70]1843 self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
1844 bookedFlight.departureICAO,
1845 bookedFlight.arrivalICAO)
[170]1846 startSound(const.SOUND_NOTAM)
[64]1847
1848 def _notamsCallback(self, returned, result):
1849 """Callback for the NOTAMs."""
1850 gobject.idle_add(self._handleNOTAMs, returned, result)
1851
1852 def _handleNOTAMs(self, returned, result):
1853 """Handle the NOTAMs."""
1854 if returned:
1855 self._wizard._departureNOTAMs = result.departureNOTAMs
1856 self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
[67]1857 else:
1858 self._wizard._departureNOTAMs = None
1859 self._wizard._arrivalNOTAMs = None
[64]1860
[67]1861 bookedFlight = self._wizard._bookedFlight
[107]1862 self._wizard.gui.beginBusy(xstr("route_down_metars"))
[67]1863 self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
1864 [bookedFlight.departureICAO,
1865 bookedFlight.arrivalICAO])
1866
1867 def _metarsCallback(self, returned, result):
1868 """Callback for the METARs."""
1869 gobject.idle_add(self._handleMETARs, returned, result)
1870
1871 def _handleMETARs(self, returned, result):
1872 """Handle the METARs."""
1873 self._wizard._departureMETAR = None
1874 self._wizard._arrivalMETAR = None
1875 bookedFlight = self._wizard._bookedFlight
1876 if returned:
1877 if bookedFlight.departureICAO in result.metars:
1878 self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
1879 if bookedFlight.arrivalICAO in result.metars:
1880 self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
1881
1882 self._wizard.gui.endBusy()
[70]1883 self._backButton.set_sensitive(True)
1884 self._button.set_sensitive(True)
[62]1885 self._wizard.nextPage()
1886
1887#-----------------------------------------------------------------------------
1888
[67]1889class BriefingPage(Page):
1890 """Page for the briefing."""
1891 def __init__(self, wizard, departure):
1892 """Construct the briefing page."""
1893 self._departure = departure
[347]1894
[107]1895 title = xstr("briefing_title") % (1 if departure else 2,
1896 xstr("briefing_departure")
1897 if departure
1898 else xstr("briefing_arrival"))
1899 super(BriefingPage, self).__init__(wizard, title, xstr("briefing_help"),
1900 completedHelp = xstr("briefing_chelp"))
[64]1901
1902 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1903 xscale = 1.0, yscale = 1.0)
1904
1905 mainBox = gtk.VBox()
1906 alignment.add(mainBox)
1907 self.setMainWidget(alignment)
1908
[67]1909 self._notamsFrame = gtk.Frame()
[107]1910 self._notamsFrame.set_label(xstr("briefing_notams_init"))
[64]1911 scrolledWindow = gtk.ScrolledWindow()
[67]1912 scrolledWindow.set_size_request(-1, 128)
[94]1913 # FIXME: these constants should be in common
[69]1914 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1915 else gtk.POLICY_AUTOMATIC,
1916 gtk.PolicyType.AUTOMATIC if pygobject
1917 else gtk.POLICY_AUTOMATIC)
[67]1918 self._notams = gtk.TextView()
1919 self._notams.set_editable(False)
1920 self._notams.set_accepts_tab(False)
1921 self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
1922 scrolledWindow.add(self._notams)
1923 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1924 xscale = 1.0, yscale = 1.0)
1925 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1926 padding_left = 0, padding_right = 0)
1927 alignment.add(scrolledWindow)
1928 self._notamsFrame.add(alignment)
1929 mainBox.pack_start(self._notamsFrame, True, True, 4)
[347]1930
[67]1931 self._metarFrame = gtk.Frame()
[107]1932 self._metarFrame.set_label(xstr("briefing_metar_init"))
[67]1933 scrolledWindow = gtk.ScrolledWindow()
1934 scrolledWindow.set_size_request(-1, 32)
[69]1935 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1936 else gtk.POLICY_AUTOMATIC,
1937 gtk.PolicyType.AUTOMATIC if pygobject
1938 else gtk.POLICY_AUTOMATIC)
[138]1939
1940 self._uppercasingMETAR = False
1941
[67]1942 self._metar = gtk.TextView()
1943 self._metar.set_accepts_tab(False)
1944 self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
[106]1945 self._metar.get_buffer().connect("changed", self._metarChanged)
[138]1946 self._metar.get_buffer().connect_after("insert-text", self._metarInserted)
[67]1947 scrolledWindow.add(self._metar)
1948 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1949 xscale = 1.0, yscale = 1.0)
1950 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1951 padding_left = 0, padding_right = 0)
1952 alignment.add(scrolledWindow)
1953 self._metarFrame.add(alignment)
1954 mainBox.pack_start(self._metarFrame, True, True, 4)
[106]1955 self.metarEdited = False
[64]1956
[208]1957 self.addCancelFlightButton()
1958
[107]1959 self.addPreviousButton(clicked = self._backClicked)
1960 self._button = self.addNextButton(clicked = self._forwardClicked)
[64]1961
[97]1962 @property
1963 def metar(self):
1964 """Get the METAR on the page."""
1965 buffer = self._metar.get_buffer()
1966 return buffer.get_text(buffer.get_start_iter(),
[347]1967 buffer.get_end_iter(), True)
[97]1968
[106]1969 def setMETAR(self, metar):
1970 """Set the metar."""
1971 self._metar.get_buffer().set_text(metar)
1972 self.metarEdited = False
1973
[64]1974 def activate(self):
1975 """Activate the page."""
[70]1976 if not self._departure:
[107]1977 self._button.set_label(xstr("briefing_button"))
1978 self._button.set_has_tooltip(False)
[70]1979 self._button.set_use_stock(False)
1980
1981 bookedFlight = self._wizard._bookedFlight
[67]1982
[70]1983 icao = bookedFlight.departureICAO if self._departure \
1984 else bookedFlight.arrivalICAO
1985 notams = self._wizard._departureNOTAMs if self._departure \
1986 else self._wizard._arrivalNOTAMs
1987 metar = self._wizard._departureMETAR if self._departure \
1988 else self._wizard._arrivalMETAR
[64]1989
[107]1990 self._notamsFrame.set_label(xstr("briefing_notams_template") % (icao,))
[70]1991 buffer = self._notams.get_buffer()
1992 if notams is None:
[107]1993 buffer.set_text(xstr("briefing_notams_failed"))
[92]1994 elif not notams:
[107]1995 buffer.set_text(xstr("briefing_notams_missing"))
[70]1996 else:
1997 s = ""
1998 for notam in notams:
[570]1999 s += str(notam)
[70]2000 s += "-------------------- * --------------------\n"
2001 buffer.set_text(s)
[67]2002
[107]2003 self._metarFrame.set_label(xstr("briefing_metar_template") % (icao,))
[70]2004 buffer = self._metar.get_buffer()
2005 if metar is None:
[584]2006 #buffer.set_text(xstr("briefing_metar_failed"))
2007 buffer.set_text("")
2008 self.setHelp(xstr("briefing_help_nometar"))
[70]2009 else:
2010 buffer.set_text(metar)
[584]2011 self._updateButton()
[67]2012
[107]2013 label = self._metarFrame.get_label_widget()
2014 label.set_use_underline(True)
2015 label.set_mnemonic_widget(self._metar)
2016
[106]2017 self.metarEdited = False
2018
[70]2019 def _backClicked(self, button):
2020 """Called when the Back button is pressed."""
2021 self.goBack()
[347]2022
[67]2023 def _forwardClicked(self, button):
[64]2024 """Called when the forward button is clicked."""
[70]2025 if not self._departure:
[94]2026 if not self._completed:
[70]2027 self._wizard.gui.startMonitoring()
[107]2028 self._button.set_label(xstr("button_next"))
2029 self._button.set_tooltip_text(xstr("button_next_tooltip"))
[94]2030 self.complete()
[71]2031
2032 self._wizard.nextPage()
2033
[106]2034 def _metarChanged(self, buffer):
2035 """Called when the METAR has changed."""
[138]2036 if not self._uppercasingMETAR:
2037 self.metarEdited = True
[584]2038 self._updateButton()
[138]2039
2040 def _metarInserted(self, textBuffer, iter, text, length):
2041 """Called when new characters are inserted into the METAR.
2042
2043 It uppercases all characters."""
2044 if not self._uppercasingMETAR:
2045 self._uppercasingMETAR = True
2046
2047 iter1 = iter.copy()
2048 iter1.backward_chars(length)
2049 textBuffer.delete(iter, iter1)
2050
2051 textBuffer.insert(iter, text.upper())
2052
2053 self._uppercasingMETAR = False
[106]2054
[584]2055 def _updateButton(self):
2056 """Update the sensitivity of the Next button based on the contents of
2057 the METAR field."""
2058 buffer = self._metar.get_buffer()
2059 self._button.set_sensitive(buffer.get_text(buffer.get_start_iter(),
2060 buffer.get_end_iter(),
2061 True)!="")
2062
2063
[71]2064#-----------------------------------------------------------------------------
2065
2066class TakeoffPage(Page):
2067 """Page for entering the takeoff data."""
2068 def __init__(self, wizard):
2069 """Construct the takeoff page."""
[107]2070 super(TakeoffPage, self).__init__(wizard, xstr("takeoff_title"),
2071 xstr("takeoff_help"),
2072 completedHelp = xstr("takeoff_chelp"))
[71]2073
[101]2074 self._forwardAllowed = False
2075
[71]2076 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2077 xscale = 0.0, yscale = 0.0)
2078
[391]2079 table = gtk.Table(8, 4)
[71]2080 table.set_row_spacings(4)
2081 table.set_col_spacings(16)
2082 table.set_homogeneous(False)
2083 alignment.add(table)
2084 self.setMainWidget(alignment)
2085
[107]2086 label = gtk.Label(xstr("takeoff_runway"))
[71]2087 label.set_use_underline(True)
2088 label.set_alignment(0.0, 0.5)
2089 table.attach(label, 0, 1, 0, 1)
2090
2091 self._runway = gtk.Entry()
2092 self._runway.set_width_chars(10)
[107]2093 self._runway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
[138]2094 self._runway.connect("changed", self._upperChanged)
[84]2095 table.attach(self._runway, 1, 3, 0, 1)
[71]2096 label.set_mnemonic_widget(self._runway)
[347]2097
[107]2098 label = gtk.Label(xstr("takeoff_sid"))
[71]2099 label.set_use_underline(True)
2100 label.set_alignment(0.0, 0.5)
2101 table.attach(label, 0, 1, 1, 2)
2102
2103 self._sid = gtk.Entry()
2104 self._sid.set_width_chars(10)
[107]2105 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
[138]2106 self._sid.connect("changed", self._upperChanged)
[84]2107 table.attach(self._sid, 1, 3, 1, 2)
[71]2108 label.set_mnemonic_widget(self._sid)
[347]2109
[107]2110 label = gtk.Label(xstr("takeoff_v1"))
[71]2111 label.set_use_markup(True)
2112 label.set_use_underline(True)
2113 label.set_alignment(0.0, 0.5)
2114 table.attach(label, 0, 1, 2, 3)
2115
[84]2116 self._v1 = IntegerEntry()
[86]2117 self._v1.set_width_chars(4)
[241]2118 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip_knots"))
[101]2119 self._v1.connect("integer-changed", self._valueChanged)
[84]2120 table.attach(self._v1, 2, 3, 2, 3)
[71]2121 label.set_mnemonic_widget(self._v1)
[241]2122
2123 self._v1Unit = gtk.Label(xstr("label_knots"))
[384]2124 self._v1Unit.set_alignment(0.0, 0.5)
[241]2125 table.attach(self._v1Unit, 3, 4, 2, 3)
[347]2126
[107]2127 label = gtk.Label(xstr("takeoff_vr"))
[71]2128 label.set_use_markup(True)
2129 label.set_use_underline(True)
2130 label.set_alignment(0.0, 0.5)
2131 table.attach(label, 0, 1, 3, 4)
2132
[84]2133 self._vr = IntegerEntry()
[86]2134 self._vr.set_width_chars(4)
[241]2135 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip_knots"))
[101]2136 self._vr.connect("integer-changed", self._valueChanged)
[84]2137 table.attach(self._vr, 2, 3, 3, 4)
[71]2138 label.set_mnemonic_widget(self._vr)
[347]2139
[241]2140 self._vrUnit = gtk.Label(xstr("label_knots"))
[384]2141 self._vrUnit.set_alignment(0.0, 0.5)
[241]2142 table.attach(self._vrUnit, 3, 4, 3, 4)
[347]2143
[107]2144 label = gtk.Label(xstr("takeoff_v2"))
[71]2145 label.set_use_markup(True)
2146 label.set_use_underline(True)
2147 label.set_alignment(0.0, 0.5)
2148 table.attach(label, 0, 1, 4, 5)
2149
[84]2150 self._v2 = IntegerEntry()
[86]2151 self._v2.set_width_chars(4)
[241]2152 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip_knots"))
[101]2153 self._v2.connect("integer-changed", self._valueChanged)
[84]2154 table.attach(self._v2, 2, 3, 4, 5)
[71]2155 label.set_mnemonic_widget(self._v2)
[347]2156
[241]2157 self._v2Unit = gtk.Label(xstr("label_knots"))
[384]2158 self._v2Unit.set_alignment(0.0, 0.5)
[241]2159 table.attach(self._v2Unit, 3, 4, 4, 5)
[71]2160
[512]2161 self._derateType = acft.DERATE_NONE
[384]2162
2163 self._derateLabel = gtk.Label()
2164 self._derateLabel.set_use_underline(True)
2165 self._derateLabel.set_markup(xstr("takeoff_derate_tupolev"))
2166 self._derateLabel.set_alignment(0.0, 0.5)
2167 table.attach(self._derateLabel, 0, 1, 5, 6)
2168
[512]2169 self._derate = gtk.Alignment()
2170 table.attach(self._derate, 2, 4, 5, 6)
2171 self._derateWidget = None
2172 self._derateEntry = None
2173 self._derateUnit = None
2174 self._derateButtons = None
[384]2175
[391]2176 self._antiIceOn = gtk.CheckButton(xstr("takeoff_antiice"))
2177 self._antiIceOn.set_use_underline(True)
2178 self._antiIceOn.set_tooltip_text(xstr("takeoff_antiice_tooltip"))
2179 table.attach(self._antiIceOn, 2, 4, 6, 7)
2180
[349]2181 self._rto = gtk.CheckButton(xstr("takeoff_rto"))
2182 self._rto.set_use_underline(True)
2183 self._rto.set_tooltip_text(xstr("takeoff_rto_tooltip"))
2184 self._rto.connect("toggled", self._rtoToggled)
[391]2185 table.attach(self._rto, 2, 4, 7, 8, ypadding = 8)
[349]2186
[208]2187 self.addCancelFlightButton()
2188
[107]2189 self.addPreviousButton(clicked = self._backClicked)
2190
2191 self._button = self.addNextButton(clicked = self._forwardClicked)
[71]2192
[84]2193 @property
[97]2194 def runway(self):
2195 """Get the runway."""
2196 return self._runway.get_text()
2197
2198 @property
2199 def sid(self):
2200 """Get the SID."""
2201 return self._sid.get_text()
2202
2203 @property
[84]2204 def v1(self):
2205 """Get the v1 speed."""
2206 return self._v1.get_int()
2207
2208 @property
2209 def vr(self):
2210 """Get the vr speed."""
2211 return self._vr.get_int()
2212
2213 @property
2214 def v2(self):
2215 """Get the v2 speed."""
2216 return self._v2.get_int()
2217
[349]2218 @property
[384]2219 def derate(self):
2220 """Get the derate value, if any."""
[512]2221 if self._derateWidget is None:
2222 return None
2223 if self._derateType==acft.DERATE_BOEING:
2224 derate = self._derateEntry.get_text()
[384]2225 return derate if derate else None
[512]2226 elif self._derateType==acft.DERATE_EPR:
2227 derate = self._derateWidget.get_text()
2228 return derate if derate else None
2229 elif self._derateType==acft.DERATE_TUPOLEV:
2230 return acft.DERATE_TUPOLEV_NOMINAL \
2231 if self._derateButtons[0].get_active() \
2232 else acft.DERATE_TUPOLEV_TAKEOFF
2233 elif self._derateType==acft.DERATE_B462:
2234 return self._derateWidget.get_active()
[384]2235 else:
2236 return None
2237
2238 @property
[391]2239 def antiIceOn(self):
2240 """Get whether the anti-ice system has been turned on."""
2241 return self._antiIceOn.get_active()
2242
2243 @antiIceOn.setter
2244 def antiIceOn(self, value):
2245 """Set the anti-ice indicator."""
2246 self._antiIceOn.set_active(value)
2247
2248 @property
[349]2249 def rtoIndicated(self):
2250 """Get whether the pilot has indicated if there was an RTO."""
2251 return self._rto.get_active()
2252
[71]2253 def activate(self):
2254 """Activate the page."""
[551]2255 print "TakeoffPage.activate"
2256
[72]2257 self._runway.set_text("")
[71]2258 self._runway.set_sensitive(True)
[72]2259 self._sid.set_text("")
[71]2260 self._sid.set_sensitive(True)
[84]2261 self._v1.set_int(None)
[71]2262 self._v1.set_sensitive(True)
[86]2263 self._vr.set_int(None)
[71]2264 self._vr.set_sensitive(True)
[86]2265 self._v2.set_int(None)
[71]2266 self._v2.set_sensitive(True)
[241]2267
2268 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
2269 speedUnit = xstr("label" + i18nSpeedUnit)
2270 self._v1Unit.set_text(speedUnit)
2271 self._vrUnit.set_text(speedUnit)
2272 self._v2Unit.set_text(speedUnit)
2273
2274 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip" + i18nSpeedUnit))
2275 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip" + i18nSpeedUnit))
2276 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip" + i18nSpeedUnit))
2277
[512]2278 self._derateType = self._wizard.gui.flight.aircraft.derateType
2279
2280 self._setupDerateWidget()
[384]2281
[349]2282 self._rto.set_active(False)
2283 self._rto.set_sensitive(False)
2284
[84]2285 self._button.set_sensitive(False)
[218]2286 self._forwardAllowed = False
[347]2287
[101]2288 def allowForward(self):
2289 """Allow going to the next page."""
[551]2290 print "TakeoffPage.allowForward"
[101]2291 self._forwardAllowed = True
2292 self._updateForwardButton()
2293
[241]2294 def reset(self):
2295 """Reset the page if the wizard is reset."""
[551]2296 print "TakeoffPage.reset"
2297
[241]2298 super(TakeoffPage, self).reset()
2299 self._v1.reset()
2300 self._vr.reset()
2301 self._v2.reset()
[384]2302 self._hasDerate = False
[391]2303 self._antiIceOn.set_active(False)
[384]2304
[349]2305 def setRTOEnabled(self, enabled):
2306 """Set the RTO checkbox enabled or disabled."""
2307 if not enabled:
2308 self._rto.set_active(False)
2309 self._rto.set_sensitive(enabled)
2310
[101]2311 def _updateForwardButton(self):
2312 """Update the sensitivity of the forward button based on some conditions."""
[551]2313
[101]2314 sensitive = self._forwardAllowed and \
2315 self._runway.get_text()!="" and \
2316 self._sid.get_text()!="" and \
2317 self.v1 is not None and \
2318 self.vr is not None and \
2319 self.v2 is not None and \
2320 self.v1 <= self.vr and \
[384]2321 self.vr <= self.v2 and \
[512]2322 (self._derateType==acft.DERATE_NONE or
2323 self.derate is not None)
[551]2324
2325 print "TakeoffPage._updateForwardButton: forwardAllowed:", self._forwardAllowed, ", sensitive:", sensitive
2326
[101]2327 self._button.set_sensitive(sensitive)
2328
2329 def _valueChanged(self, widget, arg = None):
2330 """Called when the value of some widget has changed."""
[551]2331 print "TakeoffPage._valueChanged"
2332
[101]2333 self._updateForwardButton()
[347]2334
[138]2335 def _upperChanged(self, entry, arg = None):
2336 """Called when the value of some entry widget has changed and the value
2337 should be converted to uppercase."""
[551]2338 print "TakeoffPage._upperChanged"
[138]2339 entry.set_text(entry.get_text().upper())
2340 self._valueChanged(entry, arg)
[347]2341
[384]2342 def _derateChanged(self, entry):
2343 """Called when the value of the derate is changed."""
[551]2344 print "TakeoffPage._derateChanged"
[384]2345 self._updateForwardButton()
2346
[349]2347 def _rtoToggled(self, button):
2348 """Called when the RTO check button is toggled."""
2349 self._wizard.rtoToggled(button.get_active())
2350
[71]2351 def _backClicked(self, button):
2352 """Called when the Back button is pressed."""
2353 self.goBack()
[347]2354
[71]2355 def _forwardClicked(self, button):
2356 """Called when the forward button is clicked."""
[391]2357 aircraft = self._wizard.gui.flight.aircraft
2358 aircraft.updateV1R2()
[512]2359 if self.derate is not None:
[391]2360 aircraft.updateDerate()
2361 aircraft.updateTakeoffAntiIce()
[75]2362 self._wizard.nextPage()
2363
[512]2364 def _setupDerateWidget(self):
2365 """Setup the derate widget."""
2366 if self._derateWidget is not None:
2367 self._derate.remove(self._derateWidget)
2368
2369 if self._derateType==acft.DERATE_BOEING:
2370 self._derateLabel.set_text(xstr("takeoff_derate_boeing"))
2371 self._derateLabel.set_use_underline(True)
2372 self._derateLabel.set_sensitive(True)
2373
2374 self._derateEntry = gtk.Entry()
2375 self._derateEntry.set_width_chars(7)
2376 self._derateEntry.set_tooltip_text(xstr("takeoff_derate_boeing_tooltip"))
2377 self._derateEntry.set_alignment(1.0)
2378 self._derateEntry.connect("changed", self._derateChanged)
2379 self._derateLabel.set_mnemonic_widget(self._derateEntry)
2380
2381 self._derateUnit = gtk.Label("%")
2382 self._derateUnit.set_alignment(0.0, 0.5)
2383
2384 self._derateWidget = gtk.Table(3, 1)
2385 self._derateWidget.set_row_spacings(4)
2386 self._derateWidget.set_col_spacings(16)
2387 self._derateWidget.set_homogeneous(False)
2388
2389 self._derateWidget.attach(self._derateEntry, 0, 2, 0, 1)
2390 self._derateWidget.attach(self._derateUnit, 2, 3, 0, 1)
2391
2392 self._derate.add(self._derateWidget)
2393 elif self._derateType==acft.DERATE_EPR:
2394 self._derateLabel.set_text("_EPR:")
2395 self._derateLabel.set_use_underline(True)
2396 self._derateLabel.set_sensitive(True)
2397
2398 self._derateWidget = gtk.Entry()
2399 self._derateWidget.set_width_chars(7)
2400 self._derateWidget.set_tooltip_text(xstr("takeoff_derate_epr_tooltip"))
2401 self._derateWidget.set_alignment(1.0)
2402 self._derateWidget.connect("changed", self._derateChanged)
2403 self._derateLabel.set_mnemonic_widget(self._derateWidget)
2404
2405 self._derate.add(self._derateWidget)
2406 elif self._derateType==acft.DERATE_TUPOLEV:
2407 self._derateLabel.set_text(xstr("takeoff_derate_tupolev"))
2408 self._derateLabel.set_use_underline(True)
2409 self._derateLabel.set_sensitive(True)
2410
2411 if pygobject:
2412 nominal = gtk.RadioButton.\
2413 new_with_label_from_widget(None,
2414 xstr("takeoff_derate_tupolev_nominal"))
2415 else:
2416 nominal = gtk.RadioButton(None,
2417 xstr("takeoff_derate_tupolev_nominal"))
2418 nominal.set_use_underline(True)
2419 nominal.set_tooltip_text(xstr("takeoff_derate_tupolev_nominal_tooltip"))
2420 nominal.connect("toggled", self._derateChanged)
2421
2422 if pygobject:
2423 takeoff = gtk.RadioButton.\
2424 new_with_label_from_widget(nominal,
2425 xstr("takeoff_derate_tupolev_takeoff"))
2426 else:
2427 takeoff = gtk.RadioButton(nominal,
2428 xstr("takeoff_derate_tupolev_takeoff"))
2429
2430 takeoff.set_use_underline(True)
2431 takeoff.set_tooltip_text(xstr("takeoff_derate_tupolev_takeoff_tooltip"))
2432 takeoff.connect("toggled", self._derateChanged)
2433
2434 self._derateButtons = [nominal, takeoff]
2435
2436 self._derateWidget = gtk.HBox()
2437 self._derateWidget.pack_start(nominal, False, False, 4)
2438 self._derateWidget.pack_start(takeoff, False, False, 4)
2439
2440 self._derate.add(self._derateWidget)
2441 elif self._derateType==acft.DERATE_B462:
2442 self._derateLabel.set_text("")
2443
2444 self._derateWidget = gtk.CheckButton(xstr("takeoff_derate_b462"))
2445 self._derateWidget.set_tooltip_text(xstr("takeoff_derate_b462_tooltip"))
2446 self._derateWidget.set_use_underline(True)
2447 self._derate.add(self._derateWidget)
2448 else:
2449 self._derateWidget = None
2450 self._derateLabel.set_text("")
2451 self._derateLabel.set_sensitive(False)
2452
[75]2453#-----------------------------------------------------------------------------
2454
[383]2455class CruisePage(Page):
2456 """The page containing the flight level that might change during flight."""
2457 def __init__(self, wizard):
2458 """Construct the page."""
2459 super(CruisePage, self).__init__(wizard, xstr("cruise_title"),
2460 xstr("cruise_help"))
2461
2462 self._loggable = False
2463 self._loggedCruiseLevel = 240
2464 self._activated = False
2465
2466 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
2467 xscale = 0.0, yscale = 1.0)
2468
2469 mainBox = gtk.VBox()
2470 alignment.add(mainBox)
2471 self.setMainWidget(alignment)
2472
2473 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
2474 xscale = 0.0, yscale = 0.0)
2475 mainBox.pack_start(alignment, False, False, 16)
2476
2477 levelBox = gtk.HBox()
2478
2479 label = gtk.Label(xstr("route_level"))
2480 label.set_use_underline(True)
2481 levelBox.pack_start(label, True, True, 0)
2482
2483 self._cruiseLevel = gtk.SpinButton()
2484 self._cruiseLevel.set_increments(step = 10, page = 100)
2485 self._cruiseLevel.set_range(min = 50, max = 500)
2486 self._cruiseLevel.set_tooltip_text(xstr("cruise_route_level_tooltip"))
2487 self._cruiseLevel.set_numeric(True)
2488 self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
2489 label.set_mnemonic_widget(self._cruiseLevel)
2490
2491 levelBox.pack_start(self._cruiseLevel, False, False, 8)
2492
2493 self._updateButton = gtk.Button(xstr("cruise_route_level_update"));
2494 self._updateButton.set_use_underline(True)
2495 self._updateButton.set_tooltip_text(xstr("cruise_route_level_update_tooltip"))
2496 self._updateButton.connect("clicked", self._updateButtonClicked)
2497
2498 levelBox.pack_start(self._updateButton, False, False, 16)
2499
2500 mainBox.pack_start(levelBox, False, False, 0)
2501
2502 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
2503 xscale = 0.0, yscale = 1.0)
2504 mainBox.pack_start(alignment, True, True, 0)
2505
2506 self.addCancelFlightButton()
2507
2508 self._backButton = self.addPreviousButton(clicked = self._backClicked)
2509 self._button = self.addNextButton(clicked = self._forwardClicked)
2510
2511 @property
2512 def activated(self):
2513 """Determine if the page is already activated or not."""
2514 return self._activated
2515
2516 @property
2517 def cruiseLevel(self):
2518 """Get the cruise level."""
2519 return self._loggedCruiseLevel
2520
2521 @property
2522 def loggableCruiseLevel(self):
2523 """Get the cruise level which should be logged."""
2524 return self._cruiseLevel.get_value_as_int()
2525
2526 def setLoggable(self, loggable):
2527 """Set whether the cruise altitude can be logged."""
2528 self._loggable = loggable
2529 self._updateButtons()
2530
2531 def activate(self):
2532 """Setup the route from the booked flight."""
2533 self._loggedCruiseLevel = self._wizard.filedCruiseLevel
2534 self._cruiseLevel.set_value(self._loggedCruiseLevel)
2535 self._activated = True
2536
2537 def reset(self):
2538 """Reset the page."""
2539 self._loggable = False
2540 self._activated = False
2541 super(CruisePage, self).reset()
2542
2543 def _updateButtons(self):
2544 """Update the sensitivity of the buttons."""
2545 self._updateButton.set_sensitive(self._loggable and
2546 self.loggableCruiseLevel!=
2547 self._loggedCruiseLevel)
2548
2549 def _cruiseLevelChanged(self, spinButton):
2550 """Called when the cruise level has changed."""
2551 self._updateButtons()
2552
2553 def _updateButtonClicked(self, button):
2554 """Called when the update button is clicked."""
2555 if self._wizard.cruiseLevelChanged():
2556 self._loggedCruiseLevel = self.loggableCruiseLevel
2557 self._updateButtons()
2558
2559 def _backClicked(self, button):
2560 """Called when the Back button is pressed."""
2561 self.goBack()
2562
2563 def _forwardClicked(self, button):
2564 """Called when the Forward button is clicked."""
2565 self._wizard.nextPage()
2566
2567#-----------------------------------------------------------------------------
2568
[75]2569class LandingPage(Page):
2570 """Page for entering landing data."""
2571 def __init__(self, wizard):
2572 """Construct the landing page."""
[107]2573 super(LandingPage, self).__init__(wizard, xstr("landing_title"),
2574 xstr("landing_help"),
2575 completedHelp = xstr("landing_chelp"))
[75]2576
[88]2577 self._flightEnded = False
2578
[75]2579 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2580 xscale = 0.0, yscale = 0.0)
2581
[391]2582 table = gtk.Table(6, 5)
[75]2583 table.set_row_spacings(4)
2584 table.set_col_spacings(16)
2585 table.set_homogeneous(False)
2586 alignment.add(table)
2587 self.setMainWidget(alignment)
2588
2589 self._starButton = gtk.CheckButton()
2590 self._starButton.connect("clicked", self._starButtonClicked)
2591 table.attach(self._starButton, 0, 1, 0, 1)
2592
[107]2593 label = gtk.Label(xstr("landing_star"))
[75]2594 label.set_use_underline(True)
2595 label.set_alignment(0.0, 0.5)
2596 table.attach(label, 1, 2, 0, 1)
2597
2598 self._star = gtk.Entry()
2599 self._star.set_width_chars(10)
[107]2600 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
[138]2601 self._star.connect("changed", self._upperChanged)
[75]2602 self._star.set_sensitive(False)
[86]2603 table.attach(self._star, 2, 4, 0, 1)
[75]2604 label.set_mnemonic_widget(self._starButton)
2605
2606 self._transitionButton = gtk.CheckButton()
2607 self._transitionButton.connect("clicked", self._transitionButtonClicked)
2608 table.attach(self._transitionButton, 0, 1, 1, 2)
2609
[107]2610 label = gtk.Label(xstr("landing_transition"))
[75]2611 label.set_use_underline(True)
2612 label.set_alignment(0.0, 0.5)
2613 table.attach(label, 1, 2, 1, 2)
2614
2615 self._transition = gtk.Entry()
2616 self._transition.set_width_chars(10)
[107]2617 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
[138]2618 self._transition.connect("changed", self._upperChanged)
[75]2619 self._transition.set_sensitive(False)
[86]2620 table.attach(self._transition, 2, 4, 1, 2)
[75]2621 label.set_mnemonic_widget(self._transitionButton)
2622
[107]2623 label = gtk.Label(xstr("landing_runway"))
[75]2624 label.set_use_underline(True)
2625 label.set_alignment(0.0, 0.5)
2626 table.attach(label, 1, 2, 2, 3)
2627
2628 self._runway = gtk.Entry()
2629 self._runway.set_width_chars(10)
[107]2630 self._runway.set_tooltip_text(xstr("landing_runway_tooltip"))
[138]2631 self._runway.connect("changed", self._upperChanged)
[86]2632 table.attach(self._runway, 2, 4, 2, 3)
[75]2633 label.set_mnemonic_widget(self._runway)
2634
[107]2635 label = gtk.Label(xstr("landing_approach"))
[75]2636 label.set_use_underline(True)
2637 label.set_alignment(0.0, 0.5)
2638 table.attach(label, 1, 2, 3, 4)
2639
2640 self._approachType = gtk.Entry()
2641 self._approachType.set_width_chars(10)
[107]2642 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
[138]2643 self._approachType.connect("changed", self._upperChanged)
[86]2644 table.attach(self._approachType, 2, 4, 3, 4)
[75]2645 label.set_mnemonic_widget(self._approachType)
2646
[107]2647 label = gtk.Label(xstr("landing_vref"))
[75]2648 label.set_use_markup(True)
2649 label.set_use_underline(True)
2650 label.set_alignment(0.0, 0.5)
[391]2651 table.attach(label, 1, 2, 4, 5)
[75]2652
[86]2653 self._vref = IntegerEntry()
2654 self._vref.set_width_chars(5)
[241]2655 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip_knots"))
[86]2656 self._vref.connect("integer-changed", self._vrefChanged)
[391]2657 table.attach(self._vref, 3, 4, 4, 5)
[75]2658 label.set_mnemonic_widget(self._vref)
[241]2659
2660 self._vrefUnit = gtk.Label(xstr("label_knots"))
[391]2661 table.attach(self._vrefUnit, 4, 5, 4, 5)
2662
2663 self._antiIceOn = gtk.CheckButton(xstr("landing_antiice"))
2664 self._antiIceOn.set_use_underline(True)
2665 self._antiIceOn.set_tooltip_text(xstr("landing_antiice_tooltip"))
2666 table.attach(self._antiIceOn, 3, 5, 5, 6)
[75]2667
[208]2668 self.addCancelFlightButton()
2669
[107]2670 self.addPreviousButton(clicked = self._backClicked)
2671
2672 self._button = self.addNextButton(clicked = self._forwardClicked)
[75]2673
[76]2674 # These are needed for correct size calculations
2675 self._starButton.set_active(True)
2676 self._transitionButton.set_active(True)
2677
[86]2678 @property
[97]2679 def star(self):
2680 """Get the STAR or None if none entered."""
2681 return self._star.get_text() if self._starButton.get_active() else None
2682
2683 @property
2684 def transition(self):
2685 """Get the transition or None if none entered."""
2686 return self._transition.get_text() \
2687 if self._transitionButton.get_active() else None
2688
2689 @property
2690 def approachType(self):
2691 """Get the approach type."""
2692 return self._approachType.get_text()
2693
2694 @property
2695 def runway(self):
2696 """Get the runway."""
2697 return self._runway.get_text()
2698
2699 @property
[86]2700 def vref(self):
2701 """Return the landing reference speed."""
2702 return self._vref.get_int()
2703
[391]2704 @property
2705 def antiIceOn(self):
2706 """Get whether the anti-ice system has been turned on."""
2707 return self._antiIceOn.get_active()
2708
2709 @antiIceOn.setter
2710 def antiIceOn(self, value):
2711 """Set the anti-ice indicator."""
2712 self._antiIceOn.set_active(value)
2713
[218]2714 def reset(self):
2715 """Reset the page if the wizard is reset."""
2716 super(LandingPage, self).reset()
[241]2717 self._vref.reset()
[391]2718 self._antiIceOn.set_active(False)
[218]2719 self._flightEnded = False
[347]2720
[75]2721 def activate(self):
2722 """Called when the page is activated."""
2723 self._starButton.set_sensitive(True)
2724 self._starButton.set_active(False)
2725 self._star.set_text("")
2726
2727 self._transitionButton.set_sensitive(True)
2728 self._transitionButton.set_active(False)
2729 self._transition.set_text("")
2730
2731 self._runway.set_text("")
2732 self._runway.set_sensitive(True)
2733
2734 self._approachType.set_text("")
2735 self._approachType.set_sensitive(True)
2736
[86]2737 self._vref.set_int(None)
[75]2738 self._vref.set_sensitive(True)
2739
[241]2740 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
2741 speedUnit = xstr("label" + i18nSpeedUnit)
2742 self._vrefUnit.set_text(speedUnit)
2743
2744 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip" +
2745 i18nSpeedUnit))
2746
[75]2747 self._updateForwardButton()
2748
[88]2749 def flightEnded(self):
2750 """Called when the flight has ended."""
[275]2751 super(LandingPage, self).flightEnded()
[88]2752 self._flightEnded = True
2753 self._updateForwardButton()
2754
[75]2755 def _starButtonClicked(self, button):
2756 """Called when the STAR button is clicked."""
2757 active = button.get_active()
2758 self._star.set_sensitive(active)
2759 if active:
2760 self._star.grab_focus()
2761 self._updateForwardButton()
2762
2763 def _transitionButtonClicked(self, button):
2764 """Called when the Transition button is clicked."""
2765 active = button.get_active()
2766 self._transition.set_sensitive(active)
2767 if active:
[347]2768 self._transition.grab_focus()
2769 self._updateForwardButton()
[75]2770
[138]2771 def _updateForwardButton(self):
[75]2772 """Update the sensitivity of the forward button."""
[88]2773 sensitive = self._flightEnded and \
2774 (self._starButton.get_active() or \
[75]2775 self._transitionButton.get_active()) and \
2776 (self._star.get_text()!="" or
2777 not self._starButton.get_active()) and \
2778 (self._transition.get_text()!="" or
2779 not self._transitionButton.get_active()) and \
2780 self._runway.get_text()!="" and \
[86]2781 self._approachType.get_text()!="" and \
2782 self.vref is not None
[75]2783 self._button.set_sensitive(sensitive)
2784
[138]2785 def _upperChanged(self, entry):
2786 """Called for entry widgets that must be converted to uppercase."""
2787 entry.set_text(entry.get_text().upper())
2788 self._updateForwardButton()
2789
[86]2790 def _vrefChanged(self, widget, value):
2791 """Called when the Vref has changed."""
2792 self._updateForwardButton()
2793
[75]2794 def _backClicked(self, button):
2795 """Called when the Back button is pressed."""
2796 self.goBack()
[347]2797
[75]2798 def _forwardClicked(self, button):
2799 """Called when the forward button is clicked."""
[391]2800 aircraft = self._wizard.gui.flight.aircraft
2801 aircraft.updateVRef()
2802 aircraft.updateLandingAntiIce()
[136]2803 if self._wizard.gui.config.onlineGateSystem and \
[215]2804 self._wizard.loggedIn and not self._completed and \
[184]2805 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
2806 not self._wizard.entranceExam:
[130]2807 self._wizard.getFleet(callback = self._fleetRetrieved,
2808 force = True)
2809 else:
2810 self._wizard.nextPage()
2811
2812 def _fleetRetrieved(self, fleet):
2813 """Callback for the fleet retrieval."""
[89]2814 self._wizard.nextPage()
2815
2816#-----------------------------------------------------------------------------
2817
2818class FinishPage(Page):
2819 """Flight finish page."""
[107]2820 _flightTypes = [ ("flighttype_scheduled", const.FLIGHTTYPE_SCHEDULED),
2821 ("flighttype_ot", const.FLIGHTTYPE_OLDTIMER),
2822 ("flighttype_vip", const.FLIGHTTYPE_VIP),
2823 ("flighttype_charter", const.FLIGHTTYPE_CHARTER) ]
[347]2824
[89]2825 def __init__(self, wizard):
2826 """Construct the finish page."""
[564]2827 help = xstr("finish_help") + xstr("finish_help_goodtime")
[563]2828 super(FinishPage, self).__init__(wizard, xstr("finish_title"), help)
[347]2829
[89]2830 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2831 xscale = 0.0, yscale = 0.0)
2832
[556]2833 table = gtk.Table(10, 2)
[89]2834 table.set_row_spacings(4)
2835 table.set_col_spacings(16)
[96]2836 table.set_homogeneous(False)
[89]2837 alignment.add(table)
2838 self.setMainWidget(alignment)
2839
[555]2840 row = 0
2841
[89]2842 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]2843 label = gtk.Label(xstr("finish_rating"))
[89]2844 labelAlignment.add(label)
[555]2845 table.attach(labelAlignment, 0, 1, row, row+1)
[89]2846
2847 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2848 self._flightRating = gtk.Label()
[154]2849 self._flightRating.set_width_chars(8)
[89]2850 self._flightRating.set_alignment(0.0, 0.5)
2851 self._flightRating.set_use_markup(True)
2852 labelAlignment.add(self._flightRating)
[555]2853 table.attach(labelAlignment, 1, 2, row, row+1)
2854
2855 row += 1
2856
2857 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2858 label = gtk.Label(xstr("finish_dep_time"))
2859 labelAlignment.add(label)
2860 table.attach(labelAlignment, 0, 1, row, row+1)
2861
2862 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2863 self._depTime = gtk.Label()
[556]2864 self._depTime.set_width_chars(13)
[555]2865 self._depTime.set_alignment(0.0, 0.5)
2866 self._depTime.set_use_markup(True)
[558]2867 self._depTime.set_tooltip_markup(xstr("finish_dep_time_tooltip"))
[555]2868 labelAlignment.add(self._depTime)
2869 table.attach(labelAlignment, 1, 2, row, row+1)
2870
2871 row += 1
[89]2872
2873 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]2874 label = gtk.Label(xstr("finish_flight_time"))
[89]2875 labelAlignment.add(label)
[555]2876 table.attach(labelAlignment, 0, 1, row, row+1)
[89]2877
2878 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2879 self._flightTime = gtk.Label()
2880 self._flightTime.set_width_chars(10)
2881 self._flightTime.set_alignment(0.0, 0.5)
2882 self._flightTime.set_use_markup(True)
2883 labelAlignment.add(self._flightTime)
[555]2884 table.attach(labelAlignment, 1, 2, row, row+1)
2885
2886 row += 1
[89]2887
2888 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]2889 label = gtk.Label(xstr("finish_block_time"))
[89]2890 labelAlignment.add(label)
[555]2891 table.attach(labelAlignment, 0, 1, row, row+1)
[89]2892
2893 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2894 self._blockTime = gtk.Label()
2895 self._blockTime.set_width_chars(10)
2896 self._blockTime.set_alignment(0.0, 0.5)
2897 self._blockTime.set_use_markup(True)
2898 labelAlignment.add(self._blockTime)
[555]2899 table.attach(labelAlignment, 1, 2, row, row+1)
2900
2901 row += 1
2902
2903 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2904 label = gtk.Label(xstr("finish_arr_time"))
2905 labelAlignment.add(label)
2906 table.attach(labelAlignment, 0, 1, row, row+1)
2907
2908 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2909 self._arrTime = gtk.Label()
[556]2910 self._arrTime.set_width_chars(13)
[555]2911 self._arrTime.set_alignment(0.0, 0.5)
2912 self._arrTime.set_use_markup(True)
[558]2913 self._arrTime.set_tooltip_markup(xstr("finish_arr_time_tooltip"))
[555]2914 labelAlignment.add(self._arrTime)
2915 table.attach(labelAlignment, 1, 2, row, row+1)
2916
2917 row += 1
[89]2918
2919 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]2920 label = gtk.Label(xstr("finish_distance"))
[89]2921 labelAlignment.add(label)
[555]2922 table.attach(labelAlignment, 0, 1, row, row+1)
[89]2923
2924 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2925 self._distanceFlown = gtk.Label()
2926 self._distanceFlown.set_width_chars(10)
2927 self._distanceFlown.set_alignment(0.0, 0.5)
2928 self._distanceFlown.set_use_markup(True)
2929 labelAlignment.add(self._distanceFlown)
[555]2930 table.attach(labelAlignment, 1, 2, row, row+1)
2931
2932 row += 1
[347]2933
[89]2934 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
[107]2935 label = gtk.Label(xstr("finish_fuel"))
[89]2936 labelAlignment.add(label)
[555]2937 table.attach(labelAlignment, 0, 1, row, row+1)
[89]2938
2939 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2940 self._fuelUsed = gtk.Label()
2941 self._fuelUsed.set_width_chars(10)
2942 self._fuelUsed.set_alignment(0.0, 0.5)
2943 self._fuelUsed.set_use_markup(True)
2944 labelAlignment.add(self._fuelUsed)
[555]2945 table.attach(labelAlignment, 1, 2, row, row+1)
2946
2947 row += 1
[89]2948
[107]2949 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
2950 yalign = 0.5, yscale = 0.0)
2951 label = gtk.Label(xstr("finish_type"))
[96]2952 label.set_use_underline(True)
2953 labelAlignment.add(label)
[555]2954 table.attach(labelAlignment, 0, 1, row, row+1)
[96]2955
2956 flightTypeModel = gtk.ListStore(str, int)
[97]2957 for (name, type) in FinishPage._flightTypes:
[107]2958 flightTypeModel.append([xstr(name), type])
[96]2959
2960 self._flightType = gtk.ComboBox(model = flightTypeModel)
2961 renderer = gtk.CellRendererText()
2962 self._flightType.pack_start(renderer, True)
2963 self._flightType.add_attribute(renderer, "text", 0)
[107]2964 self._flightType.set_tooltip_text(xstr("finish_type_tooltip"))
[96]2965 self._flightType.set_active(0)
2966 self._flightType.connect("changed", self._flightTypeChanged)
2967 flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2968 flightTypeAlignment.add(self._flightType)
[555]2969 table.attach(flightTypeAlignment, 1, 2, row, row+1)
[347]2970 label.set_mnemonic_widget(self._flightType)
[96]2971
[555]2972 row += 1
2973
[107]2974 self._onlineFlight = gtk.CheckButton(xstr("finish_online"))
[96]2975 self._onlineFlight.set_use_underline(True)
[107]2976 self._onlineFlight.set_tooltip_text(xstr("finish_online_tooltip"))
[96]2977 onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2978 onlineFlightAlignment.add(self._onlineFlight)
[555]2979 table.attach(onlineFlightAlignment, 1, 2, row, row + 1)
2980
2981 row += 1
[96]2982
[130]2983 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
2984 yalign = 0.5, yscale = 0.0)
2985 self._gateLabel = gtk.Label(xstr("finish_gate"))
2986 self._gateLabel.set_use_underline(True)
2987 labelAlignment.add(self._gateLabel)
[555]2988 table.attach(labelAlignment, 0, 1, row, row+1)
[130]2989
2990 self._gatesModel = gtk.ListStore(str)
2991
2992 self._gate = gtk.ComboBox(model = self._gatesModel)
2993 renderer = gtk.CellRendererText()
2994 self._gate.pack_start(renderer, True)
2995 self._gate.add_attribute(renderer, "text", 0)
2996 self._gate.set_tooltip_text(xstr("finish_gate_tooltip"))
[347]2997 self._gate.connect("changed", self._gateChanged)
[130]2998 gateAlignment = gtk.Alignment(xalign=0.0, xscale=1.0)
2999 gateAlignment.add(self._gate)
[555]3000 table.attach(gateAlignment, 1, 2, row, row+1)
[130]3001 self._gateLabel.set_mnemonic_widget(self._gate)
3002
[208]3003 self.addButton(xstr("finish_newFlight"),
3004 sensitive = True,
3005 clicked = self._newFlightClicked,
3006 tooltip = xstr("finish_newFlight_tooltip"),
3007 padding = 16)
3008
[107]3009 self.addPreviousButton(clicked = self._backClicked)
[94]3010
[107]3011 self._saveButton = self.addButton(xstr("finish_save"),
3012 sensitive = False,
[151]3013 clicked = self._saveClicked,
3014 tooltip = xstr("finish_save_tooltip"))
3015 self._savePIREPDialog = None
3016 self._lastSavePath = None
[208]3017
[555]3018 self._tooBigTimeDifference = False
3019 self._deferredAutoSave = False
[208]3020 self._pirepSaved = False
3021 self._pirepSent = False
[347]3022
[151]3023 self._sendButton = self.addButton(xstr("sendPIREP"), default = True,
[107]3024 sensitive = False,
3025 clicked = self._sendClicked,
[151]3026 tooltip = xstr("sendPIREP_tooltip"))
[347]3027
[555]3028 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), 10*60.0)
3029 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), 20*60.0)
3030 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), 0*60.0)
3031 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), (23*60.0+50)*60.0)
3032 # self._formatTime(datetime.datetime(1970, 1, 1, 1, 0), (1*60.0+5)*60.0)
3033 # self._formatTime(datetime.datetime(1970, 1, 1, 1, 0), (0*60.0+50)*60.0)
3034 # self._formatTime(datetime.datetime(1970, 1, 1, 23, 55), (0*60.0+5)*60.0)
3035 # self._formatTime(datetime.datetime(1970, 1, 1, 23, 55), (23*60.0+45)*60.0)
3036
[97]3037 @property
3038 def flightType(self):
3039 """Get the flight type."""
3040 index = self._flightType.get_active()
3041 return None if index<0 else self._flightType.get_model()[index][1]
3042
3043 @property
3044 def online(self):
3045 """Get whether the flight was an online flight or not."""
3046 return self._onlineFlight.get_active()
[89]3047
3048 def activate(self):
3049 """Activate the page."""
[555]3050 self._deferredAutoSave = False
[208]3051 self._pirepSaved = False
3052 self._pirepSent = False
3053
[89]3054 flight = self._wizard.gui._flight
3055 rating = flight.logger.getRating()
3056 if rating<0:
3057 self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
3058 else:
3059 self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
3060
3061 flightLength = flight.flightTimeEnd - flight.flightTimeStart
3062 self._flightTime.set_markup("<b>%s</b>" % \
3063 (util.getTimeIntervalString(flightLength),))
[347]3064
[89]3065 blockLength = flight.blockTimeEnd - flight.blockTimeStart
3066 self._blockTime.set_markup("<b>%s</b>" % \
3067 (util.getTimeIntervalString(blockLength),))
3068
3069 self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
3070 (flight.flownDistance,))
[347]3071
[89]3072 self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
[102]3073 (flight.startFuel - flight.endFuel,))
[64]3074
[96]3075 self._flightType.set_active(-1)
[215]3076 self._onlineFlight.set_active(self._wizard.loggedIn)
[96]3077
[130]3078 self._gatesModel.clear()
[136]3079 if self._wizard.gui.config.onlineGateSystem and \
[215]3080 self._wizard.loggedIn and \
[184]3081 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
3082 not self._wizard.entranceExam:
[130]3083 occupiedGates = self._wizard._fleet.getOccupiedGateNumbers()
3084 for gateNumber in const.lhbpGateNumbers:
3085 if gateNumber not in occupiedGates:
3086 self._gatesModel.append([gateNumber])
3087 self._gateLabel.set_sensitive(True)
3088 self._gate.set_sensitive(True)
3089 self._gate.set_active(-1)
3090 else:
3091 self._gateLabel.set_sensitive(False)
3092 self._gate.set_sensitive(False)
3093
[564]3094 self._updateTimes()
[555]3095
3096 def updateButtons(self):
[130]3097 """Update the sensitivity state of the buttons."""
[555]3098 gui = self._wizard.gui
[130]3099 sensitive = self._flightType.get_active()>=0 and \
3100 (self._gatesModel.get_iter_first() is None or
[555]3101 self._gate.get_active()>=0) and \
3102 (not self._tooBigTimeDifference or
3103 gui.hasComments or gui.hasDelayCode)
[347]3104
[393]3105 wasSensitive = self._saveButton.get_sensitive()
3106
[555]3107 if gui.config.pirepAutoSave and sensitive and not wasSensitive:
3108 if gui.isWizardActive():
3109 self._autoSavePIREP()
3110 else:
3111 self._deferredAutoSave = True
3112
3113 if not sensitive:
3114 self._deferredAutoSave = False
[393]3115
[151]3116 self._saveButton.set_sensitive(sensitive)
[184]3117 self._sendButton.set_sensitive(sensitive and
3118 self._wizard.bookedFlight.id is not None)
[130]3119
[555]3120 def grabDefault(self):
3121 """If the page has a default button, make it the default one."""
3122 super(FinishPage, self).grabDefault()
3123 if self._deferredAutoSave:
3124 self._autoSavePIREP()
3125 self._deferredAutoSave = False
3126
3127 def _autoSavePIREP(self):
3128 """Perform the automatic saving of the PIREP."""
3129 self._lastSavePath = os.path.join(self._wizard.gui.config.pirepDirectory,
3130 self._getDefaultPIREPName())
3131 self._lastSavePath = text2unicode(self._lastSavePath)
3132 self._savePIREP(automatic = True)
3133
3134 def _backClicked(self, button):
3135 """Called when the Back button is pressed."""
3136 self.goBack()
3137
[96]3138 def _flightTypeChanged(self, comboBox):
3139 """Called when the flight type has changed."""
[564]3140 self._updateTimes()
[130]3141
3142 def _gateChanged(self, comboBox):
3143 """Called when the arrival gate has changed."""
[555]3144 self.updateButtons()
[97]3145
[208]3146 def _newFlightClicked(self, button):
3147 """Called when the new flight button is clicked."""
3148 gui = self._wizard.gui
3149 if not self._pirepSent and not self._pirepSaved:
3150 dialog = gtk.MessageDialog(parent = gui.mainWindow,
3151 type = MESSAGETYPE_QUESTION,
3152 message_format = xstr("finish_newFlight_question"))
3153
3154 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
3155 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
3156
3157 dialog.set_title(WINDOW_TITLE_BASE)
3158 result = dialog.run()
3159 dialog.hide()
3160 if result!=RESPONSETYPE_YES:
3161 return
[347]3162
[208]3163 gui.reset()
3164
[393]3165 def _getDefaultPIREPName(self):
3166 """Get the default name of the PIREP."""
[151]3167 gui = self._wizard.gui
3168
3169 bookedFlight = gui.bookedFlight
3170 tm = time.gmtime()
[215]3171
3172 pilotID = self._wizard.pilotID
3173 if pilotID: pilotID += " "
[393]3174 return "%s%s %02d%02d %s-%s.pirep" % \
3175 (pilotID, str(bookedFlight.departureTime.date()),
3176 tm.tm_hour, tm.tm_min,
3177 bookedFlight.departureICAO, bookedFlight.arrivalICAO)
3178
3179
3180 def _saveClicked(self, button):
3181 """Called when the Save PIREP button is clicked."""
3182 gui = self._wizard.gui
3183
3184 fileName = self._getDefaultPIREPName()
[151]3185
3186 dialog = self._getSaveDialog()
3187
3188 if self._lastSavePath is None:
3189 pirepDirectory = gui.config.pirepDirectory
3190 if pirepDirectory is not None:
3191 dialog.set_current_folder(pirepDirectory)
3192 else:
3193 dialog.set_current_folder(os.path.dirname(self._lastSavePath))
[347]3194
[151]3195 dialog.set_current_name(fileName)
3196 result = dialog.run()
3197 dialog.hide()
3198
3199 if result==RESPONSETYPE_OK:
[164]3200 self._lastSavePath = text2unicode(dialog.get_filename())
[393]3201 self._savePIREP()
3202
3203 def _savePIREP(self, automatic = False):
3204 """Perform the saving of the PIREP."""
3205
3206 gui = self._wizard.gui
3207
3208 if automatic:
3209 gui.beginBusy(xstr("finish_autosave_busy"))
3210
3211 pirep = PIREP(gui.flight)
3212 error = pirep.save(self._lastSavePath)
3213
3214 if automatic:
3215 gui.endBusy()
3216
3217 if error:
3218 type = MESSAGETYPE_ERROR
3219 message = xstr("finish_save_failed")
3220 secondary = xstr("finish_save_failed_sec") % (text2unicode(error),)
3221 else:
3222 type = MESSAGETYPE_INFO
3223 message = xstr("finish_save_done")
3224 if automatic:
3225 secondary = xstr("finish_save_done_sec") % (self._lastSavePath,)
[151]3226 else:
[393]3227 secondary = None
3228 self._pirepSaved = True
3229
3230 dialog = gtk.MessageDialog(parent = gui.mainWindow,
3231 type = type, message_format = message)
3232 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3233 dialog.set_title(WINDOW_TITLE_BASE)
3234 if secondary is not None:
3235 dialog.format_secondary_markup(secondary)
3236
3237 dialog.run()
3238 dialog.hide()
[151]3239
3240 def _getSaveDialog(self):
3241 """Get the PIREP saving dialog.
3242
3243 If it does not exist yet, create it."""
3244 if self._savePIREPDialog is None:
3245 gui = self._wizard.gui
3246 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
3247 xstr("finish_save_title"),
3248 action = FILE_CHOOSER_ACTION_SAVE,
3249 buttons = (gtk.STOCK_CANCEL,
3250 RESPONSETYPE_CANCEL,
3251 gtk.STOCK_OK, RESPONSETYPE_OK),
3252 parent = gui.mainWindow)
3253 dialog.set_modal(True)
3254 dialog.set_do_overwrite_confirmation(True)
[347]3255
[151]3256 filter = gtk.FileFilter()
[184]3257 filter.set_name(xstr("file_filter_pireps"))
[151]3258 filter.add_pattern("*.pirep")
3259 dialog.add_filter(filter)
[347]3260
[151]3261 filter = gtk.FileFilter()
[184]3262 filter.set_name(xstr("file_filter_all"))
[151]3263 filter.add_pattern("*.*")
3264 dialog.add_filter(filter)
3265
3266 self._savePIREPDialog = dialog
3267
3268 return self._savePIREPDialog
[347]3269
[151]3270
[97]3271 def _sendClicked(self, button):
3272 """Called when the Send button is clicked."""
[262]3273 pirep = PIREP(self._wizard.gui.flight)
[151]3274 self._wizard.gui.sendPIREP(pirep,
3275 callback = self._handlePIREPSent)
[97]3276
3277 def _handlePIREPSent(self, returned, result):
3278 """Callback for the PIREP sending result."""
[208]3279 self._pirepSent = returned and result.success
[184]3280 if self._wizard.gui.config.onlineGateSystem and \
[215]3281 self._wizard.loggedIn and not self._wizard.entranceExam and \
[184]3282 returned and result.success:
[130]3283 bookedFlight = self._wizard.bookedFlight
3284 if bookedFlight.arrivalICAO=="LHBP":
[347]3285 iter = self._gate.get_active_iter()
[130]3286 gateNumber = None if iter is None \
3287 else self._gatesModel.get_value(iter, 0)
[347]3288
[130]3289 status = const.PLANE_PARKING if gateNumber is None \
3290 else const.PLANE_HOME
3291 else:
3292 gateNumber = None
3293 status = const.PLANE_AWAY
3294
3295 self._wizard.updatePlane(self._planeUpdated,
3296 bookedFlight.tailNumber,
3297 status, gateNumber = gateNumber)
3298
3299 def _planeUpdated(self, success):
3300 """Callback for the plane updating."""
3301 pass
[347]3302
[564]3303 def _formatTime(self, scheduledTime, realTimestamp, (warning, error)):
[555]3304 """Format the departure or arrival time based on the given data as a
[564]3305 markup for a label."""
[555]3306 realTime = time.gmtime(realTimestamp)
3307
[564]3308 if warning:
3309 colour = "red" if error else "orange"
[555]3310 markupBegin = '<span foreground="%s">' % (colour,)
3311 markupEnd = '</span>'
3312 else:
3313 markupBegin = markupEnd = ""
3314
3315 markup = "<b>%s%02d:%02d [%02d:%02d]%s</b>" % \
3316 (markupBegin,
3317 realTime.tm_hour, realTime.tm_min,
3318 scheduledTime.hour, scheduledTime.minute,
3319 markupEnd)
3320
[564]3321 return markup
3322
3323 def _updateTimes(self):
3324 """Format the flight times and the help text according to the flight
3325 type.
3326
3327 The buttons are also updated.
3328 """
3329 flight = self._wizard.gui._flight
3330 bookedFlight = flight.bookedFlight
3331
3332 (departureWarning, departureError) = flight.blockTimeStartWrong
3333 (arrivalWarning, arrivalError) = flight.blockTimeEndWrong
3334
3335 if self.flightType==const.FLIGHTTYPE_VIP:
3336 departureError = arrivalError = False
3337
3338 self._tooBigTimeDifference = departureError or arrivalError
3339
3340 if self._tooBigTimeDifference and self.flightType is not None:
3341 self.setHelp(xstr("finish_help") + xstr("finish_help_wrongtime"))
3342 else:
3343 self.setHelp(xstr("finish_help") + xstr("finish_help_goodtime"))
3344
3345 self._depTime.set_markup(self._formatTime(bookedFlight.departureTime,
3346 flight.blockTimeStart,
3347 (departureWarning,
3348 departureError)))
3349
3350 self._arrTime.set_markup(self._formatTime(bookedFlight.arrivalTime,
3351 flight.blockTimeEnd,
3352 (arrivalWarning,
3353 arrivalError)))
3354
3355 self.updateButtons()
[555]3356
[64]3357#-----------------------------------------------------------------------------
3358
[42]3359class Wizard(gtk.VBox):
3360 """The flight wizard."""
3361 def __init__(self, gui):
3362 """Construct the wizard."""
3363 super(Wizard, self).__init__()
3364
3365 self.gui = gui
3366
3367 self._pages = []
3368 self._currentPage = None
[184]3369
3370 self._loginPage = LoginPage(self)
3371 self._pages.append(self._loginPage)
[42]3372 self._pages.append(FlightSelectionPage(self))
[51]3373 self._pages.append(GateSelectionPage(self))
3374 self._pages.append(ConnectPage(self))
[347]3375 self._payloadPage = PayloadPage(self)
[84]3376 self._pages.append(self._payloadPage)
[117]3377 self._payloadIndex = len(self._pages)
[61]3378 self._pages.append(TimePage(self))
[141]3379 self._pages.append(FuelPage(self))
[84]3380 self._routePage = RoutePage(self)
3381 self._pages.append(self._routePage)
[97]3382 self._departureBriefingPage = BriefingPage(self, True)
3383 self._pages.append(self._departureBriefingPage)
3384 self._arrivalBriefingPage = BriefingPage(self, False)
3385 self._pages.append(self._arrivalBriefingPage)
[117]3386 self._arrivalBriefingIndex = len(self._pages)
[347]3387 self._takeoffPage = TakeoffPage(self)
[84]3388 self._pages.append(self._takeoffPage)
[383]3389 self._cruisePage = CruisePage(self)
3390 self._pages.append(self._cruisePage)
[347]3391 self._landingPage = LandingPage(self)
[86]3392 self._pages.append(self._landingPage)
[97]3393 self._finishPage = FinishPage(self)
3394 self._pages.append(self._finishPage)
[201]3395
[556]3396 self._requestedWidth = None
3397 self._requestedHeight = None
3398
3399 self.connect("size-allocate", self._sizeAllocate)
3400
3401 for page in self._pages:
3402 page.show_all()
3403 page.setStyle()
3404
3405 self._initialize()
3406
3407 def _sizeAllocate(self, widget, allocation):
3408 if self._requestedWidth is not None and \
3409 self._requestedHeight is not None:
3410 return
3411
3412 if self._currentPage is not None:
3413 self.remove(self._pages[self._currentPage])
3414
[51]3415 maxWidth = 0
3416 maxHeight = 0
3417 for page in self._pages:
[556]3418 self.add(page)
3419 self.show_all()
[51]3420 pageSizeRequest = page.size_request()
3421 width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
3422 height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
3423 maxWidth = max(maxWidth, width)
3424 maxHeight = max(maxHeight, height)
[556]3425 self.remove(page)
3426
3427 if self._currentPage is not None:
3428 self.add(self._pages[self._currentPage])
3429
3430 self._requestedWidth = maxWidth
3431 self._requestedHeight = maxHeight
[51]3432 self.set_size_request(maxWidth, maxHeight)
3433
[184]3434 @property
[215]3435 def pilotID(self):
3436 """Get the pilot ID, if given."""
3437 return self._loginPage.pilotID
3438
3439 @property
[184]3440 def entranceExam(self):
3441 """Get whether an entrance exam is about to be taken."""
3442 return self._loginPage.entranceExam
[215]3443
3444 @property
3445 def loggedIn(self):
3446 """Indicate if there was a successful login."""
3447 return self._loginResult is not None
[347]3448
[48]3449 @property
3450 def loginResult(self):
3451 """Get the login result."""
3452 return self._loginResult
3453
[70]3454 def setCurrentPage(self, index, finalize = False):
[42]3455 """Set the current page to the one with the given index."""
3456 assert index < len(self._pages)
[70]3457
3458 fromPage = self._currentPage
3459 if fromPage is not None:
3460 page = self._pages[fromPage]
[94]3461 if finalize and not page._completed:
3462 page.complete()
[70]3463 self.remove(page)
[42]3464
3465 self._currentPage = index
[70]3466 page = self._pages[index]
3467 self.add(page)
3468 if page._fromPage is None:
3469 page._fromPage = fromPage
[94]3470 page.initialize()
[42]3471 self.show_all()
[72]3472 if fromPage is not None:
3473 self.grabDefault()
[42]3474
[84]3475 @property
[97]3476 def bookedFlight(self):
3477 """Get the booked flight selected."""
3478 return self._bookedFlight
3479
3480 @property
[303]3481 def numCrew(self):
3482 """Get the number of crew members."""
3483 return self._payloadPage.numCrew
3484
3485 @property
3486 def numPassengers(self):
3487 """Get the number of passengers."""
3488 return self._payloadPage.numPassengers
3489
3490 @property
3491 def bagWeight(self):
3492 """Get the baggage weight."""
3493 return self._payloadPage.bagWeight
3494
3495 @property
[97]3496 def cargoWeight(self):
[303]3497 """Get the cargo weight."""
[97]3498 return self._payloadPage.cargoWeight
3499
3500 @property
[303]3501 def mailWeight(self):
3502 """Get the mail weight."""
3503 return self._payloadPage.mailWeight
3504
3505 @property
[84]3506 def zfw(self):
3507 """Get the calculated ZFW value."""
3508 return 0 if self._bookedFlight is None \
3509 else self._payloadPage.calculateZFW()
3510
3511 @property
[383]3512 def filedCruiseLevel(self):
3513 """Get the filed cruise level."""
3514 return self._routePage.filedCruiseLevel
3515
3516 @property
[97]3517 def filedCruiseAltitude(self):
3518 """Get the filed cruise altitude."""
3519 return self._routePage.filedCruiseLevel * 100
3520
3521 @property
[84]3522 def cruiseAltitude(self):
3523 """Get the cruise altitude."""
[383]3524 level = self._cruisePage.cruiseLevel if self._cruisePage.activated \
3525 else self._routePage.filedCruiseLevel
3526 return level * 100
3527
3528 @property
3529 def loggableCruiseAltitude(self):
3530 """Get the cruise altitude that can be logged."""
3531 if self._cruisePage.activated:
3532 return self._cruisePage.loggableCruiseLevel * 100
3533 else:
3534 return 0
[84]3535
3536 @property
[97]3537 def route(self):
3538 """Get the route."""
3539 return self._routePage.route
3540
3541 @property
3542 def departureMETAR(self):
3543 """Get the METAR of the departure airport."""
3544 return self._departureBriefingPage.metar
3545
3546 @property
3547 def arrivalMETAR(self):
3548 """Get the METAR of the arrival airport."""
3549 return self._arrivalBriefingPage.metar
3550
3551 @property
3552 def departureRunway(self):
3553 """Get the departure runway."""
3554 return self._takeoffPage.runway
3555
3556 @property
3557 def sid(self):
3558 """Get the SID."""
3559 return self._takeoffPage.sid
3560
3561 @property
[84]3562 def v1(self):
3563 """Get the V1 speed."""
[86]3564 return self._takeoffPage.v1
[84]3565
3566 @property
3567 def vr(self):
3568 """Get the Vr speed."""
[86]3569 return self._takeoffPage.vr
[84]3570
3571 @property
3572 def v2(self):
3573 """Get the V2 speed."""
[86]3574 return self._takeoffPage.v2
3575
3576 @property
[384]3577 def derate(self):
3578 """Get the derate value."""
3579 return self._takeoffPage.derate
3580
3581 @property
[391]3582 def takeoffAntiIceOn(self):
3583 """Get whether the anti-ice system was on during take-off."""
3584 return self._takeoffPage.antiIceOn
3585
3586 @takeoffAntiIceOn.setter
3587 def takeoffAntiIceOn(self, value):
3588 """Set anti-ice on indicator."""
3589 self._takeoffPage.antiIceOn = value
3590
3591 @property
[349]3592 def rtoIndicated(self):
3593 """Get whether the pilot has indicated that an RTO has occured."""
3594 return self._takeoffPage.rtoIndicated
3595
3596 @property
[97]3597 def arrivalRunway(self):
3598 """Get the arrival runway."""
3599 return self._landingPage.runway
3600
3601 @property
3602 def star(self):
3603 """Get the STAR."""
3604 return self._landingPage.star
3605
3606 @property
3607 def transition(self):
3608 """Get the transition."""
3609 return self._landingPage.transition
3610
3611 @property
3612 def approachType(self):
3613 """Get the approach type."""
3614 return self._landingPage.approachType
3615
3616 @property
[86]3617 def vref(self):
3618 """Get the Vref speed."""
3619 return self._landingPage.vref
[84]3620
[97]3621 @property
[391]3622 def landingAntiIceOn(self):
3623 """Get whether the anti-ice system was on during landing."""
3624 return self._landingPage.antiIceOn
3625
3626 @landingAntiIceOn.setter
3627 def landingAntiIceOn(self, value):
3628 """Set anti-ice on indicator."""
3629 self._landingPage.antiIceOn = value
3630
3631 @property
[97]3632 def flightType(self):
3633 """Get the flight type."""
3634 return self._finishPage.flightType
3635
3636 @property
3637 def online(self):
3638 """Get whether the flight was online or not."""
3639 return self._finishPage.online
3640
[70]3641 def nextPage(self, finalize = True):
[42]3642 """Go to the next page."""
[70]3643 self.jumpPage(1, finalize)
[51]3644
[70]3645 def jumpPage(self, count, finalize = True):
[51]3646 """Go to the page which is 'count' pages after the current one."""
[70]3647 self.setCurrentPage(self._currentPage + count, finalize = finalize)
[46]3648
3649 def grabDefault(self):
3650 """Make the default button of the current page the default."""
3651 self._pages[self._currentPage].grabDefault()
[51]3652
[59]3653 def connected(self, fsType, descriptor):
3654 """Called when the connection could be made to the simulator."""
3655 self.nextPage()
3656
[208]3657 def reset(self, loginResult):
[91]3658 """Resets the wizard to go back to the login page."""
[208]3659 self._initialize(keepLoginResult = loginResult is None,
3660 loginResult = loginResult)
[59]3661
[84]3662 def setStage(self, stage):
3663 """Set the flight stage to the given one."""
[383]3664 if stage!=const.STAGE_END:
3665 self._cruisePage.setLoggable(Flight.canLogCruiseAltitude(stage))
3666
[84]3667 if stage==const.STAGE_TAKEOFF:
[101]3668 self._takeoffPage.allowForward()
[106]3669 elif stage==const.STAGE_LANDING:
3670 if not self._arrivalBriefingPage.metarEdited:
3671 print "Downloading arrival METAR again"
3672 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
3673 [self._bookedFlight.arrivalICAO])
[347]3674
[88]3675 elif stage==const.STAGE_END:
[275]3676 for page in self._pages:
3677 page.flightEnded()
[84]3678
[208]3679 def _initialize(self, keepLoginResult = False, loginResult = None):
[59]3680 """Initialize the wizard."""
[208]3681 if not keepLoginResult:
3682 self._loginResult = loginResult
3683
3684 self._loginCallback = None
3685
[59]3686 self._fleet = None
3687 self._fleetCallback = None
[347]3688
[59]3689 self._bookedFlight = None
3690 self._departureGate = "-"
[141]3691 self._fuelData = None
[64]3692 self._departureNOTAMs = None
[67]3693 self._departureMETAR = None
[64]3694 self._arrivalNOTAMs = None
[67]3695 self._arrivalMETAR = None
3696
[208]3697 firstPage = 0 if self._loginResult is None else 1
3698 for page in self._pages[firstPage:]:
[67]3699 page.reset()
[347]3700
[208]3701 self.setCurrentPage(firstPage)
[563]3702 #self.setCurrentPage(13)
[208]3703
3704 def login(self, callback, pilotID, password, entranceExam):
3705 """Called when the login button was clicked."""
3706 self._loginCallback = callback
3707 if pilotID is None:
3708 loginResult = self._loginResult
3709 assert loginResult is not None and loginResult.loggedIn
3710 pilotID = loginResult.pilotID
3711 password = loginResult.password
3712 entranceExam = loginResult.entranceExam
3713 busyMessage = xstr("reload_busy")
3714 else:
3715 self._loginResult = None
3716 busyMessage = xstr("login_busy")
3717
3718 self.gui.beginBusy(busyMessage)
[347]3719
[208]3720 self.gui.webHandler.login(self._loginResultCallback,
3721 pilotID, password,
3722 entranceExam = entranceExam)
3723
3724 def reloadFlights(self, callback):
3725 """Reload the flights from the MAVA server."""
3726 self.login(callback, None, None, None)
3727
[304]3728 def cruiseLevelChanged(self):
3729 """Called when the cruise level is changed."""
[383]3730 return self.gui.cruiseLevelChanged()
[304]3731
[208]3732 def _loginResultCallback(self, returned, result):
3733 """The login result callback, called in the web handler's thread."""
3734 gobject.idle_add(self._handleLoginResult, returned, result)
3735
3736 def _handleLoginResult(self, returned, result):
3737 """Handle the login result."""
3738 self.gui.endBusy()
[555]3739 returned = True
[208]3740 isReload = self._loginResult is not None
3741 if returned:
3742 if result.loggedIn:
3743 self._loginResult = result
3744 else:
3745 if isReload:
3746 message = xstr("reload_failed")
3747 else:
3748 message = xstr("login_entranceExam_invalid"
3749 if self.entranceExam else
3750 xstr("login_invalid"))
3751 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
3752 type = MESSAGETYPE_ERROR,
3753 message_format = message)
3754 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3755 dialog.set_title(WINDOW_TITLE_BASE)
3756 if isReload:
3757 secondary = xstr("reload_failed_sec")
3758 else:
3759 secondary = xstr("login_entranceExam_invalid_sec"
3760 if self.entranceExam else
3761 xstr("login_invalid_sec"))
3762 dialog.format_secondary_markup(secondary)
3763 dialog.run()
3764 dialog.hide()
3765 else:
3766 message = xstr("reload_failconn") if isReload \
3767 else xstr("login_failconn")
3768 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
3769 type = MESSAGETYPE_ERROR,
3770 message_format = message)
3771 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3772 dialog.set_title(WINDOW_TITLE_BASE)
3773 secondary = xstr("reload_failconn_sec") if isReload \
3774 else xstr("login_failconn_sec")
3775 dialog.format_secondary_markup(secondary)
[347]3776
[208]3777 dialog.run()
3778 dialog.hide()
3779
3780 callback = self._loginCallback
3781 self._loginCallback = None
3782 callback(returned, result)
[126]3783
[130]3784 def getFleet(self, callback, force = False):
[126]3785 """Get the fleet via the GUI and call the given callback."""
3786 self._fleetCallback = callback
[130]3787 self.gui.getFleet(callback = self._fleetRetrieved, force = force)
[126]3788
3789 def _fleetRetrieved(self, fleet):
3790 """Callback for the fleet retrieval."""
3791 self._fleet = fleet
3792 if self._fleetCallback is not None:
3793 self._fleetCallback(fleet)
3794 self._fleetCallback = None
[347]3795
[130]3796 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
[51]3797 """Update the given plane's gate information."""
[130]3798 self.gui.updatePlane(tailNumber, status, gateNumber = gateNumber,
3799 callback = callback)
[51]3800
[349]3801 def updateRTO(self):
3802 """Update the RTO state.
3803
3804 The RTO checkbox will be enabled if the flight has an RTO state and the
3805 comments field contains some text."""
3806 flight = self.gui.flight
3807 rtoEnabled = flight is not None and flight.hasRTO and \
3808 self.gui.hasComments
3809 self._takeoffPage.setRTOEnabled(rtoEnabled)
3810
[555]3811 def commentsChanged(self):
3812 """Called when the comments have changed."""
3813 self.updateRTO()
3814 self._finishPage.updateButtons()
3815
3816 def delayCodesChanged(self):
3817 """Called when the delay codes have changed."""
3818 self._finishPage.updateButtons()
3819
[349]3820 def rtoToggled(self, indicated):
3821 """Called when the RTO indication has changed."""
3822 self.gui.rtoToggled(indicated)
3823
[501]3824 def _connectSimulator(self, simulatorType):
[51]3825 """Connect to the simulator."""
[501]3826 self.gui.connectSimulator(self._bookedFlight.aircraftType,
3827 simulatorType)
[106]3828
3829 def _arrivalMETARCallback(self, returned, result):
3830 """Called when the METAR of the arrival airport is retrieved."""
3831 gobject.idle_add(self._handleArrivalMETAR, returned, result)
[347]3832
[106]3833 def _handleArrivalMETAR(self, returned, result):
3834 """Called when the METAR of the arrival airport is retrieved."""
3835 icao = self._bookedFlight.arrivalICAO
3836 if returned and icao in result.metars:
3837 metar = result.metars[icao]
3838 if metar!="":
3839 self._arrivalBriefingPage.setMETAR(metar)
[347]3840
[42]3841#-----------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.