source: src/mlx/gui/flight.py@ 303:8d5607e36aed

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

The number of the crew and the passengers as well as all payload weights can be edited

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