source: src/mlx/gui/flight.py@ 199:1fa4570c7c5a

Last change on this file since 199:1fa4570c7c5a was 191:b23bf6aa7672, checked in by István Váradi <ivaradi@…>, 13 years ago

Added support for the charter configuration version of the Boeing 737-800

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