Index: src/mlx/gui/common.py
===================================================================
--- src/mlx/gui/common.py	(revision 575)
+++ src/mlx/gui/common.py	(revision 604)
@@ -57,5 +57,7 @@
     DIALOG_MODAL = gtk.DIALOG_MODAL
     WRAP_WORD = gtk.WRAP_WORD
+
     JUSTIFY_CENTER = gtk.JUSTIFY_CENTER
+    JUSTIFY_LEFT = gtk.JUSTIFY_LEFT
 
     CONTROL_MASK = gdk.CONTROL_MASK
@@ -78,4 +80,6 @@
 
     POLICY_AUTOMATIC = gtk.POLICY_AUTOMATIC
+    POLICY_NEVER = gtk.POLICY_NEVER
+    POLICY_ALWAYS = gtk.POLICY_ALWAYS
 
     WEIGHT_NORMAL = pango.WEIGHT_NORMAL
@@ -131,4 +135,5 @@
     WRAP_WORD = gtk.WrapMode.WORD
     JUSTIFY_CENTER = gtk.Justification.CENTER
+    JUSTIFY_LEFT = gtk.Justification.LEFT
 
     CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
@@ -151,4 +156,6 @@
 
     POLICY_AUTOMATIC = gtk.PolicyType.AUTOMATIC
+    POLICY_NEVER = gtk.PolicyType.NEVER
+    POLICY_ALWAYS = gtk.PolicyType.ALWAYS
 
     WEIGHT_NORMAL = pango.Weight.NORMAL
