source: src/mlx/gui/pirep.py@ 985:f5569c17e934

python3
Last change on this file since 985:f5569c17e934 was 985:f5569c17e934, checked in by István Váradi <ivaradi@…>, 5 years ago

The sender of a message is visible in the PIREP viewer (re #347).

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