source: src/mlx/gui/flight.py@ 184:0a000ef19c3a

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

Added support for the entrance exam

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