source: src/mlx/gui/flightlist.py@ 868:15ff07dedf9a

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

A double click in the accepted flights list views the selected flight (re #307)

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