source: src/mlx/gui/pirep.py@ 878:4947f6756415

Last change on this file since 878:4947f6756415 was 855:c1d387ee73d6, checked in by István Váradi <ivaradi@…>, 8 years ago

The PIREP message (if any) is displayed for an accepted flight (re #307)

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