source: src/mlx/gui/pirep.py@ 986:97ad2dd3f77f

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

The PIREP reviewer's message is not editable.

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