source: src/mlx/gui/pirep.py@ 999:e096a5638b87

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

Removed Gtk 2/3 constant definitions (re #347)

File size: 59.9 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(Gtk.WrapMode.WORD)
43 heading.set_size_request(-1, 16)
44
45 buffer = heading.get_buffer()
46 self._headingTag = buffer.create_tag("heading", weight=Pango.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(Gtk.WrapMode.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(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
115 scroller.set_shadow_type(Gtk.ShadowType.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(Gtk.ShadowType.IN)
207 scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC,
208 Gtk.PolicyType.AUTOMATIC)
209
210 textView = Gtk.TextView()
211 textView.set_wrap_mode(Gtk.WrapMode.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"), Gtk.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"), Gtk.ResponseType.CANCEL)
872
873 self._okButton = self.add_button(xstr("button_save"), Gtk.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 self._sid = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1225
1226 self._sid.set_entry_text_column(0)
1227 self._sid.get_child().set_width_chars(10)
1228 self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
1229 self._sid.connect("changed", self._upperChangedComboBox)
1230
1231 dataBox.pack_start(self._sid, False, False, 8)
1232
1233 return frame
1234
1235 def _buildArrivalFrame(self):
1236 """Build the frame for the arrival data."""
1237 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
1238
1239 mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
1240 False, False, 0)
1241 (metarWindow, self._arrivalMETAR) = \
1242 PIREPViewer.getTextWindow(heightRequest = -1,
1243 editable = True)
1244 self._arrivalMETAR.get_buffer().connect("changed", self._updateButtons)
1245 self._arrivalMETAR.set_tooltip_text(xstr("landing_metar_tooltip"))
1246 mainBox.pack_start(metarWindow, True, True, 0)
1247
1248 PIREPViewer.addVFiller(mainBox)
1249
1250 table = Gtk.Table(2, 4)
1251 mainBox.pack_start(table, False, False, 0)
1252 table.set_row_spacings(4)
1253 table.set_col_spacings(8)
1254
1255 # FIXME: quite the same as in the wizard
1256 self._star = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1257
1258 self._star.set_entry_text_column(0)
1259 self._star.get_child().set_width_chars(10)
1260 self._star.set_tooltip_text(xstr("landing_star_tooltip"))
1261 self._star.connect("changed", self._upperChangedComboBox)
1262
1263 PIREPEditor.tableAttachWidget(table, 0, 0,
1264 xstr("pirepView_star"),
1265 self._star)
1266
1267 # FIXME: quite the same as in the wizard
1268 self._transition = Gtk.ComboBox.new_with_model_and_entry(comboModel)
1269
1270 self._transition.set_entry_text_column(0)
1271 self._transition.get_child().set_width_chars(10)
1272 self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
1273 self._transition.connect("changed", self._upperChangedComboBox)
1274
1275 PIREPEditor.tableAttachWidget(table, 2, 0,
1276 xstr("pirepView_transition"),
1277 self._transition)
1278
1279
1280 # FIXME: quite the same as in the wizard
1281 self._approachType = Gtk.Entry()
1282 self._approachType.set_width_chars(10)
1283 self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
1284 self._approachType.connect("changed", self._upperChanged)
1285
1286 PIREPEditor.tableAttachWidget(table, 0, 1,
1287 xstr("pirepView_approachType"),
1288 self._approachType)
1289
1290 # FIXME: quite the same as in the wizard
1291 self._arrivalRunway = Gtk.Entry()
1292 self._arrivalRunway.set_width_chars(10)
1293 self._arrivalRunway.set_tooltip_text(xstr("landing_runway_tooltip"))
1294 self._arrivalRunway.connect("changed", self._upperChanged)
1295
1296 PIREPEditor.tableAttachWidget(table, 2, 1,
1297 xstr("pirepView_runway"),
1298 self._arrivalRunway)
1299
1300 return frame
1301
1302 def _buildStatisticsFrame(self):
1303 """Build the frame for the statistics data."""
1304 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
1305
1306 table = Gtk.Table(4, 4)
1307 mainBox.pack_start(table, False, False, 0)
1308 table.set_row_spacings(4)
1309 table.set_col_spacings(8)
1310 table.set_homogeneous(False)
1311
1312 self._blockTimeStart = \
1313 PIREPEditor.tableAttachTimeEntry(table, 0, 0,
1314 xstr("pirepView_blockTimeStart"))
1315 self._blockTimeStart.connect("changed", self._updateButtons)
1316 self._blockTimeStart.set_tooltip_text(xstr("pirepEdit_block_time_start_tooltip"))
1317
1318 self._blockTimeEnd = \
1319 PIREPEditor.tableAttachTimeEntry(table, 2, 0,
1320 xstr("pirepView_blockTimeEnd"))
1321 self._blockTimeEnd.connect("changed", self._updateButtons)
1322 self._blockTimeEnd.set_tooltip_text(xstr("pirepEdit_block_time_end_tooltip"))
1323
1324 self._flightTimeStart = \
1325 PIREPEditor.tableAttachTimeEntry(table, 0, 1,
1326 xstr("pirepView_flightTimeStart"))
1327 self._flightTimeStart.connect("changed", self._updateButtons)
1328 self._flightTimeStart.set_tooltip_text(xstr("pirepEdit_flight_time_start_tooltip"))
1329
1330 self._flightTimeEnd = \
1331 PIREPEditor.tableAttachTimeEntry(table, 2, 1,
1332 xstr("pirepView_flightTimeEnd"))
1333 self._flightTimeEnd.connect("changed", self._updateButtons)
1334 self._flightTimeEnd.set_tooltip_text(xstr("pirepEdit_flight_time_end_tooltip"))
1335
1336 self._flownDistance = PIREPViewer.getDataLabel(width = 3)
1337 PIREPEditor.tableAttachWidget(table, 0, 2,
1338 xstr("pirepView_flownDistance"),
1339 self._flownDistance)
1340
1341 self._fuelUsed = \
1342 PIREPEditor.tableAttachSpinButton(table, 2, 2,
1343 xstr("pirepView_fuelUsed"),
1344 1000000)
1345 self._fuelUsed.connect("value-changed", self._updateButtons)
1346 self._fuelUsed.set_tooltip_text(xstr("pirepEdit_fuel_used_tooltip"))
1347
1348 self._rating = PIREPViewer.getDataLabel(width = 3)
1349 PIREPEditor.tableAttachWidget(table, 0, 3,
1350 xstr("pirepView_rating"),
1351 self._rating)
1352 return frame
1353
1354 def _buildMiscellaneousFrame(self):
1355 """Build the frame for the miscellaneous data."""
1356 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
1357
1358 table = Gtk.Table(6, 2)
1359 mainBox.pack_start(table, False, False, 0)
1360 table.set_row_spacings(4)
1361 table.set_col_spacings(8)
1362 table.set_homogeneous(False)
1363
1364 self._flownNumPassengers = \
1365 PIREPEditor.tableAttachSpinButton(table, 0, 0,
1366 xstr("pirepView_numPassengers"),
1367 300)
1368 self._flownNumPassengers.connect("value-changed", self._updateButtons)
1369 self._flownNumPassengers.set_tooltip_text(xstr("payload_pax_tooltip"))
1370
1371 self._flownNumCrew = \
1372 PIREPEditor.tableAttachSpinButton(table, 2, 0,
1373 xstr("pirepView_numCrew"),
1374 10)
1375 self._flownNumCrew.connect("value-changed", self._updateButtons)
1376 self._flownNumCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
1377
1378 self._flownBagWeight = \
1379 PIREPEditor.tableAttachSpinButton(table, 0, 1,
1380 xstr("pirepView_bagWeight"),
1381 100000, width = 6)
1382 self._flownBagWeight.connect("value-changed", self._updateButtons)
1383 self._flownBagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
1384
1385 self._flownCargoWeight = \
1386 PIREPEditor.tableAttachSpinButton(table, 2, 1,
1387 xstr("pirepView_cargoWeight"),
1388 100000, width = 6)
1389 self._flownCargoWeight.connect("value-changed", self._updateButtons)
1390 self._flownCargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
1391
1392 self._flownMailWeight = \
1393 PIREPEditor.tableAttachSpinButton(table, 4, 1,
1394 xstr("pirepView_mailWeight"),
1395 100000, width = 6)
1396 self._flownMailWeight.connect("value-changed", self._updateButtons)
1397 self._flownMailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
1398
1399 self._flightType = createFlightTypeComboBox()
1400 PIREPEditor.tableAttachWidget(table, 0, 2,
1401 xstr("pirepView_flightType"),
1402 self._flightType)
1403 self._flightType.connect("changed", self._updateButtons)
1404 self._flightType.set_tooltip_text(xstr("pirepEdit_flight_type_tooltip"))
1405
1406 self._online = Gtk.CheckButton(xstr("pirepEdit_online"))
1407 table.attach(self._online, 2, 3, 2, 3)
1408 self._online.connect("toggled", self._updateButtons)
1409 self._online.set_tooltip_text(xstr("pirepEdit_online_tooltip"))
1410
1411 PIREPViewer.addVFiller(mainBox)
1412
1413 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
1414 False, False, 0)
1415
1416 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
1417 mainBox.pack_start(textWindow, False, False, 0)
1418 self._delayCodes.set_tooltip_text(xstr("pirepEdit_delayCodes_tooltip"))
1419
1420 return frame
1421
1422 def _buildCommentsTab(self):
1423 """Build the tab with the comments and flight defects."""
1424 return FlightInfo(self._gui, callbackObject = self)
1425
1426 def _buildLogTab(self):
1427 """Build the log tab."""
1428 mainBox = Gtk.VBox()
1429
1430 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
1431 addFaultTag(self._log.get_buffer())
1432 mainBox.pack_start(logWindow, True, True, 0)
1433
1434 return mainBox
1435
1436 def _upperChanged(self, entry, arg = None):
1437 """Called when the value of some entry widget has changed and the value
1438 should be converted to uppercase."""
1439 entry.set_text(entry.get_text().upper())
1440 self._updateButtons()
1441 #self._valueChanged(entry, arg)
1442
1443 def _upperChangedComboBox(self, comboBox):
1444 """Called for combo box widgets that must be converted to uppercase."""
1445 entry = comboBox.get_child()
1446 if comboBox.get_active()==-1:
1447 entry.set_text(entry.get_text().upper())
1448 self._updateButtons()
1449 #self._valueChanged(entry)
1450
1451 def _updateButtons(self, *kwargs):
1452 """Update the activity state of the buttons."""
1453 pirep = self._pirep
1454 bookedFlight = pirep.bookedFlight
1455
1456 departureMinutes = \
1457 bookedFlight.departureTime.hour*60 + bookedFlight.departureTime.minute
1458 departureDifference = abs(Flight.getMinutesDifference(self._blockTimeStart.minutes,
1459 departureMinutes))
1460 flightStartDifference = \
1461 Flight.getMinutesDifference(self._flightTimeStart.minutes,
1462 self._blockTimeStart.minutes)
1463 arrivalMinutes = \
1464 bookedFlight.arrivalTime.hour*60 + bookedFlight.arrivalTime.minute
1465 arrivalDifference = abs(Flight.getMinutesDifference(self._blockTimeEnd.minutes,
1466 arrivalMinutes))
1467 flightEndDifference = \
1468 Flight.getMinutesDifference(self._blockTimeEnd.minutes,
1469 self._flightTimeEnd.minutes)
1470
1471 timesOK = self._flightInfo.hasComments or \
1472 self._flightInfo.hasDelayCode or \
1473 (departureDifference<=Flight.TIME_ERROR_DIFFERENCE and
1474 arrivalDifference<=Flight.TIME_ERROR_DIFFERENCE and
1475 flightStartDifference>=0 and flightStartDifference<30 and
1476 flightEndDifference>=0 and flightEndDifference<30)
1477
1478 text = self._sid.get_child().get_text()
1479 sid = text if self._sid.get_active()!=0 and text and text!="N/A" \
1480 else None
1481
1482 text = self._star.get_child().get_text()
1483 star = text if self._star.get_active()!=0 and text and text!="N/A" \
1484 else None
1485
1486 text = self._transition.get_child().get_text()
1487 transition = text if self._transition.get_active()!=0 \
1488 and text and text!="N/A" else None
1489
1490
1491 buffer = self._userRoute.get_buffer()
1492 route = buffer.get_text(buffer.get_start_iter(),
1493 buffer.get_end_iter(), True)
1494
1495 self._okButton.set_sensitive(self._modified and timesOK and
1496 self._flightInfo.faultsFullyExplained and
1497 self._flownNumPassengers.get_value_as_int()>0 and
1498 self._flownNumCrew.get_value_as_int()>2 and
1499 self._fuelUsed.get_value_as_int()>0 and
1500 self._departureRunway.get_text_length()>0 and
1501 self._arrivalRunway.get_text_length()>0 and
1502 self._departureMETAR.get_buffer().get_char_count()>0 and
1503 self._arrivalMETAR.get_buffer().get_char_count()>0 and
1504 self._filedCruiseLevel.get_value_as_int()>=50 and
1505 self._modifiedCruiseLevel.get_value_as_int()>=50 and
1506 sid is not None and (star is not None or
1507 transition is not None) and route!="" and
1508 self._approachType.get_text()!="")
1509
1510 def _okClicked(self, button):
1511 """Called when the OK button has been clicked.
1512
1513 The PIREP is updated from the data in the window."""
1514 if not askYesNo(xstr("pirepEdit_save_question"), parent = self):
1515 self.response(Gtk.ResponseType.CANCEL)
1516
1517 pirep = self._pirep
1518
1519 pirep.filedCruiseAltitude = \
1520 self._filedCruiseLevel.get_value_as_int() * 100
1521 pirep.cruiseAltitude = \
1522 self._modifiedCruiseLevel.get_value_as_int() * 100
1523
1524 pirep.route = getTextViewText(self._userRoute)
1525
1526 pirep.departureMETAR = getTextViewText(self._departureMETAR)
1527 pirep.departureRunway = self._departureRunway.get_text()
1528 pirep.sid = self._sid.get_child().get_text()
1529
1530 pirep.arrivalMETAR = getTextViewText(self._arrivalMETAR)
1531 pirep.star = None if self._star.get_active()==0 \
1532 else self._star.get_child().get_text()
1533 pirep.transition = None if self._transition.get_active()==0 \
1534 else self._transition.get_child().get_text()
1535 pirep.approachType = self._approachType.get_text()
1536 pirep.arrivalRunway = self._arrivalRunway.get_text()
1537
1538 pirep.blockTimeStart = \
1539 self._blockTimeStart.getTimestampFrom(pirep.blockTimeStart)
1540 pirep.blockTimeEnd = \
1541 self._blockTimeEnd.getTimestampFrom(pirep.blockTimeEnd)
1542 pirep.flightTimeStart = \
1543 self._flightTimeStart.getTimestampFrom(pirep.flightTimeStart)
1544 pirep.flightTimeEnd = \
1545 self._flightTimeEnd.getTimestampFrom(pirep.flightTimeEnd)
1546
1547 pirep.fuelUsed = self._fuelUsed.get_value()
1548
1549 pirep.numCrew = self._flownNumCrew.get_value()
1550 pirep.numPassengers = self._flownNumPassengers.get_value()
1551 pirep.bagWeight = self._flownBagWeight.get_value()
1552 pirep.cargoWeight = self._flownCargoWeight.get_value()
1553 pirep.mailWeight = self._flownMailWeight.get_value()
1554
1555 pirep.flightType = flightTypes[self._flightType.get_active()]
1556 pirep.online = self._online.get_active()
1557
1558 pirep.delayCodes = self._flightInfo.delayCodes
1559 pirep.comments = self._flightInfo.comments
1560 pirep.flightDefects = self._flightInfo.faultsAndExplanations
1561
1562 self.response(Gtk.ResponseType.OK)
1563
1564
1565#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.