source: src/mlx/gui/pirep.py@ 996:8035d80d5feb

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

Using 'Gtk' instead of 'gtk' (re #347)

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