source: src/mlx/gui/flight.py@ 625:363e7cf53546

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

The flight should exist and be at the end for the buttons to be active and PIREP be saved

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