source: src/mlx/gui/flight.py@ 61:7deb4cf7dd78

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

The time page is implemented too.

File size: 35.0 KB
Line 
1# The flight handling "wizard"
2
3from mlx.gui.common import *
4
5import mlx.const as const
6import mlx.fs as fs
7from mlx.checks import PayloadChecker
8
9import datetime
10import time
11
12#-----------------------------------------------------------------------------
13
14class Page(gtk.Alignment):
15 """A page in the flight wizard."""
16 def __init__(self, wizard, title, help):
17 """Construct the page."""
18 super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
19 xscale = 1.0, yscale = 1.0)
20 self.set_padding(padding_top = 4, padding_bottom = 4,
21 padding_left = 12, padding_right = 12)
22
23 frame = gtk.Frame()
24 self.add(frame)
25
26 style = self.get_style() if pygobject else self.rc_get_style()
27
28 self._vbox = gtk.VBox()
29 self._vbox.set_homogeneous(False)
30 frame.add(self._vbox)
31
32 eventBox = gtk.EventBox()
33 eventBox.modify_bg(0, style.bg[3])
34
35 alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
36
37 label = gtk.Label(title)
38 label.modify_fg(0, style.fg[3])
39 label.modify_font(pango.FontDescription("bold 24"))
40 alignment.set_padding(padding_top = 4, padding_bottom = 4,
41 padding_left = 6, padding_right = 0)
42
43 alignment.add(label)
44 eventBox.add(alignment)
45
46 self._vbox.pack_start(eventBox, False, False, 0)
47
48 table = gtk.Table(3, 1)
49 table.set_homogeneous(True)
50
51 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
52 xscale = 1.0, yscale = 1.0)
53 alignment.set_padding(padding_top = 16, padding_bottom = 16,
54 padding_left = 16, padding_right = 16)
55 alignment.add(table)
56 self._vbox.pack_start(alignment, True, True, 0)
57
58 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
59 xscale = 0, yscale = 0.0)
60 alignment.set_padding(padding_top = 0, padding_bottom = 16,
61 padding_left = 0, padding_right = 0)
62
63 label = gtk.Label(help)
64 label.set_justify(gtk.Justification.CENTER if pygobject
65 else gtk.JUSTIFY_CENTER)
66 alignment.add(label)
67 table.attach(alignment, 0, 1, 0, 1)
68
69 self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
70 xscale = 1.0, yscale = 1.0)
71 table.attach(self._mainAlignment, 0, 1, 1, 3)
72
73 buttonAlignment = gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
74 buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
75 padding_left = 16, padding_right = 16)
76
77 self._buttonBox = gtk.HButtonBox()
78 self._defaultButton = None
79 buttonAlignment.add(self._buttonBox)
80
81 self._vbox.pack_start(buttonAlignment, False, False, 0)
82
83 self._wizard = wizard
84
85 def setMainWidget(self, widget):
86 """Set the given widget as the main one."""
87 self._mainAlignment.add(widget)
88
89 def addButton(self, label, default = False):
90 """Add a button with the given label.
91
92 Return the button object created."""
93 button = gtk.Button(label)
94 self._buttonBox.add(button)
95 button.set_use_underline(True)
96 if default:
97 button.set_can_default(True)
98 self._defaultButton = button
99 return button
100
101 def activate(self):
102 """Called when this page becomes active.
103
104 This default implementation does nothing."""
105 pass
106
107 def grabDefault(self):
108 """If the page has a default button, make it the default one."""
109 if self._defaultButton is not None:
110 self._defaultButton.grab_default()
111
112#-----------------------------------------------------------------------------
113
114class LoginPage(Page):
115 """The login page."""
116 def __init__(self, wizard):
117 """Construct the login page."""
118 help = "Enter your MAVA pilot's ID and password to\n" \
119 "log in to the MAVA website and download\n" \
120 "your booked flights."
121 super(LoginPage, self).__init__(wizard, "Login", help)
122
123 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
124 xscale = 0.0, yscale = 0.0)
125
126 table = gtk.Table(2, 3)
127 table.set_row_spacings(4)
128 table.set_col_spacings(32)
129 alignment.add(table)
130 self.setMainWidget(alignment)
131
132 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
133 label = gtk.Label("Pilot _ID:")
134 label.set_use_underline(True)
135 labelAlignment.add(label)
136 table.attach(labelAlignment, 0, 1, 0, 1)
137
138 self._pilotID = gtk.Entry()
139 self._pilotID.connect("changed", self._setLoginButton)
140 self._pilotID.set_tooltip_text("Enter your MAVA pilot's ID. This "
141 "usually starts with a "
142 "'P' followed by 3 digits.")
143 table.attach(self._pilotID, 1, 2, 0, 1)
144 label.set_mnemonic_widget(self._pilotID)
145
146 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
147 label = gtk.Label("_Password:")
148 label.set_use_underline(True)
149 labelAlignment.add(label)
150 table.attach(labelAlignment, 0, 1, 1, 2)
151
152 self._password = gtk.Entry()
153 self._password.set_visibility(False)
154 self._password.connect("changed", self._setLoginButton)
155 self._password.set_tooltip_text("Enter the password for your pilot's ID")
156 table.attach(self._password, 1, 2, 1, 2)
157 label.set_mnemonic_widget(self._password)
158
159 self._rememberButton = gtk.CheckButton("_Remember password")
160 self._rememberButton.set_use_underline(True)
161 self._rememberButton.set_tooltip_text("If checked, your password will "
162 "be stored, so that you should "
163 "not have to enter it every time. "
164 "Note, however, that the password "
165 "is stored as text, and anybody "
166 "who can access your files will "
167 "be able to read it.")
168 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
169
170 self._loginButton = self.addButton("_Login", default = True)
171 self._loginButton.set_sensitive(False)
172 self._loginButton.connect("clicked", self._loginClicked)
173 self._loginButton.set_tooltip_text("Click to log in.")
174
175 config = self._wizard.gui.config
176 self._pilotID.set_text(config.pilotID)
177 self._password.set_text(config.password)
178 self._rememberButton.set_active(config.rememberPassword)
179
180 def _setLoginButton(self, entry):
181 """Set the login button's sensitivity.
182
183 The button is sensitive only if both the pilot ID and the password
184 fields contain values."""
185 self._loginButton.set_sensitive(self._pilotID.get_text()!="" and
186 self._password.get_text()!="")
187
188 def _loginClicked(self, button):
189 """Called when the login button was clicked."""
190 self._wizard.gui.beginBusy("Logging in...")
191 self._wizard.gui.webHandler.login(self._loginResultCallback,
192 self._pilotID.get_text(),
193 self._password.get_text())
194
195 def _loginResultCallback(self, returned, result):
196 """The login result callback, called in the web handler's thread."""
197 gobject.idle_add(self._handleLoginResult, returned, result)
198
199 def _handleLoginResult(self, returned, result):
200 """Handle the login result."""
201 self._wizard.gui.endBusy()
202 if returned:
203 if result.loggedIn:
204 config = self._wizard.gui.config
205
206 config.pilotID = self._pilotID.get_text()
207
208 rememberPassword = self._rememberButton.get_active()
209 config.password = self._password.get_text() if rememberPassword \
210 else ""
211
212 config.rememberPassword = rememberPassword
213
214 config.save()
215 self._wizard._loginResult = result
216 self._wizard.nextPage()
217 else:
218 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
219 buttons = BUTTONSTYPE_OK,
220 message_format =
221 "Invalid pilot's ID or password.")
222 dialog.format_secondary_markup("Check the ID and try to reenter"
223 " the password.")
224 dialog.run()
225 dialog.hide()
226 else:
227 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
228 buttons = BUTTONSTYPE_OK,
229 message_format =
230 "Failed to connect to the MAVA website.")
231 dialog.format_secondary_markup("Try again in a few minutes.")
232 dialog.run()
233 dialog.hide()
234
235#-----------------------------------------------------------------------------
236
237class FlightSelectionPage(Page):
238 """The page to select the flight."""
239 def __init__(self, wizard):
240 """Construct the flight selection page."""
241 super(FlightSelectionPage, self).__init__(wizard, "Flight selection",
242 "Select the flight you want "
243 "to perform.")
244
245
246 self._listStore = gtk.ListStore(str, str, str, str)
247 self._flightList = gtk.TreeView(self._listStore)
248 column = gtk.TreeViewColumn("Flight no.", gtk.CellRendererText(),
249 text = 1)
250 column.set_expand(True)
251 self._flightList.append_column(column)
252 column = gtk.TreeViewColumn("Departure time [UTC]", gtk.CellRendererText(),
253 text = 0)
254 column.set_expand(True)
255 self._flightList.append_column(column)
256 column = gtk.TreeViewColumn("From", gtk.CellRendererText(),
257 text = 2)
258 column.set_expand(True)
259 self._flightList.append_column(column)
260 column = gtk.TreeViewColumn("To", gtk.CellRendererText(),
261 text = 3)
262 column.set_expand(True)
263 self._flightList.append_column(column)
264
265 flightSelection = self._flightList.get_selection()
266 flightSelection.connect("changed", self._selectionChanged)
267
268 scrolledWindow = gtk.ScrolledWindow()
269 scrolledWindow.add(self._flightList)
270 scrolledWindow.set_size_request(400, -1)
271 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
272 else gtk.POLICY_AUTOMATIC,
273 gtk.PolicyType.ALWAYS if pygobject
274 else gtk.POLICY_ALWAYS)
275
276 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
277 alignment.add(scrolledWindow)
278
279 self.setMainWidget(alignment)
280
281 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
282 self._button.set_use_stock(True)
283 self._button.set_sensitive(False)
284 self._button.connect("clicked", self._forwardClicked)
285
286 self._activated = False
287
288 def activate(self):
289 """Fill the flight list."""
290 if not self._activated:
291 for flight in self._wizard.loginResult.flights:
292 self._listStore.append([str(flight.departureTime),
293 flight.callsign,
294 flight.departureICAO,
295 flight.arrivalICAO])
296 self._activated = True
297
298 def _selectionChanged(self, selection):
299 """Called when the selection is changed."""
300 self._button.set_sensitive(selection.count_selected_rows()==1)
301
302 def _forwardClicked(self, button):
303 """Called when the forward button was clicked."""
304 selection = self._flightList.get_selection()
305 (listStore, iter) = selection.get_selected()
306 path = listStore.get_path(iter)
307 [index] = path.get_indices() if pygobject else path
308
309 flight = self._wizard.loginResult.flights[index]
310 self._wizard._bookedFlight = flight
311
312 self._updateDepartureGate()
313
314 def _updateDepartureGate(self):
315 """Update the departure gate for the booked flight."""
316 flight = self._wizard._bookedFlight
317 if flight.departureICAO=="LHBP":
318 self._wizard._getFleet(self._fleetRetrieved)
319 else:
320 self._wizard.jumpPage(2)
321
322 def _fleetRetrieved(self, fleet):
323 """Called when the fleet has been retrieved."""
324 if fleet is None:
325 self._wizard.jumpPage(2)
326 else:
327 plane = fleet[self._wizard._bookedFlight.tailNumber]
328 if plane is None:
329 self._wizard.jumpPage(2)
330
331 if plane.gateNumber is not None and \
332 not fleet.isGateConflicting(plane):
333 self._wizard._departureGate = plane.gateNumber
334 self._wizard.jumpPage(2)
335 else:
336 self._wizard.nextPage()
337
338#-----------------------------------------------------------------------------
339
340class GateSelectionPage(Page):
341 """Page to select a free gate at LHBP.
342
343 This page should be displayed only if we have fleet information!."""
344 def __init__(self, wizard):
345 """Construct the gate selection page."""
346 help = "The airplane's gate position is invalid.\n\n" \
347 "Select the gate from which you\n" \
348 "would like to begin the flight."
349 super(GateSelectionPage, self).__init__(wizard,
350 "LHBP gate selection",
351 help)
352
353 self._listStore = gtk.ListStore(str)
354 self._gateList = gtk.TreeView(self._listStore)
355 column = gtk.TreeViewColumn(None, gtk.CellRendererText(),
356 text = 0)
357 column.set_expand(True)
358 self._gateList.append_column(column)
359 self._gateList.set_headers_visible(False)
360
361 gateSelection = self._gateList.get_selection()
362 gateSelection.connect("changed", self._selectionChanged)
363
364 scrolledWindow = gtk.ScrolledWindow()
365 scrolledWindow.add(self._gateList)
366 scrolledWindow.set_size_request(50, -1)
367 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
368 else gtk.POLICY_AUTOMATIC,
369 gtk.PolicyType.ALWAYS if pygobject
370 else gtk.POLICY_ALWAYS)
371
372 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
373 alignment.add(scrolledWindow)
374
375 self.setMainWidget(alignment)
376
377 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
378 self._button.set_use_stock(True)
379 self._button.set_sensitive(False)
380 self._button.connect("clicked", self._forwardClicked)
381
382 def activate(self):
383 """Fill the gate list."""
384 self._listStore.clear()
385 occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
386 for gateNumber in const.lhbpGateNumbers:
387 if gateNumber not in occupiedGateNumbers:
388 self._listStore.append([gateNumber])
389
390 def _selectionChanged(self, selection):
391 """Called when the selection is changed."""
392 self._button.set_sensitive(selection.count_selected_rows()==1)
393
394 def _forwardClicked(self, button):
395 """Called when the forward button is clicked."""
396 selection = self._gateList.get_selection()
397 (listStore, iter) = selection.get_selected()
398 (gateNumber,) = listStore.get(iter, 0)
399
400 self._wizard._departureGate = gateNumber
401
402 #self._wizard._updatePlane(self._planeUpdated,
403 # self._wizard._bookedFlight.tailNumber,
404 # const.PLANE_HOME,
405 # gateNumber)
406 self._wizard.nextPage()
407
408 def _planeUpdated(self, success):
409 """Callback for the plane updating call."""
410 if success is None or success:
411 self._wizard.nextPage()
412 else:
413 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
414 buttons = BUTTONSTYPE_OK,
415 message_format = "Gate conflict detected again")
416 dialog.format_secondary_markup("Try to select a different gate.")
417 dialog.run()
418 dialog.hide()
419
420 self._wizard._getFleet(self._fleetRetrieved)
421
422 def _fleetRetrieved(self, fleet):
423 """Called when the fleet has been retrieved."""
424 if fleet is None:
425 self._wizard.nextPage()
426 else:
427 self.activate()
428
429#-----------------------------------------------------------------------------
430
431class ConnectPage(Page):
432 """Page which displays the departure airport and gate (if at LHBP)."""
433 def __init__(self, wizard):
434 """Construct the connect page."""
435 help = "The flight begins at the airport given below.\n" \
436 "Park your aircraft there, at the gate below, if given.\n\n" \
437 "Then press the Connect button to connect to the simulator."
438 super(ConnectPage, self).__init__(wizard,
439 "Connect to the simulator",
440 help)
441
442 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
443 xscale = 0.0, yscale = 0.0)
444
445 table = gtk.Table(2, 2)
446 table.set_row_spacings(4)
447 table.set_col_spacings(16)
448 table.set_homogeneous(True)
449 alignment.add(table)
450 self.setMainWidget(alignment)
451
452 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
453 label = gtk.Label("ICAO code:")
454 labelAlignment.add(label)
455 table.attach(labelAlignment, 0, 1, 0, 1)
456
457 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
458 self._departureICAO = gtk.Label()
459 self._departureICAO.set_width_chars(5)
460 self._departureICAO.set_alignment(0.0, 0.5)
461 labelAlignment.add(self._departureICAO)
462 table.attach(labelAlignment, 1, 2, 0, 1)
463
464 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
465 label = gtk.Label("Gate:")
466 labelAlignment.add(label)
467 table.attach(labelAlignment, 0, 1, 1, 2)
468
469 labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
470 self._departureGate = gtk.Label()
471 self._departureGate.set_width_chars(5)
472 self._departureGate.set_alignment(0.0, 0.5)
473 labelAlignment.add(self._departureGate)
474 table.attach(labelAlignment, 1, 2, 1, 2)
475
476 self._button = self.addButton("_Connect", default = True)
477 self._button.set_use_underline(True)
478 self._button.connect("clicked", self._connectClicked)
479
480 def activate(self):
481 """Setup the departure information."""
482 icao = self._wizard._bookedFlight.departureICAO
483 self._departureICAO.set_markup("<b>" + icao + "</b>")
484 gate = self._wizard._departureGate
485 if gate!="-":
486 gate = "<b>" + gate + "</b>"
487 self._departureGate.set_markup(gate)
488
489 def _connectClicked(self, button):
490 """Called when the Connect button is pressed."""
491 self._wizard._connectSimulator()
492
493#-----------------------------------------------------------------------------
494
495class PayloadPage(Page):
496 """Page to allow setting up the payload."""
497 def __init__(self, wizard):
498 """Construct the page."""
499 help = "The briefing contains the weights below.\n" \
500 "Setup the cargo weight here and the payload weight in the simulator.\n\n" \
501 "You can also check here what the simulator reports as ZFW."
502
503 super(PayloadPage, self).__init__(wizard, "Payload", help)
504
505 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
506 xscale = 0.0, yscale = 0.0)
507
508 table = gtk.Table(7, 3)
509 table.set_row_spacings(4)
510 table.set_col_spacings(16)
511 table.set_homogeneous(False)
512 alignment.add(table)
513 self.setMainWidget(alignment)
514
515 label = gtk.Label("Crew:")
516 label.set_alignment(0.0, 0.5)
517 table.attach(label, 0, 1, 0, 1)
518
519 self._numCrew = gtk.Label()
520 self._numCrew.set_width_chars(6)
521 self._numCrew.set_alignment(1.0, 0.5)
522 table.attach(self._numCrew, 1, 2, 0, 1)
523
524 label = gtk.Label("Passengers:")
525 label.set_alignment(0.0, 0.5)
526 table.attach(label, 0, 1, 1, 2)
527
528 self._numPassengers = gtk.Label()
529 self._numPassengers.set_width_chars(6)
530 self._numPassengers.set_alignment(1.0, 0.5)
531 table.attach(self._numPassengers, 1, 2, 1, 2)
532
533 label = gtk.Label("Baggage:")
534 label.set_alignment(0.0, 0.5)
535 table.attach(label, 0, 1, 2, 3)
536
537 self._bagWeight = gtk.Label()
538 self._bagWeight.set_width_chars(6)
539 self._bagWeight.set_alignment(1.0, 0.5)
540 table.attach(self._bagWeight, 1, 2, 2, 3)
541
542 table.attach(gtk.Label("kg"), 2, 3, 2, 3)
543
544 label = gtk.Label("_Cargo:")
545 label.set_use_underline(True)
546 label.set_alignment(0.0, 0.5)
547 table.attach(label, 0, 1, 3, 4)
548
549 self._cargoWeight = gtk.Entry()
550 self._cargoWeight.set_width_chars(6)
551 self._cargoWeight.set_alignment(1.0)
552 self._cargoWeight.connect("changed", self._cargoWeightChanged)
553 self._cargoWeight.set_tooltip_text("The weight of the cargo for your flight.")
554 table.attach(self._cargoWeight, 1, 2, 3, 4)
555 self._cargoWeightValue = 0
556 label.set_mnemonic_widget(self._cargoWeight)
557
558 table.attach(gtk.Label("kg"), 2, 3, 3, 4)
559
560 label = gtk.Label("Mail:")
561 label.set_alignment(0.0, 0.5)
562 table.attach(label, 0, 1, 4, 5)
563
564 self._mailWeight = gtk.Label()
565 self._mailWeight.set_width_chars(6)
566 self._mailWeight.set_alignment(1.0, 0.5)
567 table.attach(self._mailWeight, 1, 2, 4, 5)
568
569 table.attach(gtk.Label("kg"), 2, 3, 4, 5)
570
571 label = gtk.Label("<b>Calculated ZFW:</b>")
572 label.set_alignment(0.0, 0.5)
573 label.set_use_markup(True)
574 table.attach(label, 0, 1, 5, 6)
575
576 self._calculatedZFW = gtk.Label()
577 self._calculatedZFW.set_width_chars(6)
578 self._calculatedZFW.set_alignment(1.0, 0.5)
579 table.attach(self._calculatedZFW, 1, 2, 5, 6)
580
581 table.attach(gtk.Label("kg"), 2, 3, 5, 6)
582
583 button = gtk.Button("_ZFW from FS:")
584 button.set_use_underline(True)
585 button.connect("clicked", self._zfwRequested)
586 table.attach(button, 0, 1, 6, 7)
587
588 self._simulatorZFW = gtk.Label("-")
589 self._simulatorZFW.set_width_chars(6)
590 self._simulatorZFW.set_alignment(1.0, 0.5)
591 table.attach(self._simulatorZFW, 1, 2, 6, 7)
592 self._simulatorZFWValue = None
593
594 table.attach(gtk.Label("kg"), 2, 3, 6, 7)
595
596 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
597 self._button.set_use_stock(True)
598 self._button.connect("clicked", self._forwardClicked)
599
600 def activate(self):
601 """Setup the information."""
602 bookedFlight = self._wizard._bookedFlight
603 self._numCrew.set_text(str(bookedFlight.numCrew))
604 self._numPassengers.set_text(str(bookedFlight.numPassengers))
605 self._bagWeight.set_text(str(bookedFlight.bagWeight))
606 self._cargoWeightValue = bookedFlight.cargoWeight
607 self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
608 self._mailWeight.set_text(str(bookedFlight.mailWeight))
609 self._updateCalculatedZFW()
610
611 def _calculateZFW(self):
612 """Calculate the ZFW value."""
613 zfw = self._wizard.gui._flight.aircraft.dow
614 bookedFlight = self._wizard._bookedFlight
615 zfw += (bookedFlight.numCrew + bookedFlight.numPassengers) * 82
616 zfw += bookedFlight.bagWeight
617 zfw += self._cargoWeightValue
618 zfw += bookedFlight.mailWeight
619 return zfw
620
621 def _updateCalculatedZFW(self):
622 """Update the calculated ZFW"""
623 zfw = self._calculateZFW()
624
625 markupBegin = "<b>"
626 markupEnd = "</b>"
627 if self._simulatorZFWValue is not None and \
628 PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
629 markupBegin += '<span foreground="red">'
630 markupEnd = "</span>" + markupEnd
631 self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
632
633 def _cargoWeightChanged(self, entry):
634 """Called when the cargo weight has changed."""
635 text = self._cargoWeight.get_text()
636 if text=="":
637 self._cargoWeightValue = 0
638 else:
639 try:
640 self._cargoWeightValue = int(text)
641 except:
642 self._cargoWeight.set_text(str(self._cargoWeightValue))
643 self._updateCalculatedZFW()
644
645 def _zfwRequested(self, button):
646 """Called when the ZFW is requested from the simulator."""
647 self._wizard.gui.beginBusy("Querying ZFW...")
648 self._wizard.gui.simulator.requestZFW(self._handleZFW)
649
650 def _handleZFW(self, zfw):
651 """Called when the ZFW value is retrieved."""
652 gobject.idle_add(self._processZFW, zfw)
653
654 def _processZFW(self, zfw):
655 """Process the given ZFW value received from the simulator."""
656 self._wizard.gui.endBusy()
657 self._simulatorZFWValue = zfw
658 self._simulatorZFW.set_text("%.0f" % (zfw,))
659 self._updateCalculatedZFW()
660
661 def _forwardClicked(self, button):
662 """Called when the forward button is clicked."""
663 self._wizard._zfw = self._calculateZFW()
664 self._wizard.nextPage()
665
666#-----------------------------------------------------------------------------
667
668class TimePage(Page):
669 """Page displaying the departure and arrival times and allows querying the
670 current time from the flight simulator."""
671 def __init__(self, wizard):
672 help = "The departure and arrival times are displayed below in UTC.\n\n" \
673 "You can also query the current UTC time from the simulator.\n" \
674 "Ensure that you have enough time to properly prepare for the flight."
675
676 super(TimePage, self).__init__(wizard, "Time", help)
677
678 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
679 xscale = 0.0, yscale = 0.0)
680
681 table = gtk.Table(3, 2)
682 table.set_row_spacings(4)
683 table.set_col_spacings(16)
684 table.set_homogeneous(False)
685 alignment.add(table)
686 self.setMainWidget(alignment)
687
688 label = gtk.Label("Departure:")
689 label.set_alignment(0.0, 0.5)
690 table.attach(label, 0, 1, 0, 1)
691
692 self._departure = gtk.Label()
693 self._departure.set_alignment(0.0, 0.5)
694 table.attach(self._departure, 1, 2, 0, 1)
695
696 label = gtk.Label("Arrival:")
697 label.set_alignment(0.0, 0.5)
698 table.attach(label, 0, 1, 1, 2)
699
700 self._arrival = gtk.Label()
701 self._arrival.set_alignment(0.0, 0.5)
702 table.attach(self._arrival, 1, 2, 1, 2)
703
704 button = gtk.Button("_Time from FS:")
705 button.set_use_underline(True)
706 button.connect("clicked", self._timeRequested)
707 table.attach(button, 0, 1, 2, 3)
708
709 self._simulatorTime = gtk.Label("-")
710 self._simulatorTime.set_alignment(0.0, 0.5)
711 table.attach(self._simulatorTime, 1, 2, 2, 3)
712
713 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
714 self._button.set_use_stock(True)
715 self._button.connect("clicked", self._forwardClicked)
716
717 def activate(self):
718 """Activate the page."""
719 bookedFlight = self._wizard._bookedFlight
720 self._departure.set_text(str(bookedFlight.departureTime.time()))
721 self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
722
723 def _timeRequested(self, button):
724 """Request the time from the simulator."""
725 self._wizard.gui.beginBusy("Querying time...")
726 self._wizard.gui.simulator.requestTime(self._handleTime)
727
728 def _handleTime(self, timestamp):
729 """Handle the result of a time retrieval."""
730 gobject.idle_add(self._processTime, timestamp)
731
732 def _processTime(self, timestamp):
733 """Process the given time."""
734 self._wizard.gui.endBusy()
735 tm = time.gmtime(timestamp)
736 t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
737 self._simulatorTime.set_text(str(t))
738
739 ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
740 dt = self._wizard._bookedFlight.departureTime.time()
741 dts = dt.hour * 3600 + dt.minute * 60 + dt.second
742 diff = dts-ts
743
744 markupBegin = ""
745 markupEnd = ""
746 if diff < 0:
747 markupBegin = '<b><span foreground="red">'
748 markupEnd = '</span></b>'
749 elif diff < 3*60 or diff > 30*60:
750 markupBegin = '<b><span foreground="orange">'
751 markupEnd = '</span></b>'
752
753 self._departure.set_markup(markupBegin + str(dt) + markupEnd)
754
755 def _forwardClicked(self, button):
756 """Called when the forward button is clicked."""
757 self._wizard.nextPage()
758
759#-----------------------------------------------------------------------------
760
761class Wizard(gtk.VBox):
762 """The flight wizard."""
763 def __init__(self, gui):
764 """Construct the wizard."""
765 super(Wizard, self).__init__()
766
767 self.gui = gui
768
769 self._pages = []
770 self._currentPage = None
771
772 self._pages.append(LoginPage(self))
773 self._pages.append(FlightSelectionPage(self))
774 self._pages.append(GateSelectionPage(self))
775 self._pages.append(ConnectPage(self))
776 self._pages.append(PayloadPage(self))
777 self._pages.append(TimePage(self))
778
779 maxWidth = 0
780 maxHeight = 0
781 for page in self._pages:
782 page.show_all()
783 pageSizeRequest = page.size_request()
784 width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
785 height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
786 maxWidth = max(maxWidth, width)
787 maxHeight = max(maxHeight, height)
788 maxWidth += 16
789 maxHeight += 32
790 self.set_size_request(maxWidth, maxHeight)
791
792 self._initialize()
793
794 @property
795 def loginResult(self):
796 """Get the login result."""
797 return self._loginResult
798
799 def setCurrentPage(self, index):
800 """Set the current page to the one with the given index."""
801 assert index < len(self._pages)
802
803 if self._currentPage is not None:
804 self.remove(self._pages[self._currentPage])
805
806 self._currentPage = index
807 self.add(self._pages[index])
808 self._pages[index].activate()
809 self.show_all()
810
811 def nextPage(self):
812 """Go to the next page."""
813 self.jumpPage(1)
814
815 def jumpPage(self, count):
816 """Go to the page which is 'count' pages after the current one."""
817 self.setCurrentPage(self._currentPage + count)
818 self.grabDefault()
819
820 def grabDefault(self):
821 """Make the default button of the current page the default."""
822 self._pages[self._currentPage].grabDefault()
823
824 def connected(self, fsType, descriptor):
825 """Called when the connection could be made to the simulator."""
826 self.nextPage()
827
828 def connectionFailed(self):
829 """Called when the connection could not be made to the simulator."""
830 self._initialize()
831
832 def disconnected(self):
833 """Called when we have disconnected from the simulator."""
834 self._initialize()
835
836 def _initialize(self):
837 """Initialize the wizard."""
838 self._fleet = None
839 self._fleetCallback = None
840 self._updatePlaneCallback = None
841
842 self._loginResult = None
843 self._bookedFlight = None
844 self._departureGate = "-"
845 self._zfw = None
846
847 self.setCurrentPage(0)
848
849 def _getFleet(self, callback, force = False):
850 """Get the fleet, if needed.
851
852 callback is function that will be called, when the feet is retrieved,
853 or the retrieval fails. It should have a single argument that will
854 receive the fleet object on success, None otherwise.
855 """
856 if self._fleet is not None and not force:
857 callback(self._fleet)
858
859 self.gui.beginBusy("Retrieving fleet...")
860 self._fleetCallback = callback
861 self.gui.webHandler.getFleet(self._fleetResultCallback)
862
863 def _fleetResultCallback(self, returned, result):
864 """Called when the fleet has been queried."""
865 gobject.idle_add(self._handleFleetResult, returned, result)
866
867 def _handleFleetResult(self, returned, result):
868 """Handle the fleet result."""
869 self.gui.endBusy()
870 if returned:
871 self._fleet = result.fleet
872 else:
873 self._fleet = None
874
875 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
876 buttons = BUTTONSTYPE_OK,
877 message_format =
878 "Failed to retrieve the information on "
879 "the fleet.")
880 dialog.run()
881 dialog.hide()
882
883 self._fleetCallback(self._fleet)
884
885 def _updatePlane(self, callback, tailNumber, status, gateNumber = None):
886 """Update the given plane's gate information."""
887 self.gui.beginBusy("Updating plane status...")
888 self._updatePlaneCallback = callback
889 self.gui.webHandler.updatePlane(self._updatePlaneResultCallback,
890 tailNumber, status, gateNumber)
891
892 def _updatePlaneResultCallback(self, returned, result):
893 """Callback for the plane updating operation."""
894 gobject.idle_add(self._handleUpdatePlaneResult, returned, result)
895
896 def _handleUpdatePlaneResult(self, returned, result):
897 """Handle the result of a plane update operation."""
898 self.gui.endBusy()
899 if returned:
900 success = result.success
901 else:
902 success = None
903
904 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
905 buttons = BUTTONSTYPE_OK,
906 message_format =
907 "Failed to update the statuis of "
908 "the airplane.")
909 dialog.run()
910 dialog.hide()
911
912 self._updatePlaneCallback(success)
913
914 def _connectSimulator(self):
915 """Connect to the simulator."""
916 self.gui.connectSimulator(self._bookedFlight.aircraftType)
917
918#-----------------------------------------------------------------------------
919
Note: See TracBrowser for help on using the repository browser.