source: src/mlx/gui/pirep.py@ 1034:4836f52b49cd

python3
Last change on this file since 1034:4836f52b49cd was 1034:4836f52b49cd, checked in by István Váradi <ivaradi@…>, 2 years ago

Updated the flight type handling (re #357)

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