source: src/mlx/gui/flight.py@ 383:fcb9932b14ee

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

Added the new Cruise page where the cruise level can be modified (#160)

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