source: src/mlx/gui/flight.py@ 349:41c486c8a0b4

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

The basic strobe-less RTO handling logic works (#143)

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