source: src/mlx/gui/flight.py@ 170:7cda0cc74e19

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

The background sounds play back properly

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