source: src/mlx/gui/flightlist.py@ 1096:3b923185a50d

python3
Last change on this file since 1096:3b923185a50d was 1033:330058d37574, checked in by István Váradi <ivaradi@…>, 3 years ago

Updates for the new crew and passenger handling (re #357)

File size: 28.4 KB
Line 
1# A widget which is a generic list of flights
2
3#-----------------------------------------------------------------------------
4
5from mlx.gui.common import *
6
7import mlx.const as const
8
9#-----------------------------------------------------------------------------
10
11class ColumnDescriptor(object):
12 """A descriptor for a column in the list."""
13 def __init__(self, attribute, heading, type = str,
14 convertFn = None, renderer = None,
15 extraColumnAttributes = None, sortable = False,
16 defaultSortable = False, defaultDescending = False,
17 cellDataFn = None):
18 """Construct the descriptor."""
19 self._attribute = attribute
20 self._heading = heading
21 self._type = type
22 self._convertFn = convertFn
23 self._renderer = \
24 Gtk.CellRendererText() if renderer is None else renderer
25 self._extraColumnAttributes = extraColumnAttributes
26 self._sortable = sortable
27 self._defaultSortable = defaultSortable
28 self._defaultDescending = defaultDescending
29 self._cellDataFn = cellDataFn
30
31 @property
32 def attribute(self):
33 """Get the attribute the column belongs to."""
34 return self._attribute
35
36 @property
37 def defaultSortable(self):
38 """Determine if this column is the default sortable one."""
39 return self._defaultSortable
40
41 def appendType(self, types):
42 """Append the type of this column to the given list of types."""
43 types.append(self._type)
44
45 def getViewColumn(self, index):
46 """Get a new column object for a tree view.
47
48 @param index is the 0-based index of the column."""
49 if isinstance(self._renderer, Gtk.CellRendererText):
50 column = Gtk.TreeViewColumn(self._heading, self._renderer,
51 text = index)
52 elif isinstance(self._renderer, Gtk.CellRendererToggle):
53 column = Gtk.TreeViewColumn(self._heading, self._renderer,
54 active = index)
55 else:
56 column = Gtk.TreeViewColumn(self._heading, self._renderer)
57 column.set_expand(True)
58 if self._sortable:
59 column.set_sort_column_id(index)
60 column.set_sort_indicator(True)
61
62 if self._extraColumnAttributes is not None:
63 for (key, value) in self._extraColumnAttributes.items():
64 if key=="alignment":
65 self._renderer.set_alignment(value, 0.5)
66 else:
67 raise Exception("unhandled extra column attribute '" +
68 key + "'")
69 if self._cellDataFn is not None:
70 column.set_cell_data_func(self._renderer, self._cellDataFn)
71
72 return column
73
74 def getValueFrom(self, flight):
75 """Get the value from the given flight."""
76 attributes = self._attribute.split(".")
77 value = getattr(flight, attributes[0])
78 for attr in attributes[1:]:
79 value = getattr(value, attr)
80 return self._type(value) if self._convertFn is None \
81 else self._convertFn(value, flight)
82
83#-----------------------------------------------------------------------------
84
85class FlightList(Gtk.Alignment):
86 """Construct the flight list.
87
88 This is a complete widget with a scroll window. It is alignment centered
89 horizontally and expandable vertically."""
90
91 defaultColumnDescriptors = [
92 ColumnDescriptor("callsign", xstr("flightsel_no")),
93 ColumnDescriptor("departureTime", xstr("flightsel_deptime"),
94 sortable = True, defaultSortable = True),
95 ColumnDescriptor("departureICAO", xstr("flightsel_from"),
96 sortable = True),
97 ColumnDescriptor("arrivalICAO", xstr("flightsel_to"), sortable = True)
98 ]
99
100 def __init__(self, columnDescriptors = defaultColumnDescriptors,
101 popupMenuProducer = None, widthRequest = None,
102 multiSelection = False):
103 """Construct the flight list with the given column descriptors."""
104
105 self._columnDescriptors = columnDescriptors
106 self._popupMenuProducer = popupMenuProducer
107 self._popupMenu = None
108
109 types = [int]
110 defaultSortableIndex = None
111 for columnDescriptor in self._columnDescriptors:
112 if columnDescriptor.defaultSortable:
113 defaultSortableIndex = len(types)
114 columnDescriptor.appendType(types)
115
116 self._model = Gtk.ListStore(*types)
117 if defaultSortableIndex is not None:
118 sortOrder = Gtk.SortType.DESCENDING \
119 if self._columnDescriptors[defaultSortableIndex-1]._defaultDescending \
120 else Gtk.SortType.ASCENDING
121 self._model.set_sort_column_id(defaultSortableIndex, sortOrder)
122 self._view = Gtk.TreeView(self._model)
123
124 flightIndexColumn = Gtk.TreeViewColumn()
125 flightIndexColumn.set_visible(False)
126 self._view.append_column(flightIndexColumn)
127
128 index = 1
129 for columnDescriptor in self._columnDescriptors:
130 column = columnDescriptor.getViewColumn(index)
131 self._view.append_column(column)
132 index += 1
133
134 self._view.connect("row-activated", self._rowActivated)
135 self._view.connect("button-press-event", self._buttonPressEvent)
136
137 selection = self._view.get_selection()
138 selection.connect("changed", self._selectionChanged)
139 if multiSelection:
140 selection.set_mode(Gtk.SelectionMode.MULTIPLE)
141
142 scrolledWindow = Gtk.ScrolledWindow()
143 scrolledWindow.add(self._view)
144 if widthRequest is not None:
145 scrolledWindow.set_size_request(widthRequest, -1)
146 # FIXME: these should be constants in common.py
147 scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC,
148 Gtk.PolicyType.AUTOMATIC)
149 scrolledWindow.set_shadow_type(Gtk.ShadowType.IN)
150
151 super(FlightList, self).__init__(xalign = 0.5, yalign = 0.0,
152 xscale = 0.0, yscale = 1.0)
153 self.add(scrolledWindow)
154
155 @property
156 def selectedIndexes(self):
157 """Get the indexes of the selected entries, if any.
158
159 The indexes are sorted."""
160 selection = self._view.get_selection()
161 (model, rows) = selection.get_selected_rows()
162
163 indexes = [self._getIndexForPath(path) for path in rows]
164 indexes.sort()
165 return indexes
166
167 @property
168 def hasFlights(self):
169 """Determine if there are any flights in the list."""
170 return self._model.get_iter_first() is not None
171
172 def clear(self):
173 """Clear the model."""
174 self._model.clear()
175
176 def addFlight(self, flight):
177 """Add the given booked flight."""
178 values = [self._model.iter_n_children(None)]
179 for columnDescriptor in self._columnDescriptors:
180 values.append(columnDescriptor.getValueFrom(flight))
181 self._model.append(values)
182
183 def removeFlights(self, indexes):
184 """Remove the flights with the given indexes."""
185 model = self._model
186 idx = 0
187 iter = model.get_iter_first()
188 while iter is not None:
189 nextIter = model.iter_next(iter)
190 if model.get_value(iter, 0) in indexes:
191 model.remove(iter)
192 else:
193 model.set_value(iter, 0, idx)
194 idx += 1
195 iter = nextIter
196
197 def _getIndexForPath(self, path):
198 """Get the index for the given path."""
199 iter = self._model.get_iter(path)
200 return self._model.get_value(iter, 0)
201
202 def _rowActivated(self, flightList, path, column):
203 """Called when a row is selected."""
204 self.emit("row-activated", self._getIndexForPath(path))
205
206 def _buttonPressEvent(self, widget, event):
207 """Called when a mouse button is pressed or released."""
208 if event.type!=Gdk.EventType.BUTTON_PRESS or event.button!=3 or \
209 self._popupMenuProducer is None:
210 return
211
212 (path, _, _, _) = self._view.get_path_at_pos(int(event.x),
213 int(event.y))
214 selection = self._view.get_selection()
215 selection.unselect_all()
216 selection.select_path(path)
217
218 if self._popupMenu is None:
219 self._popupMenu = self._popupMenuProducer()
220 menu = self._popupMenu
221 menu.popup(None, None, None, None, event.button, event.time)
222
223 def _selectionChanged(self, selection):
224 """Called when the selection has changed."""
225 self.emit("selection-changed", self.selectedIndexes)
226
227#-------------------------------------------------------------------------------
228
229GObject.signal_new("row-activated", FlightList, GObject.SIGNAL_RUN_FIRST,
230 None, (int,))
231
232GObject.signal_new("selection-changed", FlightList, GObject.SIGNAL_RUN_FIRST,
233 None, (object,))
234
235#-----------------------------------------------------------------------------
236
237class PendingFlightsFrame(Gtk.Frame):
238 """A frame for a list of pending (reported or rejected) flights.
239
240 It contains the list and the buttons available."""
241 @staticmethod
242 def getAircraft(tailNumber, bookedFlight):
243 """Get the aircraft from the given booked flight.
244
245 This is the tail number followed by the ICAO code of the aircraft's
246 type."""
247 return tailNumber + \
248 " (" + const.icaoCodes[bookedFlight.aircraftType] + ")"
249
250 def _getAcft(tailNumber, bookedFlight):
251 return PendingFlightsFrame.getAircraft(tailNumber, bookedFlight)
252
253 columnDescriptors = [
254 ColumnDescriptor("callsign", xstr("flightsel_no")),
255 ColumnDescriptor("departureTime", xstr("flightsel_deptime"),
256 sortable = True, defaultSortable = True),
257 ColumnDescriptor("departureICAO", xstr("flightsel_from"),
258 sortable = True),
259 ColumnDescriptor("arrivalICAO", xstr("flightsel_to"),
260 sortable = True),
261 ColumnDescriptor("tailNumber", xstr("pendflt_acft"),
262 convertFn = _getAcft)
263 ]
264
265 def __init__(self, which, wizard, window, pirepEditable = False):
266 """Construct the frame with the given title."""
267 super(PendingFlightsFrame, self).__init__()
268 self.set_label(xstr("pendflt_title_" + which))
269
270 self._which = which
271 self._wizard = wizard
272 self._window = window
273 self._pirepEditable = pirepEditable
274
275 alignment = Gtk.Alignment(xscale = 1.0, yscale = 1.0)
276 alignment.set_padding(padding_top = 2, padding_bottom = 8,
277 padding_left = 4, padding_right = 4)
278
279 hbox = Gtk.HBox()
280
281 self._flights = []
282 self._flightList = FlightList(columnDescriptors =
283 PendingFlightsFrame.columnDescriptors,
284 widthRequest = 500, multiSelection = True,
285 popupMenuProducer =
286 self._producePopupMenu)
287 self._flightList.connect("selection-changed", self._selectionChanged)
288
289 hbox.pack_start(self._flightList, True, True, 4)
290
291 buttonBox = Gtk.VBox()
292
293 self._editButton = Gtk.Button(xstr("pendflt_" +
294 ("edit" if pirepEditable else
295 "view") + "_" + which))
296 self._editButton.set_sensitive(False)
297 self._editButton.set_use_underline(True)
298 self._editButton.connect("clicked", self._editClicked)
299 buttonBox.pack_start(self._editButton, False, False, 2)
300
301 self._reflyButton = Gtk.Button(xstr("pendflt_refly_" + which))
302 self._reflyButton.set_sensitive(False)
303 self._reflyButton.set_use_underline(True)
304 self._reflyButton.connect("clicked", self._reflyClicked)
305 buttonBox.pack_start(self._reflyButton, False, False, 2)
306
307 self._deleteButton = Gtk.Button(xstr("pendflt_delete_" + which))
308 self._deleteButton.set_sensitive(False)
309 self._deleteButton.set_use_underline(True)
310 self._deleteButton.connect("clicked", self._deleteClicked)
311 buttonBox.pack_start(self._deleteButton, False, False, 2)
312
313 hbox.pack_start(buttonBox, False, False, 4)
314
315 alignment.add(hbox)
316 self.add(alignment)
317
318 @property
319 def hasFlights(self):
320 """Determine if there are any flights in the list."""
321 return self._flightList.hasFlights
322
323 def clear(self):
324 """Clear the lists."""
325 self._flights = []
326 self._flightList.clear()
327
328 def addFlight(self, flight):
329 """Add a flight to the list."""
330 self._flights.append(flight)
331 self._flightList.addFlight(flight)
332
333 def _selectionChanged(self, flightList, selectedIndexes):
334 """Called when the selection in the list has changed."""
335 self._editButton.set_sensitive(len(selectedIndexes)==1)
336 self._reflyButton.set_sensitive(len(selectedIndexes)>0)
337 self._deleteButton.set_sensitive(len(selectedIndexes)>0)
338
339 def _editClicked(self, button):
340 """Called when the Edit button is clicked."""
341 self._editSelected()
342
343 def _editSelected(self):
344 """Edit or view the selected flight."""
345 gui = self._wizard.gui
346 gui.beginBusy(xstr("pendflt_pirep_busy"))
347 self.set_sensitive(False)
348
349 indexes = self._flightList.selectedIndexes
350 assert(len(indexes)==1)
351
352 flightID = self._flights[indexes[0]].id
353 gui.webHandler.getPIREP(self._pirepResultCallback, flightID)
354
355 def _pirepResultCallback(self, returned, result):
356 """Called when the PIREP query result is available."""
357 GObject.idle_add(self._handlePIREPResult, returned, result)
358
359 def _handlePIREPResult(self, returned, result):
360 """Handle the refly result."""
361
362 self.set_sensitive(True)
363 gui = self._wizard.gui
364 gui.endBusy()
365
366 if returned:
367 if self._pirepEditable:
368 gui.editPIREP(result.pirep)
369 else:
370 gui.viewMessagedPIREP(result.pirep)
371
372 def _reflyClicked(self, button):
373 """Called when the Refly button is clicked."""
374 self._reflySelected()
375
376 def _reflySelected(self):
377 """Mark the selected flight(s) to refly."""
378 if askYesNo(xstr("pendflt_refly_question"), parent = self._window):
379 gui = self._wizard.gui
380 gui.beginBusy(xstr("pendflt_refly_busy"))
381 self.set_sensitive(False)
382
383 flightIDs = [self._flights[i].id
384 for i in self._flightList.selectedIndexes]
385 gui.webHandler.reflyFlights(self._reflyResultCallback, flightIDs)
386
387 def _reflyResultCallback(self, returned, result):
388 """Called when the refly result is available."""
389 GObject.idle_add(self._handleReflyResult, returned, result)
390
391 def _handleReflyResult(self, returned, result):
392 """Handle the refly result."""
393
394 self.set_sensitive(True)
395 gui = self._wizard.gui
396 gui.endBusy()
397
398 print("PendingFlightsFrame._handleReflyResult", returned, result)
399
400 if returned:
401 indexes = self._flightList.selectedIndexes
402
403 flights = [self._flights[index] for index in indexes]
404
405 self._flightList.removeFlights(indexes)
406 for index in indexes[::-1]:
407 del self._flights[index]
408
409 for flight in flights:
410 self._wizard.reflyFlight(flight)
411 self._window.checkFlights()
412 else:
413 communicationErrorDialog()
414
415 def _deleteClicked(self, button):
416 """Called when the Delete button is clicked."""
417 self._deleteSelected()
418
419 def _deleteSelected(self):
420 """Delete the selected flight."""
421 if askYesNo(xstr("flight_delete_question"), parent = self._window):
422 gui = self._wizard.gui
423 gui.beginBusy(xstr("pendflt_refly_busy"))
424 self.set_sensitive(False)
425
426 flightIDs = [self._flights[i].id
427 for i in self._flightList.selectedIndexes]
428 gui.webHandler.deleteFlights(self._deleteResultCallback, flightIDs)
429
430 def _deleteResultCallback(self, returned, result):
431 """Called when the deletion result is available."""
432 GObject.idle_add(self._handleDeleteResult, returned, result)
433
434 def _handleDeleteResult(self, returned, result):
435 """Handle the delete result."""
436
437 self.set_sensitive(True)
438 gui = self._wizard.gui
439 gui.endBusy()
440
441 print("PendingFlightsFrame._handleDeleteResult", returned, result)
442
443 if returned:
444 indexes = self._flightList.selectedIndexes
445
446 flights = [self._flights[index] for index in indexes]
447
448 self._flightList.removeFlights(indexes)
449 for index in indexes[::-1]:
450 del self._flights[index]
451
452 for flight in flights:
453 self._wizard.deleteFlight(flight)
454 self._window.checkFlights()
455 else:
456 communicationErrorDialog()
457
458 def _producePopupMenu(self):
459 """Create the popup menu for the flights."""
460 menu = Gtk.Menu()
461
462 menuItem = Gtk.MenuItem()
463 menuItem.set_label(xstr("pendflt_" +
464 ("edit" if self._pirepEditable else "view") +
465 "_" + self._which))
466 menuItem.set_use_underline(True)
467 menuItem.connect("activate", self._popupEdit)
468 menuItem.show()
469
470 menu.append(menuItem)
471
472 menuItem = Gtk.MenuItem()
473 menuItem.set_label(xstr("pendflt_refly_" + self._which))
474 menuItem.set_use_underline(True)
475 menuItem.connect("activate", self._popupRefly)
476 menuItem.show()
477
478 menu.append(menuItem)
479
480 menuItem = Gtk.MenuItem()
481 menuItem.set_label(xstr("pendflt_delete_" + self._which))
482 menuItem.set_use_underline(True)
483 menuItem.connect("activate", self._popupDelete)
484 menuItem.show()
485
486 menu.append(menuItem)
487
488 return menu
489
490 def _popupEdit(self, menuitem):
491 """Called when the Edit or View menu item is selected from the popup
492 menu."""
493 self._editSelected()
494
495 def _popupRefly(self, menuitem):
496 """Called when the Refly menu item is selected from the popup menu."""
497 self._reflySelected()
498
499 def _popupDelete(self, menuitem):
500 """Called when the Delete menu item is selected from the popup menu."""
501 self._deleteSelected()
502
503#-----------------------------------------------------------------------------
504
505class PendingFlightsWindow(Gtk.Window):
506 """The window to display the lists of the pending (reported or rejected)
507 flights."""
508 def __init__(self, wizard):
509 """Construct the window"""
510 super(PendingFlightsWindow, self).__init__()
511
512 gui = wizard.gui
513
514 self.set_title(WINDOW_TITLE_BASE + " - " + xstr("pendflt_title"))
515 self.set_size_request(-1, 450)
516 self.set_transient_for(gui.mainWindow)
517 self.set_modal(True)
518
519 mainAlignment = Gtk.Alignment(xalign = 0.5, yalign = 0.5,
520 xscale = 1.0, yscale = 1.0)
521 mainAlignment.set_padding(padding_top = 0, padding_bottom = 12,
522 padding_left = 8, padding_right = 8)
523
524 vbox = Gtk.VBox()
525
526 self._reportedFrame = PendingFlightsFrame("reported", wizard, self,
527 True)
528 vbox.pack_start(self._reportedFrame, True, True, 2)
529
530 self._rejectedFrame = PendingFlightsFrame("rejected", wizard, self)
531 vbox.pack_start(self._rejectedFrame, True, True, 2)
532
533 alignment = Gtk.Alignment(xalign = 0.5, yalign = 0.5,
534 xscale = 0.0, yscale = 0.0)
535 self._closeButton = Gtk.Button(xstr("button_ok"))
536 self._closeButton.connect("clicked", self._closeClicked)
537 self._closeButton.set_use_underline(True)
538 alignment.add(self._closeButton)
539 vbox.pack_start(alignment, False, False, 2)
540
541 mainAlignment.add(vbox)
542
543 self.add(mainAlignment)
544
545 self.connect("key-press-event", self._keyPressed)
546
547 @property
548 def hasFlights(self):
549 """Determine if the window has any flights."""
550 return self._reportedFrame.hasFlights or self._rejectedFrame.hasFlights
551
552 def clear(self):
553 """Clear the lists."""
554 self._reportedFrame.clear()
555 self._rejectedFrame.clear()
556
557 def addReportedFlight(self, flight):
558 """Add a reported flight."""
559 self._reportedFrame.addFlight(flight)
560
561 def addRejectedFlight(self, flight):
562 """Add a rejected flight."""
563 self._rejectedFrame.addFlight(flight)
564
565 def checkFlights(self):
566 """Check if there are any flights in any of the lists, and close the
567 window if not."""
568 if not self.hasFlights:
569 self.emit("delete-event", None)
570
571 def _closeClicked(self, button):
572 """Called when the Close button is clicked.
573
574 A 'delete-event' is emitted to close the window."""
575 self.emit("delete-event", None)
576
577 def _keyPressed(self, window, event):
578 """Called when a key is pressed in the window.
579
580 If the Escape key is pressed, 'delete-event' is emitted to close the
581 window."""
582 if Gdk.keyval_name(event.keyval) == "Escape":
583 self.emit("delete-event", None)
584 return True
585
586#-----------------------------------------------------------------------------
587
588class AcceptedFlightsWindow(Gtk.Window):
589 """A window for a list of accepted flights."""
590 def getFlightDuration(flightTimeStart, flight):
591 """Get the flight duration for the given flight."""
592 minutes = int(round((flight.flightTimeEnd - flightTimeStart)/60.0))
593 return "%02d:%02d" % (minutes/60, minutes%60)
594
595 columnDescriptors = [
596 ColumnDescriptor("bookedFlight.callsign", xstr("flightsel_no")),
597 ColumnDescriptor("bookedFlight.departureTime", xstr("flightsel_deptime"),
598 sortable = True, defaultSortable = True,
599 defaultDescending = True),
600 ColumnDescriptor("bookedFlight.departureICAO", xstr("flightsel_from"),
601 sortable = True),
602 ColumnDescriptor("bookedFlight.arrivalICAO", xstr("flightsel_to"),
603 sortable = True),
604 ColumnDescriptor("bookedFlight.tailNumber", xstr("pendflt_acft"),
605 convertFn = lambda value, flight:
606 PendingFlightsFrame.getAircraft(value,
607 flight.bookedFlight)),
608 ColumnDescriptor("flightTimeStart", xstr("acceptedflt_flight_duration"),
609 convertFn = getFlightDuration, sortable = True,
610 extraColumnAttributes =
611 { "alignment": 0.5 } ),
612 ColumnDescriptor("totalNumPassengers", xstr("acceptedflt_num_pax"),
613 type = int, sortable = True,
614 extraColumnAttributes =
615 { "alignment": 1.0 } ),
616 ColumnDescriptor("fuelUsed", xstr("acceptedflt_fuel"),
617 type = int, sortable = True,
618 extraColumnAttributes =
619 { "alignment": 1.0 } ),
620 ColumnDescriptor("rating", xstr("acceptedflt_rating"),
621 type = float, sortable = True,
622 extraColumnAttributes =
623 { "alignment": 1.0 },
624 cellDataFn = lambda col, cell, model, iter, data:
625 cell.set_property("text",
626 "%.0f" %
627 (model.get(iter, 9)[0],)))
628 ]
629
630 def __init__(self, gui):
631 """Construct the window."""
632 super(AcceptedFlightsWindow, self).__init__()
633
634 self._gui = gui
635
636 self.set_title(WINDOW_TITLE_BASE + " - " + xstr("acceptedflt_title"))
637 self.set_size_request(-1, 700)
638 self.set_transient_for(gui.mainWindow)
639
640 alignment = Gtk.Alignment(xscale = 1.0, yscale = 1.0)
641 alignment.set_padding(padding_top = 2, padding_bottom = 8,
642 padding_left = 4, padding_right = 4)
643
644 vbox = Gtk.VBox()
645
646 hbox = Gtk.HBox()
647 vbox.pack_start(hbox, True, True, 4)
648
649 self._flights = []
650 self._flightList = FlightList(columnDescriptors =
651 AcceptedFlightsWindow.columnDescriptors,
652 widthRequest = 750,
653 multiSelection = False)
654 self._flightList.connect("selection-changed", self._selectionChanged)
655 self._flightList.connect("row-activated", self._rowActivated)
656
657 hbox.pack_start(self._flightList, True, True, 4)
658
659 buttonBox = Gtk.VBox()
660
661 self._refreshButton = Gtk.Button(xstr("acceptedflt_refresh"))
662 self._refreshButton.set_sensitive(True)
663 self._refreshButton.set_use_underline(True)
664 self._refreshButton.connect("clicked", self._refreshClicked)
665 buttonBox.pack_start(self._refreshButton, False, False, 2)
666
667 filler = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
668 xscale = 1.0, yscale = 1.0)
669 filler.set_size_request(-1, 4)
670 buttonBox.pack_start(filler, False, False, 0)
671
672 self._viewButton = Gtk.Button(xstr("acceptedflt_view"))
673 self._viewButton.set_sensitive(False)
674 self._viewButton.set_use_underline(True)
675 self._viewButton.connect("clicked", self._viewClicked)
676 buttonBox.pack_start(self._viewButton, False, False, 2)
677
678 hbox.pack_start(buttonBox, False, False, 4)
679
680 buttonAlignment = Gtk.Alignment(xscale = 0.0, yscale = 0.0,
681 xalign = 0.5, yalign = 0.5)
682
683 self._closeButton = Gtk.Button(xstr("button_ok"))
684 self._closeButton.connect("clicked", self._closeClicked)
685 self._closeButton.set_use_underline(True)
686
687 buttonAlignment.add(self._closeButton)
688 vbox.pack_start(buttonAlignment, False, False, 2)
689
690 alignment.add(vbox)
691
692 self.add(alignment)
693
694 self.connect("key-press-event", self._keyPressed)
695
696 @property
697 def hasFlights(self):
698 """Determine if there are any flights that we know of."""
699 return len(self._flights)>0
700
701 def clear(self):
702 """Clear the flight list."""
703 self._flights = []
704 self._flightList.clear()
705
706 def addFlight(self, flight):
707 """Add the given flight."""
708 self._flights.append(flight)
709 self._flightList.addFlight(flight)
710
711 def _selectionChanged(self, flightList, selectedIndexes):
712 """Called when the selection has changed."""
713 self._viewButton.set_sensitive(len(selectedIndexes)==1)
714
715 def _rowActivated(self, timetable, index):
716 """Called when a row has been activated (e.g. double-clicked) in the
717 flight list."""
718 self._viewSelected()
719
720 def _refreshClicked(self, button):
721 """Called when the refresh button has been clicked."""
722 self.clear()
723 self._gui.showFlights(None)
724
725 def _viewClicked(self, button):
726 """Called when the view button has been clicked."""
727 self._viewSelected()
728
729 def _viewSelected(self):
730 """View the selected flight."""
731 gui = self._gui
732 gui.beginBusy(xstr("pendflt_pirep_busy"))
733 self.set_sensitive(False)
734
735 indexes = self._flightList.selectedIndexes
736 assert(len(indexes)==1)
737
738 flightID = self._flights[indexes[0]].bookedFlight.id
739 gui.webHandler.getPIREP(self._pirepResultCallback, flightID)
740
741 def _pirepResultCallback(self, returned, result):
742 """Called when the PIREP query result is available."""
743 GObject.idle_add(self._handlePIREPResult, returned, result)
744
745 def _handlePIREPResult(self, returned, result):
746 """Handle the refly result."""
747 self.set_sensitive(True)
748 gui = self._gui
749 gui.endBusy()
750
751 if returned:
752 gui.viewMessagedPIREP(result.pirep)
753
754 def _closeClicked(self, button):
755 """Called when the Close button is clicked.
756
757 A 'delete-event' is emitted to close the window."""
758 self.emit("delete-event", None)
759
760 def _keyPressed(self, window, event):
761 """Called when a key is pressed in the window.
762
763 If the Escape key is pressed, 'delete-event' is emitted to close the
764 window."""
765 if Gdk.keyval_name(event.keyval) == "Escape":
766 self.emit("delete-event", None)
767 return True
768
769#-----------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.