source: src/mlx/gui/flight.py@ 821:158bfb360027

Last change on this file since 821:158bfb360027 was 821:158bfb360027, checked in by István Váradi <ivaradi@…>, 8 years ago

A flight can be marked for reflying (re #307).

File size: 212.1 KB
Line 
1
2from mlx.gui.common import *
3import mlx.gui.cef as cef
4from mlx.gui.flightlist import ColumnDescriptor, FlightList, PendingFlightsWindow
5
6import mlx.const as const
7import mlx.fs as fs
8import mlx.acft as acft
9from mlx.flight import Flight
10from mlx.checks import PayloadChecker
11from mlx.gates import lhbpGates
12import mlx.util as util
13from mlx.pirep import PIREP
14from mlx.i18n import xstr, getLanguage
15from mlx.sound import startSound
16import mlx.web as web
17
18import datetime
19import time
20import os
21import tempfile
22import threading
23import re
24import webbrowser
25
26#-----------------------------------------------------------------------------
27
28## @package mlx.gui.flight
29#
30# The flight "wizard".
31#
32# This module implements the main tab of the application, the flight
33# wizard. The wizard consists of \ref Page "pages", that come one after the
34# other. As some pages might be skipped, the pages dynamically store the index
35# of the previous page so that going back to it is simpler. The \ref
36# Page.activate "activate" function is called before a page is first shown
37# during a flight. This function should initialize the page's controls and fill
38# it with initial data. When a page is left for the first time, its \ref
39# Page.finalize "finalize" function is called. It should set those controls
40# insensitive, that will not be available if the user comes back to this page.
41#
42# Each page has a title at the top displayed in inverted colors and a big
43# font. There is a help text below it centered, that shortly describes what is
44# expected on the page. There can be two help texts: one shown when the page is
45# first displayed during a flight, another shown when the user goes back to the
46# page. The main content area is below this, also centered. Finally, there are
47# some buttons at the bottom on the right. As some buttons occur very
48# frequently, there are functions to add them (\ref Page.addCancelFlightButton
49# "addCancelFlightButton", \ref Page.addPreviousButton "addPreviousButton" and
50# \ref Page.addNextButton "addNextButton".
51#
52# The \ref Wizard class is the main class to collect the pages. It also stores
53# some data passed from one page to another and provides properties to access
54# data items set via the wizard pages.
55
56#-----------------------------------------------------------------------------
57
58comboModel = gtk.ListStore(gobject.TYPE_STRING)
59comboModel.append(("N/A",))
60comboModel.append(("VECTORS",))
61
62#-----------------------------------------------------------------------------
63
64class Page(gtk.Alignment):
65 """A page in the flight wizard."""
66 def __init__(self, wizard, id, title, help, completedHelp = None):
67 """Construct the page."""
68 super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
69 xscale = 1.0, yscale = 1.0)
70 self.set_padding(padding_top = 4, padding_bottom = 4,
71 padding_left = 12, padding_right = 12)
72
73 frame = gtk.Frame()
74 self.add(frame)
75
76 self._vbox = gtk.VBox()
77 self._vbox.set_homogeneous(False)
78 frame.add(self._vbox)
79
80 eventBox = gtk.EventBox()
81
82 alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
83
84 titleLabel = gtk.Label(title)
85 titleLabel.modify_font(pango.FontDescription("bold 24"))
86 alignment.set_padding(padding_top = 4, padding_bottom = 4,
87 padding_left = 6, padding_right = 0)
88
89 alignment.add(titleLabel)
90 eventBox.add(alignment)
91
92 self._vbox.pack_start(eventBox, False, False, 0)
93
94 self._titleEventBox = eventBox
95 self._titleLabel = titleLabel
96
97 mainBox = gtk.VBox()
98
99 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
100 xscale = 1.0, yscale = 1.0)
101 alignment.set_padding(padding_top = 16, padding_bottom = 16,
102 padding_left = 16, padding_right = 16)
103 alignment.add(mainBox)
104 self._vbox.pack_start(alignment, True, True, 0)
105
106 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
107 xscale = 0.0, yscale = 0.0)
108 alignment.set_padding(padding_top = 0, padding_bottom = 16,
109 padding_left = 0, padding_right = 0)
110
111 self._help = help
112 self._completedHelp = completedHelp
113
114 if self._completedHelp is None or \
115 len(help.splitlines())>=len(completedHelp.splitlines()):
116 longerHelp = help
117 else:
118 longerHelp = completedHelp
119
120 self._helpLabel = gtk.Label(longerHelp)
121 # FIXME: should be a constant in common
122 self._helpLabel.set_justify(gtk.Justification.CENTER if pygobject
123 else gtk.JUSTIFY_CENTER)
124 self._helpLabel.set_use_markup(True)
125 alignment.add(self._helpLabel)
126 mainBox.pack_start(alignment, False, False, 0)
127
128 self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
129 xscale = 1.0, yscale = 1.0)
130 mainBox.pack_start(self._mainAlignment, True, True, 0)
131
132 buttonAlignment = gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
133 buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
134 padding_left = 16, padding_right = 16)
135
136 self._buttonBox = gtk.HBox()
137 self._buttonBox.set_homogeneous(False)
138 self._defaultButton = None
139 buttonAlignment.add(self._buttonBox)
140
141 self._vbox.pack_start(buttonAlignment, False, False, 0)
142
143 self._wizard = wizard
144 self._id = id
145 self._nextPageID = None
146
147 self._cancelFlightButton = None
148
149 self._completed = False
150 self._fromPage = None
151
152 @property
153 def id(self):
154 """Get the identifier of the page."""
155 return self._id
156
157 @property
158 def nextPageID(self):
159 """Get the identifier of the next page, if set."""
160 return self._nextPageID
161
162 @nextPageID.setter
163 def nextPageID(self, nextPageID):
164 """Set the identifier of the next page."""
165 self._nextPageID = nextPageID
166
167 def setMainWidget(self, widget):
168 """Set the given widget as the main one."""
169 self._mainAlignment.add(widget)
170
171 def addButton(self, label, default = False, sensitive = True,
172 tooltip = None, clicked = None, padding = 4,
173 clickedArg = None):
174 """Add a button with the given label.
175
176 Return the button object created."""
177 button = gtk.Button(label)
178 self._buttonBox.pack_start(button, False, False, padding)
179 button.set_use_underline(True)
180 if default:
181 button.set_can_default(True)
182 self._defaultButton = button
183 button.set_sensitive(sensitive)
184 if tooltip is not None:
185 button.set_tooltip_text(tooltip)
186 if clicked is not None:
187 if clickedArg is None:
188 button.connect("clicked", clicked)
189 else:
190 button.connect("clicked", clicked, clickedArg)
191 return button
192
193 def addCancelFlightButton(self):
194 """Add the 'Cancel flight' button to the page."""
195 self._cancelFlightButton = \
196 self.addButton(xstr("button_cancelFlight"),
197 sensitive = True,
198 tooltip = xstr("button_cancelFlight_tooltip"),
199 clicked = self._cancelFlight,
200 padding = 16)
201 return self._cancelFlightButton
202
203 def addPreviousButton(self, sensitive = True, clicked = None):
204 """Add the 'Next' button to the page."""
205 return self.addButton(xstr("button_previous"),
206 sensitive = sensitive,
207 tooltip = xstr("button_previous_tooltip"),
208 clicked = clicked)
209
210 def addNextButton(self, default = True, sensitive = True,
211 clicked = None):
212 """Add the 'Next' button to the page."""
213 return self.addButton(xstr("button_next"),
214 default = default,
215 sensitive = sensitive,
216 tooltip = xstr("button_next_tooltip"),
217 clicked = clicked)
218
219 def setStyle(self):
220 """Set the styles of some of the items on the page."""
221 if pygobject:
222 context = self.get_style_context()
223 color = context.get_background_color(gtk.StateFlags.SELECTED)
224 self._titleEventBox.modify_bg(0, color.to_color())
225 color = context.get_color(gtk.StateFlags.SELECTED)
226 self._titleLabel.modify_fg(0, color.to_color())
227 else:
228 style = self.rc_get_style()
229 self._titleEventBox.modify_bg(0, style.bg[3])
230 self._titleLabel.modify_fg(0, style.fg[3])
231
232 def initialize(self):
233 """Initialize the page.
234
235 It sets up the primary help, and calls the activate() function."""
236 self._helpLabel.set_markup(self._help)
237 self._helpLabel.set_sensitive(True)
238 self.activate()
239
240 def activate(self):
241 """Called when this page becomes active.
242
243 This default implementation does nothing."""
244 pass
245
246 def setHelp(self, help):
247 """Set the help string."""
248 self._help = help
249 if not self._completed:
250 self._helpLabel.set_markup(self._help)
251 self._helpLabel.set_sensitive(True)
252
253 def complete(self):
254 """Called when the page is completed.
255
256 It greys out/changes the help text and then calls finalize()."""
257 self.finalize()
258 if self._completedHelp is None:
259 self._helpLabel.set_sensitive(False)
260 else:
261 self._helpLabel.set_markup(self._completedHelp)
262 self._completed = True
263
264 def finalize(self):
265 """Called when the page is finalized."""
266 pass
267
268 def grabDefault(self):
269 """If the page has a default button, make it the default one."""
270 if self._defaultButton is not None:
271 self._defaultButton.grab_default()
272
273 def reset(self):
274 """Reset the page if the wizard is reset."""
275 self._completed = False
276 self._fromPage = None
277 if self._cancelFlightButton is not None:
278 self._cancelFlightButton.set_sensitive(True)
279
280 def goBack(self):
281 """Go to the page we were invoked from."""
282 assert self._fromPage is not None
283
284 self._wizard.setCurrentPage(self._fromPage, finalize = False)
285
286 def flightEnded(self):
287 """Called when the flight has ended.
288
289 This default implementation disables the cancel flight button."""
290 if self._cancelFlightButton is not None:
291 self._cancelFlightButton.set_sensitive(False)
292
293 def _cancelFlight(self, button):
294 """Called when the Cancel flight button is clicked."""
295 self._wizard.gui.cancelFlight()
296
297#-----------------------------------------------------------------------------
298
299class LoginPage(Page):
300 """The login page."""
301 def __init__(self, wizard):
302 """Construct the login page."""
303 super(LoginPage, self).__init__(wizard, "login",
304 xstr("login"), xstr("loginHelp"))
305
306 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
307 xscale = 0.0, yscale = 0.0)
308
309 table = gtk.Table(3, 2)
310 table.set_row_spacings(4)
311 table.set_col_spacings(32)
312 alignment.add(table)
313 self.setMainWidget(alignment)
314
315 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
316 xscale = 0.0, yscale = 0.0)
317 label = gtk.Label(xstr("label_pilotID"))
318 label.set_use_underline(True)
319 labelAlignment.add(label)
320 table.attach(labelAlignment, 0, 1, 0, 1)
321
322 self._pilotID = gtk.Entry()
323 self._pilotID.connect("changed", self._pilotIDChanged)
324 self._pilotID.set_tooltip_text(xstr("login_pilotID_tooltip"))
325 table.attach(self._pilotID, 1, 2, 0, 1)
326 label.set_mnemonic_widget(self._pilotID)
327
328 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
329 xscale = 0.0, yscale = 0.0)
330 label = gtk.Label(xstr("label_password"))
331 label.set_use_underline(True)
332 labelAlignment.add(label)
333 table.attach(labelAlignment, 0, 1, 1, 2)
334
335 self._password = gtk.Entry()
336 self._password.set_visibility(False)
337 self._password.connect("changed", self._setControls)
338 self._password.set_tooltip_text(xstr("login_password_tooltip"))
339 table.attach(self._password, 1, 2, 1, 2)
340 label.set_mnemonic_widget(self._password)
341
342 self._rememberButton = gtk.CheckButton(xstr("remember_password"))
343 self._rememberButton.set_use_underline(True)
344 self._rememberButton.set_tooltip_text(xstr("login_remember_tooltip"))
345 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
346
347 self.addButton(xstr("button_login_register"),
348 clicked = self._registerClicked,
349 tooltip = xstr("button_login_register_tooltip"))
350
351 self.addButton(xstr("button_offline"),
352 clicked = self._offlineClicked,
353 tooltip = xstr("button_offline_tooltip"))
354
355 self._loginButton = self.addButton(xstr("button_login"), default = True)
356 self._loginButton.connect("clicked", self._loginClicked)
357 self._loginButton.set_tooltip_text(xstr("login_button_tooltip"))
358
359
360 @property
361 def pilotID(self):
362 """Get the pilot ID, if given."""
363 return self._pilotID.get_text()
364
365 def activate(self):
366 """Activate the page."""
367 config = self._wizard.gui.config
368 self._pilotID.set_text(config.pilotID)
369 self._password.set_text(config.password)
370 self._rememberButton.set_active(config.rememberPassword)
371 self._setControls(None)
372
373 def _pilotIDChanged(self, entry):
374 """Called when the pilot ID has changed.
375
376 It sets the text to upper-case and calls _setControls to update other
377 stuff."""
378 entry.set_text(entry.get_text().upper())
379 self._setControls(entry)
380
381 def _setControls(self, entry = None):
382 """Set the sensitivity of the various controls.
383
384 The login button is sensitive only if both the pilot ID and the
385 password fields contain values.
386
387 The password field is sensitive only, if the entrance exam checkbox is
388 not selected.
389
390 The remember password checkbox is sensitive only, if the password field
391 contains text.
392
393 The entrance exam checkbox is sensitive only, if the pilot ID is not
394 empty."""
395 pilotID = self._pilotID.get_text()
396 password = self._password.get_text()
397 self._rememberButton.set_sensitive(password!="")
398 self._loginButton.set_sensitive(pilotID!="" and password!="")
399
400 def _registerClicked(self, button):
401 """Called when the Register button was clicked."""
402 self._wizard.jumpPage("register")
403
404 def _offlineClicked(self, button):
405 """Called when the offline button was clicked."""
406 print "mlx.flight.LoginPage: offline flight selected"
407 self._wizard.nextPage()
408
409 def _loginClicked(self, button):
410 """Called when the login button was clicked."""
411 print "mlx.flight.LoginPage: logging in"
412 self._wizard.login(self._handleLoginResult,
413 self._pilotID.get_text(),
414 self._password.get_text())
415
416 def _handleLoginResult(self, returned, result):
417 """Handle the login result."""
418 self._loginButton.set_sensitive(True)
419 if returned and result.loggedIn:
420 config = self._wizard.gui.config
421
422 config.pilotID = self._pilotID.get_text()
423
424 rememberPassword = self._rememberButton.get_active()
425 config.password = result.password if rememberPassword else ""
426
427 config.rememberPassword = rememberPassword
428
429 config.save()
430 if result.rank=="STU":
431 self._wizard.jumpPage("student")
432 else:
433 self._wizard.nextPage()
434
435#-----------------------------------------------------------------------------
436
437class FlightSelectionPage(Page):
438 """The page to select the flight."""
439 def __init__(self, wizard):
440 """Construct the flight selection page."""
441 help = xstr("flightsel_help")
442 completedHelp = xstr("flightsel_chelp")
443 super(FlightSelectionPage, self).__init__(wizard, "flightsel",
444 xstr("flightsel_title"),
445 help, completedHelp = completedHelp)
446
447 self._flightList = FlightList(popupMenuProducer =
448 self._createListPopupMenu,
449 widthRequest = 400)
450 self._flightList.connect("row-activated", self._rowActivated)
451 self._flightList.connect("selection-changed", self._selectionChanged)
452
453 self.setMainWidget(self._flightList)
454
455 self._pendingButton = self.addButton(xstr("flightsel_pending"),
456 sensitive = False,
457 clicked = self._pendingClicked,
458 tooltip = xstr("flightsel_pending_tooltip"))
459
460 self._saveButton = self.addButton(xstr("flightsel_save"),
461 sensitive = False,
462 clicked = self._saveClicked,
463 tooltip = xstr("flightsel_save_tooltip"))
464 self._saveDialog = None
465
466 self._refreshButton = self.addButton(xstr("flightsel_refresh"),
467 sensitive = True,
468 clicked = self._refreshClicked,
469 tooltip = xstr("flightsel_refresh_tooltip"))
470
471 self._loadButton = self.addButton(xstr("flightsel_load"),
472 sensitive = True,
473 tooltip = xstr("flightsel_load_tooltip"))
474 self._loadButton.connect("clicked", self._loadButtonClicked)
475 self._loadDialog = None
476
477 self._button = self.addNextButton(sensitive = False,
478 clicked = self._forwardClicked)
479
480 self._flights = []
481
482 self._pendingFlightsWindow = PendingFlightsWindow(self._wizard)
483 self._pendingFlightsWindowShown = False
484 self._pendingFlightsWindow.connect("delete-event",
485 self._deletePendingFlightsWindow)
486
487 def activate(self):
488 """Fill the flight list."""
489 self._setupHelp()
490 self._flightList.set_sensitive(True)
491 self._loadButton.set_sensitive(True)
492 self._refreshButton.set_sensitive(self._wizard.loggedIn)
493 self._buildFlights()
494
495 def finalize(self):
496 """Finalize the page."""
497 self._flightList.set_sensitive(False)
498 self._loadButton.set_sensitive(False)
499 self._refreshButton.set_sensitive(False)
500
501 def _setupHelp(self):
502 """Setup the help string"""
503 help = ""
504
505 if self._wizard.loggedIn:
506 numReported = len(self._wizard.loginResult.reportedFlights)
507 numRejected = len(self._wizard.loginResult.rejectedFlights)
508 if numReported==0 and numRejected==0:
509 help = xstr("flightsel_prehelp_nopending")
510 elif numReported>0 and numRejected==0:
511 help = xstr("flightsel_prehelp_rep_0rej") % (numReported,)
512 elif numReported==0 and numRejected>0:
513 help = xstr("flightsel_prehelp_0rep_rej") % (numRejected,)
514 else:
515 help = xstr("flightsel_prehelp_rep_rej") % \
516 (numReported, numRejected)
517
518 help += xstr("flightsel_help")
519
520 self.setHelp(help)
521
522 def _buildFlights(self):
523 """Rebuild the flights from the login result."""
524 self._flights = []
525 self._flightList.clear()
526 self._pendingFlightsWindow.clear()
527 loginResult = self._wizard.loginResult
528 if self._wizard.loggedIn:
529 for flight in loginResult.flights:
530 self._addFlight(flight)
531 for flight in loginResult.reportedFlights:
532 self._pendingFlightsWindow.addReportedFlight(flight)
533 for flight in loginResult.rejectedFlights:
534 self._pendingFlightsWindow.addRejectedFlight(flight)
535
536 self._updatePendingButton()
537
538 def _addFlight(self, flight):
539 """Add the given file to the list of flights."""
540 self._flights.append(flight)
541 self._flightList.addFlight(flight)
542
543 def _reflyFlight(self, flight):
544 """Refly the given flight."""
545 self._addFlight(flight)
546 self._setupHelp()
547 self._updatePendingButton()
548
549 def _pendingClicked(self, button):
550 """Called when the Pending flights button is clicked."""
551 self._pendingFlightsWindow.show_all()
552 self._pendingFlightsWindowShown = True
553 self._updateNextButton()
554
555 def _deletePendingFlightsWindow(self, window, event):
556 """Called when the pending flights window is closed."""
557 self._pendingFlightsWindow.hide()
558 self._pendingFlightsWindowShown = False
559 self._updateNextButton()
560 return True
561
562 def _saveClicked(self, button):
563 """Called when the Save flight button is clicked."""
564 self._saveSelected()
565
566 def _saveSelected(self):
567 """Save the selected flight."""
568 flight = self._getSelectedFlight()
569 date = flight.departureTime.date()
570 name = "%04d-%02d-%02d %s %s-%s.vaflight" % \
571 (date.year, date.month, date.day, flight.callsign,
572 flight.departureICAO, flight.arrivalICAO)
573
574 dialog = self._getSaveDialog()
575 dialog.set_current_name(name)
576 dialog.show_all()
577 response = dialog.run()
578 dialog.hide()
579
580 if response==RESPONSETYPE_OK:
581 fileName = text2unicode(dialog.get_filename())
582 print "Saving", fileName
583 try:
584 with open(fileName, "wt") as f:
585 flight.writeIntoFile(f)
586 except Exception, e:
587 print "Failed to save flight:", util.utf2unicode(str(e))
588 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
589 type = MESSAGETYPE_ERROR,
590 message_format =
591 xstr("flightsel_save_failed"))
592 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
593 dialog.set_title(WINDOW_TITLE_BASE)
594 secondary = xstr("flightsel_save_failed_sec")
595 dialog.format_secondary_markup(secondary)
596 dialog.run()
597 dialog.hide()
598
599 def _refreshClicked(self, button):
600 """Called when the refresh button is clicked."""
601 self._wizard.reloadFlights(self._refreshCallback)
602
603 def _refreshCallback(self, returned, result):
604 """Callback for the refresh."""
605 if returned:
606 self._setupHelp()
607 if result.loggedIn:
608 self._buildFlights()
609
610 def _selectionChanged(self, flightList, index):
611 """Called when the selection is changed."""
612 selected = index is not None
613 self._saveButton.set_sensitive(selected)
614 self._updateNextButton()
615
616 def _updatePendingButton(self):
617 """Update the senstivity of the Pending button."""
618 self._pendingButton.set_sensitive(self._pendingFlightsWindow.hasFlights)
619
620 def _updateNextButton(self):
621 """Update the sensitivity of the Next button."""
622 sensitive = self._flightList.selectedIndex is not None and \
623 not self._pendingFlightsWindowShown
624 self._button.set_sensitive(sensitive)
625
626 def _loadButtonClicked(self, loadButton):
627 """Called when the load a flight button is clicked."""
628 dialog = self._getLoadDialog()
629 dialog.show_all()
630 response = dialog.run()
631 dialog.hide()
632
633 if response==RESPONSETYPE_OK:
634 fileName = text2unicode(dialog.get_filename())
635 print "Loading", fileName
636 bookedFlight = web.BookedFlight()
637 try:
638 with open(fileName, "rt") as f:
639 bookedFlight.readFromFile(f)
640 self._addFlight(bookedFlight)
641 except Exception, e:
642 print "Failed to load flight:", util.utf2unicode(str(e))
643 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
644 type = MESSAGETYPE_ERROR,
645 message_format =
646 xstr("flightsel_load_failed"))
647 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
648 dialog.set_title(WINDOW_TITLE_BASE)
649 secondary = xstr("flightsel_load_failed_sec")
650 dialog.format_secondary_markup(secondary)
651 dialog.run()
652 dialog.hide()
653
654 def _forwardClicked(self, button):
655 """Called when the forward button was clicked."""
656 if self._completed:
657 self._wizard.jumpPage(self._nextID, finalize = False)
658 else:
659 self._flightSelected()
660
661 def _rowActivated(self, flightList, index):
662 """Called when a row is activated."""
663 if not self._completed:
664 self._flightSelected()
665
666 def _flightSelected(self):
667 """Called when a flight has been selected."""
668 flight = self._getSelectedFlight()
669 self._wizard._bookedFlight = flight
670 self._wizard.gui.enableFlightInfo(flight.aircraftType)
671
672 self._updateDepartureGate()
673
674 def _getSelectedFlight(self):
675 """Get the currently selected flight."""
676 index = self._flightList.selectedIndex
677 return self._flights[index]
678
679 def _updateDepartureGate(self):
680 """Update the departure gate for the booked flight."""
681 flight = self._wizard._bookedFlight
682 if self._wizard.gui.config.onlineGateSystem and \
683 self._wizard.loggedIn and not self._wizard.entranceExam:
684 if flight.departureICAO=="LHBP":
685 self._wizard.getFleet(self._fleetRetrieved)
686 else:
687 self._wizard.updatePlane(self._planeUpdated,
688 flight.tailNumber,
689 const.PLANE_AWAY)
690 else:
691 self._nextID = "connect"
692 self._wizard.jumpPage("connect")
693
694 def _fleetRetrieved(self, fleet):
695 """Called when the fleet has been retrieved."""
696 if fleet is None:
697 self._nextID = "connect"
698 self._wizard.jumpPage("connect")
699 else:
700 plane = fleet[self._wizard._bookedFlight.tailNumber]
701 if plane is None:
702 self._nextID = "connect"
703 self._wizard.jumpPage("connect")
704 elif plane.gateNumber is not None and \
705 not fleet.isGateConflicting(plane):
706 self._wizard._departureGate = plane.gateNumber
707 self._nextID = "connect"
708 self._wizard.jumpPage("connect")
709 else:
710 self._nextID = "gatesel"
711 self._wizard.jumpPage("gatesel")
712
713 def _planeUpdated(self, success):
714 """Callback for the plane updating."""
715 self._nextID = "connect"
716 self._wizard.jumpPage("connect")
717
718 def _getSaveDialog(self):
719 """Get the dialog to load a flight file."""
720 if self._saveDialog is not None:
721 return self._saveDialog
722
723 gui = self._wizard.gui
724 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
725 xstr("flightsel_save_title"),
726 action = FILE_CHOOSER_ACTION_SAVE,
727 buttons = (gtk.STOCK_CANCEL,
728 RESPONSETYPE_CANCEL,
729 gtk.STOCK_OK, RESPONSETYPE_OK),
730 parent = gui.mainWindow)
731 dialog.set_modal(True)
732 dialog.set_do_overwrite_confirmation(True)
733
734 filter = gtk.FileFilter()
735 filter.set_name(xstr("flightsel_filter_flights"))
736 filter.add_pattern("*.vaflight")
737 dialog.add_filter(filter)
738
739 filter = gtk.FileFilter()
740 filter.set_name(xstr("file_filter_all"))
741 filter.add_pattern("*.*")
742 dialog.add_filter(filter)
743
744 self._saveDialog = dialog
745
746 return dialog
747
748 def _getLoadDialog(self):
749 """Get the dialog to load a flight file."""
750 if self._loadDialog is not None:
751 return self._loadDialog
752
753 gui = self._wizard.gui
754 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
755 xstr("flightsel_load_title"),
756 action = FILE_CHOOSER_ACTION_OPEN,
757 buttons = (gtk.STOCK_CANCEL,
758 RESPONSETYPE_CANCEL,
759 gtk.STOCK_OK, RESPONSETYPE_OK),
760 parent = gui.mainWindow)
761 dialog.set_modal(True)
762
763 filter = gtk.FileFilter()
764 filter.set_name(xstr("flightsel_filter_flights"))
765 filter.add_pattern("*.vaflight")
766 dialog.add_filter(filter)
767
768 filter = gtk.FileFilter()
769 filter.set_name(xstr("file_filter_all"))
770 filter.add_pattern("*.*")
771 dialog.add_filter(filter)
772
773 self._loadDialog = dialog
774
775 return dialog
776
777 def _createListPopupMenu(self):
778 """Get the flight list popup menu."""
779 menu = gtk.Menu()
780
781 menuItem = gtk.MenuItem()
782 menuItem.set_label(xstr("flightsel_popup_select"))
783 menuItem.set_use_underline(True)
784 menuItem.connect("activate", self._popupSelect)
785 menuItem.show()
786
787 menu.append(menuItem)
788
789 menuItem = gtk.MenuItem()
790 menuItem.set_label(xstr("flightsel_popup_save"))
791 menuItem.set_use_underline(True)
792 menuItem.connect("activate", self._popupSave)
793 menuItem.show()
794
795 menu.append(menuItem)
796
797 return menu
798
799 def _popupSelect(self, menuItem):
800 """Called when the Select menu item is activated in the popup menu."""
801 if not self._completed:
802 self._flightSelected()
803
804 def _popupSave(self, menuItem):
805 """Called when the Save menu item is activated in the popup menu."""
806 if not self._completed:
807 self._saveSelected()
808
809#-----------------------------------------------------------------------------
810
811class GateSelectionPage(Page):
812 """Page to select a free gate at LHBP.
813 This page should be displayed only if we have fleet information!."""
814 def __init__(self, wizard):
815 """Construct the gate selection page."""
816 super(GateSelectionPage, self).__init__(wizard, "gatesel",
817 xstr("gatesel_title"),
818 xstr("gatesel_help"))
819
820 self._listStore = gtk.ListStore(str)
821 self._gateList = gtk.TreeView(self._listStore)
822 column = gtk.TreeViewColumn(None, gtk.CellRendererText(),
823 text = 0)
824 column.set_expand(True)
825 self._gateList.append_column(column)
826 self._gateList.set_headers_visible(False)
827 self._gateList.connect("row-activated", self._rowActivated)
828
829 gateSelection = self._gateList.get_selection()
830 gateSelection.connect("changed", self._selectionChanged)
831
832 scrolledWindow = gtk.ScrolledWindow()
833 scrolledWindow.add(self._gateList)
834 scrolledWindow.set_size_request(50, -1)
835 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
836 else gtk.POLICY_AUTOMATIC,
837 gtk.PolicyType.AUTOMATIC if pygobject
838 else gtk.POLICY_AUTOMATIC)
839 scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
840 else gtk.SHADOW_IN)
841
842 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
843 alignment.add(scrolledWindow)
844
845 self.setMainWidget(alignment)
846
847 self.addCancelFlightButton()
848
849 self.addPreviousButton(clicked = self._backClicked)
850
851 self._button = self.addNextButton(sensitive = False,
852 clicked = self._forwardClicked)
853
854 def activate(self):
855 """Fill the gate list."""
856 self._listStore.clear()
857 self._gateList.set_sensitive(True)
858 occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
859 for gate in lhbpGates.gates:
860 if gate.isAvailable(lhbpGates, occupiedGateNumbers):
861 self._listStore.append([gate.number])
862
863 def finalize(self):
864 """Finalize the page."""
865 self._gateList.set_sensitive(False)
866
867 def _selectionChanged(self, selection):
868 """Called when the selection is changed."""
869 self._button.set_sensitive(selection.count_selected_rows()==1)
870
871 def _backClicked(self, button):
872 """Called when the Back button is pressed."""
873 self.goBack()
874
875 def _forwardClicked(self, button):
876 """Called when the forward button is clicked."""
877 if not self._completed:
878 self._gateSelected()
879 else:
880 self._wizard.jumpPage("connect")
881
882 def _rowActivated(self, flightList, path, column):
883 """Called when a row is activated."""
884 if not self._completed:
885 self._gateSelected()
886
887 def _gateSelected(self):
888 """Called when a gate has been selected."""
889 selection = self._gateList.get_selection()
890 (listStore, iter) = selection.get_selected()
891 (gateNumber,) = listStore.get(iter, 0)
892
893 self._wizard._departureGate = gateNumber
894
895 self._wizard.updatePlane(self._planeUpdated,
896 self._wizard._bookedFlight.tailNumber,
897 const.PLANE_HOME, gateNumber)
898
899 def _planeUpdated(self, success):
900 """Callback for the plane updating call."""
901 if success is None or success:
902 self._wizard.jumpPage("connect")
903 else:
904 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
905 type = MESSAGETYPE_ERROR,
906 message_format = xstr("gatesel_conflict"))
907 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
908 dialog.set_title(WINDOW_TITLE_BASE)
909 dialog.format_secondary_markup(xstr("gatesel_conflict_sec"))
910 dialog.run()
911 dialog.hide()
912
913 self._wizard.getFleet(self._fleetRetrieved)
914
915 def _fleetRetrieved(self, fleet):
916 """Called when the fleet has been retrieved."""
917 if fleet is None:
918 self._wizard.jumpPage("connect")
919 else:
920 self.activate()
921
922#-----------------------------------------------------------------------------
923
924class RegisterPage(Page):
925 """A page to enter the registration data."""
926
927 # The minimal year of birth
928 _minYearOfBirth = 1900
929
930 # The maximal year of birth
931 _maxYearOfBirth = datetime.date.today().year
932
933 # The regular expression to check the e-mail address with
934 _emailAddressRE = re.compile("[^@]+@[^@]+\.[^@]+")
935
936 def __init__(self, wizard):
937 """Construct the registration page."""
938 super(RegisterPage, self).__init__(wizard, "register",
939 xstr("register_title"),
940 xstr("register_help"))
941
942 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
943 xscale = 0.0, yscale = 0.0)
944
945 table = gtk.Table(12, 3)
946 table.set_row_spacings(4)
947 table.set_col_spacings(32)
948 alignment.add(table)
949 self.setMainWidget(alignment)
950
951 row = 0
952
953 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
954 xscale = 0.0, yscale = 0.0)
955 label = gtk.Label(xstr("register_name1"))
956 label.set_use_underline(True)
957 labelAlignment.add(label)
958 table.attach(labelAlignment, 0, 1, row, row+1)
959
960 self._name1 = gtk.Entry()
961 self._name1.connect("changed", self._updateButtons)
962 self._name1.set_tooltip_text(xstr("register_name1_tooltip"))
963 self._name1.set_width_chars(15)
964 table.attach(self._name1, 1, 2, row, row+1)
965 label.set_mnemonic_widget(self._name1)
966
967 row += 1
968
969 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
970 xscale = 0.0, yscale = 0.0)
971 label = gtk.Label(xstr("register_name2"))
972 label.set_use_underline(True)
973 labelAlignment.add(label)
974 table.attach(labelAlignment, 0, 1, row, row+1)
975
976 self._name2 = gtk.Entry()
977 self._name2.connect("changed", self._updateButtons)
978 self._name2.set_tooltip_text(xstr("register_name2_tooltip"))
979 self._name2.set_width_chars(15)
980 table.attach(self._name2, 1, 2, row, row+1)
981 label.set_mnemonic_widget(self._name2)
982
983 row += 1
984
985 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
986 xscale = 0.0, yscale = 0.0)
987 label = gtk.Label(xstr("register_year_of_birth"))
988 label.set_use_underline(True)
989 labelAlignment.add(label)
990 table.attach(labelAlignment, 0, 1, row, row+1)
991
992 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
993 xscale = 0.0, yscale = 0.0)
994
995 self._yearOfBirth = gtk.SpinButton()
996 self._yearOfBirth.set_increments(step = 1, page = 10)
997 self._yearOfBirth.set_range(min = RegisterPage._minYearOfBirth,
998 max = RegisterPage._maxYearOfBirth)
999 self._yearOfBirth.set_numeric(True)
1000 self._yearOfBirth.set_tooltip_text(xstr("register_year_of_birth_tooltip"))
1001 self._yearOfBirth.set_width_chars(5)
1002 self._yearOfBirth.connect("changed", self._updateButtons)
1003 self._yearOfBirth.connect("value-changed", self._updateButtons)
1004 alignment.add(self._yearOfBirth)
1005 table.attach(alignment, 1, 2, row, row+1)
1006 label.set_mnemonic_widget(self._yearOfBirth)
1007
1008 row += 1
1009
1010 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1011 xscale = 0.0, yscale = 0.0)
1012 label = gtk.Label(xstr("register_email"))
1013 label.set_use_underline(True)
1014 labelAlignment.add(label)
1015 table.attach(labelAlignment, 0, 1, row, row+1)
1016
1017 self._emailAddress = gtk.Entry()
1018 self._emailAddress.connect("changed", self._updateButtons)
1019 self._emailAddress.set_tooltip_text(xstr("register_email_tooltip"))
1020 table.attach(self._emailAddress, 1, 2, row, row+1)
1021 label.set_mnemonic_widget(self._emailAddress)
1022
1023 self._emailAddressPublic = gtk.CheckButton(xstr("register_email_public"))
1024 self._emailAddressPublic.set_use_underline(True)
1025 self._emailAddressPublic.set_tooltip_text(xstr("register_email_public_tooltip"))
1026 table.attach(self._emailAddressPublic, 2, 3, row, row+1)
1027
1028 row += 1
1029
1030 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1031 xscale = 0.0, yscale = 0.0)
1032 label = gtk.Label(xstr("register_vatsim_id"))
1033 label.set_use_underline(True)
1034 labelAlignment.add(label)
1035 table.attach(labelAlignment, 0, 1, row, row+1)
1036
1037 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1038 xscale = 0.0, yscale = 0.0)
1039 self._vatsimID = IntegerEntry()
1040 self._vatsimID.connect("changed", self._updateButtons)
1041 self._vatsimID.set_tooltip_text(xstr("register_vatsim_id_tooltip"))
1042 self._vatsimID.set_width_chars(7)
1043 alignment.add(self._vatsimID)
1044 table.attach(alignment, 1, 2, row, row+1)
1045 label.set_mnemonic_widget(self._vatsimID)
1046
1047 row += 1
1048
1049 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1050 xscale = 0.0, yscale = 0.0)
1051 label = gtk.Label(xstr("register_ivao_id"))
1052 label.set_use_underline(True)
1053 labelAlignment.add(label)
1054 table.attach(labelAlignment, 0, 1, row, row+1)
1055
1056 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1057 xscale = 0.0, yscale = 0.0)
1058 self._ivaoID = IntegerEntry()
1059 self._ivaoID.connect("changed", self._updateButtons)
1060 self._ivaoID.set_tooltip_text(xstr("register_ivao_id_tooltip"))
1061 self._ivaoID.set_width_chars(7)
1062 alignment.add(self._ivaoID)
1063 table.attach(alignment, 1, 2, row, row+1)
1064 label.set_mnemonic_widget(self._ivaoID)
1065
1066 row += 1
1067
1068 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1069 xscale = 0.0, yscale = 0.0)
1070 label = gtk.Label(xstr("register_phone_num"))
1071 label.set_use_underline(True)
1072 label.set_use_markup(True)
1073 labelAlignment.add(label)
1074 table.attach(labelAlignment, 0, 1, row, row+1)
1075
1076 self._phoneNumber = gtk.Entry()
1077 self._phoneNumber.set_tooltip_text(xstr("register_phone_num_tooltip"))
1078 table.attach(self._phoneNumber, 1, 2, row, row+1)
1079 label.set_mnemonic_widget(self._phoneNumber)
1080
1081 row += 1
1082
1083 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1084 xscale = 0.0, yscale = 0.0)
1085 label = gtk.Label(xstr("register_nationality"))
1086 label.set_use_underline(True)
1087 label.set_use_markup(True)
1088 labelAlignment.add(label)
1089 table.attach(labelAlignment, 0, 1, row, row+1)
1090
1091
1092 self._nationality = gtk.Entry()
1093 self._nationality.set_tooltip_text(xstr("register_nationality_tooltip"))
1094 table.attach(self._nationality, 1, 2, row, row+1)
1095 label.set_mnemonic_widget(self._nationality)
1096
1097 placeholder = gtk.Label()
1098 placeholder.set_text(xstr("register_password_mismatch"))
1099 placeholder.set_use_markup(True)
1100 placeholder.set_child_visible(False)
1101 placeholder.hide()
1102 table.attach(placeholder, 2, 3, row, row+1)
1103
1104 row += 1
1105
1106 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1107 xscale = 0.0, yscale = 0.0)
1108 label = gtk.Label(xstr("register_password"))
1109 label.set_use_underline(True)
1110 labelAlignment.add(label)
1111 table.attach(labelAlignment, 0, 1, row, row+1)
1112
1113 self._password = gtk.Entry()
1114 self._password.set_visibility(False)
1115 self._password.connect("changed", self._updateButtons)
1116 self._password.set_tooltip_text(xstr("register_password_tooltip"))
1117 table.attach(self._password, 1, 2, row, row+1)
1118 label.set_mnemonic_widget(self._password)
1119
1120 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1121 xscale = 0.0, yscale = 0.0)
1122 self._passwordStatus = gtk.Label()
1123 alignment.add(self._passwordStatus)
1124 table.attach(alignment, 2, 3, row, row+1)
1125
1126 row += 1
1127
1128 labelAlignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
1129 xscale = 0.0, yscale = 0.0)
1130 label = gtk.Label(xstr("register_password2"))
1131 label.set_use_underline(True)
1132 labelAlignment.add(label)
1133 table.attach(labelAlignment, 0, 1, row, row+1)
1134
1135 self._password2 = gtk.Entry()
1136 self._password2.set_visibility(False)
1137 self._password2.connect("changed", self._updateButtons)
1138 self._password2.set_tooltip_text(xstr("register_password2_tooltip"))
1139 table.attach(self._password2, 1, 2, row, row+1)
1140 label.set_mnemonic_widget(self._password2)
1141
1142 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1143 xscale = 0.0, yscale = 0.0)
1144 self._password2Status = gtk.Label()
1145 alignment.add(self._password2Status)
1146 table.attach(alignment, 2, 3, row, row+1)
1147
1148 row += 1
1149
1150 self._rememberButton = gtk.CheckButton(xstr("remember_password"))
1151 self._rememberButton.set_use_underline(True)
1152 self._rememberButton.set_tooltip_text(xstr("login_remember_tooltip"))
1153 table.attach(self._rememberButton, 1, 2, row, row+1)
1154
1155 cancelButton = \
1156 self.addButton(xstr("button_cancel"))
1157 cancelButton.connect("clicked", self._cancelClicked)
1158
1159 self._registerButton = \
1160 self.addButton(xstr("button_register"), default = True,
1161 tooltip = xstr("button_register_tooltip"))
1162 self._registerButton.connect("clicked", self._registerClicked)
1163
1164 self._updateButtons()
1165
1166 @property
1167 def name1(self):
1168 """Get the first name component entered."""
1169 return self._name1.get_text()
1170
1171 @property
1172 def name2(self):
1173 """Get the second name component entered."""
1174 return self._name2.get_text()
1175
1176 @property
1177 def yearOfBirth(self):
1178 """Get the year of birth."""
1179 yearOfBirthText = self._yearOfBirth.get_text()
1180 return int(yearOfBirthText) if yearOfBirthText else 0
1181
1182 @property
1183 def emailAddress(self):
1184 """Get the e-mail address."""
1185 return self._emailAddress.get_text()
1186
1187 @property
1188 def emailAddressPublic(self):
1189 """Get the whether the e-mail address is public."""
1190 return self._emailAddressPublic.get_active()
1191
1192 @property
1193 def vatsimID(self):
1194 """Get the VATSIM ID."""
1195 return self._vatsimID.get_int()
1196
1197 @property
1198 def ivaoID(self):
1199 """Get the IVAO ID."""
1200 return self._ivaoID.get_int()
1201
1202 @property
1203 def phoneNumber(self):
1204 """Get the phone number."""
1205 return self._phoneNumber.get_text()
1206
1207 @property
1208 def nationality(self):
1209 """Get the nationality."""
1210 return self._nationality.get_text()
1211
1212 @property
1213 def password(self):
1214 """Get the password."""
1215 return self._password.get_text()
1216
1217 @property
1218 def rememberPassword(self):
1219 """Get whether the password should be remembered."""
1220 return self._rememberButton.get_active()
1221
1222 def activate(self):
1223 """Setup the route from the booked flight."""
1224 self._yearOfBirth.set_value(0)
1225 self._yearOfBirth.set_text("")
1226 self._updateButtons()
1227
1228 def _updateButtons(self, widget = None):
1229 """Update the sensitive state of the buttons"""
1230 yearOfBirth = self.yearOfBirth
1231
1232 emailAddress = self.emailAddress
1233 emailAddressMatch = RegisterPage._emailAddressRE.match(emailAddress)
1234
1235 vatsimID = self.vatsimID
1236 ivaoID = self.ivaoID
1237
1238 password = self.password
1239 password2 = self._password2.get_text()
1240 if not password:
1241 self._passwordStatus.set_text("")
1242 elif len(password)<5:
1243 self._passwordStatus.set_text(xstr("register_password_too_short"))
1244 else:
1245 self._passwordStatus.set_text(xstr("register_password_ok"))
1246 self._passwordStatus.set_use_markup(True)
1247
1248 if len(password)<5 or not password2:
1249 self._password2Status.set_text("")
1250 elif password!=password2:
1251 self._password2Status.set_text(xstr("register_password_mismatch"))
1252 else:
1253 self._password2Status.set_text(xstr("register_password_ok"))
1254 self._password2Status.set_use_markup(True)
1255
1256 sensitive = \
1257 len(self.name1)>0 and len(self.name2)>0 and \
1258 yearOfBirth>=RegisterPage._minYearOfBirth and \
1259 yearOfBirth<=RegisterPage._maxYearOfBirth and \
1260 emailAddressMatch is not None and \
1261 (vatsimID>=800000 or ivaoID>=100000) and \
1262 len(password)>=5 and password==password2
1263
1264 self._registerButton.set_sensitive(sensitive)
1265
1266 def _cancelClicked(self, button):
1267 """Called when the Cancel button is clicked."""
1268 self.goBack()
1269
1270 def _registerClicked(self, button):
1271 """Called when the Register button is clicked."""
1272 nameOrder = xstr("register_nameorder")
1273
1274 if nameOrder=="eastern":
1275 surName = self.name1
1276 firstName = self.name2
1277 else:
1278 surName = self.name2
1279 firstName = self.name1
1280
1281 nationality = self.nationality.lower()
1282
1283 if getLanguage().lower()=="hu" or nationality.find("hung")!=-1 or \
1284 nationality.find("magyar")!=-1:
1285 requestedNameOrder = "eastern"
1286 else:
1287 requestedNameOrder = "western"
1288
1289 registrationData = web.Registration(surName, firstName,
1290 requestedNameOrder,
1291 self.yearOfBirth,
1292 self.emailAddress,
1293 self.emailAddressPublic,
1294 self.vatsimID, self.ivaoID,
1295 self.phoneNumber, self.nationality,
1296 self.password)
1297 print "Registering with data:"
1298 print " name:", self.name1, self.name2, registrationData.firstName, registrationData.surName, requestedNameOrder
1299 print " yearOfBirth:", self.yearOfBirth, registrationData.yearOfBirth
1300 print " emailAddress:", self.emailAddress, registrationData.emailAddress
1301 print " emailAddressPublic:", self.emailAddressPublic, registrationData.emailAddressPublic
1302 print " vatsimID:", self.vatsimID, registrationData.vatsimID
1303 print " ivaoID:", self.ivaoID, registrationData.ivaoID
1304 print " phoneNumber:", self.phoneNumber, registrationData.phoneNumber
1305 print " nationality:", self.nationality, registrationData.nationality
1306
1307 gui = self._wizard.gui
1308 gui.beginBusy(xstr("register_busy"))
1309 gui.webHandler.register(self._registerResultCallback, registrationData)
1310
1311 def _registerResultCallback(self, returned, result):
1312 """Called when the registration result is available."""
1313 gobject.idle_add(self._handleRegisterResult, returned, result)
1314
1315 def _handleRegisterResult(self, returned, result):
1316 """Handle the registration result."""
1317 gui = self._wizard.gui
1318
1319 gui.endBusy()
1320
1321 print "Registration result:"
1322 print " returned:", returned
1323 if returned:
1324 print " registered:", result.registered
1325 if result.registered:
1326 print " pilotID", result.pilotID
1327 print " loggedIn", result.loggedIn
1328 print " emailAlreadyRegistered:", result.emailAlreadyRegistered
1329 print " invalidData:", result.invalidData
1330
1331 registrationOK = returned and result.registered
1332
1333 message = xstr("register_ok") if registrationOK \
1334 else xstr("register_failed")
1335 secondaryMessage = None
1336 if registrationOK:
1337 if result.loggedIn:
1338 secondaryMessage = xstr("register_info") % (result.pilotID,)
1339 else:
1340 secondaryMessage = xstr("register_nologin") % (result.pilotID,)
1341 messageType = MESSAGETYPE_INFO
1342
1343 config = gui.config
1344 config.pilotID = result.pilotID
1345 config.rememberPassword = self.rememberPassword
1346 if config.rememberPassword:
1347 config.password = self.password
1348 else:
1349 config.password = ""
1350
1351 config.save()
1352 elif returned and result.emailAlreadyRegistered:
1353 secondaryMessage = xstr("register_email_already")
1354 messageType = MESSAGETYPE_ERROR
1355 elif returned and result.invalidData:
1356 secondaryMessage = xstr("register_invalid_data")
1357 messageType = MESSAGETYPE_ERROR
1358 else:
1359 secondaryMessage = xstr("register_error")
1360 messageType = MESSAGETYPE_ERROR
1361
1362 dialog = gtk.MessageDialog(parent = gui.mainWindow,
1363 type = messageType,
1364 message_format = message)
1365 dialog.set_title(WINDOW_TITLE_BASE + " - " +
1366 xstr("register_result_title"))
1367 dialog.format_secondary_markup(secondaryMessage)
1368
1369 dialog.add_button(xstr("button_ok"), 0)
1370
1371 dialog.run()
1372 dialog.hide()
1373
1374 if registrationOK:
1375 if result.loggedIn:
1376 self._wizard._loginResult = result
1377 self._wizard.nextPage()
1378 else:
1379 self._wizard.jumpPage("login")
1380
1381#-----------------------------------------------------------------------------
1382
1383class StudentPage(Page):
1384 """A page displayed to students after logging in."""
1385 _entryExamStatusQueryInterval = 60*1000
1386
1387 def __init__(self, wizard):
1388 """Construct the student page."""
1389 super(StudentPage, self).__init__(wizard, "student",
1390 xstr("student_title"),
1391 xstr("student_help"))
1392
1393
1394 self._getEntryExamStatusCancelled = False
1395
1396 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1397 xscale = 0.5, yscale = 0.0)
1398
1399 table = gtk.Table(6, 4)
1400 table.set_row_spacings(4)
1401 table.set_col_spacings(0)
1402 table.set_homogeneous(False)
1403 alignment.add(table)
1404 self.setMainWidget(alignment)
1405
1406 row = 0
1407
1408 labelAlignment = gtk.Alignment(xalign=0.0, yalign = 0.5,
1409 xscale=0.0, yscale = 0.0)
1410 label = gtk.Label(xstr("student_entry_exam_status"))
1411 label.set_alignment(0.0, 0.5)
1412 labelAlignment.add(label)
1413 labelAlignment.resize_children()
1414 table.attach(labelAlignment, 0, 1, row, row + 1, xoptions = FILL)
1415
1416 alignment = gtk.Alignment(xalign=0.0, yalign = 0.5,
1417 xscale=1.0, yscale = 0.0)
1418 self._entryExamStatus = gtk.Label()
1419 self._entryExamStatus.set_use_markup(True)
1420 self._entryExamStatus.set_alignment(0.0, 0.5)
1421 alignment.add(self._entryExamStatus)
1422 alignment.resize_children()
1423 table.attach(alignment, 1, 4, row, row + 1)
1424
1425 row += 1
1426
1427 buttonAlignment = gtk.Alignment(xalign=0.0, xscale=1.0)
1428 button = self._entryExamButton = gtk.Button(xstr("student_entry_exam"))
1429 button.set_use_underline(True)
1430 button.connect("clicked", self._entryExamClicked)
1431 button.set_tooltip_text(xstr("student_entry_exam_tooltip"))
1432
1433 buttonAlignment.add(button)
1434 table.attach(buttonAlignment, 0, 4, row, row + 1, xoptions = FILL,
1435 ypadding = 4)
1436
1437 row += 3
1438
1439 labelAlignment = gtk.Alignment(xalign=0.0, yalign = 0.5,
1440 xscale=0.0, yscale = 0.0)
1441 label = gtk.Label(xstr("student_check_flight_status"))
1442 labelAlignment.add(label)
1443 table.attach(labelAlignment, 0, 1, row, row + 1, xoptions = FILL)
1444
1445 alignment = gtk.Alignment(xalign=0.0, yalign = 0.5,
1446 xscale=1.0, yscale = 0.0)
1447 self._checkFlightStatus = gtk.Label()
1448 self._checkFlightStatus.set_use_markup(True)
1449 self._checkFlightStatus.set_alignment(0.0, 0.5)
1450 alignment.add(self._checkFlightStatus)
1451 table.attach(alignment, 1, 4, row, row + 1)
1452
1453 row += 1
1454
1455 alignment = gtk.Alignment(xalign=0.0, xscale=1.0)
1456
1457 hbox = gtk.HBox()
1458 hbox.set_homogeneous(False)
1459 hbox.set_spacing(0)
1460
1461 aircraftTypesModel = gtk.ListStore(str, int)
1462 for aircraftType in web.BookedFlight.checkFlightTypes:
1463 aircraftTypesModel.append([aircraftNames[aircraftType],
1464 aircraftType])
1465
1466 aircraftTypeAlignment = gtk.Alignment(xalign = 0.0, xscale = 1.0)
1467
1468 self._aircraftType = gtk.ComboBox(model = aircraftTypesModel)
1469 renderer = gtk.CellRendererText()
1470 self._aircraftType.pack_start(renderer, True)
1471 self._aircraftType.add_attribute(renderer, "text", 0)
1472 self._aircraftType.set_tooltip_text(xstr("student_check_flight_type_tooltip"))
1473 self._aircraftType.set_active(0)
1474
1475 aircraftTypeAlignment.add(self._aircraftType)
1476
1477 hbox.pack_start(aircraftTypeAlignment, False, False, 0)
1478
1479 buttonAlignment = gtk.Alignment(xalign=0.0, xscale=1.0)
1480 button = self._checkFlightButton = gtk.Button(xstr("student_check_flight"))
1481 button.set_use_underline(True)
1482 button.connect("clicked", self._checkFlightClicked)
1483 button.set_tooltip_text(xstr("student_check_flight_tooltip"))
1484
1485 hbox.pack_start(button, True, True, 0)
1486
1487 alignment.add(hbox)
1488 table.attach(alignment, 0, 4, row, row + 1, xoptions = FILL)
1489
1490 @property
1491 def aircraftType(self):
1492 """Get the type of the aircraft used to perform the check flight."""
1493 index = self._aircraftType.get_active()
1494 return self._aircraftType.get_model()[index][1]
1495
1496 def activate(self):
1497 """Activate the student page."""
1498 print "StudentPage.activate"
1499 self._getEntryExamStatusCancelled = False
1500
1501 loginResult = self._wizard.loginResult
1502 self._entryExamLink = loginResult.entryExamLink
1503
1504 self._updateEntryExamStatus(loginResult.entryExamPassed)
1505 self._getEntryExamStatus()
1506
1507 # FIXME: call with real value
1508 self._updateCheckFlightStatus(self._wizard.loginResult.checkFlightStatus)
1509
1510 def finalize(self):
1511 """Finalize the page."""
1512 print "StudentPage.finalize"
1513 self._getEntryExamStatusCancelled = True
1514
1515 def _entryExamClicked(self, button):
1516 """Called when the entry exam button is clicked."""
1517 webbrowser.open(self._entryExamLink)
1518
1519 def _getEntryExamStatus(self):
1520 """Initiate the query of the entry exam status after the interval."""
1521 if not self._getEntryExamStatusCancelled:
1522 gobject.timeout_add(StudentPage._entryExamStatusQueryInterval,
1523 lambda: self._wizard.gui.webHandler. \
1524 getEntryExamStatus(self._entryExamStatusCallback))
1525
1526 def _entryExamStatusCallback(self, returned, result):
1527 """Called when the entry exam status is available."""
1528 gobject.idle_add(self._handleEntryExamStatus, returned, result)
1529
1530 def _handleEntryExamStatus(self, returned, result):
1531 """Called when the entry exam status is availabe."""
1532 print "_handleEntryExamStatus", returned, result
1533 if returned and not self._getEntryExamStatusCancelled:
1534 self._entryExamLink = result.entryExamLink
1535 self._updateEntryExamStatus(result.entryExamPassed)
1536 if result.madeFO:
1537 self._madeFO()
1538 else:
1539 self._getEntryExamStatus()
1540
1541 def _updateEntryExamStatus(self, passed):
1542 """Update the entry exam status display and button."""
1543 self._entryExamStatus.set_text(xstr("student_entry_exam_passed")
1544 if passed else
1545 xstr("student_entry_exam_not_passed"))
1546 self._entryExamStatus.set_use_markup(True)
1547 self._entryExamButton.set_sensitive(not passed)
1548 self._wizard._loginResult.entryExamPassed = passed
1549
1550 def _checkFlightClicked(self, button):
1551 """Called when the check flight button is clicked."""
1552 aircraftType = self.aircraftType
1553 self._wizard._bookedFlight = \
1554 web.BookedFlight.forCheckFlight(aircraftType)
1555 self._wizard.gui.enableFlightInfo(aircraftType)
1556 self._wizard.jumpPage("connect")
1557
1558 def _updateCheckFlightStatus(self, passed):
1559 """Update the status of the check flight."""
1560 self._aircraftType.set_sensitive(not passed)
1561 self._checkFlightStatus.set_text(xstr("student_check_flight_passed")
1562 if passed else
1563 xstr("student_check_flight_not_passed"))
1564 self._checkFlightStatus.set_use_markup(True)
1565 self._checkFlightButton.set_sensitive(not passed)
1566
1567 def _madeFO(self):
1568 """Handle the event when the pilot has become a first officer."""
1569 wizard = self._wizard
1570 loginResult = wizard.loginResult
1571 loginResult.rank = "FO"
1572
1573 gui = wizard.gui
1574
1575 dialog = gtk.MessageDialog(parent = gui.mainWindow,
1576 type = MESSAGETYPE_INFO,
1577 message_format = xstr("student_fo"))
1578
1579 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
1580 dialog.set_title(WINDOW_TITLE_BASE)
1581 secondary = xstr("student_fo_secondary")
1582 dialog.format_secondary_markup(secondary)
1583 dialog.run()
1584 dialog.hide()
1585
1586 gui.reset()
1587
1588#-----------------------------------------------------------------------------
1589
1590class ConnectPage(Page):
1591 """Page which displays the departure airport and gate (if at LHBP)."""
1592 def __init__(self, wizard):
1593 """Construct the connect page."""
1594 help = "Load the aircraft below into the simulator and park it\n" \
1595 "at the given airport, at the gate below, if present.\n\n" \
1596 "Then press the Connect button to connect to the simulator."
1597 completedHelp = "The basic data of your flight can be read below."
1598 super(ConnectPage, self).__init__(wizard, "connect",
1599 xstr("connect_title"),
1600 xstr("connect_help"),
1601 completedHelp = xstr("connect_chelp"))
1602
1603 self._selectSimulator = os.name=="nt" or "FORCE_SELECT_SIM" in os.environ
1604
1605 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1606 xscale = 0.0, yscale = 0.0)
1607
1608 table = gtk.Table(7 if self._selectSimulator else 5, 2)
1609 table.set_row_spacings(4)
1610 table.set_col_spacings(16)
1611 table.set_homogeneous(True)
1612 alignment.add(table)
1613 self.setMainWidget(alignment)
1614
1615 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1616 label = gtk.Label(xstr("connect_flightno"))
1617 labelAlignment.add(label)
1618 table.attach(labelAlignment, 0, 1, 0, 1)
1619
1620 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1621 self._flightNumber = gtk.Label()
1622 self._flightNumber.set_width_chars(9)
1623 self._flightNumber.set_alignment(0.0, 0.5)
1624 labelAlignment.add(self._flightNumber)
1625 table.attach(labelAlignment, 1, 2, 0, 1)
1626
1627 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1628 label = gtk.Label(xstr("connect_acft"))
1629 labelAlignment.add(label)
1630 table.attach(labelAlignment, 0, 1, 1, 2)
1631
1632 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1633 self._aircraft = gtk.Label()
1634 self._aircraft.set_width_chars(25)
1635 self._aircraft.set_alignment(0.0, 0.5)
1636 labelAlignment.add(self._aircraft)
1637 table.attach(labelAlignment, 1, 2, 1, 2)
1638
1639 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1640 label = gtk.Label(xstr("connect_tailno"))
1641 labelAlignment.add(label)
1642 table.attach(labelAlignment, 0, 1, 2, 3)
1643
1644 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1645 self._tailNumber = gtk.Label()
1646 self._tailNumber.set_width_chars(10)
1647 self._tailNumber.set_alignment(0.0, 0.5)
1648 labelAlignment.add(self._tailNumber)
1649 table.attach(labelAlignment, 1, 2, 2, 3)
1650
1651 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1652 label = gtk.Label(xstr("connect_airport"))
1653 labelAlignment.add(label)
1654 table.attach(labelAlignment, 0, 1, 3, 4)
1655
1656 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1657 self._departureICAO = gtk.Label()
1658 self._departureICAO.set_width_chars(6)
1659 self._departureICAO.set_alignment(0.0, 0.5)
1660 labelAlignment.add(self._departureICAO)
1661 table.attach(labelAlignment, 1, 2, 3, 4)
1662
1663 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
1664 label = gtk.Label(xstr("connect_gate"))
1665 labelAlignment.add(label)
1666 table.attach(labelAlignment, 0, 1, 4, 5)
1667
1668 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
1669 self._departureGate = gtk.Label()
1670 self._departureGate.set_width_chars(5)
1671 self._departureGate.set_alignment(0.0, 0.5)
1672 labelAlignment.add(self._departureGate)
1673 table.attach(labelAlignment, 1, 2, 4, 5)
1674
1675 if self._selectSimulator:
1676 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0, yalign=0.5)
1677 label = gtk.Label(xstr("connect_sim"))
1678 labelAlignment.add(label)
1679 table.attach(labelAlignment, 0, 1, 5, 7)
1680
1681 selectAlignment = gtk.Alignment(xalign=0.0, xscale=0.0, yalign=0.5)
1682
1683 selectBox = gtk.HBox()
1684 if pygobject:
1685 self._selectMSFS = \
1686 gtk.RadioButton.new_with_mnemonic_from_widget(None,
1687 xstr("connect_sim_msfs"))
1688 else:
1689 self._selectMSFS = gtk.RadioButton(None,
1690 xstr("connect_sim_msfs"))
1691
1692 selectBox.pack_start(self._selectMSFS, False, False, 0);
1693
1694 if pygobject:
1695 self._selectXPlane = \
1696 gtk.RadioButton.new_with_mnemonic_from_widget(self._selectMSFS,
1697 xstr("connect_sim_xplane"))
1698 else:
1699 self._selectXPlane = gtk.RadioButton(self._selectMSFS,
1700 xstr("connect_sim_xplane"))
1701
1702 selectBox.pack_start(self._selectXPlane, False, False, 8);
1703
1704 selectAlignment.add(selectBox)
1705 table.attach(selectAlignment, 1, 2, 5, 7)
1706
1707
1708 self.addCancelFlightButton()
1709
1710 self._previousButton = \
1711 self.addPreviousButton(clicked = self._backClicked)
1712
1713 self._button = self.addButton(xstr("button_connect"), default = True,
1714 tooltip = xstr("button_connect_tooltip"))
1715 self._clickedID = self._button.connect("clicked", self._connectClicked)
1716
1717 def activate(self):
1718 """Setup the departure information."""
1719 self._button.set_label(xstr("button_connect"))
1720 self._button.set_use_underline(True)
1721 self._button.set_tooltip_text(xstr("button_connect_tooltip"))
1722 self._button.disconnect(self._clickedID)
1723 self._clickedID = self._button.connect("clicked", self._connectClicked)
1724
1725 bookedFlight = self._wizard._bookedFlight
1726
1727 self._flightNumber.set_markup("<b>" + bookedFlight.callsign + "</b>")
1728
1729 aircraftType = aircraftNames[bookedFlight.aircraftType]
1730 self._aircraft.set_markup("<b>" + aircraftType + "</b>")
1731
1732 self._tailNumber.set_markup("<b>" + bookedFlight.tailNumber + "</b>")
1733
1734 icao = bookedFlight.departureICAO
1735 self._departureICAO.set_markup("<b>" + icao + "</b>")
1736 gate = self._wizard._departureGate
1737 if gate!="-":
1738 gate = "<b>" + gate + "</b>"
1739 self._departureGate.set_markup(gate)
1740
1741 if self._selectSimulator:
1742 config = self._wizard.gui.config
1743 self._selectMSFS.set_active(config.defaultMSFS)
1744 self._selectXPlane.set_active(not config.defaultMSFS)
1745
1746 self._previousButton.set_sensitive(not self._wizard.entranceExam)
1747
1748 def finalize(self):
1749 """Finalize the page."""
1750 self._button.set_label(xstr("button_next"))
1751 self._button.set_use_underline(True)
1752 self._button.set_tooltip_text(xstr("button_next_tooltip"))
1753 self._button.disconnect(self._clickedID)
1754 self._clickedID = self._button.connect("clicked", self._forwardClicked)
1755
1756 def _backClicked(self, button):
1757 """Called when the Back button is pressed."""
1758 self.goBack()
1759
1760 def _connectClicked(self, button):
1761 """Called when the Connect button is pressed."""
1762 if self._selectSimulator:
1763 simulatorType = const.SIM_MSFS9 if self._selectMSFS.get_active() \
1764 else const.SIM_XPLANE10
1765 else:
1766 simulatorType = const.SIM_MSFS9 if os.name=="nt" \
1767 else const.SIM_XPLANE10
1768
1769 config = self._wizard.gui.config
1770 config.defaultMSFS = simulatorType == const.SIM_MSFS9
1771 config.save()
1772
1773 self._wizard._connectSimulator(simulatorType)
1774
1775 def _forwardClicked(self, button):
1776 """Called when the Forward button is pressed."""
1777 self._wizard.nextPage()
1778
1779#-----------------------------------------------------------------------------
1780
1781class PayloadPage(Page):
1782 """Page to allow setting up the payload."""
1783 def __init__(self, wizard):
1784 """Construct the page."""
1785 super(PayloadPage, self).__init__(wizard, "payload",
1786 xstr("payload_title"),
1787 xstr("payload_help"),
1788 completedHelp = xstr("payload_chelp"))
1789
1790 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1791 xscale = 0.0, yscale = 0.0)
1792
1793 table = gtk.Table(7, 3)
1794 table.set_row_spacings(4)
1795 table.set_col_spacings(16)
1796 table.set_homogeneous(False)
1797 alignment.add(table)
1798 self.setMainWidget(alignment)
1799
1800 label = gtk.Label(xstr("payload_crew"))
1801 label.set_use_underline(True)
1802 label.set_alignment(0.0, 0.5)
1803 table.attach(label, 0, 1, 0, 1)
1804
1805 self._numCrew = IntegerEntry(defaultValue = 0)
1806 self._numCrew.set_width_chars(6)
1807 self._numCrew.connect("integer-changed", self._weightChanged)
1808 self._numCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
1809 table.attach(self._numCrew, 1, 2, 0, 1)
1810 label.set_mnemonic_widget(self._numCrew)
1811
1812 label = gtk.Label(xstr("payload_pax"))
1813 label.set_use_underline(True)
1814 label.set_alignment(0.0, 0.5)
1815 table.attach(label, 0, 1, 1, 2)
1816
1817 self._numPassengers = IntegerEntry(defaultValue = 0)
1818 self._numPassengers.set_width_chars(6)
1819 self._numPassengers.connect("integer-changed", self._weightChanged)
1820 self._numPassengers.set_tooltip_text(xstr("payload_pax_tooltip"))
1821 table.attach(self._numPassengers, 1, 2, 1, 2)
1822 label.set_mnemonic_widget(self._numPassengers)
1823
1824 label = gtk.Label(xstr("payload_bag"))
1825 label.set_use_underline(True)
1826 label.set_alignment(0.0, 0.5)
1827 table.attach(label, 0, 1, 2, 3)
1828
1829 self._bagWeight = IntegerEntry(defaultValue = 0)
1830 self._bagWeight.set_width_chars(6)
1831 self._bagWeight.connect("integer-changed", self._weightChanged)
1832 self._bagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
1833 table.attach(self._bagWeight, 1, 2, 2, 3)
1834 label.set_mnemonic_widget(self._bagWeight)
1835
1836 table.attach(gtk.Label("kg"), 2, 3, 2, 3)
1837
1838 label = gtk.Label(xstr("payload_cargo"))
1839 label.set_use_underline(True)
1840 label.set_alignment(0.0, 0.5)
1841 table.attach(label, 0, 1, 3, 4)
1842
1843 self._cargoWeight = IntegerEntry(defaultValue = 0)
1844 self._cargoWeight.set_width_chars(6)
1845 self._cargoWeight.connect("integer-changed", self._weightChanged)
1846 self._cargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
1847 table.attach(self._cargoWeight, 1, 2, 3, 4)
1848 label.set_mnemonic_widget(self._cargoWeight)
1849
1850 table.attach(gtk.Label("kg"), 2, 3, 3, 4)
1851
1852 label = gtk.Label(xstr("payload_mail"))
1853 label.set_use_underline(True)
1854 label.set_alignment(0.0, 0.5)
1855 table.attach(label, 0, 1, 4, 5)
1856
1857 self._mailWeight = IntegerEntry(defaultValue = 0)
1858 self._mailWeight.set_width_chars(6)
1859 self._mailWeight.connect("integer-changed", self._weightChanged)
1860 self._mailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
1861 table.attach(self._mailWeight, 1, 2, 4, 5)
1862 label.set_mnemonic_widget(self._mailWeight)
1863
1864 table.attach(gtk.Label("kg"), 2, 3, 4, 5)
1865
1866 label = gtk.Label("<b>" + xstr("payload_zfw") + "</b>")
1867 label.set_alignment(0.0, 0.5)
1868 label.set_use_markup(True)
1869 table.attach(label, 0, 1, 5, 6)
1870
1871 self._calculatedZFW = gtk.Label()
1872 self._calculatedZFW.set_width_chars(6)
1873 self._calculatedZFW.set_alignment(1.0, 0.5)
1874 table.attach(self._calculatedZFW, 1, 2, 5, 6)
1875
1876 table.attach(gtk.Label("kg"), 2, 3, 5, 6)
1877
1878 self._zfwButton = gtk.Button(xstr("payload_fszfw"))
1879 self._zfwButton.set_use_underline(True)
1880 self._zfwButton.connect("clicked", self._zfwRequested)
1881 self._zfwButton.set_tooltip_text(xstr("payload_fszfw_tooltip"))
1882 table.attach(self._zfwButton, 0, 1, 6, 7)
1883
1884 self._simulatorZFW = gtk.Label("-")
1885 self._simulatorZFW.set_width_chars(6)
1886 self._simulatorZFW.set_alignment(1.0, 0.5)
1887 table.attach(self._simulatorZFW, 1, 2, 6, 7)
1888 self._simulatorZFWValue = None
1889
1890 table.attach(gtk.Label("kg"), 2, 3, 6, 7)
1891
1892 self.addCancelFlightButton()
1893 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1894 self._button = self.addNextButton(clicked = self._forwardClicked)
1895
1896 @property
1897 def numCrew(self):
1898 """The number of the crew members on the flight."""
1899 return self._numCrew.get_int()
1900
1901 @property
1902 def numPassengers(self):
1903 """The number of the passengers on the flight."""
1904 return self._numPassengers.get_int()
1905
1906 @property
1907 def bagWeight(self):
1908 """Get the bag weight entered."""
1909 return self._bagWeight.get_int()
1910
1911 @property
1912 def cargoWeight(self):
1913 """Get the cargo weight entered."""
1914 return self._cargoWeight.get_int()
1915
1916 @property
1917 def mailWeight(self):
1918 """Get the bag weight entered."""
1919 return self._mailWeight.get_int()
1920
1921 def activate(self):
1922 """Setup the information."""
1923 bookedFlight = self._wizard._bookedFlight
1924
1925 self._numCrew.set_int(bookedFlight.numCrew)
1926 self._numCrew.set_sensitive(True)
1927 self._numPassengers.set_int(bookedFlight.numPassengers)
1928 self._numPassengers.set_sensitive(True)
1929
1930 self._bagWeight.set_int(bookedFlight.bagWeight)
1931 self._bagWeight.set_sensitive(True)
1932 self._cargoWeight.set_int(bookedFlight.cargoWeight)
1933 self._cargoWeight.set_sensitive(True)
1934 self._mailWeight.set_int(bookedFlight.mailWeight)
1935 self._mailWeight.set_sensitive(True)
1936
1937 self._simulatorZFW.set_text("-")
1938 self._simulatorZFWValue = None
1939 self._zfwButton.set_sensitive(True)
1940 self._updateCalculatedZFW()
1941
1942 def finalize(self):
1943 """Finalize the payload page."""
1944 self._numCrew.set_sensitive(False)
1945 self._numPassengers.set_sensitive(False)
1946 self._bagWeight.set_sensitive(False)
1947 self._cargoWeight.set_sensitive(False)
1948 self._mailWeight.set_sensitive(False)
1949 self._wizard.gui.initializeWeightHelp()
1950
1951 def calculateZFW(self):
1952 """Calculate the ZFW value."""
1953 zfw = self._wizard.gui._flight.aircraft.dow
1954 zfw += (self._numCrew.get_int() + self._numPassengers.get_int()) * 82
1955 zfw += self._bagWeight.get_int()
1956 zfw += self._cargoWeight.get_int()
1957 zfw += self._mailWeight.get_int()
1958 return zfw
1959
1960 def _updateCalculatedZFW(self):
1961 """Update the calculated ZFW"""
1962 zfw = self.calculateZFW()
1963
1964 markupBegin = "<b>"
1965 markupEnd = "</b>"
1966 if self._simulatorZFWValue is not None and \
1967 PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
1968 markupBegin += '<span foreground="red">'
1969 markupEnd = "</span>" + markupEnd
1970 self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
1971
1972 def _weightChanged(self, entry, weight):
1973 """Called when one of the weight values or humanm counts has changed."""
1974 self._updateCalculatedZFW()
1975
1976 def _zfwRequested(self, button):
1977 """Called when the ZFW is requested from the simulator."""
1978 self._zfwButton.set_sensitive(False)
1979 self._backButton.set_sensitive(False)
1980 self._button.set_sensitive(False)
1981 gui = self._wizard.gui
1982 gui.beginBusy(xstr("payload_zfw_busy"))
1983 gui.simulator.requestZFW(self._handleZFW)
1984
1985 def _handleZFW(self, zfw):
1986 """Called when the ZFW value is retrieved."""
1987 gobject.idle_add(self._processZFW, zfw)
1988
1989 def _processZFW(self, zfw):
1990 """Process the given ZFW value received from the simulator."""
1991 self._wizard.gui.endBusy()
1992 self._zfwButton.set_sensitive(True)
1993 self._backButton.set_sensitive(True)
1994 self._button.set_sensitive(True)
1995 self._simulatorZFWValue = zfw
1996 self._simulatorZFW.set_text("%.0f" % (zfw,))
1997 self._updateCalculatedZFW()
1998
1999 def _forwardClicked(self, button):
2000 """Called when the forward button is clicked."""
2001 self._wizard.nextPage()
2002
2003 def _backClicked(self, button):
2004 """Called when the Back button is pressed."""
2005 self.goBack()
2006
2007#-----------------------------------------------------------------------------
2008
2009class TimePage(Page):
2010 """Page displaying the departure and arrival times and allows querying the
2011 current time from the flight simulator."""
2012 def __init__(self, wizard):
2013 super(TimePage, self).__init__(wizard, "time",
2014 xstr("time_title"),
2015 xstr("time_help"),
2016 completedHelp = xstr("time_chelp"))
2017
2018 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2019 xscale = 0.0, yscale = 0.0)
2020
2021 table = gtk.Table(3, 2)
2022 table.set_row_spacings(4)
2023 table.set_col_spacings(16)
2024 table.set_homogeneous(False)
2025 alignment.add(table)
2026 self.setMainWidget(alignment)
2027
2028 label = gtk.Label(xstr("time_departure"))
2029 label.set_alignment(0.0, 0.5)
2030 table.attach(label, 0, 1, 0, 1)
2031
2032 self._departure = gtk.Label()
2033 self._departure.set_alignment(0.0, 0.5)
2034 table.attach(self._departure, 1, 2, 0, 1)
2035
2036 label = gtk.Label(xstr("time_arrival"))
2037 label.set_alignment(0.0, 0.5)
2038 table.attach(label, 0, 1, 1, 2)
2039
2040 self._arrival = gtk.Label()
2041 self._arrival.set_alignment(0.0, 0.5)
2042 table.attach(self._arrival, 1, 2, 1, 2)
2043
2044 self._timeButton = gtk.Button(xstr("time_fs"))
2045 self._timeButton.set_use_underline(True)
2046 self._timeButton.set_tooltip_text(xstr("time_fs_tooltip"))
2047 self._timeButton.connect("clicked", self._timeRequested)
2048 table.attach(self._timeButton, 0, 1, 2, 3)
2049
2050 self._simulatorTime = gtk.Label("-")
2051 self._simulatorTime.set_alignment(0.0, 0.5)
2052 table.attach(self._simulatorTime, 1, 2, 2, 3)
2053
2054 self.addCancelFlightButton()
2055
2056 self._backButton = self.addPreviousButton(clicked = self._backClicked)
2057 self._button = self.addNextButton(clicked = self._forwardClicked)
2058
2059 def activate(self):
2060 """Activate the page."""
2061 self._timeButton.set_sensitive(True)
2062 bookedFlight = self._wizard._bookedFlight
2063 self._departure.set_text(str(bookedFlight.departureTime.time()))
2064 self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
2065 self._simulatorTime.set_text("-")
2066
2067 def _timeRequested(self, button):
2068 """Request the time from the simulator."""
2069 self._timeButton.set_sensitive(False)
2070 self._backButton.set_sensitive(False)
2071 self._button.set_sensitive(False)
2072 self._wizard.gui.beginBusy(xstr("time_busy"))
2073 self._wizard.gui.simulator.requestTime(self._handleTime)
2074
2075 def _handleTime(self, timestamp):
2076 """Handle the result of a time retrieval."""
2077 gobject.idle_add(self._processTime, timestamp)
2078
2079 def _processTime(self, timestamp):
2080 """Process the given time."""
2081 self._wizard.gui.endBusy()
2082 self._timeButton.set_sensitive(True)
2083 self._backButton.set_sensitive(True)
2084 self._button.set_sensitive(True)
2085 tm = time.gmtime(timestamp)
2086 t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
2087 self._simulatorTime.set_text(str(t))
2088
2089 ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
2090 dt = self._wizard._bookedFlight.departureTime.time()
2091 dts = dt.hour * 3600 + dt.minute * 60 + dt.second
2092 diff = dts-ts
2093
2094 markupBegin = ""
2095 markupEnd = ""
2096 if diff < 0:
2097 markupBegin = '<b><span foreground="red">'
2098 markupEnd = '</span></b>'
2099 elif diff < 3*60 or diff > 30*60:
2100 markupBegin = '<b><span foreground="orange">'
2101 markupEnd = '</span></b>'
2102
2103 self._departure.set_markup(markupBegin + str(dt) + markupEnd)
2104
2105 def _backClicked(self, button):
2106 """Called when the Back button is pressed."""
2107 self.goBack()
2108
2109 def _forwardClicked(self, button):
2110 """Called when the forward button is clicked."""
2111 if not self._completed:
2112 gui = self._wizard.gui
2113 gui.beginBusy(xstr("fuel_get_busy"))
2114
2115 gui.simulator.getFuel(self._handleFuel)
2116 else:
2117 self._wizard.nextPage()
2118
2119 def _handleFuel(self, fuelData):
2120 """Callback for the fuel query operation."""
2121 gobject.idle_add(self._processFuel, fuelData)
2122
2123 def _processFuel(self, fuelData):
2124 """Process the given fuel data."""
2125 self._wizard.gui.endBusy()
2126 self._wizard._fuelData = fuelData
2127 self._wizard.nextPage()
2128
2129#-----------------------------------------------------------------------------
2130
2131class RoutePage(Page):
2132 """The page containing the route and the flight level."""
2133 def __init__(self, wizard):
2134 """Construct the page."""
2135 super(RoutePage, self).__init__(wizard, "route",
2136 xstr("route_title"),
2137 xstr("route_help"),
2138 completedHelp = xstr("route_chelp"))
2139
2140 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2141 xscale = 0.0, yscale = 0.0)
2142
2143 mainBox = gtk.VBox()
2144 alignment.add(mainBox)
2145 self.setMainWidget(alignment)
2146
2147 levelBox = gtk.HBox()
2148
2149 label = gtk.Label(xstr("route_level"))
2150 label.set_use_underline(True)
2151 levelBox.pack_start(label, True, True, 0)
2152
2153 self._cruiseLevel = gtk.SpinButton()
2154 self._cruiseLevel.set_increments(step = 10, page = 100)
2155 self._cruiseLevel.set_range(min = 0, max = 500)
2156 self._cruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
2157 self._cruiseLevel.set_numeric(True)
2158 self._cruiseLevel.connect("changed", self._cruiseLevelChanged)
2159 self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
2160 label.set_mnemonic_widget(self._cruiseLevel)
2161
2162 levelBox.pack_start(self._cruiseLevel, False, False, 8)
2163
2164 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
2165 xscale = 0.0, yscale = 0.0)
2166 alignment.add(levelBox)
2167
2168 mainBox.pack_start(alignment, False, False, 0)
2169
2170
2171 routeBox = gtk.VBox()
2172
2173 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
2174 xscale = 0.0, yscale = 0.0)
2175 label = gtk.Label(xstr("route_route"))
2176 label.set_use_underline(True)
2177 alignment.add(label)
2178 routeBox.pack_start(alignment, True, True, 0)
2179
2180 routeWindow = gtk.ScrolledWindow()
2181 routeWindow.set_size_request(400, 80)
2182 routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
2183 else gtk.SHADOW_IN)
2184 routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
2185 else gtk.POLICY_AUTOMATIC,
2186 gtk.PolicyType.AUTOMATIC if pygobject
2187 else gtk.POLICY_AUTOMATIC)
2188
2189 self._uppercasingRoute = False
2190
2191 self._route = gtk.TextView()
2192 self._route.set_tooltip_text(xstr("route_route_tooltip"))
2193 self._route.set_wrap_mode(WRAP_WORD)
2194 self._route.get_buffer().connect("changed", self._routeChanged)
2195 self._route.get_buffer().connect_after("insert-text", self._routeInserted)
2196 routeWindow.add(self._route)
2197
2198 label.set_mnemonic_widget(self._route)
2199 routeBox.pack_start(routeWindow, True, True, 0)
2200
2201 mainBox.pack_start(routeBox, True, True, 8)
2202
2203 alternateBox = gtk.HBox()
2204
2205 label = gtk.Label(xstr("route_altn"))
2206 label.set_use_underline(True)
2207 alternateBox.pack_start(label, True, True, 0)
2208
2209 self._alternate = gtk.Entry()
2210 self._alternate.set_width_chars(6)
2211 self._alternate.connect("changed", self._alternateChanged)
2212 self._alternate.set_tooltip_text(xstr("route_altn_tooltip"))
2213 label.set_mnemonic_widget(self._alternate)
2214
2215 alternateBox.pack_start(self._alternate, False, False, 8)
2216
2217 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
2218 xscale = 0.0, yscale = 0.0)
2219 alignment.add(alternateBox)
2220
2221 mainBox.pack_start(alignment, False, False, 0)
2222
2223 self.addCancelFlightButton()
2224
2225 self._backButton = self.addPreviousButton(clicked = self._backClicked)
2226 self._button = self.addNextButton(clicked = self._forwardClicked)
2227
2228 @property
2229 def filedCruiseLevel(self):
2230 """Get the filed cruise level."""
2231 return self._cruiseLevel.get_value_as_int()
2232
2233 @property
2234 def route(self):
2235 """Get the route."""
2236 return self._getRoute()
2237
2238 @property
2239 def alternate(self):
2240 """Get the ICAO code of the alternate airport."""
2241 return self._alternate.get_text()
2242
2243 def activate(self):
2244 """Setup the route from the booked flight."""
2245 self._cruiseLevel.set_value(0)
2246 self._cruiseLevel.set_text("")
2247 self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
2248 self._alternate.set_text("")
2249 self._updateForwardButton()
2250
2251 def _getRoute(self):
2252 """Get the text of the route."""
2253 buffer = self._route.get_buffer()
2254 return buffer.get_text(buffer.get_start_iter(),
2255 buffer.get_end_iter(), True)
2256
2257 def _updateForwardButton(self):
2258 """Update the sensitivity of the forward button."""
2259 cruiseLevelText = self._cruiseLevel.get_text()
2260 cruiseLevel = int(cruiseLevelText) if cruiseLevelText else 0
2261 alternate = self._alternate.get_text()
2262 self._button.set_sensitive(cruiseLevel>=50 and self._getRoute()!="" and
2263 (len(alternate)==4 or self._wizard.entranceExam))
2264
2265 def _cruiseLevelChanged(self, *arg):
2266 """Called when the cruise level has changed."""
2267 self._updateForwardButton()
2268
2269 def _routeChanged(self, textBuffer):
2270 """Called when the route has changed."""
2271 if not self._uppercasingRoute:
2272 self._updateForwardButton()
2273
2274 def _routeInserted(self, textBuffer, iter, text, length):
2275 """Called when new characters are inserted into the route.
2276
2277 It uppercases all characters."""
2278 if not self._uppercasingRoute:
2279 self._uppercasingRoute = True
2280
2281 iter1 = iter.copy()
2282 iter1.backward_chars(length)
2283 textBuffer.delete(iter, iter1)
2284
2285 textBuffer.insert(iter, text.upper())
2286
2287 self._uppercasingRoute = False
2288
2289 def _alternateChanged(self, entry):
2290 """Called when the alternate airport has changed."""
2291 entry.set_text(entry.get_text().upper())
2292 self._updateForwardButton()
2293
2294 def _backClicked(self, button):
2295 """Called when the Back button is pressed."""
2296 self.goBack()
2297
2298 def _forwardClicked(self, button):
2299 """Called when the Forward button is clicked."""
2300 if self._wizard.gui.flight.aircraft.simBriefData is None:
2301 self._wizard.usingSimBrief = False
2302 if self._wizard.gui.config.useSimBrief and \
2303 self._wizard.usingSimBrief is not False:
2304 self._wizard.jumpPage("simbrief_setup")
2305 else:
2306 self._wizard.usingSimBrief = False
2307 self._wizard.jumpPage("fuel")
2308
2309#-----------------------------------------------------------------------------
2310
2311class SimBriefCredentialsDialog(gtk.Dialog):
2312 """A dialog window to ask for SimBrief credentials."""
2313 def __init__(self, gui, userName, password, rememberPassword):
2314 """Construct the dialog."""
2315 super(SimBriefCredentialsDialog, self).__init__(WINDOW_TITLE_BASE + " - " +
2316 xstr("simbrief_credentials_title"),
2317 gui.mainWindow,
2318 DIALOG_MODAL)
2319 self.add_button(xstr("button_cancel"), RESPONSETYPE_CANCEL)
2320 self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
2321
2322 contentArea = self.get_content_area()
2323
2324 contentAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2325 xscale = 0.0, yscale = 0.0)
2326 contentAlignment.set_padding(padding_top = 4, padding_bottom = 16,
2327 padding_left = 8, padding_right = 8)
2328
2329 contentArea.pack_start(contentAlignment, False, False, 0)
2330
2331 contentVBox = gtk.VBox()
2332 contentAlignment.add(contentVBox)
2333
2334 label = gtk.Label(xstr("simbrief_login_failed"))
2335 label.set_alignment(0.0, 0.0)
2336
2337 contentVBox.pack_start(label, False, False, 0)
2338
2339 tableAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2340 xscale = 0.0, yscale = 0.0)
2341 tableAlignment.set_padding(padding_top = 24, padding_bottom = 0,
2342 padding_left = 0, padding_right = 0)
2343
2344 table = gtk.Table(3, 2)
2345 table.set_row_spacings(4)
2346 table.set_col_spacings(16)
2347 table.set_homogeneous(False)
2348
2349 tableAlignment.add(table)
2350 contentVBox.pack_start(tableAlignment, True, True, 0)
2351
2352 label = gtk.Label(xstr("simbrief_username"))
2353 label.set_use_underline(True)
2354 label.set_alignment(0.0, 0.5)
2355 table.attach(label, 0, 1, 0, 1)
2356
2357 self._userName = gtk.Entry()
2358 self._userName.set_width_chars(16)
2359 #self._userName.connect("changed",
2360 # lambda button: self._updateForwardButton())
2361 self._userName.set_tooltip_text(xstr("simbrief_username_tooltip"))
2362 self._userName.set_text(userName)
2363 table.attach(self._userName, 1, 2, 0, 1)
2364 label.set_mnemonic_widget(self._userName)
2365
2366 label = gtk.Label(xstr("simbrief_password"))
2367 label.set_use_underline(True)
2368 label.set_alignment(0.0, 0.5)
2369 table.attach(label, 0, 1, 1, 2)
2370
2371 self._password = gtk.Entry()
2372 self._password.set_visibility(False)
2373 #self._password.connect("changed",
2374 # lambda button: self._updateForwardButton())
2375 self._password.set_tooltip_text(xstr("simbrief_password_tooltip"))
2376 self._password.set_text(password)
2377 table.attach(self._password, 1, 2, 1, 2)
2378 label.set_mnemonic_widget(self._password)
2379
2380 self._rememberButton = gtk.CheckButton(xstr("simbrief_remember_password"))
2381 self._rememberButton.set_use_underline(True)
2382 self._rememberButton.set_tooltip_text(xstr("simbrief_remember_tooltip"))
2383 self._rememberButton.set_active(rememberPassword)
2384 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
2385
2386 @property
2387 def userName(self):
2388 """Get the user name entered."""
2389 return self._userName.get_text()
2390
2391 @property
2392 def password(self):
2393 """Get the password entered."""
2394 return self._password.get_text()
2395
2396 @property
2397 def rememberPassword(self):
2398 """Get whether the password is to be remembered."""
2399 return self._rememberButton.get_active()
2400
2401 def run(self):
2402 """Run the dialog."""
2403 self.show_all()
2404
2405 response = super(SimBriefCredentialsDialog, self).run()
2406
2407 self.hide()
2408
2409 return response
2410
2411#-----------------------------------------------------------------------------
2412
2413class SimBriefSetupPage(Page):
2414 """Page for setting up some parameters for SimBrief."""
2415 monthNum2Name = [
2416 "JAN",
2417 "FEB",
2418 "MAR",
2419 "APR",
2420 "MAY",
2421 "JUN",
2422 "JUL",
2423 "AUG",
2424 "SEP",
2425 "OCT",
2426 "NOV",
2427 "DEC"
2428 ]
2429
2430 progress2Message = {
2431 cef.SIMBRIEF_PROGRESS_SEARCHING_BROWSER: "simbrief_progress_searching_browser",
2432 cef.SIMBRIEF_PROGRESS_LOADING_FORM: "simbrief_progress_loading_form",
2433 cef.SIMBRIEF_PROGRESS_FILLING_FORM: "simbrief_progress_filling_form",
2434 cef.SIMBRIEF_PROGRESS_WAITING_LOGIN: "simbrief_progress_waiting_login",
2435 cef.SIMBRIEF_PROGRESS_LOGGING_IN: "simbrief_progress_logging_in",
2436 cef.SIMBRIEF_PROGRESS_WAITING_RESULT: "simbrief_progress_waiting_result",
2437 cef.SIMBRIEF_PROGRESS_RETRIEVING_BRIEFING: "simbrief_progress_retrieving_briefing"
2438 }
2439
2440 result2Message = {
2441 cef.SIMBRIEF_RESULT_ERROR_OTHER: "simbrief_result_error_other",
2442 cef.SIMBRIEF_RESULT_ERROR_NO_FORM: "simbrief_result_error_no_form",
2443 cef.SIMBRIEF_RESULT_ERROR_NO_POPUP: "simbrief_result_error_no_popup",
2444 cef.SIMBRIEF_RESULT_ERROR_LOGIN_FAILED: "simbrief_result_error_login_failed"
2445 }
2446
2447 @staticmethod
2448 def getHTMLFilePath():
2449 """Get the path of the HTML file to contain the generated flight
2450 plan."""
2451 if os.name=="nt":
2452 return os.path.join(tempfile.gettempdir(),
2453 "mlx_simbrief" +
2454 (".secondary" if secondaryInstallation else "") +
2455 ".html")
2456 else:
2457 import pwd
2458 return os.path.join(tempfile.gettempdir(),
2459 "mlx_simbrief." + pwd.getpwuid(os.getuid())[0] + "" +
2460 (".secondary" if secondaryInstallation else "") +
2461 ".html")
2462
2463 def __init__(self, wizard):
2464 """Construct the setup page."""
2465
2466 super(SimBriefSetupPage, self).__init__(wizard, "simbrief_setup",
2467 xstr("simbrief_setup_title"),
2468 xstr("simbrief_setup_help"),
2469 xstr("simbrief_setup_chelp"))
2470
2471 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2472 xscale = 0.0, yscale = 0.0)
2473
2474 table = gtk.Table(9, 3)
2475 table.set_row_spacings(4)
2476 table.set_col_spacings(16)
2477 table.set_homogeneous(False)
2478 alignment.add(table)
2479 self.setMainWidget(alignment)
2480
2481 label = gtk.Label(xstr("simbrief_username"))
2482 label.set_use_underline(True)
2483 label.set_alignment(0.0, 0.5)
2484 table.attach(label, 0, 1, 0, 1)
2485
2486 self._userName = gtk.Entry()
2487 self._userName.set_width_chars(16)
2488 self._userName.connect("changed",
2489 lambda button: self._updateForwardButton())
2490 self._userName.set_tooltip_text(xstr("simbrief_username_tooltip"))
2491 table.attach(self._userName, 1, 2, 0, 1)
2492 label.set_mnemonic_widget(self._userName)
2493
2494 label = gtk.Label(xstr("simbrief_password"))
2495 label.set_use_underline(True)
2496 label.set_alignment(0.0, 0.5)
2497 table.attach(label, 0, 1, 1, 2)
2498
2499 self._password = gtk.Entry()
2500 self._password.set_visibility(False)
2501 self._password.connect("changed",
2502 lambda button: self._updateForwardButton())
2503 self._password.set_tooltip_text(xstr("simbrief_password_tooltip"))
2504 table.attach(self._password, 1, 2, 1, 2)
2505 label.set_mnemonic_widget(self._password)
2506
2507 self._rememberButton = gtk.CheckButton(xstr("simbrief_remember_password"))
2508 self._rememberButton.set_use_underline(True)
2509 self._rememberButton.set_tooltip_text(xstr("simbrief_remember_tooltip"))
2510 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
2511
2512 label = gtk.Label(xstr("simbrief_extra_fuel"))
2513 label.set_use_underline(True)
2514 label.set_alignment(0.0, 0.5)
2515 table.attach(label, 0, 1, 3, 4)
2516
2517 self._extraFuel = IntegerEntry(defaultValue = 0)
2518 self._extraFuel.set_width_chars(6)
2519 self._extraFuel.set_tooltip_text(xstr("simbrief_extra_fuel_tooltip"))
2520 table.attach(self._extraFuel, 1, 2, 3, 4)
2521 label.set_mnemonic_widget(self._extraFuel)
2522
2523 table.attach(gtk.Label("kg"), 2, 3, 3, 4)
2524
2525 label = gtk.Label(xstr("simbrief_takeoff_runway"))
2526 label.set_use_underline(True)
2527 label.set_alignment(0.0, 0.5)
2528 table.attach(label, 0, 1, 4, 5)
2529
2530 self._takeoffRunway = gtk.Entry()
2531 self._takeoffRunway.set_width_chars(10)
2532 self._takeoffRunway.set_tooltip_text(xstr("simbrief_takeoff_runway_tooltip"))
2533 self._takeoffRunway.connect("changed", self._upperChanged)
2534 table.attach(self._takeoffRunway, 1, 2, 4, 5)
2535 label.set_mnemonic_widget(self._takeoffRunway)
2536
2537 label = gtk.Label(xstr("simbrief_landing_runway"))
2538 label.set_use_underline(True)
2539 label.set_alignment(0.0, 0.5)
2540 table.attach(label, 0, 1, 5, 6)
2541
2542 self._landingRunway = gtk.Entry()
2543 self._landingRunway.set_width_chars(10)
2544 self._landingRunway.set_tooltip_text(xstr("simbrief_takeoff_runway_tooltip"))
2545 self._landingRunway.connect("changed", self._upperChanged)
2546 table.attach(self._landingRunway, 1, 2, 5, 6)
2547 label.set_mnemonic_widget(self._landingRunway)
2548
2549 label = gtk.Label(xstr("simbrief_climb_profile"))
2550 label.set_use_underline(True)
2551 label.set_alignment(0.0, 0.5)
2552 table.attach(label, 0, 1, 6, 7)
2553
2554 self._climbProfile = gtk.ComboBox()
2555 renderer = gtk.CellRendererText()
2556 self._climbProfile.pack_start(renderer, True)
2557 self._climbProfile.add_attribute(renderer, "text", 0)
2558 self._climbProfile.set_tooltip_text(xstr("simbrief_climb_profile_tooltip"))
2559 table.attach(self._climbProfile, 1, 2, 6, 7)
2560 label.set_mnemonic_widget(self._climbProfile)
2561
2562 label = gtk.Label(xstr("simbrief_cruise_profile"))
2563 label.set_use_underline(True)
2564 label.set_alignment(0.0, 0.5)
2565 table.attach(label, 0, 1, 7, 8)
2566
2567 self._cruiseProfile = gtk.ComboBox()
2568 renderer = gtk.CellRendererText()
2569 self._cruiseProfile.pack_start(renderer, True)
2570 self._cruiseProfile.add_attribute(renderer, "text", 0)
2571 self._cruiseProfile.set_tooltip_text(xstr("simbrief_cruise_profile_tooltip"))
2572 table.attach(self._cruiseProfile, 1, 2, 7, 8)
2573 label.set_mnemonic_widget(self._cruiseProfile)
2574
2575 label = gtk.Label(xstr("simbrief_descent_profile"))
2576 label.set_use_underline(True)
2577 label.set_alignment(0.0, 0.5)
2578 table.attach(label, 0, 1, 8, 9)
2579
2580 self._descentProfile = gtk.ComboBox()
2581 renderer = gtk.CellRendererText()
2582 self._descentProfile.pack_start(renderer, True)
2583 self._descentProfile.add_attribute(renderer, "text", 0)
2584 self._descentProfile.set_tooltip_text(xstr("simbrief_descent_profile_tooltip"))
2585 table.attach(self._descentProfile, 1, 2, 8, 9)
2586 label.set_mnemonic_widget(self._descentProfile)
2587
2588 self.addCancelFlightButton()
2589
2590 self._backButton = self.addPreviousButton(clicked = self._backClicked)
2591 self._button = self.addNextButton(clicked = self._forwardClicked)
2592
2593 def activate(self):
2594 """Activate the SimBrief setup page"""
2595 config = self._wizard.gui.config
2596
2597 self._userName.set_text(config.simBriefUserName)
2598 self._userName.set_sensitive(True)
2599
2600 self._password.set_text(config.simBriefPassword)
2601 self._password.set_sensitive(True)
2602
2603 self._rememberButton.set_active(config.rememberSimBriefPassword)
2604 self._rememberButton.set_sensitive(True)
2605
2606 self._extraFuel.set_int(0)
2607 self._extraFuel.set_sensitive(True)
2608
2609 self._takeoffRunway.set_text("")
2610 self._takeoffRunway.set_sensitive(True)
2611
2612 self._landingRunway.set_text("")
2613 self._landingRunway.set_sensitive(True)
2614
2615 simBriefData = self._wizard.gui.flight.aircraft.simBriefData
2616 for (control, profiles) in [(self._climbProfile,
2617 simBriefData.climbProfiles),
2618 (self._cruiseProfile,
2619 simBriefData.cruiseProfiles),
2620 (self._descentProfile,
2621 simBriefData.descentProfiles)]:
2622 model = gtk.ListStore(str)
2623 for profile in profiles:
2624 model.append([profile])
2625 control.set_model(model)
2626 control.set_sensitive(True)
2627
2628 self._climbProfile.set_active(0)
2629 self._cruiseProfile.set_active(0)
2630 self._descentProfile.set_active(0)
2631
2632 self._updateForwardButton()
2633
2634 def _updateForwardButton(self):
2635 """Update the sensitivity of the forward button."""
2636 self._button.set_sensitive(len(self._userName.get_text())>0 and
2637 len(self._password.get_text())>0)
2638
2639 def _backClicked(self, button):
2640 """Called when the Back button is pressed."""
2641 self.goBack()
2642
2643 def _forwardClicked(self, button):
2644 if self._completed:
2645 self._wizard.nextPage()
2646 else:
2647 config = self._wizard.gui.config
2648
2649 config.simBriefUserName = self._userName.get_text()
2650
2651 rememberPassword = self._rememberButton.get_active()
2652 config.simBriefPassword = \
2653 self._password.get_text() if rememberPassword else ""
2654 config.rememberSimBriefPassword = rememberPassword
2655
2656 config.save()
2657
2658 plan = self._getPlan()
2659 print "plan:", plan
2660
2661 takeoffRunway = self._takeoffRunway.get_text()
2662 if takeoffRunway:
2663 self._wizard.takeoffRunway = takeoffRunway
2664
2665 landingRunway = self._landingRunway.get_text()
2666 if landingRunway:
2667 self._wizard.landingRunway = landingRunway
2668
2669 self._userName.set_sensitive(False)
2670 self._password.set_sensitive(False)
2671 self._rememberButton.set_sensitive(False)
2672 self._extraFuel.set_sensitive(False)
2673 self._takeoffRunway.set_sensitive(False)
2674 self._landingRunway.set_sensitive(False)
2675
2676 self._climbProfile.set_sensitive(False)
2677 self._cruiseProfile.set_sensitive(False)
2678 self._descentProfile.set_sensitive(False)
2679
2680 self._wizard.gui.beginBusy(xstr("simbrief_calling"))
2681
2682 cef.callSimBrief(plan,
2683 self._getCredentials,
2684 self._simBriefProgress,
2685 SimBriefSetupPage.getHTMLFilePath())
2686
2687 startSound(const.SOUND_NOTAM)
2688
2689 def _getCredentials(self, count):
2690 """Get the credentials.
2691
2692 If count is 0, the user name and password entered into the setup page
2693 are returned. Otherwise a dialog box is displayed informing the user of
2694 invalid credentials and requesting another set of them."""
2695 print "_getCredentials", count
2696 if count==0:
2697 return (self._userName.get_text(), self._password.get_text())
2698 else:
2699 gui = self._wizard.gui
2700 config = gui.config
2701
2702 dialog = SimBriefCredentialsDialog(gui,
2703 config.simBriefUserName,
2704 config.simBriefPassword,
2705 config.rememberSimBriefPassword)
2706 response = dialog.run()
2707
2708 if response==RESPONSETYPE_OK:
2709 userName = dialog.userName
2710 self._userName.set_text(userName)
2711 password = dialog.password
2712 self._password.set_text(password)
2713 rememberPassword = dialog.rememberPassword
2714
2715 config.simBriefUserName = userName
2716
2717 config.simBriefPassword = \
2718 password if rememberPassword else ""
2719 config.rememberSimBriefPassword = rememberPassword
2720
2721 config.save()
2722
2723 return (userName, password)
2724 else:
2725 return (None, None)
2726
2727 def _simBriefProgress(self, progress, result, flightInfo):
2728 """The real SimBrief progress handler."""
2729 print "_simBriefProgress", progress, result, flightInfo
2730 if result==cef.SIMBRIEF_RESULT_NONE:
2731 message = SimBriefSetupPage.progress2Message.get(progress,
2732 "simbrief_progress_unknown")
2733 self._wizard.gui.updateBusyState(xstr(message))
2734 else:
2735 self._wizard.gui.endBusy()
2736
2737 if result==cef.SIMBRIEF_RESULT_OK:
2738 self._wizard.departureMETARChanged(flightInfo["orig_metar"],
2739 self)
2740 self._wizard.arrivalMETARChanged(flightInfo["dest_metar"], self)
2741 self._wizard.nextPage()
2742 else:
2743 message = SimBriefSetupPage.result2Message.get(result,
2744 "simbrief_result_unknown")
2745 dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
2746 type = MESSAGETYPE_ERROR,
2747 message_format =
2748 xstr(message) + "\n"+
2749 xstr("simbrief_cancelled"))
2750
2751 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
2752 dialog.set_title(WINDOW_TITLE_BASE)
2753 secondary = xstr("flightsel_save_failed_sec")
2754 dialog.format_secondary_markup(secondary)
2755 dialog.run()
2756 dialog.hide()
2757
2758 self._wizard.usingSimBrief = False
2759 self._wizard.jumpPage("fuel", fromPageShift = 1)
2760
2761 def _getPlan(self):
2762 """Get the flight plan data for SimBrief."""
2763 plan = {
2764 "airline": "MAH",
2765 "selcal": "XXXX",
2766 "fuelfactor": "P000",
2767 "contpct": "0.05",
2768 "resvrule": "45",
2769 "taxiout": "10",
2770 "taxiin": "10",
2771 "civalue": "AUTO"
2772 }
2773
2774 wizard = self._wizard
2775 gui = wizard.gui
2776
2777 loginResult = wizard.loginResult
2778 plan["cpt"] = loginResult.pilotName
2779 plan["pid"] = loginResult.pilotID
2780
2781 bookedFlight = wizard.bookedFlight
2782 plan["fltnum"] = wizard.bookedFlight.callsign[2:]
2783 plan["type"] = const.icaoCodes[bookedFlight.aircraftType]
2784 plan["orig"] = bookedFlight.departureICAO
2785 plan["dest"] = bookedFlight.arrivalICAO
2786 plan["reg"] = bookedFlight.tailNumber
2787 plan["fin"] = bookedFlight.tailNumber[3:]
2788 plan["pax"] = str(bookedFlight.numPassengers)
2789
2790 departureTime = bookedFlight.departureTime
2791 plan["date"] = "%d%s%d" % (departureTime.day,
2792 SimBriefSetupPage.monthNum2Name[departureTime.month-1],
2793 departureTime.year%100)
2794 plan["deph"] = str(departureTime.hour)
2795 plan["depm"] = str(departureTime.minute)
2796
2797 arrivalTime = bookedFlight.arrivalTime
2798 plan["steh"] = str(arrivalTime.hour)
2799 plan["stem"] = str(arrivalTime.minute)
2800
2801 plan["manualzfw"] = str(wizard.zfw / 1000.0)
2802 plan["cargo"] = str((wizard.bagWeight + wizard.cargoWeight + wizard.mailWeight)/1000.0)
2803
2804 plan["route"] = wizard.route
2805 plan["fl"] = str(wizard.filedCruiseAltitude)
2806 plan["altn"] = wizard.alternate
2807
2808 plan["addedfuel"] = str(self._extraFuel.get_int() / 1000.0)
2809 plan["origrwy"] = self._takeoffRunway.get_text()
2810 plan["destrwy"] = self._landingRunway.get_text()
2811
2812 for (key, control) in [("climb", self._climbProfile),
2813 ("cruise", self._cruiseProfile),
2814 ("descent", self._descentProfile)]:
2815 model = control.get_model()
2816 active = control.get_active_iter()
2817 value = model.get_value(active, 0)
2818 plan[key] = value
2819
2820 return plan
2821
2822 def _upperChanged(self, entry, arg = None):
2823 """Called when the value of some entry widget has changed and the value
2824 should be converted to uppercase."""
2825 entry.set_text(entry.get_text().upper())
2826
2827#-----------------------------------------------------------------------------
2828
2829class SimBriefingPage(Page):
2830 """Page to display the SimBrief HTML briefing."""
2831 class BrowserLifeSpanHandler(object):
2832 """The life-span handler of a browser."""
2833 def __init__(self, simBriefingPage):
2834 """Construct the life-span handler for the given page."""
2835 self._simBriefingPage = simBriefingPage
2836
2837 def OnBeforeClose(self, browser):
2838 """Called before closing the browser."""
2839 self._simBriefingPage._invalidateBrowser()
2840
2841 def __init__(self, wizard):
2842 """Construct the setup page."""
2843
2844 super(SimBriefingPage, self).__init__(wizard, "simbrief_result",
2845 xstr("simbrief_result_title"), "")
2846
2847 self._alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2848 xscale = 1.0, yscale = 1.0)
2849
2850 self._container = cef.getContainer()
2851 self._alignment.add(self._container)
2852
2853 self.setMainWidget(self._alignment)
2854
2855 self._browser = None
2856
2857 self.addCancelFlightButton()
2858
2859 self.addPreviousButton(clicked = self._backClicked)
2860
2861 self._button = self.addNextButton(clicked = self._forwardClicked)
2862 self._button.set_label(xstr("briefing_button"))
2863 self._button.set_has_tooltip(False)
2864 self._button.set_use_stock(False)
2865
2866 def activate(self):
2867 """Activate the SimBrief flight plan page"""
2868 if self._browser is None:
2869 self._startBrowser()
2870 else:
2871 self._browser.Reload()
2872
2873 def grabDefault(self):
2874 """If the page has a default button, make it the default one."""
2875 super(SimBriefingPage, self).grabDefault()
2876
2877 if self._browser is None:
2878 self._startBrowser()
2879
2880 def _backClicked(self, button):
2881 """Called when the Back button has been pressed."""
2882 self.goBack()
2883
2884 def _forwardClicked(self, button):
2885 """Called when the Forward button has been pressed."""
2886 if not self._completed:
2887 self._button.set_label(xstr("button_next"))
2888 self._button.set_tooltip_text(xstr("button_next_tooltip"))
2889 self._wizard.usingSimBrief = True
2890 self.complete()
2891
2892 self._wizard.nextPage()
2893
2894 def _startBrowser(self):
2895 """Start the browser.
2896
2897 If a container is needed, create one."""
2898 if self._container is None:
2899 self._container = cef.getContainer()
2900 self._alignment.add(self._container)
2901
2902 url = "file://" + SimBriefSetupPage.getHTMLFilePath()
2903 self._browser = cef.startInContainer(self._container, url)
2904
2905 lifeSpanHandler = SimBriefingPage.BrowserLifeSpanHandler(self)
2906 self._browser.SetClientHandler(lifeSpanHandler)
2907
2908 def _invalidateBrowser(self):
2909 """Invalidate the browser (and associated stuff)."""
2910 self._alignment.remove(self._container)
2911 self._container = None
2912 self._browser = None
2913
2914#-----------------------------------------------------------------------------
2915
2916class FuelTank(gtk.VBox):
2917 """Widget for the fuel tank."""
2918 def __init__(self, fuelTank, name, capacity, currentWeight):
2919 """Construct the widget for the tank with the given name."""
2920 super(FuelTank, self).__init__()
2921
2922 self._enabled = True
2923 self.fuelTank = fuelTank
2924 self.capacity = capacity
2925 self.currentWeight = currentWeight
2926 self.expectedWeight = currentWeight
2927
2928 label = gtk.Label("<b>" + name + "</b>")
2929 label.set_use_markup(True)
2930 label.set_use_underline(True)
2931 label.set_justify(JUSTIFY_CENTER)
2932 label.set_alignment(0.5, 1.0)
2933 self.pack_start(label, False, False, 4)
2934
2935 self._tankFigure = gtk.EventBox()
2936 self._tankFigure.set_size_request(38, -1)
2937 self._tankFigure.set_visible_window(False)
2938 self._tankFigure.set_tooltip_markup(xstr("fuel_tank_tooltip"))
2939
2940 if pygobject:
2941 self._tankFigure.connect("draw", self._drawTankFigure)
2942 else:
2943 self._tankFigure.connect("expose_event", self._drawTankFigure)
2944 self._tankFigure.connect("button_press_event", self._buttonPressed)
2945 self._tankFigure.connect("motion_notify_event", self._motionNotify)
2946 self._tankFigure.connect("scroll-event", self._scrolled)
2947
2948 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2949 xscale = 0.0, yscale = 1.0)
2950 alignment.add(self._tankFigure)
2951
2952 self.pack_start(alignment, True, True, 4)
2953
2954 self._expectedButton = gtk.SpinButton()
2955 self._expectedButton.set_numeric(True)
2956 self._expectedButton.set_range(0, self.capacity)
2957 self._expectedButton.set_increments(10, 100)
2958 self._expectedButton.set_value(currentWeight)
2959 self._expectedButton.set_alignment(1.0)
2960 self._expectedButton.set_width_chars(5)
2961 self._expectedButton.connect("value-changed", self._expectedChanged)
2962
2963 label.set_mnemonic_widget(self._expectedButton)
2964
2965 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2966 xscale = 0.0, yscale = 1.0)
2967 alignment.add(self._expectedButton)
2968 self.pack_start(alignment, False, False, 4)
2969
2970 def setCurrent(self, currentWeight):
2971 """Set the current weight."""
2972 self.currentWeight = currentWeight
2973 self._redraw()
2974
2975 def isCorrect(self):
2976 """Determine if the contents of the fuel tank are as expected"""
2977 return abs(self.expectedWeight - self.currentWeight)<=1
2978
2979 def disable(self):
2980 """Disable the fuel tank."""
2981 self._expectedButton.set_sensitive(False)
2982 self._enabled = False
2983
2984 def _redraw(self):
2985 """Redraw the tank figure."""
2986 self._tankFigure.queue_draw()
2987
2988 def _drawTankFigure(self, tankFigure, eventOrContext):
2989 """Draw the tank figure."""
2990 triangleSize = 5
2991
2992 context = eventOrContext if pygobject else tankFigure.window.cairo_create()
2993 (xOffset, yOffset) = (0, 0) if pygobject \
2994 else (tankFigure.allocation.x, tankFigure.allocation.y)
2995
2996 width = tankFigure.get_allocated_width() if pygobject \
2997 else tankFigure.allocation.width
2998 height = tankFigure.get_allocated_height() if pygobject \
2999 else tankFigure.allocation.height
3000
3001 rectangleX0 = triangleSize
3002 rectangleY0 = triangleSize
3003 rectangleX1 = width - 1 - triangleSize
3004 rectangleY1 = height - 1 - triangleSize
3005 rectangleLineWidth = 2.0
3006
3007 context.set_source_rgb(0.0, 0.0, 0.0)
3008 context.set_line_width(rectangleLineWidth)
3009 context.rectangle(xOffset + rectangleX0 + rectangleLineWidth/2,
3010 yOffset + rectangleY0 + rectangleLineWidth/2,
3011 rectangleX1 - rectangleX0 - rectangleLineWidth,
3012 rectangleY1 - rectangleY0 - rectangleLineWidth)
3013 context.stroke()
3014
3015 rectangleInnerLeft = rectangleX0 + rectangleLineWidth
3016 rectangleInnerRight = rectangleX1 - rectangleLineWidth
3017 self._rectangleInnerTop = rectangleInnerTop = rectangleY0 + rectangleLineWidth
3018 self._rectangleInnerBottom = rectangleInnerBottom = rectangleY1 - rectangleLineWidth
3019
3020 rectangleInnerWidth = rectangleInnerRight - rectangleInnerLeft
3021 rectangleInnerHeight = rectangleInnerBottom - rectangleInnerTop
3022
3023 context.set_source_rgb(1.0, 0.9, 0.6)
3024 currentHeight = self.currentWeight * rectangleInnerHeight / self.capacity
3025 currentX = rectangleInnerTop + rectangleInnerHeight - currentHeight
3026 context.rectangle(xOffset + rectangleInnerLeft,
3027 yOffset + rectangleInnerTop +
3028 rectangleInnerHeight - currentHeight,
3029 rectangleInnerWidth, currentHeight)
3030 context.fill()
3031
3032 expectedHeight = self.expectedWeight * rectangleInnerHeight / self.capacity
3033 expectedY = rectangleInnerTop + rectangleInnerHeight - expectedHeight
3034
3035 context.set_line_width(1.5)
3036 context.set_source_rgb(0.0, 0.85, 0.85)
3037 context.move_to(xOffset + rectangleX0, yOffset + expectedY)
3038 context.line_to(xOffset + rectangleX1, yOffset + expectedY)
3039 context.stroke()
3040
3041 context.set_line_width(0.0)
3042 context.move_to(xOffset + 0, yOffset + expectedY - triangleSize)
3043 context.line_to(xOffset + 0, yOffset + expectedY + triangleSize)
3044 context.line_to(xOffset + rectangleX0 + 1, yOffset + expectedY)
3045 context.line_to(xOffset + 0, yOffset + expectedY - triangleSize)
3046 context.fill()
3047
3048 context.set_line_width(0.0)
3049 context.move_to(xOffset + width, yOffset + expectedY - triangleSize)
3050 context.line_to(xOffset + width, yOffset + expectedY + triangleSize)
3051 context.line_to(xOffset + rectangleX1 - 1, yOffset + expectedY)
3052 context.line_to(xOffset + width, yOffset + expectedY - triangleSize)
3053 context.fill()
3054
3055 return True
3056
3057 def _setExpectedFromY(self, y):
3058 """Set the expected weight from the given Y-coordinate."""
3059 level = (self._rectangleInnerBottom - y) / \
3060 (self._rectangleInnerBottom - self._rectangleInnerTop)
3061 level = min(1.0, max(0.0, level))
3062 self._expectedButton.set_value(level * self.capacity)
3063
3064 def _buttonPressed(self, tankFigure, event):
3065 """Called when a button is pressed in the figure.
3066
3067 The expected level will be set there."""
3068 if self._enabled and event.button==1:
3069 self._setExpectedFromY(event.y)
3070
3071 def _motionNotify(self, tankFigure, event):
3072 """Called when the mouse pointer moves within the area of a tank figure."""
3073 if self._enabled and event.state==BUTTON1_MASK:
3074 self._setExpectedFromY(event.y)
3075
3076 def _scrolled(self, tankFigure, event):
3077 """Called when a scroll event is received."""
3078 if self._enabled:
3079 increment = 1 if event.state==CONTROL_MASK \
3080 else 100 if event.state==SHIFT_MASK \
3081 else 10 if event.state==0 else 0
3082 if increment!=0:
3083 if event.direction==SCROLL_DOWN:
3084 increment *= -1
3085 self._expectedButton.spin(SPIN_USER_DEFINED, increment)
3086
3087 def _expectedChanged(self, spinButton):
3088 """Called when the expected value has changed."""
3089 self.expectedWeight = spinButton.get_value_as_int()
3090 self._redraw()
3091
3092#-----------------------------------------------------------------------------
3093
3094class FuelPage(Page):
3095 """The page containing the fuel tank filling."""
3096 _pumpStep = 0.02
3097
3098 def __init__(self, wizard):
3099 """Construct the page."""
3100 super(FuelPage, self).__init__(wizard, "fuel",
3101 xstr("fuel_title"),
3102 xstr("fuel_help_pre") +
3103 xstr("fuel_help_post"),
3104 completedHelp = xstr("fuel_chelp"))
3105
3106 self._fuelTanks = []
3107 self._fuelTable = None
3108 self._fuelAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
3109 xscale = 0.0, yscale = 1.0)
3110 self.setMainWidget(self._fuelAlignment)
3111
3112 tankData = [(tank, 2500, 3900) for tank in acft.mostFuelTanks]
3113 self._setupTanks(tankData)
3114
3115 self.addCancelFlightButton()
3116
3117 self._backButton = self.addPreviousButton(clicked = self._backClicked)
3118 self._button = self.addNextButton(clicked = self._forwardClicked)
3119
3120 self._pumpIndex = 0
3121
3122 def activate(self):
3123 """Activate the page."""
3124 self._setupTanks(self._wizard._fuelData)
3125
3126 aircraft = self._wizard.gui.flight.aircraft
3127 minLandingFuel = aircraft.minLandingFuel
3128 recommendedLandingFuel = aircraft.recommendedLandingFuel
3129
3130 middleHelp = "" if minLandingFuel is None else \
3131 (xstr("fuel_help_min") % (minLandingFuel,)) \
3132 if recommendedLandingFuel is None else \
3133 (xstr("fuel_help_min_rec") % (minLandingFuel,
3134 recommendedLandingFuel))
3135 self.setHelp(xstr("fuel_help_pre") + middleHelp + xstr("fuel_help_post"))
3136
3137 def finalize(self):
3138 """Finalize the page."""
3139 for fuelTank in self._fuelTanks:
3140 fuelTank.disable()
3141
3142 def _backClicked(self, button):
3143 """Called when the Back button is pressed."""
3144 self.goBack()
3145
3146 def _forwardClicked(self, button):
3147 """Called when the forward button is clicked."""
3148 if not self._completed:
3149 self._pumpIndex = 0
3150 self._wizard.gui.beginBusy(xstr("fuel_pump_busy"))
3151 self._pump()
3152 elif self._wizard.usingSimBrief:
3153 self._wizard.jumpPage("takeoff")
3154 else:
3155 self._wizard.jumpPage("briefing1")
3156
3157 def _setupTanks(self, tankData):
3158 """Setup the tanks for the given data."""
3159 numTanks = len(tankData)
3160 if self._fuelTable is not None:
3161 self._fuelAlignment.remove(self._fuelTable)
3162
3163 self._fuelTanks = []
3164 self._fuelTable = gtk.Table(numTanks, 1)
3165 self._fuelTable.set_col_spacings(16)
3166 index = 0
3167 for (tank, current, capacity) in tankData:
3168 fuelTank = FuelTank(tank,
3169 xstr("fuel_tank_" +
3170 const.fuelTank2string(tank)),
3171 capacity, current)
3172 self._fuelTable.attach(fuelTank, index, index+1, 0, 1)
3173 self._fuelTanks.append(fuelTank)
3174 index += 1
3175
3176 self._fuelAlignment.add(self._fuelTable)
3177 self.show_all()
3178
3179 def _pump(self):
3180 """Perform one step of pumping.
3181
3182 It is checked, if the current tank's contents are of the right
3183 quantity. If not, it is filled one step further to the desired
3184 contents. Otherwise the next tank is started. If all tanks are are
3185 filled, the next page is selected."""
3186 numTanks = len(self._fuelTanks)
3187
3188 fuelTank = None
3189 while self._pumpIndex < numTanks:
3190 fuelTank = self._fuelTanks[self._pumpIndex]
3191 if fuelTank.isCorrect():
3192 self._pumpIndex += 1
3193 fuelTank = None
3194 else:
3195 break
3196
3197 if fuelTank is None:
3198 self._wizard.gui.endBusy()
3199 if self._wizard.usingSimBrief:
3200 self._wizard.gui.startMonitoring()
3201 self._wizard.jumpPage("takeoff")
3202 else:
3203 bookedFlight = self._wizard._bookedFlight
3204 self._wizard.gui.beginBusy(xstr("route_down_notams"))
3205 self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
3206 bookedFlight.departureICAO,
3207 bookedFlight.arrivalICAO)
3208 startSound(const.SOUND_NOTAM)
3209 else:
3210 currentLevel = fuelTank.currentWeight / fuelTank.capacity
3211 expectedLevel = fuelTank.expectedWeight / fuelTank.capacity
3212 if currentLevel<expectedLevel:
3213 currentLevel += FuelPage._pumpStep
3214 if currentLevel>expectedLevel: currentLevel = expectedLevel
3215 else:
3216 currentLevel -= FuelPage._pumpStep
3217 if currentLevel<expectedLevel: currentLevel = expectedLevel
3218 fuelTank.setCurrent(currentLevel * fuelTank.capacity)
3219 self._wizard.gui.simulator.setFuelLevel([(fuelTank.fuelTank,
3220 currentLevel)])
3221 gobject.timeout_add(50, self._pump)
3222
3223 def _notamsCallback(self, returned, result):
3224 """Callback for the NOTAMs."""
3225 gobject.idle_add(self._handleNOTAMs, returned, result)
3226
3227 def _handleNOTAMs(self, returned, result):
3228 """Handle the NOTAMs."""
3229 if returned:
3230 self._wizard._departureNOTAMs = result.departureNOTAMs
3231 self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
3232 else:
3233 self._wizard._departureNOTAMs = None
3234 self._wizard._arrivalNOTAMs = None
3235
3236 bookedFlight = self._wizard._bookedFlight
3237 self._wizard.gui.beginBusy(xstr("route_down_metars"))
3238 self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
3239 [bookedFlight.departureICAO,
3240 bookedFlight.arrivalICAO])
3241
3242 def _metarsCallback(self, returned, result):
3243 """Callback for the METARs."""
3244 gobject.idle_add(self._handleMETARs, returned, result)
3245
3246 def _handleMETARs(self, returned, result):
3247 """Handle the METARs."""
3248 self._wizard._departureMETAR = None
3249 self._wizard._arrivalMETAR = None
3250 bookedFlight = self._wizard._bookedFlight
3251 if returned:
3252 if bookedFlight.departureICAO in result.metars:
3253 self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
3254 if bookedFlight.arrivalICAO in result.metars:
3255 self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
3256
3257 self._wizard.gui.endBusy()
3258 self._backButton.set_sensitive(True)
3259 self._button.set_sensitive(True)
3260 self._wizard.nextPage()
3261
3262#-----------------------------------------------------------------------------
3263
3264class BriefingPage(Page):
3265 """Page for the briefing."""
3266 def __init__(self, wizard, departure):
3267 """Construct the briefing page."""
3268 self._departure = departure
3269
3270 number = 1 if departure else 2
3271
3272 title = xstr("briefing_title") % (number,
3273 xstr("briefing_departure")
3274 if departure
3275 else xstr("briefing_arrival"))
3276 super(BriefingPage, self).__init__(wizard,
3277 "briefing%d" % (number,),
3278 title, xstr("briefing_help"),
3279 completedHelp = xstr("briefing_chelp"))
3280
3281 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
3282 xscale = 1.0, yscale = 1.0)
3283
3284 mainBox = gtk.VBox()
3285 alignment.add(mainBox)
3286 self.setMainWidget(alignment)
3287
3288 self._notamsFrame = gtk.Frame()
3289 self._notamsFrame.set_label(xstr("briefing_notams_init"))
3290 scrolledWindow = gtk.ScrolledWindow()
3291 scrolledWindow.set_size_request(-1, 128)
3292 # FIXME: these constants should be in common
3293 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
3294 else gtk.POLICY_AUTOMATIC,
3295 gtk.PolicyType.AUTOMATIC if pygobject
3296 else gtk.POLICY_AUTOMATIC)
3297 self._notams = gtk.TextView()
3298 self._notams.set_editable(False)
3299 self._notams.set_accepts_tab(False)
3300 self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
3301 scrolledWindow.add(self._notams)
3302 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
3303 xscale = 1.0, yscale = 1.0)
3304 alignment.set_padding(padding_top = 4, padding_bottom = 0,
3305 padding_left = 0, padding_right = 0)
3306 alignment.add(scrolledWindow)
3307 self._notamsFrame.add(alignment)
3308 mainBox.pack_start(self._notamsFrame, True, True, 4)
3309
3310 self._metarFrame = gtk.Frame()
3311 self._metarFrame.set_label(xstr("briefing_metar_init"))
3312 scrolledWindow = gtk.ScrolledWindow()
3313 scrolledWindow.set_size_request(-1, 32)
3314 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
3315 else gtk.POLICY_AUTOMATIC,
3316 gtk.PolicyType.AUTOMATIC if pygobject
3317 else gtk.POLICY_AUTOMATIC)
3318
3319 self._updatingMETAR = False
3320
3321 self._metar = gtk.TextView()
3322 self._metar.set_accepts_tab(False)
3323 self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
3324 self._metar.get_buffer().connect("changed", self._metarChanged)
3325 self._metar.get_buffer().connect_after("insert-text", self._metarInserted)
3326 scrolledWindow.add(self._metar)
3327 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
3328 xscale = 1.0, yscale = 1.0)
3329 alignment.set_padding(padding_top = 4, padding_bottom = 0,
3330 padding_left = 0, padding_right = 0)
3331 alignment.add(scrolledWindow)
3332 self._metarFrame.add(alignment)
3333 mainBox.pack_start(self._metarFrame, True, True, 4)
3334 self.metarEdited = False
3335
3336 self.addCancelFlightButton()
3337
3338 self.addPreviousButton(clicked = self._backClicked)
3339 self._button = self.addNextButton(clicked = self._forwardClicked)
3340
3341 @property
3342 def metar(self):
3343 """Get the METAR on the page."""
3344 buffer = self._metar.get_buffer()
3345 return buffer.get_text(buffer.get_start_iter(),
3346 buffer.get_end_iter(), True)
3347
3348 def setMETAR(self, metar):
3349 """Set the METAR."""
3350 self._metar.get_buffer().set_text(metar)
3351 self.metarEdited = False
3352
3353 def changeMETAR(self, metar):
3354 """Change the METAR as a result of an edit on one of the other
3355 pages."""
3356 self._updatingMETAR = True
3357 self._metar.get_buffer().set_text(metar)
3358 self._updatingMETAR = False
3359
3360 self._updateButton()
3361 self.metarEdited = True
3362
3363 def activate(self):
3364 """Activate the page."""
3365 if not self._departure:
3366 self._button.set_label(xstr("briefing_button"))
3367 self._button.set_has_tooltip(False)
3368 self._button.set_use_stock(False)
3369
3370 bookedFlight = self._wizard._bookedFlight
3371
3372 icao = bookedFlight.departureICAO if self._departure \
3373 else bookedFlight.arrivalICAO
3374 notams = self._wizard._departureNOTAMs if self._departure \
3375 else self._wizard._arrivalNOTAMs
3376 metar = self._wizard._departureMETAR if self._departure \
3377 else self._wizard._arrivalMETAR
3378
3379 self._notamsFrame.set_label(xstr("briefing_notams_template") % (icao,))
3380 buffer = self._notams.get_buffer()
3381 if notams is None:
3382 buffer.set_text(xstr("briefing_notams_failed"))
3383 elif not notams:
3384 buffer.set_text(xstr("briefing_notams_missing"))
3385 else:
3386 s = ""
3387 for notam in notams:
3388 s += str(notam)
3389 s += "-------------------- * --------------------\n"
3390 buffer.set_text(s)
3391
3392 self._metarFrame.set_label(xstr("briefing_metar_template") % (icao,))
3393 buffer = self._metar.get_buffer()
3394 self._updatingMETAR = True
3395 if metar is None:
3396 buffer.set_text("")
3397 self.setHelp(xstr("briefing_help_nometar"))
3398 else:
3399 buffer.set_text(metar)
3400 self._updatingMETAR = False
3401 self._updateButton()
3402
3403 label = self._metarFrame.get_label_widget()
3404 label.set_use_underline(True)
3405 label.set_mnemonic_widget(self._metar)
3406
3407 self.metarEdited = False
3408
3409 def _backClicked(self, button):
3410 """Called when the Back button is pressed."""
3411 self.goBack()
3412
3413 def _forwardClicked(self, button):
3414 """Called when the forward button is clicked."""
3415 if not self._departure:
3416 if not self._completed:
3417 self._wizard.gui.startMonitoring()
3418 self._button.set_label(xstr("button_next"))
3419 self._button.set_tooltip_text(xstr("button_next_tooltip"))
3420 self.complete()
3421
3422 self._wizard.nextPage()
3423
3424 def _metarChanged(self, buffer):
3425 """Called when the METAR has changed."""
3426 print "BriefingPage.metarChanged", self._updatingMETAR
3427 if not self._updatingMETAR:
3428 self.metarEdited = True
3429 self._updateButton()
3430 metar = buffer.get_text(buffer.get_start_iter(),
3431 buffer.get_end_iter(), True)
3432 self._wizard.metarChanged(metar, self)
3433
3434 def _metarInserted(self, textBuffer, iter, text, length):
3435 """Called when new characters are inserted into the METAR.
3436
3437 It uppercases all characters."""
3438 print "BriefingPage.metarInserted", self._updatingMETAR
3439 if not self._updatingMETAR:
3440 self._updatingMETAR = True
3441
3442 iter1 = iter.copy()
3443 iter1.backward_chars(length)
3444 textBuffer.delete(iter, iter1)
3445
3446 textBuffer.insert(iter, text.upper())
3447
3448 self._updatingMETAR = False
3449
3450 def _updateButton(self):
3451 """Update the sensitivity of the Next button based on the contents of
3452 the METAR field."""
3453 buffer = self._metar.get_buffer()
3454 self._button.set_sensitive(buffer.get_text(buffer.get_start_iter(),
3455 buffer.get_end_iter(),
3456 True)!="")
3457
3458
3459#-----------------------------------------------------------------------------
3460
3461class TakeoffPage(Page):
3462 """Page for entering the takeoff data."""
3463 def __init__(self, wizard):
3464 """Construct the takeoff page."""
3465 super(TakeoffPage, self).__init__(wizard, "takeoff",
3466 xstr("takeoff_title"),
3467 xstr("takeoff_help"),
3468 completedHelp = xstr("takeoff_chelp"))
3469
3470 self._forwardAllowed = False
3471
3472 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
3473 xscale = 0.0, yscale = 0.0)
3474
3475 table = gtk.Table(9, 24)
3476 table.set_row_spacings(4)
3477 table.set_col_spacings(16)
3478 table.set_homogeneous(False)
3479 alignment.add(table)
3480 self.setMainWidget(alignment)
3481
3482 row = 0
3483
3484 label = gtk.Label(xstr("takeoff_metar"))
3485 label.set_use_underline(True)
3486 label.set_alignment(0.0, 0.5)
3487 table.attach(label, 0, 1, row, row+1)
3488
3489 self._metar = gtk.Entry()
3490 self._metar.set_width_chars(40)
3491 self._metar.set_tooltip_text(xstr("takeoff_metar_tooltip"))
3492 self._metar.connect("changed", self._metarChanged)
3493 self._metar.get_buffer().connect_after("inserted-text", self._metarInserted)
3494 table.attach(self._metar, 1, 24, row, row+1)
3495 label.set_mnemonic_widget(self._metar)
3496
3497 self._updatingMETAR = False
3498
3499 row += 1
3500
3501 label = gtk.Label(xstr("takeoff_runway"))
3502 label.set_use_underline(True)
3503 label.set_alignment(0.0, 0.5)
3504 table.attach(label, 0, 1, row, row+1)
3505
3506 self._runway = gtk.Entry()
3507 self._runway.set_width_chars(10)
3508 self._runway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
3509 self._runway.connect("changed", self._upperChanged)
3510 table.attach(self._runway, 1, 3, row, row+1)
3511 label.set_mnemonic_widget(self._runway)
3512
3513 row += 1
3514
3515 label = gtk.Label(xstr("takeoff_sid"))
3516 label.set_use_underline(True)
3517 label.set_alignment(0.0, 0.5)
3518 table.attach(label, 0, 1, row, row+1)
3519
3520 if pygobject:
3521 self._sid = gtk.ComboBox.new_with_model_and_entry(comboModel)
3522 else:
3523 self._sid = gtk.ComboBoxEntry(comboModel)
3524
3525 self._sid.set_entry_text_column(0)
3526 self._sid.get_child().set_width_chars(10)
3527 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
3528 self._sid.connect("changed", self._upperChangedComboBox)
3529 table.attach(self._sid, 1, 3, row, row+1)
3530 label.set_mnemonic_widget(self._sid)
3531
3532 row += 1
3533
3534 label = gtk.Label(xstr("takeoff_v1"))
3535 label.set_use_markup(True)
3536 label.set_use_underline(True)
3537 label.set_alignment(0.0, 0.5)
3538 table.attach(label, 0, 1, row, row+1)
3539
3540 self._v1 = IntegerEntry()
3541 self._v1.set_width_chars(4)
3542 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip_knots"))
3543 self._v1.connect("integer-changed", self._valueChanged)
3544 table.attach(self._v1, 2, 3, row, row+1)
3545 label.set_mnemonic_widget(self._v1)
3546
3547 self._v1Unit = gtk.Label(xstr("label_knots"))
3548 self._v1Unit.set_alignment(0.0, 0.5)
3549 table.attach(self._v1Unit, 3, 4, row, row+1)
3550
3551 row += 1
3552
3553 label = gtk.Label(xstr("takeoff_vr"))
3554 label.set_use_markup(True)
3555 label.set_use_underline(True)
3556 label.set_alignment(0.0, 0.5)
3557 table.attach(label, 0, 1, row, row+1)
3558
3559 self._vr = IntegerEntry()
3560 self._vr.set_width_chars(4)
3561 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip_knots"))
3562 self._vr.connect("integer-changed", self._valueChanged)
3563 table.attach(self._vr, 2, 3, row, row+1)
3564 label.set_mnemonic_widget(self._vr)
3565
3566 self._vrUnit = gtk.Label(xstr("label_knots"))
3567 self._vrUnit.set_alignment(0.0, 0.5)
3568 table.attach(self._vrUnit, 3, 4, row, row+1)
3569
3570 row += 1
3571
3572 label = gtk.Label(xstr("takeoff_v2"))
3573 label.set_use_markup(True)
3574 label.set_use_underline(True)
3575 label.set_alignment(0.0, 0.5)
3576 table.attach(label, 0, 1, row, row+1)
3577
3578 self._v2 = IntegerEntry()
3579 self._v2.set_width_chars(4)
3580 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip_knots"))
3581 self._v2.connect("integer-changed", self._valueChanged)
3582 table.attach(self._v2, 2, 3, row, row+1)
3583 label.set_mnemonic_widget(self._v2)
3584
3585 self._v2Unit = gtk.Label(xstr("label_knots"))
3586 self._v2Unit.set_alignment(0.0, 0.5)
3587 table.attach(self._v2Unit, 3, 4, row, row+1)
3588
3589 row += 1
3590
3591 self._derateType = acft.DERATE_NONE
3592
3593 self._derateLabel = gtk.Label()
3594 self._derateLabel.set_use_underline(True)
3595 self._derateLabel.set_markup(xstr("takeoff_derate_tupolev"))
3596 self._derateLabel.set_alignment(0.0, 0.5)
3597 table.attach(self._derateLabel, 0, 1, row, row+1)
3598
3599 self._derate = gtk.Alignment()
3600 table.attach(self._derate, 2, 4, row, row+1)
3601 self._derateWidget = None
3602 self._derateEntry = None
3603 self._derateUnit = None
3604 self._derateButtons = None
3605
3606 row += 1
3607
3608 self._antiIceOn = gtk.CheckButton(xstr("takeoff_antiice"))
3609 self._antiIceOn.set_use_underline(True)
3610 self._antiIceOn.set_tooltip_text(xstr("takeoff_antiice_tooltip"))
3611 table.attach(self._antiIceOn, 2, 4, row, row+1)
3612
3613 row += 1
3614
3615 self._rto = gtk.CheckButton(xstr("takeoff_rto"))
3616 self._rto.set_use_underline(True)
3617 self._rto.set_tooltip_text(xstr("takeoff_rto_tooltip"))
3618 self._rto.connect("toggled", self._rtoToggled)
3619 table.attach(self._rto, 2, 4, row, row+1, ypadding = 8)
3620
3621 self.addCancelFlightButton()
3622
3623 self.addPreviousButton(clicked = self._backClicked)
3624
3625 self._button = self.addNextButton(clicked = self._forwardClicked)
3626
3627 self._active = False
3628
3629 @property
3630 def runway(self):
3631 """Get the runway."""
3632 return self._runway.get_text()
3633
3634 @property
3635 def sid(self):
3636 """Get the SID."""
3637 text = self._sid.get_child().get_text()
3638 return text if self._sid.get_active()!=0 and text and text!="N/A" \
3639 else None
3640
3641 @property
3642 def v1(self):
3643 """Get the v1 speed."""
3644 return self._v1.get_int()
3645
3646 @property
3647 def vr(self):
3648 """Get the vr speed."""
3649 return self._vr.get_int()
3650
3651 @property
3652 def v2(self):
3653 """Get the v2 speed."""
3654 return self._v2.get_int()
3655
3656 @property
3657 def derate(self):
3658 """Get the derate value, if any."""
3659 if self._derateWidget is None:
3660 return None
3661 if self._derateType==acft.DERATE_BOEING:
3662 derate = self._derateEntry.get_text()
3663 return derate if derate else None
3664 elif self._derateType==acft.DERATE_EPR:
3665 derate = self._derateWidget.get_text()
3666 return derate if derate else None
3667 elif self._derateType==acft.DERATE_TUPOLEV:
3668 return acft.DERATE_TUPOLEV_NOMINAL \
3669 if self._derateButtons[0].get_active() \
3670 else acft.DERATE_TUPOLEV_TAKEOFF
3671 elif self._derateType==acft.DERATE_B462:
3672 return self._derateWidget.get_active()
3673 else:
3674 return None
3675
3676 @property
3677 def antiIceOn(self):
3678 """Get whether the anti-ice system has been turned on."""
3679 return self._antiIceOn.get_active()
3680
3681 @antiIceOn.setter
3682 def antiIceOn(self, value):
3683 """Set the anti-ice indicator."""
3684 self._antiIceOn.set_active(value)
3685
3686 @property
3687 def rtoIndicated(self):
3688 """Get whether the pilot has indicated if there was an RTO."""
3689 return self._rto.get_active()
3690
3691 def activate(self):
3692 """Activate the page."""
3693 print "TakeoffPage.activate"
3694
3695 self._updatingMETAR = True
3696 self._metar.get_buffer().set_text(self._wizard.departureMETAR, -1)
3697 self._updatingMETAR = False
3698
3699 if self._wizard.takeoffRunway is None:
3700 self._runway.set_text("")
3701 else:
3702 self._runway.set_text(self._wizard.takeoffRunway)
3703 self._runway.set_sensitive(True)
3704 self._sid.set_active(0)
3705 self._sid.set_sensitive(True)
3706 self._v1.set_int(None)
3707 self._v1.set_sensitive(True)
3708 self._vr.set_int(None)
3709 self._vr.set_sensitive(True)
3710 self._v2.set_int(None)
3711 self._v2.set_sensitive(True)
3712
3713 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
3714 speedUnit = xstr("label" + i18nSpeedUnit)
3715 self._v1Unit.set_text(speedUnit)
3716 self._vrUnit.set_text(speedUnit)
3717 self._v2Unit.set_text(speedUnit)
3718
3719 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip" + i18nSpeedUnit))
3720 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip" + i18nSpeedUnit))
3721 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip" + i18nSpeedUnit))
3722
3723 self._derateType = self._wizard.gui.flight.aircraft.derateType
3724
3725 self._setupDerateWidget()
3726
3727 self._rto.set_active(False)
3728 self._rto.set_sensitive(False)
3729
3730 self._button.set_sensitive(False)
3731 self._forwardAllowed = False
3732
3733 self._active = True
3734
3735 def allowForward(self):
3736 """Allow going to the next page."""
3737 print "TakeoffPage.allowForward"
3738 self._forwardAllowed = True
3739 self._updateForwardButton()
3740
3741 def reset(self):
3742 """Reset the page if the wizard is reset."""
3743 print "TakeoffPage.reset"
3744
3745 super(TakeoffPage, self).reset()
3746 self._v1.reset()
3747 self._vr.reset()
3748 self._v2.reset()
3749 self._hasDerate = False
3750 self._antiIceOn.set_active(False)
3751 self._active = False
3752
3753 def setRTOEnabled(self, enabled):
3754 """Set the RTO checkbox enabled or disabled."""
3755 if not enabled:
3756 self._rto.set_active(False)
3757 self._rto.set_sensitive(enabled)
3758
3759 def changeMETAR(self, metar):
3760 """Change the METAR as a result of an edit on one of the other
3761 pages."""
3762 if self._active:
3763 print "TakeoffPage.changeMETAR"
3764 self._updatingMETAR = True
3765 self._metar.get_buffer().set_text(metar, -1)
3766 self._updatingMETAR = False
3767
3768 self._updateForwardButton()
3769
3770 def _updateForwardButton(self):
3771 """Update the sensitivity of the forward button based on some conditions."""
3772 sensitive = self._forwardAllowed and \
3773 self._metar.get_text()!="" and \
3774 self._runway.get_text()!="" and \
3775 self.sid is not None and \
3776 self.v1 is not None and \
3777 self.vr is not None and \
3778 self.v2 is not None and \
3779 self.v1 <= self.vr and \
3780 self.vr <= self.v2 and \
3781 (self._derateType==acft.DERATE_NONE or
3782 self.derate is not None)
3783
3784 print "TakeoffPage._updateForwardButton: forwardAllowed:", self._forwardAllowed, ", sensitive:", sensitive
3785 if self._forwardAllowed:
3786 print " METAR: ", self._metar.get_text()
3787 print " runway: ", self._runway.get_text()
3788 print " SID:", self.sid
3789 print " V1:", self.v1
3790 print " VR:", self.vr
3791 print " V2:", self.v2
3792 print " derateType:", self._derateType
3793 print " derate:", self.derate
3794
3795 self._button.set_sensitive(sensitive)
3796
3797 def _valueChanged(self, widget, arg = None):
3798 """Called when the value of some widget has changed."""
3799 print "TakeoffPage._valueChanged"
3800
3801 self._updateForwardButton()
3802
3803 def _upperChanged(self, entry, arg = None):
3804 """Called when the value of some entry widget has changed and the value
3805 should be converted to uppercase."""
3806 print "TakeoffPage._upperChanged"
3807 entry.set_text(entry.get_text().upper())
3808 self._valueChanged(entry, arg)
3809
3810 def _upperChangedComboBox(self, comboBox):
3811 """Called for combo box widgets that must be converted to uppercase."""
3812 entry = comboBox.get_child()
3813 if comboBox.get_active()==-1:
3814 entry.set_text(entry.get_text().upper())
3815 self._valueChanged(entry)
3816
3817 def _derateChanged(self, entry):
3818 """Called when the value of the derate is changed."""
3819 print "TakeoffPage._derateChanged"
3820 self._updateForwardButton()
3821
3822 def _rtoToggled(self, button):
3823 """Called when the RTO check button is toggled."""
3824 self._wizard.rtoToggled(button.get_active())
3825
3826 def _backClicked(self, button):
3827 """Called when the Back button is pressed."""
3828 self.goBack()
3829
3830 def _forwardClicked(self, button):
3831 """Called when the forward button is clicked."""
3832 aircraft = self._wizard.gui.flight.aircraft
3833 aircraft.updateV1R2()
3834 if self.derate is not None:
3835 aircraft.updateDerate()
3836 aircraft.updateTakeoffAntiIce()
3837 self._wizard.nextPage()
3838
3839 def _setupDerateWidget(self):
3840 """Setup the derate widget."""
3841 if self._derateWidget is not None:
3842 self._derate.remove(self._derateWidget)
3843
3844 if self._derateType==acft.DERATE_BOEING:
3845 self._derateLabel.set_text(xstr("takeoff_derate_boeing"))
3846 self._derateLabel.set_use_underline(True)
3847 self._derateLabel.set_sensitive(True)
3848
3849 self._derateEntry = gtk.Entry()
3850 self._derateEntry.set_width_chars(7)
3851 self._derateEntry.set_tooltip_text(xstr("takeoff_derate_boeing_tooltip"))
3852 self._derateEntry.set_alignment(1.0)
3853 self._derateEntry.connect("changed", self._derateChanged)
3854 self._derateLabel.set_mnemonic_widget(self._derateEntry)
3855
3856 self._derateUnit = gtk.Label("%")
3857 self._derateUnit.set_alignment(0.0, 0.5)
3858
3859 self._derateWidget = gtk.Table(3, 1)
3860 self._derateWidget.set_row_spacings(4)
3861 self._derateWidget.set_col_spacings(16)
3862 self._derateWidget.set_homogeneous(False)
3863
3864 self._derateWidget.attach(self._derateEntry, 0, 2, 0, 1)
3865 self._derateWidget.attach(self._derateUnit, 2, 3, 0, 1)
3866
3867 self._derate.add(self._derateWidget)
3868 elif self._derateType==acft.DERATE_EPR:
3869 self._derateLabel.set_text("_EPR:")
3870 self._derateLabel.set_use_underline(True)
3871 self._derateLabel.set_sensitive(True)
3872
3873 self._derateWidget = gtk.Entry()
3874 self._derateWidget.set_width_chars(7)
3875 self._derateWidget.set_tooltip_text(xstr("takeoff_derate_epr_tooltip"))
3876 self._derateWidget.set_alignment(1.0)
3877 self._derateWidget.connect("changed", self._derateChanged)
3878 self._derateLabel.set_mnemonic_widget(self._derateWidget)
3879
3880 self._derate.add(self._derateWidget)
3881 elif self._derateType==acft.DERATE_TUPOLEV:
3882 self._derateLabel.set_text(xstr("takeoff_derate_tupolev"))
3883 self._derateLabel.set_use_underline(True)
3884 self._derateLabel.set_sensitive(True)
3885
3886 if pygobject:
3887 nominal = gtk.RadioButton.\
3888 new_with_label_from_widget(None,
3889 xstr("takeoff_derate_tupolev_nominal"))
3890 else:
3891 nominal = gtk.RadioButton(None,
3892 xstr("takeoff_derate_tupolev_nominal"))
3893 nominal.set_use_underline(True)
3894 nominal.set_tooltip_text(xstr("takeoff_derate_tupolev_nominal_tooltip"))
3895 nominal.connect("toggled", self._derateChanged)
3896
3897 if pygobject:
3898 takeoff = gtk.RadioButton.\
3899 new_with_label_from_widget(nominal,
3900 xstr("takeoff_derate_tupolev_takeoff"))
3901 else:
3902 takeoff = gtk.RadioButton(nominal,
3903 xstr("takeoff_derate_tupolev_takeoff"))
3904
3905 takeoff.set_use_underline(True)
3906 takeoff.set_tooltip_text(xstr("takeoff_derate_tupolev_takeoff_tooltip"))
3907 takeoff.connect("toggled", self._derateChanged)
3908
3909 self._derateButtons = [nominal, takeoff]
3910
3911 self._derateWidget = gtk.HBox()
3912 self._derateWidget.pack_start(nominal, False, False, 4)
3913 self._derateWidget.pack_start(takeoff, False, False, 4)
3914
3915 self._derate.add(self._derateWidget)
3916 elif self._derateType==acft.DERATE_B462:
3917 self._derateLabel.set_text("")
3918
3919 self._derateWidget = gtk.CheckButton(xstr("takeoff_derate_b462"))
3920 self._derateWidget.set_tooltip_text(xstr("takeoff_derate_b462_tooltip"))
3921 self._derateWidget.set_use_underline(True)
3922 self._derate.add(self._derateWidget)
3923 else:
3924 self._derateWidget = None
3925 self._derateLabel.set_text("")
3926 self._derateLabel.set_sensitive(False)
3927
3928 def _metarChanged(self, entry):
3929 """Called when the METAR has changed."""
3930 print "TakeoffPage.metarChanged", self._updatingMETAR
3931 if not self._updatingMETAR:
3932 self._updateForwardButton()
3933 self._wizard.metarChanged(entry.get_text(), self)
3934
3935 def _metarInserted(self, buffer, position, text, length):
3936 """Called when new characters are inserted into the METAR.
3937
3938 It uppercases all characters."""
3939 print "TakeoffPage.metarInserted", self._updatingMETAR
3940 if not self._updatingMETAR:
3941 self._updatingMETAR = True
3942
3943 buffer.delete_text(position, length)
3944 buffer.insert_text(position, text.upper(), length)
3945
3946 self._updatingMETAR = False
3947
3948#-----------------------------------------------------------------------------
3949
3950class CruisePage(Page):
3951 """The page containing the flight level that might change during flight."""
3952 def __init__(self, wizard):
3953 """Construct the page."""
3954 super(CruisePage, self).__init__(wizard, "cruise",
3955 xstr("cruise_title"),
3956 xstr("cruise_help"))
3957
3958 self._loggable = False
3959 self._loggedCruiseLevel = 240
3960 self._activated = False
3961
3962 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
3963 xscale = 0.0, yscale = 1.0)
3964
3965 mainBox = gtk.VBox()
3966 alignment.add(mainBox)
3967 self.setMainWidget(alignment)
3968
3969 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
3970 xscale = 0.0, yscale = 0.0)
3971 mainBox.pack_start(alignment, False, False, 16)
3972
3973 levelBox = gtk.HBox()
3974
3975 label = gtk.Label(xstr("route_level"))
3976 label.set_use_underline(True)
3977 levelBox.pack_start(label, True, True, 0)
3978
3979 self._cruiseLevel = gtk.SpinButton()
3980 self._cruiseLevel.set_increments(step = 10, page = 100)
3981 self._cruiseLevel.set_range(min = 50, max = 500)
3982 self._cruiseLevel.set_tooltip_text(xstr("cruise_route_level_tooltip"))
3983 self._cruiseLevel.set_numeric(True)
3984 self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
3985 label.set_mnemonic_widget(self._cruiseLevel)
3986
3987 levelBox.pack_start(self._cruiseLevel, False, False, 8)
3988
3989 self._updateButton = gtk.Button(xstr("cruise_route_level_update"));
3990 self._updateButton.set_use_underline(True)
3991 self._updateButton.set_tooltip_text(xstr("cruise_route_level_update_tooltip"))
3992 self._updateButton.connect("clicked", self._updateButtonClicked)
3993
3994 levelBox.pack_start(self._updateButton, False, False, 16)
3995
3996 mainBox.pack_start(levelBox, False, False, 0)
3997
3998 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
3999 xscale = 0.0, yscale = 1.0)
4000 mainBox.pack_start(alignment, True, True, 0)
4001
4002 self.addCancelFlightButton()
4003
4004 self._backButton = self.addPreviousButton(clicked = self._backClicked)
4005 self._button = self.addNextButton(clicked = self._forwardClicked)
4006
4007 @property
4008 def activated(self):
4009 """Determine if the page is already activated or not."""
4010 return self._activated
4011
4012 @property
4013 def cruiseLevel(self):
4014 """Get the cruise level."""
4015 return self._loggedCruiseLevel
4016
4017 @property
4018 def loggableCruiseLevel(self):
4019 """Get the cruise level which should be logged."""
4020 return self._cruiseLevel.get_value_as_int()
4021
4022 def setLoggable(self, loggable):
4023 """Set whether the cruise altitude can be logged."""
4024 self._loggable = loggable
4025 self._updateButtons()
4026
4027 def activate(self):
4028 """Setup the route from the booked flight."""
4029 self._loggedCruiseLevel = self._wizard.filedCruiseLevel
4030 self._cruiseLevel.set_value(self._loggedCruiseLevel)
4031 self._activated = True
4032
4033 def reset(self):
4034 """Reset the page."""
4035 self._loggable = False
4036 self._activated = False
4037 super(CruisePage, self).reset()
4038
4039 def _updateButtons(self):
4040 """Update the sensitivity of the buttons."""
4041 self._updateButton.set_sensitive(self._loggable and
4042 self.loggableCruiseLevel!=
4043 self._loggedCruiseLevel)
4044
4045 def _cruiseLevelChanged(self, spinButton):
4046 """Called when the cruise level has changed."""
4047 self._updateButtons()
4048
4049 def _updateButtonClicked(self, button):
4050 """Called when the update button is clicked."""
4051 if self._wizard.cruiseLevelChanged():
4052 self._loggedCruiseLevel = self.loggableCruiseLevel
4053 self._updateButtons()
4054
4055 def _backClicked(self, button):
4056 """Called when the Back button is pressed."""
4057 self.goBack()
4058
4059 def _forwardClicked(self, button):
4060 """Called when the Forward button is clicked."""
4061 self._wizard.nextPage()
4062
4063#-----------------------------------------------------------------------------
4064
4065class LandingPage(Page):
4066 """Page for entering landing data."""
4067 def __init__(self, wizard):
4068 """Construct the landing page."""
4069 super(LandingPage, self).__init__(wizard, "landing",
4070 xstr("landing_title"),
4071 xstr("landing_help"),
4072 completedHelp = xstr("landing_chelp"))
4073
4074 self._flightEnded = False
4075
4076 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
4077 xscale = 0.0, yscale = 0.0)
4078
4079 table = gtk.Table(7, 24)
4080 table.set_row_spacings(4)
4081 table.set_col_spacings(16)
4082 table.set_homogeneous(False)
4083 alignment.add(table)
4084 self.setMainWidget(alignment)
4085
4086 row = 0
4087
4088 label = gtk.Label(xstr("landing_metar"))
4089 label.set_use_underline(True)
4090 label.set_alignment(0.0, 0.5)
4091 table.attach(label, 1, 2, row, row+1)
4092
4093 self._metar = gtk.Entry()
4094 self._metar.set_width_chars(40)
4095 self._metar.set_tooltip_text(xstr("landing_metar_tooltip"))
4096 self._metar.connect("changed", self._metarChanged)
4097 self._metar.get_buffer().connect_after("inserted-text", self._metarInserted)
4098 table.attach(self._metar, 2, 24, row, row+1)
4099 label.set_mnemonic_widget(self._metar)
4100
4101 self._updatingMETAR = False
4102
4103 row += 1
4104
4105 label = gtk.Label(xstr("landing_star"))
4106 label.set_use_underline(True)
4107 label.set_alignment(0.0, 0.5)
4108 table.attach(label, 1, 2, row, row + 1)
4109
4110 if pygobject:
4111 self._star = gtk.ComboBox.new_with_model_and_entry(comboModel)
4112 else:
4113 self._star = gtk.ComboBoxEntry(comboModel)
4114
4115 self._star.set_entry_text_column(0)
4116 self._star.get_child().set_width_chars(10)
4117 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
4118 self._star.connect("changed", self._upperChangedComboBox)
4119 self._star.set_sensitive(False)
4120 table.attach(self._star, 2, 4, row, row + 1)
4121 label.set_mnemonic_widget(self._star)
4122
4123 row += 1
4124
4125 label = gtk.Label(xstr("landing_transition"))
4126 label.set_use_underline(True)
4127 label.set_alignment(0.0, 0.5)
4128 table.attach(label, 1, 2, row, row + 1)
4129
4130 if pygobject:
4131 self._transition = gtk.ComboBox.new_with_model_and_entry(comboModel)
4132 else:
4133 self._transition = gtk.ComboBoxEntry(comboModel)
4134
4135 self._transition.set_entry_text_column(0)
4136 self._transition.get_child().set_width_chars(10)
4137 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
4138 self._transition.connect("changed", self._upperChangedComboBox)
4139 self._transition.set_sensitive(False)
4140 table.attach(self._transition, 2, 4, row, row + 1)
4141 label.set_mnemonic_widget(self._transition)
4142
4143 row += 1
4144
4145 label = gtk.Label(xstr("landing_runway"))
4146 label.set_use_underline(True)
4147 label.set_alignment(0.0, 0.5)
4148 table.attach(label, 1, 2, row, row + 1)
4149
4150 self._runway = gtk.Entry()
4151 self._runway.set_width_chars(10)
4152 self._runway.set_tooltip_text(xstr("landing_runway_tooltip"))
4153 self._runway.connect("changed", self._upperChanged)
4154 table.attach(self._runway, 2, 4, row, row + 1)
4155 label.set_mnemonic_widget(self._runway)
4156
4157 row += 1
4158
4159 label = gtk.Label(xstr("landing_approach"))
4160 label.set_use_underline(True)
4161 label.set_alignment(0.0, 0.5)
4162 table.attach(label, 1, 2, row, row + 1)
4163
4164 self._approachType = gtk.Entry()
4165 self._approachType.set_width_chars(10)
4166 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
4167 self._approachType.connect("changed", self._upperChanged)
4168 table.attach(self._approachType, 2, 4, row, row + 1)
4169 label.set_mnemonic_widget(self._approachType)
4170
4171 row += 1
4172
4173 label = gtk.Label(xstr("landing_vref"))
4174 label.set_use_markup(True)
4175 label.set_use_underline(True)
4176 label.set_alignment(0.0, 0.5)
4177 table.attach(label, 1, 2, row, row + 1)
4178
4179 self._vref = IntegerEntry()
4180 self._vref.set_width_chars(5)
4181 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip_knots"))
4182 self._vref.connect("integer-changed", self._vrefChanged)
4183 table.attach(self._vref, 3, 4, row, row + 1)
4184 label.set_mnemonic_widget(self._vref)
4185
4186 self._vrefUnit = gtk.Label(xstr("label_knots"))
4187 table.attach(self._vrefUnit, 4, 5, row, row + 1)
4188
4189 row += 1
4190
4191 self._antiIceOn = gtk.CheckButton(xstr("landing_antiice"))
4192 self._antiIceOn.set_use_underline(True)
4193 self._antiIceOn.set_tooltip_text(xstr("landing_antiice_tooltip"))
4194 table.attach(self._antiIceOn, 3, 5, row, row + 1)
4195
4196 self.addCancelFlightButton()
4197
4198 self.addPreviousButton(clicked = self._backClicked)
4199
4200 self._button = self.addNextButton(clicked = self._forwardClicked)
4201
4202 self._active = False
4203
4204 @property
4205 def star(self):
4206 """Get the STAR or None if none entered."""
4207 text = self._star.get_child().get_text()
4208 return text if self._star.get_active()!=0 and text and text!="N/A" \
4209 else None
4210
4211 @property
4212 def transition(self):
4213 """Get the transition or None if none entered."""
4214 text = self._transition.get_child().get_text()
4215 return text if self._transition.get_active()!=0 and text and text!="N/A" \
4216 else None
4217
4218 @property
4219 def approachType(self):
4220 """Get the approach type."""
4221 return self._approachType.get_text()
4222
4223 @property
4224 def runway(self):
4225 """Get the runway."""
4226 return self._runway.get_text()
4227
4228 @property
4229 def vref(self):
4230 """Return the landing reference speed."""
4231 return self._vref.get_int()
4232
4233 @property
4234 def antiIceOn(self):
4235 """Get whether the anti-ice system has been turned on."""
4236 return self._antiIceOn.get_active()
4237
4238 @antiIceOn.setter
4239 def antiIceOn(self, value):
4240 """Set the anti-ice indicator."""
4241 self._antiIceOn.set_active(value)
4242
4243 def reset(self):
4244 """Reset the page if the wizard is reset."""
4245 super(LandingPage, self).reset()
4246 self._vref.reset()
4247 self._antiIceOn.set_active(False)
4248 self._flightEnded = False
4249 self._active = False
4250
4251 def activate(self):
4252 """Called when the page is activated."""
4253 self._updatingMETAR = True
4254 self._metar.get_buffer().set_text(self._wizard.arrivalMETAR, -1)
4255 self._updatingMETAR = False
4256
4257 self._star.set_active(0)
4258 self._star.set_sensitive(True)
4259
4260 self._transition.set_active(0)
4261 self._transition.set_sensitive(True)
4262
4263 if self._wizard.landingRunway is None:
4264 self._runway.set_text("")
4265 else:
4266 self._runway.set_text(self._wizard.landingRunway)
4267 self._runway.set_sensitive(True)
4268
4269 self._approachType.set_text("")
4270 self._approachType.set_sensitive(True)
4271
4272 self._vref.set_int(None)
4273 self._vref.set_sensitive(True)
4274
4275 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
4276 speedUnit = xstr("label" + i18nSpeedUnit)
4277 self._vrefUnit.set_text(speedUnit)
4278
4279 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip" +
4280 i18nSpeedUnit))
4281
4282 self._updateForwardButton()
4283
4284 self._active = True
4285
4286 def flightEnded(self):
4287 """Called when the flight has ended."""
4288 super(LandingPage, self).flightEnded()
4289 self._flightEnded = True
4290 self._updateForwardButton()
4291
4292 def changeMETAR(self, metar):
4293 """Change the METAR as a result of an edit on one of the other
4294 pages."""
4295 if self._active:
4296 print "LandingPage.changeMETAR"
4297 self._updatingMETAR = True
4298 self._metar.get_buffer().set_text(metar, -1)
4299 self._updatingMETAR = False
4300
4301 self._updateForwardButton()
4302
4303 def _updateForwardButton(self):
4304 """Update the sensitivity of the forward button."""
4305 sensitive = self._flightEnded and \
4306 self._metar.get_text()!="" and \
4307 (self.star is not None or
4308 self.transition is not None) and \
4309 self._runway.get_text()!="" and \
4310 self._approachType.get_text()!="" and \
4311 self.vref is not None
4312 self._button.set_sensitive(sensitive)
4313
4314 def _upperChanged(self, entry):
4315 """Called for entry widgets that must be converted to uppercase."""
4316 entry.set_text(entry.get_text().upper())
4317 self._updateForwardButton()
4318
4319 def _upperChangedComboBox(self, comboBox):
4320 """Called for combo box widgets that must be converted to uppercase."""
4321 if comboBox.get_active()==-1:
4322 entry = comboBox.get_child()
4323 entry.set_text(entry.get_text().upper())
4324 self._updateForwardButton()
4325
4326 def _vrefChanged(self, widget, value):
4327 """Called when the Vref has changed."""
4328 self._updateForwardButton()
4329
4330 def _backClicked(self, button):
4331 """Called when the Back button is pressed."""
4332 self.goBack()
4333
4334 def _forwardClicked(self, button):
4335 """Called when the forward button is clicked."""
4336 wizard = self._wizard
4337
4338 aircraft = wizard.gui.flight.aircraft
4339 aircraft.updateVRef()
4340 aircraft.updateLandingAntiIce()
4341 if wizard.gui.config.onlineGateSystem and \
4342 wizard.loggedIn and not self._completed and \
4343 wizard.bookedFlight.arrivalICAO=="LHBP" and \
4344 not wizard.entranceExam:
4345 wizard.getFleet(callback = self._fleetRetrieved, force = True)
4346 elif wizard.entranceExam:
4347 self._handleEntranceExamDone()
4348 else:
4349 wizard.nextPage()
4350
4351 def _fleetRetrieved(self, fleet):
4352 """Callback for the fleet retrieval."""
4353 self._wizard.nextPage()
4354
4355 def _metarChanged(self, entry):
4356 """Called when the METAR has changed."""
4357 print "LandingPage.metarChanged", self._updatingMETAR
4358 if not self._updatingMETAR:
4359 self._updateForwardButton()
4360 self._wizard.metarChanged(entry.get_text(), self)
4361
4362 def _metarInserted(self, buffer, position, text, length):
4363 """Called when new characters are inserted into the METAR.
4364
4365 It uppercases all characters."""
4366 print "LandingPage.metarInserted", self._updatingMETAR
4367 if not self._updatingMETAR:
4368 self._updatingMETAR = True
4369
4370 buffer.delete_text(position, length)
4371 buffer.insert_text(position, text.upper(), length)
4372
4373 self._updatingMETAR = False
4374
4375 def _handleEntranceExamDone(self):
4376 """Handle the end of the entrance exam.
4377
4378 If the there was a NO-GO fault, notify the user that exam is a failure
4379 and take them back to the student page. Otherwise congratulate, update
4380 the database to reflect that the exam has been taken and go back to the
4381 student page."""
4382 self._wizard.jumpPage("chkfinish")
4383
4384#-----------------------------------------------------------------------------
4385
4386class PIREPSaveHelper(object):
4387 """A helper to use for saving PIREPs."""
4388 def __init__(self, wizard):
4389 """Construct the helper."""
4390 super(PIREPSaveHelper, self).__init__()
4391
4392 self._wizard = wizard
4393
4394 self._lastSavePath = None
4395 self._savePIREPDialog = None
4396
4397 def addButton(self, page):
4398 """Add a button to save the PIREP to the given page."""
4399 return page.addButton(xstr("finish_save"), sensitive = False,
4400 clicked = self._saveClicked,
4401 tooltip = xstr("finish_save_tooltip"),
4402 clickedArg = page)
4403
4404 def autoSavePIREP(self, page):
4405 """Perform the automatic saving of the PIREP."""
4406 self._lastSavePath = os.path.join(self._wizard.gui.config.pirepDirectory,
4407 self._getDefaultPIREPName())
4408 self._lastSavePath = text2unicode(self._lastSavePath)
4409 self._savePIREP(page, automatic = True)
4410
4411 def _getDefaultPIREPName(self):
4412 """Get the default name of the PIREP."""
4413 gui = self._wizard.gui
4414
4415 bookedFlight = gui.bookedFlight
4416 tm = time.gmtime()
4417
4418 pilotID = self._wizard.pilotID
4419 if pilotID: pilotID += " "
4420 return "%s%s %02d%02d %s-%s.pirep" % \
4421 (pilotID, str(bookedFlight.departureTime.date()),
4422 tm.tm_hour, tm.tm_min,
4423 bookedFlight.departureICAO, bookedFlight.arrivalICAO)
4424
4425 def _saveClicked(self, button, page):
4426 """Called when the Save PIREP button is clicked."""
4427 gui = self._wizard.gui
4428
4429 fileName = self._getDefaultPIREPName()
4430
4431 dialog = self._getSaveDialog()
4432
4433 if self._lastSavePath is None:
4434 pirepDirectory = gui.config.pirepDirectory
4435 if pirepDirectory is not None:
4436 dialog.set_current_folder(pirepDirectory)
4437 else:
4438 dialog.set_current_folder(os.path.dirname(self._lastSavePath))
4439
4440 dialog.set_current_name(fileName)
4441 result = dialog.run()
4442 dialog.hide()
4443
4444 if result==RESPONSETYPE_OK:
4445 self._lastSavePath = text2unicode(dialog.get_filename())
4446 self._savePIREP(page)
4447
4448 def _savePIREP(self, page, automatic = False):
4449 """Perform the saving of the PIREP."""
4450
4451 gui = self._wizard.gui
4452
4453 if automatic:
4454 gui.beginBusy(xstr("finish_autosave_busy"))
4455
4456 pirep = PIREP(gui.flight)
4457 error = pirep.save(self._lastSavePath)
4458
4459 if automatic:
4460 gui.endBusy()
4461
4462 if error:
4463 type = MESSAGETYPE_ERROR
4464 message = xstr("finish_save_failed")
4465 secondary = xstr("finish_save_failed_sec") % (text2unicode(error),)
4466 else:
4467 type = MESSAGETYPE_INFO
4468 message = xstr("finish_save_done")
4469 if automatic:
4470 secondary = xstr("finish_save_done_sec") % (self._lastSavePath,)
4471 else:
4472 secondary = None
4473 page.setPIREPSaved()
4474
4475 dialog = gtk.MessageDialog(parent = gui.mainWindow,
4476 type = type, message_format = message)
4477 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
4478 dialog.set_title(WINDOW_TITLE_BASE)
4479 if secondary is not None:
4480 dialog.format_secondary_markup(secondary)
4481
4482 dialog.run()
4483 dialog.hide()
4484
4485 def _getSaveDialog(self):
4486 """Get the PIREP saving dialog.
4487
4488 If it does not exist yet, create it."""
4489 if self._savePIREPDialog is None:
4490 gui = self._wizard.gui
4491 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
4492 xstr("finish_save_title"),
4493 action = FILE_CHOOSER_ACTION_SAVE,
4494 buttons = (gtk.STOCK_CANCEL,
4495 RESPONSETYPE_CANCEL,
4496 gtk.STOCK_OK, RESPONSETYPE_OK),
4497 parent = gui.mainWindow)
4498 dialog.set_modal(True)
4499 dialog.set_do_overwrite_confirmation(True)
4500
4501 filter = gtk.FileFilter()
4502 filter.set_name(xstr("file_filter_pireps"))
4503 filter.add_pattern("*.pirep")
4504 dialog.add_filter(filter)
4505
4506 filter = gtk.FileFilter()
4507 filter.set_name(xstr("file_filter_all"))
4508 filter.add_pattern("*.*")
4509 dialog.add_filter(filter)
4510
4511 self._savePIREPDialog = dialog
4512
4513 return self._savePIREPDialog
4514
4515#-----------------------------------------------------------------------------
4516
4517class FinishPage(Page):
4518 """Flight finish page."""
4519 _flightTypes = [ ("flighttype_scheduled", const.FLIGHTTYPE_SCHEDULED),
4520 ("flighttype_ot", const.FLIGHTTYPE_OLDTIMER),
4521 ("flighttype_vip", const.FLIGHTTYPE_VIP),
4522 ("flighttype_charter", const.FLIGHTTYPE_CHARTER) ]
4523
4524 def __init__(self, wizard, saveHelper):
4525 """Construct the finish page."""
4526 help = xstr("finish_help") + xstr("finish_help_goodtime")
4527 super(FinishPage, self).__init__(wizard, "finish",
4528 xstr("finish_title"), help)
4529
4530 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
4531 xscale = 0.0, yscale = 0.0)
4532
4533 table = gtk.Table(10, 2)
4534 table.set_row_spacings(4)
4535 table.set_col_spacings(16)
4536 table.set_homogeneous(False)
4537 alignment.add(table)
4538 self.setMainWidget(alignment)
4539
4540 row = 0
4541
4542 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4543 label = gtk.Label(xstr("finish_rating"))
4544 labelAlignment.add(label)
4545 table.attach(labelAlignment, 0, 1, row, row+1)
4546
4547 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4548 self._flightRating = gtk.Label()
4549 self._flightRating.set_width_chars(8)
4550 self._flightRating.set_alignment(0.0, 0.5)
4551 self._flightRating.set_use_markup(True)
4552 labelAlignment.add(self._flightRating)
4553 table.attach(labelAlignment, 1, 2, row, row+1)
4554
4555 row += 1
4556
4557 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4558 label = gtk.Label(xstr("finish_dep_time"))
4559 labelAlignment.add(label)
4560 table.attach(labelAlignment, 0, 1, row, row+1)
4561
4562 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4563 self._depTime = gtk.Label()
4564 self._depTime.set_width_chars(13)
4565 self._depTime.set_alignment(0.0, 0.5)
4566 self._depTime.set_use_markup(True)
4567 self._depTime.set_tooltip_markup(xstr("finish_dep_time_tooltip"))
4568 labelAlignment.add(self._depTime)
4569 table.attach(labelAlignment, 1, 2, row, row+1)
4570
4571 row += 1
4572
4573 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4574 label = gtk.Label(xstr("finish_flight_time"))
4575 labelAlignment.add(label)
4576 table.attach(labelAlignment, 0, 1, row, row+1)
4577
4578 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4579 self._flightTime = gtk.Label()
4580 self._flightTime.set_width_chars(10)
4581 self._flightTime.set_alignment(0.0, 0.5)
4582 self._flightTime.set_use_markup(True)
4583 labelAlignment.add(self._flightTime)
4584 table.attach(labelAlignment, 1, 2, row, row+1)
4585
4586 row += 1
4587
4588 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4589 label = gtk.Label(xstr("finish_block_time"))
4590 labelAlignment.add(label)
4591 table.attach(labelAlignment, 0, 1, row, row+1)
4592
4593 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4594 self._blockTime = gtk.Label()
4595 self._blockTime.set_width_chars(10)
4596 self._blockTime.set_alignment(0.0, 0.5)
4597 self._blockTime.set_use_markup(True)
4598 labelAlignment.add(self._blockTime)
4599 table.attach(labelAlignment, 1, 2, row, row+1)
4600
4601 row += 1
4602
4603 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4604 label = gtk.Label(xstr("finish_arr_time"))
4605 labelAlignment.add(label)
4606 table.attach(labelAlignment, 0, 1, row, row+1)
4607
4608 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4609 self._arrTime = gtk.Label()
4610 self._arrTime.set_width_chars(13)
4611 self._arrTime.set_alignment(0.0, 0.5)
4612 self._arrTime.set_use_markup(True)
4613 self._arrTime.set_tooltip_markup(xstr("finish_arr_time_tooltip"))
4614 labelAlignment.add(self._arrTime)
4615 table.attach(labelAlignment, 1, 2, row, row+1)
4616
4617 row += 1
4618
4619 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4620 label = gtk.Label(xstr("finish_distance"))
4621 labelAlignment.add(label)
4622 table.attach(labelAlignment, 0, 1, row, row+1)
4623
4624 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4625 self._distanceFlown = gtk.Label()
4626 self._distanceFlown.set_width_chars(10)
4627 self._distanceFlown.set_alignment(0.0, 0.5)
4628 self._distanceFlown.set_use_markup(True)
4629 labelAlignment.add(self._distanceFlown)
4630 table.attach(labelAlignment, 1, 2, row, row+1)
4631
4632 row += 1
4633
4634 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
4635 label = gtk.Label(xstr("finish_fuel"))
4636 labelAlignment.add(label)
4637 table.attach(labelAlignment, 0, 1, row, row+1)
4638
4639 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4640 self._fuelUsed = gtk.Label()
4641 self._fuelUsed.set_width_chars(10)
4642 self._fuelUsed.set_alignment(0.0, 0.5)
4643 self._fuelUsed.set_use_markup(True)
4644 labelAlignment.add(self._fuelUsed)
4645 table.attach(labelAlignment, 1, 2, row, row+1)
4646
4647 row += 1
4648
4649 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
4650 yalign = 0.5, yscale = 0.0)
4651 label = gtk.Label(xstr("finish_type"))
4652 label.set_use_underline(True)
4653 labelAlignment.add(label)
4654 table.attach(labelAlignment, 0, 1, row, row+1)
4655
4656 flightTypeModel = gtk.ListStore(str, int)
4657 for (name, type) in FinishPage._flightTypes:
4658 flightTypeModel.append([xstr(name), type])
4659
4660 self._flightType = gtk.ComboBox(model = flightTypeModel)
4661 renderer = gtk.CellRendererText()
4662 self._flightType.pack_start(renderer, True)
4663 self._flightType.add_attribute(renderer, "text", 0)
4664 self._flightType.set_tooltip_text(xstr("finish_type_tooltip"))
4665 self._flightType.set_active(0)
4666 self._flightType.connect("changed", self._flightTypeChanged)
4667 flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4668 flightTypeAlignment.add(self._flightType)
4669 table.attach(flightTypeAlignment, 1, 2, row, row+1)
4670 label.set_mnemonic_widget(self._flightType)
4671
4672 row += 1
4673
4674 self._onlineFlight = gtk.CheckButton(xstr("finish_online"))
4675 self._onlineFlight.set_use_underline(True)
4676 self._onlineFlight.set_tooltip_text(xstr("finish_online_tooltip"))
4677 onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
4678 onlineFlightAlignment.add(self._onlineFlight)
4679 table.attach(onlineFlightAlignment, 1, 2, row, row + 1)
4680
4681 row += 1
4682
4683 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
4684 yalign = 0.5, yscale = 0.0)
4685 self._gateLabel = gtk.Label(xstr("finish_gate"))
4686 self._gateLabel.set_use_underline(True)
4687 labelAlignment.add(self._gateLabel)
4688 table.attach(labelAlignment, 0, 1, row, row+1)
4689
4690 self._gatesModel = gtk.ListStore(str)
4691
4692 self._gate = gtk.ComboBox(model = self._gatesModel)
4693 renderer = gtk.CellRendererText()
4694 self._gate.pack_start(renderer, True)
4695 self._gate.add_attribute(renderer, "text", 0)
4696 self._gate.set_tooltip_text(xstr("finish_gate_tooltip"))
4697 self._gate.connect("changed", self._gateChanged)
4698 gateAlignment = gtk.Alignment(xalign=0.0, xscale=1.0)
4699 gateAlignment.add(self._gate)
4700 table.attach(gateAlignment, 1, 2, row, row+1)
4701 self._gateLabel.set_mnemonic_widget(self._gate)
4702
4703 self.addButton(xstr("finish_newFlight"),
4704 sensitive = True,
4705 clicked = self._newFlightClicked,
4706 tooltip = xstr("finish_newFlight_tooltip"),
4707 padding = 16)
4708
4709 self.addPreviousButton(clicked = self._backClicked)
4710
4711 self._saveHelper = saveHelper
4712 self._saveButton = saveHelper.addButton(self)
4713
4714 self._tooBigTimeDifference = False
4715 self._deferredAutoSave = False
4716 self._pirepSaved = False
4717 self._pirepSent = False
4718
4719 self._sendButton = self.addButton(xstr("sendPIREP"), default = True,
4720 sensitive = False,
4721 clicked = self._sendClicked,
4722 tooltip = xstr("sendPIREP_tooltip"))
4723
4724 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), 10*60.0)
4725 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), 20*60.0)
4726 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), 0*60.0)
4727 # self._formatTime(datetime.datetime(1970, 1, 1, 0, 10), (23*60.0+50)*60.0)
4728 # self._formatTime(datetime.datetime(1970, 1, 1, 1, 0), (1*60.0+5)*60.0)
4729 # self._formatTime(datetime.datetime(1970, 1, 1, 1, 0), (0*60.0+50)*60.0)
4730 # self._formatTime(datetime.datetime(1970, 1, 1, 23, 55), (0*60.0+5)*60.0)
4731 # self._formatTime(datetime.datetime(1970, 1, 1, 23, 55), (23*60.0+45)*60.0)
4732
4733 @property
4734 def flightType(self):
4735 """Get the flight type."""
4736 index = self._flightType.get_active()
4737 return None if index<0 else self._flightType.get_model()[index][1]
4738
4739 @property
4740 def online(self):
4741 """Get whether the flight was an online flight or not."""
4742 return self._onlineFlight.get_active()
4743
4744 def activate(self):
4745 """Activate the page."""
4746 self._deferredAutoSave = False
4747 self._pirepSaved = False
4748 self._pirepSent = False
4749
4750 flight = self._wizard.gui._flight
4751 rating = flight.logger.getRating()
4752 if rating<0:
4753 self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
4754 else:
4755 self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
4756
4757 flightLength = flight.flightTimeEnd - flight.flightTimeStart
4758 self._flightTime.set_markup("<b>%s</b>" % \
4759 (util.getTimeIntervalString(flightLength),))
4760
4761 blockLength = flight.blockTimeEnd - flight.blockTimeStart
4762 self._blockTime.set_markup("<b>%s</b>" % \
4763 (util.getTimeIntervalString(blockLength),))
4764
4765 self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
4766 (flight.flownDistance,))
4767
4768 self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
4769 (flight.startFuel - flight.endFuel,))
4770
4771 self._flightType.set_active(-1)
4772 self._onlineFlight.set_active(self._wizard.loggedIn)
4773
4774 self._gatesModel.clear()
4775 if self._wizard.gui.config.onlineGateSystem and \
4776 self._wizard.loggedIn and \
4777 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
4778 not self._wizard.entranceExam:
4779 occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
4780 for gate in lhbpGates.gates:
4781 if gate.isAvailable(lhbpGates, occupiedGateNumbers):
4782 self._gatesModel.append([gate.number])
4783 self._gateLabel.set_sensitive(True)
4784 self._gate.set_sensitive(True)
4785 self._gate.set_active(-1)
4786 else:
4787 self._gateLabel.set_sensitive(False)
4788 self._gate.set_sensitive(False)
4789
4790 self._updateTimes()
4791
4792 def updateButtons(self):
4793 """Update the sensitivity state of the buttons."""
4794 gui = self._wizard.gui
4795 faultsExplained = gui.faultsFullyExplained
4796 timesCorrect = self.flightType is None or \
4797 not self._tooBigTimeDifference or \
4798 gui.hasComments or gui.hasDelayCode
4799 sensitive = gui.flight is not None and \
4800 gui.flight.stage==const.STAGE_END and \
4801 self._flightType.get_active()>=0 and \
4802 (self._gatesModel.get_iter_first() is None or
4803 self._gate.get_active()>=0) and \
4804 faultsExplained and timesCorrect
4805
4806 self._updateHelp(faultsExplained, timesCorrect)
4807
4808 wasSensitive = self._saveButton.get_sensitive()
4809
4810 if gui.config.pirepAutoSave and sensitive and not wasSensitive:
4811 if gui.isWizardActive():
4812 self._saveHelper.autoSavePIREP(self)
4813 else:
4814 self._deferredAutoSave = True
4815
4816 if not sensitive:
4817 self._deferredAutoSave = False
4818
4819 self._saveButton.set_sensitive(sensitive)
4820 self._sendButton.set_sensitive(sensitive and
4821 self._wizard.bookedFlight.id is not None)
4822
4823 def grabDefault(self):
4824 """If the page has a default button, make it the default one."""
4825 super(FinishPage, self).grabDefault()
4826 if self._deferredAutoSave:
4827 self._saveHelper.autoSavePIREP(self)
4828 self._deferredAutoSave = False
4829
4830 def setPIREPSaved(self):
4831 """Mark the PIREP as saved."""
4832 self._pirepSaved = True
4833
4834 def _backClicked(self, button):
4835 """Called when the Back button is pressed."""
4836 self.goBack()
4837
4838 def _flightTypeChanged(self, comboBox):
4839 """Called when the flight type has changed."""
4840 self._updateTimes()
4841
4842 def _gateChanged(self, comboBox):
4843 """Called when the arrival gate has changed."""
4844 self.updateButtons()
4845
4846 def _newFlightClicked(self, button):
4847 """Called when the new flight button is clicked."""
4848 gui = self._wizard.gui
4849 if not self._pirepSent and not self._pirepSaved:
4850 dialog = gtk.MessageDialog(parent = gui.mainWindow,
4851 type = MESSAGETYPE_QUESTION,
4852 message_format = xstr("finish_newFlight_question"))
4853
4854 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
4855 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
4856
4857 dialog.set_title(WINDOW_TITLE_BASE)
4858 result = dialog.run()
4859 dialog.hide()
4860 if result!=RESPONSETYPE_YES:
4861 return
4862
4863 gui.reset()
4864
4865 def _sendClicked(self, button):
4866 """Called when the Send button is clicked."""
4867 pirep = PIREP(self._wizard.gui.flight)
4868 self._wizard.gui.sendPIREP(pirep,
4869 callback = self._handlePIREPSent)
4870
4871 def _handlePIREPSent(self, returned, result):
4872 """Callback for the PIREP sending result."""
4873 self._pirepSent = returned and result.success
4874 if self._wizard.gui.config.onlineGateSystem and \
4875 self._wizard.loggedIn and not self._wizard.entranceExam and \
4876 returned and result.success:
4877 bookedFlight = self._wizard.bookedFlight
4878 if bookedFlight.arrivalICAO=="LHBP":
4879 iter = self._gate.get_active_iter()
4880 gateNumber = None if iter is None \
4881 else self._gatesModel.get_value(iter, 0)
4882
4883 status = const.PLANE_PARKING if gateNumber is None \
4884 else const.PLANE_HOME
4885 else:
4886 gateNumber = None
4887 status = const.PLANE_AWAY
4888
4889 self._wizard.updatePlane(self._planeUpdated,
4890 bookedFlight.tailNumber,
4891 status, gateNumber = gateNumber)
4892
4893 def _planeUpdated(self, success):
4894 """Callback for the plane updating."""
4895 pass
4896
4897 def _formatTime(self, scheduledTime, realTimestamp, (warning, error)):
4898 """Format the departure or arrival time based on the given data as a
4899 markup for a label."""
4900 realTime = time.gmtime(realTimestamp)
4901
4902 if warning:
4903 colour = "red" if error else "orange"
4904 markupBegin = '<span foreground="%s">' % (colour,)
4905 markupEnd = '</span>'
4906 else:
4907 markupBegin = markupEnd = ""
4908
4909 markup = "<b>%s%02d:%02d [%02d:%02d]%s</b>" % \
4910 (markupBegin,
4911 realTime.tm_hour, realTime.tm_min,
4912 scheduledTime.hour, scheduledTime.minute,
4913 markupEnd)
4914
4915 return markup
4916
4917 def _updateTimes(self):
4918 """Format the flight times and the help text according to the flight
4919 type.
4920
4921 The buttons are also updated.
4922 """
4923 flight = self._wizard.gui._flight
4924 bookedFlight = flight.bookedFlight
4925
4926 (departureWarning, departureError) = flight.blockTimeStartWrong
4927 (arrivalWarning, arrivalError) = flight.blockTimeEndWrong
4928
4929 if self.flightType==const.FLIGHTTYPE_VIP:
4930 departureError = arrivalError = False
4931
4932 self._tooBigTimeDifference = departureError or arrivalError
4933
4934 self._depTime.set_markup(self._formatTime(bookedFlight.departureTime,
4935 flight.blockTimeStart,
4936 (departureWarning,
4937 departureError)))
4938
4939 self._arrTime.set_markup(self._formatTime(bookedFlight.arrivalTime,
4940 flight.blockTimeEnd,
4941 (arrivalWarning,
4942 arrivalError)))
4943
4944 self.updateButtons()
4945
4946 def _updateHelp(self, faultsExplained, timesCorrect):
4947 """Update the help text according to the actual situation."""
4948 if not faultsExplained:
4949 self.setHelp(xstr("finish_help") + xstr("finish_help_faults"))
4950 elif not timesCorrect:
4951 self.setHelp(xstr("finish_help") + xstr("finish_help_wrongtime"))
4952 else:
4953 self.setHelp(xstr("finish_help") + xstr("finish_help_goodtime"))
4954
4955
4956#-----------------------------------------------------------------------------
4957
4958class CheckFlightFinishPage(Page):
4959 """Finish page for a check flight."""
4960 def __init__(self, wizard, saveHelper):
4961 """Construct the check flight finish page."""
4962 super(CheckFlightFinishPage, self).__init__(wizard,
4963 "chkfinish",
4964 xstr("chkfinish_title"),
4965 "")
4966
4967 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
4968 xscale = 1.0, yscale = 1.0)
4969 self._label = gtk.Label()
4970 alignment.add(self._label)
4971
4972 self.setMainWidget(alignment)
4973
4974 self._saveHelper = saveHelper
4975 self._saveButton = saveHelper.addButton(self)
4976
4977 self._button = self.addNextButton(sensitive = False,
4978 clicked = self._forwardClicked)
4979
4980 def activate(self):
4981 """Activate the page."""
4982 wizard = self._wizard
4983 loginResult = wizard.loginResult
4984 gui = wizard.gui
4985 rating = gui.flight.logger.getRating()
4986
4987 if rating>=0:
4988 loginResult.checkFlightStatus = True
4989
4990 firstOfficer = \
4991 loginResult.entryExamPassed and loginResult.checkFlightStatus
4992
4993 if firstOfficer:
4994 loginResult.rank = "FO"
4995
4996 if rating<0:
4997 mainMessage = xstr("chkfinish_failed")
4998 else:
4999 mainMessage = xstr("chkfinish_passed_begin")
5000 if firstOfficer:
5001 mainMessage += xstr("chkfinish_passed_fo")
5002 mainMessage += xstr("chkfinish_passed_end")
5003
5004 if firstOfficer:
5005 nextMessage = xstr("chkfinish_next")
5006 else:
5007 nextMessage = xstr("chkfinish_next_student_begin")
5008 if not loginResult.entryExamPassed and \
5009 not loginResult.checkFlightStatus:
5010 nextMessage += xstr("chkfinish_next_student_nothing")
5011 elif loginResult.entryExamPassed and \
5012 not loginResult.checkFlightStatus:
5013 nextMessage += xstr("chkfinish_next_student_no_flight")
5014 elif not loginResult.entryExamPassed and \
5015 loginResult.checkFlightStatus:
5016 nextMessage += xstr("chkfinish_next_student_no_exam")
5017
5018 self._label.set_text(mainMessage +
5019 xstr("chkfinish_savepirep") +
5020 nextMessage)
5021 self._label.set_use_markup(True)
5022 self._label.set_alignment(0.5, 0.0)
5023
5024 self._saveButton.set_sensitive(True)
5025 self._button.set_sensitive(True)
5026
5027 def _forwardClicked(self, button):
5028 """Jump to the student page if there are some tasks to do,
5029 or to the flight selection page, if the pilot is allowed to perform
5030 MAVA flights."""
5031 wizard = self._wizard
5032 gui = wizard.gui
5033
5034 loginResult = wizard.loginResult
5035 if loginResult.checkFlightStatus:
5036 gui.beginBusy(xstr("chkfinish_updateweb_busy"))
5037 gui.webHandler.setCheckFlightPassed(self._checkFlightPassedSetCallback,
5038 wizard.checkFlightAircraftType)
5039 else:
5040 self._resetGUI()
5041
5042 def _checkFlightPassedSetCallback(self, returned, result):
5043 """Called when the check flight status has been set."""
5044 gobject.idle_add(self._checkFlightPassedSet, returned, result)
5045
5046 def _checkFlightPassedSet(self, returned, result):
5047 """Handle the result of an attempt to set the check flight status."""
5048 gui = self._wizard.gui
5049
5050 gui.endBusy()
5051
5052 if returned:
5053 self._resetGUI()
5054 else:
5055 dialog = gtk.MessageDialog(parent = gui.mainWindow,
5056 type = MESSAGETYPE_ERROR,
5057 message_format =
5058 xstr("chkfinish_passedset_failed"))
5059 dialog.set_title(WINDOW_TITLE_BASE + " - " +
5060 xstr("chkfinish_passedset_failed_title"))
5061 dialog.format_secondary_markup(xstr("chkfinish_passedset_failed_secondary"))
5062
5063 dialog.add_button(xstr("button_ok"), 0)
5064
5065 dialog.run()
5066 dialog.hide()
5067
5068 def _resetGUI(self):
5069 """Reset the GUI."""
5070 gui = self._wizard.gui
5071 gui.reset()
5072
5073#-----------------------------------------------------------------------------
5074
5075class Wizard(gtk.VBox):
5076 """The flight wizard."""
5077 def __init__(self, gui):
5078 """Construct the wizard."""
5079 super(Wizard, self).__init__()
5080
5081 self.gui = gui
5082
5083 self._pages = []
5084 self._currentPage = None
5085
5086 self._loginPage = LoginPage(self)
5087 self._pages.append(self._loginPage)
5088 self._flightSelectionPage = FlightSelectionPage(self)
5089 self._pages.append(self._flightSelectionPage)
5090 self._pages.append(GateSelectionPage(self))
5091 self._pages.append(RegisterPage(self))
5092 self._studentPage = StudentPage(self)
5093 self._pages.append(self._studentPage)
5094 self._pages.append(ConnectPage(self))
5095 self._payloadPage = PayloadPage(self)
5096 self._pages.append(self._payloadPage)
5097 self._payloadIndex = len(self._pages)
5098 self._pages.append(TimePage(self))
5099 self._routePage = RoutePage(self)
5100 self._pages.append(self._routePage)
5101 self._simBriefSetupPage = SimBriefSetupPage(self)
5102 self._pages.append(self._simBriefSetupPage)
5103 self._simBriefingPage = SimBriefingPage(self)
5104 self._pages.append(self._simBriefingPage)
5105 self._pages.append(FuelPage(self))
5106 self._departureBriefingPage = BriefingPage(self, True)
5107 self._pages.append(self._departureBriefingPage)
5108 self._arrivalBriefingPage = BriefingPage(self, False)
5109 self._pages.append(self._arrivalBriefingPage)
5110 self._arrivalBriefingIndex = len(self._pages)
5111 self._takeoffPage = TakeoffPage(self)
5112 self._pages.append(self._takeoffPage)
5113 self._cruisePage = CruisePage(self)
5114 self._pages.append(self._cruisePage)
5115 self._landingPage = LandingPage(self)
5116 self._pages.append(self._landingPage)
5117
5118 pirepSaveHelper = PIREPSaveHelper(self)
5119
5120 self._finishPage = FinishPage(self, pirepSaveHelper)
5121 self._pages.append(self._finishPage)
5122 self._pages.append(CheckFlightFinishPage(self, pirepSaveHelper))
5123
5124 self._requestedWidth = None
5125 self._requestedHeight = None
5126
5127 self.connect("size-allocate", self._sizeAllocate)
5128
5129 for page in self._pages:
5130 page.show_all()
5131 page.setStyle()
5132
5133 self._initialize()
5134
5135 def _sizeAllocate(self, widget, allocation):
5136 if self._requestedWidth is not None and \
5137 self._requestedHeight is not None:
5138 return
5139
5140 if self._currentPage is not None:
5141 self.remove(self._pages[self._currentPage])
5142
5143 maxWidth = 0
5144 maxHeight = 0
5145 for page in self._pages:
5146 self.add(page)
5147 self.show_all()
5148 pageSizeRequest = page.size_request()
5149 width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
5150 height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
5151 maxWidth = max(maxWidth, width)
5152 maxHeight = max(maxHeight, height)
5153 self.remove(page)
5154
5155 if self._currentPage is not None:
5156 self.add(self._pages[self._currentPage])
5157
5158 self._requestedWidth = maxWidth
5159 self._requestedHeight = maxHeight
5160 self.set_size_request(maxWidth, maxHeight)
5161
5162 @property
5163 def pilotID(self):
5164 """Get the pilot ID, if given."""
5165 return self._loginPage.pilotID
5166
5167 @property
5168 def entranceExam(self):
5169 """Get whether an entrance exam is about to be taken."""
5170 return self._loginResult is not None and self._loginResult.rank=="STU"
5171
5172 @property
5173 def loggedIn(self):
5174 """Indicate if there was a successful login."""
5175 return self._loginResult is not None
5176
5177 @property
5178 def loginResult(self):
5179 """Get the login result."""
5180 return self._loginResult
5181
5182 @property
5183 def checkFlightAircraftType(self):
5184 """Get the type of the aircraft used to perform the check flight."""
5185 return self._studentPage.aircraftType
5186
5187 def setCurrentPage(self, index, finalize = False, fromPageShift = None):
5188 """Set the current page to the one with the given index.
5189
5190 @param fromPageShift if given, the relative index of one of the
5191 previous pages that should be used as the from-page of the next
5192 page. E.g. if fromPageShift is 1, the previous page will be the
5193 from-page."""
5194 assert index < len(self._pages)
5195
5196 fromPage = self._currentPage
5197 if fromPage is not None:
5198 page = self._pages[fromPage]
5199 if finalize and not page._completed:
5200 page.complete()
5201 self.remove(page)
5202 if fromPageShift is not None:
5203 fromPage -= fromPageShift
5204
5205 self._currentPage = index
5206 page = self._pages[index]
5207 self.add(page)
5208 if page._fromPage is None:
5209 page._fromPage = fromPage
5210 page.initialize()
5211 self.show_all()
5212 if fromPage is not None:
5213 self.grabDefault()
5214
5215 @property
5216 def bookedFlight(self):
5217 """Get the booked flight selected."""
5218 return self._bookedFlight
5219
5220 @property
5221 def numCrew(self):
5222 """Get the number of crew members."""
5223 return self._payloadPage.numCrew
5224
5225 @property
5226 def numPassengers(self):
5227 """Get the number of passengers."""
5228 return self._payloadPage.numPassengers
5229
5230 @property
5231 def bagWeight(self):
5232 """Get the baggage weight."""
5233 return self._payloadPage.bagWeight
5234
5235 @property
5236 def cargoWeight(self):
5237 """Get the cargo weight."""
5238 return self._payloadPage.cargoWeight
5239
5240 @property
5241 def mailWeight(self):
5242 """Get the mail weight."""
5243 return self._payloadPage.mailWeight
5244
5245 @property
5246 def zfw(self):
5247 """Get the calculated ZFW value."""
5248 return 0 if self._bookedFlight is None \
5249 else self._payloadPage.calculateZFW()
5250
5251 @property
5252 def filedCruiseLevel(self):
5253 """Get the filed cruise level."""
5254 return self._routePage.filedCruiseLevel
5255
5256 @property
5257 def filedCruiseAltitude(self):
5258 """Get the filed cruise altitude."""
5259 return self._routePage.filedCruiseLevel * 100
5260
5261 @property
5262 def cruiseAltitude(self):
5263 """Get the cruise altitude."""
5264 level = self._cruisePage.cruiseLevel if self._cruisePage.activated \
5265 else self._routePage.filedCruiseLevel
5266 return level * 100
5267
5268 @property
5269 def loggableCruiseAltitude(self):
5270 """Get the cruise altitude that can be logged."""
5271 if self._cruisePage.activated:
5272 return self._cruisePage.loggableCruiseLevel * 100
5273 else:
5274 return 0
5275
5276 @property
5277 def route(self):
5278 """Get the route."""
5279 return self._routePage.route
5280
5281 @property
5282 def alternate(self):
5283 """Get the ICAO code of the alternate airport."""
5284 return self._routePage.alternate
5285
5286 @property
5287 def departureMETAR(self):
5288 """Get the METAR of the departure airport."""
5289 return self._departureBriefingPage.metar
5290
5291 @property
5292 def arrivalMETAR(self):
5293 """Get the METAR of the arrival airport."""
5294 return self._arrivalBriefingPage.metar
5295
5296 @property
5297 def departureRunway(self):
5298 """Get the departure runway."""
5299 return self._takeoffPage.runway
5300
5301 @property
5302 def sid(self):
5303 """Get the SID."""
5304 return self._takeoffPage.sid
5305
5306 @property
5307 def v1(self):
5308 """Get the V1 speed."""
5309 return self._takeoffPage.v1
5310
5311 @property
5312 def vr(self):
5313 """Get the Vr speed."""
5314 return self._takeoffPage.vr
5315
5316 @property
5317 def v2(self):
5318 """Get the V2 speed."""
5319 return self._takeoffPage.v2
5320
5321 @property
5322 def derate(self):
5323 """Get the derate value."""
5324 return self._takeoffPage.derate
5325
5326 @property
5327 def takeoffAntiIceOn(self):
5328 """Get whether the anti-ice system was on during take-off."""
5329 return self._takeoffPage.antiIceOn
5330
5331 @takeoffAntiIceOn.setter
5332 def takeoffAntiIceOn(self, value):
5333 """Set anti-ice on indicator."""
5334 self._takeoffPage.antiIceOn = value
5335
5336 @property
5337 def rtoIndicated(self):
5338 """Get whether the pilot has indicated that an RTO has occured."""
5339 return self._takeoffPage.rtoIndicated
5340
5341 @property
5342 def arrivalRunway(self):
5343 """Get the arrival runway."""
5344 return self._landingPage.runway
5345
5346 @property
5347 def star(self):
5348 """Get the STAR."""
5349 return self._landingPage.star
5350
5351 @property
5352 def transition(self):
5353 """Get the transition."""
5354 return self._landingPage.transition
5355
5356 @property
5357 def approachType(self):
5358 """Get the approach type."""
5359 return self._landingPage.approachType
5360
5361 @property
5362 def vref(self):
5363 """Get the Vref speed."""
5364 return self._landingPage.vref
5365
5366 @property
5367 def landingAntiIceOn(self):
5368 """Get whether the anti-ice system was on during landing."""
5369 return self._landingPage.antiIceOn
5370
5371 @landingAntiIceOn.setter
5372 def landingAntiIceOn(self, value):
5373 """Set anti-ice on indicator."""
5374 self._landingPage.antiIceOn = value
5375
5376 @property
5377 def flightType(self):
5378 """Get the flight type."""
5379 return self._finishPage.flightType
5380
5381 @property
5382 def online(self):
5383 """Get whether the flight was online or not."""
5384 return self._finishPage.online
5385
5386 @property
5387 def usingSimBrief(self):
5388 """Indicate if we are using a SimBrief briefing or not."""
5389 return self._usingSimBrief
5390
5391 @usingSimBrief.setter
5392 def usingSimBrief(self, x):
5393 """Set whether we are using a SimBrief briefing or not."""
5394 self._usingSimBrief = x
5395
5396 def nextPage(self, finalize = True):
5397 """Go to the next page."""
5398 nextPageID = self._pages[self._currentPage].nextPageID
5399 self.jumpPage(1 if nextPageID is None else nextPageID, finalize)
5400
5401 def jumpPage(self, countOrID, finalize = True, fromPageShift = None):
5402 """Go to the page which is 'count' pages after the current one."""
5403 if isinstance(countOrID, str):
5404 targetIndex = self._getIndexOf(countOrID)
5405 else:
5406 targetIndex = self._currentPage + countOrID
5407 self.setCurrentPage(targetIndex,
5408 finalize = finalize, fromPageShift = fromPageShift)
5409
5410 def grabDefault(self):
5411 """Make the default button of the current page the default."""
5412 self._pages[self._currentPage].grabDefault()
5413
5414 def connected(self, fsType, descriptor):
5415 """Called when the connection could be made to the simulator."""
5416 self.nextPage()
5417
5418 def reset(self, loginResult):
5419 """Resets the wizard to go back to the login page."""
5420 self._initialize(keepLoginResult = loginResult is None,
5421 loginResult = loginResult)
5422
5423 def setStage(self, stage):
5424 """Set the flight stage to the given one."""
5425 if stage!=const.STAGE_END:
5426 self._cruisePage.setLoggable(Flight.canLogCruiseAltitude(stage))
5427
5428 if stage==const.STAGE_TAKEOFF:
5429 self._takeoffPage.allowForward()
5430 elif stage==const.STAGE_LANDING:
5431 if not self._arrivalBriefingPage.metarEdited:
5432 print "Downloading arrival METAR again"
5433 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
5434 [self._bookedFlight.arrivalICAO])
5435
5436 elif stage==const.STAGE_END:
5437 for page in self._pages:
5438 page.flightEnded()
5439
5440 def _initialize(self, keepLoginResult = False, loginResult = None):
5441 """Initialize the wizard."""
5442 if not keepLoginResult:
5443 self._loginResult = loginResult
5444
5445 self._loginCallback = None
5446
5447 self._fleet = None
5448 self._fleetCallback = None
5449
5450 self._bookedFlight = None
5451 self._departureGate = "-"
5452 self._fuelData = None
5453 self._departureNOTAMs = None
5454 self._departureMETAR = None
5455 self._arrivalNOTAMs = None
5456 self._arrivalMETAR = None
5457 self._usingSimBrief = None
5458 self.takeoffRunway = None
5459 self.landingRunway = None
5460
5461 firstPage = 0 if self._loginResult is None else 1
5462 for page in self._pages[firstPage:]:
5463 page.reset()
5464
5465 self.setCurrentPage(firstPage)
5466 #self.setCurrentPage(10)
5467
5468 def login(self, callback, pilotID, password):
5469 """Called when the login button was clicked."""
5470 self._loginCallback = callback
5471 if pilotID is None:
5472 loginResult = self._loginResult
5473 assert loginResult is not None and loginResult.loggedIn
5474 pilotID = loginResult.pilotID
5475 password = loginResult.password
5476 busyMessage = xstr("reload_busy")
5477 else:
5478 self._loginResult = None
5479 busyMessage = xstr("login_busy")
5480
5481 self.gui.beginBusy(busyMessage)
5482
5483 self.gui.webHandler.login(self._loginResultCallback,
5484 pilotID, password)
5485
5486 def reloadFlights(self, callback):
5487 """Reload the flights from the MAVA server."""
5488 self.login(callback, None, None)
5489
5490 def reflyFlight(self, bookedFlight):
5491 """Add the given booked flight to the flight selection page."""
5492 self._removePendingFlight(bookedFlight)
5493 self._flightSelectionPage._reflyFlight(bookedFlight)
5494
5495 def cancelFlight(self, reloadCallback):
5496 """Cancel the flight.
5497
5498 If it is an entry exam flight, we go back to the student page.
5499 Otherwise we reload the flights."""
5500 if self.entranceExam:
5501 self.reset(None)
5502 self.jumpPage("student")
5503 else:
5504 self.reloadFlights(reloadCallback)
5505
5506 def cruiseLevelChanged(self):
5507 """Called when the cruise level is changed."""
5508 return self.gui.cruiseLevelChanged()
5509
5510 def metarChanged(self, metar, originator):
5511 """Called when a METER is changed on on of the pages.
5512
5513 originator is the page that originated the changed. It will be used to
5514 determine which METAR (departure or arrival) has changed."""
5515 metar = metar.upper()
5516 if originator in [self._departureBriefingPage, self._takeoffPage]:
5517 self.departureMETARChanged(metar, originator)
5518 else:
5519 self.arrivalMETARChanged(metar, originator)
5520
5521 def departureMETARChanged(self, metar, originator):
5522 """Called when the departure METAR has been edited on one of the
5523 pages.
5524
5525 originator is the page that originated the change. It will not be
5526 called to set the METAR, while others will be."""
5527 for page in [self._departureBriefingPage, self._takeoffPage]:
5528 if page is not originator:
5529 page.changeMETAR(metar)
5530
5531 def arrivalMETARChanged(self, metar, originator):
5532 """Called when the arrival METAR has been edited on one of the
5533 pages.
5534
5535 originator is the page that originated the change. It will not be
5536 called to set the METAR, while others will be."""
5537 for page in [self._arrivalBriefingPage, self._landingPage]:
5538 if page is not originator:
5539 page.changeMETAR(metar)
5540
5541 def _removePendingFlight(self, flight):
5542 """Remove the given pending flight from the login result."""
5543 for flights in [self._loginResult.reportedFlights,
5544 self._loginResult.rejectedFlights]:
5545 for f in flights:
5546 if f.id==flight.id:
5547 flights.remove(f)
5548 return
5549
5550 def _loginResultCallback(self, returned, result):
5551 """The login result callback, called in the web handler's thread."""
5552 gobject.idle_add(self._handleLoginResult, returned, result)
5553
5554 def _handleLoginResult(self, returned, result):
5555 """Handle the login result."""
5556 self.gui.endBusy()
5557 isReload = self._loginResult is not None
5558 if returned:
5559 if result.loggedIn:
5560 self._loginResult = result
5561 else:
5562 if isReload:
5563 message = xstr("reload_failed")
5564 else:
5565 message = xstr("login_entranceExam_invalid"
5566 if self.entranceExam else
5567 xstr("login_invalid"))
5568 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
5569 type = MESSAGETYPE_ERROR,
5570 message_format = message)
5571 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
5572 dialog.set_title(WINDOW_TITLE_BASE)
5573 if isReload:
5574 secondary = xstr("reload_failed_sec")
5575 else:
5576 secondary = xstr("login_entranceExam_invalid_sec"
5577 if self.entranceExam else
5578 xstr("login_invalid_sec"))
5579 dialog.format_secondary_markup(secondary)
5580 dialog.run()
5581 dialog.hide()
5582 else:
5583 message = xstr("reload_failconn") if isReload \
5584 else xstr("login_failconn")
5585 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
5586 type = MESSAGETYPE_ERROR,
5587 message_format = message)
5588 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
5589 dialog.set_title(WINDOW_TITLE_BASE)
5590 secondary = xstr("reload_failconn_sec") if isReload \
5591 else xstr("login_failconn_sec")
5592 dialog.format_secondary_markup(secondary)
5593
5594 dialog.run()
5595 dialog.hide()
5596
5597 callback = self._loginCallback
5598 self._loginCallback = None
5599 callback(returned, result)
5600
5601 def getFleet(self, callback, force = False):
5602 """Get the fleet via the GUI and call the given callback."""
5603 self._fleetCallback = callback
5604 self.gui.getFleet(callback = self._fleetRetrieved, force = force)
5605
5606 def _fleetRetrieved(self, fleet):
5607 """Callback for the fleet retrieval."""
5608 self._fleet = fleet
5609 if self._fleetCallback is not None:
5610 self._fleetCallback(fleet)
5611 self._fleetCallback = None
5612
5613 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
5614 """Update the given plane's gate information."""
5615 self.gui.updatePlane(tailNumber, status, gateNumber = gateNumber,
5616 callback = callback)
5617
5618 def updateRTO(self):
5619 """Update the RTO state.
5620
5621 The RTO checkbox will be enabled if the flight has an RTO state and the
5622 comments field contains some text."""
5623 flight = self.gui.flight
5624 rtoEnabled = flight is not None and flight.hasRTO and \
5625 self.gui.hasComments
5626 self._takeoffPage.setRTOEnabled(rtoEnabled)
5627
5628 def commentsChanged(self):
5629 """Called when the comments have changed."""
5630 self.updateRTO()
5631 self._finishPage.updateButtons()
5632
5633 def delayCodesChanged(self):
5634 """Called when the delay codes have changed."""
5635 self._finishPage.updateButtons()
5636
5637 def faultExplanationsChanged(self):
5638 """Called when the faults and their explanations have changed."""
5639 self._finishPage.updateButtons()
5640
5641 def rtoToggled(self, indicated):
5642 """Called when the RTO indication has changed."""
5643 self.gui.rtoToggled(indicated)
5644
5645 def _connectSimulator(self, simulatorType):
5646 """Connect to the simulator."""
5647 self.gui.connectSimulator(self._bookedFlight, simulatorType)
5648
5649 def _arrivalMETARCallback(self, returned, result):
5650 """Called when the METAR of the arrival airport is retrieved."""
5651 gobject.idle_add(self._handleArrivalMETAR, returned, result)
5652
5653 def _handleArrivalMETAR(self, returned, result):
5654 """Called when the METAR of the arrival airport is retrieved."""
5655 icao = self._bookedFlight.arrivalICAO
5656 if returned and icao in result.metars:
5657 metar = result.metars[icao]
5658 if metar!="":
5659 self._arrivalBriefingPage.setMETAR(metar)
5660
5661 def _getIndexOf(self, pageID):
5662 """Get the index for the given page ID.
5663
5664 It is an assertion failure if the ID is not found."""
5665 for index in range(0, len(self._pages)):
5666 page = self._pages[index]
5667 if page.id==pageID:
5668 return index
5669 assert False
5670
5671#-----------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.