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

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

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

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