Index: src/mlx/gui/pirep.py
===================================================================
--- src/mlx/gui/pirep.py	(revision 831)
+++ src/mlx/gui/pirep.py	(revision 833)
@@ -1,4 +1,7 @@
 
 from common import *
+from dcdata import getTable
+from info import FlightInfo
+from flight import comboModel
 
 from mlx.pirep import PIREP
@@ -6,4 +9,5 @@
 
 import time
+import re
 
 #------------------------------------------------------------------------------
@@ -11,5 +15,5 @@
 ## @package mlx.gui.pirep
 #
-# The detailed PIREP viewer.
+# The detailed PIREP viewer and editor windows.
 #
 # The \ref PIREPViewer class is a dialog displaying all information found in a
@@ -47,7 +51,7 @@
 
     @staticmethod
-    def getLabel(text):
+    def getLabel(text, extraText = ""):
         """Get a bold label with the given text."""
-        label = gtk.Label("<b>" + text + "</b>")
+        label = gtk.Label("<b>" + text + "</b>" + extraText)
         label.set_use_markup(True)
         label.set_alignment(0.0, 0.5)
@@ -64,5 +68,5 @@
 
     @staticmethod
-    def getTextWindow(heightRequest = 40):
+    def getTextWindow(heightRequest = 40, editable = False):
         """Get a scrollable text window.
 
@@ -76,6 +80,6 @@
         textView = gtk.TextView()
         textView.set_wrap_mode(WRAP_WORD)
-        textView.set_editable(False)
-        textView.set_cursor_visible(False)
+        textView.set_editable(editable)
+        textView.set_cursor_visible(editable)
         textView.set_size_request(-1, heightRequest)
         scrolledWindow.add(textView)
@@ -106,5 +110,5 @@
         """Add a label and a data label to the given HBox.
 
-        Returnsd the data label."""
+        Returns the data label."""
         label = PIREPViewer.getLabel(labelText)
         hBox.pack_start(label, False, False, 0)
@@ -114,4 +118,12 @@
 
         return dataLabel
+
+    @staticmethod
+    def addHFiller(hBox, width = 8):
+        """Add a filler to the given horizontal box."""
+        filler = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                               xscale = 1.0, yscale = 1.0)
+        filler.set_size_request(width, -1)
+        hBox.pack_start(filler, False, False, 0)
 
     @staticmethod
@@ -615,2 +627,623 @@
 
 #------------------------------------------------------------------------------
