Ignore:
Timestamp:
05/21/17 15:21:55 (8 years ago)
Author:
István Váradi <ivaradi@…>
Branch:
default
Phase:
public
Message:

The accepted flights can be queried and viewed (re #307)

Location:
src/mlx/gui
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/mlx/gui/flight.py

    r836 r854  
    55565556            if result.loggedIn:
    55575557                self._loginResult = result
     5558                self.gui.loginSuccessful()
    55585559            else:
    55595560                if isReload:
  • src/mlx/gui/flightlist.py

    r830 r854  
    1212    """A descriptor for a column in the list."""
    1313    def __init__(self, attribute, heading, type = str,
    14                  convertFn = None, renderer = gtk.CellRendererText(),
     14                 convertFn = None, renderer = None,
    1515                 extraColumnAttributes = None, sortable = False,
    16                  defaultSortable = False):
     16                 defaultSortable = False, defaultDescending = False,
     17                 cellDataFn = None):
    1718        """Construct the descriptor."""
    1819        self._attribute = attribute
     
    2021        self._type = type
    2122        self._convertFn = convertFn
    22         self._renderer = renderer
     23        self._renderer = \
     24          gtk.CellRendererText() if renderer is None else renderer
    2325        self._extraColumnAttributes = extraColumnAttributes
    2426        self._sortable = sortable
    2527        self._defaultSortable = defaultSortable
     28        self._defaultDescending = defaultDescending
     29        self._cellDataFn = cellDataFn
    2630
    2731    @property
     
    3842
    3943        @param index is the 0-based index of the column."""
    40         if self._extraColumnAttributes is None:
    41             if isinstance(self._renderer, gtk.CellRendererText):
    42                 extraColumnAttributes = {"text" : index}
    43             else:
    44                 extraColumnAttributes = {}
    45         else:
    46             extraColumnAttributes = self._extraColumnAttributes
    47 
    4844        column = gtk.TreeViewColumn(self._heading, self._renderer,
    4945                                    text = index)
     
    5349            column.set_sort_indicator(True)
    5450
     51        if self._extraColumnAttributes is not None:
     52            for (key, value) in self._extraColumnAttributes.iteritems():
     53                if key=="alignment":
     54                    self._renderer.set_alignment(value, 0.5)
     55                else:
     56                    raise Exception("unhandled extra column attribute '" +
     57                                    key + "'")
     58        if self._cellDataFn is not None:
     59            column.set_cell_data_func(self._renderer, self._cellDataFn)
     60
    5561        return column
    5662
    5763    def getValueFrom(self, flight):
    5864        """Get the value from the given flight."""
    59         value = getattr(flight, self._attribute)
     65        attributes = self._attribute.split(".")
     66        value = getattr(flight, attributes[0])
     67        for attr in attributes[1:]:
     68            value = getattr(value, attr)
    6069        return self._type(value) if self._convertFn is None \
    6170            else self._convertFn(value, flight)
     
    96105        self._model = gtk.ListStore(*types)
    97106        if defaultSortableIndex is not None:
    98             self._model.set_sort_column_id(defaultSortableIndex,
    99                                            SORT_ASCENDING)
     107            sortOrder = SORT_DESCENDING \
     108              if self._columnDescriptors[defaultSortableIndex-1]._defaultDescending \
     109              else SORT_ASCENDING
     110            self._model.set_sort_column_id(defaultSortableIndex, sortOrder)
    100111        self._view = gtk.TreeView(self._model)
    101112
     
    223234
    224235    It contains the list and the buttons available."""
     236    @staticmethod
    225237    def getAircraft(tailNumber, bookedFlight):
    226238        """Get the aircraft from the given booked flight.
     
    230242        return tailNumber + \
    231243            " (" + const.icaoCodes[bookedFlight.aircraftType] + ")"
     244
     245    def _getAcft(tailNumber, bookedFlight):
     246        return PendingFlightsFrame.getAircraft(tailNumber, bookedFlight)
    232247
    233248    columnDescriptors = [
     
    240255                         sortable = True),
    241256        ColumnDescriptor("tailNumber", xstr("pendflt_acft"),
    242                          convertFn = getAircraft)
     257                         convertFn = _getAcft)
    243258    ]
    244259
     
    501516
    502517#-----------------------------------------------------------------------------
     518
     519class AcceptedFlightsWindow(gtk.Window):
     520    """A window for a list of accepted flights."""
     521    def getFlightDuration(flightTimeStart, flight):
     522        """Get the flight duration for the given flight."""
     523        minutes = int(round((flight.flightTimeEnd - flightTimeStart)/60.0))
     524        return "%02d:%02d" % (minutes/60, minutes%60)
     525
     526    columnDescriptors = [
     527        ColumnDescriptor("bookedFlight.callsign", xstr("flightsel_no")),
     528        ColumnDescriptor("bookedFlight.departureTime", xstr("flightsel_deptime"),
     529                         sortable = True, defaultSortable = True,
     530                         defaultDescending = True),
     531        ColumnDescriptor("bookedFlight.departureICAO", xstr("flightsel_from"),
     532                         sortable = True),
     533        ColumnDescriptor("bookedFlight.arrivalICAO", xstr("flightsel_to"),
     534                         sortable = True),
     535        ColumnDescriptor("bookedFlight.tailNumber", xstr("pendflt_acft"),
     536                         convertFn = lambda value, flight:
     537                         PendingFlightsFrame.getAircraft(value,
     538                                                         flight.bookedFlight)),
     539        ColumnDescriptor("flightTimeStart", xstr("acceptedflt_flight_duration"),
     540                         convertFn = getFlightDuration, sortable = True,
     541                         extraColumnAttributes =
     542                             { "alignment": 0.5 } ),
     543        ColumnDescriptor("numPassengers", xstr("acceptedflt_num_pax"),
     544                         type = int, sortable = True,
     545                         extraColumnAttributes =
     546                             { "alignment": 1.0 } ),
     547        ColumnDescriptor("fuelUsed", xstr("acceptedflt_fuel"),
     548                         type = int, sortable = True,
     549                         extraColumnAttributes =
     550                             { "alignment": 1.0 } ),
     551        ColumnDescriptor("rating", xstr("acceptedflt_rating"),
     552                         type = float, sortable = True,
     553                         extraColumnAttributes =
     554                             { "alignment": 1.0 },
     555                         cellDataFn = lambda col, cell, model, iter:
     556                             cell.set_property("text",
     557                                               "%.0f" %
     558                                               (model.get(iter, 9)[0],)))
     559    ]
     560
     561    def __init__(self, gui):
     562        """Construct the window."""
     563        super(AcceptedFlightsWindow, self).__init__()
     564
     565        self._gui = gui
     566
     567        self.set_title(WINDOW_TITLE_BASE + " - " + xstr("acceptedflt_title"))
     568        self.set_size_request(-1, 700)
     569        self.set_transient_for(gui.mainWindow)
     570
     571        alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
     572        alignment.set_padding(padding_top = 2, padding_bottom = 8,
     573                              padding_left = 4, padding_right = 4)
     574
     575        vbox = gtk.VBox()
     576
     577        hbox = gtk.HBox()
     578        vbox.pack_start(hbox, True, True, 4)
     579
     580        self._flights = []
     581        self._flightList = FlightList(columnDescriptors =
     582                                      AcceptedFlightsWindow.columnDescriptors,
     583                                      widthRequest = 750,
     584                                      multiSelection = False)
     585        self._flightList.connect("selection-changed", self._selectionChanged)
     586
     587        hbox.pack_start(self._flightList, True, True, 4)
     588
     589        buttonBox = gtk.VBox()
     590
     591        self._refreshButton = gtk.Button(xstr("acceptedflt_refresh"))
     592        self._refreshButton.set_sensitive(True)
     593        self._refreshButton.connect("clicked", self._refreshClicked)
     594        buttonBox.pack_start(self._refreshButton, False, False, 2)
     595
     596        filler = gtk.Alignment(xalign = 0.0, yalign = 0.0,
     597                               xscale = 1.0, yscale = 1.0)
     598        filler.set_size_request(-1, 4)
     599        buttonBox.pack_start(filler, False, False, 0)
     600
     601        self._viewButton = gtk.Button(xstr("acceptedflt_view"))
     602        self._viewButton.set_sensitive(False)
     603        self._viewButton.connect("clicked", self._viewClicked)
     604        buttonBox.pack_start(self._viewButton, False, False, 2)
     605
     606        hbox.pack_start(buttonBox, False, False, 4)
     607
     608        buttonAlignment = gtk.Alignment(xscale = 0.0, yscale = 0.0,
     609                                        xalign = 0.5, yalign = 0.5)
     610
     611        self._closeButton =  gtk.Button(xstr("button_ok"))
     612        self._closeButton.connect("clicked", self._closeClicked)
     613
     614        buttonAlignment.add(self._closeButton)
     615        vbox.pack_start(buttonAlignment, False, False, 2)
     616
     617        alignment.add(vbox)
     618
     619        self.add(alignment)
     620
     621        self.connect("key-press-event", self._keyPressed)
     622
     623    @property
     624    def hasFlights(self):
     625        """Determine if there are any flights that we know of."""
     626        return len(self._flights)>0
     627
     628    def clear(self):
     629        """Clear the flight list."""
     630        self._flights = []
     631        self._flightList.clear()
     632
     633    def addFlight(self, flight):
     634        """Add the given flight."""
     635        self._flights.append(flight)
     636        self._flightList.addFlight(flight)
     637
     638    def _selectionChanged(self, flightList, selectedIndexes):
     639        """Called when the selection has changed."""
     640        self._viewButton.set_sensitive(len(selectedIndexes)==1)
     641
     642    def _refreshClicked(self, button):
     643        """Called when the refresh button has been clicked."""
     644        self.clear()
     645        self._gui.showFlights(None)
     646
     647    def _viewClicked(self, button):
     648        """Called when the view button has been clicked."""
     649        gui = self._gui
     650        gui.beginBusy(xstr("pendflt_pirep_busy"))
     651        self.set_sensitive(False)
     652
     653        indexes = self._flightList.selectedIndexes
     654        assert(len(indexes)==1)
     655
     656        flightID = self._flights[indexes[0]].bookedFlight.id
     657        gui.webHandler.getPIREP(self._pirepResultCallback, flightID)
     658
     659    def _pirepResultCallback(self, returned, result):
     660        """Called when the PIREP query result is available."""
     661        gobject.idle_add(self._handlePIREPResult, returned, result)
     662
     663    def _handlePIREPResult(self, returned, result):
     664        """Handle the refly result."""
     665        self.set_sensitive(True)
     666        gui = self._gui
     667        gui.endBusy()
     668
     669        if returned:
     670            gui.viewPIREP(result.pirep)
     671
     672    def _closeClicked(self, button):
     673        """Called when the Close button is clicked.
     674
     675        A 'delete-event' is emitted to close the window."""
     676        self.emit("delete-event", None)
     677
     678    def _keyPressed(self, window, event):
     679        """Called when a key is pressed in the window.
     680
     681        If the Escape key is pressed, 'delete-event' is emitted to close the
     682        window."""
     683        if gdk.keyval_name(event.keyval) == "Escape":
     684            self.emit("delete-event", None)
     685            return True
     686
     687#-----------------------------------------------------------------------------
  • src/mlx/gui/gui.py

    r853 r854  
    1313from mlx.gui.checklist import ChecklistEditor
    1414from mlx.gui.callouts import ApproachCalloutsEditor
     15from mlx.gui.flightlist import AcceptedFlightsWindow
    1516from mlx.gui.pirep import PIREPViewer, PIREPEditor
    1617from mlx.gui.bugreport import BugReportDialog
     
    119120
    120121        self._preferences = Preferences(self)
     122        self._flightsWindow = AcceptedFlightsWindow(self)
     123        self._flightsWindow.connect("delete-event", self._hideFlightsWindow)
    121124        self._checklistEditor = ChecklistEditor(self)
    122125        self._approachCalloutsEditor = ApproachCalloutsEditor(self)
     
    10591062        toolsMenuItem.set_submenu(toolsMenu)
    10601063        menuBar.append(toolsMenuItem)
     1064
     1065        self._flightsMenuItem = flightsMenuItem = \
     1066          gtk.ImageMenuItem(gtk.STOCK_SPELL_CHECK)
     1067        flightsMenuItem.set_use_stock(True)
     1068        flightsMenuItem.set_label(xstr("menu_tools_flights"))
     1069        flightsMenuItem.add_accelerator("activate", accelGroup,
     1070                                        ord(xstr("menu_tools_flights_key")),
     1071                                        CONTROL_MASK, ACCEL_VISIBLE)
     1072        flightsMenuItem.connect("activate", self.showFlights)
     1073        self._flightsMenuItem.set_sensitive(False)
     1074        toolsMenu.append(flightsMenuItem)
    10611075
    10621076        checklistMenuItem = gtk.ImageMenuItem(gtk.STOCK_APPLY)
     
    12221236            self._mainWindow.set_default(None)
    12231237
     1238    def loginSuccessful(self):
     1239        """Called when the login is successful."""
     1240        self._flightsMenuItem.set_sensitive(True)
     1241
    12241242    def isWizardActive(self):
    12251243        """Determine if the flight wizard is active."""
    12261244        return self._notebook.get_current_page()==0
     1245
     1246    def showFlights(self, menuItem):
     1247        """Callback for showing the flight list."""
     1248        if self._flightsWindow.hasFlights:
     1249            self._flightsWindow.show_all()
     1250        else:
     1251            self.beginBusy(xstr("acceptedflt_query_busy"))
     1252            self.webHandler.getAcceptedFlights(self._acceptedFlightsCallback)
     1253
     1254    def _acceptedFlightsCallback(self, returned, result):
     1255        """Called when the accepted flights have been received."""
     1256        gobject.idle_add(self._handleAcceptedFlights, returned, result)
     1257
     1258    def _handleAcceptedFlights(self, returned, result):
     1259        """Handle the result of the query for accepted flights."""
     1260        self.endBusy()
     1261        if returned:
     1262            self._flightsWindow.clear()
     1263            for flight in result.flights:
     1264                self._flightsWindow.addFlight(flight)
     1265            self._flightsWindow.show_all()
     1266        else:
     1267            dialog = gtk.MessageDialog(parent = self.mainWindow,
     1268                                       type = MESSAGETYPE_ERROR,
     1269                                       message_format = xstr("acceptedflt_failed"))
     1270            dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
     1271            dialog.set_title(WINDOW_TITLE_BASE)
     1272            dialog.run()
     1273            dialog.hide()
     1274
     1275    def _hideFlightsWindow(self, window, event):
     1276        """Hide the window of the accepted flights."""
     1277        self._flightsWindow.hide()
     1278        return True
    12271279
    12281280    def _editChecklist(self, menuItem):
Note: See TracChangeset for help on using the changeset viewer.