source: src/mlx/gui/flight.py@ 347:175e29566656

Last change on this file since 347:175e29566656 was 347:175e29566656, checked in by István Váradi <ivaradi@…>, 11 years ago

Removed trailing whitespace

File size: 119.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_use_underline(True)
1016 label.set_alignment(0.0, 0.5)
1017 table.attach(label, 0, 1, 0, 1)
1018
1019 self._numCrew = IntegerEntry(defaultValue = 0)
1020 self._numCrew.set_width_chars(6)
1021 self._numCrew.connect("integer-changed", self._weightChanged)
1022 self._numCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
1023 table.attach(self._numCrew, 1, 2, 0, 1)
1024 label.set_mnemonic_widget(self._numCrew)
1025
1026 label = gtk.Label(xstr("payload_pax"))
1027 label.set_use_underline(True)
1028 label.set_alignment(0.0, 0.5)
1029 table.attach(label, 0, 1, 1, 2)
1030
1031 self._numPassengers = IntegerEntry(defaultValue = 0)
1032 self._numPassengers.set_width_chars(6)
1033 self._numPassengers.connect("integer-changed", self._weightChanged)
1034 self._numPassengers.set_tooltip_text(xstr("payload_pax_tooltip"))
1035 table.attach(self._numPassengers, 1, 2, 1, 2)
1036 label.set_mnemonic_widget(self._numPassengers)
1037
1038 label = gtk.Label(xstr("payload_bag"))
1039 label.set_use_underline(True)
1040 label.set_alignment(0.0, 0.5)
1041 table.attach(label, 0, 1, 2, 3)
1042
1043 self._bagWeight = IntegerEntry(defaultValue = 0)
1044 self._bagWeight.set_width_chars(6)
1045 self._bagWeight.connect("integer-changed", self._weightChanged)
1046 self._bagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
1047 table.attach(self._bagWeight, 1, 2, 2, 3)
1048 label.set_mnemonic_widget(self._bagWeight)
1049
1050 table.attach(gtk.Label("kg"), 2, 3, 2, 3)
1051
1052 label = gtk.Label(xstr("payload_cargo"))
1053 label.set_use_underline(True)
1054 label.set_alignment(0.0, 0.5)
1055 table.attach(label, 0, 1, 3, 4)
1056
1057 self._cargoWeight = IntegerEntry(defaultValue = 0)
1058 self._cargoWeight.set_width_chars(6)
1059 self._cargoWeight.connect("integer-changed", self._weightChanged)
1060 self._cargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
1061 table.attach(self._cargoWeight, 1, 2, 3, 4)
1062 label.set_mnemonic_widget(self._cargoWeight)
1063
1064 table.attach(gtk.Label("kg"), 2, 3, 3, 4)
1065
1066 label = gtk.Label(xstr("payload_mail"))
1067 label.set_use_underline(True)
1068 label.set_alignment(0.0, 0.5)
1069 table.attach(label, 0, 1, 4, 5)
1070
1071 self._mailWeight = IntegerEntry(defaultValue = 0)
1072 self._mailWeight.set_width_chars(6)
1073 self._mailWeight.connect("integer-changed", self._weightChanged)
1074 self._mailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
1075 table.attach(self._mailWeight, 1, 2, 4, 5)
1076 label.set_mnemonic_widget(self._mailWeight)
1077
1078 table.attach(gtk.Label("kg"), 2, 3, 4, 5)
1079
1080 label = gtk.Label("<b>" + xstr("payload_zfw") + "</b>")
1081 label.set_alignment(0.0, 0.5)
1082 label.set_use_markup(True)
1083 table.attach(label, 0, 1, 5, 6)
1084
1085 self._calculatedZFW = gtk.Label()
1086 self._calculatedZFW.set_width_chars(6)
1087 self._calculatedZFW.set_alignment(1.0, 0.5)
1088 table.attach(self._calculatedZFW, 1, 2, 5, 6)
1089
1090 table.attach(gtk.Label("kg"), 2, 3, 5, 6)
1091
1092 self._zfwButton = gtk.Button(xstr("payload_fszfw"))
1093 self._zfwButton.set_use_underline(True)
1094 self._zfwButton.connect("clicked", self._zfwRequested)
1095 self._zfwButton.set_tooltip_text(xstr("payload_fszfw_tooltip"))
1096 table.attach(self._zfwButton, 0, 1, 6, 7)
1097
1098 self._simulatorZFW = gtk.Label("-")
1099 self._simulatorZFW.set_width_chars(6)
1100 self._simulatorZFW.set_alignment(1.0, 0.5)
1101 table.attach(self._simulatorZFW, 1, 2, 6, 7)
1102 self._simulatorZFWValue = None
1103
1104 table.attach(gtk.Label("kg"), 2, 3, 6, 7)
1105
1106 self.addCancelFlightButton()
1107 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1108 self._button = self.addNextButton(clicked = self._forwardClicked)
1109
1110 @property
1111 def numCrew(self):
1112 """The number of the crew members on the flight."""
1113 return self._numCrew.get_int()
1114
1115 @property
1116 def numPassengers(self):
1117 """The number of the passengers on the flight."""
1118 return self._numPassengers.get_int()
1119
1120 @property
1121 def bagWeight(self):
1122 """Get the bag weight entered."""
1123 return self._bagWeight.get_int()
1124
1125 @property
1126 def cargoWeight(self):
1127 """Get the cargo weight entered."""
1128 return self._cargoWeight.get_int()
1129
1130 @property
1131 def mailWeight(self):
1132 """Get the bag weight entered."""
1133 return self._mailWeight.get_int()
1134
1135 def activate(self):
1136 """Setup the information."""
1137 bookedFlight = self._wizard._bookedFlight
1138
1139 self._numCrew.set_int(bookedFlight.numCrew)
1140 self._numCrew.set_sensitive(True)
1141 self._numPassengers.set_int(bookedFlight.numPassengers)
1142 self._numPassengers.set_sensitive(True)
1143
1144 self._bagWeight.set_int(bookedFlight.bagWeight)
1145 self._bagWeight.set_sensitive(True)
1146 self._cargoWeight.set_int(bookedFlight.cargoWeight)
1147 self._cargoWeight.set_sensitive(True)
1148 self._mailWeight.set_int(bookedFlight.mailWeight)
1149 self._mailWeight.set_sensitive(True)
1150
1151 self._simulatorZFW.set_text("-")
1152 self._simulatorZFWValue = None
1153 self._zfwButton.set_sensitive(True)
1154 self._updateCalculatedZFW()
1155
1156 def finalize(self):
1157 """Finalize the payload page."""
1158 self._numCrew.set_sensitive(False)
1159 self._numPassengers.set_sensitive(False)
1160 self._bagWeight.set_sensitive(False)
1161 self._cargoWeight.set_sensitive(False)
1162 self._mailWeight.set_sensitive(False)
1163 self._wizard.gui.initializeWeightHelp()
1164
1165 def calculateZFW(self):
1166 """Calculate the ZFW value."""
1167 zfw = self._wizard.gui._flight.aircraft.dow
1168 zfw += (self._numCrew.get_int() + self._numPassengers.get_int()) * 82
1169 zfw += self._bagWeight.get_int()
1170 zfw += self._cargoWeight.get_int()
1171 zfw += self._mailWeight.get_int()
1172 return zfw
1173
1174 def _updateCalculatedZFW(self):
1175 """Update the calculated ZFW"""
1176 zfw = self.calculateZFW()
1177
1178 markupBegin = "<b>"
1179 markupEnd = "</b>"
1180 if self._simulatorZFWValue is not None and \
1181 PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
1182 markupBegin += '<span foreground="red">'
1183 markupEnd = "</span>" + markupEnd
1184 self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
1185
1186 def _weightChanged(self, entry, weight):
1187 """Called when one of the weight values or humanm counts has changed."""
1188 self._updateCalculatedZFW()
1189
1190 def _zfwRequested(self, button):
1191 """Called when the ZFW is requested from the simulator."""
1192 self._zfwButton.set_sensitive(False)
1193 self._backButton.set_sensitive(False)
1194 self._button.set_sensitive(False)
1195 gui = self._wizard.gui
1196 gui.beginBusy(xstr("payload_zfw_busy"))
1197 gui.simulator.requestZFW(self._handleZFW)
1198
1199 def _handleZFW(self, zfw):
1200 """Called when the ZFW value is retrieved."""
1201 gobject.idle_add(self._processZFW, zfw)
1202
1203 def _processZFW(self, zfw):
1204 """Process the given ZFW value received from the simulator."""
1205 self._wizard.gui.endBusy()
1206 self._zfwButton.set_sensitive(True)
1207 self._backButton.set_sensitive(True)
1208 self._button.set_sensitive(True)
1209 self._simulatorZFWValue = zfw
1210 self._simulatorZFW.set_text("%.0f" % (zfw,))
1211 self._updateCalculatedZFW()
1212
1213 def _forwardClicked(self, button):
1214 """Called when the forward button is clicked."""
1215 self._wizard.nextPage()
1216
1217 def _backClicked(self, button):
1218 """Called when the Back button is pressed."""
1219 self.goBack()
1220
1221#-----------------------------------------------------------------------------
1222
1223class TimePage(Page):
1224 """Page displaying the departure and arrival times and allows querying the
1225 current time from the flight simulator."""
1226 def __init__(self, wizard):
1227 super(TimePage, self).__init__(wizard, xstr("time_title"),
1228 xstr("time_help"),
1229 completedHelp = xstr("time_chelp"))
1230
1231 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1232 xscale = 0.0, yscale = 0.0)
1233
1234 table = gtk.Table(3, 2)
1235 table.set_row_spacings(4)
1236 table.set_col_spacings(16)
1237 table.set_homogeneous(False)
1238 alignment.add(table)
1239 self.setMainWidget(alignment)
1240
1241 label = gtk.Label(xstr("time_departure"))
1242 label.set_alignment(0.0, 0.5)
1243 table.attach(label, 0, 1, 0, 1)
1244
1245 self._departure = gtk.Label()
1246 self._departure.set_alignment(0.0, 0.5)
1247 table.attach(self._departure, 1, 2, 0, 1)
1248
1249 label = gtk.Label(xstr("time_arrival"))
1250 label.set_alignment(0.0, 0.5)
1251 table.attach(label, 0, 1, 1, 2)
1252
1253 self._arrival = gtk.Label()
1254 self._arrival.set_alignment(0.0, 0.5)
1255 table.attach(self._arrival, 1, 2, 1, 2)
1256
1257 self._timeButton = gtk.Button(xstr("time_fs"))
1258 self._timeButton.set_use_underline(True)
1259 self._timeButton.set_tooltip_text(xstr("time_fs_tooltip"))
1260 self._timeButton.connect("clicked", self._timeRequested)
1261 table.attach(self._timeButton, 0, 1, 2, 3)
1262
1263 self._simulatorTime = gtk.Label("-")
1264 self._simulatorTime.set_alignment(0.0, 0.5)
1265 table.attach(self._simulatorTime, 1, 2, 2, 3)
1266
1267 self.addCancelFlightButton()
1268
1269 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1270 self._button = self.addNextButton(clicked = self._forwardClicked)
1271
1272 def activate(self):
1273 """Activate the page."""
1274 self._timeButton.set_sensitive(True)
1275 bookedFlight = self._wizard._bookedFlight
1276 self._departure.set_text(str(bookedFlight.departureTime.time()))
1277 self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
1278 self._simulatorTime.set_text("-")
1279
1280 def _timeRequested(self, button):
1281 """Request the time from the simulator."""
1282 self._timeButton.set_sensitive(False)
1283 self._backButton.set_sensitive(False)
1284 self._button.set_sensitive(False)
1285 self._wizard.gui.beginBusy(xstr("time_busy"))
1286 self._wizard.gui.simulator.requestTime(self._handleTime)
1287
1288 def _handleTime(self, timestamp):
1289 """Handle the result of a time retrieval."""
1290 gobject.idle_add(self._processTime, timestamp)
1291
1292 def _processTime(self, timestamp):
1293 """Process the given time."""
1294 self._wizard.gui.endBusy()
1295 self._timeButton.set_sensitive(True)
1296 self._backButton.set_sensitive(True)
1297 self._button.set_sensitive(True)
1298 tm = time.gmtime(timestamp)
1299 t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
1300 self._simulatorTime.set_text(str(t))
1301
1302 ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
1303 dt = self._wizard._bookedFlight.departureTime.time()
1304 dts = dt.hour * 3600 + dt.minute * 60 + dt.second
1305 diff = dts-ts
1306
1307 markupBegin = ""
1308 markupEnd = ""
1309 if diff < 0:
1310 markupBegin = '<b><span foreground="red">'
1311 markupEnd = '</span></b>'
1312 elif diff < 3*60 or diff > 30*60:
1313 markupBegin = '<b><span foreground="orange">'
1314 markupEnd = '</span></b>'
1315
1316 self._departure.set_markup(markupBegin + str(dt) + markupEnd)
1317
1318 def _backClicked(self, button):
1319 """Called when the Back button is pressed."""
1320 self.goBack()
1321
1322 def _forwardClicked(self, button):
1323 """Called when the forward button is clicked."""
1324 if not self._completed:
1325 gui = self._wizard.gui
1326 gui.beginBusy(xstr("fuel_get_busy"))
1327
1328 gui.simulator.getFuel(self._handleFuel)
1329 else:
1330 self._wizard.nextPage()
1331
1332 def _handleFuel(self, fuelData):
1333 """Callback for the fuel query operation."""
1334 gobject.idle_add(self._processFuel, fuelData)
1335
1336 def _processFuel(self, fuelData):
1337 """Process the given fuel data."""
1338 self._wizard.gui.endBusy()
1339 self._wizard._fuelData = fuelData
1340 self._wizard.nextPage()
1341
1342#-----------------------------------------------------------------------------
1343
1344class FuelTank(gtk.VBox):
1345 """Widget for the fuel tank."""
1346 def __init__(self, fuelTank, name, capacity, currentWeight):
1347 """Construct the widget for the tank with the given name."""
1348 super(FuelTank, self).__init__()
1349
1350 self._enabled = True
1351 self.fuelTank = fuelTank
1352 self.capacity = capacity
1353 self.currentWeight = currentWeight
1354 self.expectedWeight = currentWeight
1355
1356 label = gtk.Label("<b>" + name + "</b>")
1357 label.set_use_markup(True)
1358 label.set_use_underline(True)
1359 label.set_justify(JUSTIFY_CENTER)
1360 label.set_alignment(0.5, 1.0)
1361 self.pack_start(label, False, False, 4)
1362
1363 self._tankFigure = gtk.EventBox()
1364 self._tankFigure.set_size_request(38, -1)
1365 self._tankFigure.set_visible_window(False)
1366 self._tankFigure.set_tooltip_markup(xstr("fuel_tank_tooltip"))
1367
1368 if pygobject:
1369 self._tankFigure.connect("draw", self._drawTankFigure)
1370 else:
1371 self._tankFigure.connect("expose_event", self._drawTankFigure)
1372 self._tankFigure.connect("button_press_event", self._buttonPressed)
1373 self._tankFigure.connect("motion_notify_event", self._motionNotify)
1374 self._tankFigure.connect("scroll-event", self._scrolled)
1375
1376 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1377 xscale = 0.0, yscale = 1.0)
1378 alignment.add(self._tankFigure)
1379
1380 self.pack_start(alignment, True, True, 4)
1381
1382 self._expectedButton = gtk.SpinButton()
1383 self._expectedButton.set_numeric(True)
1384 self._expectedButton.set_range(0, self.capacity)
1385 self._expectedButton.set_increments(10, 100)
1386 self._expectedButton.set_value(currentWeight)
1387 self._expectedButton.set_alignment(1.0)
1388 self._expectedButton.set_width_chars(5)
1389 self._expectedButton.connect("value-changed", self._expectedChanged)
1390
1391 label.set_mnemonic_widget(self._expectedButton)
1392
1393 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1394 xscale = 0.0, yscale = 1.0)
1395 alignment.add(self._expectedButton)
1396 self.pack_start(alignment, False, False, 4)
1397
1398 def setCurrent(self, currentWeight):
1399 """Set the current weight."""
1400 self.currentWeight = currentWeight
1401 self._redraw()
1402
1403 def isCorrect(self):
1404 """Determine if the contents of the fuel tank are as expected"""
1405 return abs(self.expectedWeight - self.currentWeight)<=1
1406
1407 def disable(self):
1408 """Disable the fuel tank."""
1409 self._expectedButton.set_sensitive(False)
1410 self._enabled = False
1411
1412 def _redraw(self):
1413 """Redraw the tank figure."""
1414 self._tankFigure.queue_draw()
1415
1416 def _drawTankFigure(self, tankFigure, eventOrContext):
1417 """Draw the tank figure."""
1418 triangleSize = 5
1419
1420 context = eventOrContext if pygobject else tankFigure.window.cairo_create()
1421 (xOffset, yOffset) = (0, 0) if pygobject \
1422 else (tankFigure.allocation.x, tankFigure.allocation.y)
1423
1424 width = tankFigure.get_allocated_width() if pygobject \
1425 else tankFigure.allocation.width
1426 height = tankFigure.get_allocated_height() if pygobject \
1427 else tankFigure.allocation.height
1428
1429 rectangleX0 = triangleSize
1430 rectangleY0 = triangleSize
1431 rectangleX1 = width - 1 - triangleSize
1432 rectangleY1 = height - 1 - triangleSize
1433 rectangleLineWidth = 2.0
1434
1435 context.set_source_rgb(0.0, 0.0, 0.0)
1436 context.set_line_width(rectangleLineWidth)
1437 context.rectangle(xOffset + rectangleX0 + rectangleLineWidth/2,
1438 yOffset + rectangleY0 + rectangleLineWidth/2,
1439 rectangleX1 - rectangleX0 - rectangleLineWidth,
1440 rectangleY1 - rectangleY0 - rectangleLineWidth)
1441 context.stroke()
1442
1443 rectangleInnerLeft = rectangleX0 + rectangleLineWidth
1444 rectangleInnerRight = rectangleX1 - rectangleLineWidth
1445 self._rectangleInnerTop = rectangleInnerTop = rectangleY0 + rectangleLineWidth
1446 self._rectangleInnerBottom = rectangleInnerBottom = rectangleY1 - rectangleLineWidth
1447
1448 rectangleInnerWidth = rectangleInnerRight - rectangleInnerLeft
1449 rectangleInnerHeight = rectangleInnerBottom - rectangleInnerTop
1450
1451 context.set_source_rgb(1.0, 0.9, 0.6)
1452 currentHeight = self.currentWeight * rectangleInnerHeight / self.capacity
1453 currentX = rectangleInnerTop + rectangleInnerHeight - currentHeight
1454 context.rectangle(xOffset + rectangleInnerLeft,
1455 yOffset + rectangleInnerTop +
1456 rectangleInnerHeight - currentHeight,
1457 rectangleInnerWidth, currentHeight)
1458 context.fill()
1459
1460 expectedHeight = self.expectedWeight * rectangleInnerHeight / self.capacity
1461 expectedY = rectangleInnerTop + rectangleInnerHeight - expectedHeight
1462
1463 context.set_line_width(1.5)
1464 context.set_source_rgb(0.0, 0.85, 0.85)
1465 context.move_to(xOffset + rectangleX0, yOffset + expectedY)
1466 context.line_to(xOffset + rectangleX1, yOffset + expectedY)
1467 context.stroke()
1468
1469 context.set_line_width(0.0)
1470 context.move_to(xOffset + 0, yOffset + expectedY - triangleSize)
1471 context.line_to(xOffset + 0, yOffset + expectedY + triangleSize)
1472 context.line_to(xOffset + rectangleX0 + 1, yOffset + expectedY)
1473 context.line_to(xOffset + 0, yOffset + expectedY - triangleSize)
1474 context.fill()
1475
1476 context.set_line_width(0.0)
1477 context.move_to(xOffset + width, yOffset + expectedY - triangleSize)
1478 context.line_to(xOffset + width, yOffset + expectedY + triangleSize)
1479 context.line_to(xOffset + rectangleX1 - 1, yOffset + expectedY)
1480 context.line_to(xOffset + width, yOffset + expectedY - triangleSize)
1481 context.fill()
1482
1483 return True
1484
1485 def _setExpectedFromY(self, y):
1486 """Set the expected weight from the given Y-coordinate."""
1487 level = (self._rectangleInnerBottom - y) / \
1488 (self._rectangleInnerBottom - self._rectangleInnerTop)
1489 level = min(1.0, max(0.0, level))
1490 self._expectedButton.set_value(level * self.capacity)
1491
1492 def _buttonPressed(self, tankFigure, event):
1493 """Called when a button is pressed in the figure.
1494
1495 The expected level will be set there."""
1496 if self._enabled and event.button==1:
1497 self._setExpectedFromY(event.y)
1498
1499 def _motionNotify(self, tankFigure, event):
1500 """Called when the mouse pointer moves within the area of a tank figure."""
1501 if self._enabled and event.state==BUTTON1_MASK:
1502 self._setExpectedFromY(event.y)
1503
1504 def _scrolled(self, tankFigure, event):
1505 """Called when a scroll event is received."""
1506 if self._enabled:
1507 increment = 1 if event.state==CONTROL_MASK \
1508 else 100 if event.state==SHIFT_MASK \
1509 else 10 if event.state==0 else 0
1510 if increment!=0:
1511 if event.direction==SCROLL_DOWN:
1512 increment *= -1
1513 self._expectedButton.spin(SPIN_USER_DEFINED, increment)
1514
1515 def _expectedChanged(self, spinButton):
1516 """Called when the expected value has changed."""
1517 self.expectedWeight = spinButton.get_value_as_int()
1518 self._redraw()
1519
1520#-----------------------------------------------------------------------------
1521
1522class FuelPage(Page):
1523 """The page containing the fuel tank filling."""
1524 _pumpStep = 0.02
1525
1526 def __init__(self, wizard):
1527 """Construct the page."""
1528 super(FuelPage, self).__init__(wizard, xstr("fuel_title"),
1529 xstr("fuel_help"),
1530 completedHelp = xstr("fuel_chelp"))
1531
1532 self._fuelTanks = []
1533 self._fuelTable = None
1534 self._fuelAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1535 xscale = 0.0, yscale = 1.0)
1536 self.setMainWidget(self._fuelAlignment)
1537
1538 tankData = [(tank, 2500, 3900) for tank in acft.mostFuelTanks]
1539 self._setupTanks(tankData)
1540
1541 self.addCancelFlightButton()
1542
1543 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1544 self._button = self.addNextButton(clicked = self._forwardClicked)
1545
1546 self._pumpIndex = 0
1547
1548 def activate(self):
1549 """Activate the page."""
1550 self._setupTanks(self._wizard._fuelData)
1551
1552 def finalize(self):
1553 """Finalize the page."""
1554 for fuelTank in self._fuelTanks:
1555 fuelTank.disable()
1556
1557 def _backClicked(self, button):
1558 """Called when the Back button is pressed."""
1559 self.goBack()
1560
1561 def _forwardClicked(self, button):
1562 """Called when the forward button is clicked."""
1563 if not self._completed:
1564 self._pumpIndex = 0
1565 self._wizard.gui.beginBusy(xstr("fuel_pump_busy"))
1566 self._pump()
1567 else:
1568 self._wizard.nextPage()
1569
1570 def _setupTanks(self, tankData):
1571 """Setup the tanks for the given data."""
1572 numTanks = len(tankData)
1573 if self._fuelTable is not None:
1574 self._fuelAlignment.remove(self._fuelTable)
1575
1576 self._fuelTanks = []
1577 self._fuelTable = gtk.Table(numTanks, 1)
1578 self._fuelTable.set_col_spacings(16)
1579 index = 0
1580 for (tank, current, capacity) in tankData:
1581 fuelTank = FuelTank(tank,
1582 xstr("fuel_tank_" +
1583 const.fuelTank2string(tank)),
1584 capacity, current)
1585 self._fuelTable.attach(fuelTank, index, index+1, 0, 1)
1586 self._fuelTanks.append(fuelTank)
1587 index += 1
1588
1589 self._fuelAlignment.add(self._fuelTable)
1590 self.show_all()
1591
1592 def _pump(self):
1593 """Perform one step of pumping.
1594
1595 It is checked, if the current tank's contents are of the right
1596 quantity. If not, it is filled one step further to the desired
1597 contents. Otherwise the next tank is started. If all tanks are are
1598 filled, the next page is selected."""
1599 numTanks = len(self._fuelTanks)
1600
1601 fuelTank = None
1602 while self._pumpIndex < numTanks:
1603 fuelTank = self._fuelTanks[self._pumpIndex]
1604 if fuelTank.isCorrect():
1605 self._pumpIndex += 1
1606 fuelTank = None
1607 else:
1608 break
1609
1610 if fuelTank is None:
1611 self._wizard.gui.endBusy()
1612 self._wizard.nextPage()
1613 else:
1614 currentLevel = fuelTank.currentWeight / fuelTank.capacity
1615 expectedLevel = fuelTank.expectedWeight / fuelTank.capacity
1616 if currentLevel<expectedLevel:
1617 currentLevel += FuelPage._pumpStep
1618 if currentLevel>expectedLevel: currentLevel = expectedLevel
1619 else:
1620 currentLevel -= FuelPage._pumpStep
1621 if currentLevel<expectedLevel: currentLevel = expectedLevel
1622 fuelTank.setCurrent(currentLevel * fuelTank.capacity)
1623 self._wizard.gui.simulator.setFuelLevel([(fuelTank.fuelTank,
1624 currentLevel)])
1625 gobject.timeout_add(50, self._pump)
1626
1627#-----------------------------------------------------------------------------
1628
1629class RoutePage(Page):
1630 """The page containing the route and the flight level."""
1631 def __init__(self, wizard):
1632 """Construct the page."""
1633 super(RoutePage, self).__init__(wizard, xstr("route_title"),
1634 xstr("route_help"),
1635 completedHelp = xstr("route_chelp"))
1636
1637 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1638 xscale = 0.0, yscale = 0.0)
1639
1640 mainBox = gtk.VBox()
1641 alignment.add(mainBox)
1642 self.setMainWidget(alignment)
1643
1644 levelBox = gtk.HBox()
1645
1646 label = gtk.Label(xstr("route_level"))
1647 label.set_use_underline(True)
1648 levelBox.pack_start(label, True, True, 0)
1649
1650 self._cruiseLevel = gtk.SpinButton()
1651 self._cruiseLevel.set_increments(step = 10, page = 100)
1652 self._cruiseLevel.set_range(min = 50, max = 500)
1653 self._cruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
1654 self._cruiseLevel.set_numeric(True)
1655 self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
1656 label.set_mnemonic_widget(self._cruiseLevel)
1657 self._filedCruiseLevel = 240
1658
1659 levelBox.pack_start(self._cruiseLevel, False, False, 8)
1660
1661 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1662 xscale = 0.0, yscale = 0.0)
1663 alignment.add(levelBox)
1664
1665 mainBox.pack_start(alignment, False, False, 0)
1666
1667
1668 routeBox = gtk.VBox()
1669
1670 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
1671 xscale = 0.0, yscale = 0.0)
1672 label = gtk.Label(xstr("route_route"))
1673 label.set_use_underline(True)
1674 alignment.add(label)
1675 routeBox.pack_start(alignment, True, True, 0)
1676
1677 routeWindow = gtk.ScrolledWindow()
1678 routeWindow.set_size_request(400, 80)
1679 routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
1680 else gtk.SHADOW_IN)
1681 routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1682 else gtk.POLICY_AUTOMATIC,
1683 gtk.PolicyType.AUTOMATIC if pygobject
1684 else gtk.POLICY_AUTOMATIC)
1685
1686 self._uppercasingRoute = False
1687
1688 self._route = gtk.TextView()
1689 self._route.set_tooltip_text(xstr("route_route_tooltip"))
1690 self._route.set_wrap_mode(WRAP_WORD)
1691 self._route.get_buffer().connect("changed", self._routeChanged)
1692 self._route.get_buffer().connect_after("insert-text", self._routeInserted)
1693 routeWindow.add(self._route)
1694
1695 label.set_mnemonic_widget(self._route)
1696 routeBox.pack_start(routeWindow, True, True, 0)
1697
1698 mainBox.pack_start(routeBox, True, True, 8)
1699
1700 self.addCancelFlightButton()
1701
1702 self._backButton = self.addPreviousButton(clicked = self._backClicked)
1703 self._button = self.addNextButton(clicked = self._forwardClicked)
1704
1705 @property
1706 def filedCruiseLevel(self):
1707 """Get the filed cruise level."""
1708 return self._filedCruiseLevel
1709
1710 @property
1711 def cruiseLevel(self):
1712 """Get the cruise level."""
1713 return self._cruiseLevel.get_value_as_int()
1714
1715 @property
1716 def route(self):
1717 """Get the route."""
1718 return self._getRoute()
1719
1720 def activate(self):
1721 """Setup the route from the booked flight."""
1722 self._cruiseLevel.set_value(240)
1723 self._filedCruiseLevel = 240
1724 self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
1725 self._updateForwardButton()
1726
1727 def _getRoute(self):
1728 """Get the text of the route."""
1729 buffer = self._route.get_buffer()
1730 return buffer.get_text(buffer.get_start_iter(),
1731 buffer.get_end_iter(), True)
1732
1733 def _updateForwardButton(self):
1734 """Update the sensitivity of the forward button."""
1735 self._button.set_sensitive(self._cruiseLevel.get_value_as_int()>=50 and \
1736 self._getRoute()!="")
1737
1738 def _cruiseLevelChanged(self, spinButton):
1739 """Called when the cruise level has changed."""
1740 self._updateForwardButton()
1741 self._wizard.cruiseLevelChanged()
1742
1743 def _routeChanged(self, textBuffer):
1744 """Called when the route has changed."""
1745 if not self._uppercasingRoute:
1746 self._updateForwardButton()
1747
1748 def _routeInserted(self, textBuffer, iter, text, length):
1749 """Called when new characters are inserted into the route.
1750
1751 It uppercases all characters."""
1752 if not self._uppercasingRoute:
1753 self._uppercasingRoute = True
1754
1755 iter1 = iter.copy()
1756 iter1.backward_chars(length)
1757 textBuffer.delete(iter, iter1)
1758
1759 textBuffer.insert(iter, text.upper())
1760
1761 self._uppercasingRoute = False
1762
1763 def _backClicked(self, button):
1764 """Called when the Back button is pressed."""
1765 self.goBack()
1766
1767 def _forwardClicked(self, button):
1768 """Called when the Forward button is clicked."""
1769 if self._completed:
1770 self._wizard.nextPage()
1771 else:
1772 bookedFlight = self._wizard._bookedFlight
1773 self._filedCruiseLevel = self.cruiseLevel
1774 self._wizard.gui.beginBusy(xstr("route_down_notams"))
1775 self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
1776 bookedFlight.departureICAO,
1777 bookedFlight.arrivalICAO)
1778 startSound(const.SOUND_NOTAM)
1779
1780 def _notamsCallback(self, returned, result):
1781 """Callback for the NOTAMs."""
1782 gobject.idle_add(self._handleNOTAMs, returned, result)
1783
1784 def _handleNOTAMs(self, returned, result):
1785 """Handle the NOTAMs."""
1786 if returned:
1787 self._wizard._departureNOTAMs = result.departureNOTAMs
1788 self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
1789 else:
1790 self._wizard._departureNOTAMs = None
1791 self._wizard._arrivalNOTAMs = None
1792
1793 bookedFlight = self._wizard._bookedFlight
1794 self._wizard.gui.beginBusy(xstr("route_down_metars"))
1795 self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
1796 [bookedFlight.departureICAO,
1797 bookedFlight.arrivalICAO])
1798
1799 def _metarsCallback(self, returned, result):
1800 """Callback for the METARs."""
1801 gobject.idle_add(self._handleMETARs, returned, result)
1802
1803 def _handleMETARs(self, returned, result):
1804 """Handle the METARs."""
1805 self._wizard._departureMETAR = None
1806 self._wizard._arrivalMETAR = None
1807 bookedFlight = self._wizard._bookedFlight
1808 if returned:
1809 if bookedFlight.departureICAO in result.metars:
1810 self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
1811 if bookedFlight.arrivalICAO in result.metars:
1812 self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
1813
1814 self._wizard.gui.endBusy()
1815 self._backButton.set_sensitive(True)
1816 self._button.set_sensitive(True)
1817 self._wizard.nextPage()
1818
1819#-----------------------------------------------------------------------------
1820
1821class BriefingPage(Page):
1822 """Page for the briefing."""
1823 def __init__(self, wizard, departure):
1824 """Construct the briefing page."""
1825 self._departure = departure
1826
1827 title = xstr("briefing_title") % (1 if departure else 2,
1828 xstr("briefing_departure")
1829 if departure
1830 else xstr("briefing_arrival"))
1831 super(BriefingPage, self).__init__(wizard, title, xstr("briefing_help"),
1832 completedHelp = xstr("briefing_chelp"))
1833
1834 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
1835 xscale = 1.0, yscale = 1.0)
1836
1837 mainBox = gtk.VBox()
1838 alignment.add(mainBox)
1839 self.setMainWidget(alignment)
1840
1841 self._notamsFrame = gtk.Frame()
1842 self._notamsFrame.set_label(xstr("briefing_notams_init"))
1843 scrolledWindow = gtk.ScrolledWindow()
1844 scrolledWindow.set_size_request(-1, 128)
1845 # FIXME: these constants should be in common
1846 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1847 else gtk.POLICY_AUTOMATIC,
1848 gtk.PolicyType.AUTOMATIC if pygobject
1849 else gtk.POLICY_AUTOMATIC)
1850 self._notams = gtk.TextView()
1851 self._notams.set_editable(False)
1852 self._notams.set_accepts_tab(False)
1853 self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
1854 scrolledWindow.add(self._notams)
1855 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1856 xscale = 1.0, yscale = 1.0)
1857 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1858 padding_left = 0, padding_right = 0)
1859 alignment.add(scrolledWindow)
1860 self._notamsFrame.add(alignment)
1861 mainBox.pack_start(self._notamsFrame, True, True, 4)
1862
1863 self._metarFrame = gtk.Frame()
1864 self._metarFrame.set_label(xstr("briefing_metar_init"))
1865 scrolledWindow = gtk.ScrolledWindow()
1866 scrolledWindow.set_size_request(-1, 32)
1867 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
1868 else gtk.POLICY_AUTOMATIC,
1869 gtk.PolicyType.AUTOMATIC if pygobject
1870 else gtk.POLICY_AUTOMATIC)
1871
1872 self._uppercasingMETAR = False
1873
1874 self._metar = gtk.TextView()
1875 self._metar.set_accepts_tab(False)
1876 self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
1877 self._metar.get_buffer().connect("changed", self._metarChanged)
1878 self._metar.get_buffer().connect_after("insert-text", self._metarInserted)
1879 scrolledWindow.add(self._metar)
1880 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
1881 xscale = 1.0, yscale = 1.0)
1882 alignment.set_padding(padding_top = 4, padding_bottom = 0,
1883 padding_left = 0, padding_right = 0)
1884 alignment.add(scrolledWindow)
1885 self._metarFrame.add(alignment)
1886 mainBox.pack_start(self._metarFrame, True, True, 4)
1887 self.metarEdited = False
1888
1889 self.addCancelFlightButton()
1890
1891 self.addPreviousButton(clicked = self._backClicked)
1892 self._button = self.addNextButton(clicked = self._forwardClicked)
1893
1894 @property
1895 def metar(self):
1896 """Get the METAR on the page."""
1897 buffer = self._metar.get_buffer()
1898 return buffer.get_text(buffer.get_start_iter(),
1899 buffer.get_end_iter(), True)
1900
1901 def setMETAR(self, metar):
1902 """Set the metar."""
1903 self._metar.get_buffer().set_text(metar)
1904 self.metarEdited = False
1905
1906 def activate(self):
1907 """Activate the page."""
1908 if not self._departure:
1909 self._button.set_label(xstr("briefing_button"))
1910 self._button.set_has_tooltip(False)
1911 self._button.set_use_stock(False)
1912
1913 bookedFlight = self._wizard._bookedFlight
1914
1915 icao = bookedFlight.departureICAO if self._departure \
1916 else bookedFlight.arrivalICAO
1917 notams = self._wizard._departureNOTAMs if self._departure \
1918 else self._wizard._arrivalNOTAMs
1919 metar = self._wizard._departureMETAR if self._departure \
1920 else self._wizard._arrivalMETAR
1921
1922 self._notamsFrame.set_label(xstr("briefing_notams_template") % (icao,))
1923 buffer = self._notams.get_buffer()
1924 if notams is None:
1925 buffer.set_text(xstr("briefing_notams_failed"))
1926 elif not notams:
1927 buffer.set_text(xstr("briefing_notams_missing"))
1928 else:
1929 s = ""
1930 for notam in notams:
1931 s += str(notam.begin)
1932 if notam.end is not None:
1933 s += " - " + str(notam.end)
1934 elif notam.permanent:
1935 s += " - PERMANENT"
1936 s += "\n"
1937 if notam.repeatCycle:
1938 s += "Repeat cycle: " + notam.repeatCycle + "\n"
1939 s += notam.notice + "\n"
1940 s += "-------------------- * --------------------\n"
1941 buffer.set_text(s)
1942
1943 self._metarFrame.set_label(xstr("briefing_metar_template") % (icao,))
1944 buffer = self._metar.get_buffer()
1945 if metar is None:
1946 buffer.set_text(xstr("briefing_metar_failed"))
1947 else:
1948 buffer.set_text(metar)
1949
1950 label = self._metarFrame.get_label_widget()
1951 label.set_use_underline(True)
1952 label.set_mnemonic_widget(self._metar)
1953
1954 self.metarEdited = False
1955
1956 def _backClicked(self, button):
1957 """Called when the Back button is pressed."""
1958 self.goBack()
1959
1960 def _forwardClicked(self, button):
1961 """Called when the forward button is clicked."""
1962 if not self._departure:
1963 if not self._completed:
1964 self._wizard.gui.startMonitoring()
1965 self._button.set_label(xstr("button_next"))
1966 self._button.set_tooltip_text(xstr("button_next_tooltip"))
1967 self.complete()
1968
1969 self._wizard.nextPage()
1970
1971 def _metarChanged(self, buffer):
1972 """Called when the METAR has changed."""
1973 if not self._uppercasingMETAR:
1974 self.metarEdited = True
1975 self._button.set_sensitive(buffer.get_text(buffer.get_start_iter(),
1976 buffer.get_end_iter(),
1977 True)!="")
1978
1979 def _metarInserted(self, textBuffer, iter, text, length):
1980 """Called when new characters are inserted into the METAR.
1981
1982 It uppercases all characters."""
1983 if not self._uppercasingMETAR:
1984 self._uppercasingMETAR = True
1985
1986 iter1 = iter.copy()
1987 iter1.backward_chars(length)
1988 textBuffer.delete(iter, iter1)
1989
1990 textBuffer.insert(iter, text.upper())
1991
1992 self._uppercasingMETAR = False
1993
1994#-----------------------------------------------------------------------------
1995
1996class TakeoffPage(Page):
1997 """Page for entering the takeoff data."""
1998 def __init__(self, wizard):
1999 """Construct the takeoff page."""
2000 super(TakeoffPage, self).__init__(wizard, xstr("takeoff_title"),
2001 xstr("takeoff_help"),
2002 completedHelp = xstr("takeoff_chelp"))
2003
2004 self._forwardAllowed = False
2005
2006 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2007 xscale = 0.0, yscale = 0.0)
2008
2009 table = gtk.Table(5, 4)
2010 table.set_row_spacings(4)
2011 table.set_col_spacings(16)
2012 table.set_homogeneous(False)
2013 alignment.add(table)
2014 self.setMainWidget(alignment)
2015
2016 label = gtk.Label(xstr("takeoff_runway"))
2017 label.set_use_underline(True)
2018 label.set_alignment(0.0, 0.5)
2019 table.attach(label, 0, 1, 0, 1)
2020
2021 self._runway = gtk.Entry()
2022 self._runway.set_width_chars(10)
2023 self._runway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
2024 self._runway.connect("changed", self._upperChanged)
2025 table.attach(self._runway, 1, 3, 0, 1)
2026 label.set_mnemonic_widget(self._runway)
2027
2028 label = gtk.Label(xstr("takeoff_sid"))
2029 label.set_use_underline(True)
2030 label.set_alignment(0.0, 0.5)
2031 table.attach(label, 0, 1, 1, 2)
2032
2033 self._sid = gtk.Entry()
2034 self._sid.set_width_chars(10)
2035 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
2036 self._sid.connect("changed", self._upperChanged)
2037 table.attach(self._sid, 1, 3, 1, 2)
2038 label.set_mnemonic_widget(self._sid)
2039
2040 label = gtk.Label(xstr("takeoff_v1"))
2041 label.set_use_markup(True)
2042 label.set_use_underline(True)
2043 label.set_alignment(0.0, 0.5)
2044 table.attach(label, 0, 1, 2, 3)
2045
2046 self._v1 = IntegerEntry()
2047 self._v1.set_width_chars(4)
2048 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip_knots"))
2049 self._v1.connect("integer-changed", self._valueChanged)
2050 table.attach(self._v1, 2, 3, 2, 3)
2051 label.set_mnemonic_widget(self._v1)
2052
2053 self._v1Unit = gtk.Label(xstr("label_knots"))
2054 table.attach(self._v1Unit, 3, 4, 2, 3)
2055
2056 label = gtk.Label(xstr("takeoff_vr"))
2057 label.set_use_markup(True)
2058 label.set_use_underline(True)
2059 label.set_alignment(0.0, 0.5)
2060 table.attach(label, 0, 1, 3, 4)
2061
2062 self._vr = IntegerEntry()
2063 self._vr.set_width_chars(4)
2064 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip_knots"))
2065 self._vr.connect("integer-changed", self._valueChanged)
2066 table.attach(self._vr, 2, 3, 3, 4)
2067 label.set_mnemonic_widget(self._vr)
2068
2069 self._vrUnit = gtk.Label(xstr("label_knots"))
2070 table.attach(self._vrUnit, 3, 4, 3, 4)
2071
2072 label = gtk.Label(xstr("takeoff_v2"))
2073 label.set_use_markup(True)
2074 label.set_use_underline(True)
2075 label.set_alignment(0.0, 0.5)
2076 table.attach(label, 0, 1, 4, 5)
2077
2078 self._v2 = IntegerEntry()
2079 self._v2.set_width_chars(4)
2080 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip_knots"))
2081 self._v2.connect("integer-changed", self._valueChanged)
2082 table.attach(self._v2, 2, 3, 4, 5)
2083 label.set_mnemonic_widget(self._v2)
2084
2085 self._v2Unit = gtk.Label(xstr("label_knots"))
2086 table.attach(self._v2Unit, 3, 4, 4, 5)
2087
2088 self.addCancelFlightButton()
2089
2090 self.addPreviousButton(clicked = self._backClicked)
2091
2092 self._button = self.addNextButton(clicked = self._forwardClicked)
2093
2094 @property
2095 def runway(self):
2096 """Get the runway."""
2097 return self._runway.get_text()
2098
2099 @property
2100 def sid(self):
2101 """Get the SID."""
2102 return self._sid.get_text()
2103
2104 @property
2105 def v1(self):
2106 """Get the v1 speed."""
2107 return self._v1.get_int()
2108
2109 @property
2110 def vr(self):
2111 """Get the vr speed."""
2112 return self._vr.get_int()
2113
2114 @property
2115 def v2(self):
2116 """Get the v2 speed."""
2117 return self._v2.get_int()
2118
2119 def activate(self):
2120 """Activate the page."""
2121 self._runway.set_text("")
2122 self._runway.set_sensitive(True)
2123 self._sid.set_text("")
2124 self._sid.set_sensitive(True)
2125 self._v1.set_int(None)
2126 self._v1.set_sensitive(True)
2127 self._vr.set_int(None)
2128 self._vr.set_sensitive(True)
2129 self._v2.set_int(None)
2130 self._v2.set_sensitive(True)
2131
2132 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
2133 speedUnit = xstr("label" + i18nSpeedUnit)
2134 self._v1Unit.set_text(speedUnit)
2135 self._vrUnit.set_text(speedUnit)
2136 self._v2Unit.set_text(speedUnit)
2137
2138 self._v1.set_tooltip_markup(xstr("takeoff_v1_tooltip" + i18nSpeedUnit))
2139 self._vr.set_tooltip_markup(xstr("takeoff_vr_tooltip" + i18nSpeedUnit))
2140 self._v2.set_tooltip_markup(xstr("takeoff_v2_tooltip" + i18nSpeedUnit))
2141
2142 self._button.set_sensitive(False)
2143 self._forwardAllowed = False
2144
2145 def allowForward(self):
2146 """Allow going to the next page."""
2147 self._forwardAllowed = True
2148 self._updateForwardButton()
2149
2150 def reset(self):
2151 """Reset the page if the wizard is reset."""
2152 super(TakeoffPage, self).reset()
2153 self._v1.reset()
2154 self._vr.reset()
2155 self._v2.reset()
2156
2157 def _updateForwardButton(self):
2158 """Update the sensitivity of the forward button based on some conditions."""
2159 sensitive = self._forwardAllowed and \
2160 self._runway.get_text()!="" and \
2161 self._sid.get_text()!="" and \
2162 self.v1 is not None and \
2163 self.vr is not None and \
2164 self.v2 is not None and \
2165 self.v1 <= self.vr and \
2166 self.vr <= self.v2
2167 self._button.set_sensitive(sensitive)
2168
2169 def _valueChanged(self, widget, arg = None):
2170 """Called when the value of some widget has changed."""
2171 self._updateForwardButton()
2172
2173 def _upperChanged(self, entry, arg = None):
2174 """Called when the value of some entry widget has changed and the value
2175 should be converted to uppercase."""
2176 entry.set_text(entry.get_text().upper())
2177 self._valueChanged(entry, arg)
2178
2179 def _backClicked(self, button):
2180 """Called when the Back button is pressed."""
2181 self.goBack()
2182
2183 def _forwardClicked(self, button):
2184 """Called when the forward button is clicked."""
2185 self._wizard.gui.flight.aircraft.updateV1R2()
2186 self._wizard.nextPage()
2187
2188#-----------------------------------------------------------------------------
2189
2190class LandingPage(Page):
2191 """Page for entering landing data."""
2192 def __init__(self, wizard):
2193 """Construct the landing page."""
2194 super(LandingPage, self).__init__(wizard, xstr("landing_title"),
2195 xstr("landing_help"),
2196 completedHelp = xstr("landing_chelp"))
2197
2198 self._flightEnded = False
2199
2200 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2201 xscale = 0.0, yscale = 0.0)
2202
2203 table = gtk.Table(5, 5)
2204 table.set_row_spacings(4)
2205 table.set_col_spacings(16)
2206 table.set_homogeneous(False)
2207 alignment.add(table)
2208 self.setMainWidget(alignment)
2209
2210 self._starButton = gtk.CheckButton()
2211 self._starButton.connect("clicked", self._starButtonClicked)
2212 table.attach(self._starButton, 0, 1, 0, 1)
2213
2214 label = gtk.Label(xstr("landing_star"))
2215 label.set_use_underline(True)
2216 label.set_alignment(0.0, 0.5)
2217 table.attach(label, 1, 2, 0, 1)
2218
2219 self._star = gtk.Entry()
2220 self._star.set_width_chars(10)
2221 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
2222 self._star.connect("changed", self._upperChanged)
2223 self._star.set_sensitive(False)
2224 table.attach(self._star, 2, 4, 0, 1)
2225 label.set_mnemonic_widget(self._starButton)
2226
2227 self._transitionButton = gtk.CheckButton()
2228 self._transitionButton.connect("clicked", self._transitionButtonClicked)
2229 table.attach(self._transitionButton, 0, 1, 1, 2)
2230
2231 label = gtk.Label(xstr("landing_transition"))
2232 label.set_use_underline(True)
2233 label.set_alignment(0.0, 0.5)
2234 table.attach(label, 1, 2, 1, 2)
2235
2236 self._transition = gtk.Entry()
2237 self._transition.set_width_chars(10)
2238 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
2239 self._transition.connect("changed", self._upperChanged)
2240 self._transition.set_sensitive(False)
2241 table.attach(self._transition, 2, 4, 1, 2)
2242 label.set_mnemonic_widget(self._transitionButton)
2243
2244 label = gtk.Label(xstr("landing_runway"))
2245 label.set_use_underline(True)
2246 label.set_alignment(0.0, 0.5)
2247 table.attach(label, 1, 2, 2, 3)
2248
2249 self._runway = gtk.Entry()
2250 self._runway.set_width_chars(10)
2251 self._runway.set_tooltip_text(xstr("landing_runway_tooltip"))
2252 self._runway.connect("changed", self._upperChanged)
2253 table.attach(self._runway, 2, 4, 2, 3)
2254 label.set_mnemonic_widget(self._runway)
2255
2256 label = gtk.Label(xstr("landing_approach"))
2257 label.set_use_underline(True)
2258 label.set_alignment(0.0, 0.5)
2259 table.attach(label, 1, 2, 3, 4)
2260
2261 self._approachType = gtk.Entry()
2262 self._approachType.set_width_chars(10)
2263 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
2264 self._approachType.connect("changed", self._upperChanged)
2265 table.attach(self._approachType, 2, 4, 3, 4)
2266 label.set_mnemonic_widget(self._approachType)
2267
2268 label = gtk.Label(xstr("landing_vref"))
2269 label.set_use_markup(True)
2270 label.set_use_underline(True)
2271 label.set_alignment(0.0, 0.5)
2272 table.attach(label, 1, 2, 5, 6)
2273
2274 self._vref = IntegerEntry()
2275 self._vref.set_width_chars(5)
2276 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip_knots"))
2277 self._vref.connect("integer-changed", self._vrefChanged)
2278 table.attach(self._vref, 3, 4, 5, 6)
2279 label.set_mnemonic_widget(self._vref)
2280
2281 self._vrefUnit = gtk.Label(xstr("label_knots"))
2282 table.attach(self._vrefUnit, 4, 5, 5, 6)
2283
2284 self.addCancelFlightButton()
2285
2286 self.addPreviousButton(clicked = self._backClicked)
2287
2288 self._button = self.addNextButton(clicked = self._forwardClicked)
2289
2290 # These are needed for correct size calculations
2291 self._starButton.set_active(True)
2292 self._transitionButton.set_active(True)
2293
2294 @property
2295 def star(self):
2296 """Get the STAR or None if none entered."""
2297 return self._star.get_text() if self._starButton.get_active() else None
2298
2299 @property
2300 def transition(self):
2301 """Get the transition or None if none entered."""
2302 return self._transition.get_text() \
2303 if self._transitionButton.get_active() else None
2304
2305 @property
2306 def approachType(self):
2307 """Get the approach type."""
2308 return self._approachType.get_text()
2309
2310 @property
2311 def runway(self):
2312 """Get the runway."""
2313 return self._runway.get_text()
2314
2315 @property
2316 def vref(self):
2317 """Return the landing reference speed."""
2318 return self._vref.get_int()
2319
2320 def reset(self):
2321 """Reset the page if the wizard is reset."""
2322 super(LandingPage, self).reset()
2323 self._vref.reset()
2324 self._flightEnded = False
2325
2326 def activate(self):
2327 """Called when the page is activated."""
2328 self._starButton.set_sensitive(True)
2329 self._starButton.set_active(False)
2330 self._star.set_text("")
2331
2332 self._transitionButton.set_sensitive(True)
2333 self._transitionButton.set_active(False)
2334 self._transition.set_text("")
2335
2336 self._runway.set_text("")
2337 self._runway.set_sensitive(True)
2338
2339 self._approachType.set_text("")
2340 self._approachType.set_sensitive(True)
2341
2342 self._vref.set_int(None)
2343 self._vref.set_sensitive(True)
2344
2345 i18nSpeedUnit = self._wizard.gui.flight.getI18NSpeedUnit()
2346 speedUnit = xstr("label" + i18nSpeedUnit)
2347 self._vrefUnit.set_text(speedUnit)
2348
2349 self._vref.set_tooltip_markup(xstr("landing_vref_tooltip" +
2350 i18nSpeedUnit))
2351
2352 self._updateForwardButton()
2353
2354 def flightEnded(self):
2355 """Called when the flight has ended."""
2356 super(LandingPage, self).flightEnded()
2357 self._flightEnded = True
2358 self._updateForwardButton()
2359
2360 def _starButtonClicked(self, button):
2361 """Called when the STAR button is clicked."""
2362 active = button.get_active()
2363 self._star.set_sensitive(active)
2364 if active:
2365 self._star.grab_focus()
2366 self._updateForwardButton()
2367
2368 def _transitionButtonClicked(self, button):
2369 """Called when the Transition button is clicked."""
2370 active = button.get_active()
2371 self._transition.set_sensitive(active)
2372 if active:
2373 self._transition.grab_focus()
2374 self._updateForwardButton()
2375
2376 def _updateForwardButton(self):
2377 """Update the sensitivity of the forward button."""
2378 sensitive = self._flightEnded and \
2379 (self._starButton.get_active() or \
2380 self._transitionButton.get_active()) and \
2381 (self._star.get_text()!="" or
2382 not self._starButton.get_active()) and \
2383 (self._transition.get_text()!="" or
2384 not self._transitionButton.get_active()) and \
2385 self._runway.get_text()!="" and \
2386 self._approachType.get_text()!="" and \
2387 self.vref is not None
2388 self._button.set_sensitive(sensitive)
2389
2390 def _upperChanged(self, entry):
2391 """Called for entry widgets that must be converted to uppercase."""
2392 entry.set_text(entry.get_text().upper())
2393 self._updateForwardButton()
2394
2395 def _vrefChanged(self, widget, value):
2396 """Called when the Vref has changed."""
2397 self._updateForwardButton()
2398
2399 def _backClicked(self, button):
2400 """Called when the Back button is pressed."""
2401 self.goBack()
2402
2403 def _forwardClicked(self, button):
2404 """Called when the forward button is clicked."""
2405 self._wizard.gui.flight.aircraft.updateVRef()
2406 if self._wizard.gui.config.onlineGateSystem and \
2407 self._wizard.loggedIn and not self._completed and \
2408 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
2409 not self._wizard.entranceExam:
2410 self._wizard.getFleet(callback = self._fleetRetrieved,
2411 force = True)
2412 else:
2413 self._wizard.nextPage()
2414
2415 def _fleetRetrieved(self, fleet):
2416 """Callback for the fleet retrieval."""
2417 self._wizard.nextPage()
2418
2419#-----------------------------------------------------------------------------
2420
2421class FinishPage(Page):
2422 """Flight finish page."""
2423 _flightTypes = [ ("flighttype_scheduled", const.FLIGHTTYPE_SCHEDULED),
2424 ("flighttype_ot", const.FLIGHTTYPE_OLDTIMER),
2425 ("flighttype_vip", const.FLIGHTTYPE_VIP),
2426 ("flighttype_charter", const.FLIGHTTYPE_CHARTER) ]
2427
2428 def __init__(self, wizard):
2429 """Construct the finish page."""
2430 super(FinishPage, self).__init__(wizard, xstr("finish_title"),
2431 xstr("finish_help"))
2432
2433 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
2434 xscale = 0.0, yscale = 0.0)
2435
2436 table = gtk.Table(8, 2)
2437 table.set_row_spacings(4)
2438 table.set_col_spacings(16)
2439 table.set_homogeneous(False)
2440 alignment.add(table)
2441 self.setMainWidget(alignment)
2442
2443 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2444 label = gtk.Label(xstr("finish_rating"))
2445 labelAlignment.add(label)
2446 table.attach(labelAlignment, 0, 1, 0, 1)
2447
2448 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2449 self._flightRating = gtk.Label()
2450 self._flightRating.set_width_chars(8)
2451 self._flightRating.set_alignment(0.0, 0.5)
2452 self._flightRating.set_use_markup(True)
2453 labelAlignment.add(self._flightRating)
2454 table.attach(labelAlignment, 1, 2, 0, 1)
2455
2456 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2457 label = gtk.Label(xstr("finish_flight_time"))
2458 labelAlignment.add(label)
2459 table.attach(labelAlignment, 0, 1, 1, 2)
2460
2461 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2462 self._flightTime = gtk.Label()
2463 self._flightTime.set_width_chars(10)
2464 self._flightTime.set_alignment(0.0, 0.5)
2465 self._flightTime.set_use_markup(True)
2466 labelAlignment.add(self._flightTime)
2467 table.attach(labelAlignment, 1, 2, 1, 2)
2468
2469 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2470 label = gtk.Label(xstr("finish_block_time"))
2471 labelAlignment.add(label)
2472 table.attach(labelAlignment, 0, 1, 2, 3)
2473
2474 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2475 self._blockTime = gtk.Label()
2476 self._blockTime.set_width_chars(10)
2477 self._blockTime.set_alignment(0.0, 0.5)
2478 self._blockTime.set_use_markup(True)
2479 labelAlignment.add(self._blockTime)
2480 table.attach(labelAlignment, 1, 2, 2, 3)
2481
2482 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2483 label = gtk.Label(xstr("finish_distance"))
2484 labelAlignment.add(label)
2485 table.attach(labelAlignment, 0, 1, 3, 4)
2486
2487 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2488 self._distanceFlown = gtk.Label()
2489 self._distanceFlown.set_width_chars(10)
2490 self._distanceFlown.set_alignment(0.0, 0.5)
2491 self._distanceFlown.set_use_markup(True)
2492 labelAlignment.add(self._distanceFlown)
2493 table.attach(labelAlignment, 1, 2, 3, 4)
2494
2495 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
2496 label = gtk.Label(xstr("finish_fuel"))
2497 labelAlignment.add(label)
2498 table.attach(labelAlignment, 0, 1, 4, 5)
2499
2500 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2501 self._fuelUsed = gtk.Label()
2502 self._fuelUsed.set_width_chars(10)
2503 self._fuelUsed.set_alignment(0.0, 0.5)
2504 self._fuelUsed.set_use_markup(True)
2505 labelAlignment.add(self._fuelUsed)
2506 table.attach(labelAlignment, 1, 2, 4, 5)
2507
2508 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
2509 yalign = 0.5, yscale = 0.0)
2510 label = gtk.Label(xstr("finish_type"))
2511 label.set_use_underline(True)
2512 labelAlignment.add(label)
2513 table.attach(labelAlignment, 0, 1, 5, 6)
2514
2515 flightTypeModel = gtk.ListStore(str, int)
2516 for (name, type) in FinishPage._flightTypes:
2517 flightTypeModel.append([xstr(name), type])
2518
2519 self._flightType = gtk.ComboBox(model = flightTypeModel)
2520 renderer = gtk.CellRendererText()
2521 self._flightType.pack_start(renderer, True)
2522 self._flightType.add_attribute(renderer, "text", 0)
2523 self._flightType.set_tooltip_text(xstr("finish_type_tooltip"))
2524 self._flightType.set_active(0)
2525 self._flightType.connect("changed", self._flightTypeChanged)
2526 flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2527 flightTypeAlignment.add(self._flightType)
2528 table.attach(flightTypeAlignment, 1, 2, 5, 6)
2529 label.set_mnemonic_widget(self._flightType)
2530
2531 self._onlineFlight = gtk.CheckButton(xstr("finish_online"))
2532 self._onlineFlight.set_use_underline(True)
2533 self._onlineFlight.set_tooltip_text(xstr("finish_online_tooltip"))
2534 onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
2535 onlineFlightAlignment.add(self._onlineFlight)
2536 table.attach(onlineFlightAlignment, 1, 2, 6, 7)
2537
2538 labelAlignment = gtk.Alignment(xalign = 1.0, xscale = 0.0,
2539 yalign = 0.5, yscale = 0.0)
2540 self._gateLabel = gtk.Label(xstr("finish_gate"))
2541 self._gateLabel.set_use_underline(True)
2542 labelAlignment.add(self._gateLabel)
2543 table.attach(labelAlignment, 0, 1, 7, 8)
2544
2545 self._gatesModel = gtk.ListStore(str)
2546
2547 self._gate = gtk.ComboBox(model = self._gatesModel)
2548 renderer = gtk.CellRendererText()
2549 self._gate.pack_start(renderer, True)
2550 self._gate.add_attribute(renderer, "text", 0)
2551 self._gate.set_tooltip_text(xstr("finish_gate_tooltip"))
2552 self._gate.connect("changed", self._gateChanged)
2553 gateAlignment = gtk.Alignment(xalign=0.0, xscale=1.0)
2554 gateAlignment.add(self._gate)
2555 table.attach(gateAlignment, 1, 2, 7, 8)
2556 self._gateLabel.set_mnemonic_widget(self._gate)
2557
2558 self.addButton(xstr("finish_newFlight"),
2559 sensitive = True,
2560 clicked = self._newFlightClicked,
2561 tooltip = xstr("finish_newFlight_tooltip"),
2562 padding = 16)
2563
2564 self.addPreviousButton(clicked = self._backClicked)
2565
2566 self._saveButton = self.addButton(xstr("finish_save"),
2567 sensitive = False,
2568 clicked = self._saveClicked,
2569 tooltip = xstr("finish_save_tooltip"))
2570 self._savePIREPDialog = None
2571 self._lastSavePath = None
2572
2573 self._pirepSaved = False
2574 self._pirepSent = False
2575
2576 self._sendButton = self.addButton(xstr("sendPIREP"), default = True,
2577 sensitive = False,
2578 clicked = self._sendClicked,
2579 tooltip = xstr("sendPIREP_tooltip"))
2580
2581 @property
2582 def flightType(self):
2583 """Get the flight type."""
2584 index = self._flightType.get_active()
2585 return None if index<0 else self._flightType.get_model()[index][1]
2586
2587 @property
2588 def online(self):
2589 """Get whether the flight was an online flight or not."""
2590 return self._onlineFlight.get_active()
2591
2592 def activate(self):
2593 """Activate the page."""
2594 self._pirepSaved = False
2595 self._pirepSent = False
2596
2597 flight = self._wizard.gui._flight
2598 rating = flight.logger.getRating()
2599 if rating<0:
2600 self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
2601 else:
2602 self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
2603
2604 flightLength = flight.flightTimeEnd - flight.flightTimeStart
2605 self._flightTime.set_markup("<b>%s</b>" % \
2606 (util.getTimeIntervalString(flightLength),))
2607
2608 blockLength = flight.blockTimeEnd - flight.blockTimeStart
2609 self._blockTime.set_markup("<b>%s</b>" % \
2610 (util.getTimeIntervalString(blockLength),))
2611
2612 self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
2613 (flight.flownDistance,))
2614
2615 self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
2616 (flight.startFuel - flight.endFuel,))
2617
2618 self._flightType.set_active(-1)
2619 self._onlineFlight.set_active(self._wizard.loggedIn)
2620
2621 self._gatesModel.clear()
2622 if self._wizard.gui.config.onlineGateSystem and \
2623 self._wizard.loggedIn and \
2624 self._wizard.bookedFlight.arrivalICAO=="LHBP" and \
2625 not self._wizard.entranceExam:
2626 occupiedGates = self._wizard._fleet.getOccupiedGateNumbers()
2627 for gateNumber in const.lhbpGateNumbers:
2628 if gateNumber not in occupiedGates:
2629 self._gatesModel.append([gateNumber])
2630 self._gateLabel.set_sensitive(True)
2631 self._gate.set_sensitive(True)
2632 self._gate.set_active(-1)
2633 else:
2634 self._gateLabel.set_sensitive(False)
2635 self._gate.set_sensitive(False)
2636
2637 def _backClicked(self, button):
2638 """Called when the Back button is pressed."""
2639 self.goBack()
2640
2641 def _updateButtons(self):
2642 """Update the sensitivity state of the buttons."""
2643 sensitive = self._flightType.get_active()>=0 and \
2644 (self._gatesModel.get_iter_first() is None or
2645 self._gate.get_active()>=0)
2646
2647 self._saveButton.set_sensitive(sensitive)
2648 self._sendButton.set_sensitive(sensitive and
2649 self._wizard.bookedFlight.id is not None)
2650
2651 def _flightTypeChanged(self, comboBox):
2652 """Called when the flight type has changed."""
2653 self._updateButtons()
2654
2655 def _gateChanged(self, comboBox):
2656 """Called when the arrival gate has changed."""
2657 self._updateButtons()
2658
2659 def _newFlightClicked(self, button):
2660 """Called when the new flight button is clicked."""
2661 gui = self._wizard.gui
2662 if not self._pirepSent and not self._pirepSaved:
2663 dialog = gtk.MessageDialog(parent = gui.mainWindow,
2664 type = MESSAGETYPE_QUESTION,
2665 message_format = xstr("finish_newFlight_question"))
2666
2667 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
2668 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
2669
2670 dialog.set_title(WINDOW_TITLE_BASE)
2671 result = dialog.run()
2672 dialog.hide()
2673 if result!=RESPONSETYPE_YES:
2674 return
2675
2676 gui.reset()
2677
2678 def _saveClicked(self, button):
2679 """Called when the Save PIREP button is clicked."""
2680 gui = self._wizard.gui
2681
2682 bookedFlight = gui.bookedFlight
2683 tm = time.gmtime()
2684
2685 pilotID = self._wizard.pilotID
2686 if pilotID: pilotID += " "
2687 fileName = "%s%s %02d%02d %s-%s.pirep" % \
2688 (pilotID, str(bookedFlight.departureTime.date()),
2689 tm.tm_hour, tm.tm_min,
2690 bookedFlight.departureICAO,
2691 bookedFlight.arrivalICAO)
2692
2693 dialog = self._getSaveDialog()
2694
2695 if self._lastSavePath is None:
2696 pirepDirectory = gui.config.pirepDirectory
2697 if pirepDirectory is not None:
2698 dialog.set_current_folder(pirepDirectory)
2699 else:
2700 dialog.set_current_folder(os.path.dirname(self._lastSavePath))
2701
2702 dialog.set_current_name(fileName)
2703 result = dialog.run()
2704 dialog.hide()
2705
2706 if result==RESPONSETYPE_OK:
2707 pirep = PIREP(gui.flight)
2708
2709 self._lastSavePath = text2unicode(dialog.get_filename())
2710
2711 if pirep.save(self._lastSavePath):
2712 type = MESSAGETYPE_INFO
2713 message = xstr("finish_save_done")
2714 secondary = None
2715 self._pirepSaved = True
2716 else:
2717 type = MESSAGETYPE_ERROR
2718 message = xstr("finish_save_failed")
2719 secondary = xstr("finish_save_failed_sec")
2720
2721 dialog = gtk.MessageDialog(parent = gui.mainWindow,
2722 type = type, message_format = message)
2723 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
2724 dialog.set_title(WINDOW_TITLE_BASE)
2725 if secondary is not None:
2726 dialog.format_secondary_markup(secondary)
2727
2728 dialog.run()
2729 dialog.hide()
2730
2731 def _getSaveDialog(self):
2732 """Get the PIREP saving dialog.
2733
2734 If it does not exist yet, create it."""
2735 if self._savePIREPDialog is None:
2736 gui = self._wizard.gui
2737 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
2738 xstr("finish_save_title"),
2739 action = FILE_CHOOSER_ACTION_SAVE,
2740 buttons = (gtk.STOCK_CANCEL,
2741 RESPONSETYPE_CANCEL,
2742 gtk.STOCK_OK, RESPONSETYPE_OK),
2743 parent = gui.mainWindow)
2744 dialog.set_modal(True)
2745 dialog.set_do_overwrite_confirmation(True)
2746
2747 filter = gtk.FileFilter()
2748 filter.set_name(xstr("file_filter_pireps"))
2749 filter.add_pattern("*.pirep")
2750 dialog.add_filter(filter)
2751
2752 filter = gtk.FileFilter()
2753 filter.set_name(xstr("file_filter_all"))
2754 filter.add_pattern("*.*")
2755 dialog.add_filter(filter)
2756
2757 self._savePIREPDialog = dialog
2758
2759 return self._savePIREPDialog
2760
2761
2762 def _sendClicked(self, button):
2763 """Called when the Send button is clicked."""
2764 pirep = PIREP(self._wizard.gui.flight)
2765 self._wizard.gui.sendPIREP(pirep,
2766 callback = self._handlePIREPSent)
2767
2768 def _handlePIREPSent(self, returned, result):
2769 """Callback for the PIREP sending result."""
2770 self._pirepSent = returned and result.success
2771 if self._wizard.gui.config.onlineGateSystem and \
2772 self._wizard.loggedIn and not self._wizard.entranceExam and \
2773 returned and result.success:
2774 bookedFlight = self._wizard.bookedFlight
2775 if bookedFlight.arrivalICAO=="LHBP":
2776 iter = self._gate.get_active_iter()
2777 gateNumber = None if iter is None \
2778 else self._gatesModel.get_value(iter, 0)
2779
2780 status = const.PLANE_PARKING if gateNumber is None \
2781 else const.PLANE_HOME
2782 else:
2783 gateNumber = None
2784 status = const.PLANE_AWAY
2785
2786 self._wizard.updatePlane(self._planeUpdated,
2787 bookedFlight.tailNumber,
2788 status, gateNumber = gateNumber)
2789
2790 def _planeUpdated(self, success):
2791 """Callback for the plane updating."""
2792 pass
2793
2794#-----------------------------------------------------------------------------
2795
2796class Wizard(gtk.VBox):
2797 """The flight wizard."""
2798 def __init__(self, gui):
2799 """Construct the wizard."""
2800 super(Wizard, self).__init__()
2801
2802 self.gui = gui
2803
2804 self._pages = []
2805 self._currentPage = None
2806
2807 self._loginPage = LoginPage(self)
2808 self._pages.append(self._loginPage)
2809 self._pages.append(FlightSelectionPage(self))
2810 self._pages.append(GateSelectionPage(self))
2811 self._pages.append(ConnectPage(self))
2812 self._payloadPage = PayloadPage(self)
2813 self._pages.append(self._payloadPage)
2814 self._payloadIndex = len(self._pages)
2815 self._pages.append(TimePage(self))
2816 self._pages.append(FuelPage(self))
2817 self._routePage = RoutePage(self)
2818 self._pages.append(self._routePage)
2819 self._departureBriefingPage = BriefingPage(self, True)
2820 self._pages.append(self._departureBriefingPage)
2821 self._arrivalBriefingPage = BriefingPage(self, False)
2822 self._pages.append(self._arrivalBriefingPage)
2823 self._arrivalBriefingIndex = len(self._pages)
2824 self._takeoffPage = TakeoffPage(self)
2825 self._pages.append(self._takeoffPage)
2826 self._landingPage = LandingPage(self)
2827 self._pages.append(self._landingPage)
2828 self._finishPage = FinishPage(self)
2829 self._pages.append(self._finishPage)
2830
2831 maxWidth = 0
2832 maxHeight = 0
2833 for page in self._pages:
2834 page.show_all()
2835 pageSizeRequest = page.size_request()
2836 width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
2837 height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
2838 maxWidth = max(maxWidth, width)
2839 maxHeight = max(maxHeight, height)
2840 page.setStyle()
2841 maxWidth += 16
2842 maxHeight += 32
2843 self.set_size_request(maxWidth, maxHeight)
2844
2845 self._initialize()
2846
2847 @property
2848 def pilotID(self):
2849 """Get the pilot ID, if given."""
2850 return self._loginPage.pilotID
2851
2852 @property
2853 def entranceExam(self):
2854 """Get whether an entrance exam is about to be taken."""
2855 return self._loginPage.entranceExam
2856
2857 @property
2858 def loggedIn(self):
2859 """Indicate if there was a successful login."""
2860 return self._loginResult is not None
2861
2862 @property
2863 def loginResult(self):
2864 """Get the login result."""
2865 return self._loginResult
2866
2867 def setCurrentPage(self, index, finalize = False):
2868 """Set the current page to the one with the given index."""
2869 assert index < len(self._pages)
2870
2871 fromPage = self._currentPage
2872 if fromPage is not None:
2873 page = self._pages[fromPage]
2874 if finalize and not page._completed:
2875 page.complete()
2876 self.remove(page)
2877
2878 self._currentPage = index
2879 page = self._pages[index]
2880 self.add(page)
2881 if page._fromPage is None:
2882 page._fromPage = fromPage
2883 page.initialize()
2884 self.show_all()
2885 if fromPage is not None:
2886 self.grabDefault()
2887
2888 @property
2889 def bookedFlight(self):
2890 """Get the booked flight selected."""
2891 return self._bookedFlight
2892
2893 @property
2894 def numCrew(self):
2895 """Get the number of crew members."""
2896 return self._payloadPage.numCrew
2897
2898 @property
2899 def numPassengers(self):
2900 """Get the number of passengers."""
2901 return self._payloadPage.numPassengers
2902
2903 @property
2904 def bagWeight(self):
2905 """Get the baggage weight."""
2906 return self._payloadPage.bagWeight
2907
2908 @property
2909 def cargoWeight(self):
2910 """Get the cargo weight."""
2911 return self._payloadPage.cargoWeight
2912
2913 @property
2914 def mailWeight(self):
2915 """Get the mail weight."""
2916 return self._payloadPage.mailWeight
2917
2918 @property
2919 def zfw(self):
2920 """Get the calculated ZFW value."""
2921 return 0 if self._bookedFlight is None \
2922 else self._payloadPage.calculateZFW()
2923
2924 @property
2925 def filedCruiseAltitude(self):
2926 """Get the filed cruise altitude."""
2927 return self._routePage.filedCruiseLevel * 100
2928
2929 @property
2930 def cruiseAltitude(self):
2931 """Get the cruise altitude."""
2932 return self._routePage.cruiseLevel * 100
2933
2934 @property
2935 def route(self):
2936 """Get the route."""
2937 return self._routePage.route
2938
2939 @property
2940 def departureMETAR(self):
2941 """Get the METAR of the departure airport."""
2942 return self._departureBriefingPage.metar
2943
2944 @property
2945 def arrivalMETAR(self):
2946 """Get the METAR of the arrival airport."""
2947 return self._arrivalBriefingPage.metar
2948
2949 @property
2950 def departureRunway(self):
2951 """Get the departure runway."""
2952 return self._takeoffPage.runway
2953
2954 @property
2955 def sid(self):
2956 """Get the SID."""
2957 return self._takeoffPage.sid
2958
2959 @property
2960 def v1(self):
2961 """Get the V1 speed."""
2962 return self._takeoffPage.v1
2963
2964 @property
2965 def vr(self):
2966 """Get the Vr speed."""
2967 return self._takeoffPage.vr
2968
2969 @property
2970 def v2(self):
2971 """Get the V2 speed."""
2972 return self._takeoffPage.v2
2973
2974 @property
2975 def arrivalRunway(self):
2976 """Get the arrival runway."""
2977 return self._landingPage.runway
2978
2979 @property
2980 def star(self):
2981 """Get the STAR."""
2982 return self._landingPage.star
2983
2984 @property
2985 def transition(self):
2986 """Get the transition."""
2987 return self._landingPage.transition
2988
2989 @property
2990 def approachType(self):
2991 """Get the approach type."""
2992 return self._landingPage.approachType
2993
2994 @property
2995 def vref(self):
2996 """Get the Vref speed."""
2997 return self._landingPage.vref
2998
2999 @property
3000 def flightType(self):
3001 """Get the flight type."""
3002 return self._finishPage.flightType
3003
3004 @property
3005 def online(self):
3006 """Get whether the flight was online or not."""
3007 return self._finishPage.online
3008
3009 def nextPage(self, finalize = True):
3010 """Go to the next page."""
3011 self.jumpPage(1, finalize)
3012
3013 def jumpPage(self, count, finalize = True):
3014 """Go to the page which is 'count' pages after the current one."""
3015 self.setCurrentPage(self._currentPage + count, finalize = finalize)
3016
3017 def grabDefault(self):
3018 """Make the default button of the current page the default."""
3019 self._pages[self._currentPage].grabDefault()
3020
3021 def connected(self, fsType, descriptor):
3022 """Called when the connection could be made to the simulator."""
3023 self.nextPage()
3024
3025 def reset(self, loginResult):
3026 """Resets the wizard to go back to the login page."""
3027 self._initialize(keepLoginResult = loginResult is None,
3028 loginResult = loginResult)
3029
3030 def setStage(self, stage):
3031 """Set the flight stage to the given one."""
3032 if stage==const.STAGE_TAKEOFF:
3033 self._takeoffPage.allowForward()
3034 elif stage==const.STAGE_LANDING:
3035 if not self._arrivalBriefingPage.metarEdited:
3036 print "Downloading arrival METAR again"
3037 self.gui.webHandler.getMETARs(self._arrivalMETARCallback,
3038 [self._bookedFlight.arrivalICAO])
3039
3040 elif stage==const.STAGE_END:
3041 for page in self._pages:
3042 page.flightEnded()
3043
3044 def _initialize(self, keepLoginResult = False, loginResult = None):
3045 """Initialize the wizard."""
3046 if not keepLoginResult:
3047 self._loginResult = loginResult
3048
3049 self._loginCallback = None
3050
3051 self._fleet = None
3052 self._fleetCallback = None
3053
3054 self._bookedFlight = None
3055 self._departureGate = "-"
3056 self._fuelData = None
3057 self._departureNOTAMs = None
3058 self._departureMETAR = None
3059 self._arrivalNOTAMs = None
3060 self._arrivalMETAR = None
3061
3062 firstPage = 0 if self._loginResult is None else 1
3063 for page in self._pages[firstPage:]:
3064 page.reset()
3065
3066 self.setCurrentPage(firstPage)
3067
3068 def login(self, callback, pilotID, password, entranceExam):
3069 """Called when the login button was clicked."""
3070 self._loginCallback = callback
3071 if pilotID is None:
3072 loginResult = self._loginResult
3073 assert loginResult is not None and loginResult.loggedIn
3074 pilotID = loginResult.pilotID
3075 password = loginResult.password
3076 entranceExam = loginResult.entranceExam
3077 busyMessage = xstr("reload_busy")
3078 else:
3079 self._loginResult = None
3080 busyMessage = xstr("login_busy")
3081
3082 self.gui.beginBusy(busyMessage)
3083
3084 self.gui.webHandler.login(self._loginResultCallback,
3085 pilotID, password,
3086 entranceExam = entranceExam)
3087
3088 def reloadFlights(self, callback):
3089 """Reload the flights from the MAVA server."""
3090 self.login(callback, None, None, None)
3091
3092 def cruiseLevelChanged(self):
3093 """Called when the cruise level is changed."""
3094 self.gui.cruiseLevelChanged()
3095
3096 def _loginResultCallback(self, returned, result):
3097 """The login result callback, called in the web handler's thread."""
3098 gobject.idle_add(self._handleLoginResult, returned, result)
3099
3100 def _handleLoginResult(self, returned, result):
3101 """Handle the login result."""
3102 self.gui.endBusy()
3103 isReload = self._loginResult is not None
3104 if returned:
3105 if result.loggedIn:
3106 self._loginResult = result
3107 else:
3108 if isReload:
3109 message = xstr("reload_failed")
3110 else:
3111 message = xstr("login_entranceExam_invalid"
3112 if self.entranceExam else
3113 xstr("login_invalid"))
3114 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
3115 type = MESSAGETYPE_ERROR,
3116 message_format = message)
3117 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3118 dialog.set_title(WINDOW_TITLE_BASE)
3119 if isReload:
3120 secondary = xstr("reload_failed_sec")
3121 else:
3122 secondary = xstr("login_entranceExam_invalid_sec"
3123 if self.entranceExam else
3124 xstr("login_invalid_sec"))
3125 dialog.format_secondary_markup(secondary)
3126 dialog.run()
3127 dialog.hide()
3128 else:
3129 message = xstr("reload_failconn") if isReload \
3130 else xstr("login_failconn")
3131 dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
3132 type = MESSAGETYPE_ERROR,
3133 message_format = message)
3134 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
3135 dialog.set_title(WINDOW_TITLE_BASE)
3136 secondary = xstr("reload_failconn_sec") if isReload \
3137 else xstr("login_failconn_sec")
3138 dialog.format_secondary_markup(secondary)
3139
3140 dialog.run()
3141 dialog.hide()
3142
3143 callback = self._loginCallback
3144 self._loginCallback = None
3145 callback(returned, result)
3146
3147 def getFleet(self, callback, force = False):
3148 """Get the fleet via the GUI and call the given callback."""
3149 self._fleetCallback = callback
3150 self.gui.getFleet(callback = self._fleetRetrieved, force = force)
3151
3152 def _fleetRetrieved(self, fleet):
3153 """Callback for the fleet retrieval."""
3154 self._fleet = fleet
3155 if self._fleetCallback is not None:
3156 self._fleetCallback(fleet)
3157 self._fleetCallback = None
3158
3159 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
3160 """Update the given plane's gate information."""
3161 self.gui.updatePlane(tailNumber, status, gateNumber = gateNumber,
3162 callback = callback)
3163
3164 def _connectSimulator(self):
3165 """Connect to the simulator."""
3166 self.gui.connectSimulator(self._bookedFlight.aircraftType)
3167
3168 def _arrivalMETARCallback(self, returned, result):
3169 """Called when the METAR of the arrival airport is retrieved."""
3170 gobject.idle_add(self._handleArrivalMETAR, returned, result)
3171
3172 def _handleArrivalMETAR(self, returned, result):
3173 """Called when the METAR of the arrival airport is retrieved."""
3174 icao = self._bookedFlight.arrivalICAO
3175 if returned and icao in result.metars:
3176 metar = result.metars[icao]
3177 if metar!="":
3178 self._arrivalBriefingPage.setMETAR(metar)
3179
3180#-----------------------------------------------------------------------------
3181
Note: See TracBrowser for help on using the repository browser.