Changeset 859:1e789c934953 for src/mlx/gui/timetable.py
- Timestamp:
- 06/18/17 11:17:51 (7 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/mlx/gui/timetable.py
r858 r859 5 5 from mlx.gui.common import * 6 6 from flightlist import ColumnDescriptor 7 from mlx.rpc import ScheduledFlight 7 8 8 9 import mlx.const as const 9 10 10 11 import datetime 12 import random 11 13 12 14 #----------------------------------------------------------------------------- … … 38 40 "%02d:%02d" % (duration/3600, 39 41 (duration%3600)/60)), 40 ColumnDescriptor(" spec", xstr("timetable_vip"), type = bool,42 ColumnDescriptor("type", xstr("timetable_vip"), type = bool, 41 43 renderer = _getVIPRenderer(), 42 44 sortable = True, 43 convertFn = lambda spec, flight: spec==1) 45 convertFn = lambda type, flight: 46 type==ScheduledFlight.TYPE_VIP) 44 47 ] 48 49 columnOrdering = ["callsign", "aircraftType", 50 "date", "departureTime", "arrivalTime", 51 "departureICAO", "arrivalICAO", "duration", "type"] 45 52 46 53 @staticmethod … … 48 55 """Determine if the given flight is selected by the given 49 56 filtering conditions.""" 50 return ((regularEnabled and flight. spec==0) or \51 (vipEnabled and flight. spec==1)) and \57 return ((regularEnabled and flight.type==ScheduledFlight.TYPE_NORMAL) or \ 58 (vipEnabled and flight.type==ScheduledFlight.TYPE_VIP)) and \ 52 59 flight.aircraftType in aircraftTypes 53 60 … … 75 82 self._view = gtk.TreeView(self._model) 76 83 84 self._tooltips = gtk.Tooltips() 85 self._tooltips.disable() 86 self._view.connect("motion-notify-event", self._updateTooltip) 87 77 88 flightPairIndexColumn = gtk.TreeViewColumn() 78 89 flightPairIndexColumn.set_visible(False) … … 83 94 column = columnDescriptor.getViewColumn(index) 84 95 self._view.append_column(column) 96 self._model.set_sort_func(index, self._compareFlights, 97 columnDescriptor.attribute) 85 98 index += 1 86 99 … … 110 123 111 124 @property 125 def selectedIndexes(self): 126 """Get the indexes of the selected entries, if any. 127 128 The indexes are sorted.""" 129 selection = self._view.get_selection() 130 (model, rows) = selection.get_selected_rows() 131 132 indexes = [self._getIndexForPath(path) for path in rows] 133 indexes.sort() 134 return indexes 135 136 @property 112 137 def hasFlightPairs(self): 113 138 """Determine if the timetable contains any flights.""" … … 125 150 126 151 self._flightPairs = flightPairs 152 153 def getFlightPair(self, index): 154 """Get the flight pair with the given index.""" 155 return self._flightPairs[index] 127 156 128 157 def updateList(self, regularEnabled, vipEnabled, types): … … 140 169 index += 1 141 170 171 def _getIndexForPath(self, path): 172 """Get the index for the given path.""" 173 iter = self._model.get_iter(path) 174 return self._model.get_value(iter, 0) 175 142 176 def _rowActivated(self, flightList, path, column): 143 177 """Called when a row is selected.""" 144 print "_rowActivated"178 self.emit("row-activated", self._getIndexForPath(path)) 145 179 146 180 def _buttonPressEvent(self, widget, event): 147 181 """Called when a mouse button is pressed or released.""" 148 print "_buttonPressEvent", event 182 if event.type!=EVENT_BUTTON_PRESS or event.button!=3 or \ 183 self._popupMenuProducer is None: 184 return 185 186 (path, _, _, _) = self._view.get_path_at_pos(int(event.x), 187 int(event.y)) 188 selection = self._view.get_selection() 189 selection.unselect_all() 190 selection.select_path(path) 191 192 if self._popupMenu is None: 193 self._popupMenu = self._popupMenuProducer() 194 menu = self._popupMenu 195 if pygobject: 196 menu.popup(None, None, None, None, event.button, event.time) 197 else: 198 menu.popup(None, None, None, event.button, event.time) 149 199 150 200 def _selectionChanged(self, selection): 151 201 """Called when the selection has changed.""" 152 print "_selectionChanged" 202 self.emit("selection-changed", self.selectedIndexes) 203 204 def _compareFlights(self, model, iter1, iter2, mainColumn): 205 """Compare the flights at the given iterators according to the given 206 main column.""" 207 index1 = self._model.get_value(iter1, 0) 208 index2 = self._model.get_value(iter2, 0) 209 210 flightPair1 = self._flightPairs[index1] 211 flightPair2 = self._flightPairs[index2] 212 213 result = flightPair1.compareBy(flightPair2, mainColumn) 214 if result==0: 215 for column in Timetable.columnOrdering: 216 if column!=mainColumn: 217 result = flightPair1.compareBy(flightPair2, column) 218 if result!=0: 219 break 220 return result 221 222 def _updateTooltip(self, widget, event): 223 """Update the tooltip for the position of the given event.""" 224 try: 225 (path, col, x, y) = widget.get_path_at_pos( int(event.x), int(event.y)) 226 index = self._getIndexForPath(path) 227 228 flight = self._flightPairs[index].flight0 229 comment = flight.comment 230 date = flight.date 231 232 if comment or date!=const.defaultDate: 233 text = "" 234 if comment: 235 text = comment 236 if date!=const.defaultDate: 237 if text: 238 text += "; " 239 text += date.strftime("%Y-%m-%d") 240 241 self._tooltips.set_tip(widget, text) 242 self._tooltips.enable() 243 else: 244 self._tooltips.set_tip(widget, "") 245 self._tooltips.disable() 246 except Exception, e: 247 print e 248 self._tooltips.set_tip(widget, "") 249 self._tooltips.disable() 153 250 154 251 #----------------------------------------------------------------------------- … … 207 304 #----------------------------------------------------------------------------- 208 305 306 class BookDialog(gtk.Dialog): 307 """The dialog box to select additional data for a booking.""" 308 def __init__(self, timetableWindow, flightPair, planes): 309 """Construct the dialog box.""" 310 super(BookDialog, self).__init__(title = WINDOW_TITLE_BASE + 311 " - " + 312 xstr("timetable_book_title"), 313 parent = timetableWindow) 314 contentArea = self.get_content_area() 315 316 frame = gtk.Frame(xstr("timetable_book_frame_title")) 317 frame.set_size_request(600, -1) 318 319 mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5, 320 xscale = 0.0, yscale = 0.0) 321 mainAlignment.set_padding(padding_top = 16, padding_bottom = 12, 322 padding_left = 8, padding_right = 8) 323 324 table = gtk.Table(6, 2) 325 table.set_row_spacings(8) 326 table.set_col_spacings(16) 327 328 row = 0 329 label = gtk.Label() 330 label.set_markup(xstr("timetable_book_callsign")) 331 label.set_alignment(0.0, 0.5) 332 table.attach(label, 0, 1, row, row + 1) 333 334 text = flightPair.flight0.callsign 335 if flightPair.flight1 is not None: 336 text += " / " + flightPair.flight1.callsign 337 label = gtk.Label(text) 338 label.set_alignment(0.0, 0.5) 339 table.attach(label, 1, 2, row, row + 1) 340 341 row += 1 342 343 label = gtk.Label() 344 label.set_markup(xstr("timetable_book_from_to")) 345 label.set_alignment(0.0, 0.5) 346 table.attach(label, 0, 1, row, row + 1) 347 348 text = flightPair.flight0.departureICAO + " - " + \ 349 flightPair.flight0.arrivalICAO 350 if flightPair.flight1 is not None: 351 text += " - " + flightPair.flight1.arrivalICAO 352 label = gtk.Label(text) 353 label.set_alignment(0.0, 0.5) 354 table.attach(label, 1, 2, row, row + 1) 355 356 row += 1 357 358 if flightPair.flight0.type==ScheduledFlight.TYPE_VIP and \ 359 flightPair.flight0.date!=const.defaultDate: 360 label = gtk.Label() 361 label.set_markup(xstr("timetable_book_flightDate")) 362 label.set_use_underline(True) 363 label.set_alignment(0.0, 0.5) 364 table.attach(label, 0, 1, row, row + 1) 365 366 self._flightDate = gtk.Button() 367 self._flightDate.connect("clicked", self._flightDateClicked) 368 self._flightDate.set_tooltip_text(xstr("timetable_book_flightDate_tooltip")) 369 label.set_mnemonic_widget(self._flightDate) 370 371 table.attach(self._flightDate, 1, 2, row, row + 1) 372 373 self._calendarWindow = calendarWindow = CalendarWindow() 374 calendarWindow.set_transient_for(self) 375 calendarWindow.connect("delete-event", self._calendarWindowDeleted) 376 calendarWindow.connect("date-selected", self._calendarWindowDateSelected) 377 378 self._setDate(flightPair.flight0.date) 379 380 row += 1 381 else: 382 self._flightDate = None 383 self._calendarWindow = None 384 385 label = gtk.Label() 386 label.set_markup(xstr("timetable_book_dep_arr")) 387 label.set_alignment(0.0, 0.5) 388 table.attach(label, 0, 1, row, row + 1) 389 390 text = str(flightPair.flight0.departureTime) + " - " + \ 391 str(flightPair.flight0.arrivalTime) 392 if flightPair.flight1 is not None: 393 text += " / " + str(flightPair.flight1.departureTime) + " - " + \ 394 str(flightPair.flight1.arrivalTime) 395 label = gtk.Label(text) 396 label.set_alignment(0.0, 0.5) 397 table.attach(label, 1, 2, row, row + 1) 398 399 row += 1 400 401 label = gtk.Label() 402 label.set_markup(xstr("timetable_book_duration")) 403 label.set_alignment(0.0, 0.5) 404 table.attach(label, 0, 1, row, row + 1) 405 406 407 duration = flightPair.flight0.duration 408 text = "%02d:%02d" % (duration/3600, (duration%3600)/60) 409 if flightPair.flight1 is not None: 410 duration = flightPair.flight0.duration 411 text += " / %02d:%02d" % (duration/3600, (duration%3600)/60) 412 label = gtk.Label(text) 413 label.set_alignment(0.0, 0.5) 414 table.attach(label, 1, 2, row, row + 1) 415 416 row += 2 417 418 label = gtk.Label() 419 label.set_markup(xstr("timetable_book_tailNumber")) 420 label.set_alignment(0.0, 0.5) 421 table.attach(label, 0, 1, row, row + 1) 422 423 self._planes = planes 424 tailNumbersModel = gtk.ListStore(str) 425 for plane in planes: 426 tailNumbersModel.append((plane.tailNumber,)) 427 428 self._tailNumber = gtk.ComboBox(model = tailNumbersModel) 429 renderer = gtk.CellRendererText() 430 self._tailNumber.pack_start(renderer, True) 431 self._tailNumber.add_attribute(renderer, "text", 0) 432 self._tailNumber.set_tooltip_text(xstr("timetable_book_tailNumber_tooltip")) 433 self._tailNumber.set_active(random.randint(0, len(planes)-1)) 434 435 table.attach(self._tailNumber, 1, 2, row, row + 1) 436 437 mainAlignment.add(table) 438 439 frame.add(mainAlignment) 440 contentArea.pack_start(frame, True, True, 4) 441 442 self.add_button(xstr("button_cancel"), RESPONSETYPE_CANCEL) 443 444 self._okButton = self.add_button(xstr("button_book"), RESPONSETYPE_OK) 445 self._okButton.set_use_underline(True) 446 self._okButton.set_can_default(True) 447 448 @property 449 def plane(self): 450 """Get the currently selected plane.""" 451 return self._planes[self._tailNumber.get_active()] 452 453 @property 454 def date(self): 455 """Get the flight date, if selected.""" 456 return None if self._calendarWindow is None \ 457 else self._calendarWindow.getDate() 458 459 def _setDate(self, date): 460 """Set the date to the given one.""" 461 self._flightDate.set_label(date.strftime("%Y-%m-%d")) 462 self._calendarWindow.setDate(date) 463 464 def _flightDateClicked(self, button): 465 """Called when the flight date button is clicked.""" 466 self._calendarWindow.set_position(gtk.WIN_POS_MOUSE) 467 self.set_focus(self._calendarWindow) 468 self._calendarWindow.show_all() 469 470 def _calendarWindowDeleted(self, window, event): 471 """Called when the flight date window is deleted.""" 472 self._calendarWindow.hide() 473 474 def _calendarWindowDateSelected(self, window): 475 """Called when the flight date window is deleted.""" 476 self._calendarWindow.hide() 477 date = window.getDate() 478 self._flightDate.set_label(date.strftime("%Y-%m-%d")) 479 480 #----------------------------------------------------------------------------- 481 209 482 class TimetableWindow(gtk.Window): 210 483 """The window to display the timetable.""" … … 255 528 256 529 self._flightDate = gtk.Button() 530 self._flightDate.connect("clicked", self._flightDateClicked) 257 531 self._flightDate.connect("clicked", self._flightDateClicked) 258 532 self._flightDate.set_tooltip_text(xstr("timetable_flightdate_tooltip")) … … 317 591 vbox.pack_start(filterAlignment, False, False, 2) 318 592 319 self._timetable = Timetable() 593 self._timetable = Timetable(popupMenuProducer = 594 self._createTimetablePopupMenu) 595 self._timetable.connect("row-activated", self._rowActivated) 596 self._timetable.connect("selection-changed", self._selectionChanged) 320 597 vbox.pack_start(self._timetable, True, True, 2) 321 598 322 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,599 alignment = gtk.Alignment(xalign = 1.0, yalign = 0.5, 323 600 xscale = 0.0, yscale = 0.0) 324 self._closeButton = gtk.Button(xstr("button_ok")) 601 buttonBox = gtk.HBox() 602 603 self._bookButton = gtk.Button(xstr("button_book")) 604 self._bookButton.set_use_underline(True) 605 self._bookButton.set_can_default(True) 606 self._bookButton.connect("clicked", self._bookClicked) 607 self._bookButton.set_sensitive(False) 608 buttonBox.pack_start(self._bookButton, False, False, 4); 609 610 self._closeButton = gtk.Button(xstr("button_close")) 611 self._closeButton.set_use_underline(True) 325 612 self._closeButton.connect("clicked", self._closeClicked) 326 alignment.add(self._closeButton) 613 buttonBox.pack_start(self._closeButton, False, False, 4); 614 615 alignment.add(buttonBox) 327 616 vbox.pack_start(alignment, False, False, 2) 328 617 … … 337 626 338 627 self.setDate(datetime.date.today()) 628 629 self._flightPairToBook = None 339 630 340 631 @property … … 423 714 self.isVIPEnabled, 424 715 aircraftTypes) 716 717 def _bookClicked(self, button): 718 """Called when the book button has been clicked.""" 719 self._book(self._timetable.getFlightPair(self._timetable.selectedIndexes[0])) 720 721 def _rowActivated(self, timetable, index): 722 """Called when a row has been activated (e.g. double-clicked) in the 723 timetable.""" 724 self._book(self._timetable.getFlightPair(index)) 725 726 def _selectionChanged(self, timetable, indexes): 727 """Called when the selection has changed. 728 729 It sets the sensitivity of the book button based on whether a row is 730 selected or not.""" 731 self._bookButton.set_sensitive(len(indexes)>0) 732 733 def _book(self, flightPair): 734 """Try to book the given flight pair.""" 735 self._flightPairToBook = flightPair 736 self._gui.getFleet(callback = self._continueBook, 737 busyCallback = self._busyCallback) 738 739 def _busyCallback(self, busy): 740 """Called when the busy state has changed.""" 741 self.set_sensitive(not busy) 742 743 def _continueBook(self, fleet): 744 """Continue booking, once the fleet is available.""" 745 flightPair = self._flightPairToBook 746 aircraftType = flightPair.flight0.aircraftType 747 planes = [plane for plane in fleet 748 if plane.aircraftType == aircraftType] 749 planes.sort(cmp = lambda p1, p2: cmp(p1.tailNumber, p2.tailNumber)) 750 751 dialog = BookDialog(self, flightPair, planes) 752 dialog.show_all() 753 result = dialog.run() 754 dialog.hide() 755 if result==RESPONSETYPE_OK: 756 flightIDs = [flightPair.flight0.id] 757 if flightPair.flight1 is not None: 758 flightIDs.append(flightPair.flight1.id) 759 760 date = dialog.date 761 if date is None: 762 date = self._calendarWindow.getDate() 763 764 self._gui.bookFlights(self._bookFlightsCallback, 765 flightIDs, date, dialog.plane.tailNumber, 766 busyCallback = self._busyCallback) 767 768 def _bookFlightsCallback(self, returned, result): 769 """Called when the booking has finished.""" 770 if returned: 771 dialog = gtk.MessageDialog(parent = self, 772 type = MESSAGETYPE_INFO, 773 message_format = xstr("bookflights_successful")) 774 dialog.format_secondary_markup(xstr("bookflights_successful_secondary")) 775 else: 776 dialog = gtk.MessageDialog(parent = self, 777 type = MESSAGETYPE_ERROR, 778 message_format = xstr("bookflights_failed")) 779 dialog.format_secondary_markup(xstr("bookflights_failed_secondary")) 780 781 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK) 782 dialog.set_title(WINDOW_TITLE_BASE) 783 784 dialog.run() 785 dialog.hide() 786 787 def _createTimetablePopupMenu(self): 788 """Get the popuop menu for the timetable.""" 789 menu = gtk.Menu() 790 791 menuItem = gtk.MenuItem() 792 menuItem.set_label(xstr("timetable_popup_book")) 793 menuItem.set_use_underline(True) 794 menuItem.connect("activate", self._popupBook) 795 menuItem.show() 796 797 menu.append(menuItem) 798 799 return menu 800 801 def _popupBook(self, menuItem): 802 """Try to book the given flight pair.""" 803 index = self._timetable.selectedIndexes[0] 804 self._book(self._timetable.getFlightPair(index))
Note:
See TracChangeset
for help on using the changeset viewer.