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
RevLine 
[220]1
2from common import *
[845]3from dcdata import getTable
4from info import FlightInfo
5from flight import comboModel
[220]6
[236]7from mlx.pirep import PIREP
[220]8from mlx.const import *
9
10import time
[845]11import re
[220]12
13#------------------------------------------------------------------------------
14
[300]15## @package mlx.gui.pirep
16#
[845]17# The detailed PIREP viewer and editor windows.
[300]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
[220]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
[831]35 contents.
[220]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)
[831]49
[220]50 return (frame, box)
51
52 @staticmethod
[845]53 def getLabel(text, extraText = ""):
[220]54 """Get a bold label with the given text."""
[845]55 label = gtk.Label("<b>" + text + "</b>" + extraText)
[220]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
[845]70 def getTextWindow(heightRequest = 40, editable = False):
[220]71 """Get a scrollable text window.
[831]72
[220]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)
[845]82 textView.set_editable(editable)
83 textView.set_cursor_visible(editable)
[220]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
[831]93 table.
94
[220]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)
[831]101
[220]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.
[831]111
[845]112 Returns the data label."""
[220]113 label = PIREPViewer.getLabel(labelText)
114 hBox.pack_start(label, False, False, 0)
[831]115
[220]116 dataLabel = PIREPViewer.getDataLabel(width = width)
117 hBox.pack_start(dataLabel, False, False, dataPadding)
118
119 return dataLabel
120
121 @staticmethod
[845]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
[220]130 def addVFiller(vBox, height = 4):
[238]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)
[220]134 filler.set_size_request(-1, height)
135 vBox.pack_start(filler, False, False, 0)
[831]136
[220]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)
[831]150
[220]151 self.set_resizable(False)
152
153 self._gui = gui
[831]154
[220]155 contentArea = self.get_content_area()
[221]156
157 self._notebook = gtk.Notebook()
158 contentArea.pack_start(self._notebook, False, False, 4)
[831]159
[220]160 dataTab = self._buildDataTab()
[221]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)
[831]165
[221]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)
[831]171
[221]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)
[224]177
178 self._okButton = self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
179 self._okButton.set_can_default(True)
[831]180
[220]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)
[831]189
[220]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))
[831]205
[220]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)
[831]232
[220]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
[303]242 self._flownNumCrew.set_text("%d" % (pirep.numCrew,))
243 self._flownNumPassengers.set_text("%d" % (pirep.numPassengers,))
244 self._flownBagWeight.set_text("%.0f" % (pirep.bagWeight,))
[223]245 self._flownCargoWeight.set_text("%.0f" % (pirep.cargoWeight,))
[303]246 self._flownMailWeight.set_text("%.0f" % (pirep.mailWeight,))
[831]247 self._flightType.set_text(xstr("flighttype_" +
[220]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 += ", "
[437]255 delayCodes += code
[831]256
257 self._delayCodes.get_buffer().set_text(delayCodes)
[221]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("")
[225]264 lineIndex = 0
[221]265 for (timeStr, line) in pirep.logLines:
[225]266 isFault = lineIndex in pirep.faultLineIndexes
[226]267 appendTextBuffer(logBuffer,
268 formatFlightLogLine(timeStr, line),
269 isFault = isFault)
[225]270 lineIndex += 1
[221]271
272 self._notebook.set_current_page(0)
[224]273 self._okButton.grab_default()
[220]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)
[831]284
[220]285 box2 = gtk.VBox()
286 table.attach(box2, 1, 2, 0, 1)
[831]287
[220]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."""
[831]310
[220]311 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
[831]312
[220]313 dataBox = gtk.HBox()
314 mainBox.pack_start(dataBox, False, False, 0)
[831]315
[220]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)
[831]341 table.set_col_spacings(8)
[220]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)
[831]366 table.set_col_spacings(8)
[220]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 = \
[831]379 PIREPViewer.tableAttach(table, 0, 1,
[220]380 xstr("pirepView_bagWeight"),
381 width = 5)
382
383 self._cargoWeight = \
[831]384 PIREPViewer.tableAttach(table, 1, 1,
[220]385 xstr("pirepView_cargoWeight"),
386 width = 5)
387
388 self._mailWeight = \
[831]389 PIREPViewer.tableAttach(table, 2, 1,
[220]390 xstr("pirepView_mailWeight"),
391 width = 5)
[831]392
[220]393 PIREPViewer.addVFiller(mainBox)
394
395 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
396 False, False, 0)
[831]397
[220]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."""
[831]406
[220]407 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
408
409 levelBox = gtk.HBox()
410 mainBox.pack_start(levelBox, False, False, 0)
[831]411
[220]412 self._filedCruiseLevel = \
[831]413 PIREPViewer.addLabeledData(levelBox,
[220]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):
[831]430 """Build the frame for the departure data."""
[220]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)
[831]443
[220]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
[831]455
[220]456 def _buildArrivalFrame(self):
[831]457 """Build the frame for the arrival data."""
[220]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)
[831]471 table.set_col_spacings(8)
[220]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)
[831]482
[220]483 self._approachType = \
484 PIREPViewer.tableAttach(table, 0, 1,
485 xstr("pirepView_approachType"),
486 width = 7)
[831]487
[220]488 self._arrivalRunway = \
[831]489 PIREPViewer.tableAttach(table, 1, 1,
[220]490 xstr("pirepView_runway"),
491 width = 5)
[831]492
[220]493 return frame
494
495 def _buildStatisticsFrame(self):
[831]496 """Build the frame for the statistics data."""
[220]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)
[221]503 table.set_homogeneous(False)
[831]504
[220]505 self._blockTimeStart = \
506 PIREPViewer.tableAttach(table, 0, 0,
507 xstr("pirepView_blockTimeStart"),
508 width = 6)
[831]509
[220]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)
[831]519
[220]520 self._flightTimeEnd = \
[831]521 PIREPViewer.tableAttach(table, 1, 1,
[220]522 xstr("pirepView_flightTimeEnd"),
523 width = 6)
524
525 self._flownDistance = \
526 PIREPViewer.tableAttach(table, 0, 2,
527 xstr("pirepView_flownDistance"),
528 width = 8)
[831]529
[220]530 self._fuelUsed = \
531 PIREPViewer.tableAttach(table, 1, 2,
532 xstr("pirepView_fuelUsed"),
533 width = 6)
[831]534
[220]535 self._rating = \
536 PIREPViewer.tableAttach(table, 0, 3,
537 xstr("pirepView_rating"),
538 width = 7)
539 return frame
540
541 def _buildMiscellaneousFrame(self):
[831]542 """Build the frame for the miscellaneous data."""
[220]543 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
[303]544
545 table = gtk.Table(3, 2)
546 mainBox.pack_start(table, False, False, 0)
547 table.set_row_spacings(4)
[831]548 table.set_col_spacings(8)
549
[303]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
[223]565 self._flownCargoWeight = \
[303]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)
[223]574
[220]575 self._flightType = \
[303]576 PIREPViewer.tableAttach(table, 0, 2,
577 xstr("pirepView_flightType"),
578 width = 15)
[831]579
[220]580 self._online = \
[303]581 PIREPViewer.tableAttach(table, 1, 2,
582 xstr("pirepView_online"),
583 width = 5)
[220]584
585 PIREPViewer.addVFiller(mainBox)
586
587 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
588 False, False, 0)
[831]589
[220]590 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
591 mainBox.pack_start(textWindow, False, False, 0)
592
[831]593 return frame
[220]594
[221]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)
[831]615
[221]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)
[226]623 addFaultTag(self._log.get_buffer())
[221]624 mainBox.pack_start(logWindow, True, True, 0)
[831]625
[221]626 return mainBox
[831]627
[220]628#------------------------------------------------------------------------------
[845]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.