source: src/mlx/gui/pirep.py@ 1005:5ba38c0f2ab9

python3
Last change on this file since 1005:5ba38c0f2ab9 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
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
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))
[831]343
[220]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)
[831]370
[220]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
[303]380 self._flownNumCrew.set_text("%d" % (pirep.numCrew,))
381 self._flownNumPassengers.set_text("%d" % (pirep.numPassengers,))
382 self._flownBagWeight.set_text("%.0f" % (pirep.bagWeight,))
[223]383 self._flownCargoWeight.set_text("%.0f" % (pirep.cargoWeight,))
[303]384 self._flownMailWeight.set_text("%.0f" % (pirep.mailWeight,))
[831]385 self._flightType.set_text(xstr("flighttype_" +
[220]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 += ", "
[437]393 delayCodes += code
[831]394
395 self._delayCodes.get_buffer().set_text(delayCodes)
[221]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("")
[225]402 lineIndex = 0
[221]403 for (timeStr, line) in pirep.logLines:
[225]404 isFault = lineIndex in pirep.faultLineIndexes
[226]405 appendTextBuffer(logBuffer,
406 formatFlightLogLine(timeStr, line),
407 isFault = isFault)
[225]408 lineIndex += 1
[221]409
[855]410 if self._showMessages:
411 self._messages.reset()
412 for message in pirep.messages:
413 self._messages.addMessage(message)
414
[221]415 self._notebook.set_current_page(0)
[224]416 self._okButton.grab_default()
[220]417
418 def _buildDataTab(self):
419 """Build the data tab of the viewer."""
[996]420 table = Gtk.Table(1, 2)
[220]421 table.set_row_spacings(4)
422 table.set_col_spacings(16)
423 table.set_homogeneous(True)
424
[996]425 box1 = Gtk.VBox()
[220]426 table.attach(box1, 0, 1, 0, 1)
[831]427
[996]428 box2 = Gtk.VBox()
[220]429 table.attach(box2, 1, 2, 0, 1)
[831]430
[220]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."""
[831]453
[220]454 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
[831]455
[996]456 dataBox = Gtk.HBox()
[220]457 mainBox.pack_start(dataBox, False, False, 0)
[831]458
[220]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
[996]471 dataBox = Gtk.HBox()
[220]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
[996]481 table = Gtk.Table(3, 2)
[220]482 mainBox.pack_start(table, False, False, 0)
483 table.set_row_spacings(4)
[831]484 table.set_col_spacings(8)
[220]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
[996]506 table = Gtk.Table(3, 2)
[220]507 mainBox.pack_start(table, False, False, 0)
508 table.set_row_spacings(4)
[831]509 table.set_col_spacings(8)
[220]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 = \
[831]522 PIREPViewer.tableAttach(table, 0, 1,
[220]523 xstr("pirepView_bagWeight"),
524 width = 5)
525
526 self._cargoWeight = \
[831]527 PIREPViewer.tableAttach(table, 1, 1,
[220]528 xstr("pirepView_cargoWeight"),
529 width = 5)
530
531 self._mailWeight = \
[831]532 PIREPViewer.tableAttach(table, 2, 1,
[220]533 xstr("pirepView_mailWeight"),
534 width = 5)
[831]535
[220]536 PIREPViewer.addVFiller(mainBox)
537
538 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
539 False, False, 0)
[831]540
[220]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."""
[831]549
[220]550 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
551
[996]552 levelBox = Gtk.HBox()
[220]553 mainBox.pack_start(levelBox, False, False, 0)
[831]554
[220]555 self._filedCruiseLevel = \
[831]556 PIREPViewer.addLabeledData(levelBox,
[220]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):
[831]573 """Build the frame for the departure data."""
[220]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
[996]584 dataBox = Gtk.HBox()
[220]585 mainBox.pack_start(dataBox, False, False, 0)
[831]586
[220]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
[831]598
[220]599 def _buildArrivalFrame(self):
[831]600 """Build the frame for the arrival data."""
[220]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
[996]611 table = Gtk.Table(2, 2)
[220]612 mainBox.pack_start(table, False, False, 0)
613 table.set_row_spacings(4)
[831]614 table.set_col_spacings(8)
[220]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)
[831]625
[220]626 self._approachType = \
627 PIREPViewer.tableAttach(table, 0, 1,
628 xstr("pirepView_approachType"),
629 width = 7)
[831]630
[220]631 self._arrivalRunway = \
[831]632 PIREPViewer.tableAttach(table, 1, 1,
[220]633 xstr("pirepView_runway"),
634 width = 5)
[831]635
[220]636 return frame
637
638 def _buildStatisticsFrame(self):
[831]639 """Build the frame for the statistics data."""
[220]640 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
641
[996]642 table = Gtk.Table(4, 2)
[220]643 mainBox.pack_start(table, False, False, 0)
644 table.set_row_spacings(4)
645 table.set_col_spacings(8)
[221]646 table.set_homogeneous(False)
[831]647
[220]648 self._blockTimeStart = \
649 PIREPViewer.tableAttach(table, 0, 0,
650 xstr("pirepView_blockTimeStart"),
651 width = 6)
[831]652
[220]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)
[831]662
[220]663 self._flightTimeEnd = \
[831]664 PIREPViewer.tableAttach(table, 1, 1,
[220]665 xstr("pirepView_flightTimeEnd"),
666 width = 6)
667
668 self._flownDistance = \
669 PIREPViewer.tableAttach(table, 0, 2,
670 xstr("pirepView_flownDistance"),
671 width = 8)
[831]672
[220]673 self._fuelUsed = \
674 PIREPViewer.tableAttach(table, 1, 2,
675 xstr("pirepView_fuelUsed"),
676 width = 6)
[831]677
[220]678 self._rating = \
679 PIREPViewer.tableAttach(table, 0, 3,
680 xstr("pirepView_rating"),
681 width = 7)
682 return frame
683
684 def _buildMiscellaneousFrame(self):
[831]685 """Build the frame for the miscellaneous data."""
[220]686 (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
[303]687
[996]688 table = Gtk.Table(3, 2)
[303]689 mainBox.pack_start(table, False, False, 0)
690 table.set_row_spacings(4)
[831]691 table.set_col_spacings(8)
692
[303]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
[223]708 self._flownCargoWeight = \
[303]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)
[223]717
[220]718 self._flightType = \
[303]719 PIREPViewer.tableAttach(table, 0, 2,
720 xstr("pirepView_flightType"),
721 width = 15)
[831]722
[220]723 self._online = \
[303]724 PIREPViewer.tableAttach(table, 1, 2,
725 xstr("pirepView_online"),
726 width = 5)
[220]727
728 PIREPViewer.addVFiller(mainBox)
729
730 mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
731 False, False, 0)
[831]732
[220]733 (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
734 mainBox.pack_start(textWindow, False, False, 0)
735
[831]736 return frame
[220]737
[221]738 def _buildCommentsTab(self):
739 """Build the tab with the comments and flight defects."""
[996]740 table = Gtk.Table(2, 1)
[221]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)
[831]758
[221]759 return table
760
761 def _buildLogTab(self):
762 """Build the log tab."""
[996]763 mainBox = Gtk.VBox()
[221]764
765 (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
[226]766 addFaultTag(self._log.get_buffer())
[221]767 mainBox.pack_start(logWindow, True, True, 0)
[831]768
[221]769 return mainBox
[831]770
[855]771 def _buildMessagesTab(self):
772 """Build the messages tab."""
[996]773 mainBox = Gtk.VBox()
[855]774
775 self._messages = MessagesWidget(self._gui)
776 mainBox.pack_start(self._messages, True, True, 0)
777
778 return mainBox
779
[220]780#------------------------------------------------------------------------------
[845]781
[996]782class PIREPEditor(Gtk.Dialog):
[845]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)."""
[996]792 label = Gtk.Label("<b>" + labelText + "</b>")
[845]793 label.set_use_markup(True)
[996]794 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.5,
[845]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)."""
[996]810 button = Gtk.SpinButton()
[845]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]846 self._pirep = None
847
[845]848 contentArea = self.get_content_area()
849
[996]850 self._notebook = Gtk.Notebook()
[845]851 contentArea.pack_start(self._notebook, False, False, 4)
852
853 dataTab = self._buildDataTab()
[996]854 label = Gtk.Label(xstr("pirepView_tab_data"))
[845]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()
[996]860 label = Gtk.Label(xstr("pirepView_tab_comments"))
[845]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()
[996]866 label = Gtk.Label(xstr("pirepView_tab_log"))
[845]867 label.set_use_underline(True)
868 label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
869 self._notebook.append_page(logTab, label)
870
[999]871 self.add_button(xstr("button_cancel"), Gtk.ResponseType.CANCEL)
[846]872
[999]873 self._okButton = self.add_button(xstr("button_save"), Gtk.ResponseType.NONE)
[853]874 self._okButton.connect("clicked", self._okClicked)
[845]875 self._okButton.set_can_default(True)
[849]876 self._modified = False
[853]877 self._toSave = False
[845]878
879 def setPIREP(self, pirep):
880 """Setup the data in the dialog from the given PIREP."""
[846]881 self._pirep = pirep
882
[845]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
[849]998 self._modified = False
[846]999 self._updateButtons()
[849]1000 self._modified = True
[853]1001 self._toSave = False
[846]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
[845]1015 def _buildDataTab(self):
1016 """Build the data tab of the viewer."""
[996]1017 table = Gtk.Table(1, 2)
[845]1018 table.set_row_spacings(4)
1019 table.set_col_spacings(16)
1020 table.set_homogeneous(True)
1021
[996]1022 box1 = Gtk.VBox()
[845]1023 table.attach(box1, 0, 1, 0, 1)
1024
[996]1025 box2 = Gtk.VBox()
[845]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
[996]1053 dataBox = Gtk.HBox()
[845]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
[996]1068 dataBox = Gtk.HBox()
[845]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
[996]1078 table = Gtk.Table(3, 2)
[845]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
[996]1103 table = Gtk.Table(3, 2)
[845]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
[996]1148 levelBox = Gtk.HBox()
[845]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
[996]1155 self._filedCruiseLevel = Gtk.SpinButton()
[845]1156 self._filedCruiseLevel.set_increments(step = 10, page = 100)
1157 self._filedCruiseLevel.set_range(min = 0, max = 500)
[847]1158 self._filedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
[845]1159 self._filedCruiseLevel.set_numeric(True)
[846]1160 self._filedCruiseLevel.connect("value-changed", self._updateButtons)
[845]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
[996]1170 self._modifiedCruiseLevel = Gtk.SpinButton()
[845]1171 self._modifiedCruiseLevel.set_increments(step = 10, page = 100)
1172 self._modifiedCruiseLevel.set_range(min = 0, max = 500)
[847]1173 self._modifiedCruiseLevel.set_tooltip_text(xstr("pirepEdit_modified_route_level_tooltip"))
[845]1174 self._modifiedCruiseLevel.set_numeric(True)
[846]1175 self._modifiedCruiseLevel.connect("value-changed", self._updateButtons)
[845]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)
[846]1184 self._userRoute.get_buffer().connect("changed", self._updateButtons)
[847]1185 self._userRoute.set_tooltip_text(xstr("route_route_tooltip"))
[845]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)
[846]1198 self._departureMETAR.get_buffer().connect("changed", self._updateButtons)
[847]1199 self._departureMETAR.set_tooltip_text(xstr("takeoff_metar_tooltip"))
[845]1200 mainBox.pack_start(metarWindow, True, True, 0)
1201
1202 PIREPViewer.addVFiller(mainBox)
1203
[996]1204 dataBox = Gtk.HBox()
[845]1205 mainBox.pack_start(dataBox, False, False, 0)
1206
[996]1207 label = Gtk.Label("<b>" + xstr("pirepView_runway") + "</b>")
[845]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
[996]1212 self._departureRunway = Gtk.Entry()
[845]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
[996]1218 label = Gtk.Label("<b>" + xstr("pirepView_sid") + "</b>")
[845]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
[996]1224 self._sid = Gtk.ComboBox.new_with_model_and_entry(comboModel)
[845]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)
[846]1244 self._arrivalMETAR.get_buffer().connect("changed", self._updateButtons)
[847]1245 self._arrivalMETAR.set_tooltip_text(xstr("landing_metar_tooltip"))
[845]1246 mainBox.pack_start(metarWindow, True, True, 0)
1247
1248 PIREPViewer.addVFiller(mainBox)
1249
[996]1250 table = Gtk.Table(2, 4)
[845]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
[996]1256 self._star = Gtk.ComboBox.new_with_model_and_entry(comboModel)
[845]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
[996]1268 self._transition = Gtk.ComboBox.new_with_model_and_entry(comboModel)
[845]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
[996]1281 self._approachType = Gtk.Entry()
[845]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
[996]1291 self._arrivalRunway = Gtk.Entry()
[845]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
[996]1306 table = Gtk.Table(4, 4)
[845]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"))
[846]1315 self._blockTimeStart.connect("changed", self._updateButtons)
[847]1316 self._blockTimeStart.set_tooltip_text(xstr("pirepEdit_block_time_start_tooltip"))
[845]1317
1318 self._blockTimeEnd = \
1319 PIREPEditor.tableAttachTimeEntry(table, 2, 0,
1320 xstr("pirepView_blockTimeEnd"))
[846]1321 self._blockTimeEnd.connect("changed", self._updateButtons)
[847]1322 self._blockTimeEnd.set_tooltip_text(xstr("pirepEdit_block_time_end_tooltip"))
[845]1323
1324 self._flightTimeStart = \
1325 PIREPEditor.tableAttachTimeEntry(table, 0, 1,
1326 xstr("pirepView_flightTimeStart"))
[846]1327 self._flightTimeStart.connect("changed", self._updateButtons)
[847]1328 self._flightTimeStart.set_tooltip_text(xstr("pirepEdit_flight_time_start_tooltip"))
[845]1329
1330 self._flightTimeEnd = \
1331 PIREPEditor.tableAttachTimeEntry(table, 2, 1,
1332 xstr("pirepView_flightTimeEnd"))
[846]1333 self._flightTimeEnd.connect("changed", self._updateButtons)
[847]1334 self._flightTimeEnd.set_tooltip_text(xstr("pirepEdit_flight_time_end_tooltip"))
[845]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)
[846]1345 self._fuelUsed.connect("value-changed", self._updateButtons)
[847]1346 self._fuelUsed.set_tooltip_text(xstr("pirepEdit_fuel_used_tooltip"))
[845]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
[996]1358 table = Gtk.Table(6, 2)
[845]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)
[846]1368 self._flownNumPassengers.connect("value-changed", self._updateButtons)
[847]1369 self._flownNumPassengers.set_tooltip_text(xstr("payload_pax_tooltip"))
[845]1370
1371 self._flownNumCrew = \
1372 PIREPEditor.tableAttachSpinButton(table, 2, 0,
1373 xstr("pirepView_numCrew"),
1374 10)
[846]1375 self._flownNumCrew.connect("value-changed", self._updateButtons)
[847]1376 self._flownNumCrew.set_tooltip_text(xstr("payload_crew_tooltip"))
[845]1377
1378 self._flownBagWeight = \
1379 PIREPEditor.tableAttachSpinButton(table, 0, 1,
1380 xstr("pirepView_bagWeight"),
1381 100000, width = 6)
[849]1382 self._flownBagWeight.connect("value-changed", self._updateButtons)
[847]1383 self._flownBagWeight.set_tooltip_text(xstr("payload_bag_tooltip"))
[845]1384
1385 self._flownCargoWeight = \
1386 PIREPEditor.tableAttachSpinButton(table, 2, 1,
1387 xstr("pirepView_cargoWeight"),
1388 100000, width = 6)
[849]1389 self._flownCargoWeight.connect("value-changed", self._updateButtons)
[847]1390 self._flownCargoWeight.set_tooltip_text(xstr("payload_cargo_tooltip"))
[845]1391
1392 self._flownMailWeight = \
1393 PIREPEditor.tableAttachSpinButton(table, 4, 1,
1394 xstr("pirepView_mailWeight"),
1395 100000, width = 6)
[849]1396 self._flownMailWeight.connect("value-changed", self._updateButtons)
[847]1397 self._flownMailWeight.set_tooltip_text(xstr("payload_mail_tooltip"))
[845]1398
1399 self._flightType = createFlightTypeComboBox()
1400 PIREPEditor.tableAttachWidget(table, 0, 2,
1401 xstr("pirepView_flightType"),
1402 self._flightType)
[849]1403 self._flightType.connect("changed", self._updateButtons)
[847]1404 self._flightType.set_tooltip_text(xstr("pirepEdit_flight_type_tooltip"))
[845]1405
[996]1406 self._online = Gtk.CheckButton(xstr("pirepEdit_online"))
[845]1407 table.attach(self._online, 2, 3, 2, 3)
[849]1408 self._online.connect("toggled", self._updateButtons)
[847]1409 self._online.set_tooltip_text(xstr("pirepEdit_online_tooltip"))
[845]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)
[847]1418 self._delayCodes.set_tooltip_text(xstr("pirepEdit_delayCodes_tooltip"))
[845]1419
1420 return frame
1421
1422 def _buildCommentsTab(self):
1423 """Build the tab with the comments and flight defects."""
[846]1424 return FlightInfo(self._gui, callbackObject = self)
[845]1425
1426 def _buildLogTab(self):
1427 """Build the log tab."""
[996]1428 mainBox = Gtk.VBox()
[845]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())
[846]1440 self._updateButtons()
[845]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())
[846]1448 self._updateButtons()
[845]1449 #self._valueChanged(entry)
1450
[846]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
[849]1495 self._okButton.set_sensitive(self._modified and timesOK and
[846]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
[853]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):
[999]1515 self.response(Gtk.ResponseType.CANCEL)
[853]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
[999]1562 self.response(Gtk.ResponseType.OK)
[853]1563
1564
[845]1565#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.