Index: src/mlx/gui/faultexplain.py
===================================================================
--- src/mlx/gui/faultexplain.py	(revision 604)
+++ src/mlx/gui/faultexplain.py	(revision 604)
@@ -0,0 +1,257 @@
+# Module to provide a widget displaying faults that occured during the flight
+# and giving the user some space to explain it
+
+#-------------------------------------------------------------------------------
+
+from mlx.gui.common import *
+
+#-------------------------------------------------------------------------------
+
+## @package mlx.gui.faultexplan
+#
+# The widget and associated logic to display faults and allow the pilot to
+# explain them. Each fault is displayed as the text it is accompanied by in the
+# log and there is a text entry field where the user can enter the
+# corresponding explanation. \ref FaultFrame belongs to one fault, while
+# \ref FaultExplainWidget contains the collection of all frames, which is a
+# VBox in a scrolled window.
+
+#-------------------------------------------------------------------------------
+
+class FaultFrame(gtk.Frame):
+    """A frame containing the information about a single fault.
+
+    It consists of a text view with the text of the fault and an editable text
+    view for the explanation."""
+    def __init__(self, faultText):
+        """Construct the frame."""
+        gtk.Frame.__init__(self)
+
+        self._faultText = faultText
+
+        vbox = gtk.VBox()
+
+        self._fault = fault = gtk.TextView()
+        fault.set_editable(False)
+        fault.set_can_focus(False)
+        fault.set_wrap_mode(WRAP_WORD)
+
+        buffer = fault.get_buffer()
+        self._faultTag  = buffer.create_tag("fault", weight=WEIGHT_BOLD)
+
+        self.faultText = faultText
+
+        faultAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                       xscale = 1.0, yscale = 0.0)
+        faultAlignment.set_padding(padding_top = 0, padding_bottom = 0,
+                                   padding_left = 2, padding_right = 2)
+        faultAlignment.add(fault)
+        vbox.pack_start(faultAlignment, True, True, 4)
+
+        self._explanation = explanation = gtk.TextView()
+        explanation.set_wrap_mode(WRAP_WORD)
+        explanation.set_accepts_tab(False)
+        explanation.set_size_request(-1, 100)
+
+        buffer = explanation.get_buffer()
+        buffer.connect("changed", self._explanationChanged)
+
+        vbox.pack_start(explanation, True, True, 4)
+
+        self.add(vbox)
+        self.show_all()
+
+        if pygobject:
+            styleContext = self.get_style_context()
+            color = styleContext.get_background_color(gtk.StateFlags.NORMAL)
+            fault.override_background_color(0, color)
+        else:
+            style = self.rc_get_style()
+            fault.modify_base(0, style.bg[0])
+
+        self._hasExplanation = False
+
+    @property
+    def faultText(self):
+        """Get the text of the fault."""
+        return self._faultText
+
+    @faultText.setter
+    def faultText(self, faultText):
+        """Update the text of the fault."""
+        self._faultText = faultText
+
+        buffer = self._fault.get_buffer()
+        buffer.set_text(faultText)
+        buffer.apply_tag(self._faultTag,
+                         buffer.get_start_iter(), buffer.get_end_iter())
+
+    @property
+    def explanation(self):
+        """Get the text of the explanation."""
+        buffer = self._explanation.get_buffer()
+        return buffer.get_text(buffer.get_start_iter(),
+                               buffer.get_end_iter(), True)
+
+    @property
+    def hasExplanation(self):
+        """Determine if there is a valid explanation."""
+        return self._hasExplanation
+
+    @property
+    def html(self):
+        """Convert the contents of the widget into HTML."""
+        return self._faultText + "<br/></b>" + self.explanation + "<b>"
+
+    def setMnemonicFor(self, widget):
+        """Set the explanation text view as the mnemonic widget for the given
+        one."""
+        widget.set_mnemonic_widget(self._explanation)
+
+    def _explanationChanged(self, textBuffer):
+        """Called when the explanation's text has changed."""
+        hasExplanation = len(textBuffer.get_text(textBuffer.get_start_iter(),
+                                                 textBuffer.get_end_iter(),
+                                                 True))>3
+        if self._hasExplanation != hasExplanation:
+            self._hasExplanation = hasExplanation
+            self.emit("explanation-changed", hasExplanation)
+
+#-------------------------------------------------------------------------------
+
+gobject.signal_new("explanation-changed", FaultFrame, gobject.SIGNAL_RUN_FIRST,
+                   None, (bool,))
+
+#-------------------------------------------------------------------------------
+
+class FaultExplainWidget(gtk.Frame):
+    """The widget for the failts and their explanations."""
+    @staticmethod
+    def getFaultFrame(alignment):
+        """Get the fault frame from the given alignment."""
+        return alignment.get_children()[0]
+
+    def __init__(self):
+        gtk.Frame.__init__(self)
+        self.set_label(xstr("info_faults"))
+        label = self.get_label_widget()
+        label.set_use_underline(True)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 1.0, yscale = 1.0)
+        alignment.set_padding(padding_top = 4, padding_bottom = 4,
+                              padding_left = 8, padding_right = 8)
+
+        scroller = gtk.ScrolledWindow()
+        scroller.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+
+        self._faults = gtk.VBox()
+        self._faults.set_homogeneous(False)
+        scroller.add_with_viewport(self._faults)
+
+        self._faultWidgets = {}
+
+        alignment.add(scroller)
+        self.add(alignment)
+
+        self._numFaults = 0
+        self._numExplanations = 0
+
+    @property
+    def fullyExplained(self):
+        """Indicate if the faults have been fully explained."""
+        return self._numExplanations>=self._numFaults
+
+    @property
+    def html(self):
+        """Convert the contents of the widget into HTML."""
+        html = ""
+        for alignment in self._faults.get_children():
+            faultFrame = FaultExplainWidget.getFaultFrame(alignment)
+            if html:
+                html += "<br><br>"
+            html += faultFrame.html
+        return html
+
+    def addFault(self, id, faultText):
+        """Add a fault with the given ID and text."""
+
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                      xscale = 1.0, yscale = 0.0)
+        alignment.set_padding(padding_top = 2, padding_bottom = 2,
+                              padding_left = 4, padding_right = 4)
+
+        faultFrame = FaultFrame(faultText)
+        if self._numFaults==0:
+            faultFrame.setMnemonicFor(self.get_label_widget())
+        faultFrame.connect("explanation-changed", self._explanationChanged)
+
+        alignment.add(faultFrame)
+        self._faults.pack_start(alignment, False, False, 4)
+        self._faults.show_all()
+
+        self._faultWidgets[id] = (alignment, faultFrame)
+
+        self._updateStats(numFaults = self._numFaults + 1)
+
+    def updateFault(self, id, faultText):
+        """Update the text of the fault with the given ID."""
+        self._faultWidgets[id][1].faultText = faultText
+
+    def clearFault(self, id):
+        """Clear (remove) the fault with the given ID."""
+        (alignment, faultFrame) = self._faultWidgets[id]
+        hasExplanation = faultFrame.hasExplanation
+
+        children = self._faults.get_children()
+        if alignment is children[0] and len(children)>1:
+            faultFrame = FaultExplainWidget.getFaultFrame(children[1])
+            faultFrame.setMnemonicFor(self.get_label_widget())
+
+        self._faults.remove(alignment)
+        self._faults.show_all()
+
+        del self._faultWidgets[id]
+
+        self._updateStats(numFaults = self._numFaults - 1,
+                          numExplanations = self._numExplanations -
+                          (1 if hasExplanation else 0))
+
+    def reset(self):
+        """Reset the widget by removing all faults."""
+        for (alignment, faultFrame) in self._faultWidgets.itervalues():
+            self._faults.remove(alignment)
+        self._faults.show_all()
+
+        self._faultWidgets = {}
+
+    def _updateStats(self, numFaults = None, numExplanations = None):
+        """Update the statistics.
+
+        If the explanation status has changed, emit the corresponding
+        signal."""
+        before = self.fullyExplained
+
+        if numFaults is None:
+            numFaults = self._numFaults
+
+        if numExplanations is None:
+            numExplanations = self._numExplanations
+
+        after = numExplanations >= numFaults
+
+        self._numFaults = numFaults
+        self._numExplanations = numExplanations
+
+        if before!=after:
+            self.emit("explanations-changed", after)
+
+    def _explanationChanged(self, faultFrame, hasExplanation):
+        """Called when the status of an explanation has changed."""
+        self._updateStats(numExplanations = (self._numExplanations +
+                                             (1 if hasExplanation else -1)))
+
+#-------------------------------------------------------------------------------
+
+gobject.signal_new("explanations-changed", FaultExplainWidget,
+                   gobject.SIGNAL_RUN_FIRST, None, (bool,))
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 555)
+++ src/mlx/gui/gui.py	(revision 604)
@@ -396,5 +396,5 @@
     def flightDefects(self):
         """Get the flight defects."""
