source: src/mlx/gui/flight.py@ 563:90d7776ec939

Last change on this file since 563:90d7776ec939 was 563:90d7776ec939, checked in by István Váradi <ivaradi@…>, 10 years ago

Added help text to be displayed if the arrival and/or departure times differ too much from the schedule (re #227)

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