source: src/mlx/gui/timetable.py@ 1104:efcef6ab0610

python3
Last change on this file since 1104:efcef6ab0610 was 1013:84d79c1cab91, checked in by István Váradi <ivaradi@…>, 5 years ago

The unavailable types in the booking window are not checked (re #347)

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