source: src/mlx/gui/pirep.py@ 993:2141efdd6c25

python3
Last change on this file since 993:2141efdd6c25 was 986:97ad2dd3f77f, checked in by István Váradi <ivaradi@…>, 5 years ago

The PIREP reviewer's message is not editable.

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