source: src/mlx/gui/timetable.py@ 924:05c2338a2dc4

python3
Last change on this file since 924:05c2338a2dc4 was 923:fe2a902681bc, checked in by István Váradi <ivaradi@…>, 6 years ago

Eliminated calls to cmp() (re #347).

File size: 30.3 KB
Line 
1# Module for handling the time table and booking flights
2
3#-----------------------------------------------------------------------------
4
5from mlx.gui.common import *
6from .flightlist import ColumnDescriptor
7from mlx.rpc import ScheduledFlight
8
9import mlx.const as const
10
11import datetime
12import random
13
14#-----------------------------------------------------------------------------
15
16class Timetable(gtk.Alignment):
17 """The widget for the time table."""
18 def _getVIPRenderer():
19 """Get the renderer for the VIP column."""
20 renderer = gtk.CellRendererToggle()
21 renderer.set_activatable(True)
22 return renderer
23
24 defaultColumnDescriptors = [
25 ColumnDescriptor("callsign", xstr("timetable_no"),
26 sortable = True, defaultSortable = True),
27 ColumnDescriptor("aircraftType", xstr("timetable_type"),
28 sortable = True,
29 convertFn = lambda aircraftType, flight:
30 aircraftNames[aircraftType]),
31 ColumnDescriptor("departureICAO", xstr("timetable_from"),
32 sortable = True),
33 ColumnDescriptor("arrivalICAO", xstr("timetable_to"), sortable = True),
34 ColumnDescriptor("departureTime", xstr("timetable_dep"),
35 sortable = True),
36 ColumnDescriptor("arrivalTime", xstr("timetable_arr"), sortable = True),
37 ColumnDescriptor("duration", xstr("timetable_duration"),
38 sortable = True,
39 convertFn = lambda duration, flight:
40 "%02d:%02d" % (duration/3600,
41 (duration%3600)/60)),
42 ColumnDescriptor("type", xstr("timetable_vip"), type = bool,
43 renderer = _getVIPRenderer(),
44 sortable = True,
45 convertFn = lambda type, flight:
46 type==ScheduledFlight.TYPE_VIP)
47 ]
48
49 columnOrdering = ["callsign", "aircraftType",
50 "date", "departureTime", "arrivalTime",
51 "departureICAO", "arrivalICAO", "duration", "type"]
52
53 @staticmethod
54 def isFlightSelected(flight, regularEnabled, vipEnabled, aircraftTypes):
55 """Determine if the given flight is selected by the given
56 filtering conditions."""
57 return ((regularEnabled and flight.type==ScheduledFlight.TYPE_NORMAL) or \
58 (vipEnabled and flight.type==ScheduledFlight.TYPE_VIP)) and \
59 flight.aircraftType in aircraftTypes
60
61 def __init__(self, columnDescriptors = defaultColumnDescriptors,
62 popupMenuProducer = None):
63 """Construct the time table."""
64 # FIXME: this is very similar to flightlist.FlightList
65 self._columnDescriptors = columnDescriptors
66 self._popupMenuProducer = popupMenuProducer
67 self._popupMenu = None
68
69 types = [int]
70 defaultSortableIndex = None
71 for columnDescriptor in self._columnDescriptors:
72 if columnDescriptor.defaultSortable:
73 defaultSortableIndex = len(types)
74 columnDescriptor.appendType(types)
75
76 self._model = gtk.ListStore(*types)
77 if defaultSortableIndex is not None:
78 sortOrder = SORT_DESCENDING \
79 if self._columnDescriptors[defaultSortableIndex-1]._defaultDescending \
80 else SORT_ASCENDING
81 self._model.set_sort_column_id(defaultSortableIndex, sortOrder)
82 self._view = gtk.TreeView(self._model)
83
84 self._tooltips = gtk.Tooltips()
85 self._tooltips.disable()
86 self._view.connect("motion-notify-event", self._updateTooltip)
87
88 flightPairIndexColumn = gtk.TreeViewColumn()
89 flightPairIndexColumn.set_visible(False)
90 self._view.append_column(flightPairIndexColumn)
91
92 index = 1
93 for columnDescriptor in self._columnDescriptors:
94 column = columnDescriptor.getViewColumn(index)
95 self._view.append_column(column)
96 self._model.set_sort_func(index, self._compareFlights,
97 columnDescriptor.attribute)
98 index += 1
99
100 self._view.connect("row-activated", self._rowActivated)
101 self._view.connect("button-press-event", self._buttonPressEvent)
102
103 selection = self._view.get_selection()
104 selection.connect("changed", self._selectionChanged)
105
106 scrolledWindow = gtk.ScrolledWindow()
107 scrolledWindow.add(self._view)
108 scrolledWindow.set_size_request(800, -1)
109
110 # FIXME: these should be constants in common.py
111 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
112 else gtk.POLICY_AUTOMATIC,
113 gtk.PolicyType.AUTOMATIC if pygobject
114 else gtk.POLICY_AUTOMATIC)
115 scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
116 else gtk.SHADOW_IN)
117
118 super(Timetable, self).__init__(xalign = 0.5, yalign = 0.0,
119 xscale = 0.0, yscale = 1.0)
120 self.add(scrolledWindow)
121
122 self._flightPairs = []
123
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
137 def hasFlightPairs(self):
138 """Determine if the timetable contains any flights."""
139 return len(self._flightPairs)>0
140
141 def clear(self):
142 """Clear the flight pairs."""
143 self._model.clear()
144 self._flightPairs = []
145
146 def setFlightPairs(self, flightPairs):
147 """Setup the table contents from the given list of
148 rpc.ScheduledFlightPair objects."""
149 self.clear()
150
151 self._flightPairs = flightPairs
152
153 def getFlightPair(self, index):
154 """Get the flight pair with the given index."""
155 return self._flightPairs[index]
156
157 def updateList(self, regularEnabled, vipEnabled, types):
158 """Update the actual list according to the given filter values."""
159 index = 0
160 self._model.clear()
161 for flightPair in self._flightPairs:
162 flight = flightPair.flight0
163 if Timetable.isFlightSelected(flight, regularEnabled, vipEnabled,
164 types):
165 values = [index]
166 for columnDescriptor in self._columnDescriptors:
167 values.append(columnDescriptor.getValueFrom(flight))
168 self._model.append(values)
169 index += 1
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
176 def _rowActivated(self, flightList, path, column):
177 """Called when a row is selected."""
178 self.emit("row-activated", self._getIndexForPath(path))
179
180 def _buttonPressEvent(self, widget, event):
181 """Called when a mouse button is pressed or released."""
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)
199
200 def _selectionChanged(self, selection):
201 """Called when the selection has changed."""
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 result = widget.get_path_at_pos( int(event.x), int(event.y))
226 if result is None:
227 self._tooltips.set_tip(widget, "")
228 self._tooltips.disable()
229 else:
230 (path, col, x, y) = result
231 index = self._getIndexForPath(path)
232
233 flight = self._flightPairs[index].flight0
234 comment = flight.comment
235 date = flight.date
236
237 if comment or date!=const.defaultDate:
238 text = ""
239 if comment:
240 text = comment
241 if date!=const.defaultDate:
242 if text:
243 text += "; "
244 text += date.strftime("%Y-%m-%d")
245
246 self._tooltips.set_tip(widget, text)
247 self._tooltips.enable()
248 else:
249 self._tooltips.set_tip(widget, "")
250 self._tooltips.disable()
251 except Exception as e:
252 print(e)
253 self._tooltips.set_tip(widget, "")
254 self._tooltips.disable()
255
256#-----------------------------------------------------------------------------
257
258class CalendarWindow(gtk.Window):
259 """A window for a calendar."""
260 def __init__(self):
261 """Construct the window."""
262 super(CalendarWindow, self).__init__()
263
264 self.set_decorated(False)
265 self.set_modal(True)
266 self.connect("key-press-event", self._keyPressed)
267
268 mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
269 xscale = 1.0, yscale = 1.0)
270 #mainAlignment.set_padding(padding_top = 0, padding_bottom = 12,
271 # padding_left = 8, padding_right = 8)
272
273 self._calendar = gtk.Calendar()
274 self._calendar.connect("day-selected-double-click", self._daySelectedDoubleClick)
275 mainAlignment.add(self._calendar)
276
277 self.add(mainAlignment)
278
279 def setDate(self, date):
280 """Set the current date to the given one."""
281 self._calendar.select_month(date.month-1, date.year)
282 self._calendar.select_day(date.day)
283
284 def getDate(self):
285 """Get the currently selected date."""
286 (year, monthM1, day) = self._calendar.get_date()
287 return datetime.date(year, monthM1+1, day)
288
289 def _daySelectedDoubleClick(self, calendar):
290 """Called when a date is double clicked."""
291 self.emit("date-selected")
292
293 def _keyPressed(self, window, event):
294 """Called when a key is pressed in the window.
295
296 If the Escape key is pressed, 'delete-event' is emitted to close the
297 window."""
298 keyName = gdk.keyval_name(event.keyval)
299 if keyName =="Escape":
300 self.emit("delete-event", None)
301 return True
302 elif keyName =="Return":
303 self.emit("date-selected")
304 return True
305
306gobject.signal_new("date-selected", CalendarWindow, gobject.SIGNAL_RUN_FIRST,
307 None, ())
308
309#-----------------------------------------------------------------------------
310
311class BookDialog(gtk.Dialog):
312 """The dialog box to select additional data for a booking."""
313 def __init__(self, timetableWindow, flightPair, planes):
314 """Construct the dialog box."""
315 super(BookDialog, self).__init__(title = WINDOW_TITLE_BASE +
316 " - " +
317 xstr("timetable_book_title"),
318 parent = timetableWindow)
319 contentArea = self.get_content_area()
320
321 frame = gtk.Frame(xstr("timetable_book_frame_title"))
322 frame.set_size_request(600, -1)
323
324 mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
325 xscale = 0.0, yscale = 0.0)
326 mainAlignment.set_padding(padding_top = 16, padding_bottom = 12,
327 padding_left = 8, padding_right = 8)
328
329 table = gtk.Table(6, 2)
330 table.set_row_spacings(8)
331 table.set_col_spacings(16)
332
333 row = 0
334 label = gtk.Label()
335 label.set_markup(xstr("timetable_book_callsign"))
336 label.set_alignment(0.0, 0.5)
337 table.attach(label, 0, 1, row, row + 1)
338
339 text = flightPair.flight0.callsign
340 if flightPair.flight1 is not None:
341 text += " / " + flightPair.flight1.callsign
342 label = gtk.Label(text)
343 label.set_alignment(0.0, 0.5)
344 table.attach(label, 1, 2, row, row + 1)
345
346 row += 1
347
348 label = gtk.Label()
349 label.set_markup(xstr("timetable_book_from_to"))
350 label.set_alignment(0.0, 0.5)
351 table.attach(label, 0, 1, row, row + 1)
352
353 text = flightPair.flight0.departureICAO + " - " + \
354 flightPair.flight0.arrivalICAO
355 if flightPair.flight1 is not None:
356 text += " - " + flightPair.flight1.arrivalICAO
357 label = gtk.Label(text)
358 label.set_alignment(0.0, 0.5)
359 table.attach(label, 1, 2, row, row + 1)
360
361 row += 1
362
363 if flightPair.flight0.type==ScheduledFlight.TYPE_VIP and \
364 flightPair.flight0.date!=const.defaultDate:
365 label = gtk.Label()
366 label.set_markup(xstr("timetable_book_flightDate"))
367 label.set_use_underline(True)
368 label.set_alignment(0.0, 0.5)
369 table.attach(label, 0, 1, row, row + 1)
370
371 self._flightDate = gtk.Button()
372 self._flightDate.connect("clicked", self._flightDateClicked)
373 self._flightDate.set_tooltip_text(xstr("timetable_book_flightDate_tooltip"))
374 label.set_mnemonic_widget(self._flightDate)
375
376 table.attach(self._flightDate, 1, 2, row, row + 1)
377
378 self._calendarWindow = calendarWindow = CalendarWindow()
379 calendarWindow.set_transient_for(self)
380 calendarWindow.connect("delete-event", self._calendarWindowDeleted)
381 calendarWindow.connect("date-selected", self._calendarWindowDateSelected)
382
383 self._setDate(flightPair.flight0.date)
384
385 row += 1
386 else:
387 self._flightDate = None
388 self._calendarWindow = None
389
390 label = gtk.Label()
391 label.set_markup(xstr("timetable_book_dep_arr"))
392 label.set_alignment(0.0, 0.5)
393 table.attach(label, 0, 1, row, row + 1)
394
395 text = str(flightPair.flight0.departureTime) + " - " + \
396 str(flightPair.flight0.arrivalTime)
397 if flightPair.flight1 is not None:
398 text += " / " + str(flightPair.flight1.departureTime) + " - " + \
399 str(flightPair.flight1.arrivalTime)
400 label = gtk.Label(text)
401 label.set_alignment(0.0, 0.5)
402 table.attach(label, 1, 2, row, row + 1)
403
404 row += 1
405
406 label = gtk.Label()
407 label.set_markup(xstr("timetable_book_duration"))
408 label.set_alignment(0.0, 0.5)
409 table.attach(label, 0, 1, row, row + 1)
410
411
412 duration = flightPair.flight0.duration
413 text = "%02d:%02d" % (duration/3600, (duration%3600)/60)
414 if flightPair.flight1 is not None:
415 duration = flightPair.flight0.duration
416 text += " / %02d:%02d" % (duration/3600, (duration%3600)/60)
417 label = gtk.Label(text)
418 label.set_alignment(0.0, 0.5)
419 table.attach(label, 1, 2, row, row + 1)
420
421 row += 2
422
423 label = gtk.Label()
424 label.set_markup(xstr("timetable_book_tailNumber"))
425 label.set_alignment(0.0, 0.5)
426 table.attach(label, 0, 1, row, row + 1)
427
428 self._planes = planes
429 tailNumbersModel = gtk.ListStore(str)
430 for plane in planes:
431 tailNumbersModel.append((plane.tailNumber,))
432
433 self._tailNumber = gtk.ComboBox(model = tailNumbersModel)
434 renderer = gtk.CellRendererText()
435 self._tailNumber.pack_start(renderer, True)
436 self._tailNumber.add_attribute(renderer, "text", 0)
437 self._tailNumber.set_tooltip_text(xstr("timetable_book_tailNumber_tooltip"))
438 self._tailNumber.set_active(random.randint(0, len(planes)-1))
439
440 table.attach(self._tailNumber, 1, 2, row, row + 1)
441
442 mainAlignment.add(table)
443
444 frame.add(mainAlignment)
445 contentArea.pack_start(frame, True, True, 4)
446
447 self.add_button(xstr("button_cancel"), RESPONSETYPE_CANCEL)
448
449 self._okButton = self.add_button(xstr("button_book"), RESPONSETYPE_OK)
450 self._okButton.set_use_underline(True)
451 self._okButton.set_can_default(True)
452
453 @property
454 def plane(self):
455 """Get the currently selected plane."""
456 return self._planes[self._tailNumber.get_active()]
457
458 @property
459 def date(self):
460 """Get the flight date, if selected."""
461 return None if self._calendarWindow is None \
462 else self._calendarWindow.getDate()
463
464 def _setDate(self, date):
465 """Set the date to the given one."""
466 self._flightDate.set_label(date.strftime("%Y-%m-%d"))
467 self._calendarWindow.setDate(date)
468
469 def _flightDateClicked(self, button):
470 """Called when the flight date button is clicked."""
471 self._calendarWindow.set_position(gtk.WIN_POS_MOUSE)
472 self.set_focus(self._calendarWindow)
473 self._calendarWindow.show_all()
474
475 def _calendarWindowDeleted(self, window, event):
476 """Called when the flight date window is deleted."""
477 self._calendarWindow.hide()
478
479 def _calendarWindowDateSelected(self, window):
480 """Called when the flight date window is deleted."""
481 self._calendarWindow.hide()
482 date = window.getDate()
483 self._flightDate.set_label(date.strftime("%Y-%m-%d"))
484
485#-----------------------------------------------------------------------------
486
487class TimetableWindow(gtk.Window):
488 """The window to display the timetable."""
489 typeFamilies = [
490 const.AIRCRAFT_FAMILY_B737NG,
491 const.AIRCRAFT_FAMILY_DH8D,
492 const.AIRCRAFT_FAMILY_B767,
493
494 const.AIRCRAFT_FAMILY_B737CL,
495 const.AIRCRAFT_FAMILY_CRJ2,
496 const.AIRCRAFT_FAMILY_F70,
497
498 const.AIRCRAFT_FAMILY_T134,
499 const.AIRCRAFT_FAMILY_T154
500 ]
501
502 def __init__(self, gui):
503 super(TimetableWindow, self).__init__()
504
505 self._gui = gui
506 self.set_title(WINDOW_TITLE_BASE + " - " + xstr("timetable_title"))
507 self.set_size_request(-1, 600)
508 self.set_transient_for(gui.mainWindow)
509 self.set_modal(True)
510 self.connect("key-press-event", self._keyPressed)
511
512 mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
513 xscale = 1.0, yscale = 1.0)
514 mainAlignment.set_padding(padding_top = 0, padding_bottom = 12,
515 padding_left = 8, padding_right = 8)
516
517 vbox = gtk.VBox()
518
519 filterAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
520 xscale = 1.0, yscale = 1.0)
521
522 filterFrame = gtk.Frame(xstr("timetable_filter"))
523
524 filterVBox = gtk.VBox()
525
526 topAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
527 xscale = 0.0, yscale = 0.0)
528 topHBox = gtk.HBox()
529
530 label = gtk.Label(xstr("timetable_flightdate"))
531 label.set_use_underline(True)
532 topHBox.pack_start(label, False, False, 4)
533
534 self._flightDate = gtk.Button()
535 self._flightDate.connect("clicked", self._flightDateClicked)
536 self._flightDate.connect("clicked", self._flightDateClicked)
537 self._flightDate.set_tooltip_text(xstr("timetable_flightdate_tooltip"))
538 label.set_mnemonic_widget(self._flightDate)
539 topHBox.pack_start(self._flightDate, False, False, 4)
540
541 filler = gtk.Alignment()
542 filler.set_size_request(48, 2)
543 topHBox.pack_start(filler, False, True, 0)
544
545 self._regularFlights = gtk.CheckButton(xstr("timetable_show_regular"))
546 self._regularFlights.set_use_underline(True)
547 self._regularFlights.set_tooltip_text(xstr("timetable_show_regular_tooltip"))
548 self._regularFlights.set_active(True)
549 self._regularFlights.connect("toggled", self._filterChanged)
550 topHBox.pack_start(self._regularFlights, False, False, 8)
551
552 self._vipFlights = gtk.CheckButton(xstr("timetable_show_vip"))
553 self._vipFlights.set_use_underline(True)
554 self._vipFlights.set_tooltip_text(xstr("timetable_show_vip_tooltip"))
555 self._vipFlights.set_active(True)
556 self._vipFlights.connect("toggled", self._filterChanged)
557 topHBox.pack_start(self._vipFlights, False, False, 8)
558
559 topAlignment.add(topHBox)
560
561 filterVBox.pack_start(topAlignment, False, False, 4)
562
563 separator = gtk.HSeparator()
564 filterVBox.pack_start(separator, False, False, 4)
565
566 typeAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
567 xscale = 0.0, yscale = 0.0)
568
569 numColumns = 4
570 numRows = (len(TimetableWindow.typeFamilies)+numColumns-1)/numColumns
571
572 typeTable = gtk.Table(numRows, numColumns)
573 typeTable.set_col_spacings(8)
574 row = 0
575 column = 0
576 self._typeFamilyButtons = {}
577 for typeFamily in TimetableWindow.typeFamilies:
578 checkButton = gtk.CheckButton(aircraftFamilyNames[typeFamily])
579 checkButton.set_active(True)
580 checkButton.connect("toggled", self._filterChanged)
581 self._typeFamilyButtons[typeFamily] = checkButton
582
583 typeTable.attach(checkButton, column, column + 1, row, row+1)
584
585 column += 1
586 if column>=numColumns:
587 row += 1
588 column = 0
589
590 typeAlignment.add(typeTable)
591 filterVBox.pack_start(typeAlignment, False, False, 4)
592
593 filterFrame.add(filterVBox)
594
595 filterAlignment.add(filterFrame)
596 vbox.pack_start(filterAlignment, False, False, 2)
597
598 self._timetable = Timetable(popupMenuProducer =
599 self._createTimetablePopupMenu)
600 self._timetable.connect("row-activated", self._rowActivated)
601 self._timetable.connect("selection-changed", self._selectionChanged)
602 vbox.pack_start(self._timetable, True, True, 2)
603
604 alignment = gtk.Alignment(xalign = 1.0, yalign = 0.5,
605 xscale = 0.0, yscale = 0.0)
606 buttonBox = gtk.HBox()
607
608 self._bookButton = gtk.Button(xstr("button_book"))
609 self._bookButton.set_use_underline(True)
610 self._bookButton.set_can_default(True)
611 self._bookButton.connect("clicked", self._bookClicked)
612 self._bookButton.set_sensitive(False)
613 buttonBox.pack_start(self._bookButton, False, False, 4);
614
615 self._closeButton = gtk.Button(xstr("button_close"))
616 self._closeButton.set_use_underline(True)
617 self._closeButton.connect("clicked", self._closeClicked)
618 buttonBox.pack_start(self._closeButton, False, False, 4);
619
620 alignment.add(buttonBox)
621 vbox.pack_start(alignment, False, False, 2)
622
623 mainAlignment.add(vbox)
624
625 self._calendarWindow = calendarWindow = CalendarWindow()
626 calendarWindow.set_transient_for(self)
627 calendarWindow.connect("delete-event", self._calendarWindowDeleted)
628 calendarWindow.connect("date-selected", self._calendarWindowDateSelected)
629
630 self.add(mainAlignment)
631
632 self.setDate(datetime.date.today())
633
634 self._flightPairToBook = None
635
636 @property
637 def hasFlightPairs(self):
638 """Determine if there any flight pairs displayed in the window."""
639 return self._timetable.hasFlightPairs
640
641 @property
642 def isRegularEnabled(self):
643 """Determine if regular flights are enabled."""
644 return self._regularFlights.get_active()!=0
645
646 @property
647 def isVIPEnabled(self):
648 """Determine if VIP flights are enabled."""
649 return self._vipFlights.get_active()!=0
650
651 def setTypes(self, aircraftTypes):
652 """Enable/disable the type family checkboxes according to the given
653 list of types."""
654 typeFamilies = set()
655 for aircraftType in aircraftTypes:
656 typeFamilies.add(const.aircraftType2Family(aircraftType))
657
658 for (typeFamily, checkButton) in self._typeFamilyButtons.items():
659 checkButton.set_sensitive(typeFamily in typeFamilies)
660
661 def clear(self):
662 """Clear all flight pairs."""
663 self._timetable.clear()
664
665 def setFlightPairs(self, flightPairs):
666 """Set the flight pairs."""
667 self._timetable.setFlightPairs(flightPairs)
668 self._updateList()
669
670 def setDate(self, date):
671 """Set the date to the given one."""
672 self._flightDate.set_label(date.strftime("%Y-%m-%d"))
673 self._calendarWindow.setDate(date)
674
675 def _closeClicked(self, button):
676 """Called when the Close button is clicked.
677
678 A 'delete-event' is emitted to close the window."""
679 self.emit("delete-event", None)
680
681 def _flightDateClicked(self, button):
682 """Called when the flight date button is clicked."""
683 self._calendarWindow.set_position(gtk.WIN_POS_MOUSE)
684 self.set_focus(self._calendarWindow)
685 self._calendarWindow.show_all()
686
687 def _calendarWindowDeleted(self, window, event):
688 """Called when the flight date window is deleted."""
689 self._calendarWindow.hide()
690
691 def _calendarWindowDateSelected(self, window):
692 """Called when the flight date window is deleted."""
693 self._calendarWindow.hide()
694 date = window.getDate()
695 self._flightDate.set_label(date.strftime("%Y-%m-%d"))
696 self._gui.updateTimeTable(date)
697
698 def _filterChanged(self, checkButton):
699 """Called when the filter conditions have changed."""
700 self._updateList()
701
702 def _keyPressed(self, window, event):
703 """Called when a key is pressed in the window.
704
705 If the Escape key is pressed, 'delete-event' is emitted to close the
706 window."""
707 if gdk.keyval_name(event.keyval) == "Escape":
708 self.emit("delete-event", None)
709 return True
710
711 def _updateList(self):
712 """Update the timetable list."""
713 aircraftTypes = []
714 for (aircraftFamily, button) in self._typeFamilyButtons.items():
715 if button.get_active():
716 aircraftTypes += const.aircraftFamily2Types[aircraftFamily]
717
718 self._timetable.updateList(self.isRegularEnabled,
719 self.isVIPEnabled,
720 aircraftTypes)
721
722 def _bookClicked(self, button):
723 """Called when the book button has been clicked."""
724 self._book(self._timetable.getFlightPair(self._timetable.selectedIndexes[0]))
725
726 def _rowActivated(self, timetable, index):
727 """Called when a row has been activated (e.g. double-clicked) in the
728 timetable."""
729 self._book(self._timetable.getFlightPair(index))
730
731 def _selectionChanged(self, timetable, indexes):
732 """Called when the selection has changed.
733
734 It sets the sensitivity of the book button based on whether a row is
735 selected or not."""
736 self._bookButton.set_sensitive(len(indexes)>0)
737
738 def _book(self, flightPair):
739 """Try to book the given flight pair."""
740 self._flightPairToBook = flightPair
741 self._gui.getFleet(callback = self._continueBook,
742 busyCallback = self._busyCallback)
743
744 def _busyCallback(self, busy):
745 """Called when the busy state has changed."""
746 self.set_sensitive(not busy)
747
748 def _continueBook(self, fleet):
749 """Continue booking, once the fleet is available."""
750 flightPair = self._flightPairToBook
751 aircraftType = flightPair.flight0.aircraftType
752 planes = [plane for plane in fleet
753 if plane.aircraftType == aircraftType]
754 planes.sort(key = lambda p: p.tailNumber)
755
756 dialog = BookDialog(self, flightPair, planes)
757 dialog.show_all()
758 result = dialog.run()
759 dialog.hide()
760 if result==RESPONSETYPE_OK:
761 flightIDs = [flightPair.flight0.id]
762 if flightPair.flight1 is not None:
763 flightIDs.append(flightPair.flight1.id)
764
765 date = dialog.date
766 if date is None:
767 date = self._calendarWindow.getDate()
768
769 self._gui.bookFlights(self._bookFlightsCallback,
770 flightIDs, date, dialog.plane.tailNumber,
771 busyCallback = self._busyCallback)
772
773 def _bookFlightsCallback(self, returned, result):
774 """Called when the booking has finished."""
775 if returned:
776 dialog = gtk.MessageDialog(parent = self,
777 type = MESSAGETYPE_INFO,
778 message_format = xstr("bookflights_successful"))
779 dialog.format_secondary_markup(xstr("bookflights_successful_secondary"))
780 else:
781 dialog = gtk.MessageDialog(parent = self,
782 type = MESSAGETYPE_ERROR,
783 message_format = xstr("bookflights_failed"))
784 dialog.format_secondary_markup(xstr("bookflights_failed_secondary"))
785
786 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
787 dialog.set_title(WINDOW_TITLE_BASE)
788
789 dialog.run()
790 dialog.hide()
791
792 def _createTimetablePopupMenu(self):
793 """Get the popuop menu for the timetable."""
794 menu = gtk.Menu()
795
796 menuItem = gtk.MenuItem()
797 menuItem.set_label(xstr("timetable_popup_book"))
798 menuItem.set_use_underline(True)
799 menuItem.connect("activate", self._popupBook)
800 menuItem.show()
801
802 menu.append(menuItem)
803
804 return menu
805
806 def _popupBook(self, menuItem):
807 """Try to book the given flight pair."""
808 index = self._timetable.selectedIndexes[0]
809 self._book(self._timetable.getFlightPair(index))
Note: See TracBrowser for help on using the repository browser.