source: src/mlx/gui/pirep.py@ 650:751fe5133670

Last change on this file since 650:751fe5133670 was 437:750a9bfbc6dd, checked in by István Váradi <ivaradi@…>, 12 years ago

The main delay code handling logic is present (re #154)

File size: 22.6 KB
Line 
1
2from common import *
3
4from mlx.pirep import PIREP
5from mlx.const import *
6
7import time
8
9#------------------------------------------------------------------------------
10
11## @package mlx.gui.pirep
12#
13# The detailed PIREP viewer.
14#
15# The \ref PIREPViewer class is a dialog displaying all information found in a
16# PIREP. It consists of three tabs. The Data tab displays the simple,
17# itemizable data. The Comments & defects tab contains the flight comments and
18# defects, while the Log tab contains the flight log collected by the
19# \ref mlx.logger.Logger "logger".
20
21#------------------------------------------------------------------------------
22
23class PIREPViewer(gtk.Dialog):
24 """The dialog for PIREP viewing."""
25 @staticmethod
26 def createFrame(label):
27 """Create a frame with the given label.
28
29 The frame will contain an alignment to properly distance the
30 insides. The alignment will contain a VBox to contain the real
31 contents.
32
33 The function returns a tuple with the following items:
34 - the frame,
35 - the inner VBox."""
36 frame = gtk.Frame(label = label)
37
38 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
39 xscale = 1.0, yscale = 1.0)
40 frame.add(alignment)
41 alignment.set_padding(padding_top = 4, padding_bottom = 4,
42 padding_left = 4, padding_right = 4)
43 box = gtk.VBox()
44 alignment.add(box)
45
46 return (frame, box)
47
48 @staticmethod
49 def getLabel(text):
50 """Get a bold label with the given text."""
51 label = gtk.Label("<b>" + text + "</b>")
52 label.set_use_markup(True)
53 label.set_alignment(0.0, 0.5)
54 return label
55
56 @staticmethod
57 def getDataLabel(width = None, xAlignment = 0.0):
58 """Get a bold label with the given text."""
59 label = gtk.Label()
60 if width is not None:
61 label.set_width_chars(width)
62 label.set_alignment(xAlignment, 0.5)
63 return label
64
65 @staticmethod
66 def getTextWindow(heightRequest = 40):
67 """Get a scrollable text window.
68
69 Returns a tuple of the following items:
70 - the window,
71 - the text view."""
72 scrolledWindow = gtk.ScrolledWindow()
73 scrolledWindow.set_shadow_type(SHADOW_IN)
74 scrolledWindow.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
75
76 textView = gtk.TextView()
77 textView.set_wrap_mode(WRAP_WORD)
78 textView.set_editable(False)
79 textView.set_cursor_visible(False)
80 textView.set_size_request(-1, heightRequest)
81 scrolledWindow.add(textView)
82
83 return (scrolledWindow, textView)
84
85 @staticmethod
86 def tableAttach(table, column, row, labelText, width = None,
87 dataLabelXAlignment = 0.0):
88 """Attach a labeled data to the given column and row of the
89 table.
90
91 If width is given, that will be the width of the data
92 label.
93
94 Returns the data label attached."""
95 dataBox = gtk.HBox()
96 table.attach(dataBox, column, column+1, row, row+1)
97
98 dataLabel = PIREPViewer.addLabeledData(dataBox, labelText,
99 width = width)
100 dataLabel.set_alignment(dataLabelXAlignment, 0.5)
101
102 return dataLabel
103
104 @staticmethod
105 def addLabeledData(hBox, labelText, width = None, dataPadding = 8):
106 """Add a label and a data label to the given HBox.
107
108 Returnsd the data label."""
109 label = PIREPViewer.getLabel(labelText)
110 hBox.pack_start(label, False, False, 0)
111
112 dataLabel = PIREPViewer.getDataLabel(width = width)
113 hBox.pack_start(dataLabel, False, False, dataPadding)
114
115 return dataLabel
116
117 @staticmethod
118 def addVFiller(vBox, height = 4):
119 """Add a filler to the given vertical box."""
120 filler = gtk.Alignment(xalign = 0.0, yalign = 0.0,
121 xscale = 1.0, yscale = 1.0)
122 filler.set_size_request(-1, height)
123 vBox.pack_start(filler, False, False, 0)
124
125 @staticmethod
126 def timestamp2text(label, timestamp):
127 """Convert the given timestamp into a text containing the hour
128 and minute in UTC and put that text into the given label."""
129 tm = time.gmtime(timestamp)
130 label.set_text("%02d:%02d" % (tm.tm_hour, tm.tm_min))
131
132 def __init__(self, gui):
133 """Construct the PIREP viewer."""
134 super(PIREPViewer, self).__init__(title = WINDOW_TITLE_BASE +
135 " - " +
136 xstr("pirepView_title"),
137 parent = gui.mainWindow)
138
139 self.set_resizable(False)
140
141 self._gui = gui
142
143 contentArea = self.get_content_area()
144
145 self._notebook = gtk.Notebook()
146 contentArea.pack_start(self._notebook, False, False, 4)
147
148 dataTab = self._buildDataTab()
149 label = gtk.Label(xstr("pirepView_tab_data"))
150 label.set_use_underline(True)
151 label.set_tooltip_text(xstr("pirepView_tab_data_tooltip"))
152 self._notebook.append_page(dataTab, label)
153
154 commentsTab = self._buildCommentsTab()
155 label = gtk.Label(xstr("pirepView_tab_comments"))
156 label.set_use_underline(True)
157 label.set_tooltip_text(xstr("pirepView_tab_comments_tooltip"))
158 self._notebook.append_page(commentsTab, label)
159
160 logTab = self._buildLogTab()
161 label = gtk.Label(xstr("pirepView_tab_log"))
162 label.set_use_underline(True)
163 label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
164 self._notebook.append_page(logTab, label)
165
166 self._okButton = self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
167 self._okButton.set_can_default(True)
168
169 def setPIREP(self, pirep):
170 """Setup the data in the dialog from the given PIREP."""
171 bookedFlight = pirep.bookedFlight
172
173 self._callsign.set_text(bookedFlight.callsign)
174 self._tailNumber.set_text(bookedFlight.tailNumber)
175 aircraftType = xstr("aircraft_" + icaoCodes[bookedFlight.aircraftType].lower())
176 self._aircraftType.set_text(aircraftType)
177
178 self._departureICAO.set_text(bookedFlight.departureICAO)
179 self._departureTime.set_text("%02d:%02d" % \
180 (bookedFlight.departureTime.hour,
181 bookedFlight.departureTime.minute))
182
183 self._arrivalICAO.set_text(bookedFlight.arrivalICAO)
184 self._arrivalTime.set_text("%02d:%02d" % \
185 (bookedFlight.arrivalTime.hour,
186 bookedFlight.arrivalTime.minute))
187
188 self._numPassengers.set_text(str(bookedFlight.numPassengers))
189 self._numCrew.set_text(str(bookedFlight.numCrew))
190 self._bagWeight.set_text(str(bookedFlight.bagWeight))
191 self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
192 self._mailWeight.set_text(str(bookedFlight.mailWeight))
193
194 self._route.get_buffer().set_text(bookedFlight.route)
195
196 self._filedCruiseLevel.set_text("FL" + str(pirep.filedCruiseAltitude/100))
197
198 if pirep.cruiseAltitude != pirep.filedCruiseAltitude:
199 self._modifiedCruiseLevel.set_text("FL" + str(pirep.cruiseAltitude/100))
200 else:
201 self._modifiedCruiseLevel.set_text("-")
202
203 self._userRoute.get_buffer().set_text(pirep.route)
204
205 self._departureMETAR.get_buffer().set_text(pirep.departureMETAR)
206
207 self._arrivalMETAR.get_buffer().set_text(pirep.arrivalMETAR)
208 self._departureRunway.set_text(pirep.departureRunway)
209 self._sid.set_text(pirep.sid)
210
211 self._star.set_text("-" if pirep.star is None else pirep.star)
212 self._transition.set_text("-" if pirep.transition is None else pirep.transition)
213 self._approachType.set_text(pirep.approachType)
214 self._arrivalRunway.set_text(pirep.arrivalRunway)
215
216 PIREPViewer.timestamp2text(self._blockTimeStart, pirep.blockTimeStart)
217 PIREPViewer.timestamp2text(self._blockTimeEnd, pirep.blockTimeEnd)
218 PIREPViewer.timestamp2text(self._flightTimeStart, pirep.flightTimeStart)
219 PIREPViewer.timestamp2text(self._flightTimeEnd, pirep.flightTimeEnd)
220
221 self._flownDistance.set_text("%.1f" % (pirep.flownDistance,))
222 self._fuelUsed.set_text("%.0f" % (pirep.fuelUsed,))
223
224 rating = pirep.rating
225 if rating<0:
226 self._rating.set_markup('<b><span foreground="red">NO GO</span></b>')
227 else:
228 self._rating.set_text("%.1f %%" % (rating,))
229
230 self._flownNumCrew.set_text("%d" % (pirep.numCrew,))
231 self._flownNumPassengers.set_text("%d" % (pirep.numPassengers,))
232 self._flownBagWeight.set_text("%.0f" % (pirep.bagWeight,))
233 self._flownCargoWeight.set_text("%.0f" % (pirep.cargoWeight,))
234 self._flownMailWeight.set_text("%.0f" % (pirep.mailWeight,))
235 self._flightType.set_text(xstr("flighttype_" +
236 flightType2string(pirep.flightType)))
237 self._online.set_text(xstr("pirepView_" +
238 ("yes" if pirep.online else "no")))
239
240 delayCodes = ""
241 for code in pirep.delayCodes:
242 if delayCodes: delayCodes += ", "
243 delayCodes += code
244
245 self._delayCodes.get_buffer().set_text(delayCodes)
246
247 self._comments.get_buffer().set_text(pirep.comments)
248 self._flightDefects.get_buffer().set_text(pirep.flightDefects)
249
250 logBuffer = self._log.get_buffer()
251 logBuffer.set_text("")
252 lineIndex = 0
253 for (timeStr, line) in pirep.logLines:
254 isFault = lineIndex in pirep.faultLineIndexes
255 appendTextBuffer(logBuffer,
256 formatFlightLogLine(timeStr, line),
257 isFault = isFault)
258 lineIndex += 1
259
260 self._notebook.set_current_page(0)
261 self._okButton.grab_default()
262
263 def _buildDataTab(self):
264 """Build the data tab of the viewer."""
265 table = gtk.Table(1, 2)
266 table.set_row_spacings(4)
267 table.set_col_spacings(16)
268 table.set_homogeneous(True)
269
270 box1 = gtk.VBox()
271 table.attach(box1, 0, 1, 0, 1)
272
273 box2 = gtk.VBox()
274 table.attach(box2, 1, 2, 0, 1)
275
276 flightFrame = self._buildFlightFrame()
277 box1.pack_start(flightFrame, False, False, 4)
278
279 routeFrame = self._buildRouteFrame()
280 box1.pack_start(routeFrame, False, False, 4)
281
282 departureFrame = self._buildDepartureFrame()
283 box2.pack_start(departureFrame, True, True, 4)
284
285 arrivalFrame = self._buildArrivalFrame()
286 box2.pack_start(arrivalFrame, True, True, 4)
287
288 statisticsFrame = self._buildStatisticsFrame()
289 box2.pack_start(statisticsFrame, False, False, 4)
290
291 miscellaneousFrame = self._buildMiscellaneousFrame()
292 box1.pack_start(miscellaneousFrame, False, False, 4)
293
294 return table
295
296 def _buildFlightFrame(self):
297 """Build the frame for the flight data."""
298
299 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
300
301 dataBox = gtk.HBox()
302 mainBox.pack_start(dataBox, False, False, 0)
303
304 self._callsign = \
305 PIREPViewer.addLabeledData(dataBox,
306 xstr("pirepView_callsign"),
307 width = 8)
308
309 self._tailNumber = \
310 PIREPViewer.addLabeledData(dataBox,
311 xstr("pirepView_tailNumber"),
312 width = 7)
313
314 PIREPViewer.addVFiller(mainBox)
315
316 dataBox = gtk.HBox()
317 mainBox.pack_start(dataBox, False, False, 0)
318
319 self._aircraftType = \
320 PIREPViewer.addLabeledData(dataBox,
321 xstr("pirepView_aircraftType"),
322 width = 25)
323
324 PIREPViewer.addVFiller(mainBox)
325
326 table = gtk.Table(3, 2)
327 mainBox.pack_start(table, False, False, 0)
328 table.set_row_spacings(4)
329 table.set_col_spacings(8)
330
331 self._departureICAO = \
332 PIREPViewer.tableAttach(table, 0, 0,
333 xstr("pirepView_departure"),
334 width = 5)
335
336 self._departureTime = \
337 PIREPViewer.tableAttach(table, 1, 0,
338 xstr("pirepView_departure_time"),
339 width = 6)
340
341 self._arrivalICAO = \
342 PIREPViewer.tableAttach(table, 0, 1,
343 xstr("pirepView_arrival"),
344 width = 5)
345
346 self._arrivalTime = \
347 PIREPViewer.tableAttach(table, 1, 1,
348 xstr("pirepView_arrival_time"),
349 width = 6)
350
351 table = gtk.Table(3, 2)
352 mainBox.pack_start(table, False, False, 0)
353 table.set_row_spacings(4)
354 table.set_col_spacings(8)
355
356 self._numPassengers = \
357 PIREPViewer.tableAttach(table, 0, 0,
358 xstr("pirepView_numPassengers"),
359 width = 4)
360
361 self._numCrew = \
362 PIREPViewer.tableAttach(table, 1, 0,
363 xstr("pirepView_numCrew"),
364 width = 3)
365
366 self._bagWeight = \
367 PIREPViewer.tableAttach(table, 0, 1,
368 xstr("pirepView_bagWeight"),
369 width = 5)
370
371 self._cargoWeight = \
372 PIREPViewer.tableAttach(table, 1, 1,
373 xstr("pirepView_cargoWeight"),
374 width = 5)
375
376 self._mailWeight = \
377 PIREPViewer.tableAttach(table, 2, 1,
378 xstr("pirepView_mailWeight"),
379 width = 5)
380
381 PIREPViewer.addVFiller(mainBox)
382
383 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
384 False, False, 0)
385
386 (routeWindow, self._route) = PIREPViewer.getTextWindow()
387 mainBox.pack_start(routeWindow, False, False, 0)
388
389 return frame
390
391 def _buildRouteFrame(self):
392 """Build the frame for the user-specified route and flight
393 level."""
394
395 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
396
397 levelBox = gtk.HBox()
398 mainBox.pack_start(levelBox, False, False, 0)
399
400 self._filedCruiseLevel = \
401 PIREPViewer.addLabeledData(levelBox,
402 xstr("pirepView_filedCruiseLevel"),
403 width = 6)
404
405 self._modifiedCruiseLevel = \
406 PIREPViewer.addLabeledData(levelBox,
407 xstr("pirepView_modifiedCruiseLevel"),
408 width = 6)
409
410 PIREPViewer.addVFiller(mainBox)
411
412 (routeWindow, self._userRoute) = PIREPViewer.getTextWindow()
413 mainBox.pack_start(routeWindow, False, False, 0)
414
415 return frame
416
417 def _buildDepartureFrame(self):
418 """Build the frame for the departure data."""
419 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
420
421 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
422 False, False, 0)
423 (metarWindow, self._departureMETAR) = \
424 PIREPViewer.getTextWindow(heightRequest = -1)
425 mainBox.pack_start(metarWindow, True, True, 0)
426
427 PIREPViewer.addVFiller(mainBox)
428
429 dataBox = gtk.HBox()
430 mainBox.pack_start(dataBox, False, False, 0)
431
432 self._departureRunway = \
433 PIREPViewer.addLabeledData(dataBox,
434 xstr("pirepView_runway"),
435 width = 5)
436
437 self._sid = \
438 PIREPViewer.addLabeledData(dataBox,
439 xstr("pirepView_sid"),
440 width = 12)
441
442 return frame
443
444 def _buildArrivalFrame(self):
445 """Build the frame for the arrival data."""
446 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
447
448 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
449 False, False, 0)
450 (metarWindow, self._arrivalMETAR) = \
451 PIREPViewer.getTextWindow(heightRequest = -1)
452 mainBox.pack_start(metarWindow, True, True, 0)
453
454 PIREPViewer.addVFiller(mainBox)
455
456 table = gtk.Table(2, 2)
457 mainBox.pack_start(table, False, False, 0)
458 table.set_row_spacings(4)
459 table.set_col_spacings(8)
460
461 self._star = \
462 PIREPViewer.tableAttach(table, 0, 0,
463 xstr("pirepView_star"),
464 width = 12)
465
466 self._transition = \
467 PIREPViewer.tableAttach(table, 1, 0,
468 xstr("pirepView_transition"),
469 width = 12)
470
471 self._approachType = \
472 PIREPViewer.tableAttach(table, 0, 1,
473 xstr("pirepView_approachType"),
474 width = 7)
475
476 self._arrivalRunway = \
477 PIREPViewer.tableAttach(table, 1, 1,
478 xstr("pirepView_runway"),
479 width = 5)
480
481 return frame
482
483 def _buildStatisticsFrame(self):
484 """Build the frame for the statistics data."""
485 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
486
487 table = gtk.Table(4, 2)
488 mainBox.pack_start(table, False, False, 0)
489 table.set_row_spacings(4)
490 table.set_col_spacings(8)
491 table.set_homogeneous(False)
492
493 self._blockTimeStart = \
494 PIREPViewer.tableAttach(table, 0, 0,
495 xstr("pirepView_blockTimeStart"),
496 width = 6)
497
498 self._blockTimeEnd = \
499 PIREPViewer.tableAttach(table, 1, 0,
500 xstr("pirepView_blockTimeEnd"),
501 width = 8)
502
503 self._flightTimeStart = \
504 PIREPViewer.tableAttach(table, 0, 1,
505 xstr("pirepView_flightTimeStart"),
506 width = 6)
507
508 self._flightTimeEnd = \
509 PIREPViewer.tableAttach(table, 1, 1,
510 xstr("pirepView_flightTimeEnd"),
511 width = 6)
512
513 self._flownDistance = \
514 PIREPViewer.tableAttach(table, 0, 2,
515 xstr("pirepView_flownDistance"),
516 width = 8)
517
518 self._fuelUsed = \
519 PIREPViewer.tableAttach(table, 1, 2,
520 xstr("pirepView_fuelUsed"),
521 width = 6)
522
523 self._rating = \
524 PIREPViewer.tableAttach(table, 0, 3,
525 xstr("pirepView_rating"),
526 width = 7)
527 return frame
528
529 def _buildMiscellaneousFrame(self):
530 """Build the frame for the miscellaneous data."""
531 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
532
533 table = gtk.Table(3, 2)
534 mainBox.pack_start(table, False, False, 0)
535 table.set_row_spacings(4)
536 table.set_col_spacings(8)
537
538 self._flownNumPassengers = \
539 PIREPViewer.tableAttach(table, 0, 0,
540 xstr("pirepView_numPassengers"),
541 width = 4)
542
543 self._flownNumCrew = \
544 PIREPViewer.tableAttach(table, 1, 0,
545 xstr("pirepView_numCrew"),
546 width = 3)
547
548 self._flownBagWeight = \
549 PIREPViewer.tableAttach(table, 0, 1,
550 xstr("pirepView_bagWeight"),
551 width = 5)
552
553 self._flownCargoWeight = \
554 PIREPViewer.tableAttach(table, 1, 1,
555 xstr("pirepView_cargoWeight"),
556 width = 6)
557
558 self._flownMailWeight = \
559 PIREPViewer.tableAttach(table, 2, 1,
560 xstr("pirepView_mailWeight"),
561 width = 5)
562
563 self._flightType = \
564 PIREPViewer.tableAttach(table, 0, 2,
565 xstr("pirepView_flightType"),
566 width = 15)
567
568 self._online = \
569 PIREPViewer.tableAttach(table, 1, 2,
570 xstr("pirepView_online"),
571 width = 5)
572
573 PIREPViewer.addVFiller(mainBox)
574
575 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
576 False, False, 0)
577
578 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
579 mainBox.pack_start(textWindow, False, False, 0)
580
581 return frame
582
583 def _buildCommentsTab(self):
584 """Build the tab with the comments and flight defects."""
585 table = gtk.Table(2, 1)
586 table.set_col_spacings(16)
587
588 (frame, commentsBox) = \
589 PIREPViewer.createFrame(xstr("pirepView_comments"))
590 table.attach(frame, 0, 1, 0, 1)
591
592 (commentsWindow, self._comments) = \
593 PIREPViewer.getTextWindow(heightRequest = -1)
594 commentsBox.pack_start(commentsWindow, True, True, 0)
595
596 (frame, flightDefectsBox) = \
597 PIREPViewer.createFrame(xstr("pirepView_flightDefects"))
598 table.attach(frame, 1, 2, 0, 1)
599
600 (flightDefectsWindow, self._flightDefects) = \
601 PIREPViewer.getTextWindow(heightRequest = -1)
602 flightDefectsBox.pack_start(flightDefectsWindow, True, True, 0)
603
604 return table
605
606 def _buildLogTab(self):
607 """Build the log tab."""
608 mainBox = gtk.VBox()
609
610 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
611 addFaultTag(self._log.get_buffer())
612 mainBox.pack_start(logWindow, True, True, 0)
613
614 return mainBox
615
616#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.