source: src/mlx/gui/flight.py@ 153:f53ca1f24fcc

Last change on this file since 153:f53ca1f24fcc was 151:a2584357ff6c, checked in by István Váradi <ivaradi@…>, 13 years ago

Added support for saving and loading PIREPs

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