-        return self._flightInfo.flightDefects
+        return self._flightInfo.faultsAndExplanations
 
     @property
@@ -585,4 +585,18 @@
         """Remove the flight log line with the given index."""
         gobject.idle_add(self._removeFlightLogLine, index)
+
+    def addFault(self, id, timestampString, text):
+        """Add a fault to the list of faults."""
+        faultText = formatFlightLogLine(timestampString, text).strip()
+        self._flightInfo.addFault(id, faultText)
+
+    def updateFault(self, id, timestampString, text):
+        """Update a fault in the list of faults."""
+        faultText = formatFlightLogLine(timestampString, text).strip()
+        self._flightInfo.updateFault(id, faultText)
+
+    def clearFault(self, id):
+        """Clear a fault in the list of faults."""
+        self._flightInfo.clearFault(id)
 
     def _removeFlightLogLine(self, index):
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 555)
+++ src/mlx/gui/info.py	(revision 604)
@@ -3,4 +3,5 @@
 
 from mlx.gui.delaycodes import DelayCodeTable
+from mlx.gui.faultexplain import FaultExplainWidget
 
 from mlx.i18n import xstr
@@ -14,7 +15,7 @@
 #
 # This module implements to \ref FlightInfo class, which is the widget for the
-# extra information related to the flight. It contains text areas for the
-# comments and the flight defects at the top next to each other, and the frame
-# for the delay codes at the bottom in the centre.
+# extra information related to the flight. It contains a text area for the
+# comments, the fault list widget, and the frame for the delay codes at the
+# bottom in the centre.
 
 #------------------------------------------------------------------------------
@@ -61,4 +62,5 @@
                                                 xscale = 1.0, yscale = 1.0)
         commentsBox = gtk.HBox()
