source: src/mlx/gui/flight.py@ 202:aee91ecda48a

Last change on this file since 202:aee91ecda48a was 201:1999280506e6, checked in by István Váradi <ivaradi@…>, 13 years ago

Reworked the styling of the wizard pages so that the background of the title is correct on Gtk+ 3 too

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