Changeset 854:3e7dca86c1ed for src
- Timestamp:
- 05/21/17 15:21:55 (8 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- src/mlx
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
src/mlx/gui/flight.py
r836 r854 5556 5556 if result.loggedIn: 5557 5557 self._loginResult = result 5558 self.gui.loginSuccessful() 5558 5559 else: 5559 5560 if isReload: -
src/mlx/gui/flightlist.py
r830 r854 12 12 """A descriptor for a column in the list.""" 13 13 def __init__(self, attribute, heading, type = str, 14 convertFn = None, renderer = gtk.CellRendererText(),14 convertFn = None, renderer = None, 15 15 extraColumnAttributes = None, sortable = False, 16 defaultSortable = False): 16 defaultSortable = False, defaultDescending = False, 17 cellDataFn = None): 17 18 """Construct the descriptor.""" 18 19 self._attribute = attribute … … 20 21 self._type = type 21 22 self._convertFn = convertFn 22 self._renderer = renderer 23 self._renderer = \ 24 gtk.CellRendererText() if renderer is None else renderer 23 25 self._extraColumnAttributes = extraColumnAttributes 24 26 self._sortable = sortable 25 27 self._defaultSortable = defaultSortable 28 self._defaultDescending = defaultDescending 29 self._cellDataFn = cellDataFn 26 30 27 31 @property … … 38 42 39 43 @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._extraColumnAttributes47 48 44 column = gtk.TreeViewColumn(self._heading, self._renderer, 49 45 text = index) … … 53 49 column.set_sort_indicator(True) 54 50 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 55 61 return column 56 62 57 63 def getValueFrom(self, flight): 58 64 """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) 60 69 return self._type(value) if self._convertFn is None \ 61 70 else self._convertFn(value, flight) … … 96 105 self._model = gtk.ListStore(*types) 97 106 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) 100 111 self._view = gtk.TreeView(self._model) 101 112 … … 223 234 224 235 It contains the list and the buttons available.""" 236 @staticmethod 225 237 def getAircraft(tailNumber, bookedFlight): 226 238 """Get the aircraft from the given booked flight. … … 230 242 return tailNumber + \ 231 243 " (" + const.icaoCodes[bookedFlight.aircraftType] + ")" 244 245 def _getAcft(tailNumber, bookedFlight): 246 return PendingFlightsFrame.getAircraft(tailNumber, bookedFlight) 232 247 233 248 columnDescriptors = [ … … 240 255 sortable = True), 241 256 ColumnDescriptor("tailNumber", xstr("pendflt_acft"), 242 convertFn = getAircraft)257 convertFn = _getAcft) 243 258 ] 244 259 … … 501 516 502 517 #----------------------------------------------------------------------------- 518 519 class 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 13 13 from mlx.gui.checklist import ChecklistEditor 14 14 from mlx.gui.callouts import ApproachCalloutsEditor 15 from mlx.gui.flightlist import AcceptedFlightsWindow 15 16 from mlx.gui.pirep import PIREPViewer, PIREPEditor 16 17 from mlx.gui.bugreport import BugReportDialog … … 119 120 120 121 self._preferences = Preferences(self) 122 self._flightsWindow = AcceptedFlightsWindow(self) 123 self._flightsWindow.connect("delete-event", self._hideFlightsWindow) 121 124 self._checklistEditor = ChecklistEditor(self) 122 125 self._approachCalloutsEditor = ApproachCalloutsEditor(self) … … 1059 1062 toolsMenuItem.set_submenu(toolsMenu) 1060 1063 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) 1061 1075 1062 1076 checklistMenuItem = gtk.ImageMenuItem(gtk.STOCK_APPLY) … … 1222 1236 self._mainWindow.set_default(None) 1223 1237 1238 def loginSuccessful(self): 1239 """Called when the login is successful.""" 1240 self._flightsMenuItem.set_sensitive(True) 1241 1224 1242 def isWizardActive(self): 1225 1243 """Determine if the flight wizard is active.""" 1226 1244 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 1227 1279 1228 1280 def _editChecklist(self, menuItem): -
src/mlx/pirep.py
r839 r854 170 170 171 171 self.filedCruiseAltitude = int(pirepData["filedCruiseLevel"][2:])*100 172 cruiseLevel = pirepData["cruiseLevel"] 172 cruiseLevel = pirepData["cruiseLevel"].strip() 173 if cruiseLevel: 174 if cruiseLevel.startswith("FL"): 175 cruiseLevel = cruiseLevel[2:] 173 176 if cruiseLevel: 174 177 self.cruiseAltitude = int(cruiseLevel[2:])*100 -
src/mlx/rpc.py
r853 r854 7 7 import hashlib 8 8 import datetime 9 import calendar 10 import sys 9 11 10 12 #--------------------------------------------------------------------------------------- … … 32 34 continue 33 35 34 value = instruction(value) 36 try: 37 value = instruction(value) 38 except: 39 print >> sys.stderr, "Failed to convert value '%s' of attribute '%s':" % \ 40 (value, key) 41 import traceback 42 traceback.print_exc() 35 43 setattr(self, key, value) 36 44 … … 131 139 #--------------------------------------------------------------------------------------- 132 140 141 class AcceptedFlight(RPCObject): 142 """A flight that has been already accepted.""" 143 # The instructions for the construction 144 @staticmethod 145 def parseTimestamp(s): 146 """Parse the given RPC timestamp.""" 147 dt = datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S") 148 return calendar.timegm(dt.utctimetuple()) 149 150 _instructions = { 151 "bookedFlight" : lambda value: BookedFlight(value), 152 "numPassengers" : int, 153 "fuelUsed" : int, 154 "rating" : lambda value: float(value) if value else 0.0 155 } 156 157 def __init__(self, value): 158 """Construct the booked flight object from the given RPC result 159 value.""" 160 super(AcceptedFlight, self).__init__(value, AcceptedFlight._instructions) 161 self.flightTimeStart = \ 162 AcceptedFlight.parseTimestamp(self.flightDate + " " + 163 self.flightTimeStart) 164 self.flightTimeEnd = \ 165 AcceptedFlight.parseTimestamp(self.flightDate + " " + 166 self.flightTimeEnd) 167 if self.flightTimeEnd<self.flightTimeStart: 168 self.flightTimeEnd += 24*60*60 169 170 #--------------------------------------------------------------------------------------- 171 133 172 class Plane(rpccommon.Plane, RPCObject): 134 173 """An airplane in the fleet.""" … … 299 338 return (bookedFlights, reportedFlights, rejectedFlights) 300 339 340 def getAcceptedFlights(self): 341 """Get the flights that are already accepted.""" 342 value = self._performCall(lambda sessionID: 343 self._server.getAcceptedFlights(sessionID)) 344 flights = [] 345 for flight in value: 346 flights.append(AcceptedFlight(flight)) 347 return flights 348 301 349 def getEntryExamStatus(self): 302 350 """Get the status of the exams needed for joining MAVA.""" -
src/mlx/web.py
r853 r854 1326 1326 #------------------------------------------------------------------------------ 1327 1327 1328 class GetAcceptedFlights(RPCRequest): 1329 """Request to get the accepted flights.""" 1330 def __init__(self, client, callback): 1331 """Construct the request with the given client and callback function.""" 1332 super(GetAcceptedFlights, self).__init__(client, callback) 1333 1334 def run(self): 1335 """Perform the login request.""" 1336 result = Result() 1337 1338 result.flights = self._client.getAcceptedFlights() 1339 1340 return result 1341 1342 #------------------------------------------------------------------------------ 1343 1328 1344 class Handler(threading.Thread): 1329 1345 """The handler for the web services. … … 1419 1435 self._addRequest(DeleteFlights(self._rpcClient, callback, flightIDs)) 1420 1436 1437 def getAcceptedFlights(self, callback): 1438 """Enqueue a request to get the accepted flights.""" 1439 self._addRequest(GetAcceptedFlights(self._rpcClient, callback)) 1440 1421 1441 def run(self): 1422 1442 """Process the requests."""
Note:
See TracChangeset
for help on using the changeset viewer.