+        commentsBox.set_homogeneous(True)
 
         (frame, self._comments) = FlightInfo._createCommentArea(xstr("info_comments"))
@@ -66,7 +68,6 @@
         self._comments.get_buffer().connect("changed", self._commentsChanged)
 
-        (frame, self._flightDefects) = \
-             FlightInfo._createCommentArea(xstr("info_defects"))
-        commentsBox.pack_start(frame, True, True, 8)
+        self._faultExplainWidget = FaultExplainWidget()
+        commentsBox.pack_start(self._faultExplainWidget, True, True, 8)
 
         self._commentsAlignment.add(commentsBox)
@@ -113,9 +114,7 @@
 
     @property
-    def flightDefects(self):
-        """Get the flight defects."""
-        buffer = self._flightDefects.get_buffer()
-        return text2unicode(buffer.get_text(buffer.get_start_iter(),
-                                            buffer.get_end_iter(), True))
+    def faultsAndExplanations(self):
+        """Get the faults and explanations as HTML."""
+        return self._faultExplainWidget.html
 
     @property
@@ -129,8 +128,20 @@
         return self._delayCodeTable.hasDelayCode
 
+    def addFault(self, id, faultText):
+        """Add a fault to the list of faults."""
+        self._faultExplainWidget.addFault(id, faultText)
+
+    def updateFault(self, id, faultText):
+        """Update a fault to the list of faults."""
+        self._faultExplainWidget.updateFault(id, faultText)
+
+    def clearFault(self, id):
+        """Clear a fault to the list of faults."""
+        self._faultExplainWidget.clearFault(id)
+
     def enable(self, aircraftType):
         """Enable the flight info tab."""
         self._comments.set_sensitive(True)
-        self._flightDefects.set_sensitive(True)
+        self._faultExplainWidget.set_sensitive(True)
         self._delayCodeTable.setType(aircraftType)
         self._delayWindow.set_sensitive(True)
@@ -140,5 +151,5 @@
         """Enable the flight info tab."""
         self._comments.set_sensitive(False)
-        self._flightDefects.set_sensitive(False)
+        self._faultExplainWidget.set_sensitive(False)
         self._delayWindow.set_sensitive(False)
         self._delayCodeTable.setStyle()
@@ -147,5 +158,5 @@
         """Reset the flight info tab."""
         self._comments.get_buffer().set_text("")
-        self._flightDefects.get_buffer().set_text("")
+        self._faultExplainWidget.reset()
         self._delayCodeTable.reset()
 
Index: src/mlx/logger.py
===================================================================
--- src/mlx/logger.py	(revision 400)
+++ src/mlx/logger.py	(revision 604)
@@ -284,13 +284,24 @@
                                         faultScore = score)
             self._updateEntry(id, newEntry)
+            if latestEntry.isFault:
+                self._output.updateFault(id, newEntry.timestampString, text)
+            else:
+                self._output.addFault(id, newEntry.timestampString, text)
         elif updateID is not None:
             id = updateID
-            newEntry = self._entries[id].copy(timestamp = timestamp,
-                                              text = text, faultID = faultID,
-                                              faultScore = score)
+            oldEntry = self._entries[id]
+            newEntry = oldEntry.copy(timestamp = timestamp,
+                                     text = text, faultID = faultID,
+                                     faultScore = score)
             self._updateEntry(id, newEntry)
+            if oldEntry.isFault:
+                self._output.updateFault(id, newEntry.timestampString, text)
+            else:
+                self._output.addFault(id, newEntry.timestampString, text)
         else:
-            id = self._addEntry(Logger.Entry(timestamp, text, faultID = faultID,
-                                             faultScore = score))
+            entry = Logger.Entry(timestamp, text, faultID = faultID,
+                                 faultScore = score)
+            id = self._addEntry(entry)
+            self._output.addFault(id, entry.timestampString, text)
 
         if updateID is None:
@@ -328,4 +339,5 @@
         newEntry = self._entries[id].copy(text = text, clearFault = True)
         self._updateEntry(id, newEntry)
+        self._output.clearFault(id)
 
     def _addEntry(self, entry):
