source: src/mlx/gui/flight.py@ 559:54fa2efc1dc2

Last change on this file since 559:54fa2efc1dc2 was 558:eeea8cc9afc5, checked in by István Váradi <ivaradi@…>, 11 years ago

Added tooltips to the departure and arrival time labels (re #224)

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