source: src/mlx/gui/flight.py@ 241:dea155dd3ac0

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

Added support for calculating speeds in km/h for Soviet aircraft

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