source: src/mlx/gui/pirep.py@ 985:f5569c17e934

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

The sender of a message is visible in the PIREP viewer (re #347).

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