source: src/mlx/gui/flight.py@ 304:9bfef8224383

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

Cruise level changes are logged

File size: 120.4 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 self._wizard.cruiseLevelChanged()
1738
1739 def _routeChanged(self, textBuffer):
1740 """Called when the route has changed."""
1741 if not self._uppercasingRoute:
1742 self._updateForwardButton()
1743
1744 def _routeInserted(self, textBuffer, iter, text, length):
1745 """Called when new characters are inserted into the route.
1746
1747 It uppercases all characters."""
1748 if not self._uppercasingRoute:
1749 self._uppercasingRoute = True
1750
1751 iter1 = iter.copy()
1752 iter1.backward_chars(length)
1753 textBuffer.delete(iter, iter1)
1754
1755 textBuffer.insert(iter, text.upper())
1756
1757 self._uppercasingRoute = False
1758
1759 def _backClicked(self, button):
1760 """Called when the Back button is pressed."""
1761 self.goBack()
1762
1763 def _forwardClicked(self, button):
1764 """Called when the Forward button is clicked."""
1765 if self._completed:
1766 self._wizard.nextPage()
1767 else:
1768 bookedFlight = self._wizard._bookedFlight
1769 self._filedCruiseLevel = self.cruiseLevel
1770 self._wizard.gui.beginBusy(xstr("route_down_notams"))
1771 self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
1772 bookedFlight.departureICAO,
1773 bookedFlight.arrivalICAO)
1774 startSound(const.SOUND_NOTAM)
1775
1776 def _notamsCallback(self, returned, result):
1777 """Callback for the NOTAMs."""
1778 gobject.idle_add(self._handleNOTAMs, returned, result)
1779
1780 def _handleNOTAMs(self, returned, result):
1781 """Handle the NOTAMs."""
1782 if returned:
1783 self._wizard._departureNOTAMs = result.departureNOTAMs
1784 self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
1785 else:
1786 self._wizard._departureNOTAMs = None
1787 self._wizard._arrivalNOTAMs = None
1788
1789 bookedFlight = self._wizard._bookedFlight
1790 self._wizard.gui.beginBusy(xstr("route_down_metars"))
1791 self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
1792 [bookedFlight.departureICAO,
1793 bookedFlight.arrivalICAO])
1794
1795 def _metarsCallback(self, returned, result):
1796 """Callback for the METARs."""
1797 gobject.idle_add(self._handleMETARs, returned, result)
1798
1799 def _handleMETARs(self, returned, result):
1800 """Handle the METARs."""
1801 self._wizard._departureMETAR = None
1802 self._wizard._arrivalMETAR = None
1803 bookedFlight = self._wizard._bookedFlight
1804 if returned:
1805 if bookedFlight.departureICAO in result.metars:
1806 self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
1807 if bookedFlight.arrivalICAO in result.metars:
1808 self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
1809
1810 self._wizard.gui.endBusy()
1811 self._backButton.set_sensitive(True)
1812 self._button.set_sensitive(True)
1813 self._wizard.nextPage()
1814
1815#-----------------------------------------------------------------------------
1816
1817class BriefingPage(Page):
1818 """Page for the briefing."""
1819 def __init__(self, wizard, departure):
1820 """Construct the briefing page."""
1821 self._departure = departure
1822
1823 title = xstr("briefing_title") % (1 if departure else 2,
1824 xstr("briefing_departure")
1825 if departure
1826 else xstr("briefing_arrival"))
1827 super(BriefingPage, self).__init__(wizard, title, xstr("briefing_help"),
1828 completedHelp = xstr("briefing_chelp"))
1829
1830 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1831 xscale = 1.0, yscale = 1.0)
1832
1833 mainBox = gtk.VBox()
1834 alignment.add(mainBox)
1835 self.setMainWidget(alignment)
1836
1837 self._notamsFrame = gtk.Frame()
1838 self._notamsFrame.set_label(xstr("briefing_notams_init"))
1839 scrolledWindow = gtk.ScrolledWindow()
1840 scrolledWindow.set_size_request(-1, 128)
1841 # FIXME: these constants should be in common
1842 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1843 else gtk.POLICY_AUTOMATIC,
1844 gtk.PolicyType.AUTOMATIC if pygobject
1845 else gtk.POLICY_AUTOMATIC)
1846 self._notams = gtk.TextView()
1847 self._notams.set_editable(False)
1848 self._notams.set_accepts_tab(False)
1849 self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
1850 scrolledWindow.add(self._notams)
1851 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1852 xscale = 1.0, yscale = 1.0)
1853 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1854 padding_left = 0, padding_right = 0)
1855 alignment.add(scrolledWindow)
1856 self._notamsFrame.add(alignment)
1857 mainBox.pack_start(self._notamsFrame, True, True, 4)
1858
1859 self._metarFrame = gtk.Frame()
1860 self._metarFrame.set_label(xstr("briefing_metar_init"))
1861 scrolledWindow = gtk.ScrolledWindow()
1862 scrolledWindow.set_size_request(-1, 32)
1863 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1864 else gtk.POLICY_AUTOMATIC,
1865 gtk.PolicyType.AUTOMATIC if pygobject
1866 else gtk.POLICY_AUTOMATIC)
1867
1868 self._uppercasingMETAR = False
1869
1870 self._metar = gtk.TextView()
1871 self._metar.set_accepts_tab(False)
1872 self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
1873 self._metar.get_buffer().connect("changed", self._metarChanged)
1874 self._metar.get_buffer().connect_after("insert-text", self._metarInserted)
1875 scrolledWindow.add(self._metar)
1876 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1877 xscale = 1.0, yscale = 1.0)
1878 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1879 padding_left = 0, padding_right = 0)
1880 alignment.add(scrolledWindow)
1881 self._metarFrame.add(alignment)
1882 mainBox.pack_start(self._metarFrame, True, True, 4)
1883 self.metarEdited = False
1884
1885 self.addCancelFlightButton()
1886
1887 self.addPreviousButton(clicked = self._backClicked)
1888 self._button = self.addNextButton(clicked = self._forwardClicked)
1889
1890 @property
1891 def metar(self):
1892 """Get the METAR on the page."""
1893 buffer = self._metar.get_buffer()
1894 return buffer.get_text(buffer.get_start_iter(),
1895 buffer.get_end_iter(), True)
1896
1897 def setMETAR(self, metar):
1898 """Set the metar."""
1899 self._metar.get_buffer().set_text(metar)
1900 self.metarEdited = False
1901
1902 def activate(self):
1903 """Activate the page."""
1904 if not self._departure:
1905 self._button.set_label(xstr("briefing_button"))
1906 self._button.set_has_tooltip(False)
1907 self._button.set_use_stock(False)
1908
1909 bookedFlight = self._wizard._bookedFlight
1910
1911 icao = bookedFlight.departureICAO if self._departure \
1912 else bookedFlight.arrivalICAO
1913 notams = self._wizard._departureNOTAMs if self._departure \
1914 else self._wizard._arrivalNOTAMs
1915 metar = self._wizard._departureMETAR if self._departure \
1916 else self._wizard._arrivalMETAR
1917
1918 self._notamsFrame.set_label(xstr("briefing_notams_template") % (icao,))
1919 buffer = self._notams.get_buffer()
1920 if notams is None:
1921 buffer.set_text(xstr("briefing_notams_failed"))
1922 elif not notams:
1923 buffer.set_text(xstr("briefing_notams_missing"))
1924 else:
1925 s = ""
1926 for notam in notams:
1927 s += str(notam.begin)
1928 if notam.end is not None:
1929 s += " - " + str(notam.end)
1930 elif notam.permanent:
1931 s += " - PERMANENT"
1932 s += "\n"
1933 if notam.repeatCycle:
1934 s += "Repeat cycle: " + notam.repeatCycle + "\n"
1935 s += notam.notice + "\n"
1936 s += "-------------------- * --------------------\n"
1937 buffer.set_text(s)
1938
1939 self._metarFrame.set_label(xstr("briefing_metar_template") % (icao,))
1940 buffer = self._metar.get_buffer()
1941 if metar is None:
1942 buffer.set_text(xstr("briefing_metar_failed"))
1943 else:
1944 buffer.set_text(metar)
1945
1946 label = self._metarFrame.get_label_widget()
1947 label.set_use_underline(True)
1948 label.set_mnemonic_widget(self._metar)
1949
1950 self.metarEdited = False
1951
1952 def _backClicked(self, button):
1953 """Called when the Back button is pressed."""
1954 self.goBack()
1955
1956 def _forwardClicked(self, button):
1957 """Called when the forward button is clicked."""
1958 if not self._departure:
1959 if not self._completed:
1960 self._wizard.gui.startMonitoring()
1961 self._button.set_label(xstr("button_next"))
1962 self._button.set_tooltip_text(xstr("button_next_tooltip"))
1963 self.complete()
1964
1965 self._wizard.nextPage()
1966
1967 def _metarChanged(self, buffer):
1968 """Called when the METAR has changed."""
1969 if not self._uppercasingMETAR:
1970 self.metarEdited = True
1971 self._button.set_sensitive(buffer.get_text(buffer.get_start_iter(),
1972 buffer.get_end_iter(),
1973 True)!="")
1974
1975 def _metarInserted(self, textBuffer, iter, text, length):
1976 """Called when new characters are inserted into the METAR.
1977
1978 It uppercases all characters."""
1979 if not self._uppercasingMETAR:
1980 self._uppercasingMETAR = True
1981
1982 iter1 = iter.copy()
1983 iter1.backward_chars(length)
1984 textBuffer.delete(iter, iter1)
1985
1986 textBuffer.insert(iter, text.upper())
1987
1988 self._uppercasingMETAR = False
1989
1990#-----------------------------------------------------------------------------
1991
1992class TakeoffPage(Page):
1993 """Page for entering the takeoff data."""
1994 def __init__(self, wizard):
1995 """Construct the takeoff page."""
1996 super(TakeoffPage, self).__init__(wizard, xstr("takeoff_title"),
1997 xstr("takeoff_help"),
1998 completedHelp = xstr("takeoff_chelp"))
1999
2000 self._forwardAllowed = False
2001
2002 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2003 xscale = 0.0, yscale = 0.0)
2004
2005 table = gtk.Table(5, 4)
2006 table.set_row_spacings(4)
2007 table.set_col_spacings(16)
2008 table.set_homogeneous(False)
2009 alignment.add(table)
2010 self.setMainWidget(alignment)
2011
2012 label = gtk.Label(xstr("takeoff_runway"))
2013 label.set_use_underline(True)
2014 label.set_alignment(0.0, 0.5)
2015 table.attach(label, 0, 1, 0, 1)
2016
2017 self._runway = gtk.Entry()
2018 self._runway.set_width_chars(10)
2019 self._runway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
2020 self._runway.connect("changed", self._upperChanged)
2021 table.attach(self._runway, 1, 3, 0, 1)
2022 label.set_mnemonic_widget(self._runway)
2023
2024 label = gtk.Label(xstr("takeoff_sid"))
2025 label.set_use_underline(True)
2026 label.set_alignment(0.0, 0.5)
2027 table.attach(label, 0, 1, 1, 2)
2028
2029 self._sid = gtk.Entry()
2030 self._sid.set_width_chars(10)
2031 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
2032 self._sid.connect("changed", self._upperChanged)
2033 table.attach(self._sid, 1, 3, 1, 2)
2034 label.set_mnemonic_widget(self._sid)
2035
2036 label = gtk.Label(xstr("takeoff_v1"))
2037 label.set_use_markup(True)
2038 label.set_use_underline(True)
2039 label.set_alignment(0.0, 0.5)
2040 table.attach(label, 0, 1, 2, 3)
2041
2042 self._v1 = IntegerEntry()
2043 self._v1.set_width_chars(4)
2044 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip_knots"))
2045 self._v1.connect("integer-changed", self._valueChanged)
2046 table.attach(self._v1, 2, 3, 2, 3)
2047 label.set_mnemonic_widget(self._v1)
2048
2049 self._v1Unit = gtk.Label(xstr("label_knots"))
2050 table.attach(self._v1Unit, 3, 4, 2, 3)
2051
2052 label = gtk.Label(xstr("takeoff_vr"))
2053 label.set_use_markup(True)
2054 label.set_use_underline(True)
2055 label.set_alignment(0.0, 0.5)
2056 table.attach(label, 0, 1, 3, 4)
2057
2058 self._vr = IntegerEntry()
2059 self._vr.set_width_chars(4)
2060 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip_knots"))
2061 self._vr.connect("integer-changed", self._valueChanged)
2062 table.attach(self._vr, 2, 3, 3, 4)
2063 label.set_mnemonic_widget(self._vr)
2064
2065 self._vrUnit = gtk.Label(xstr("label_knots"))
2066 table.attach(self._vrUnit, 3, 4, 3, 4)
2067
2068 label = gtk.Label(xstr("takeoff_v2"))
2069 label.set_use_markup(True)
2070 label.set_use_underline(True)
2071 label.set_alignment(0.0, 0.5)
2072 table.attach(label, 0, 1, 4, 5)
2073
2074 self._v2 = IntegerEntry()
2075 self._v2.set_width_chars(4)
2076 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip_knots"))
2077 self._v2.connect("integer-changed", self._valueChanged)
2078 table.attach(self._v2, 2, 3, 4, 5)
2079 label.set_mnemonic_widget(self._v2)
2080
2081 self._v2Unit = gtk.Label(xstr("label_knots"))
2082 table.attach(self._v2Unit, 3, 4, 4, 5)
2083
2084 self.addCancelFlightButton()
2085
2086 self.addPreviousButton(clicked = self._backClicked)
2087
2088 self._button = self.addNextButton(clicked = self._forwardClicked)
2089
2090 @property
2091 def runway(self):
2092 """Get the runway."""
2093 return self._runway.get_text()
2094
2095 @property
2096 def sid(self):
2097 """Get the SID."""
2098 return self._sid.get_text()
2099
2100 @property
2101 def v1(self):
2102 """Get the v1 speed."""
2103 return self._v1.get_int()
2104
2105 @property
2106 def vr(self):
2107 """Get the vr speed."""
2108 return self._vr.get_int()
2109
2110 @property
2111 def v2(self):
2112 """Get the v2 speed."""
2113 return self._v2.get_int()
2114
2115 def activate(self):
2116 """Activate the page."""
2117 self._runway.set_text("")
2118 self._runway.set_sensitive(True)
2119 self._sid.set_text("")
2120 self._sid.set_sensitive(True)
2121 self._v1.set_int(None)
2122 self._v1.set_sensitive(True)
2123 self._vr.set_int(None)
2124 self._vr.set_sensitive(True)
2125 self._v2.set_int(None)
2126 self._v2.set_sensitive(True)
2127
2128 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
2129 speedUnit = xstr("label" + i18nSpeedUnit)
2130 self._v1Unit.set_text(speedUnit)
2131 self._vrUnit.set_text(speedUnit)
2132 self._v2Unit.set_text(speedUnit)
2133
2134 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip" + i18nSpeedUnit))
2135 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip" + i18nSpeedUnit))
2136 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip" + i18nSpeedUnit))
2137
2138 self._button.set_sensitive(False)
2139 self._forwardAllowed = False
2140
2141 def allowForward(self):
2142 """Allow going to the next page."""
2143 self._forwardAllowed = True
2144 self._updateForwardButton()
2145
2146 def reset(self):
2147 """Reset the page if the wizard is reset."""
2148 super(TakeoffPage, self).reset()
2149 self._v1.reset()
2150 self._vr.reset()
2151 self._v2.reset()
2152
2153 def _updateForwardButton(self):
2154 """Update the sensitivity of the forward button based on some conditions."""
2155 sensitive = self._forwardAllowed and \
2156 self._runway.get_text()!="" and \
2157 self._sid.get_text()!="" and \
2158 self.v1 is not None and \
2159 self.vr is not None and \
2160 self.v2 is not None and \
2161 self.v1 <= self.vr and \
2162 self.vr <= self.v2
2163 self._button.set_sensitive(sensitive)
2164
2165 def _valueChanged(self, widget, arg = None):
2166 """Called when the value of some widget has changed."""
2167 self._updateForwardButton()
2168
2169 def _upperChanged(self, entry, arg = None):
2170 """Called when the value of some entry widget has changed and the value
2171 should be converted to uppercase."""
2172 entry.set_text(entry.get_text().upper())
2173 self._valueChanged(entry, arg)
2174
2175 def _backClicked(self, button):
2176 """Called when the Back button is pressed."""
2177 self.goBack()
2178
2179 def _forwardClicked(self, button):
2180 """Called when the forward button is clicked."""
2181 self._wizard.gui.flight.aircraft.updateV1R2()
2182 self._wizard.nextPage()
2183
2184#-----------------------------------------------------------------------------
2185
2186class LandingPage(Page):
2187 """Page for entering landing data."""
2188 def __init__(self, wizard):
2189 """Construct the landing page."""
2190 super(LandingPage, self).__init__(wizard, xstr("landing_title"),
2191 xstr("landing_help"),
2192 completedHelp = xstr("landing_chelp"))
2193
2194 self._flightEnded = False
2195
2196 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2197 xscale = 0.0, yscale = 0.0)
2198
2199 table = gtk.Table(5, 5)
2200 table.set_row_spacings(4)
2201 table.set_col_spacings(16)
2202 table.set_homogeneous(False)
2203 alignment.add(table)
2204 self.setMainWidget(alignment)
2205
2206 self._starButton = gtk.CheckButton()
2207 self._starButton.connect("clicked", self._starButtonClicked)
2208 table.attach(self._starButton, 0, 1, 0, 1)
2209
2210 label = gtk.Label(xstr("landing_star"))
2211 label.set_use_underline(True)
2212 label.set_alignment(0.0, 0.5)
2213 table.attach(label, 1, 2, 0, 1)
2214
2215 self._star = gtk.Entry()
2216 self._star.set_width_chars(10)
2217 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
2218 self._star.connect("changed", self._upperChanged)
2219 self._star.set_sensitive(False)
2220 table.attach(self._star, 2, 4, 0, 1)
2221 label.set_mnemonic_widget(self._starButton)
2222
2223 self._transitionButton = gtk.CheckButton()
2224 self._transitionButton.connect("clicked", self._transitionButtonClicked)
2225 table.attach(self._transitionButton, 0, 1, 1, 2)
2226
2227 label = gtk.Label(xstr("landing_transition"))
2228 label.set_use_underline(True)
2229 label.set_alignment(0.0, 0.5)
2230 table.attach(label, 1, 2, 1, 2)
2231
2232 self._transition = gtk.Entry()
2233 self._transition.set_width_chars(10)
2234 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
2235 self._transition.connect("changed", self._upperChanged)
2236 self._transition.set_sensitive(False)
2237 table.attach(self._transition, 2, 4, 1, 2)
2238 label.set_mnemonic_widget(self._transitionButton)
2239
2240 label = gtk.Label(xstr("landing_runway"))
2241 label.set_use_underline(True)
2242 label.set_alignment(0.0, 0.5)
2243 table.attach(label, 1, 2, 2, 3)
2244
2245 self._runway = gtk.Entry()
2246 self._runway.set_width_chars(10)
2247 self._runway.set_tooltip_text(xstr("landing_runway_tooltip"))
2248 self._runway.connect("changed", self._upperChanged)
2249 table.attach(self._runway, 2, 4, 2, 3)
2250 label.set_mnemonic_widget(self._runway)
2251
2252 label = gtk.Label(xstr("landing_approach"))
2253 label.set_use_underline(True)
2254 label.set_alignment(0.0, 0.5)
2255 table.attach(label, 1, 2, 3, 4)
2256
2257 self._approachType = gtk.Entry()
2258 self._approachType.set_width_chars(10)
2259 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
2260 self._approachType.connect("changed", self._upperChanged)
2261 table.attach(self._approachType, 2, 4, 3, 4)
2262 label.set_mnemonic_widget(self._approachType)
2263
2264 label = gtk.Label(xstr("landing_vref"))
2265 label.set_use_markup(True)
2266 label.set_use_underline(True)
2267 label.set_alignment(0.0, 0.5)
2268 table.attach(label, 1, 2, 5, 6)
2269
2270 self._vref = IntegerEntry()
2271 self._vref.set_width_chars(5)
2272 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip_knots"))
2273 self._vref.connect("integer-changed", self._vrefChanged)
2274 table.attach(self._vref, 3, 4, 5, 6)
2275 label.set_mnemonic_widget(self._vref)
2276
2277 self._vrefUnit = gtk.Label(xstr("label_knots"))
2278 table.attach(self._vrefUnit, 4, 5, 5, 6)
2279
2280 self.addCancelFlightButton()
2281
2282 self.addPreviousButton(clicked = self._backClicked)
2283
2284 self._button = self.addNextButton(clicked = self._forwardClicked)
2285
2286 # These are needed for correct size calculations
2287 self._starButton.set_active(True)
2288 self._transitionButton.set_active(True)
2289
2290 @property
2291 def star(self):
2292 """Get the STAR or None if none entered."""
2293 return self._star.get_text() if self._starButton.get_active() else None
2294
2295 @property
2296 def transition(self):
2297 """Get the transition or None if none entered."""
2298 return self._transition.get_text() \
2299 if self._transitionButton.get_active() else None
2300
2301 @property
2302 def approachType(self):
2303 """Get the approach type."""
2304 return self._approachType.get_text()
2305
2306 @property
2307 def runway(self):
2308 """Get the runway."""
2309 return self._runway.get_text()
2310
2311 @property
2312 def vref(self):
2313 """Return the landing reference speed."""
2314 return self._vref.get_int()
2315
2316 def reset(self):
2317 """Reset the page if the wizard is reset."""
2318 super(LandingPage, self).reset()
2319 self._vref.reset()
2320 self._flightEnded = False
2321
2322 def activate(self):
2323 """Called when the page is activated."""
2324 self._starButton.set_sensitive(True)
2325 self._starButton.set_active(False)
2326 self._star.set_text("")
2327
2328 self._transitionButton.set_sensitive(True)
2329 self._transitionButton.set_active(False)
2330 self._transition.set_text("")
2331
2332 self._runway.set_text("")
2333 self._runway.set_sensitive(True)
2334
2335 self._approachType.set_text("")
2336 self._approachType.set_sensitive(True)
2337
2338 self._vref.set_int(None)
2339 self._vref.set_sensitive(True)
2340
2341 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
2342 speedUnit = xstr("label" + i18nSpeedUnit)
2343 self._vrefUnit.set_text(speedUnit)
2344
2345 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip" +
2346 i18nSpeedUnit))
2347
2348 self._updateForwardButton()
2349
2350 def flightEnded(self):
2351 """Called when the flight has ended."""
2352 super(LandingPage, self).flightEnded()
2353 self._flightEnded = True
2354 self._updateForwardButton()
2355
2356 def _starButtonClicked(self, button):
2357 """Called when the STAR button is clicked."""
2358 active = button.get_active()
2359 self._star.set_sensitive(active)
2360 if active:
2361 self._star.grab_focus()
2362 self._updateForwardButton()
2363
2364 def _transitionButtonClicked(self, button):
2365 """Called when the Transition button is clicked."""
2366 active = button.get_active()
2367 self._transition.set_sensitive(active)
2368 if active:
2369 self._transition.grab_focus()
2370 self._updateForwardButton()
2371
2372 def _updateForwardButton(self):
2373 """Update the sensitivity of the forward button."""
2374 sensitive = self._flightEnded and \
2375 (self._starButton.get_active() or \
2376 self._transitionButton.get_active()) and \
2377 (self._star.get_text()!="" or
2378 not self._starButton.get_active()) and \
2379 (self._transition.get_text()!="" or
2380 not self._transitionButton.get_active()) and \
2381 self._runway.get_text()!="" and \
2382 self._approachType.get_text()!="" and \
2383 self.vref is not None
2384 self._button.set_sensitive(sensitive)
2385
2386 def _upperChanged(self, entry):
2387 """Called for entry widgets that must be converted to uppercase."""
2388 entry.set_text(entry.get_text().upper())
2389 self._updateForwardButton()
2390
2391 def _vrefChanged(self, widget, value):
2392 """Called when the Vref has changed."""
2393 self._updateForwardButton()
2394
2395 def _backClicked(self, button):
2396 """Called when the Back button is pressed."""
2397 self.goBack()
2398
2399 def _forwardClicked(self, button):
2400 """Called when the forward button is clicked."""
2401 self._wizard.gui.flight.aircraft.updateVRef()
2402 if self._wizard.gui.config.onlineGateSystem and \
2403 self._wizard.loggedIn and not self._completed and \
2404 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
2405 not self._wizard.entranceExam:
2406 self._wizard.getFleet(callback = self._fleetRetrieved,
2407 force = True)
2408 else:
2409 self._wizard.nextPage()
2410
2411 def _fleetRetrieved(self, fleet):
2412 """Callback for the fleet retrieval."""
2413 self._wizard.nextPage()
2414
2415#-----------------------------------------------------------------------------
2416
2417class FinishPage(Page):
2418 """Flight finish page."""
2419 _flightTypes = [ ("flighttype_scheduled", const.FLIGHTTYPE_SCHEDULED),
2420 ("flighttype_ot", const.FLIGHTTYPE_OLDTIMER),
2421 ("flighttype_vip", const.FLIGHTTYPE_VIP),
2422 ("flighttype_charter", const.FLIGHTTYPE_CHARTER) ]
2423
2424 def __init__(self, wizard):
2425 """Construct the finish page."""
2426 super(FinishPage, self).__init__(wizard, xstr("finish_title"),
2427 xstr("finish_help"))
2428
2429 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2430 xscale = 0.0, yscale = 0.0)
2431
2432 table = gtk.Table(8, 2)
2433 table.set_row_spacings(4)
2434 table.set_col_spacings(16)
2435 table.set_homogeneous(False)
2436 alignment.add(table)
2437 self.setMainWidget(alignment)
2438
2439 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2440 label = gtk.Label(xstr("finish_rating"))
2441 labelAlignment.add(label)
2442 table.attach(labelAlignment, 0, 1, 0, 1)
2443
2444 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2445 self._flightRating = gtk.Label()
2446 self._flightRating.set_width_chars(8)
2447 self._flightRating.set_alignment(0.0, 0.5)
2448 self._flightRating.set_use_markup(True)
2449 labelAlignment.add(self._flightRating)
2450 table.attach(labelAlignment, 1, 2, 0, 1)
2451
2452 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2453 label = gtk.Label(xstr("finish_flight_time"))
2454 labelAlignment.add(label)
2455 table.attach(labelAlignment, 0, 1, 1, 2)
2456
2457 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2458 self._flightTime = gtk.Label()
2459 self._flightTime.set_width_chars(10)
2460 self._flightTime.set_alignment(0.0, 0.5)
2461 self._flightTime.set_use_markup(True)
2462 labelAlignment.add(self._flightTime)
2463 table.attach(labelAlignment, 1, 2, 1, 2)
2464
2465 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2466 label = gtk.Label(xstr("finish_block_time"))
2467 labelAlignment.add(label)
2468 table.attach(labelAlignment, 0, 1, 2, 3)
2469
2470 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2471 self._blockTime = gtk.Label()
2472 self._blockTime.set_width_chars(10)
2473 self._blockTime.set_alignment(0.0, 0.5)
2474 self._blockTime.set_use_markup(True)
2475 labelAlignment.add(self._blockTime)
2476 table.attach(labelAlignment, 1, 2, 2, 3)
2477
2478 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2479 label = gtk.Label(xstr("finish_distance"))
2480 labelAlignment.add(label)
2481 table.attach(labelAlignment, 0, 1, 3, 4)
2482
2483 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2484 self._distanceFlown = gtk.Label()
2485 self._distanceFlown.set_width_chars(10)
2486 self._distanceFlown.set_alignment(0.0, 0.5)
2487 self._distanceFlown.set_use_markup(True)
2488 labelAlignment.add(self._distanceFlown)
2489 table.attach(labelAlignment, 1, 2, 3, 4)
2490
2491 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2492 label = gtk.Label(xstr("finish_fuel"))
2493 labelAlignment.add(label)
2494 table.attach(labelAlignment, 0, 1, 4, 5)
2495
2496 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2497 self._fuelUsed = gtk.Label()
2498 self._fuelUsed.set_width_chars(10)
2499 self._fuelUsed.set_alignment(0.0, 0.5)
2500 self._fuelUsed.set_use_markup(True)
2501 labelAlignment.add(self._fuelUsed)
2502 table.attach(labelAlignment, 1, 2, 4, 5)
2503
2504 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
2505 yalign = 0.5, yscale = 0.0)
2506 label = gtk.Label(xstr("finish_type"))
2507 label.set_use_underline(True)
2508 labelAlignment.add(label)
2509 table.attach(labelAlignment, 0, 1, 5, 6)
2510
2511 flightTypeModel = gtk.ListStore(str, int)
2512 for (name, type) in FinishPage._flightTypes:
2513 flightTypeModel.append([xstr(name), type])
2514
2515 self._flightType = gtk.ComboBox(model = flightTypeModel)
2516 renderer = gtk.CellRendererText()
2517 self._flightType.pack_start(renderer, True)
2518 self._flightType.add_attribute(renderer, "text", 0)
2519 self._flightType.set_tooltip_text(xstr("finish_type_tooltip"))
2520 self._flightType.set_active(0)
2521 self._flightType.connect("changed", self._flightTypeChanged)
2522 flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2523 flightTypeAlignment.add(self._flightType)
2524 table.attach(flightTypeAlignment, 1, 2, 5, 6)
2525 label.set_mnemonic_widget(self._flightType)
2526
2527 self._onlineFlight = gtk.CheckButton(xstr("finish_online"))
2528 self._onlineFlight.set_use_underline(True)
2529 self._onlineFlight.set_tooltip_text(xstr("finish_online_tooltip"))
2530 onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2531 onlineFlightAlignment.add(self._onlineFlight)
2532 table.attach(onlineFlightAlignment, 1, 2, 6, 7)
2533
2534 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
2535 yalign = 0.5, yscale = 0.0)
2536 self._gateLabel = gtk.Label(xstr("finish_gate"))
2537 self._gateLabel.set_use_underline(True)
2538 labelAlignment.add(self._gateLabel)
2539 table.attach(labelAlignment, 0, 1, 7, 8)
2540
2541 self._gatesModel = gtk.ListStore(str)
2542
2543 self._gate = gtk.ComboBox(model = self._gatesModel)
2544 renderer = gtk.CellRendererText()
2545 self._gate.pack_start(renderer, True)
2546 self._gate.add_attribute(renderer, "text", 0)
2547 self._gate.set_tooltip_text(xstr("finish_gate_tooltip"))
2548 self._gate.connect("changed", self._gateChanged)
2549 gateAlignment = gtk.Alignment(xalign=0.0, xscale=1.0)
2550 gateAlignment.add(self._gate)
2551 table.attach(gateAlignment, 1, 2, 7, 8)
2552 self._gateLabel.set_mnemonic_widget(self._gate)
2553
2554 self.addButton(xstr("finish_newFlight"),
2555 sensitive = True,
2556 clicked = self._newFlightClicked,
2557 tooltip = xstr("finish_newFlight_tooltip"),
2558 padding = 16)
2559
2560 self.addPreviousButton(clicked = self._backClicked)
2561
2562 self._saveButton = self.addButton(xstr("finish_save"),
2563 sensitive = False,
2564 clicked = self._saveClicked,
2565 tooltip = xstr("finish_save_tooltip"))
2566 self._savePIREPDialog = None
2567 self._lastSavePath = None
2568
2569 self._pirepSaved = False
2570 self._pirepSent = False
2571
2572 self._sendButton = self.addButton(xstr("sendPIREP"), default = True,
2573 sensitive = False,
2574 clicked = self._sendClicked,
2575 tooltip = xstr("sendPIREP_tooltip"))
2576
2577 @property
2578 def flightType(self):
2579 """Get the flight type."""
2580 index = self._flightType.get_active()
2581 return None if index<0 else self._flightType.get_model()[index][1]
2582
2583 @property
2584 def online(self):
2585 """Get whether the flight was an online flight or not."""
2586 return self._onlineFlight.get_active()
2587
2588 def activate(self):
2589 """Activate the page."""
2590 self._pirepSaved = False
2591 self._pirepSent = False
2592
2593 flight = self._wizard.gui._flight
2594 rating = flight.logger.getRating()
2595 if rating<0:
2596 self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
2597 else:
2598 self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
2599
2600 flightLength = flight.flightTimeEnd - flight.flightTimeStart
2601 self._flightTime.set_markup("<b>%s</b>" % \
2602 (util.getTimeIntervalString(flightLength),))
2603
2604 blockLength = flight.blockTimeEnd - flight.blockTimeStart
2605 self._blockTime.set_markup("<b>%s</b>" % \
2606 (util.getTimeIntervalString(blockLength),))
2607
2608 self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
2609 (flight.flownDistance,))
2610
2611 self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
2612 (flight.startFuel - flight.endFuel,))
2613
2614 self._flightType.set_active(-1)
2615 self._onlineFlight.set_active(self._wizard.loggedIn)
2616
2617 self._gatesModel.clear()
2618 if self._wizard.gui.config.onlineGateSystem and \
2619 self._wizard.loggedIn and \
2620 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
2621 not self._wizard.entranceExam:
2622 occupiedGates = self._wizard._fleet.getOccupiedGateNumbers()
2623 for gateNumber in const.lhbpGateNumbers:
2624 if gateNumber not in occupiedGates:
2625 self._gatesModel.append([gateNumber])
2626 self._gateLabel.set_sensitive(True)
2627 self._gate.set_sensitive(True)
2628 self._gate.set_active(-1)
2629 else:
2630 self._gateLabel.set_sensitive(False)
2631 self._gate.set_sensitive(False)
2632
2633 def _backClicked(self, button):
2634 """Called when the Back button is pressed."""
2635 self.goBack()
2636
2637 def _updateButtons(self):
2638 """Update the sensitivity state of the buttons."""
2639 sensitive = self._flightType.get_active()>=0 and \
2640 (self._gatesModel.get_iter_first() is None or
2641 self._gate.get_active()>=0)
2642
2643 self._saveButton.set_sensitive(sensitive)
2644 self._sendButton.set_sensitive(sensitive and
2645 self._wizard.bookedFlight.id is not None)
2646
2647 def _flightTypeChanged(self, comboBox):
2648 """Called when the flight type has changed."""
2649 self._updateButtons()
2650
2651 def _gateChanged(self, comboBox):
2652 """Called when the arrival gate has changed."""
2653 self._updateButtons()
2654
2655 def _newFlightClicked(self, button):
2656 """Called when the new flight button is clicked."""
2657 gui = self._wizard.gui
2658 if not self._pirepSent and not self._pirepSaved:
2659 dialog = gtk.MessageDialog(parent = gui.mainWindow,
2660 type = MESSAGETYPE_QUESTION,
2661 message_format = xstr("finish_newFlight_question"))
2662
2663 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
2664 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
2665
2666 dialog.set_title(WINDOW_TITLE_BASE)
2667 result = dialog.run()
2668 dialog.hide()
2669 if result!=RESPONSETYPE_YES:
2670 return
2671
2672 gui.reset()
2673
2674 def _saveClicked(self, button):
2675 """Called when the Save PIREP button is clicked."""
2676 gui = self._wizard.gui
2677
2678 bookedFlight = gui.bookedFlight
2679 tm = time.gmtime()
2680
2681 pilotID = self._wizard.pilotID
2682 if pilotID: pilotID += " "
2683 fileName = "%s%s %02d%02d %s-%s.pirep" % \
2684 (pilotID, str(bookedFlight.departureTime.date()),
2685 tm.tm_hour, tm.tm_min,
2686 bookedFlight.departureICAO,
2687 bookedFlight.arrivalICAO)
2688
2689 dialog = self._getSaveDialog()
2690
2691 if self._lastSavePath is None:
2692 pirepDirectory = gui.config.pirepDirectory
2693 if pirepDirectory is not None:
2694 dialog.set_current_folder(pirepDirectory)
2695 else:
2696 dialog.set_current_folder(os.path.dirname(self._lastSavePath))
2697
2698 dialog.set_current_name(fileName)
2699 result = dialog.run()
2700 dialog.hide()
2701
2702 if result==RESPONSETYPE_OK:
2703 pirep = PIREP(gui.flight)
2704
2705 self._lastSavePath = text2unicode(dialog.get_filename())
2706
2707 if pirep.save(self._lastSavePath):
2708 type = MESSAGETYPE_INFO
2709 message = xstr("finish_save_done")
2710 secondary = None
2711 self._pirepSaved = True
2712 else:
2713 type = MESSAGETYPE_ERROR
2714 message = xstr("finish_save_failed")
2715 secondary = xstr("finish_save_failed_sec")
2716
2717 dialog = gtk.MessageDialog(parent = gui.mainWindow,
2718 type = type, message_format = message)
2719 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
2720 dialog.set_title(WINDOW_TITLE_BASE)
2721 if secondary is not None:
2722 dialog.format_secondary_markup(secondary)
2723
2724 dialog.run()
2725 dialog.hide()
2726
2727 def _getSaveDialog(self):
2728 """Get the PIREP saving dialog.
2729
2730 If it does not exist yet, create it."""
2731 if self._savePIREPDialog is None:
2732 gui = self._wizard.gui
2733 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
2734 xstr("finish_save_title"),
2735 action = FILE_CHOOSER_ACTION_SAVE,
2736 buttons = (gtk.STOCK_CANCEL,
2737 RESPONSETYPE_CANCEL,
2738 gtk.STOCK_OK, RESPONSETYPE_OK),
2739 parent = gui.mainWindow)
2740 dialog.set_modal(True)
2741 dialog.set_do_overwrite_confirmation(True)
2742
2743 filter = gtk.FileFilter()
2744 filter.set_name(xstr("file_filter_pireps"))
2745 filter.add_pattern("*.pirep")
2746 dialog.add_filter(filter)
2747
2748 filter = gtk.FileFilter()
2749 filter.set_name(xstr("file_filter_all"))
2750 filter.add_pattern("*.*")
2751 dialog.add_filter(filter)
2752
2753 self._savePIREPDialog = dialog
2754
2755 return self._savePIREPDialog
2756
2757
2758 def _sendClicked(self, button):
2759 """Called when the Send button is clicked."""
2760 pirep = PIREP(self._wizard.gui.flight)
2761 self._wizard.gui.sendPIREP(pirep,
2762 callback = self._handlePIREPSent)
2763
2764 def _handlePIREPSent(self, returned, result):
2765 """Callback for the PIREP sending result."""
2766 self._pirepSent = returned and result.success
2767 if self._wizard.gui.config.onlineGateSystem and \
2768 self._wizard.loggedIn and not self._wizard.entranceExam and \
2769 returned and result.success:
2770 bookedFlight = self._wizard.bookedFlight
2771 if bookedFlight.arrivalICAO=="LHBP":
2772 iter = self._gate.get_active_iter()
2773 gateNumber = None if iter is None \
2774 else self._gatesModel.get_value(iter, 0)
2775
2776 status = const.PLANE_PARKING if gateNumber is None \
2777 else const.PLANE_HOME
2778 else:
2779 gateNumber = None
2780 status = const.PLANE_AWAY
2781
2782 self._wizard.updatePlane(self._planeUpdated,
2783 bookedFlight.tailNumber,
2784 status, gateNumber = gateNumber)
2785
2786 def _planeUpdated(self, success):
2787 """Callback for the plane updating."""
2788 pass
2789
2790#-----------------------------------------------------------------------------
2791
2792class Wizard(gtk.VBox):
2793 """The flight wizard."""
2794 def __init__(self, gui):
2795 """Construct the wizard."""
2796 super(Wizard, self).__init__()
2797
2798 self.gui = gui
2799
2800 self._pages = []
2801 self._currentPage = None
2802
2803 self._loginPage = LoginPage(self)
2804 self._pages.append(self._loginPage)
2805 self._pages.append(FlightSelectionPage(self))
2806 self._pages.append(GateSelectionPage(self))
2807 self._pages.append(ConnectPage(self))
2808 self._payloadPage = PayloadPage(self)
2809 self._pages.append(self._payloadPage)
2810 self._payloadIndex = len(self._pages)
2811 self._pages.append(TimePage(self))
2812 self._pages.append(FuelPage(self))
2813 self._routePage = RoutePage(self)
2814 self._pages.append(self._routePage)
2815 self._departureBriefingPage = BriefingPage(self, True)
2816 self._pages.append(self._departureBriefingPage)
2817 self._arrivalBriefingPage = BriefingPage(self, False)
2818 self._pages.append(self._arrivalBriefingPage)
2819 self._arrivalBriefingIndex = len(self._pages)
2820 self._takeoffPage = TakeoffPage(self)
2821 self._pages.append(self._takeoffPage)
2822 self._landingPage = LandingPage(self)
2823 self._pages.append(self._landingPage)
2824 self._finishPage = FinishPage(self)
2825 self._pages.append(self._finishPage)
2826
2827 maxWidth = 0
2828 maxHeight = 0
2829 for page in self._pages:
2830 page.show_all()
2831 pageSizeRequest = page.size_request()
2832 width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
2833 height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
2834 maxWidth = max(maxWidth, width)
2835 maxHeight = max(maxHeight, height)
2836 page.setStyle()
2837 maxWidth += 16
2838 maxHeight += 32
2839 self.set_size_request(maxWidth, maxHeight)
2840
2841 self._initialize()
2842
2843 @property
2844 def pilotID(self):
2845 """Get the pilot ID, if given."""
2846 return self._loginPage.pilotID
2847
2848 @property
2849 def entranceExam(self):
2850 """Get whether an entrance exam is about to be taken."""
2851 return self._loginPage.entranceExam
2852
2853 @property
2854 def loggedIn(self):
2855 """Indicate if there was a successful login."""
2856 return self._loginResult is not None
2857
2858 @property
2859 def loginResult(self):
2860 """Get the login result."""
2861 return self._loginResult
2862
2863 def setCurrentPage(self, index, finalize = False):
2864 """Set the current page to the one with the given index."""
2865 assert index < len(self._pages)
2866
2867 fromPage = self._currentPage
2868 if fromPage is not None:
2869 page = self._pages[fromPage]
2870 if finalize and not page._completed:
2871 page.complete()
2872 self.remove(page)
2873
2874 self._currentPage = index
2875 page = self._pages[index]
2876 self.add(page)
2877 if page._fromPage is None:
2878 page._fromPage = fromPage
2879 page.initialize()
2880 self.show_all()
2881 if fromPage is not None:
2882 self.grabDefault()
2883
2884 @property
2885 def bookedFlight(self):
2886 """Get the booked flight selected."""
2887 return self._bookedFlight
2888
2889 @property
2890 def numCrew(self):
2891 """Get the number of crew members."""
2892 return self._payloadPage.numCrew
2893
2894 @property
2895 def numPassengers(self):
2896 """Get the number of passengers."""
2897 return self._payloadPage.numPassengers
2898
2899 @property
2900 def bagWeight(self):
2901 """Get the baggage weight."""
2902 return self._payloadPage.bagWeight
2903
2904 @property
2905 def cargoWeight(self):
2906 """Get the cargo weight."""
2907 return self._payloadPage.cargoWeight
2908
2909 @property
2910 def mailWeight(self):
2911 """Get the mail weight."""
2912 return self._payloadPage.mailWeight
2913
2914 @property
2915 def zfw(self):
2916 """Get the calculated ZFW value."""
2917 return 0 if self._bookedFlight is None \
2918 else self._payloadPage.calculateZFW()
2919
2920 @property
2921 def filedCruiseAltitude(self):
2922 """Get the filed cruise altitude."""
2923 return self._routePage.filedCruiseLevel * 100
2924
2925 @property
2926 def cruiseAltitude(self):
2927 """Get the cruise altitude."""
2928 return self._routePage.cruiseLevel * 100
2929
2930 @property
2931 def route(self):
2932 """Get the route."""
2933 return self._routePage.route
2934
2935 @property
2936 def departureMETAR(self):
2937 """Get the METAR of the departure airport."""
2938 return self._departureBriefingPage.metar
2939
2940 @property
2941 def arrivalMETAR(self):
2942 """Get the METAR of the arrival airport."""
2943 return self._arrivalBriefingPage.metar
2944
2945 @property
2946 def departureRunway(self):
2947 """Get the departure runway."""
2948 return self._takeoffPage.runway
2949
2950 @property
2951 def sid(self):
2952 """Get the SID."""
2953 return self._takeoffPage.sid
2954
2955 @property
2956 def v1(self):
2957 """Get the V1 speed."""
2958 return self._takeoffPage.v1
2959
2960 @property
2961 def vr(self):
2962 """Get the Vr speed."""
2963 return self._takeoffPage.vr
2964
2965 @property
2966 def v2(self):
2967 """Get the V2 speed."""
2968 return self._takeoffPage.v2
2969
2970 @property
2971 def arrivalRunway(self):
2972 """Get the arrival runway."""
2973 return self._landingPage.runway
2974
2975 @property
2976 def star(self):
2977 """Get the STAR."""
2978 return self._landingPage.star
2979
2980 @property
2981 def transition(self):
2982 """Get the transition."""
2983 return self._landingPage.transition
2984
2985 @property
2986 def approachType(self):
2987 """Get the approach type."""
2988 return self._landingPage.approachType
2989
2990 @property
2991 def vref(self):
2992 """Get the Vref speed."""
2993 return self._landingPage.vref
2994
2995 @property
2996 def flightType(self):
2997 """Get the flight type."""
2998 return self._finishPage.flightType
2999
3000 @property
3001 def online(self):
3002 """Get whether the flight was online or not."""
3003 return self._finishPage.online
3004
3005 def nextPage(self, finalize = True):
3006 """Go to the next page."""
3007 self.jumpPage(1, finalize)
3008
3009 def jumpPage(self, count, finalize = True):
3010 """Go to the page which is 'count' pages after the current one."""
3011 self.setCurrentPage(self._currentPage + count, finalize = finalize)
3012
3013 def grabDefault(self):
3014 """Make the default button of the current page the default."""
3015 self._pages[self._currentPage].grabDefault()
3016
3017 def connected(self, fsType, descriptor):
3018 """Called when the connection could be made to the simulator."""
3019 self.nextPage()
3020
3021 def reset(self, loginResult):
3022 """Resets the wizard to go back to the login page."""
3023 self._initialize(keepLoginResult = loginResult is None,
3024 loginResult = loginResult)
3025
3026 def setStage(self, stage):
3027 """Set the flight stage to the given one."""
3028 if stage==const.STAGE_TAKEOFF:
3029 self._takeoffPage.allowForward()
3030 elif stage==const.STAGE_LANDING:
3031 if not self._arrivalBriefingPage.metarEdited:
3032 print "Downloading arrival METAR again"
3033 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
3034 [self._bookedFlight.arrivalICAO])
3035
3036 elif stage==const.STAGE_END:
3037 for page in self._pages:
3038 page.flightEnded()
3039
3040 def _initialize(self, keepLoginResult = False, loginResult = None):
3041 """Initialize the wizard."""
3042 if not keepLoginResult:
3043 self._loginResult = loginResult
3044
3045 self._loginCallback = None
3046
3047 self._fleet = None
3048 self._fleetCallback = None
3049
3050 self._bookedFlight = None
3051 self._departureGate = "-"
3052 self._fuelData = None
3053 self._departureNOTAMs = None
3054 self._departureMETAR = None
3055 self._arrivalNOTAMs = None
3056 self._arrivalMETAR = None
3057
3058 firstPage = 0 if self._loginResult is None else 1
3059 for page in self._pages[firstPage:]:
3060 page.reset()
3061
3062 self.setCurrentPage(firstPage)
3063
3064 def login(self, callback, pilotID, password, entranceExam):
3065 """Called when the login button was clicked."""
3066 self._loginCallback = callback
3067 if pilotID is None:
3068 loginResult = self._loginResult
3069 assert loginResult is not None and loginResult.loggedIn
3070 pilotID = loginResult.pilotID
3071 password = loginResult.password
3072 entranceExam = loginResult.entranceExam
3073 busyMessage = xstr("reload_busy")
3074 else:
3075 self._loginResult = None
3076 busyMessage = xstr("login_busy")
3077
3078 self.gui.beginBusy(busyMessage)
3079
3080 self.gui.webHandler.login(self._loginResultCallback,
3081 pilotID, password,
3082 entranceExam = entranceExam)
3083
3084 def reloadFlights(self, callback):
3085 """Reload the flights from the MAVA server."""
3086 self.login(callback, None, None, None)
3087
3088 def cruiseLevelChanged(self):
3089 """Called when the cruise level is changed."""
3090 self.gui.cruiseLevelChanged()
3091
3092 def _loginResultCallback(self, returned, result):
3093 """The login result callback, called in the web handler's thread."""
3094 gobject.idle_add(self._handleLoginResult, returned, result)
3095
3096 def _handleLoginResult(self, returned, result):
3097 """Handle the login result."""
3098 self.gui.endBusy()
3099 isReload = self._loginResult is not None
3100 if returned:
3101 if result.loggedIn:
3102 self._loginResult = result
3103 else:
3104 if isReload:
3105 message = xstr("reload_failed")
3106 else:
3107 message = xstr("login_entranceExam_invalid"
3108 if self.entranceExam else
3109 xstr("login_invalid"))
3110 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
3111 type = MESSAGETYPE_ERROR,
3112 message_format = message)
3113 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3114 dialog.set_title(WINDOW_TITLE_BASE)
3115 if isReload:
3116 secondary = xstr("reload_failed_sec")
3117 else:
3118 secondary = xstr("login_entranceExam_invalid_sec"
3119 if self.entranceExam else
3120 xstr("login_invalid_sec"))
3121 dialog.format_secondary_markup(secondary)
3122 dialog.run()
3123 dialog.hide()
3124 else:
3125 message = xstr("reload_failconn") if isReload \
3126 else xstr("login_failconn")
3127 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
3128 type = MESSAGETYPE_ERROR,
3129 message_format = message)
3130 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3131 dialog.set_title(WINDOW_TITLE_BASE)
3132 secondary = xstr("reload_failconn_sec") if isReload \
3133 else xstr("login_failconn_sec")
3134 dialog.format_secondary_markup(secondary)
3135
3136 dialog.run()
3137 dialog.hide()
3138
3139 callback = self._loginCallback
3140 self._loginCallback = None
3141 callback(returned, result)
3142
3143 def getFleet(self, callback, force = False):
3144 """Get the fleet via the GUI and call the given callback."""
3145 self._fleetCallback = callback
3146 self.gui.getFleet(callback = self._fleetRetrieved, force = force)
3147
3148 def _fleetRetrieved(self, fleet):
3149 """Callback for the fleet retrieval."""
3150 self._fleet = fleet
3151 if self._fleetCallback is not None:
3152 self._fleetCallback(fleet)
3153 self._fleetCallback = None
3154
3155 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
3156 """Update the given plane's gate information."""
3157 self.gui.updatePlane(tailNumber, status, gateNumber = gateNumber,
3158 callback = callback)
3159
3160 def _connectSimulator(self):
3161 """Connect to the simulator."""
3162 self.gui.connectSimulator(self._bookedFlight.aircraftType)
3163
3164 def _arrivalMETARCallback(self, returned, result):
3165 """Called when the METAR of the arrival airport is retrieved."""
3166 gobject.idle_add(self._handleArrivalMETAR, returned, result)
3167
3168 def _handleArrivalMETAR(self, returned, result):
3169 """Called when the METAR of the arrival airport is retrieved."""
3170 icao = self._bookedFlight.arrivalICAO
3171 if returned and icao in result.metars:
3172 metar = result.metars[icao]
3173 if metar!="":
3174 self._arrivalBriefingPage.setMETAR(metar)
3175
3176#-----------------------------------------------------------------------------
3177
Note: See TracBrowser for help on using the repository browser.