+
+class PIREPEditor(gtk.Dialog):
+    """A PIREP editor dialog."""
+    _delayCodeRE = re.compile("([0-9]{2,3})( \([^\)]*\))")
+
+    @staticmethod
+    def tableAttachWidget(table, column, row, labelText, widget):
+        """Attach the given widget with the given label to the given table.
+
+        The label will got to cell (column, row), the widget to cell
+        (column+1, row)."""
+        label = gtk.Label("<b>" + labelText + "</b>")
+        label.set_use_markup(True)
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+        alignment.add(label)
+        table.attach(alignment, column, column + 1, row, row + 1)
+
+        table.attach(widget, column + 1, column + 2, row, row + 1)
+
+    @staticmethod
+    def tableAttachSpinButton(table, column, row, labelText, maxValue,
+                              minValue = 0, stepIncrement = 1,
+                              pageIncrement = 10, numeric = True,
+                              width = 3):
+        """Attach a spin button with the given label to the given table.
+
+        The label will got to cell (column, row), the spin button to cell
+        (column+1, row)."""
+        button = gtk.SpinButton()
+        button.set_range(min = minValue, max = maxValue)
+        button.set_increments(step = stepIncrement, page = pageIncrement)
+        button.set_numeric(True)
+        button.set_width_chars(width)
+        button.set_alignment(1.0)
+
+        PIREPEditor.tableAttachWidget(table, column, row, labelText, button)
+
+        return button
+
+    @staticmethod
+    def tableAttachTimeEntry(table, column, row, labelText):
+        """Attach a time entry widget with the given label to the given table.
+
+        The label will got to cell (column, row), the spin button to cell
+        (column+1, row)."""
+        entry = TimeEntry()
+        entry.set_width_chars(5)
+        entry.set_alignment(1.0)
+
+        PIREPEditor.tableAttachWidget(table, column, row, labelText, entry)
+
+        return entry
+
+    def __init__(self, gui):
+        """Construct the PIREP viewer."""
+        super(PIREPEditor, self).__init__(title = WINDOW_TITLE_BASE +
+                                          " - " +
+                                          xstr("pirepEdit_title"),
+                                          parent = gui.mainWindow)
+
+        self.set_resizable(False)
+
+        self._gui = gui
+
+        contentArea = self.get_content_area()
+
+        self._notebook = gtk.Notebook()
+        contentArea.pack_start(self._notebook, False, False, 4)
+
+        dataTab = self._buildDataTab()
+        label = gtk.Label(xstr("pirepView_tab_data"))
+        label.set_use_underline(True)
+        label.set_tooltip_text(xstr("pirepView_tab_data_tooltip"))
+        self._notebook.append_page(dataTab, label)
+
+        self._flightInfo = self._buildCommentsTab()
+        label = gtk.Label(xstr("pirepView_tab_comments"))
+        label.set_use_underline(True)
+        label.set_tooltip_text(xstr("pirepView_tab_comments_tooltip"))
+        self._notebook.append_page(self._flightInfo, label)
+
+        logTab = self._buildLogTab()
+        label = gtk.Label(xstr("pirepView_tab_log"))
+        label.set_use_underline(True)
+        label.set_tooltip_text(xstr("pirepView_tab_log_tooltip"))
+        self._notebook.append_page(logTab, label)
+
+        self._okButton = self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
+        self._okButton.set_can_default(True)
+
+    def setPIREP(self, pirep):
+        """Setup the data in the dialog from the given PIREP."""
+        bookedFlight = pirep.bookedFlight
+
+        self._callsign.set_text(bookedFlight.callsign)
+        self._tailNumber.set_text(bookedFlight.tailNumber)
+        aircraftType = xstr("aircraft_" + icaoCodes[bookedFlight.aircraftType].lower())
+        self._aircraftType.set_text(aircraftType)
+
+        self._departureICAO.set_text(bookedFlight.departureICAO)
+        self._departureTime.set_text("%02d:%02d" % \
+                                     (bookedFlight.departureTime.hour,
+                                      bookedFlight.departureTime.minute))
+
+        self._arrivalICAO.set_text(bookedFlight.arrivalICAO)
+        self._arrivalTime.set_text("%02d:%02d" % \
+                                   (bookedFlight.arrivalTime.hour,
+                                    bookedFlight.arrivalTime.minute))
+
+        self._numPassengers.set_text(str(bookedFlight.numPassengers))
+        self._numCrew.set_text(str(bookedFlight.numCrew))
+        self._bagWeight.set_text(str(bookedFlight.bagWeight))
+        self._cargoWeight.set_text(str(bookedFlight.cargoWeight))
+        self._mailWeight.set_text(str(bookedFlight.mailWeight))
+
+        self._route.get_buffer().set_text(bookedFlight.route)
+
+        self._filedCruiseLevel.set_value(pirep.filedCruiseAltitude/100)
+        self._modifiedCruiseLevel.set_value(pirep.cruiseAltitude/100)
+
+        self._userRoute.get_buffer().set_text(pirep.route)
+
+        self._departureMETAR.get_buffer().set_text(pirep.departureMETAR)
+
+        self._arrivalMETAR.get_buffer().set_text(pirep.arrivalMETAR)
+        self._departureRunway.set_text(pirep.departureRunway)
+        self._sid.get_child().set_text(pirep.sid)
+
+        if not pirep.star:
+            self._star.set_active(0)
+        else:
+            self._star.get_child().set_text(pirep.star)
+
+        if not pirep.transition:
+            self._transition.set_active(0)
+        else:
+            self._transition.get_child().set_text(pirep.transition)
+        self._approachType.set_text(pirep.approachType)
+        self._arrivalRunway.set_text(pirep.arrivalRunway)
+
+        self._blockTimeStart.setTimestamp(pirep.blockTimeStart)
+        self._blockTimeEnd.setTimestamp(pirep.blockTimeEnd)
+        self._flightTimeStart.setTimestamp(pirep.flightTimeStart)
+        self._flightTimeEnd.setTimestamp(pirep.flightTimeEnd)
+
+        self._flownDistance.set_text("%.1f" % (pirep.flownDistance,))
+        self._fuelUsed.set_value(int(pirep.fuelUsed))
+
+        rating = pirep.rating
+        if rating<0:
+            self._rating.set_markup('<b><span foreground="red">NO GO</span></b>')
+        else:
+            self._rating.set_text("%.1f %%" % (rating,))
+
+        self._flownNumCrew.set_value(pirep.numCrew)
+        self._flownNumPassengers.set_value(pirep.numPassengers)
+        self._flownBagWeight.set_value(pirep.bagWeight)
+        self._flownCargoWeight.set_value(pirep.cargoWeight)
+        self._flownMailWeight.set_value(pirep.mailWeight)
+        self._flightType.set_active(flightType2index(pirep.flightType))
+        self._online.set_active(pirep.online)
+
+        self._flightInfo.reset()
+        self._flightInfo.enable(bookedFlight.aircraftType)
+
+        delayCodes = ""
+        for code in pirep.delayCodes:
+            if delayCodes: delayCodes += ", "
+            delayCodes += code
+            m = PIREPEditor._delayCodeRE.match(code)
+            if m:
+                self._flightInfo.activateDelayCode(m.group(1))
+
+        self._delayCodes.get_buffer().set_text(delayCodes)
+
+        self._flightInfo.comments = pirep.comments
+        if pirep.flightDefects.find("<br/></b>")!=-1:
+            flightDefects = pirep.flightDefects.split("<br/></b>")
+            caption = flightDefects[0]
+            index = 0
+            for defect in flightDefects[1:]:
+                if defect.find("<b>")!=-1:
+                    (explanation, nextCaption) = defect.split("<b>")
+                else:
+                    explanation = defect
+                    nextCaption = None
+                self._flightInfo.addFault(index, caption)
+                self._flightInfo.setExplanation(index, explanation)
+                index += 1
+                caption = nextCaption
+
+        # self._comments.get_buffer().set_text(pirep.comments)
+        # self._flightDefects.get_buffer().set_text(pirep.flightDefects)
+
+        logBuffer = self._log.get_buffer()
+        logBuffer.set_text("")
+        lineIndex = 0
+        for (timeStr, line) in pirep.logLines:
+            isFault = lineIndex in pirep.faultLineIndexes
+            appendTextBuffer(logBuffer,
+                             formatFlightLogLine(timeStr, line),
+                             isFault = isFault)
+            lineIndex += 1
+
+        self._notebook.set_current_page(0)
+        self._okButton.grab_default()
+
+    def _buildDataTab(self):
+        """Build the data tab of the viewer."""
+        table = gtk.Table(1, 2)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(True)
+
+        box1 = gtk.VBox()
+        table.attach(box1, 0, 1, 0, 1)
+
+        box2 = gtk.VBox()
+        table.attach(box2, 1, 2, 0, 1)
+
+        flightFrame = self._buildFlightFrame()
+        box1.pack_start(flightFrame, False, False, 4)
+
+        routeFrame = self._buildRouteFrame()
+        box1.pack_start(routeFrame, False, False, 4)
+
+        departureFrame = self._buildDepartureFrame()
+        box2.pack_start(departureFrame, True, True, 4)
+
+        arrivalFrame = self._buildArrivalFrame()
+        box2.pack_start(arrivalFrame, True, True, 4)
+
+        statisticsFrame = self._buildStatisticsFrame()
+        box2.pack_start(statisticsFrame, False, False, 4)
+
+        miscellaneousFrame = self._buildMiscellaneousFrame()
+        box1.pack_start(miscellaneousFrame, False, False, 4)
+
+        return table
+
+    def _buildFlightFrame(self):
+        """Build the frame for the flight data."""
+
+        (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_flight"))
+
+        dataBox = gtk.HBox()
+        mainBox.pack_start(dataBox, False, False, 0)
+
+        self._callsign = \
+            PIREPViewer.addLabeledData(dataBox,
+                                       xstr("pirepView_callsign"),
+                                       width = 8)
+
+        self._tailNumber = \
+            PIREPViewer.addLabeledData(dataBox,
+                                       xstr("pirepView_tailNumber"),
+                                       width = 7)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        dataBox = gtk.HBox()
+        mainBox.pack_start(dataBox, False, False, 0)
+
+        self._aircraftType = \
+            PIREPViewer.addLabeledData(dataBox,
+                                       xstr("pirepView_aircraftType"),
+                                       width = 25)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        table = gtk.Table(3, 2)
+        mainBox.pack_start(table, False, False, 0)
+        table.set_row_spacings(4)
+        table.set_col_spacings(8)
+
+        self._departureICAO = \
+            PIREPViewer.tableAttach(table, 0, 0,
+                                    xstr("pirepView_departure"),
+                                    width = 5)
+
+        self._departureTime = \
+            PIREPViewer.tableAttach(table, 1, 0,
+                                    xstr("pirepView_departure_time"),
+                                    width = 6)
+
+        self._arrivalICAO = \
+            PIREPViewer.tableAttach(table, 0, 1,
+                                    xstr("pirepView_arrival"),
+                                    width = 5)
+
+        self._arrivalTime = \
+            PIREPViewer.tableAttach(table, 1, 1,
+                                    xstr("pirepView_arrival_time"),
+                                    width = 6)
+
+        table = gtk.Table(3, 2)
+        mainBox.pack_start(table, False, False, 0)
+        table.set_row_spacings(4)
+        table.set_col_spacings(8)
+
+        self._numPassengers = \
+            PIREPViewer.tableAttach(table, 0, 0,
+                                    xstr("pirepView_numPassengers"),
+                                    width = 4)
+
+        self._numCrew = \
+            PIREPViewer.tableAttach(table, 1, 0,
+                                    xstr("pirepView_numCrew"),
+                                    width = 3)
+
+        self._bagWeight = \
+            PIREPViewer.tableAttach(table, 0, 1,
+                                    xstr("pirepView_bagWeight"),
+                                    width = 5)
+
+        self._cargoWeight = \
+            PIREPViewer.tableAttach(table, 1, 1,
+                                    xstr("pirepView_cargoWeight"),
+                                    width = 5)
+
+        self._mailWeight = \
+            PIREPViewer.tableAttach(table, 2, 1,
+                                    xstr("pirepView_mailWeight"),
+                                    width = 5)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_route")),
+                           False, False, 0)
+
+        (routeWindow, self._route) = PIREPViewer.getTextWindow()
+        mainBox.pack_start(routeWindow, False, False, 0)
+
+        return frame
+
+    def _buildRouteFrame(self):
+        """Build the frame for the user-specified route and flight
+        level."""
+
+        (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_route"))
+
+        levelBox = gtk.HBox()
+        mainBox.pack_start(levelBox, False, False, 0)
+
+        label = PIREPViewer.getLabel(xstr("pirepView_filedCruiseLevel"),
+                                     xstr("pirepEdit_FL"))
+        levelBox.pack_start(label, False, False, 0)
+
+        self._filedCruiseLevel = gtk.SpinButton()
+        self._filedCruiseLevel.set_increments(step = 10, page = 100)
+        self._filedCruiseLevel.set_range(min = 0, max = 500)
+        #self._filedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
+        self._filedCruiseLevel.set_numeric(True)
+
+        levelBox.pack_start(self._filedCruiseLevel, False, False, 0)
+
+        PIREPViewer.addHFiller(levelBox)
+
+        label = PIREPViewer.getLabel(xstr("pirepView_modifiedCruiseLevel"),
+                                     xstr("pirepEdit_FL"))
+        levelBox.pack_start(label, False, False, 0)
+
+        self._modifiedCruiseLevel = gtk.SpinButton()
+        self._modifiedCruiseLevel.set_increments(step = 10, page = 100)
+        self._modifiedCruiseLevel.set_range(min = 0, max = 500)
+        #self._modifiedCruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
+        self._modifiedCruiseLevel.set_numeric(True)
+
+        levelBox.pack_start(self._modifiedCruiseLevel, False, False, 0)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        (routeWindow, self._userRoute) = \
+          PIREPViewer.getTextWindow(editable = True)
+        mainBox.pack_start(routeWindow, False, False, 0)
+
+        return frame
+
+    def _buildDepartureFrame(self):
+        """Build the frame for the departure data."""
+        (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_departure"))
+
+        mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
+                           False, False, 0)
+        (metarWindow, self._departureMETAR) = \
+            PIREPViewer.getTextWindow(heightRequest = -1,
+                                      editable = True)
+        mainBox.pack_start(metarWindow, True, True, 0)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        dataBox = gtk.HBox()
+        mainBox.pack_start(dataBox, False, False, 0)
+
+        label = gtk.Label("<b>" + xstr("pirepView_runway") + "</b>")
+        label.set_use_markup(True)
+        dataBox.pack_start(label, False, False, 0)
+
+        # FIXME: quite the same as the runway entry boxes in the wizard
+        self._departureRunway = gtk.Entry()
+        self._departureRunway.set_width_chars(5)
+        self._departureRunway.set_tooltip_text(xstr("takeoff_runway_tooltip"))
+        self._departureRunway.connect("changed", self._upperChanged)
+        dataBox.pack_start(self._departureRunway, False, False, 8)
+
+        label = gtk.Label("<b>" + xstr("pirepView_sid") + "</b>")
+        label.set_use_markup(True)
+        dataBox.pack_start(label, False, False, 0)
+
+        # FIXME: quite the same as the SID combo box in
+        # the flight wizard
+        if pygobject:
+            self._sid = gtk.ComboBox.new_with_model_and_entry(comboModel)
+        else:
+            self._sid = gtk.ComboBoxEntry(comboModel)
+
+        self._sid.set_entry_text_column(0)
+        self._sid.get_child().set_width_chars(10)
+        self._sid.set_tooltip_text(xstr("takeoff_sid_tooltip"))
+        self._sid.connect("changed", self._upperChangedComboBox)
+
+        dataBox.pack_start(self._sid, False, False, 8)
+
+        return frame
+
+    def _buildArrivalFrame(self):
+        """Build the frame for the arrival data."""
+        (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_arrival"))
+
+        mainBox.pack_start(PIREPViewer.getLabel("METAR:"),
+                           False, False, 0)
+        (metarWindow, self._arrivalMETAR) = \
+            PIREPViewer.getTextWindow(heightRequest = -1,
+                                      editable = True)
+        mainBox.pack_start(metarWindow, True, True, 0)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        table = gtk.Table(2, 4)
+        mainBox.pack_start(table, False, False, 0)
+        table.set_row_spacings(4)
+        table.set_col_spacings(8)
+
+        # FIXME: quite the same as in the wizard
+        if pygobject:
+            self._star = gtk.ComboBox.new_with_model_and_entry(comboModel)
+        else:
+            self._star = gtk.ComboBoxEntry(comboModel)
+
+        self._star.set_entry_text_column(0)
+        self._star.get_child().set_width_chars(10)
+        self._star.set_tooltip_text(xstr("landing_star_tooltip"))
+        self._star.connect("changed", self._upperChangedComboBox)
+
+        PIREPEditor.tableAttachWidget(table, 0, 0,
+                                      xstr("pirepView_star"),
+                                      self._star)
+
+        # FIXME: quite the same as in the wizard
+        if pygobject:
+            self._transition = gtk.ComboBox.new_with_model_and_entry(comboModel)
+        else:
+            self._transition = gtk.ComboBoxEntry(comboModel)
+
+        self._transition.set_entry_text_column(0)
+        self._transition.get_child().set_width_chars(10)
+        self._transition.set_tooltip_text(xstr("landing_transition_tooltip"))
+        self._transition.connect("changed", self._upperChangedComboBox)
+
+        PIREPEditor.tableAttachWidget(table, 2, 0,
+                                      xstr("pirepView_transition"),
+                                      self._transition)
+
+
+        # FIXME: quite the same as in the wizard
+        self._approachType = gtk.Entry()
+        self._approachType.set_width_chars(10)
+        self._approachType.set_tooltip_text(xstr("landing_approach_tooltip"))
+        self._approachType.connect("changed", self._upperChanged)
+
+        PIREPEditor.tableAttachWidget(table, 0, 1,
+                                      xstr("pirepView_approachType"),
+                                      self._approachType)
+
+        # FIXME: quite the same as in the wizard
+        self._arrivalRunway = gtk.Entry()
+        self._arrivalRunway.set_width_chars(10)
+        self._arrivalRunway.set_tooltip_text(xstr("landing_runway_tooltip"))
+        self._arrivalRunway.connect("changed", self._upperChanged)
+
+        PIREPEditor.tableAttachWidget(table, 2, 1,
+                                      xstr("pirepView_runway"),
+                                      self._arrivalRunway)
+
+        return frame
+
+    def _buildStatisticsFrame(self):
+        """Build the frame for the statistics data."""
+        (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_statistics"))
+
+        table = gtk.Table(4, 4)
+        mainBox.pack_start(table, False, False, 0)
+        table.set_row_spacings(4)
+        table.set_col_spacings(8)
+        table.set_homogeneous(False)
+
+        self._blockTimeStart = \
+            PIREPEditor.tableAttachTimeEntry(table, 0, 0,
+                                             xstr("pirepView_blockTimeStart"))
+
+        self._blockTimeEnd = \
+            PIREPEditor.tableAttachTimeEntry(table, 2, 0,
+                                             xstr("pirepView_blockTimeEnd"))
+
+        self._flightTimeStart = \
+            PIREPEditor.tableAttachTimeEntry(table, 0, 1,
+                                             xstr("pirepView_flightTimeStart"))
+
+        self._flightTimeEnd = \
+            PIREPEditor.tableAttachTimeEntry(table, 2, 1,
+                                             xstr("pirepView_flightTimeEnd"))
+
+        self._flownDistance = PIREPViewer.getDataLabel(width = 3)
+        PIREPEditor.tableAttachWidget(table, 0, 2,
+                                      xstr("pirepView_flownDistance"),
+                                      self._flownDistance)
+
+        self._fuelUsed = \
+            PIREPEditor.tableAttachSpinButton(table, 2, 2,
+                                              xstr("pirepView_fuelUsed"),
+                                              1000000)
+
+
+        self._rating = PIREPViewer.getDataLabel(width = 3)
+        PIREPEditor.tableAttachWidget(table, 0, 3,
+                                      xstr("pirepView_rating"),
+                                      self._rating)
+        return frame
+
+    def _buildMiscellaneousFrame(self):
+        """Build the frame for the miscellaneous data."""
+        (frame, mainBox) = PIREPViewer.createFrame(xstr("pirepView_frame_miscellaneous"))
+
+        table = gtk.Table(6, 2)
+        mainBox.pack_start(table, False, False, 0)
+        table.set_row_spacings(4)
+        table.set_col_spacings(8)
+        table.set_homogeneous(False)
+
+        self._flownNumPassengers = \
+            PIREPEditor.tableAttachSpinButton(table, 0, 0,
+                                              xstr("pirepView_numPassengers"),
+                                              300)
+
+        self._flownNumCrew = \
+            PIREPEditor.tableAttachSpinButton(table, 2, 0,
+                                              xstr("pirepView_numCrew"),
+                                              10)
+
+        self._flownBagWeight = \
+            PIREPEditor.tableAttachSpinButton(table, 0, 1,
+                                              xstr("pirepView_bagWeight"),
+                                              100000, width = 6)
+
+        self._flownCargoWeight = \
+            PIREPEditor.tableAttachSpinButton(table, 2, 1,
+                                              xstr("pirepView_cargoWeight"),
+                                              100000, width = 6)
+
+        self._flownMailWeight = \
+            PIREPEditor.tableAttachSpinButton(table, 4, 1,
+                                              xstr("pirepView_mailWeight"),
+                                              100000, width = 6)
+
+        self._flightType = createFlightTypeComboBox()
+        PIREPEditor.tableAttachWidget(table, 0, 2,
+                                      xstr("pirepView_flightType"),
+                                      self._flightType)
+
+        self._online = gtk.CheckButton(xstr("pirepView_online"))
+        table.attach(self._online, 2, 3, 2, 3)
+
+        PIREPViewer.addVFiller(mainBox)
+
+        mainBox.pack_start(PIREPViewer.getLabel(xstr("pirepView_delayCodes")),
+                           False, False, 0)
+
+        (textWindow, self._delayCodes) = PIREPViewer.getTextWindow()
+        mainBox.pack_start(textWindow, False, False, 0)
+
+        return frame
+
+    def _buildCommentsTab(self):
+        """Build the tab with the comments and flight defects."""
+        return FlightInfo(self._gui, mainInstance = False)
+
+    def _buildLogTab(self):
+        """Build the log tab."""
+        mainBox = gtk.VBox()
+
+        (logWindow, self._log) = PIREPViewer.getTextWindow(heightRequest = -1)
+        addFaultTag(self._log.get_buffer())
+        mainBox.pack_start(logWindow, True, True, 0)
+
+        return mainBox
+
+    def _upperChanged(self, entry, arg = None):
+        """Called when the value of some entry widget has changed and the value
+        should be converted to uppercase."""
+        entry.set_text(entry.get_text().upper())
+        #self._valueChanged(entry, arg)
+
+    def _upperChangedComboBox(self, comboBox):
+        """Called for combo box widgets that must be converted to uppercase."""
+        entry = comboBox.get_child()
+        if comboBox.get_active()==-1:
+            entry.set_text(entry.get_text().upper())
+        #self._valueChanged(entry)
+
+#------------------------------------------------------------------------------
