source: src/mlx/gui/flight.py@ 275:155f94c971e0

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

The "Cancel flight" buttons are disabled when the flight has ended

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