source: src/mlx/gui/timetable.py@ 968:1128dfecb282

python3
Last change on this file since 968:1128dfecb282 was 927:566a7479b869, checked in by István Váradi <ivaradi@…>, 6 years ago

Update to Gtk 3 API changes (re #347).

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