source: src/mlx/gui/pirep.py@ 1033:330058d37574

python3
Last change on this file since 1033:330058d37574 was 1033:330058d37574, checked in by István Váradi <ivaradi@…>, 2 years ago

Updates for the new crew and passenger handling (re #357)

File size: 62.3 KB
Line 
1
2from .common import *
3from .dcdata import getTable
4from .info import FlightInfo
5from .flight import comboModel
6
7from mlx.pirep import PIREP
8from mlx.flight import Flight
9from mlx.const import *
10
11import time
12import re
13
14#------------------------------------------------------------------------------
15
16## @package mlx.gui.pirep
17#
18# The detailed PIREP viewer and editor windows.
19#
20# The \ref PIREPViewer class is a dialog displaying all information found in a
21# PIREP. It consists of three tabs. The Data tab displays the simple,
22# itemizable data. The Comments & defects tab contains the flight comments and
23# defects, while the Log tab contains the flight log collected by the
24# \ref mlx.logger.Logger "logger".
25
26#------------------------------------------------------------------------------
27
28class MessageFrame(Gtk.Frame):
29 """A frame containing the information about a PIREP message.
30
31 It consists of a text view with the heading information (author, time) and
32 another text view with the actual message."""
33 def __init__(self, message, senderPID, senderName):
34 """Construct the frame."""
35 Gtk.Frame.__init__(self)
36
37 vbox = Gtk.VBox()
38
39 self._heading = heading = Gtk.TextView()
40 heading.set_editable(False)
41 heading.set_can_focus(False)
42 heading.set_wrap_mode(Gtk.WrapMode.WORD)
43 heading.set_size_request(-1, 16)
44
45 buffer = heading.get_buffer()
46 self._headingTag = buffer.create_tag("heading", weight=Pango.Weight.BOLD)
47 buffer.set_text("%s - %s" % (senderPID, senderName))
48 buffer.apply_tag(self._headingTag,
49 buffer.get_start_iter(), buffer.get_end_iter())
50
51 headingAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
52 xscale = 1.0, yscale = 0.0)
53 headingAlignment.set_padding(padding_top = 0, padding_bottom = 0,
54 padding_left = 2, padding_right = 2)
55 headingAlignment.add(heading)
56 vbox.pack_start(headingAlignment, True, True, 4)
57
58 self._messageView = messageView = Gtk.TextView()
59 messageView.set_wrap_mode(Gtk.WrapMode.WORD)
60 messageView.set_editable(False)
61 messageView.set_can_focus(False)
62 messageView.set_accepts_tab(False)
63 messageView.set_size_request(-1, 60)
64
65 buffer = messageView.get_buffer()
66 buffer.set_text(message)
67
68 vbox.pack_start(messageView, True, True, 4)
69
70 self.add(vbox)
71 self.show_all()
72
73 styleContext = self.get_style_context()
74 color = styleContext.get_background_color(Gtk.StateFlags.NORMAL)
75 heading.override_background_color(0, color)
76
77
78#-------------------------------------------------------------------------------
79
80class MessagesWidget(Gtk.Frame):
81 """The widget for the messages."""
82 @staticmethod
83 def getFaultFrame(alignment):
84 """Get the fault frame from the given alignment."""
85 return alignment.get_children()[0]
86
87 def __init__(self, gui):
88 Gtk.Frame.__init__(self)
89
90 self._gui = gui
91 self.set_label(xstr("pirep_messages"))
92 label = self.get_label_widget()
93 label.set_use_underline(True)
94
95 alignment = Gtk.Alignment(xalign = 0.5, yalign = 0.5,
96 xscale = 1.0, yscale = 1.0)
97 alignment.set_padding(padding_top = 4, padding_bottom = 4,
98 padding_left = 4, padding_right = 4)
99
100 self._outerBox = outerBox = Gtk.EventBox()
101 outerBox.add(alignment)
102
103 self._innerBox = innerBox = Gtk.EventBox()
104 alignment.add(self._innerBox)
105
106 alignment = Gtk.Alignment(xalign = 0.5, yalign = 0.5,
107 xscale = 1.0, yscale = 1.0)
108 alignment.set_padding(padding_top = 0, padding_bottom = 0,
109 padding_left = 0, padding_right = 0)
110
111 innerBox.add(alignment)
112
113 scroller = Gtk.ScrolledWindow()
114 scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
115 scroller.set_shadow_type(Gtk.ShadowType.NONE)
116
117 self._messages = Gtk.VBox()
118 self._messages.set_homogeneous(False)
119 scroller.add_with_viewport(self._messages)
120
121 alignment.add(scroller)
122
123 self._messageWidgets = []
124
125 self.add(outerBox)
126 self.show_all()
127
128 def addMessage(self, message):
129 """Add a message from the given sender."""
130
131 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
132 xscale = 1.0, yscale = 0.0)
133 alignment.set_padding(padding_top = 2, padding_bottom = 2,
134 padding_left = 4, padding_right = 4)
135
136 messageFrame = MessageFrame(message.message,
137 message.senderPID,
138 message.senderName)
139
140 alignment.add(messageFrame)
141 self._messages.pack_start(alignment, False, False, 4)
142 self._messages.show_all()
143
144 self._messageWidgets.append((alignment, messageFrame))
145
146 def reset(self):
147 """Reset the widget by removing all messages."""
148 for (alignment, messageFrame) in self._messageWidgets:
149 self._messages.remove(alignment)
150 self._messages.show_all()
151
152 self._messageWidgets = []
153
154#------------------------------------------------------------------------------
155
156class PIREPViewer(Gtk.Dialog):
157 """The dialog for PIREP viewing."""
158 @staticmethod
159 def createFrame(label):
160 """Create a frame with the given label.
161
162 The frame will contain an alignment to properly distance the
163 insides. The alignment will contain a VBox to contain the real
164 contents.
165
166 The function returns a tuple with the following items:
167 - the frame,
168 - the inner VBox."""
169 frame = Gtk.Frame(label = label)
170
171 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
172 xscale = 1.0, yscale = 1.0)
173 frame.add(alignment)
174 alignment.set_padding(padding_top = 4, padding_bottom = 4,
175 padding_left = 4, padding_right = 4)
176 box = Gtk.VBox()
177 alignment.add(box)
178
179 return (frame, box)
180
181 @staticmethod
182 def getLabel(text, extraText = ""):
183 """Get a bold label with the given text."""
184 label = Gtk.Label("<b>" + text + "</b>" + extraText)
185 label.set_use_markup(True)
186 label.set_alignment(0.0, 0.5)
187 return label
188
189 @staticmethod
190 def getDataLabel(width = None, xAlignment = 0.0):
191 """Get a bold label with the given text."""
192 label = Gtk.Label()
193 if width is not None:
194 label.set_width_chars(width)
195 label.set_alignment(xAlignment, 0.5)
196 return label
197
198 @staticmethod
199 def getTextWindow(heightRequest = 40, editable = False):
200 """Get a scrollable text window.
201
202 Returns a tuple of the following items:
203 - the window,
204 - the text view."""
205 scrolledWindow = Gtk.ScrolledWindow()
206 scrolledWindow.set_shadow_type(Gtk.ShadowType.IN)
207 scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC,
208 Gtk.PolicyType.AUTOMATIC)
209
210 textView = Gtk.TextView()
211 textView.set_wrap_mode(Gtk.WrapMode.WORD)
212 textView.set_editable(editable)
213 textView.set_cursor_visible(editable)
214 textView.set_size_request(-1, heightRequest)
215 scrolledWindow.add(textView)
216
217 return (scrolledWindow, textView)
218
219 @staticmethod
220 def tableAttach(table, column, row, labelText, width = None,
221 dataLabelXAlignment = 0.0):
222 """Attach a labeled data to the given column and row of the
223 table.
224
225 If width is given, that will be the width of the data
226 label.
227
228 Returns the data label attached."""
229 dataBox = Gtk.HBox()
230 table.attach(dataBox, column, column+1, row, row+1)
231
232 dataLabel = PIREPViewer.addLabeledData(dataBox, labelText,
233 width = width)
234 dataLabel.set_alignment(dataLabelXAlignment, 0.5)
235
236 return dataLabel
237
238 @staticmethod
239 def addLabeledData(hBox, labelText, width = None, dataPadding = 8):
240 """Add a label and a data label to the given HBox.
241
242 Returns the data label."""
243 label = PIREPViewer.getLabel(labelText)
244 hBox.pack_start(label, False, False, 0)
245
246 dataLabel = PIREPViewer.getDataLabel(width = width)
247 hBox.pack_start(dataLabel, False, False, dataPadding)
248
249 return dataLabel
250
251 @staticmethod
252 def addHFiller(hBox, width = 8):
253 """Add a filler to the given horizontal box."""
254 filler = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
255 xscale = 1.0, yscale = 1.0)
256 filler.set_size_request(width, -1)
257 hBox.pack_start(filler, False, False, 0)
258
259 @staticmethod
260 def addVFiller(vBox, height = 4):
261 """Add a filler to the given vertical box."""
262 filler = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
263 xscale = 1.0, yscale = 1.0)
264 filler.set_size_request(-1, height)
265 vBox.pack_start(filler, False, False, 0)
266
267 @staticmethod
268 def timestamp2text(label, timestamp):
269 """Convert the given timestamp into a text containing the hour
270 and minute in UTC and put that text into the given label."""
271 tm = time.gmtime(timestamp)
272 label.set_text("%02d:%02d" % (tm.tm_hour, tm.tm_min))
273
274 def __init__(self, gui, showMessages = False):
275 """Construct the PIREP viewer."""
276 super(PIREPViewer, self).__init__(title = WINDOW_TITLE_BASE +
277 " - " +
278 xstr("pirepView_title"),
279 parent = gui.mainWindow)
280
281 self.set_resizable(False)
282
283 self._gui = gui
284
285 contentArea = self.get_content_area()
286
287 self._notebook = Gtk.Notebook()
288 contentArea.pack_start(self._notebook, False, False, 4)
289
290 dataTab = self._buildDataTab()
291 label = Gtk.Label(xstr("pirepView_tab_data"))
292 label.set_use_underline(True)
293 label.set_tooltip_text(xstr("pirepView_tab_data_tooltip"))
294 self._notebook.append_page(dataTab, label)
295
296 commentsTab = self._buildCommentsTab()
297 label = Gtk.Label(xstr("pirepView_tab_comments"))
298 label.set_use_underline(True)
299 label.set_tooltip_text(xstr("pirepView_tab_comments_tooltip"))
300 self._notebook.append_page(commentsTab, label)
301
302 logTab = self._buildLogTab()
303 label = Gtk.Label(xstr("pirepView_tab_log"))
304 label.set_use_underline(True)
305 label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
306 self._notebook.append_page(logTab, label)
307
308 self._showMessages = showMessages
309 if showMessages:
310 messagesTab = self._buildMessagesTab()
311 label = Gtk.Label(xstr("pirepView_tab_messages"))
312 label.set_use_underline(True)
313 label.set_tooltip_text(xstr("pirepView_tab_messages_tooltip"))
314 self._notebook.append_page(messagesTab, label)
315
316 self._okButton = self.add_button(xstr("button_ok"), Gtk.ResponseType.OK)
317 self._okButton.set_can_default(True)
318
319 def setPIREP(self, pirep):
320 """Setup the data in the dialog from the given PIREP."""
321 bookedFlight = pirep.bookedFlight
322
323 self._callsign.set_text(bookedFlight.callsign)
324 self._tailNumber.set_text(bookedFlight.tailNumber)
325 aircraftType = xstr("aircraft_" + icaoCodes[bookedFlight.aircraftType].lower())
326 self._aircraftType.set_text(aircraftType)
327
328 self._departureICAO.set_text(bookedFlight.departureICAO)
329 self._departureTime.set_text("%02d:%02d" % \
330 (bookedFlight.departureTime.hour,
331 bookedFlight.departureTime.minute))
332
333 self._arrivalICAO.set_text(bookedFlight.arrivalICAO)
334 self._arrivalTime.set_text("%02d:%02d" % \
335 (bookedFlight.arrivalTime.hour,
336 bookedFlight.arrivalTime.minute))
337
338 self._numPassengers.set_text(str(bookedFlight.numPassengers) + " + " +
339 str(bookedFlight.numChildren) + " + " +
340 str(bookedFlight.numInfants))
341 self._numCrew.set_text(str(bookedFlight.numCockpitCrew) + " + " +
342 str(bookedFlight.numCabinCrew))
343 self._bagWeight.set_text(str(bookedFlight.bagWeight))
344 self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
345 self._mailWeight.set_text(str(bookedFlight.mailWeight))
346
347 self._route.get_buffer().set_text(bookedFlight.route)
348
349 self._filedCruiseLevel.set_text("FL" + str(pirep.filedCruiseAltitude/100))
350
351 if pirep.cruiseAltitude != pirep.filedCruiseAltitude:
352 self._modifiedCruiseLevel.set_text("FL" + str(pirep.cruiseAltitude/100))
353 else:
354 self._modifiedCruiseLevel.set_text("-")
355
356 self._userRoute.get_buffer().set_text(pirep.route)
357
358 self._departureMETAR.get_buffer().set_text(pirep.departureMETAR)
359
360 self._arrivalMETAR.get_buffer().set_text(pirep.arrivalMETAR)
361 self._departureRunway.set_text(pirep.departureRunway)
362 self._sid.set_text(pirep.sid)
363
364 self._star.set_text("-" if pirep.star is None else pirep.star)
365 self._transition.set_text("-" if pirep.transition is None else pirep.transition)
366 self._approachType.set_text(pirep.approachType)
367 self._arrivalRunway.set_text(pirep.arrivalRunway)
368
369 PIREPViewer.timestamp2text(self._blockTimeStart, pirep.blockTimeStart)
370 PIREPViewer.timestamp2text(self._blockTimeEnd, pirep.blockTimeEnd)
371 PIREPViewer.timestamp2text(self._flightTimeStart, pirep.flightTimeStart)
372 PIREPViewer.timestamp2text(self._flightTimeEnd, pirep.flightTimeEnd)
373
374 self._flownDistance.set_text("%.1f" % (pirep.flownDistance,))
375 self._fuelUsed.set_text("%.0f" % (pirep.fuelUsed,))
376
377 rating = pirep.rating
378 if rating<0:
379 self._rating.set_markup('<b><span foreground="red">NO GO</span></b>')
380 else:
381 self._rating.set_text("%.1f %%" % (rating,))
382
383 self._flownNumCabinCrew.set_text("%d" % (pirep.numCabinCrew,))
384 self._flownNumPassengers.set_text("%d" % (pirep.numPassengers,))
385 self._flownBagWeight.set_text("%.0f" % (pirep.bagWeight,))
386 self._flownCargoWeight.set_text("%.0f" % (pirep.cargoWeight,))
387 self._flownMailWeight.set_text("%.0f" % (pirep.mailWeight,))
388 self._flightType.set_text(xstr("flighttype_" +
389 flightType2string(pirep.flightType)))
390 self._online.set_text(xstr("pirepView_" +
391 ("yes" if pirep.online else "no")))
392
393 delayCodes = ""
394 for code in pirep.delayCodes:
395 if delayCodes: delayCodes += ", "
396 delayCodes += code
397
398 self._delayCodes.get_buffer().set_text(delayCodes)
399
400 self._comments.get_buffer().set_text(pirep.comments)
401 self._flightDefects.get_buffer().set_text(pirep.flightDefects)
402
403 logBuffer = self._log.get_buffer()
404 logBuffer.set_text("")
405 lineIndex = 0
406 for (timeStr, line) in pirep.logLines:
407 isFault = lineIndex in pirep.faultLineIndexes
408 appendTextBuffer(logBuffer,
409 formatFlightLogLine(timeStr, line),
410 isFault = isFault)
411 lineIndex += 1
412
413 if self._showMessages:
414 self._messages.reset()
415 for message in pirep.messages:
416 self._messages.addMessage(message)
417
418 self._notebook.set_current_page(0)
419 self._okButton.grab_default()
420
421 def _buildDataTab(self):
422 """Build the data tab of the viewer."""
423 table = Gtk.Table(1, 2)
424 table.set_row_spacings(4)
425 table.set_col_spacings(16)
426 table.set_homogeneous(True)
427
428 box1 = Gtk.VBox()
429 table.attach(box1, 0, 1, 0, 1)
430
431 box2 = Gtk.VBox()
432 table.attach(box2, 1, 2, 0, 1)
433
434 flightFrame = self._buildFlightFrame()
435 box1.pack_start(flightFrame, False, False, 4)
436
437 routeFrame = self._buildRouteFrame()
438 box1.pack_start(routeFrame, False, False, 4)
439
440 departureFrame = self._buildDepartureFrame()
441 box2.pack_start(departureFrame, True, True, 4)
442
443 arrivalFrame = self._buildArrivalFrame()
444 box2.pack_start(arrivalFrame, True, True, 4)
445
446 statisticsFrame = self._buildStatisticsFrame()
447 box2.pack_start(statisticsFrame, False, False, 4)
448
449 miscellaneousFrame = self._buildMiscellaneousFrame()
450 box1.pack_start(miscellaneousFrame, False, False, 4)
451
452 return table
453
454 def _buildFlightFrame(self):
455 """Build the frame for the flight data."""
456
457 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
458
459 dataBox = Gtk.HBox()
460 mainBox.pack_start(dataBox, False, False, 0)
461
462 self._callsign = \
463 PIREPViewer.addLabeledData(dataBox,
464 xstr("pirepView_callsign"),
465 width = 8)
466
467 self._tailNumber = \
468 PIREPViewer.addLabeledData(dataBox,
469 xstr("pirepView_tailNumber"),
470 width = 7)
471
472 PIREPViewer.addVFiller(mainBox)
473
474 dataBox = Gtk.HBox()
475 mainBox.pack_start(dataBox, False, False, 0)
476
477 self._aircraftType = \
478 PIREPViewer.addLabeledData(dataBox,
479 xstr("pirepView_aircraftType"),
480 width = 25)
481
482 PIREPViewer.addVFiller(mainBox)
483
484 table = Gtk.Table(3, 2)
485 mainBox.pack_start(table, False, False, 0)
486 table.set_row_spacings(4)
487 table.set_col_spacings(8)
488
489 self._departureICAO = \
490 PIREPViewer.tableAttach(table, 0, 0,
491 xstr("pirepView_departure"),
492 width = 5)
493
494 self._departureTime = \
495 PIREPViewer.tableAttach(table, 1, 0,
496 xstr("pirepView_departure_time"),
497 width = 6)
498
499 self._arrivalICAO = \
500 PIREPViewer.tableAttach(table, 0, 1,
501 xstr("pirepView_arrival"),
502 width = 5)
503
504 self._arrivalTime = \
505 PIREPViewer.tableAttach(table, 1, 1,
506 xstr("pirepView_arrival_time"),
507 width = 6)
508
509 table = Gtk.Table(3, 2)
510 mainBox.pack_start(table, False, False, 0)
511 table.set_row_spacings(4)
512 table.set_col_spacings(8)
513
514 self._numPassengers = \
515 PIREPViewer.tableAttach(table, 0, 0,
516 xstr("pirepView_numPassengers"),
517 width = 4)
518
519 self._numCrew = \
520 PIREPViewer.tableAttach(table, 1, 0,
521 xstr("pirepView_numCrew"),
522 width = 3)
523
524 self._bagWeight = \
525 PIREPViewer.tableAttach(table, 0, 1,
526 xstr("pirepView_bagWeight"),
527 width = 5)
528
529 self._cargoWeight = \
530 PIREPViewer.tableAttach(table, 1, 1,
531 xstr("pirepView_cargoWeight"),
532 width = 5)
533
534 self._mailWeight = \
535 PIREPViewer.tableAttach(table, 2, 1,
536 xstr("pirepView_mailWeight"),
537 width = 5)
538
539 PIREPViewer.addVFiller(mainBox)
540
541 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
542 False, False, 0)
543
544 (routeWindow, self._route) = PIREPViewer.getTextWindow()
545 mainBox.pack_start(routeWindow, False, False, 0)
546
547 return frame
548
549 def _buildRouteFrame(self):
550 """Build the frame for the user-specified route and flight
551 level."""
552
553 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
554
555 levelBox = Gtk.HBox()
556 mainBox.pack_start(levelBox, False, False, 0)
557
558 self._filedCruiseLevel = \
559 PIREPViewer.addLabeledData(levelBox,
560 xstr("pirepView_filedCruiseLevel"),
561 width = 6)
562
563 self._modifiedCruiseLevel = \
564 PIREPViewer.addLabeledData(levelBox,
565 xstr("pirepView_modifiedCruiseLevel"),
566 width = 6)
567
568 PIREPViewer.addVFiller(mainBox)
569
570 (routeWindow, self._userRoute) = PIREPViewer.getTextWindow()
571 mainBox.pack_start(routeWindow, False, False, 0)
572
573 return frame
574
575 def _buildDepartureFrame(self):
576 """Build the frame for the departure data."""
577 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
578
579 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
580 False, False, 0)
581 (metarWindow, self._departureMETAR) = \
582 PIREPViewer.getTextWindow(heightRequest = -1)
583 mainBox.pack_start(metarWindow, True, True, 0)
584
585 PIREPViewer.addVFiller(mainBox)
586
587 dataBox = Gtk.HBox()
588 mainBox.pack_start(dataBox, False, False, 0)
589
590 self._departureRunway = \
591 PIREPViewer.addLabeledData(dataBox,
592 xstr("pirepView_runway"),
593 width = 5)
594
595 self._sid = \
596 PIREPViewer.addLabeledData(dataBox,
597 xstr("pirepView_sid"),
598 width = 12)
599
600 return frame
601
602 def _buildArrivalFrame(self):
603 """Build the frame for the arrival data."""
604 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
605
606 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
607 False, False, 0)
608 (metarWindow, self._arrivalMETAR) = \
609 PIREPViewer.getTextWindow(heightRequest = -1)
610 mainBox.pack_start(metarWindow, True, True, 0)
611
612 PIREPViewer.addVFiller(mainBox)
613
614 table = Gtk.Table(2, 2)
615 mainBox.pack_start(table, False, False, 0)
616 table.set_row_spacings(4)
617 table.set_col_spacings(8)
618
619 self._star = \
620 PIREPViewer.tableAttach(table, 0, 0,
621 xstr("pirepView_star"),
622 width = 12)
623
624 self._transition = \
625 PIREPViewer.tableAttach(table, 1, 0,
626 xstr("pirepView_transition"),
627 width = 12)
628
629 self._approachType = \
630 PIREPViewer.tableAttach(table, 0, 1,
631 xstr("pirepView_approachType"),
632 width = 7)
633
634 self._arrivalRunway = \
635 PIREPViewer.tableAttach(table, 1, 1,
636 xstr("pirepView_runway"),
637 width = 5)
638
639 return frame
640
641 def _buildStatisticsFrame(self):
642 """Build the frame for the statistics data."""
643 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
644
645 table = Gtk.Table(4, 2)
646 mainBox.pack_start(table, False, False, 0)
647 table.set_row_spacings(4)
648 table.set_col_spacings(8)
649 table.set_homogeneous(False)
650
651 self._blockTimeStart = \
652 PIREPViewer.tableAttach(table, 0, 0,
653 xstr("pirepView_blockTimeStart"),
654 width = 6)
655
656 self._blockTimeEnd = \
657 PIREPViewer.tableAttach(table, 1, 0,
658 xstr("pirepView_blockTimeEnd"),
659 width = 8)
660
661 self._flightTimeStart = \
662 PIREPViewer.tableAttach(table, 0, 1,
663 xstr("pirepView_flightTimeStart"),
664 width = 6)
665
666 self._flightTimeEnd = \
667 PIREPViewer.tableAttach(table, 1, 1,
668 xstr("pirepView_flightTimeEnd"),
669 width = 6)
670
671 self._flownDistance = \
672 PIREPViewer.tableAttach(table, 0, 2,
673 xstr("pirepView_flownDistance"),
674 width = 8)
675
676 self._fuelUsed = \
677 PIREPViewer.tableAttach(table, 1, 2,
678 xstr("pirepView_fuelUsed"),
679 width = 6)
680
681 self._rating = \
682 PIREPViewer.tableAttach(table, 0, 3,
683 xstr("pirepView_rating"),
684 width = 7)
685 return frame
686
687 def _buildMiscellaneousFrame(self):
688 """Build the frame for the miscellaneous data."""
689 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
690
691 table = Gtk.Table(3, 2)
692 mainBox.pack_start(table, False, False, 0)
693 table.set_row_spacings(4)
694 table.set_col_spacings(8)
695
696 self._flownNumPassengers = \
697 PIREPViewer.tableAttach(table, 0, 0,
698 xstr("pirepView_numPassengers"),
699 width = 4)
700
701 self._flownNumCabinCrew = \
702 PIREPViewer.tableAttach(table, 1, 0,
703 xstr("pirepView_numCrew"),
704 width = 3)
705
706 self._flownBagWeight = \
707 PIREPViewer.tableAttach(table, 0, 1,
708 xstr("pirepView_bagWeight"),
709 width = 5)
710
711 self._flownCargoWeight = \
712 PIREPViewer.tableAttach(table, 1, 1,
713 xstr("pirepView_cargoWeight"),
714 width = 6)
715
716 self._flownMailWeight = \
717 PIREPViewer.tableAttach(table, 2, 1,
718 xstr("pirepView_mailWeight"),
719 width = 5)
720
721 self._flightType = \
722 PIREPViewer.tableAttach(table, 0, 2,
723 xstr("pirepView_flightType"),
724 width = 15)
725
726 self._online = \
727 PIREPViewer.tableAttach(table, 1, 2,
728 xstr("pirepView_online"),
729 width = 5)
730
731 PIREPViewer.addVFiller(mainBox)
732
733 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
734 False, False, 0)
735
736 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
737 mainBox.pack_start(textWindow, False, False, 0)
738
739 return frame
740
741 def _buildCommentsTab(self):
742 """Build the tab with the comments and flight defects."""
743 table = Gtk.Table(2, 1)
744 table.set_col_spacings(16)
745
746 (frame, commentsBox) = \
747 PIREPViewer.createFrame(xstr("pirepView_comments"))
748 table.attach(frame, 0, 1, 0, 1)
749
750 (commentsWindow, self._comments) = \
751 PIREPViewer.getTextWindow(heightRequest = -1)
752 commentsBox.pack_start(commentsWindow, True, True, 0)
753
754 (frame, flightDefectsBox) = \
755 PIREPViewer.createFrame(xstr("pirepView_flightDefects"))
756 table.attach(frame, 1, 2, 0, 1)
757
758 (flightDefectsWindow, self._flightDefects) = \
759 PIREPViewer.getTextWindow(heightRequest = -1)
760 flightDefectsBox.pack_start(flightDefectsWindow, True, True, 0)
761
762 return table
763
764 def _buildLogTab(self):
765 """Build the log tab."""
766 mainBox = Gtk.VBox()
767
768 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
769 addFaultTag(self._log.get_buffer())
770 mainBox.pack_start(logWindow, True, True, 0)
771
772 return mainBox
773
774 def _buildMessagesTab(self):
775 """Build the messages tab."""
776 mainBox = Gtk.VBox()
777
778 self._messages = MessagesWidget(self._gui)
779 mainBox.pack_start(self._messages, True, True, 0)
780
781 return mainBox
782
783#------------------------------------------------------------------------------
784
785class PIREPEditor(Gtk.Dialog):
786 """A PIREP editor dialog."""
787 _delayCodeRE = re.compile("([0-9]{2,3})( \([^\)]*\))")
788
789 @staticmethod
790 def tableAttachWidget(table, column, row, labelText, widget):
791 """Attach the given widget with the given label to the given table.
792
793 The label will got to cell (column, row), the widget to cell
794 (column+1, row)."""
795 label = Gtk.Label("<b>" + labelText + "</b>")
796 label.set_use_markup(True)
797 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.5,
798 xscale = 0.0, yscale = 0.0)
799 alignment.add(label)
800 table.attach(alignment, column, column + 1, row, row + 1)
801
802 table.attach(widget, column + 1, column + 2, row, row + 1)
803
804 @staticmethod
805 def tableAttachSpinButton(table, column, row, labelText, maxValue,
806 minValue = 0, stepIncrement = 1,
807 pageIncrement = 10, numeric = True,
808 width = 3):
809 """Attach a spin button with the given label to the given table.
810
811 The label will got to cell (column, row), the spin button to cell
812 (column+1, row)."""
813 button = Gtk.SpinButton()
814 button.set_range(min = minValue, max = maxValue)
815 button.set_increments(step = stepIncrement, page = pageIncrement)
816 button.set_numeric(True)
817 button.set_width_chars(width)
818 button.set_alignment(1.0)
819
820 PIREPEditor.tableAttachWidget(table, column, row, labelText, button)
821
822 return button
823
824 @staticmethod
825 def tableAttachTimeEntry(table, column, row, labelText):
826 """Attach a time entry widget with the given label to the given table.
827
828 The label will got to cell (column, row), the spin button to cell
829 (column+1, row)."""
830 entry = TimeEntry()
831 entry.set_width_chars(5)
832 entry.set_alignment(1.0)
833
834 PIREPEditor.tableAttachWidget(table, column, row, labelText, entry)
835
836 return entry
837
838 def __init__(self, gui):
839 """Construct the PIREP viewer."""
840 super(PIREPEditor, self).__init__(title = WINDOW_TITLE_BASE +
841 " - " +
842 xstr("pirepEdit_title"),
843 parent = gui.mainWindow)
844
845 self.set_resizable(False)
846
847 self._gui = gui
848
849 self._pirep = None
850
851 contentArea = self.get_content_area()
852
853 self._notebook = Gtk.Notebook()
854 contentArea.pack_start(self._notebook, False, False, 4)
855
856 dataTab = self._buildDataTab()
857 label = Gtk.Label(xstr("pirepView_tab_data"))
858 label.set_use_underline(True)
859 label.set_tooltip_text(xstr("pirepView_tab_data_tooltip"))
860 self._notebook.append_page(dataTab, label)
861
862 self._flightInfo = self._buildCommentsTab()
863 label = Gtk.Label(xstr("pirepView_tab_comments"))
864 label.set_use_underline(True)
865 label.set_tooltip_text(xstr("pirepView_tab_comments_tooltip"))
866 self._notebook.append_page(self._flightInfo, label)
867
868 logTab = self._buildLogTab()
869 label = Gtk.Label(xstr("pirepView_tab_log"))
870 label.set_use_underline(True)
871 label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
872 self._notebook.append_page(logTab, label)
873
874 self.add_button(xstr("button_cancel"), Gtk.ResponseType.CANCEL)
875
876 self._okButton = self.add_button(xstr("button_save"), Gtk.ResponseType.NONE)
877 self._okButton.connect("clicked", self._okClicked)
878 self._okButton.set_can_default(True)
879 self._modified = False
880 self._toSave = False
881
882 def setPIREP(self, pirep):
883 """Setup the data in the dialog from the given PIREP."""
884 self._pirep = pirep
885
886 bookedFlight = pirep.bookedFlight
887
888 self._callsign.set_text(bookedFlight.callsign)
889 self._tailNumber.set_text(bookedFlight.tailNumber)
890 aircraftType = xstr("aircraft_" + icaoCodes[bookedFlight.aircraftType].lower())
891 self._aircraftType.set_text(aircraftType)
892
893 self._departureICAO.set_text(bookedFlight.departureICAO)
894 self._departureTime.set_text("%02d:%02d" % \
895 (bookedFlight.departureTime.hour,
896 bookedFlight.departureTime.minute))
897
898 self._arrivalICAO.set_text(bookedFlight.arrivalICAO)
899 self._arrivalTime.set_text("%02d:%02d" % \
900 (bookedFlight.arrivalTime.hour,
901 bookedFlight.arrivalTime.minute))
902
903 self._numPassengers.set_text(str(bookedFlight.numPassengers) + " + " +
904 str(bookedFlight.numChildren) + " + " +
905 str(bookedFlight.numInfants))
906 self._numCrew.set_text(str(bookedFlight.numCockpitCrew) + " + " +
907 str(bookedFlight.numCabinCrew))
908 self._bagWeight.set_text(str(bookedFlight.bagWeight))
909 self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
910 self._mailWeight.set_text(str(bookedFlight.mailWeight))
911
912 self._route.get_buffer().set_text(bookedFlight.route)
913
914 self._filedCruiseLevel.set_value(pirep.filedCruiseAltitude/100)
915 self._modifiedCruiseLevel.set_value(pirep.cruiseAltitude/100)
916
917 self._userRoute.get_buffer().set_text(pirep.route)
918
919 self._departureMETAR.get_buffer().set_text(pirep.departureMETAR)
920
921 self._arrivalMETAR.get_buffer().set_text(pirep.arrivalMETAR)
922 self._departureRunway.set_text(pirep.departureRunway)
923 self._sid.get_child().set_text(pirep.sid)
924
925 if not pirep.star:
926 self._star.set_active(0)
927 else:
928 self._star.get_child().set_text(pirep.star)
929
930 if not pirep.transition:
931 self._transition.set_active(0)
932 else:
933 self._transition.get_child().set_text(pirep.transition)
934 self._approachType.set_text(pirep.approachType)
935 self._arrivalRunway.set_text(pirep.arrivalRunway)
936
937 self._blockTimeStart.setTimestamp(pirep.blockTimeStart)
938 self._blockTimeEnd.setTimestamp(pirep.blockTimeEnd)
939 self._flightTimeStart.setTimestamp(pirep.flightTimeStart)
940 self._flightTimeEnd.setTimestamp(pirep.flightTimeEnd)
941
942 self._flownDistance.set_text("%.1f" % (pirep.flownDistance,))
943 self._fuelUsed.set_value(int(pirep.fuelUsed))
944
945 rating = pirep.rating
946 if rating<0:
947 self._rating.set_markup('<b><span foreground="red">NO GO</span></b>')
948 else:
949 self._rating.set_text("%.1f %%" % (rating,))
950
951 self._flownNumCabinCrew.set_value(pirep.numCabinCrew)
952 self._flownNumPassengers.set_value(pirep.numPassengers)
953 self._flownNumChildren.set_value(pirep.numChildren)
954 self._flownNumInfants.set_value(pirep.numInfants)
955 self._flownBagWeight.set_value(pirep.bagWeight)
956 self._flownCargoWeight.set_value(pirep.cargoWeight)
957 self._flownMailWeight.set_value(pirep.mailWeight)
958 self._flightType.set_active(flightType2index(pirep.flightType))
959 self._online.set_active(pirep.online)
960
961 self._flightInfo.reset()
962 self._flightInfo.enable(bookedFlight.aircraftType)
963
964 delayCodes = ""
965 for code in pirep.delayCodes:
966 if delayCodes: delayCodes += ", "
967 delayCodes += code
968 m = PIREPEditor._delayCodeRE.match(code)
969 if m:
970 self._flightInfo.activateDelayCode(m.group(1))
971
972 self._delayCodes.get_buffer().set_text(delayCodes)
973
974 self._flightInfo.comments = pirep.comments
975 if pirep.flightDefects.find("<br/></b>")!=-1:
976 flightDefects = pirep.flightDefects.split("<br/></b>")
977 caption = flightDefects[0]
978 index = 0
979 for defect in flightDefects[1:]:
980 if defect.find("<b>")!=-1:
981 (explanation, nextCaption) = defect.split("<b>")
982 else:
983 explanation = defect
984 nextCaption = None
985 self._flightInfo.addFault(index, caption)
986 self._flightInfo.setExplanation(index, explanation)
987 index += 1
988 caption = nextCaption
989
990 # self._comments.get_buffer().set_text(pirep.comments)
991 # self._flightDefects.get_buffer().set_text(pirep.flightDefects)
992
993 logBuffer = self._log.get_buffer()
994 logBuffer.set_text("")
995 lineIndex = 0
996 for (timeStr, line) in pirep.logLines:
997 isFault = lineIndex in pirep.faultLineIndexes
998 appendTextBuffer(logBuffer,
999 formatFlightLogLine(timeStr, line),
1000 isFault = isFault)
1001 lineIndex += 1
1002
1003 self._notebook.set_current_page(0)
1004 self._okButton.grab_default()
1005
1006 self._modified = False
1007 self._updateButtons()
1008 self._modified = True
1009 self._toSave = False
1010
1011 def delayCodesChanged(self):
1012 """Called when the delay codes have changed."""
1013 self._updateButtons()
1014
1015 def commentsChanged(self):
1016 """Called when the comments have changed."""
1017 self._updateButtons()
1018
1019 def faultExplanationsChanged(self):
1020 """Called when the fault explanations have changed."""
1021 self._updateButtons()
1022
1023 def _buildDataTab(self):
1024 """Build the data tab of the viewer."""
1025 table = Gtk.Table(1, 2)
1026 table.set_row_spacings(4)
1027 table.set_col_spacings(16)
1028 table.set_homogeneous(True)
1029
1030 box1 = Gtk.VBox()
1031 table.attach(box1, 0, 1, 0, 1)
1032
1033 box2 = Gtk.VBox()
1034 table.attach(box2, 1, 2, 0, 1)
1035
1036 flightFrame = self._buildFlightFrame()
1037 box1.pack_start(flightFrame, False, False, 4)
1038
1039 routeFrame = self._buildRouteFrame()
1040 box1.pack_start(routeFrame, False, False, 4)
1041
1042 departureFrame = self._buildDepartureFrame()
1043 box2.pack_start(departureFrame, True, True, 4)
1044
1045 arrivalFrame = self._buildArrivalFrame()
1046 box2.pack_start(arrivalFrame, True, True, 4)
1047
1048 statisticsFrame = self._buildStatisticsFrame()
1049 box2.pack_start(statisticsFrame, False, False, 4)
1050
1051 miscellaneousFrame = self._buildMiscellaneousFrame()
1052 box1.pack_start(miscellaneousFrame, False, False, 4)
1053
1054 return table
1055
1056 def _buildFlightFrame(self):
1057 """Build the frame for the flight data."""
1058
1059 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
1060
1061 dataBox = Gtk.HBox()
1062 mainBox.pack_start(dataBox, False, False, 0)
1063
1064 self._callsign = \
1065 PIREPViewer.addLabeledData(dataBox,
1066 xstr("pirepView_callsign"),
1067 width = 8)
1068
1069 self._tailNumber = \
1070 PIREPViewer.addLabeledData(dataBox,
1071 xstr("pirepView_tailNumber"),
1072 width = 7)
1073
1074 PIREPViewer.addVFiller(mainBox)
1075
1076 dataBox = Gtk.HBox()
1077 mainBox.pack_start(dataBox, False, False, 0)
1078
1079 self._aircraftType = \
1080 PIREPViewer.addLabeledData(dataBox,
1081 xstr("pirepView_aircraftType"),
1082 width = 25)
1083
1084 PIREPViewer.addVFiller(mainBox)
1085
1086 table = Gtk.Table(3, 2)
1087 mainBox.pack_start(table, False, False, 0)
1088 table.set_row_spacings(4)
1089 table.set_col_spacings(8)
1090
1091 self._departureICAO = \
1092 PIREPViewer.tableAttach(table, 0, 0,
1093 xstr("pirepView_departure"),
1094 width = 5)
1095
1096 self._departureTime = \
1097 PIREPViewer.tableAttach(table, 1, 0,
1098 xstr("pirepView_departure_time"),
1099 width = 6)
1100
1101 self._arrivalICAO = \
1102 PIREPViewer.tableAttach(table, 0, 1,
1103 xstr("pirepView_arrival"),
1104 width = 5)
1105
1106 self._arrivalTime = \
1107 PIREPViewer.tableAttach(table, 1, 1,
1108 xstr("pirepView_arrival_time"),
1109 width = 6)
1110
1111 table = Gtk.Table(3, 2)
1112 mainBox.pack_start(table, False, False, 0)
1113 table.set_row_spacings(4)
1114 table.set_col_spacings(8)
1115
1116 self._numPassengers = \
1117 PIREPViewer.tableAttach(table, 0, 0,
1118 xstr("pirepView_numPassengers"),
1119 width = 4)
1120 self._numCrew = \
1121 PIREPViewer.tableAttach(table, 1, 0,
1122 xstr("pirepView_numCrew"),
1123 width = 3)
1124
1125 self._bagWeight = \
1126 PIREPViewer.tableAttach(table, 0, 1,
1127 xstr("pirepView_bagWeight"),
1128 width = 5)
1129
1130 self._cargoWeight = \
1131 PIREPViewer.tableAttach(table, 1, 1,
1132 xstr("pirepView_cargoWeight"),
1133 width = 5)
1134
1135 self._mailWeight = \
1136 PIREPViewer.tableAttach(table, 2, 1,
1137 xstr("pirepView_mailWeight"),
1138 width = 5)
1139
1140 PIREPViewer.addVFiller(mainBox)
1141
1142 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
1143 False, False, 0)
1144
1145 (routeWindow, self._route) = PIREPViewer.getTextWindow()
1146 mainBox.pack_start(routeWindow, False, False, 0)
1147
1148 return frame
1149
1150 def _buildRouteFrame(self):
1151 """Build the frame for the user-specified route and flight
1152 level."""
1153
1154 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
1155
1156 levelBox = Gtk.HBox()
1157 mainBox.pack_start(levelBox, False, False, 0)
1158
1159 label = PIREPViewer.getLabel(xstr("pirepView_filedCruiseLevel"),
1160 xstr("pirepEdit_FL"))
1161 levelBox.pack_start(label, False, False, 0)
1162
1163 self._filedCruiseLevel = Gtk.SpinButton()
1164 self._filedCruiseLevel.set_increments(step = 10, page = 100)
1165 self._filedCruiseLevel.set_range(min = 0, max = 500)
1166 self._filedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
1167 self._filedCruiseLevel.set_numeric(True)
1168 self._filedCruiseLevel.connect("value-changed", self._updateButtons)
1169
1170 levelBox.pack_start(self._filedCruiseLevel, False, False, 0)
1171
1172 PIREPViewer.addHFiller(levelBox)
1173
1174 label = PIREPViewer.getLabel(xstr("pirepView_modifiedCruiseLevel"),
1175 xstr("pirepEdit_FL"))
1176 levelBox.pack_start(label, False, False, 0)
1177
1178 self._modifiedCruiseLevel = Gtk.SpinButton()
1179 self._modifiedCruiseLevel.set_increments(step = 10, page = 100)
1180 self._modifiedCruiseLevel.set_range(min = 0, max = 500)
1181 self._modifiedCruiseLevel.set_tooltip_text(xstr("pirepEdit_modified_route_level_tooltip"))
1182 self._modifiedCruiseLevel.set_numeric(True)
1183 self._modifiedCruiseLevel.connect("value-changed", self._updateButtons)
1184
1185 levelBox.pack_start(self._modifiedCruiseLevel, False, False, 0)
1186
1187 PIREPViewer.addVFiller(mainBox)
1188
1189 (routeWindow, self._userRoute) = \
1190 PIREPViewer.getTextWindow(editable = True)
1191 mainBox.pack_start(routeWindow, False, False, 0)
1192 self._userRoute.get_buffer().connect("changed", self._updateButtons)
1193 self._userRoute.set_tooltip_text(xstr("route_route_tooltip"))
1194
1195 return frame
1196
1197 def _buildDepartureFrame(self):
1198 """Build the frame for the departure data."""
1199 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
1200
1201 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1202 False, False, 0)
1203 (metarWindow, self._departureMETAR) = \
1204 PIREPViewer.getTextWindow(heightRequest = -1,
1205 editable = True)
1206 self._departureMETAR.get_buffer().connect("changed", self._updateButtons)
1207 self._departureMETAR.set_tooltip_text(xstr("takeoff_metar_tooltip"))
1208 mainBox.pack_start(metarWindow, True, True, 0)
1209
1210 PIREPViewer.addVFiller(mainBox)
1211
1212 dataBox = Gtk.HBox()
1213 mainBox.pack_start(dataBox, False, False, 0)
1214
1215 label = Gtk.Label("<b>" + xstr("pirepView_runway") + "</b>")
1216 label.set_use_markup(True)
1217 dataBox.pack_start(label, False, False, 0)
1218
1219 # FIXME: quite the same as the runway entry boxes in the wizard
1220 self._departureRunway = Gtk.Entry()
1221 self._departureRunway.set_width_chars(5)
1222 self._departureRunway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
1223 self._departureRunway.connect("changed", self._upperChanged)
1224 dataBox.pack_start(self._departureRunway, False, False, 8)
1225
1226 label = Gtk.Label("<b>" + xstr("pirepView_sid") + "</b>")
1227 label.set_use_markup(True)
1228 dataBox.pack_start(label, False, False, 0)
1229
1230 # FIXME: quite the same as the SID combo box in
1231 # the flight wizard
1232 self._sid = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1233
1234 self._sid.set_entry_text_column(0)
1235 self._sid.get_child().set_width_chars(10)
1236 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
1237 self._sid.connect("changed", self._upperChangedComboBox)
1238
1239 dataBox.pack_start(self._sid, False, False, 8)
1240
1241 return frame
1242
1243 def _buildArrivalFrame(self):
1244 """Build the frame for the arrival data."""
1245 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
1246
1247 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1248 False, False, 0)
1249 (metarWindow, self._arrivalMETAR) = \
1250 PIREPViewer.getTextWindow(heightRequest = -1,
1251 editable = True)
1252 self._arrivalMETAR.get_buffer().connect("changed", self._updateButtons)
1253 self._arrivalMETAR.set_tooltip_text(xstr("landing_metar_tooltip"))
1254 mainBox.pack_start(metarWindow, True, True, 0)
1255
1256 PIREPViewer.addVFiller(mainBox)
1257
1258 table = Gtk.Table(2, 4)
1259 mainBox.pack_start(table, False, False, 0)
1260 table.set_row_spacings(4)
1261 table.set_col_spacings(8)
1262
1263 # FIXME: quite the same as in the wizard
1264 self._star = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1265
1266 self._star.set_entry_text_column(0)
1267 self._star.get_child().set_width_chars(10)
1268 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
1269 self._star.connect("changed", self._upperChangedComboBox)
1270
1271 PIREPEditor.tableAttachWidget(table, 0, 0,
1272 xstr("pirepView_star"),
1273 self._star)
1274
1275 # FIXME: quite the same as in the wizard
1276 self._transition = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1277
1278 self._transition.set_entry_text_column(0)
1279 self._transition.get_child().set_width_chars(10)
1280 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
1281 self._transition.connect("changed", self._upperChangedComboBox)
1282
1283 PIREPEditor.tableAttachWidget(table, 2, 0,
1284 xstr("pirepView_transition"),
1285 self._transition)
1286
1287
1288 # FIXME: quite the same as in the wizard
1289 self._approachType = Gtk.Entry()
1290 self._approachType.set_width_chars(10)
1291 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
1292 self._approachType.connect("changed", self._upperChanged)
1293
1294 PIREPEditor.tableAttachWidget(table, 0, 1,
1295 xstr("pirepView_approachType"),
1296 self._approachType)
1297
1298 # FIXME: quite the same as in the wizard
1299 self._arrivalRunway = Gtk.Entry()
1300 self._arrivalRunway.set_width_chars(10)
1301 self._arrivalRunway.set_tooltip_text(xstr("landing_runway_tooltip"))
1302 self._arrivalRunway.connect("changed", self._upperChanged)
1303
1304 PIREPEditor.tableAttachWidget(table, 2, 1,
1305 xstr("pirepView_runway"),
1306 self._arrivalRunway)
1307
1308 return frame
1309
1310 def _buildStatisticsFrame(self):
1311 """Build the frame for the statistics data."""
1312 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
1313
1314 table = Gtk.Table(4, 4)
1315 mainBox.pack_start(table, False, False, 0)
1316 table.set_row_spacings(4)
1317 table.set_col_spacings(8)
1318 table.set_homogeneous(False)
1319
1320 self._blockTimeStart = \
1321 PIREPEditor.tableAttachTimeEntry(table, 0, 0,
1322 xstr("pirepView_blockTimeStart"))
1323 self._blockTimeStart.connect("changed", self._updateButtons)
1324 self._blockTimeStart.set_tooltip_text(xstr("pirepEdit_block_time_start_tooltip"))
1325
1326 self._blockTimeEnd = \
1327 PIREPEditor.tableAttachTimeEntry(table, 2, 0,
1328 xstr("pirepView_blockTimeEnd"))
1329 self._blockTimeEnd.connect("changed", self._updateButtons)
1330 self._blockTimeEnd.set_tooltip_text(xstr("pirepEdit_block_time_end_tooltip"))
1331
1332 self._flightTimeStart = \
1333 PIREPEditor.tableAttachTimeEntry(table, 0, 1,
1334 xstr("pirepView_flightTimeStart"))
1335 self._flightTimeStart.connect("changed", self._updateButtons)
1336 self._flightTimeStart.set_tooltip_text(xstr("pirepEdit_flight_time_start_tooltip"))
1337
1338 self._flightTimeEnd = \
1339 PIREPEditor.tableAttachTimeEntry(table, 2, 1,
1340 xstr("pirepView_flightTimeEnd"))
1341 self._flightTimeEnd.connect("changed", self._updateButtons)
1342 self._flightTimeEnd.set_tooltip_text(xstr("pirepEdit_flight_time_end_tooltip"))
1343
1344 self._flownDistance = PIREPViewer.getDataLabel(width = 3)
1345 PIREPEditor.tableAttachWidget(table, 0, 2,
1346 xstr("pirepView_flownDistance"),
1347 self._flownDistance)
1348
1349 self._fuelUsed = \
1350 PIREPEditor.tableAttachSpinButton(table, 2, 2,
1351 xstr("pirepView_fuelUsed"),
1352 1000000)
1353 self._fuelUsed.connect("value-changed", self._updateButtons)
1354 self._fuelUsed.set_tooltip_text(xstr("pirepEdit_fuel_used_tooltip"))
1355
1356 self._rating = PIREPViewer.getDataLabel(width = 3)
1357 PIREPEditor.tableAttachWidget(table, 0, 3,
1358 xstr("pirepView_rating"),
1359 self._rating)
1360 return frame
1361
1362 def _buildMiscellaneousFrame(self):
1363 """Build the frame for the miscellaneous data."""
1364 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
1365
1366 table = Gtk.Table(6, 2)
1367 mainBox.pack_start(table, False, False, 0)
1368 table.set_row_spacings(4)
1369 table.set_col_spacings(8)
1370 table.set_homogeneous(False)
1371
1372 label = Gtk.Label("<b>" + xstr("pirepView_numPassengers") + "</b>")
1373 label.set_use_markup(True)
1374 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.5,
1375 xscale = 0.0, yscale = 0.0)
1376 alignment.add(label)
1377 table.attach(alignment, 0, 1, 0, 1)
1378
1379
1380
1381 self._flownNumPassengers = button = Gtk.SpinButton()
1382 button.set_range(min = 0, max = 300)
1383 button.set_increments(step = 1, page = 10)
1384 button.set_numeric(True)
1385 button.set_width_chars(2)
1386 button.set_alignment(1.0)
1387 button.connect("value-changed", self._updateButtons)
1388 button.set_tooltip_text(xstr("payload_pax_tooltip"))
1389
1390 self._flownNumChildren = button = Gtk.SpinButton()
1391 button.set_range(min = 0, max = 300)
1392 button.set_increments(step = 1, page = 10)
1393 button.set_numeric(True)
1394 button.set_width_chars(2)
1395 button.set_alignment(1.0)
1396 button.connect("value-changed", self._updateButtons)
1397 button.set_tooltip_text(xstr("payload_pax_children_tooltip"))
1398
1399 self._flownNumInfants = button = Gtk.SpinButton()
1400 button.set_range(min = 0, max = 300)
1401 button.set_increments(step = 1, page = 10)
1402 button.set_numeric(True)
1403 button.set_width_chars(2)
1404 button.set_alignment(1.0)
1405 button.connect("value-changed", self._updateButtons)
1406 button.set_tooltip_text(xstr("payload_pax_infants_tooltip"))
1407
1408 paxBox = Gtk.HBox()
1409 paxBox.pack_start(self._flownNumPassengers, False, False, 0)
1410 paxBox.pack_start(Gtk.Label("+"), False, False, 4)
1411 paxBox.pack_start(self._flownNumChildren, False, False, 0)
1412 paxBox.pack_start(Gtk.Label("+"), False, False, 4)
1413 paxBox.pack_start(self._flownNumInfants, False, False, 0)
1414 paxBox.set_halign(Gtk.Align.END)
1415
1416 table.attach(paxBox, 1, 4, 0, 1)
1417
1418 self._flownNumCabinCrew = \
1419 PIREPEditor.tableAttachSpinButton(table, 4, 0,
1420 xstr("pirepView_numCrew"),
1421 10)
1422 self._flownNumCabinCrew.connect("value-changed", self._updateButtons)
1423 self._flownNumCabinCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
1424
1425 self._flownBagWeight = \
1426 PIREPEditor.tableAttachSpinButton(table, 0, 1,
1427 xstr("pirepView_bagWeight"),
1428 100000, width = 6)
1429 self._flownBagWeight.connect("value-changed", self._updateButtons)
1430 self._flownBagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
1431
1432 self._flownCargoWeight = \
1433 PIREPEditor.tableAttachSpinButton(table, 2, 1,
1434 xstr("pirepView_cargoWeight"),
1435 100000, width = 6)
1436 self._flownCargoWeight.connect("value-changed", self._updateButtons)
1437 self._flownCargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
1438
1439 self._flownMailWeight = \
1440 PIREPEditor.tableAttachSpinButton(table, 4, 1,
1441 xstr("pirepView_mailWeight"),
1442 100000, width = 6)
1443 self._flownMailWeight.connect("value-changed", self._updateButtons)
1444 self._flownMailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
1445
1446 self._flightType = createFlightTypeComboBox()
1447 PIREPEditor.tableAttachWidget(table, 0, 2,
1448 xstr("pirepView_flightType"),
1449 self._flightType)
1450 self._flightType.connect("changed", self._updateButtons)
1451 self._flightType.set_tooltip_text(xstr("pirepEdit_flight_type_tooltip"))
1452
1453 self._online = Gtk.CheckButton(xstr("pirepEdit_online"))
1454 table.attach(self._online, 2, 3, 2, 3)
1455 self._online.connect("toggled", self._updateButtons)
1456 self._online.set_tooltip_text(xstr("pirepEdit_online_tooltip"))
1457
1458 PIREPViewer.addVFiller(mainBox)
1459
1460 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
1461 False, False, 0)
1462
1463 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
1464 mainBox.pack_start(textWindow, False, False, 0)
1465 self._delayCodes.set_tooltip_text(xstr("pirepEdit_delayCodes_tooltip"))
1466
1467 return frame
1468
1469 def _buildCommentsTab(self):
1470 """Build the tab with the comments and flight defects."""
1471 return FlightInfo(self._gui, callbackObject = self)
1472
1473 def _buildLogTab(self):
1474 """Build the log tab."""
1475 mainBox = Gtk.VBox()
1476
1477 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
1478 addFaultTag(self._log.get_buffer())
1479 mainBox.pack_start(logWindow, True, True, 0)
1480
1481 return mainBox
1482
1483 def _upperChanged(self, entry, arg = None):
1484 """Called when the value of some entry widget has changed and the value
1485 should be converted to uppercase."""
1486 entry.set_text(entry.get_text().upper())
1487 self._updateButtons()
1488 #self._valueChanged(entry, arg)
1489
1490 def _upperChangedComboBox(self, comboBox):
1491 """Called for combo box widgets that must be converted to uppercase."""
1492 entry = comboBox.get_child()
1493 if comboBox.get_active()==-1:
1494 entry.set_text(entry.get_text().upper())
1495 self._updateButtons()
1496 #self._valueChanged(entry)
1497
1498 def _updateButtons(self, *kwargs):
1499 """Update the activity state of the buttons."""
1500 pirep = self._pirep
1501 bookedFlight = pirep.bookedFlight
1502
1503 departureMinutes = \
1504 bookedFlight.departureTime.hour*60 + bookedFlight.departureTime.minute
1505 departureDifference = abs(Flight.getMinutesDifference(self._blockTimeStart.minutes,
1506 departureMinutes))
1507 flightStartDifference = \
1508 Flight.getMinutesDifference(self._flightTimeStart.minutes,
1509 self._blockTimeStart.minutes)
1510 arrivalMinutes = \
1511 bookedFlight.arrivalTime.hour*60 + bookedFlight.arrivalTime.minute
1512 arrivalDifference = abs(Flight.getMinutesDifference(self._blockTimeEnd.minutes,
1513 arrivalMinutes))
1514 flightEndDifference = \
1515 Flight.getMinutesDifference(self._blockTimeEnd.minutes,
1516 self._flightTimeEnd.minutes)
1517
1518 timesOK = self._flightInfo.hasComments or \
1519 self._flightInfo.hasDelayCode or \
1520 (departureDifference<=Flight.TIME_ERROR_DIFFERENCE and
1521 arrivalDifference<=Flight.TIME_ERROR_DIFFERENCE and
1522 flightStartDifference>=0 and flightStartDifference<30 and
1523 flightEndDifference>=0 and flightEndDifference<30)
1524
1525 text = self._sid.get_child().get_text()
1526 sid = text if self._sid.get_active()!=0 and text and text!="N/A" \
1527 else None
1528
1529 text = self._star.get_child().get_text()
1530 star = text if self._star.get_active()!=0 and text and text!="N/A" \
1531 else None
1532
1533 text = self._transition.get_child().get_text()
1534 transition = text if self._transition.get_active()!=0 \
1535 and text and text!="N/A" else None
1536
1537
1538 buffer = self._userRoute.get_buffer()
1539 route = buffer.get_text(buffer.get_start_iter(),
1540 buffer.get_end_iter(), True)
1541
1542 numPassengers = \
1543 self._flownNumPassengers.get_value_as_int() + \
1544 self._flownNumChildren.get_value_as_int() + \
1545 self._flownNumInfants.get_value_as_int()
1546
1547 minCabinCrew = 0 if numPassengers==0 else \
1548 (bookedFlight.maxPassengers // 50) + 1
1549
1550 self._okButton.set_sensitive(self._modified and timesOK and
1551 self._flightInfo.faultsFullyExplained and
1552 numPassengers<=bookedFlight.maxPassengers and
1553 self._flownNumCabinCrew.get_value_as_int()>=minCabinCrew and
1554 self._fuelUsed.get_value_as_int()>0 and
1555 self._departureRunway.get_text_length()>0 and
1556 self._arrivalRunway.get_text_length()>0 and
1557 self._departureMETAR.get_buffer().get_char_count()>0 and
1558 self._arrivalMETAR.get_buffer().get_char_count()>0 and
1559 self._filedCruiseLevel.get_value_as_int()>=50 and
1560 self._modifiedCruiseLevel.get_value_as_int()>=50 and
1561 sid is not None and (star is not None or
1562 transition is not None) and route!="" and
1563 self._approachType.get_text()!="")
1564
1565 def _okClicked(self, button):
1566 """Called when the OK button has been clicked.
1567
1568 The PIREP is updated from the data in the window."""
1569 if not askYesNo(xstr("pirepEdit_save_question"), parent = self):
1570 self.response(Gtk.ResponseType.CANCEL)
1571
1572 pirep = self._pirep
1573
1574 pirep.filedCruiseAltitude = \
1575 self._filedCruiseLevel.get_value_as_int() * 100
1576 pirep.cruiseAltitude = \
1577 self._modifiedCruiseLevel.get_value_as_int() * 100
1578
1579 pirep.route = getTextViewText(self._userRoute)
1580
1581 pirep.departureMETAR = getTextViewText(self._departureMETAR)
1582 pirep.departureRunway = self._departureRunway.get_text()
1583 pirep.sid = self._sid.get_child().get_text()
1584
1585 pirep.arrivalMETAR = getTextViewText(self._arrivalMETAR)
1586 pirep.star = None if self._star.get_active()==0 \
1587 else self._star.get_child().get_text()
1588 pirep.transition = None if self._transition.get_active()==0 \
1589 else self._transition.get_child().get_text()
1590 pirep.approachType = self._approachType.get_text()
1591 pirep.arrivalRunway = self._arrivalRunway.get_text()
1592
1593 pirep.blockTimeStart = \
1594 self._blockTimeStart.getTimestampFrom(pirep.blockTimeStart)
1595 pirep.blockTimeEnd = \
1596 self._blockTimeEnd.getTimestampFrom(pirep.blockTimeEnd)
1597 pirep.flightTimeStart = \
1598 self._flightTimeStart.getTimestampFrom(pirep.flightTimeStart)
1599 pirep.flightTimeEnd = \
1600 self._flightTimeEnd.getTimestampFrom(pirep.flightTimeEnd)
1601
1602 pirep.fuelUsed = self._fuelUsed.get_value()
1603
1604 pirep.numCabinCrew = self._flownNumCabinCrew.get_value()
1605 pirep.numPassengers = self._flownNumPassengers.get_value()
1606 pirep.bagWeight = self._flownBagWeight.get_value()
1607 pirep.cargoWeight = self._flownCargoWeight.get_value()
1608 pirep.mailWeight = self._flownMailWeight.get_value()
1609
1610 pirep.flightType = flightTypes[self._flightType.get_active()]
1611 pirep.online = self._online.get_active()
1612
1613 pirep.delayCodes = self._flightInfo.delayCodes
1614 pirep.comments = self._flightInfo.comments
1615 pirep.flightDefects = self._flightInfo.faultsAndExplanations
1616
1617 self.response(Gtk.ResponseType.OK)
1618
1619
1620#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.