source: src/mlx/gui/pirep.py@ 1092:f3c535a548c2

python3
Last change on this file since 1092:f3c535a548c2 was 1079:bfa2f7d95934, checked in by István Váradi <ivaradi@…>, 21 months ago

The PIREP message viewer's size is determined automatically

File size: 62.2 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, -1)
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.bookedFlight.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_text(xstr("flighttype_" +
959 flightType2string(pirep.bookedFlight.flightType)))
960 self._online.set_active(pirep.online)
961
962 self._flightInfo.reset()
963 self._flightInfo.enable(bookedFlight.aircraftType)
964
965 delayCodes = ""
966 for code in pirep.delayCodes:
967 if delayCodes: delayCodes += ", "
968 delayCodes += code
969 m = PIREPEditor._delayCodeRE.match(code)
970 if m:
971 self._flightInfo.activateDelayCode(m.group(1))
972
973 self._delayCodes.get_buffer().set_text(delayCodes)
974
975 self._flightInfo.comments = pirep.comments
976 if pirep.flightDefects.find("<br/></b>")!=-1:
977 flightDefects = pirep.flightDefects.split("<br/></b>")
978 caption = flightDefects[0]
979 index = 0
980 for defect in flightDefects[1:]:
981 if defect.find("<b>")!=-1:
982 (explanation, nextCaption) = defect.split("<b>")
983 else:
984 explanation = defect
985 nextCaption = None
986 self._flightInfo.addFault(index, caption)
987 self._flightInfo.setExplanation(index, explanation)
988 index += 1
989 caption = nextCaption
990
991 # self._comments.get_buffer().set_text(pirep.comments)
992 # self._flightDefects.get_buffer().set_text(pirep.flightDefects)
993
994 logBuffer = self._log.get_buffer()
995 logBuffer.set_text("")
996 lineIndex = 0
997 for (timeStr, line) in pirep.logLines:
998 isFault = lineIndex in pirep.faultLineIndexes
999 appendTextBuffer(logBuffer,
1000 formatFlightLogLine(timeStr, line),
1001 isFault = isFault)
1002 lineIndex += 1
1003
1004 self._notebook.set_current_page(0)
1005 self._okButton.grab_default()
1006
1007 self._modified = False
1008 self._updateButtons()
1009 self._modified = True
1010 self._toSave = False
1011
1012 def delayCodesChanged(self):
1013 """Called when the delay codes have changed."""
1014 self._updateButtons()
1015
1016 def commentsChanged(self):
1017 """Called when the comments have changed."""
1018 self._updateButtons()
1019
1020 def faultExplanationsChanged(self):
1021 """Called when the fault explanations have changed."""
1022 self._updateButtons()
1023
1024 def _buildDataTab(self):
1025 """Build the data tab of the viewer."""
1026 table = Gtk.Table(1, 2)
1027 table.set_row_spacings(4)
1028 table.set_col_spacings(16)
1029 table.set_homogeneous(True)
1030
1031 box1 = Gtk.VBox()
1032 table.attach(box1, 0, 1, 0, 1)
1033
1034 box2 = Gtk.VBox()
1035 table.attach(box2, 1, 2, 0, 1)
1036
1037 flightFrame = self._buildFlightFrame()
1038 box1.pack_start(flightFrame, False, False, 4)
1039
1040 routeFrame = self._buildRouteFrame()
1041 box1.pack_start(routeFrame, False, False, 4)
1042
1043 departureFrame = self._buildDepartureFrame()
1044 box2.pack_start(departureFrame, True, True, 4)
1045
1046 arrivalFrame = self._buildArrivalFrame()
1047 box2.pack_start(arrivalFrame, True, True, 4)
1048
1049 statisticsFrame = self._buildStatisticsFrame()
1050 box2.pack_start(statisticsFrame, False, False, 4)
1051
1052 miscellaneousFrame = self._buildMiscellaneousFrame()
1053 box1.pack_start(miscellaneousFrame, False, False, 4)
1054
1055 return table
1056
1057 def _buildFlightFrame(self):
1058 """Build the frame for the flight data."""
1059
1060 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
1061
1062 dataBox = Gtk.HBox()
1063 mainBox.pack_start(dataBox, False, False, 0)
1064
1065 self._callsign = \
1066 PIREPViewer.addLabeledData(dataBox,
1067 xstr("pirepView_callsign"),
1068 width = 8)
1069
1070 self._tailNumber = \
1071 PIREPViewer.addLabeledData(dataBox,
1072 xstr("pirepView_tailNumber"),
1073 width = 7)
1074
1075 PIREPViewer.addVFiller(mainBox)
1076
1077 dataBox = Gtk.HBox()
1078 mainBox.pack_start(dataBox, False, False, 0)
1079
1080 self._aircraftType = \
1081 PIREPViewer.addLabeledData(dataBox,
1082 xstr("pirepView_aircraftType"),
1083 width = 25)
1084
1085 PIREPViewer.addVFiller(mainBox)
1086
1087 table = Gtk.Table(3, 2)
1088 mainBox.pack_start(table, False, False, 0)
1089 table.set_row_spacings(4)
1090 table.set_col_spacings(8)
1091
1092 self._departureICAO = \
1093 PIREPViewer.tableAttach(table, 0, 0,
1094 xstr("pirepView_departure"),
1095 width = 5)
1096
1097 self._departureTime = \
1098 PIREPViewer.tableAttach(table, 1, 0,
1099 xstr("pirepView_departure_time"),
1100 width = 6)
1101
1102 self._arrivalICAO = \
1103 PIREPViewer.tableAttach(table, 0, 1,
1104 xstr("pirepView_arrival"),
1105 width = 5)
1106
1107 self._arrivalTime = \
1108 PIREPViewer.tableAttach(table, 1, 1,
1109 xstr("pirepView_arrival_time"),
1110 width = 6)
1111
1112 table = Gtk.Table(3, 2)
1113 mainBox.pack_start(table, False, False, 0)
1114 table.set_row_spacings(4)
1115 table.set_col_spacings(8)
1116
1117 self._numPassengers = \
1118 PIREPViewer.tableAttach(table, 0, 0,
1119 xstr("pirepView_numPassengers"),
1120 width = 4)
1121 self._numCrew = \
1122 PIREPViewer.tableAttach(table, 1, 0,
1123 xstr("pirepView_numCrew"),
1124 width = 3)
1125
1126 self._bagWeight = \
1127 PIREPViewer.tableAttach(table, 0, 1,
1128 xstr("pirepView_bagWeight"),
1129 width = 5)
1130
1131 self._cargoWeight = \
1132 PIREPViewer.tableAttach(table, 1, 1,
1133 xstr("pirepView_cargoWeight"),
1134 width = 5)
1135
1136 self._mailWeight = \
1137 PIREPViewer.tableAttach(table, 2, 1,
1138 xstr("pirepView_mailWeight"),
1139 width = 5)
1140
1141 PIREPViewer.addVFiller(mainBox)
1142
1143 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
1144 False, False, 0)
1145
1146 (routeWindow, self._route) = PIREPViewer.getTextWindow()
1147 mainBox.pack_start(routeWindow, False, False, 0)
1148
1149 return frame
1150
1151 def _buildRouteFrame(self):
1152 """Build the frame for the user-specified route and flight
1153 level."""
1154
1155 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
1156
1157 levelBox = Gtk.HBox()
1158 mainBox.pack_start(levelBox, False, False, 0)
1159
1160 label = PIREPViewer.getLabel(xstr("pirepView_filedCruiseLevel"),
1161 xstr("pirepEdit_FL"))
1162 levelBox.pack_start(label, False, False, 0)
1163
1164 self._filedCruiseLevel = Gtk.SpinButton()
1165 self._filedCruiseLevel.set_increments(step = 10, page = 100)
1166 self._filedCruiseLevel.set_range(min = 0, max = 500)
1167 self._filedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
1168 self._filedCruiseLevel.set_numeric(True)
1169 self._filedCruiseLevel.connect("value-changed", self._updateButtons)
1170
1171 levelBox.pack_start(self._filedCruiseLevel, False, False, 0)
1172
1173 PIREPViewer.addHFiller(levelBox)
1174
1175 label = PIREPViewer.getLabel(xstr("pirepView_modifiedCruiseLevel"),
1176 xstr("pirepEdit_FL"))
1177 levelBox.pack_start(label, False, False, 0)
1178
1179 self._modifiedCruiseLevel = Gtk.SpinButton()
1180 self._modifiedCruiseLevel.set_increments(step = 10, page = 100)
1181 self._modifiedCruiseLevel.set_range(min = 0, max = 500)
1182 self._modifiedCruiseLevel.set_tooltip_text(xstr("pirepEdit_modified_route_level_tooltip"))
1183 self._modifiedCruiseLevel.set_numeric(True)
1184 self._modifiedCruiseLevel.connect("value-changed", self._updateButtons)
1185
1186 levelBox.pack_start(self._modifiedCruiseLevel, False, False, 0)
1187
1188 PIREPViewer.addVFiller(mainBox)
1189
1190 (routeWindow, self._userRoute) = \
1191 PIREPViewer.getTextWindow(editable = True)
1192 mainBox.pack_start(routeWindow, False, False, 0)
1193 self._userRoute.get_buffer().connect("changed", self._updateButtons)
1194 self._userRoute.set_tooltip_text(xstr("route_route_tooltip"))
1195
1196 return frame
1197
1198 def _buildDepartureFrame(self):
1199 """Build the frame for the departure data."""
1200 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
1201
1202 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1203 False, False, 0)
1204 (metarWindow, self._departureMETAR) = \
1205 PIREPViewer.getTextWindow(heightRequest = -1,
1206 editable = True)
1207 self._departureMETAR.get_buffer().connect("changed", self._updateButtons)
1208 self._departureMETAR.set_tooltip_text(xstr("takeoff_metar_tooltip"))
1209 mainBox.pack_start(metarWindow, True, True, 0)
1210
1211 PIREPViewer.addVFiller(mainBox)
1212
1213 dataBox = Gtk.HBox()
1214 mainBox.pack_start(dataBox, False, False, 0)
1215
1216 label = Gtk.Label("<b>" + xstr("pirepView_runway") + "</b>")
1217 label.set_use_markup(True)
1218 dataBox.pack_start(label, False, False, 0)
1219
1220 # FIXME: quite the same as the runway entry boxes in the wizard
1221 self._departureRunway = Gtk.Entry()
1222 self._departureRunway.set_width_chars(5)
1223 self._departureRunway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
1224 self._departureRunway.connect("changed", self._upperChanged)
1225 dataBox.pack_start(self._departureRunway, False, False, 8)
1226
1227 label = Gtk.Label("<b>" + xstr("pirepView_sid") + "</b>")
1228 label.set_use_markup(True)
1229 dataBox.pack_start(label, False, False, 0)
1230
1231 # FIXME: quite the same as the SID combo box in
1232 # the flight wizard
1233 self._sid = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1234
1235 self._sid.set_entry_text_column(0)
1236 self._sid.get_child().set_width_chars(10)
1237 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
1238 self._sid.connect("changed", self._upperChangedComboBox)
1239
1240 dataBox.pack_start(self._sid, False, False, 8)
1241
1242 return frame
1243
1244 def _buildArrivalFrame(self):
1245 """Build the frame for the arrival data."""
1246 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
1247
1248 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1249 False, False, 0)
1250 (metarWindow, self._arrivalMETAR) = \
1251 PIREPViewer.getTextWindow(heightRequest = -1,
1252 editable = True)
1253 self._arrivalMETAR.get_buffer().connect("changed", self._updateButtons)
1254 self._arrivalMETAR.set_tooltip_text(xstr("landing_metar_tooltip"))
1255 mainBox.pack_start(metarWindow, True, True, 0)
1256
1257 PIREPViewer.addVFiller(mainBox)
1258
1259 table = Gtk.Table(2, 4)
1260 mainBox.pack_start(table, False, False, 0)
1261 table.set_row_spacings(4)
1262 table.set_col_spacings(8)
1263
1264 # FIXME: quite the same as in the wizard
1265 self._star = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1266
1267 self._star.set_entry_text_column(0)
1268 self._star.get_child().set_width_chars(10)
1269 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
1270 self._star.connect("changed", self._upperChangedComboBox)
1271
1272 PIREPEditor.tableAttachWidget(table, 0, 0,
1273 xstr("pirepView_star"),
1274 self._star)
1275
1276 # FIXME: quite the same as in the wizard
1277 self._transition = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1278
1279 self._transition.set_entry_text_column(0)
1280 self._transition.get_child().set_width_chars(10)
1281 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
1282 self._transition.connect("changed", self._upperChangedComboBox)
1283
1284 PIREPEditor.tableAttachWidget(table, 2, 0,
1285 xstr("pirepView_transition"),
1286 self._transition)
1287
1288
1289 # FIXME: quite the same as in the wizard
1290 self._approachType = Gtk.Entry()
1291 self._approachType.set_width_chars(10)
1292 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
1293 self._approachType.connect("changed", self._upperChanged)
1294
1295 PIREPEditor.tableAttachWidget(table, 0, 1,
1296 xstr("pirepView_approachType"),
1297 self._approachType)
1298
1299 # FIXME: quite the same as in the wizard
1300 self._arrivalRunway = Gtk.Entry()
1301 self._arrivalRunway.set_width_chars(10)
1302 self._arrivalRunway.set_tooltip_text(xstr("landing_runway_tooltip"))
1303 self._arrivalRunway.connect("changed", self._upperChanged)
1304
1305 PIREPEditor.tableAttachWidget(table, 2, 1,
1306 xstr("pirepView_runway"),
1307 self._arrivalRunway)
1308
1309 return frame
1310
1311 def _buildStatisticsFrame(self):
1312 """Build the frame for the statistics data."""
1313 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
1314
1315 table = Gtk.Table(4, 4)
1316 mainBox.pack_start(table, False, False, 0)
1317 table.set_row_spacings(4)
1318 table.set_col_spacings(8)
1319 table.set_homogeneous(False)
1320
1321 self._blockTimeStart = \
1322 PIREPEditor.tableAttachTimeEntry(table, 0, 0,
1323 xstr("pirepView_blockTimeStart"))
1324 self._blockTimeStart.connect("changed", self._updateButtons)
1325 self._blockTimeStart.set_tooltip_text(xstr("pirepEdit_block_time_start_tooltip"))
1326
1327 self._blockTimeEnd = \
1328 PIREPEditor.tableAttachTimeEntry(table, 2, 0,
1329 xstr("pirepView_blockTimeEnd"))
1330 self._blockTimeEnd.connect("changed", self._updateButtons)
1331 self._blockTimeEnd.set_tooltip_text(xstr("pirepEdit_block_time_end_tooltip"))
1332
1333 self._flightTimeStart = \
1334 PIREPEditor.tableAttachTimeEntry(table, 0, 1,
1335 xstr("pirepView_flightTimeStart"))
1336 self._flightTimeStart.connect("changed", self._updateButtons)
1337 self._flightTimeStart.set_tooltip_text(xstr("pirepEdit_flight_time_start_tooltip"))
1338
1339 self._flightTimeEnd = \
1340 PIREPEditor.tableAttachTimeEntry(table, 2, 1,
1341 xstr("pirepView_flightTimeEnd"))
1342 self._flightTimeEnd.connect("changed", self._updateButtons)
1343 self._flightTimeEnd.set_tooltip_text(xstr("pirepEdit_flight_time_end_tooltip"))
1344
1345 self._flownDistance = PIREPViewer.getDataLabel(width = 3)
1346 PIREPEditor.tableAttachWidget(table, 0, 2,
1347 xstr("pirepView_flownDistance"),
1348 self._flownDistance)
1349
1350 self._fuelUsed = \
1351 PIREPEditor.tableAttachSpinButton(table, 2, 2,
1352 xstr("pirepView_fuelUsed"),
1353 1000000)
1354 self._fuelUsed.connect("value-changed", self._updateButtons)
1355 self._fuelUsed.set_tooltip_text(xstr("pirepEdit_fuel_used_tooltip"))
1356
1357 self._rating = PIREPViewer.getDataLabel(width = 3)
1358 PIREPEditor.tableAttachWidget(table, 0, 3,
1359 xstr("pirepView_rating"),
1360 self._rating)
1361 return frame
1362
1363 def _buildMiscellaneousFrame(self):
1364 """Build the frame for the miscellaneous data."""
1365 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
1366
1367 table = Gtk.Table(6, 2)
1368 mainBox.pack_start(table, False, False, 0)
1369 table.set_row_spacings(4)
1370 table.set_col_spacings(8)
1371 table.set_homogeneous(False)
1372
1373 label = Gtk.Label("<b>" + xstr("pirepView_numPassengers") + "</b>")
1374 label.set_use_markup(True)
1375 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.5,
1376 xscale = 0.0, yscale = 0.0)
1377 alignment.add(label)
1378 table.attach(alignment, 0, 1, 0, 1)
1379
1380
1381
1382 self._flownNumPassengers = button = Gtk.SpinButton()
1383 button.set_range(min = 0, max = 300)
1384 button.set_increments(step = 1, page = 10)
1385 button.set_numeric(True)
1386 button.set_width_chars(2)
1387 button.set_alignment(1.0)
1388 button.connect("value-changed", self._updateButtons)
1389 button.set_tooltip_text(xstr("payload_pax_tooltip"))
1390
1391 self._flownNumChildren = button = Gtk.SpinButton()
1392 button.set_range(min = 0, max = 300)
1393 button.set_increments(step = 1, page = 10)
1394 button.set_numeric(True)
1395 button.set_width_chars(2)
1396 button.set_alignment(1.0)
1397 button.connect("value-changed", self._updateButtons)
1398 button.set_tooltip_text(xstr("payload_pax_children_tooltip"))
1399
1400 self._flownNumInfants = button = Gtk.SpinButton()
1401 button.set_range(min = 0, max = 300)
1402 button.set_increments(step = 1, page = 10)
1403 button.set_numeric(True)
1404 button.set_width_chars(2)
1405 button.set_alignment(1.0)
1406 button.connect("value-changed", self._updateButtons)
1407 button.set_tooltip_text(xstr("payload_pax_infants_tooltip"))
1408
1409 paxBox = Gtk.HBox()
1410 paxBox.pack_start(self._flownNumPassengers, False, False, 0)
1411 paxBox.pack_start(Gtk.Label("+"), False, False, 4)
1412 paxBox.pack_start(self._flownNumChildren, False, False, 0)
1413 paxBox.pack_start(Gtk.Label("+"), False, False, 4)
1414 paxBox.pack_start(self._flownNumInfants, False, False, 0)
1415 paxBox.set_halign(Gtk.Align.END)
1416
1417 table.attach(paxBox, 1, 4, 0, 1)
1418
1419 self._flownNumCabinCrew = \
1420 PIREPEditor.tableAttachSpinButton(table, 4, 0,
1421 xstr("pirepView_numCrew"),
1422 10)
1423 self._flownNumCabinCrew.connect("value-changed", self._updateButtons)
1424 self._flownNumCabinCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
1425
1426 self._flownBagWeight = \
1427 PIREPEditor.tableAttachSpinButton(table, 0, 1,
1428 xstr("pirepView_bagWeight"),
1429 100000, width = 6)
1430 self._flownBagWeight.connect("value-changed", self._updateButtons)
1431 self._flownBagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
1432
1433 self._flownCargoWeight = \
1434 PIREPEditor.tableAttachSpinButton(table, 2, 1,
1435 xstr("pirepView_cargoWeight"),
1436 100000, width = 6)
1437 self._flownCargoWeight.connect("value-changed", self._updateButtons)
1438 self._flownCargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
1439
1440 self._flownMailWeight = \
1441 PIREPEditor.tableAttachSpinButton(table, 4, 1,
1442 xstr("pirepView_mailWeight"),
1443 100000, width = 6)
1444 self._flownMailWeight.connect("value-changed", self._updateButtons)
1445 self._flownMailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
1446
1447 self._flightType = PIREPViewer.getDataLabel(width = 3)
1448 PIREPEditor.tableAttachWidget(table, 0, 2,
1449 xstr("pirepView_flightType"),
1450 self._flightType)
1451
1452 self._online = Gtk.CheckButton(xstr("pirepEdit_online"))
1453 table.attach(self._online, 2, 3, 2, 3)
1454 self._online.connect("toggled", self._updateButtons)
1455 self._online.set_tooltip_text(xstr("pirepEdit_online_tooltip"))
1456
1457 PIREPViewer.addVFiller(mainBox)
1458
1459 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
1460 False, False, 0)
1461
1462 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
1463 mainBox.pack_start(textWindow, False, False, 0)
1464 self._delayCodes.set_tooltip_text(xstr("pirepEdit_delayCodes_tooltip"))
1465
1466 return frame
1467
1468 def _buildCommentsTab(self):
1469 """Build the tab with the comments and flight defects."""
1470 return FlightInfo(self._gui, callbackObject = self)
1471
1472 def _buildLogTab(self):
1473 """Build the log tab."""
1474 mainBox = Gtk.VBox()
1475
1476 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
1477 addFaultTag(self._log.get_buffer())
1478 mainBox.pack_start(logWindow, True, True, 0)
1479
1480 return mainBox
1481
1482 def _upperChanged(self, entry, arg = None):
1483 """Called when the value of some entry widget has changed and the value
1484 should be converted to uppercase."""
1485 entry.set_text(entry.get_text().upper())
1486 self._updateButtons()
1487 #self._valueChanged(entry, arg)
1488
1489 def _upperChangedComboBox(self, comboBox):
1490 """Called for combo box widgets that must be converted to uppercase."""
1491 entry = comboBox.get_child()
1492 if comboBox.get_active()==-1:
1493 entry.set_text(entry.get_text().upper())
1494 self._updateButtons()
1495 #self._valueChanged(entry)
1496
1497 def _updateButtons(self, *kwargs):
1498 """Update the activity state of the buttons."""
1499 pirep = self._pirep
1500 bookedFlight = pirep.bookedFlight
1501
1502 departureMinutes = \
1503 bookedFlight.departureTime.hour*60 + bookedFlight.departureTime.minute
1504 departureDifference = abs(Flight.getMinutesDifference(self._blockTimeStart.minutes,
1505 departureMinutes))
1506 flightStartDifference = \
1507 Flight.getMinutesDifference(self._flightTimeStart.minutes,
1508 self._blockTimeStart.minutes)
1509 arrivalMinutes = \
1510 bookedFlight.arrivalTime.hour*60 + bookedFlight.arrivalTime.minute
1511 arrivalDifference = abs(Flight.getMinutesDifference(self._blockTimeEnd.minutes,
1512 arrivalMinutes))
1513 flightEndDifference = \
1514 Flight.getMinutesDifference(self._blockTimeEnd.minutes,
1515 self._flightTimeEnd.minutes)
1516
1517 timesOK = self._flightInfo.hasComments or \
1518 self._flightInfo.hasDelayCode or \
1519 (departureDifference<=Flight.TIME_ERROR_DIFFERENCE and
1520 arrivalDifference<=Flight.TIME_ERROR_DIFFERENCE and
1521 flightStartDifference>=0 and flightStartDifference<30 and
1522 flightEndDifference>=0 and flightEndDifference<30)
1523
1524 text = self._sid.get_child().get_text()
1525 sid = text if self._sid.get_active()!=0 and text and text!="N/A" \
1526 else None
1527
1528 text = self._star.get_child().get_text()
1529 star = text if self._star.get_active()!=0 and text and text!="N/A" \
1530 else None
1531
1532 text = self._transition.get_child().get_text()
1533 transition = text if self._transition.get_active()!=0 \
1534 and text and text!="N/A" else None
1535
1536
1537 buffer = self._userRoute.get_buffer()
1538 route = buffer.get_text(buffer.get_start_iter(),
1539 buffer.get_end_iter(), True)
1540
1541 numPassengers = \
1542 self._flownNumPassengers.get_value_as_int() + \
1543 self._flownNumChildren.get_value_as_int() + \
1544 self._flownNumInfants.get_value_as_int()
1545
1546 minCabinCrew = 0 if numPassengers==0 else \
1547 (bookedFlight.maxPassengers // 50) + 1
1548
1549 self._okButton.set_sensitive(self._modified and timesOK and
1550 self._flightInfo.faultsFullyExplained and
1551 numPassengers<=bookedFlight.maxPassengers and
1552 self._flownNumCabinCrew.get_value_as_int()>=minCabinCrew and
1553 self._fuelUsed.get_value_as_int()>0 and
1554 self._departureRunway.get_text_length()>0 and
1555 self._arrivalRunway.get_text_length()>0 and
1556 self._departureMETAR.get_buffer().get_char_count()>0 and
1557 self._arrivalMETAR.get_buffer().get_char_count()>0 and
1558 self._filedCruiseLevel.get_value_as_int()>=50 and
1559 self._modifiedCruiseLevel.get_value_as_int()>=50 and
1560 sid is not None and (star is not None or
1561 transition is not None) and route!="" and
1562 self._approachType.get_text()!="")
1563
1564 def _okClicked(self, button):
1565 """Called when the OK button has been clicked.
1566
1567 The PIREP is updated from the data in the window."""
1568 if not askYesNo(xstr("pirepEdit_save_question"), parent = self):
1569 self.response(Gtk.ResponseType.CANCEL)
1570
1571 pirep = self._pirep
1572
1573 pirep.filedCruiseAltitude = \
1574 self._filedCruiseLevel.get_value_as_int() * 100
1575 pirep.cruiseAltitude = \
1576 self._modifiedCruiseLevel.get_value_as_int() * 100
1577
1578 pirep.route = getTextViewText(self._userRoute)
1579
1580 pirep.departureMETAR = getTextViewText(self._departureMETAR)
1581 pirep.departureRunway = self._departureRunway.get_text()
1582 pirep.sid = self._sid.get_child().get_text()
1583
1584 pirep.arrivalMETAR = getTextViewText(self._arrivalMETAR)
1585 pirep.star = None if self._star.get_active()==0 \
1586 else self._star.get_child().get_text()
1587 pirep.transition = None if self._transition.get_active()==0 \
1588 else self._transition.get_child().get_text()
1589 pirep.approachType = self._approachType.get_text()
1590 pirep.arrivalRunway = self._arrivalRunway.get_text()
1591
1592 pirep.blockTimeStart = \
1593 self._blockTimeStart.getTimestampFrom(pirep.blockTimeStart)
1594 pirep.blockTimeEnd = \
1595 self._blockTimeEnd.getTimestampFrom(pirep.blockTimeEnd)
1596 pirep.flightTimeStart = \
1597 self._flightTimeStart.getTimestampFrom(pirep.flightTimeStart)
1598 pirep.flightTimeEnd = \
1599 self._flightTimeEnd.getTimestampFrom(pirep.flightTimeEnd)
1600
1601 pirep.fuelUsed = self._fuelUsed.get_value()
1602
1603 pirep.numCabinCrew = self._flownNumCabinCrew.get_value()
1604 pirep.numPassengers = self._flownNumPassengers.get_value()
1605 pirep.bagWeight = self._flownBagWeight.get_value()
1606 pirep.cargoWeight = self._flownCargoWeight.get_value()
1607 pirep.mailWeight = self._flownMailWeight.get_value()
1608
1609 pirep.online = self._online.get_active()
1610
1611 pirep.delayCodes = self._flightInfo.delayCodes
1612 pirep.comments = self._flightInfo.comments
1613 pirep.flightDefects = self._flightInfo.faultsAndExplanations
1614
1615 self.response(Gtk.ResponseType.OK)
1616
1617
1618#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.