source: src/mlx/gui/pirep.py@ 845:9f492b8e735f

Last change on this file since 845:9f492b8e735f was 845:9f492b8e735f, checked in by István Váradi <ivaradi@…>, 7 years ago

All data can be edited in the PIREP editor widget (re #307)

File size: 46.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.const import *
9
10import time
11import re
12
13#------------------------------------------------------------------------------
14
15## @package mlx.gui.pirep
16#
17# The detailed PIREP viewer and editor windows.
18#
19# The \ref PIREPViewer class is a dialog displaying all information found in a
20# PIREP. It consists of three tabs. The Data tab displays the simple,
21# itemizable data. The Comments & defects tab contains the flight comments and
22# defects, while the Log tab contains the flight log collected by the
23# \ref mlx.logger.Logger "logger".
24
25#------------------------------------------------------------------------------
26
27class PIREPViewer(gtk.Dialog):
28 """The dialog for PIREP viewing."""
29 @staticmethod
30 def createFrame(label):
31 """Create a frame with the given label.
32
33 The frame will contain an alignment to properly distance the
34 insides. The alignment will contain a VBox to contain the real
35 contents.
36
37 The function returns a tuple with the following items:
38 - the frame,
39 - the inner VBox."""
40 frame = gtk.Frame(label = label)
41
42 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
43 xscale = 1.0, yscale = 1.0)
44 frame.add(alignment)
45 alignment.set_padding(padding_top = 4, padding_bottom = 4,
46 padding_left = 4, padding_right = 4)
47 box = gtk.VBox()
48 alignment.add(box)
49
50 return (frame, box)
51
52 @staticmethod
53 def getLabel(text, extraText = ""):
54 """Get a bold label with the given text."""
55 label = gtk.Label("<b>" + text + "</b>" + extraText)
56 label.set_use_markup(True)
57 label.set_alignment(0.0, 0.5)
58 return label
59
60 @staticmethod
61 def getDataLabel(width = None, xAlignment = 0.0):
62 """Get a bold label with the given text."""
63 label = gtk.Label()
64 if width is not None:
65 label.set_width_chars(width)
66 label.set_alignment(xAlignment, 0.5)
67 return label
68
69 @staticmethod
70 def getTextWindow(heightRequest = 40, editable = False):
71 """Get a scrollable text window.
72
73 Returns a tuple of the following items:
74 - the window,
75 - the text view."""
76 scrolledWindow = gtk.ScrolledWindow()
77 scrolledWindow.set_shadow_type(SHADOW_IN)
78 scrolledWindow.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
79
80 textView = gtk.TextView()
81 textView.set_wrap_mode(WRAP_WORD)
82 textView.set_editable(editable)
83 textView.set_cursor_visible(editable)
84 textView.set_size_request(-1, heightRequest)
85 scrolledWindow.add(textView)
86
87 return (scrolledWindow, textView)
88
89 @staticmethod
90 def tableAttach(table, column, row, labelText, width = None,
91 dataLabelXAlignment = 0.0):
92 """Attach a labeled data to the given column and row of the
93 table.
94
95 If width is given, that will be the width of the data
96 label.
97
98 Returns the data label attached."""
99 dataBox = gtk.HBox()
100 table.attach(dataBox, column, column+1, row, row+1)
101
102 dataLabel = PIREPViewer.addLabeledData(dataBox, labelText,
103 width = width)
104 dataLabel.set_alignment(dataLabelXAlignment, 0.5)
105
106 return dataLabel
107
108 @staticmethod
109 def addLabeledData(hBox, labelText, width = None, dataPadding = 8):
110 """Add a label and a data label to the given HBox.
111
112 Returns the data label."""
113 label = PIREPViewer.getLabel(labelText)
114 hBox.pack_start(label, False, False, 0)
115
116 dataLabel = PIREPViewer.getDataLabel(width = width)
117 hBox.pack_start(dataLabel, False, False, dataPadding)
118
119 return dataLabel
120
121 @staticmethod
122 def addHFiller(hBox, width = 8):
123 """Add a filler to the given horizontal box."""
124 filler = gtk.Alignment(xalign = 0.0, yalign = 0.0,
125 xscale = 1.0, yscale = 1.0)
126 filler.set_size_request(width, -1)
127 hBox.pack_start(filler, False, False, 0)
128
129 @staticmethod
130 def addVFiller(vBox, height = 4):
131 """Add a filler to the given vertical box."""
132 filler = gtk.Alignment(xalign = 0.0, yalign = 0.0,
133 xscale = 1.0, yscale = 1.0)
134 filler.set_size_request(-1, height)
135 vBox.pack_start(filler, False, False, 0)
136
137 @staticmethod
138 def timestamp2text(label, timestamp):
139 """Convert the given timestamp into a text containing the hour
140 and minute in UTC and put that text into the given label."""
141 tm = time.gmtime(timestamp)
142 label.set_text("%02d:%02d" % (tm.tm_hour, tm.tm_min))
143
144 def __init__(self, gui):
145 """Construct the PIREP viewer."""
146 super(PIREPViewer, self).__init__(title = WINDOW_TITLE_BASE +
147 " - " +
148 xstr("pirepView_title"),
149 parent = gui.mainWindow)
150
151 self.set_resizable(False)
152
153 self._gui = gui
154
155 contentArea = self.get_content_area()
156
157 self._notebook = gtk.Notebook()
158 contentArea.pack_start(self._notebook, False, False, 4)
159
160 dataTab = self._buildDataTab()
161 label = gtk.Label(xstr("pirepView_tab_data"))
162 label.set_use_underline(True)
163 label.set_tooltip_text(xstr("pirepView_tab_data_tooltip"))
164 self._notebook.append_page(dataTab, label)
165
166 commentsTab = self._buildCommentsTab()
167 label = gtk.Label(xstr("pirepView_tab_comments"))
168 label.set_use_underline(True)
169 label.set_tooltip_text(xstr("pirepView_tab_comments_tooltip"))
170 self._notebook.append_page(commentsTab, label)
171
172 logTab = self._buildLogTab()
173 label = gtk.Label(xstr("pirepView_tab_log"))
174 label.set_use_underline(True)
175 label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
176 self._notebook.append_page(logTab, label)
177
178 self._okButton = self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
179 self._okButton.set_can_default(True)
180
181 def setPIREP(self, pirep):
182 """Setup the data in the dialog from the given PIREP."""
183 bookedFlight = pirep.bookedFlight
184
185 self._callsign.set_text(bookedFlight.callsign)
186 self._tailNumber.set_text(bookedFlight.tailNumber)
187 aircraftType = xstr("aircraft_" + icaoCodes[bookedFlight.aircraftType].lower())
188 self._aircraftType.set_text(aircraftType)
189
190 self._departureICAO.set_text(bookedFlight.departureICAO)
191 self._departureTime.set_text("%02d:%02d" % \
192 (bookedFlight.departureTime.hour,
193 bookedFlight.departureTime.minute))
194
195 self._arrivalICAO.set_text(bookedFlight.arrivalICAO)
196 self._arrivalTime.set_text("%02d:%02d" % \
197 (bookedFlight.arrivalTime.hour,
198 bookedFlight.arrivalTime.minute))
199
200 self._numPassengers.set_text(str(bookedFlight.numPassengers))
201 self._numCrew.set_text(str(bookedFlight.numCrew))
202 self._bagWeight.set_text(str(bookedFlight.bagWeight))
203 self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
204 self._mailWeight.set_text(str(bookedFlight.mailWeight))
205
206 self._route.get_buffer().set_text(bookedFlight.route)
207
208 self._filedCruiseLevel.set_text("FL" + str(pirep.filedCruiseAltitude/100))
209
210 if pirep.cruiseAltitude != pirep.filedCruiseAltitude:
211 self._modifiedCruiseLevel.set_text("FL" + str(pirep.cruiseAltitude/100))
212 else:
213 self._modifiedCruiseLevel.set_text("-")
214
215 self._userRoute.get_buffer().set_text(pirep.route)
216
217 self._departureMETAR.get_buffer().set_text(pirep.departureMETAR)
218
219 self._arrivalMETAR.get_buffer().set_text(pirep.arrivalMETAR)
220 self._departureRunway.set_text(pirep.departureRunway)
221 self._sid.set_text(pirep.sid)
222
223 self._star.set_text("-" if pirep.star is None else pirep.star)
224 self._transition.set_text("-" if pirep.transition is None else pirep.transition)
225 self._approachType.set_text(pirep.approachType)
226 self._arrivalRunway.set_text(pirep.arrivalRunway)
227
228 PIREPViewer.timestamp2text(self._blockTimeStart, pirep.blockTimeStart)
229 PIREPViewer.timestamp2text(self._blockTimeEnd, pirep.blockTimeEnd)
230 PIREPViewer.timestamp2text(self._flightTimeStart, pirep.flightTimeStart)
231 PIREPViewer.timestamp2text(self._flightTimeEnd, pirep.flightTimeEnd)
232
233 self._flownDistance.set_text("%.1f" % (pirep.flownDistance,))
234 self._fuelUsed.set_text("%.0f" % (pirep.fuelUsed,))
235
236 rating = pirep.rating
237 if rating<0:
238 self._rating.set_markup('<b><span foreground="red">NO GO</span></b>')
239 else:
240 self._rating.set_text("%.1f %%" % (rating,))
241
242 self._flownNumCrew.set_text("%d" % (pirep.numCrew,))
243 self._flownNumPassengers.set_text("%d" % (pirep.numPassengers,))
244 self._flownBagWeight.set_text("%.0f" % (pirep.bagWeight,))
245 self._flownCargoWeight.set_text("%.0f" % (pirep.cargoWeight,))
246 self._flownMailWeight.set_text("%.0f" % (pirep.mailWeight,))
247 self._flightType.set_text(xstr("flighttype_" +
248 flightType2string(pirep.flightType)))
249 self._online.set_text(xstr("pirepView_" +
250 ("yes" if pirep.online else "no")))
251
252 delayCodes = ""
253 for code in pirep.delayCodes:
254 if delayCodes: delayCodes += ", "
255 delayCodes += code
256
257 self._delayCodes.get_buffer().set_text(delayCodes)
258
259 self._comments.get_buffer().set_text(pirep.comments)
260 self._flightDefects.get_buffer().set_text(pirep.flightDefects)
261
262 logBuffer = self._log.get_buffer()
263 logBuffer.set_text("")
264 lineIndex = 0
265 for (timeStr, line) in pirep.logLines:
266 isFault = lineIndex in pirep.faultLineIndexes
267 appendTextBuffer(logBuffer,
268 formatFlightLogLine(timeStr, line),
269 isFault = isFault)
270 lineIndex += 1
271
272 self._notebook.set_current_page(0)
273 self._okButton.grab_default()
274
275 def _buildDataTab(self):
276 """Build the data tab of the viewer."""
277 table = gtk.Table(1, 2)
278 table.set_row_spacings(4)
279 table.set_col_spacings(16)
280 table.set_homogeneous(True)
281
282 box1 = gtk.VBox()
283 table.attach(box1, 0, 1, 0, 1)
284
285 box2 = gtk.VBox()
286 table.attach(box2, 1, 2, 0, 1)
287
288 flightFrame = self._buildFlightFrame()
289 box1.pack_start(flightFrame, False, False, 4)
290
291 routeFrame = self._buildRouteFrame()
292 box1.pack_start(routeFrame, False, False, 4)
293
294 departureFrame = self._buildDepartureFrame()
295 box2.pack_start(departureFrame, True, True, 4)
296
297 arrivalFrame = self._buildArrivalFrame()
298 box2.pack_start(arrivalFrame, True, True, 4)
299
300 statisticsFrame = self._buildStatisticsFrame()
301 box2.pack_start(statisticsFrame, False, False, 4)
302
303 miscellaneousFrame = self._buildMiscellaneousFrame()
304 box1.pack_start(miscellaneousFrame, False, False, 4)
305
306 return table
307
308 def _buildFlightFrame(self):
309 """Build the frame for the flight data."""
310
311 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
312
313 dataBox = gtk.HBox()
314 mainBox.pack_start(dataBox, False, False, 0)
315
316 self._callsign = \
317 PIREPViewer.addLabeledData(dataBox,
318 xstr("pirepView_callsign"),
319 width = 8)
320
321 self._tailNumber = \
322 PIREPViewer.addLabeledData(dataBox,
323 xstr("pirepView_tailNumber"),
324 width = 7)
325
326 PIREPViewer.addVFiller(mainBox)
327
328 dataBox = gtk.HBox()
329 mainBox.pack_start(dataBox, False, False, 0)
330
331 self._aircraftType = \
332 PIREPViewer.addLabeledData(dataBox,
333 xstr("pirepView_aircraftType"),
334 width = 25)
335
336 PIREPViewer.addVFiller(mainBox)
337
338 table = gtk.Table(3, 2)
339 mainBox.pack_start(table, False, False, 0)
340 table.set_row_spacings(4)
341 table.set_col_spacings(8)
342
343 self._departureICAO = \
344 PIREPViewer.tableAttach(table, 0, 0,
345 xstr("pirepView_departure"),
346 width = 5)
347
348 self._departureTime = \
349 PIREPViewer.tableAttach(table, 1, 0,
350 xstr("pirepView_departure_time"),
351 width = 6)
352
353 self._arrivalICAO = \
354 PIREPViewer.tableAttach(table, 0, 1,
355 xstr("pirepView_arrival"),
356 width = 5)
357
358 self._arrivalTime = \
359 PIREPViewer.tableAttach(table, 1, 1,
360 xstr("pirepView_arrival_time"),
361 width = 6)
362
363 table = gtk.Table(3, 2)
364 mainBox.pack_start(table, False, False, 0)
365 table.set_row_spacings(4)
366 table.set_col_spacings(8)
367
368 self._numPassengers = \
369 PIREPViewer.tableAttach(table, 0, 0,
370 xstr("pirepView_numPassengers"),
371 width = 4)
372
373 self._numCrew = \
374 PIREPViewer.tableAttach(table, 1, 0,
375 xstr("pirepView_numCrew"),
376 width = 3)
377
378 self._bagWeight = \
379 PIREPViewer.tableAttach(table, 0, 1,
380 xstr("pirepView_bagWeight"),
381 width = 5)
382
383 self._cargoWeight = \
384 PIREPViewer.tableAttach(table, 1, 1,
385 xstr("pirepView_cargoWeight"),
386 width = 5)
387
388 self._mailWeight = \
389 PIREPViewer.tableAttach(table, 2, 1,
390 xstr("pirepView_mailWeight"),
391 width = 5)
392
393 PIREPViewer.addVFiller(mainBox)
394
395 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
396 False, False, 0)
397
398 (routeWindow, self._route) = PIREPViewer.getTextWindow()
399 mainBox.pack_start(routeWindow, False, False, 0)
400
401 return frame
402
403 def _buildRouteFrame(self):
404 """Build the frame for the user-specified route and flight
405 level."""
406
407 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
408
409 levelBox = gtk.HBox()
410 mainBox.pack_start(levelBox, False, False, 0)
411
412 self._filedCruiseLevel = \
413 PIREPViewer.addLabeledData(levelBox,
414 xstr("pirepView_filedCruiseLevel"),
415 width = 6)
416
417 self._modifiedCruiseLevel = \
418 PIREPViewer.addLabeledData(levelBox,
419 xstr("pirepView_modifiedCruiseLevel"),
420 width = 6)
421
422 PIREPViewer.addVFiller(mainBox)
423
424 (routeWindow, self._userRoute) = PIREPViewer.getTextWindow()
425 mainBox.pack_start(routeWindow, False, False, 0)
426
427 return frame
428
429 def _buildDepartureFrame(self):
430 """Build the frame for the departure data."""
431 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
432
433 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
434 False, False, 0)
435 (metarWindow, self._departureMETAR) = \
436 PIREPViewer.getTextWindow(heightRequest = -1)
437 mainBox.pack_start(metarWindow, True, True, 0)
438
439 PIREPViewer.addVFiller(mainBox)
440
441 dataBox = gtk.HBox()
442 mainBox.pack_start(dataBox, False, False, 0)
443
444 self._departureRunway = \
445 PIREPViewer.addLabeledData(dataBox,
446 xstr("pirepView_runway"),
447 width = 5)
448
449 self._sid = \
450 PIREPViewer.addLabeledData(dataBox,
451 xstr("pirepView_sid"),
452 width = 12)
453
454 return frame
455
456 def _buildArrivalFrame(self):
457 """Build the frame for the arrival data."""
458 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
459
460 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
461 False, False, 0)
462 (metarWindow, self._arrivalMETAR) = \
463 PIREPViewer.getTextWindow(heightRequest = -1)
464 mainBox.pack_start(metarWindow, True, True, 0)
465
466 PIREPViewer.addVFiller(mainBox)
467
468 table = gtk.Table(2, 2)
469 mainBox.pack_start(table, False, False, 0)
470 table.set_row_spacings(4)
471 table.set_col_spacings(8)
472
473 self._star = \
474 PIREPViewer.tableAttach(table, 0, 0,
475 xstr("pirepView_star"),
476 width = 12)
477
478 self._transition = \
479 PIREPViewer.tableAttach(table, 1, 0,
480 xstr("pirepView_transition"),
481 width = 12)
482
483 self._approachType = \
484 PIREPViewer.tableAttach(table, 0, 1,
485 xstr("pirepView_approachType"),
486 width = 7)
487
488 self._arrivalRunway = \
489 PIREPViewer.tableAttach(table, 1, 1,
490 xstr("pirepView_runway"),
491 width = 5)
492
493 return frame
494
495 def _buildStatisticsFrame(self):
496 """Build the frame for the statistics data."""
497 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
498
499 table = gtk.Table(4, 2)
500 mainBox.pack_start(table, False, False, 0)
501 table.set_row_spacings(4)
502 table.set_col_spacings(8)
503 table.set_homogeneous(False)
504
505 self._blockTimeStart = \
506 PIREPViewer.tableAttach(table, 0, 0,
507 xstr("pirepView_blockTimeStart"),
508 width = 6)
509
510 self._blockTimeEnd = \
511 PIREPViewer.tableAttach(table, 1, 0,
512 xstr("pirepView_blockTimeEnd"),
513 width = 8)
514
515 self._flightTimeStart = \
516 PIREPViewer.tableAttach(table, 0, 1,
517 xstr("pirepView_flightTimeStart"),
518 width = 6)
519
520 self._flightTimeEnd = \
521 PIREPViewer.tableAttach(table, 1, 1,
522 xstr("pirepView_flightTimeEnd"),
523 width = 6)
524
525 self._flownDistance = \
526 PIREPViewer.tableAttach(table, 0, 2,
527 xstr("pirepView_flownDistance"),
528 width = 8)
529
530 self._fuelUsed = \
531 PIREPViewer.tableAttach(table, 1, 2,
532 xstr("pirepView_fuelUsed"),
533 width = 6)
534
535 self._rating = \
536 PIREPViewer.tableAttach(table, 0, 3,
537 xstr("pirepView_rating"),
538 width = 7)
539 return frame
540
541 def _buildMiscellaneousFrame(self):
542 """Build the frame for the miscellaneous data."""
543 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
544
545 table = gtk.Table(3, 2)
546 mainBox.pack_start(table, False, False, 0)
547 table.set_row_spacings(4)
548 table.set_col_spacings(8)
549
550 self._flownNumPassengers = \
551 PIREPViewer.tableAttach(table, 0, 0,
552 xstr("pirepView_numPassengers"),
553 width = 4)
554
555 self._flownNumCrew = \
556 PIREPViewer.tableAttach(table, 1, 0,
557 xstr("pirepView_numCrew"),
558 width = 3)
559
560 self._flownBagWeight = \
561 PIREPViewer.tableAttach(table, 0, 1,
562 xstr("pirepView_bagWeight"),
563 width = 5)
564
565 self._flownCargoWeight = \
566 PIREPViewer.tableAttach(table, 1, 1,
567 xstr("pirepView_cargoWeight"),
568 width = 6)
569
570 self._flownMailWeight = \
571 PIREPViewer.tableAttach(table, 2, 1,
572 xstr("pirepView_mailWeight"),
573 width = 5)
574
575 self._flightType = \
576 PIREPViewer.tableAttach(table, 0, 2,
577 xstr("pirepView_flightType"),
578 width = 15)
579
580 self._online = \
581 PIREPViewer.tableAttach(table, 1, 2,
582 xstr("pirepView_online"),
583 width = 5)
584
585 PIREPViewer.addVFiller(mainBox)
586
587 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
588 False, False, 0)
589
590 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
591 mainBox.pack_start(textWindow, False, False, 0)
592
593 return frame
594
595 def _buildCommentsTab(self):
596 """Build the tab with the comments and flight defects."""
597 table = gtk.Table(2, 1)
598 table.set_col_spacings(16)
599
600 (frame, commentsBox) = \
601 PIREPViewer.createFrame(xstr("pirepView_comments"))
602 table.attach(frame, 0, 1, 0, 1)
603
604 (commentsWindow, self._comments) = \
605 PIREPViewer.getTextWindow(heightRequest = -1)
606 commentsBox.pack_start(commentsWindow, True, True, 0)
607
608 (frame, flightDefectsBox) = \
609 PIREPViewer.createFrame(xstr("pirepView_flightDefects"))
610 table.attach(frame, 1, 2, 0, 1)
611
612 (flightDefectsWindow, self._flightDefects) = \
613 PIREPViewer.getTextWindow(heightRequest = -1)
614 flightDefectsBox.pack_start(flightDefectsWindow, True, True, 0)
615
616 return table
617
618 def _buildLogTab(self):
619 """Build the log tab."""
620 mainBox = gtk.VBox()
621
622 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
623 addFaultTag(self._log.get_buffer())
624 mainBox.pack_start(logWindow, True, True, 0)
625
626 return mainBox
627
628#------------------------------------------------------------------------------
629
630class PIREPEditor(gtk.Dialog):
631 """A PIREP editor dialog."""
632 _delayCodeRE = re.compile("([0-9]{2,3})( \([^\)]*\))")
633
634 @staticmethod
635 def tableAttachWidget(table, column, row, labelText, widget):
636 """Attach the given widget with the given label to the given table.
637
638 The label will got to cell (column, row), the widget to cell
639 (column+1, row)."""
640 label = gtk.Label("<b>" + labelText + "</b>")
641 label.set_use_markup(True)
642 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
643 xscale = 0.0, yscale = 0.0)
644 alignment.add(label)
645 table.attach(alignment, column, column + 1, row, row + 1)
646
647 table.attach(widget, column + 1, column + 2, row, row + 1)
648
649 @staticmethod
650 def tableAttachSpinButton(table, column, row, labelText, maxValue,
651 minValue = 0, stepIncrement = 1,
652 pageIncrement = 10, numeric = True,
653 width = 3):
654 """Attach a spin button with the given label to the given table.
655
656 The label will got to cell (column, row), the spin button to cell
657 (column+1, row)."""
658 button = gtk.SpinButton()
659 button.set_range(min = minValue, max = maxValue)
660 button.set_increments(step = stepIncrement, page = pageIncrement)
661 button.set_numeric(True)
662 button.set_width_chars(width)
663 button.set_alignment(1.0)
664
665 PIREPEditor.tableAttachWidget(table, column, row, labelText, button)
666
667 return button
668
669 @staticmethod
670 def tableAttachTimeEntry(table, column, row, labelText):
671 """Attach a time entry widget with the given label to the given table.
672
673 The label will got to cell (column, row), the spin button to cell
674 (column+1, row)."""
675 entry = TimeEntry()
676 entry.set_width_chars(5)
677 entry.set_alignment(1.0)
678
679 PIREPEditor.tableAttachWidget(table, column, row, labelText, entry)
680
681 return entry
682
683 def __init__(self, gui):
684 """Construct the PIREP viewer."""
685 super(PIREPEditor, self).__init__(title = WINDOW_TITLE_BASE +
686 " - " +
687 xstr("pirepEdit_title"),
688 parent = gui.mainWindow)
689
690 self.set_resizable(False)
691
692 self._gui = gui
693
694 contentArea = self.get_content_area()
695
696 self._notebook = gtk.Notebook()
697 contentArea.pack_start(self._notebook, False, False, 4)
698
699 dataTab = self._buildDataTab()
700 label = gtk.Label(xstr("pirepView_tab_data"))
701 label.set_use_underline(True)
702 label.set_tooltip_text(xstr("pirepView_tab_data_tooltip"))
703 self._notebook.append_page(dataTab, label)
704
705 self._flightInfo = self._buildCommentsTab()
706 label = gtk.Label(xstr("pirepView_tab_comments"))
707 label.set_use_underline(True)
708 label.set_tooltip_text(xstr("pirepView_tab_comments_tooltip"))
709 self._notebook.append_page(self._flightInfo, label)
710
711 logTab = self._buildLogTab()
712 label = gtk.Label(xstr("pirepView_tab_log"))
713 label.set_use_underline(True)
714 label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
715 self._notebook.append_page(logTab, label)
716
717 self._okButton = self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
718 self._okButton.set_can_default(True)
719
720 def setPIREP(self, pirep):
721 """Setup the data in the dialog from the given PIREP."""
722 bookedFlight = pirep.bookedFlight
723
724 self._callsign.set_text(bookedFlight.callsign)
725 self._tailNumber.set_text(bookedFlight.tailNumber)
726 aircraftType = xstr("aircraft_" + icaoCodes[bookedFlight.aircraftType].lower())
727 self._aircraftType.set_text(aircraftType)
728
729 self._departureICAO.set_text(bookedFlight.departureICAO)
730 self._departureTime.set_text("%02d:%02d" % \
731 (bookedFlight.departureTime.hour,
732 bookedFlight.departureTime.minute))
733
734 self._arrivalICAO.set_text(bookedFlight.arrivalICAO)
735 self._arrivalTime.set_text("%02d:%02d" % \
736 (bookedFlight.arrivalTime.hour,
737 bookedFlight.arrivalTime.minute))
738
739 self._numPassengers.set_text(str(bookedFlight.numPassengers))
740 self._numCrew.set_text(str(bookedFlight.numCrew))
741 self._bagWeight.set_text(str(bookedFlight.bagWeight))
742 self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
743 self._mailWeight.set_text(str(bookedFlight.mailWeight))
744
745 self._route.get_buffer().set_text(bookedFlight.route)
746
747 self._filedCruiseLevel.set_value(pirep.filedCruiseAltitude/100)
748 self._modifiedCruiseLevel.set_value(pirep.cruiseAltitude/100)
749
750 self._userRoute.get_buffer().set_text(pirep.route)
751
752 self._departureMETAR.get_buffer().set_text(pirep.departureMETAR)
753
754 self._arrivalMETAR.get_buffer().set_text(pirep.arrivalMETAR)
755 self._departureRunway.set_text(pirep.departureRunway)
756 self._sid.get_child().set_text(pirep.sid)
757
758 if not pirep.star:
759 self._star.set_active(0)
760 else:
761 self._star.get_child().set_text(pirep.star)
762
763 if not pirep.transition:
764 self._transition.set_active(0)
765 else:
766 self._transition.get_child().set_text(pirep.transition)
767 self._approachType.set_text(pirep.approachType)
768 self._arrivalRunway.set_text(pirep.arrivalRunway)
769
770 self._blockTimeStart.setTimestamp(pirep.blockTimeStart)
771 self._blockTimeEnd.setTimestamp(pirep.blockTimeEnd)
772 self._flightTimeStart.setTimestamp(pirep.flightTimeStart)
773 self._flightTimeEnd.setTimestamp(pirep.flightTimeEnd)
774
775 self._flownDistance.set_text("%.1f" % (pirep.flownDistance,))
776 self._fuelUsed.set_value(int(pirep.fuelUsed))
777
778 rating = pirep.rating
779 if rating<0:
780 self._rating.set_markup('<b><span foreground="red">NO GO</span></b>')
781 else:
782 self._rating.set_text("%.1f %%" % (rating,))
783
784 self._flownNumCrew.set_value(pirep.numCrew)
785 self._flownNumPassengers.set_value(pirep.numPassengers)
786 self._flownBagWeight.set_value(pirep.bagWeight)
787 self._flownCargoWeight.set_value(pirep.cargoWeight)
788 self._flownMailWeight.set_value(pirep.mailWeight)
789 self._flightType.set_active(flightType2index(pirep.flightType))
790 self._online.set_active(pirep.online)
791
792 self._flightInfo.reset()
793 self._flightInfo.enable(bookedFlight.aircraftType)
794
795 delayCodes = ""
796 for code in pirep.delayCodes:
797 if delayCodes: delayCodes += ", "
798 delayCodes += code
799 m = PIREPEditor._delayCodeRE.match(code)
800 if m:
801 self._flightInfo.activateDelayCode(m.group(1))
802
803 self._delayCodes.get_buffer().set_text(delayCodes)
804
805 self._flightInfo.comments = pirep.comments
806 if pirep.flightDefects.find("<br/></b>")!=-1:
807 flightDefects = pirep.flightDefects.split("<br/></b>")
808 caption = flightDefects[0]
809 index = 0
810 for defect in flightDefects[1:]:
811 if defect.find("<b>")!=-1:
812 (explanation, nextCaption) = defect.split("<b>")
813 else:
814 explanation = defect
815 nextCaption = None
816 self._flightInfo.addFault(index, caption)
817 self._flightInfo.setExplanation(index, explanation)
818 index += 1
819 caption = nextCaption
820
821 # self._comments.get_buffer().set_text(pirep.comments)
822 # self._flightDefects.get_buffer().set_text(pirep.flightDefects)
823
824 logBuffer = self._log.get_buffer()
825 logBuffer.set_text("")
826 lineIndex = 0
827 for (timeStr, line) in pirep.logLines:
828 isFault = lineIndex in pirep.faultLineIndexes
829 appendTextBuffer(logBuffer,
830 formatFlightLogLine(timeStr, line),
831 isFault = isFault)
832 lineIndex += 1
833
834 self._notebook.set_current_page(0)
835 self._okButton.grab_default()
836
837 def _buildDataTab(self):
838 """Build the data tab of the viewer."""
839 table = gtk.Table(1, 2)
840 table.set_row_spacings(4)
841 table.set_col_spacings(16)
842 table.set_homogeneous(True)
843
844 box1 = gtk.VBox()
845 table.attach(box1, 0, 1, 0, 1)
846
847 box2 = gtk.VBox()
848 table.attach(box2, 1, 2, 0, 1)
849
850 flightFrame = self._buildFlightFrame()
851 box1.pack_start(flightFrame, False, False, 4)
852
853 routeFrame = self._buildRouteFrame()
854 box1.pack_start(routeFrame, False, False, 4)
855
856 departureFrame = self._buildDepartureFrame()
857 box2.pack_start(departureFrame, True, True, 4)
858
859 arrivalFrame = self._buildArrivalFrame()
860 box2.pack_start(arrivalFrame, True, True, 4)
861
862 statisticsFrame = self._buildStatisticsFrame()
863 box2.pack_start(statisticsFrame, False, False, 4)
864
865 miscellaneousFrame = self._buildMiscellaneousFrame()
866 box1.pack_start(miscellaneousFrame, False, False, 4)
867
868 return table
869
870 def _buildFlightFrame(self):
871 """Build the frame for the flight data."""
872
873 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
874
875 dataBox = gtk.HBox()
876 mainBox.pack_start(dataBox, False, False, 0)
877
878 self._callsign = \
879 PIREPViewer.addLabeledData(dataBox,
880 xstr("pirepView_callsign"),
881 width = 8)
882
883 self._tailNumber = \
884 PIREPViewer.addLabeledData(dataBox,
885 xstr("pirepView_tailNumber"),
886 width = 7)
887
888 PIREPViewer.addVFiller(mainBox)
889
890 dataBox = gtk.HBox()
891 mainBox.pack_start(dataBox, False, False, 0)
892
893 self._aircraftType = \
894 PIREPViewer.addLabeledData(dataBox,
895 xstr("pirepView_aircraftType"),
896 width = 25)
897
898 PIREPViewer.addVFiller(mainBox)
899
900 table = gtk.Table(3, 2)
901 mainBox.pack_start(table, False, False, 0)
902 table.set_row_spacings(4)
903 table.set_col_spacings(8)
904
905 self._departureICAO = \
906 PIREPViewer.tableAttach(table, 0, 0,
907 xstr("pirepView_departure"),
908 width = 5)
909
910 self._departureTime = \
911 PIREPViewer.tableAttach(table, 1, 0,
912 xstr("pirepView_departure_time"),
913 width = 6)
914
915 self._arrivalICAO = \
916 PIREPViewer.tableAttach(table, 0, 1,
917 xstr("pirepView_arrival"),
918 width = 5)
919
920 self._arrivalTime = \
921 PIREPViewer.tableAttach(table, 1, 1,
922 xstr("pirepView_arrival_time"),
923 width = 6)
924
925 table = gtk.Table(3, 2)
926 mainBox.pack_start(table, False, False, 0)
927 table.set_row_spacings(4)
928 table.set_col_spacings(8)
929
930 self._numPassengers = \
931 PIREPViewer.tableAttach(table, 0, 0,
932 xstr("pirepView_numPassengers"),
933 width = 4)
934
935 self._numCrew = \
936 PIREPViewer.tableAttach(table, 1, 0,
937 xstr("pirepView_numCrew"),
938 width = 3)
939
940 self._bagWeight = \
941 PIREPViewer.tableAttach(table, 0, 1,
942 xstr("pirepView_bagWeight"),
943 width = 5)
944
945 self._cargoWeight = \
946 PIREPViewer.tableAttach(table, 1, 1,
947 xstr("pirepView_cargoWeight"),
948 width = 5)
949
950 self._mailWeight = \
951 PIREPViewer.tableAttach(table, 2, 1,
952 xstr("pirepView_mailWeight"),
953 width = 5)
954
955 PIREPViewer.addVFiller(mainBox)
956
957 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
958 False, False, 0)
959
960 (routeWindow, self._route) = PIREPViewer.getTextWindow()
961 mainBox.pack_start(routeWindow, False, False, 0)
962
963 return frame
964
965 def _buildRouteFrame(self):
966 """Build the frame for the user-specified route and flight
967 level."""
968
969 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
970
971 levelBox = gtk.HBox()
972 mainBox.pack_start(levelBox, False, False, 0)
973
974 label = PIREPViewer.getLabel(xstr("pirepView_filedCruiseLevel"),
975 xstr("pirepEdit_FL"))
976 levelBox.pack_start(label, False, False, 0)
977
978 self._filedCruiseLevel = gtk.SpinButton()
979 self._filedCruiseLevel.set_increments(step = 10, page = 100)
980 self._filedCruiseLevel.set_range(min = 0, max = 500)
981 #self._filedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
982 self._filedCruiseLevel.set_numeric(True)
983
984 levelBox.pack_start(self._filedCruiseLevel, False, False, 0)
985
986 PIREPViewer.addHFiller(levelBox)
987
988 label = PIREPViewer.getLabel(xstr("pirepView_modifiedCruiseLevel"),
989 xstr("pirepEdit_FL"))
990 levelBox.pack_start(label, False, False, 0)
991
992 self._modifiedCruiseLevel = gtk.SpinButton()
993 self._modifiedCruiseLevel.set_increments(step = 10, page = 100)
994 self._modifiedCruiseLevel.set_range(min = 0, max = 500)
995 #self._modifiedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
996 self._modifiedCruiseLevel.set_numeric(True)
997
998 levelBox.pack_start(self._modifiedCruiseLevel, False, False, 0)
999
1000 PIREPViewer.addVFiller(mainBox)
1001
1002 (routeWindow, self._userRoute) = \
1003 PIREPViewer.getTextWindow(editable = True)
1004 mainBox.pack_start(routeWindow, False, False, 0)
1005
1006 return frame
1007
1008 def _buildDepartureFrame(self):
1009 """Build the frame for the departure data."""
1010 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
1011
1012 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1013 False, False, 0)
1014 (metarWindow, self._departureMETAR) = \
1015 PIREPViewer.getTextWindow(heightRequest = -1,
1016 editable = True)
1017 mainBox.pack_start(metarWindow, True, True, 0)
1018
1019 PIREPViewer.addVFiller(mainBox)
1020
1021 dataBox = gtk.HBox()
1022 mainBox.pack_start(dataBox, False, False, 0)
1023
1024 label = gtk.Label("<b>" + xstr("pirepView_runway") + "</b>")
1025 label.set_use_markup(True)
1026 dataBox.pack_start(label, False, False, 0)
1027
1028 # FIXME: quite the same as the runway entry boxes in the wizard
1029 self._departureRunway = gtk.Entry()
1030 self._departureRunway.set_width_chars(5)
1031 self._departureRunway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
1032 self._departureRunway.connect("changed", self._upperChanged)
1033 dataBox.pack_start(self._departureRunway, False, False, 8)
1034
1035 label = gtk.Label("<b>" + xstr("pirepView_sid") + "</b>")
1036 label.set_use_markup(True)
1037 dataBox.pack_start(label, False, False, 0)
1038
1039 # FIXME: quite the same as the SID combo box in
1040 # the flight wizard
1041 if pygobject:
1042 self._sid = gtk.ComboBox.new_with_model_and_entry(comboModel)
1043 else:
1044 self._sid = gtk.ComboBoxEntry(comboModel)
1045
1046 self._sid.set_entry_text_column(0)
1047 self._sid.get_child().set_width_chars(10)
1048 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
1049 self._sid.connect("changed", self._upperChangedComboBox)
1050
1051 dataBox.pack_start(self._sid, False, False, 8)
1052
1053 return frame
1054
1055 def _buildArrivalFrame(self):
1056 """Build the frame for the arrival data."""
1057 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
1058
1059 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1060 False, False, 0)
1061 (metarWindow, self._arrivalMETAR) = \
1062 PIREPViewer.getTextWindow(heightRequest = -1,
1063 editable = True)
1064 mainBox.pack_start(metarWindow, True, True, 0)
1065
1066 PIREPViewer.addVFiller(mainBox)
1067
1068 table = gtk.Table(2, 4)
1069 mainBox.pack_start(table, False, False, 0)
1070 table.set_row_spacings(4)
1071 table.set_col_spacings(8)
1072
1073 # FIXME: quite the same as in the wizard
1074 if pygobject:
1075 self._star = gtk.ComboBox.new_with_model_and_entry(comboModel)
1076 else:
1077 self._star = gtk.ComboBoxEntry(comboModel)
1078
1079 self._star.set_entry_text_column(0)
1080 self._star.get_child().set_width_chars(10)
1081 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
1082 self._star.connect("changed", self._upperChangedComboBox)
1083
1084 PIREPEditor.tableAttachWidget(table, 0, 0,
1085 xstr("pirepView_star"),
1086 self._star)
1087
1088 # FIXME: quite the same as in the wizard
1089 if pygobject:
1090 self._transition = gtk.ComboBox.new_with_model_and_entry(comboModel)
1091 else:
1092 self._transition = gtk.ComboBoxEntry(comboModel)
1093
1094 self._transition.set_entry_text_column(0)
1095 self._transition.get_child().set_width_chars(10)
1096 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
1097 self._transition.connect("changed", self._upperChangedComboBox)
1098
1099 PIREPEditor.tableAttachWidget(table, 2, 0,
1100 xstr("pirepView_transition"),
1101 self._transition)
1102
1103
1104 # FIXME: quite the same as in the wizard
1105 self._approachType = gtk.Entry()
1106 self._approachType.set_width_chars(10)
1107 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
1108 self._approachType.connect("changed", self._upperChanged)
1109
1110 PIREPEditor.tableAttachWidget(table, 0, 1,
1111 xstr("pirepView_approachType"),
1112 self._approachType)
1113
1114 # FIXME: quite the same as in the wizard
1115 self._arrivalRunway = gtk.Entry()
1116 self._arrivalRunway.set_width_chars(10)
1117 self._arrivalRunway.set_tooltip_text(xstr("landing_runway_tooltip"))
1118 self._arrivalRunway.connect("changed", self._upperChanged)
1119
1120 PIREPEditor.tableAttachWidget(table, 2, 1,
1121 xstr("pirepView_runway"),
1122 self._arrivalRunway)
1123
1124 return frame
1125
1126 def _buildStatisticsFrame(self):
1127 """Build the frame for the statistics data."""
1128 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
1129
1130 table = gtk.Table(4, 4)
1131 mainBox.pack_start(table, False, False, 0)
1132 table.set_row_spacings(4)
1133 table.set_col_spacings(8)
1134 table.set_homogeneous(False)
1135
1136 self._blockTimeStart = \
1137 PIREPEditor.tableAttachTimeEntry(table, 0, 0,
1138 xstr("pirepView_blockTimeStart"))
1139
1140 self._blockTimeEnd = \
1141 PIREPEditor.tableAttachTimeEntry(table, 2, 0,
1142 xstr("pirepView_blockTimeEnd"))
1143
1144 self._flightTimeStart = \
1145 PIREPEditor.tableAttachTimeEntry(table, 0, 1,
1146 xstr("pirepView_flightTimeStart"))
1147
1148 self._flightTimeEnd = \
1149 PIREPEditor.tableAttachTimeEntry(table, 2, 1,
1150 xstr("pirepView_flightTimeEnd"))
1151
1152 self._flownDistance = PIREPViewer.getDataLabel(width = 3)
1153 PIREPEditor.tableAttachWidget(table, 0, 2,
1154 xstr("pirepView_flownDistance"),
1155 self._flownDistance)
1156
1157 self._fuelUsed = \
1158 PIREPEditor.tableAttachSpinButton(table, 2, 2,
1159 xstr("pirepView_fuelUsed"),
1160 1000000)
1161
1162
1163 self._rating = PIREPViewer.getDataLabel(width = 3)
1164 PIREPEditor.tableAttachWidget(table, 0, 3,
1165 xstr("pirepView_rating"),
1166 self._rating)
1167 return frame
1168
1169 def _buildMiscellaneousFrame(self):
1170 """Build the frame for the miscellaneous data."""
1171 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
1172
1173 table = gtk.Table(6, 2)
1174 mainBox.pack_start(table, False, False, 0)
1175 table.set_row_spacings(4)
1176 table.set_col_spacings(8)
1177 table.set_homogeneous(False)
1178
1179 self._flownNumPassengers = \
1180 PIREPEditor.tableAttachSpinButton(table, 0, 0,
1181 xstr("pirepView_numPassengers"),
1182 300)
1183
1184 self._flownNumCrew = \
1185 PIREPEditor.tableAttachSpinButton(table, 2, 0,
1186 xstr("pirepView_numCrew"),
1187 10)
1188
1189 self._flownBagWeight = \
1190 PIREPEditor.tableAttachSpinButton(table, 0, 1,
1191 xstr("pirepView_bagWeight"),
1192 100000, width = 6)
1193
1194 self._flownCargoWeight = \
1195 PIREPEditor.tableAttachSpinButton(table, 2, 1,
1196 xstr("pirepView_cargoWeight"),
1197 100000, width = 6)
1198
1199 self._flownMailWeight = \
1200 PIREPEditor.tableAttachSpinButton(table, 4, 1,
1201 xstr("pirepView_mailWeight"),
1202 100000, width = 6)
1203
1204 self._flightType = createFlightTypeComboBox()
1205 PIREPEditor.tableAttachWidget(table, 0, 2,
1206 xstr("pirepView_flightType"),
1207 self._flightType)
1208
1209 self._online = gtk.CheckButton(xstr("pirepView_online"))
1210 table.attach(self._online, 2, 3, 2, 3)
1211
1212 PIREPViewer.addVFiller(mainBox)
1213
1214 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
1215 False, False, 0)
1216
1217 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
1218 mainBox.pack_start(textWindow, False, False, 0)
1219
1220 return frame
1221
1222 def _buildCommentsTab(self):
1223 """Build the tab with the comments and flight defects."""
1224 return FlightInfo(self._gui, mainInstance = False)
1225
1226 def _buildLogTab(self):
1227 """Build the log tab."""
1228 mainBox = gtk.VBox()
1229
1230 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
1231 addFaultTag(self._log.get_buffer())
1232 mainBox.pack_start(logWindow, True, True, 0)
1233
1234 return mainBox
1235
1236 def _upperChanged(self, entry, arg = None):
1237 """Called when the value of some entry widget has changed and the value
1238 should be converted to uppercase."""
1239 entry.set_text(entry.get_text().upper())
1240 #self._valueChanged(entry, arg)
1241
1242 def _upperChangedComboBox(self, comboBox):
1243 """Called for combo box widgets that must be converted to uppercase."""
1244 entry = comboBox.get_child()
1245 if comboBox.get_active()==-1:
1246 entry.set_text(entry.get_text().upper())
1247 #self._valueChanged(entry)
1248
1249#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.