Index: src/mlx/gui/common.py
===================================================================
--- src/mlx/gui/common.py	(revision 97)
+++ src/mlx/gui/common.py	(revision 97)
@@ -0,0 +1,149 @@
+# Common things for the GUI
+
+import os
+
+appIndicator = False
+
+if os.name=="nt" or "FORCE_PYGTK" in os.environ:
+    print "Using PyGTK"
+    pygobject = False
+    import pygtk
+    import gtk.gdk as gdk
+    import gtk
+    import gobject
+    import pango
+    try:
+        import appindicator
+        appIndicator = True
+    except Exception, e:
+        pass
+
+    MESSAGETYPE_ERROR = gtk.MESSAGE_ERROR
+    MESSAGETYPE_QUESTION = gtk.MESSAGE_QUESTION
+    MESSAGETYPE_INFO = gtk.MESSAGE_INFO
+    BUTTONSTYPE_OK = gtk.BUTTONS_OK
+    BUTTONSTYPE_YES_NO = gtk.BUTTONS_YES_NO
+    RESPONSETYPE_YES = gtk.RESPONSE_YES
+    ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
+    CONTROL_MASK = gdk.CONTROL_MASK
+
+    def text2unicode(text):
+        """Convert the given text, returned by a Gtk widget, to Unicode."""
+        return unicode(text)
+else:
+    print "Using PyGObject"
+    pygobject = True
+    from gi.repository import Gdk as gdk
+    from gi.repository import Gtk as gtk
+    from gi.repository import GObject as gobject
+    from gi.repository import AppIndicator3 as appindicator
+    from gi.repository import Pango as pango
+    appIndicator = True
+    
+    MESSAGETYPE_ERROR = gtk.MessageType.ERROR
+    MESSAGETYPE_QUESTION = gtk.MessageType.QUESTION
+    MESSAGETYPE_INFO = gtk.MessageType.INFO
+    BUTTONSTYPE_OK = gtk.ButtonsType.OK
+    BUTTONSTYPE_YES_NO = gtk.ButtonsType.YES_NO
+    RESPONSETYPE_YES = gtk.ResponseType.YES
+    ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
+    CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
+
+    import codecs
+    _utf8Decoder = codecs.getdecoder("utf-8")
+    
+    def text2unicode(str):
+        """Convert the given text, returned by a Gtk widget, to Unicode."""
+        return _utf8Decoder(str)[0]
+
+import cairo
+
+#------------------------------------------------------------------------------
+
+class FlightStatusHandler(object):
+    """Base class for objects that handle the flight status in some way."""
+    def __init__(self):
+        self._stage = None
+        self._rating = 100
+        self._noGoReason = None
+
+    def resetFlightStatus(self):
+        """Reset the flight status."""
+        self._stage = None
+        self._rating = 100
+        self._noGoReason = None
+        self._updateFlightStatus()
+        
+    def setStage(self, stage):
+        """Set the stage of the flight."""
+        if stage!=self._stage:
+            self._stage = stage
+            self._updateFlightStatus()
+
+    def setRating(self, rating):
+        """Set the rating to the given value."""
+        if rating!=self._rating:
+            self._rating = rating
+            if self._noGoReason is None:
+                self._updateFlightStatus()
+
+    def setNoGo(self, reason):
+        """Set a No-Go condition with the given reason."""
+        if self._noGoReason is None:
+            self._noGoReason = reason
+            self._updateFlightStatus()
+
+#------------------------------------------------------------------------------
+
+class IntegerEntry(gtk.Entry):
+    """An entry that allows only either an empty value, or an integer."""
+    def __init__(self, defaultValue = None):
+        """Construct the entry."""
+        gtk.Entry.__init__(self)
+
+        self.set_alignment(1.0)
+
+        self._defaultValue = defaultValue
+        self._currentInteger = defaultValue
+        self._selfSetting = False
+        self._set_text()
+
+        self.connect("changed", self._handle_changed)
+
+    def get_int(self):
+        """Get the integer."""
+        return self._currentInteger
+
+    def set_int(self, value):
+        """Set the integer."""
+        if value!=self._currentInteger:
+            self._currentInteger = value
+            self.emit("integer-changed", self._currentInteger)
+        self._set_text()
+    
+    def _handle_changed(self, widget):
+        """Handle the changed signal."""
+        if self._selfSetting:
+            return
+        text = self.get_text()
+        if text=="":
+            self.set_int(self._defaultValue)
+        else:
+            try:
+                self.set_int(int(text))
+            except:
+                self._set_text()
+
+    def _set_text(self):
+        """Set the text value from the current integer."""
+        self._selfSetting = True
+        self.set_text("" if self._currentInteger is None
+                      else str(self._currentInteger))
+        self._selfSetting = False
+                
+#------------------------------------------------------------------------------
+
+gobject.signal_new("integer-changed", IntegerEntry, gobject.SIGNAL_RUN_FIRST,
+                   None, (object,))
+
+#------------------------------------------------------------------------------
Index: src/mlx/gui/common.py
===================================================================
--- src/mlx/gui/common.py	(revision 97)
+++ 	(revision )
@@ -1,149 +1,0 @@
-# Common things for the GUI
-
-import os
-
-appIndicator = False
-
-if os.name=="nt" or "FORCE_PYGTK" in os.environ:
-    print "Using PyGTK"
-    pygobject = False
-    import pygtk
-    import gtk.gdk as gdk
-    import gtk
-    import gobject
-    import pango
-    try:
-        import appindicator
-        appIndicator = True
-    except Exception, e:
-        pass
-
-    MESSAGETYPE_ERROR = gtk.MESSAGE_ERROR
-    MESSAGETYPE_QUESTION = gtk.MESSAGE_QUESTION
-    MESSAGETYPE_INFO = gtk.MESSAGE_INFO
-    BUTTONSTYPE_OK = gtk.BUTTONS_OK
-    BUTTONSTYPE_YES_NO = gtk.BUTTONS_YES_NO
-    RESPONSETYPE_YES = gtk.RESPONSE_YES
-    ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
-    CONTROL_MASK = gdk.CONTROL_MASK
-
-    def text2unicode(text):
-        """Convert the given text, returned by a Gtk widget, to Unicode."""
-        return unicode(text)
-else:
-    print "Using PyGObject"
-    pygobject = True
-    from gi.repository import Gdk as gdk
-    from gi.repository import Gtk as gtk
-    from gi.repository import GObject as gobject
-    from gi.repository import AppIndicator3 as appindicator
-    from gi.repository import Pango as pango
-    appIndicator = True
-    
-    MESSAGETYPE_ERROR = gtk.MessageType.ERROR
-    MESSAGETYPE_QUESTION = gtk.MessageType.QUESTION
-    MESSAGETYPE_INFO = gtk.MessageType.INFO
-    BUTTONSTYPE_OK = gtk.ButtonsType.OK
-    BUTTONSTYPE_YES_NO = gtk.ButtonsType.YES_NO
-    RESPONSETYPE_YES = gtk.ResponseType.YES
-    ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
-    CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
-
-    import codecs
-    _utf8Decoder = codecs.getdecoder("utf-8")
-    
-    def text2unicode(str):
-        """Convert the given text, returned by a Gtk widget, to Unicode."""
-        return _utf8Decoder(str)[0]
-
-import cairo
-
-#------------------------------------------------------------------------------
-
-class FlightStatusHandler(object):
-    """Base class for objects that handle the flight status in some way."""
-    def __init__(self):
-        self._stage = None
-        self._rating = 100
-        self._noGoReason = None
-
-    def resetFlightStatus(self):
-        """Reset the flight status."""
-        self._stage = None
-        self._rating = 100
-        self._noGoReason = None
-        self._updateFlightStatus()
-        
-    def setStage(self, stage):
-        """Set the stage of the flight."""
-        if stage!=self._stage:
-            self._stage = stage
-            self._updateFlightStatus()
-
-    def setRating(self, rating):
-        """Set the rating to the given value."""
-        if rating!=self._rating:
-            self._rating = rating
-            if self._noGoReason is None:
-                self._updateFlightStatus()
-
-    def setNoGo(self, reason):
-        """Set a No-Go condition with the given reason."""
-        if self._noGoReason is None:
-            self._noGoReason = reason
-            self._updateFlightStatus()
-
-#------------------------------------------------------------------------------
-
-class IntegerEntry(gtk.Entry):
-    """An entry that allows only either an empty value, or an integer."""
-    def __init__(self, defaultValue = None):
-        """Construct the entry."""
-        gtk.Entry.__init__(self)
-
-        self.set_alignment(1.0)
-
-        self._defaultValue = defaultValue
-        self._currentInteger = defaultValue
-        self._selfSetting = False
-        self._set_text()
-
-        self.connect("changed", self._handle_changed)
-
-    def get_int(self):
-        """Get the integer."""
-        return self._currentInteger
-
-    def set_int(self, value):
-        """Set the integer."""
-        if value!=self._currentInteger:
-            self._currentInteger = value
-            self.emit("integer-changed", self._currentInteger)
-        self._set_text()
-    
-    def _handle_changed(self, widget):
-        """Handle the changed signal."""
-        if self._selfSetting:
-            return
-        text = self.get_text()
-        if text=="":
-            self.set_int(self._defaultValue)
-        else:
-            try:
-                self.set_int(int(text))
-            except:
-                self._set_text()
-
-    def _set_text(self):
-        """Set the text value from the current integer."""
-        self._selfSetting = True
-        self.set_text("" if self._currentInteger is None
-                      else str(self._currentInteger))
-        self._selfSetting = False
-                
-#------------------------------------------------------------------------------
-
-gobject.signal_new("integer-changed", IntegerEntry, gobject.SIGNAL_RUN_FIRST,
-                   None, (object,))
-
-#------------------------------------------------------------------------------
Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 101)
+++ src/mlx/gui/flight.py	(revision 101)
@@ -0,0 +1,2209 @@
+# The flight handling "wizard"
+
+from mlx.gui.common import *
+
+import mlx.const as const
+import mlx.fs as fs
+from mlx.checks import PayloadChecker
+import mlx.util as util
+from mlx.pirep import PIREP
+
+import datetime
+import time
+
+#------------------------------------------------------------------------------
+
+acftTypeNames = { const.AIRCRAFT_B736: "Boeing 737-600",
+                  const.AIRCRAFT_B737: "Boeing 737-700",
+                  const.AIRCRAFT_B738: "Boeing 737-800",
+                  const.AIRCRAFT_DH8D: "Bombardier Dash 8-Q400",
+                  const.AIRCRAFT_B733: "Boeing 737-300",
+                  const.AIRCRAFT_B734: "Boeing 737-400",
+                  const.AIRCRAFT_B735: "Boeing 737-500",
+                  const.AIRCRAFT_B762: "Boeing 767-200",
+                  const.AIRCRAFT_B763: "Boeing 767-300",
+                  const.AIRCRAFT_CRJ2: "Bombardier CRJ200",
+                  const.AIRCRAFT_F70:  "Fokker 70",
+                  const.AIRCRAFT_DC3:  "Lisunov Li-2",
+                  const.AIRCRAFT_T134: "Tupolev Tu-134",
+                  const.AIRCRAFT_T154: "Tupolev Tu-154",
+                  const.AIRCRAFT_YK40: "Yakovlev Yak-40" }
+
+#-----------------------------------------------------------------------------
+
+class Page(gtk.Alignment):
+    """A page in the flight wizard."""
+    def __init__(self, wizard, title, help, completedHelp = None):
+        """Construct the page."""
+        super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
+                                   xscale = 1.0, yscale = 1.0)
+        self.set_padding(padding_top = 4, padding_bottom = 4,
+                         padding_left = 12, padding_right = 12)
+
+        frame = gtk.Frame()
+        self.add(frame)
+
+        style = self.get_style() if pygobject else self.rc_get_style()
+
+        self._vbox = gtk.VBox()
+        self._vbox.set_homogeneous(False)
+        frame.add(self._vbox)
+
+        eventBox = gtk.EventBox()
+        eventBox.modify_bg(0, style.bg[3])
+
+        alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
+        
+        label = gtk.Label(title)
+        label.modify_fg(0, style.fg[3])
+        label.modify_font(pango.FontDescription("bold 24"))
+        alignment.set_padding(padding_top = 4, padding_bottom = 4,
+                              padding_left = 6, padding_right = 0)
+                              
+        alignment.add(label)
+        eventBox.add(alignment)
+        
+        self._vbox.pack_start(eventBox, False, False, 0)
+
+        mainBox = gtk.VBox()        
+
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                  xscale = 1.0, yscale = 1.0)        
+        alignment.set_padding(padding_top = 16, padding_bottom = 16,
+                              padding_left = 16, padding_right = 16)
+        alignment.add(mainBox)
+        self._vbox.pack_start(alignment, True, True, 0)
+        
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
+                                  xscale = 0.0, yscale = 0.0)
+        alignment.set_padding(padding_top = 0, padding_bottom = 16,
+                              padding_left = 0, padding_right = 0)
+
+        self._help = help
+        self._completedHelp = completedHelp
+
+        if self._completedHelp is None or \
+           len(help.splitlines())>=len(completedHelp.splitlines()):
+            longerHelp = help
+        else:
+            longerHelp = completedHelp
+        
+        self._helpLabel = gtk.Label(completedHelp)
+        # FIXME: should be a constant in common
+        self._helpLabel.set_justify(gtk.Justification.CENTER if pygobject
+                                    else gtk.JUSTIFY_CENTER)
+        self._helpLabel.set_use_markup(True)
+        alignment.add(self._helpLabel)
+        mainBox.pack_start(alignment, False, False, 0)
+
+        self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                            xscale = 1.0, yscale = 1.0)
+        mainBox.pack_start(self._mainAlignment, True, True, 0)
+                                            
+        buttonAlignment =  gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
+        buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
+                                    padding_left = 16, padding_right = 16)
+
+        self._buttonBox = gtk.HBox()
+        self._buttonBox.set_homogeneous(False)
+        self._defaultButton = None
+        buttonAlignment.add(self._buttonBox)
+
+        self._vbox.pack_start(buttonAlignment, False, False, 0)
+
+        self._wizard = wizard
+
+        self._completed = False
+        self._fromPage = None
+
+    def setMainWidget(self, widget):
+        """Set the given widget as the main one."""
+        self._mainAlignment.add(widget)
+
+    def addButton(self, label, default = False):
+        """Add a button with the given label.
+
+        Return the button object created."""
+        button = gtk.Button(label)
+        self._buttonBox.pack_start(button, False, False, 4)
+        button.set_use_underline(True)
+        if default:
+            button.set_can_default(True)
+            self._defaultButton = button
+        return button
+
+    def initialize(self):
+        """Initialize the page.
+
+        It sets up the primary help, and calls the activate() function."""
+        self._helpLabel.set_markup(self._help)
+        self._helpLabel.set_sensitive(True)
+        self.activate()
+
+    def activate(self):
+        """Called when this page becomes active.
+
+        This default implementation does nothing."""
+        pass
+
+    def complete(self):
+        """Called when the page is completed.
+
+        It greys out/changes the help text and then calls finalize()."""
+        self.finalize()
+        if self._completedHelp is None:
+            self._helpLabel.set_sensitive(False)
+        else:
+            self._helpLabel.set_markup(self._completedHelp)
+        self._completed = True
+
+    def finalize(self):
+        """Called when the page is finalized."""
+        pass
+
+    def grabDefault(self):
+        """If the page has a default button, make it the default one."""
+        if self._defaultButton is not None:
+            self._defaultButton.grab_default()
+
+    def reset(self):
+        """Reset the page if the wizard is reset."""
+        self._completed = False
+        self._fromPage = None
+
+    def goBack(self):
+        """Go to the page we were invoked from."""
+        assert self._fromPage is not None
+        
+        self._wizard.setCurrentPage(self._fromPage, finalize = False)
+    
+#-----------------------------------------------------------------------------
+
+class LoginPage(Page):
+    """The login page."""
+    def __init__(self, wizard):
+        """Construct the login page."""
+        help = "Enter your MAVA pilot's ID and password to\n" \
+        "log in to the MAVA website and download\n" \
+        "your booked flights."
+        super(LoginPage, self).__init__(wizard, "Login", help)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+        
+        table = gtk.Table(2, 3)
+        table.set_row_spacings(4)
+        table.set_col_spacings(32)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Pilot _ID:")
+        label.set_use_underline(True)
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 0, 1)
+
+        self._pilotID = gtk.Entry()
+        self._pilotID.connect("changed", self._setLoginButton)
+        self._pilotID.set_tooltip_text("Enter your MAVA pilot's ID. This "
+                                       "usually starts with a "
+                                       "'P' followed by 3 digits.")
+        table.attach(self._pilotID, 1, 2, 0, 1)
+        label.set_mnemonic_widget(self._pilotID)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("_Password:")
+        label.set_use_underline(True)
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 1, 2)
+
+        self._password = gtk.Entry()
+        self._password.set_visibility(False)
+        self._password.connect("changed", self._setLoginButton)
+        self._password.set_tooltip_text("Enter the password for your pilot's ID")
+        table.attach(self._password, 1, 2, 1, 2)
+        label.set_mnemonic_widget(self._password)
+
+        self._rememberButton = gtk.CheckButton("_Remember password")
+        self._rememberButton.set_use_underline(True)
+        self._rememberButton.set_tooltip_text("If checked, your password will "
+                                              "be stored, so that you should "
+                                              "not have to enter it every time. "
+                                              "Note, however, that the password "
+                                              "is stored as text, and anybody "
+                                              "who can access your files will "
+                                              "be able to read it.")
+        table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
+
+        self._loginButton = self.addButton("_Login", default = True)
+        self._loginButton.set_sensitive(False)
+        self._loginButton.connect("clicked", self._loginClicked)
+        self._loginButton.set_tooltip_text("Click to log in.")        
+
+    def activate(self):
+        """Activate the page."""
+        config = self._wizard.gui.config
+        self._pilotID.set_text(config.pilotID)
+        self._password.set_text(config.password)
+        self._rememberButton.set_active(config.rememberPassword)
+
+    def _setLoginButton(self, entry):
+        """Set the login button's sensitivity.
+
+        The button is sensitive only if both the pilot ID and the password
+        fields contain values."""
+        self._loginButton.set_sensitive(self._pilotID.get_text()!="" and
+                                        self._password.get_text()!="")
+
+    def _loginClicked(self, button):
+        """Called when the login button was clicked."""
+        self._loginButton.set_sensitive(False)
+        gui = self._wizard.gui
+        gui.beginBusy("Logging in...")
+        gui.webHandler.login(self._loginResultCallback,
+                            self._pilotID.get_text(),
+                            self._password.get_text())
+
+    def _loginResultCallback(self, returned, result):
+        """The login result callback, called in the web handler's thread."""
+        gobject.idle_add(self._handleLoginResult, returned, result)
+
+    def _handleLoginResult(self, returned, result):
+        """Handle the login result."""
+        self._wizard.gui.endBusy()
+        self._loginButton.set_sensitive(True)
+        if returned:
+            if result.loggedIn:
+                config = self._wizard.gui.config
+
+                config.pilotID = self._pilotID.get_text()
+
+                rememberPassword = self._rememberButton.get_active()                
+                config.password = self._password.get_text() if rememberPassword  \
+                                  else ""
+
+                config.rememberPassword = rememberPassword
+                
+                config.save()
+                self._wizard._loginResult = result
+                self._wizard.nextPage()
+            else:
+                dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                           buttons = BUTTONSTYPE_OK,
+                                           message_format =
+                                           "Invalid pilot's ID or password.")
+                dialog.format_secondary_markup("Check the ID and try to reenter"
+                                               " the password.")
+                dialog.run()
+                dialog.hide()
+        else:
+            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                       buttons = BUTTONSTYPE_OK,
+                                       message_format = 
+                                       "Failed to connect to the MAVA website.")
+            dialog.format_secondary_markup("Try again in a few minutes.")
+            dialog.run()
+            dialog.hide()
+
+#-----------------------------------------------------------------------------
+
+class FlightSelectionPage(Page):
+    """The page to select the flight."""
+    def __init__(self, wizard):
+        """Construct the flight selection page."""
+        help = "Select the flight you want to perform."
+        completedHelp = "You have selected the flight highlighted below."
+        super(FlightSelectionPage, self).__init__(wizard, "Flight selection",
+                                                  help, completedHelp = completedHelp)
+
+
+        self._listStore = gtk.ListStore(str, str, str, str)
+        self._flightList = gtk.TreeView(self._listStore)
+        column = gtk.TreeViewColumn("Flight no.", gtk.CellRendererText(),
+                                    text = 1)
+        column.set_expand(True)
+        self._flightList.append_column(column)
+        column = gtk.TreeViewColumn("Departure time [UTC]", gtk.CellRendererText(),
+                                    text = 0)
+        column.set_expand(True)
+        self._flightList.append_column(column)
+        column = gtk.TreeViewColumn("From", gtk.CellRendererText(),
+                                    text = 2)
+        column.set_expand(True)
+        self._flightList.append_column(column)
+        column = gtk.TreeViewColumn("To", gtk.CellRendererText(),
+                                    text = 3)
+        column.set_expand(True)
+        self._flightList.append_column(column)
+
+        flightSelection = self._flightList.get_selection()
+        flightSelection.connect("changed", self._selectionChanged)
+
+        scrolledWindow = gtk.ScrolledWindow()
+        scrolledWindow.add(self._flightList)
+        scrolledWindow.set_size_request(400, -1)
+        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC,
+                                  gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC)
+        scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
+                                       else gtk.SHADOW_IN)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
+        alignment.add(scrolledWindow)
+
+        self.setMainWidget(alignment)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.set_sensitive(False)
+        self._button.connect("clicked", self._forwardClicked)
+
+    def activate(self):
+        """Fill the flight list."""
+        self._flightList.set_sensitive(True)
+        self._listStore.clear()
+        for flight in self._wizard.loginResult.flights:
+            self._listStore.append([str(flight.departureTime),
+                                    flight.callsign,
+                                    flight.departureICAO,
+                                    flight.arrivalICAO])
+
+    def finalize(self):
+        """Finalize the page."""
+        self._flightList.set_sensitive(False)
+
+    def _selectionChanged(self, selection):
+        """Called when the selection is changed."""
+        self._button.set_sensitive(selection.count_selected_rows()==1)
+
+    def _forwardClicked(self, button):
+        """Called when the forward button was clicked."""
+        if self._completed:
+            self._wizard.jumpPage(self._nextDistance, finalize = False)
+        else:
+            selection = self._flightList.get_selection()
+            (listStore, iter) = selection.get_selected()
+            path = listStore.get_path(iter)
+            [index] = path.get_indices() if pygobject else path
+
+            flight = self._wizard.loginResult.flights[index]
+            self._wizard._bookedFlight = flight
+            # FIXME: with PyGObject this call causes error messages to
+            # appear on the standard output
+            self._wizard.gui.enableFlightInfo()
+
+            self._updateDepartureGate()
+        
+    def _updateDepartureGate(self):
+        """Update the departure gate for the booked flight."""
+        flight = self._wizard._bookedFlight
+        if flight.departureICAO=="LHBP":
+            self._wizard._getFleet(self._fleetRetrieved)
+        else:
+            self._nextDistance = 2
+            self._wizard.jumpPage(2)
+
+    def _fleetRetrieved(self, fleet):
+        """Called when the fleet has been retrieved."""
+        if fleet is None:
+            self._nextDistance = 2
+            self._wizard.jumpPage(2)
+        else:
+            plane = fleet[self._wizard._bookedFlight.tailNumber]
+            if plane is None:
+                self._nextDistance = 2
+                self._wizard.jumpPage(2)
+            elif plane.gateNumber is not None and \
+                 not fleet.isGateConflicting(plane):
+                self._wizard._departureGate = plane.gateNumber
+                self._nextDistance = 2
+                self._wizard.jumpPage(2)
+            else:
+                self._nextDistance = 1
+                self._wizard.nextPage()
+        
+#-----------------------------------------------------------------------------
+
+class GateSelectionPage(Page):
+    """Page to select a free gate at LHBP.
+
+    This page should be displayed only if we have fleet information!."""
+    def __init__(self, wizard):
+        """Construct the gate selection page."""
+        help = "The airplane's gate position is invalid.\n\n" \
+               "Select the gate from which you\n" \
+               "would like to begin the flight."
+        super(GateSelectionPage, self).__init__(wizard,
+                                                "LHBP gate selection",
+                                                help)
+
+        self._listStore = gtk.ListStore(str)
+        self._gateList = gtk.TreeView(self._listStore)
+        column = gtk.TreeViewColumn(None, gtk.CellRendererText(),
+                                    text = 0)
+        column.set_expand(True)
+        self._gateList.append_column(column)
+        self._gateList.set_headers_visible(False)
+
+        gateSelection = self._gateList.get_selection()
+        gateSelection.connect("changed", self._selectionChanged)
+
+        scrolledWindow = gtk.ScrolledWindow()
+        scrolledWindow.add(self._gateList)
+        scrolledWindow.set_size_request(50, -1)
+        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC,
+                                  gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC)
+        scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
+                                       else gtk.SHADOW_IN)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
+        alignment.add(scrolledWindow)
+
+        self.setMainWidget(alignment)        
+
+        button = self.addButton(gtk.STOCK_GO_BACK)
+        button.set_use_stock(True)
+        button.connect("clicked", self._backClicked)
+        
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.set_sensitive(False)
+        self._button.connect("clicked", self._forwardClicked)
+
+    def activate(self):
+        """Fill the gate list."""
+        self._listStore.clear()
+        self._gateList.set_sensitive(True)
+        occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
+        for gateNumber in const.lhbpGateNumbers:
+            if gateNumber not in occupiedGateNumbers:
+                self._listStore.append([gateNumber])
+
+    def finalize(self):
+        """Finalize the page."""
+        self._gateList.set_sensitive(False)
+
+    def _selectionChanged(self, selection):
+        """Called when the selection is changed."""
+        self._button.set_sensitive(selection.count_selected_rows()==1)
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+
+    def _forwardClicked(self, button):
+        """Called when the forward button is clicked."""
+        if not self._completed:
+            selection = self._gateList.get_selection()
+            (listStore, iter) = selection.get_selected()
+            (gateNumber,) = listStore.get(iter, 0)
+
+            self._wizard._departureGate = gateNumber
+
+            #self._wizard._updatePlane(self._planeUpdated,
+            #                          self._wizard._bookedFlight.tailNumber,
+            #                          const.PLANE_HOME,
+            #                          gateNumber)
+        
+        self._wizard.nextPage()
+
+    def _planeUpdated(self, success):
+        """Callback for the plane updating call."""
+        if success is None or success:
+            self._wizard.nextPage()
+        else:
+            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                       buttons = BUTTONSTYPE_OK,
+                                       message_format = "Gate conflict detected again")
+            dialog.format_secondary_markup("Try to select a different gate.")
+            dialog.run()
+            dialog.hide()
+
+            self._wizard._getFleet(self._fleetRetrieved)
+
+    def _fleetRetrieved(self, fleet):
+        """Called when the fleet has been retrieved."""
+        if fleet is None:
+            self._wizard.nextPage()
+        else:
+            self.activate()
+            
+#-----------------------------------------------------------------------------
+
+class ConnectPage(Page):
+    """Page which displays the departure airport and gate (if at LHBP)."""
+    def __init__(self, wizard):
+        """Construct the connect page."""
+        help = "Load the aircraft below into the simulator and park it\n" \
+               "at the given airport, at the gate below, if present.\n\n" \
+               "Then press the Connect button to connect to the simulator."
+        completedHelp = "The basic data of your flight can be read below."
+        super(ConnectPage, self).__init__(wizard,
+                                          "Connect to the simulator",
+                                          help, completedHelp = completedHelp)
+        
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        table = gtk.Table(5, 2)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(True)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Flight number:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 0, 1)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._flightNumber = gtk.Label()
+        self._flightNumber.set_width_chars(7)
+        self._flightNumber.set_alignment(0.0, 0.5)
+        labelAlignment.add(self._flightNumber)
+        table.attach(labelAlignment, 1, 2, 0, 1)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Aircraft:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 1, 2)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._aircraft = gtk.Label()
+        self._aircraft.set_width_chars(25)
+        self._aircraft.set_alignment(0.0, 0.5)
+        labelAlignment.add(self._aircraft)
+        table.attach(labelAlignment, 1, 2, 1, 2)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Tail number:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 2, 3)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._tailNumber = gtk.Label()
+        self._tailNumber.set_width_chars(10)
+        self._tailNumber.set_alignment(0.0, 0.5)
+        labelAlignment.add(self._tailNumber)
+        table.attach(labelAlignment, 1, 2, 2, 3)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Airport:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 3, 4)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._departureICAO = gtk.Label()
+        self._departureICAO.set_width_chars(6)
+        self._departureICAO.set_alignment(0.0, 0.5)
+        labelAlignment.add(self._departureICAO)
+        table.attach(labelAlignment, 1, 2, 3, 4)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Gate:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 4, 5)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._departureGate = gtk.Label()
+        self._departureGate.set_width_chars(5)
+        self._departureGate.set_alignment(0.0, 0.5)
+        labelAlignment.add(self._departureGate)
+        table.attach(labelAlignment, 1, 2, 4, 5)
+
+        button = self.addButton(gtk.STOCK_GO_BACK)
+        button.set_use_stock(True)
+        button.connect("clicked", self._backClicked)
+
+        self._button = self.addButton("_Connect", default = True)
+        self._button.set_use_underline(True)
+        self._clickedID = self._button.connect("clicked", self._connectClicked)
+
+    def activate(self):
+        """Setup the departure information."""
+        self._button.set_label("_Connect")
+        self._button.set_use_underline(True)
+        self._button.disconnect(self._clickedID)
+        self._clickedID = self._button.connect("clicked", self._connectClicked)
+
+        bookedFlight = self._wizard._bookedFlight
+
+        self._flightNumber.set_markup("<b>" + bookedFlight.callsign + "</b>")
+
+        aircraftType = acftTypeNames[bookedFlight.aircraftType]
+        self._aircraft.set_markup("<b>" + aircraftType + "</b>")
+        
+        self._tailNumber.set_markup("<b>" + bookedFlight.tailNumber + "</b>")
+
+        icao = bookedFlight.departureICAO
+        self._departureICAO.set_markup("<b>" + icao + "</b>")
+        gate = self._wizard._departureGate
+        if gate!="-":
+            gate = "<b>" + gate + "</b>"
+        self._departureGate.set_markup(gate)
+
+    def finalize(self):
+        """Finalize the page."""
+        self._button.set_label(gtk.STOCK_GO_FORWARD)
+        self._button.set_use_stock(True)
+        self._button.disconnect(self._clickedID)
+        self._clickedID = self._button.connect("clicked", self._forwardClicked)
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+
+    def _connectClicked(self, button):
+        """Called when the Connect button is pressed."""
+        self._wizard._connectSimulator()
+
+    def _forwardClicked(self, button):
+        """Called when the Forward button is pressed."""
+        self._wizard.nextPage()
+
+#-----------------------------------------------------------------------------
+
+class PayloadPage(Page):
+    """Page to allow setting up the payload."""
+    def __init__(self, wizard):
+        """Construct the page."""
+        help = "The briefing contains the weights below.\n" \
+               "Setup the cargo weight here and the payload weight in the simulator.\n\n" \
+               "You can also check here what the simulator reports as ZFW."
+        completedHelp = "You can see the weights in the briefing\n" \
+                        "and the cargo weight you have selected below.\n\n" \
+                        "You can also query the ZFW reported by the simulator."
+        super(PayloadPage, self).__init__(wizard, "Payload", help,
+                                          completedHelp = completedHelp)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        table = gtk.Table(7, 3)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(False)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        label = gtk.Label("Crew:")
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 0, 1)
+
+        self._numCrew = gtk.Label()
+        self._numCrew.set_width_chars(6)
+        self._numCrew.set_alignment(1.0, 0.5)
+        table.attach(self._numCrew, 1, 2, 0, 1)
+        
+        label = gtk.Label("Passengers:")
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 1, 2)
+
+        self._numPassengers = gtk.Label()
+        self._numPassengers.set_width_chars(6)
+        self._numPassengers.set_alignment(1.0, 0.5)
+        table.attach(self._numPassengers, 1, 2, 1, 2)
+        
+        label = gtk.Label("Baggage:")
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 2, 3)
+
+        self._bagWeight = gtk.Label()
+        self._bagWeight.set_width_chars(6)
+        self._bagWeight.set_alignment(1.0, 0.5)
+        table.attach(self._bagWeight, 1, 2, 2, 3)
+
+        table.attach(gtk.Label("kg"), 2, 3, 2, 3)
+        
+        label = gtk.Label("_Cargo:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 3, 4)
+
+        self._cargoWeight = IntegerEntry(defaultValue = 0)
+        self._cargoWeight.set_width_chars(6)
+        self._cargoWeight.connect("integer-changed", self._cargoWeightChanged)
+        self._cargoWeight.set_tooltip_text("The weight of the cargo for your flight.")
+        table.attach(self._cargoWeight, 1, 2, 3, 4)
+        label.set_mnemonic_widget(self._cargoWeight)
+
+        table.attach(gtk.Label("kg"), 2, 3, 3, 4)
+        
+        label = gtk.Label("Mail:")
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 4, 5)
+
+        self._mailWeight = gtk.Label()
+        self._mailWeight.set_width_chars(6)
+        self._mailWeight.set_alignment(1.0, 0.5)
+        table.attach(self._mailWeight, 1, 2, 4, 5)
+
+        table.attach(gtk.Label("kg"), 2, 3, 4, 5)
+        
+        label = gtk.Label("<b>Calculated ZFW:</b>")
+        label.set_alignment(0.0, 0.5)
+        label.set_use_markup(True)
+        table.attach(label, 0, 1, 5, 6)
+
+        self._calculatedZFW = gtk.Label()
+        self._calculatedZFW.set_width_chars(6)
+        self._calculatedZFW.set_alignment(1.0, 0.5)
+        table.attach(self._calculatedZFW, 1, 2, 5, 6)
+
+        table.attach(gtk.Label("kg"), 2, 3, 5, 6)
+
+        self._zfwButton = gtk.Button("_ZFW from FS:")
+        self._zfwButton.set_use_underline(True)
+        self._zfwButton.connect("clicked", self._zfwRequested)
+        table.attach(self._zfwButton, 0, 1, 6, 7)
+
+        self._simulatorZFW = gtk.Label("-")
+        self._simulatorZFW.set_width_chars(6)
+        self._simulatorZFW.set_alignment(1.0, 0.5)
+        table.attach(self._simulatorZFW, 1, 2, 6, 7)
+        self._simulatorZFWValue = None
+
+        table.attach(gtk.Label("kg"), 2, 3, 6, 7)
+
+        self._backButton = self.addButton(gtk.STOCK_GO_BACK)
+        self._backButton.set_use_stock(True)
+        self._backButton.connect("clicked", self._backClicked)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.connect("clicked", self._forwardClicked)
+
+    @property
+    def cargoWeight(self):
+        """Get the cargo weight entered."""
+        return self._cargoWeight.get_int()
+
+    def activate(self):
+        """Setup the information."""
+        bookedFlight = self._wizard._bookedFlight
+        self._numCrew.set_text(str(bookedFlight.numCrew))
+        self._numPassengers.set_text(str(bookedFlight.numPassengers))
+        self._bagWeight.set_text(str(bookedFlight.bagWeight))
+        self._cargoWeight.set_int(bookedFlight.cargoWeight)
+        self._cargoWeight.set_sensitive(True)
+        self._mailWeight.set_text(str(bookedFlight.mailWeight))
+        self._simulatorZFW.set_text("-")
+        self._simulatorZFWValue = None
+        self._zfwButton.set_sensitive(True)
+        self._updateCalculatedZFW()
+
+    def finalize(self):
+        """Finalize the payload page."""
+        self._cargoWeight.set_sensitive(False)
+
+    def calculateZFW(self):
+        """Calculate the ZFW value."""
+        zfw = self._wizard.gui._flight.aircraft.dow
+        bookedFlight = self._wizard._bookedFlight
+        zfw += (bookedFlight.numCrew + bookedFlight.numPassengers) * 82
+        zfw += bookedFlight.bagWeight
+        zfw += self._cargoWeight.get_int()
+        zfw += bookedFlight.mailWeight
+        return zfw
+        
+    def _updateCalculatedZFW(self):
+        """Update the calculated ZFW"""
+        zfw = self.calculateZFW()
+
+        markupBegin = "<b>"
+        markupEnd = "</b>"
+        if self._simulatorZFWValue is not None and \
+           PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
+            markupBegin += '<span foreground="red">'
+            markupEnd = "</span>" + markupEnd
+        self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
+
+    def _cargoWeightChanged(self, entry, weight):
+        """Called when the cargo weight has changed."""
+        self._updateCalculatedZFW()
+            
+    def _zfwRequested(self, button):
+        """Called when the ZFW is requested from the simulator."""
+        self._zfwButton.set_sensitive(False)
+        self._backButton.set_sensitive(False)
+        self._button.set_sensitive(False)
+        gui = self._wizard.gui
+        gui.beginBusy("Querying ZFW...")
+        gui.simulator.requestZFW(self._handleZFW)
+
+    def _handleZFW(self, zfw):
+        """Called when the ZFW value is retrieved."""
+        gobject.idle_add(self._processZFW, zfw)
+
+    def _processZFW(self, zfw):
+        """Process the given ZFW value received from the simulator."""
+        self._wizard.gui.endBusy()
+        self._zfwButton.set_sensitive(True)
+        self._backButton.set_sensitive(True)
+        self._button.set_sensitive(True)
+        self._simulatorZFWValue = zfw
+        self._simulatorZFW.set_text("%.0f" % (zfw,))
+        self._updateCalculatedZFW()
+
+    def _forwardClicked(self, button):
+        """Called when the forward button is clicked."""
+        self._wizard.nextPage()
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+        
+#-----------------------------------------------------------------------------
+
+class TimePage(Page):
+    """Page displaying the departure and arrival times and allows querying the
+    current time from the flight simulator."""
+    def __init__(self, wizard):
+        help = "The departure and arrival times are displayed below in UTC.\n\n" \
+               "You can also query the current UTC time from the simulator.\n" \
+               "Ensure that you have enough time to properly prepare for the flight."
+        completedHelp = "The departure and arrival times are displayed below in UTC.\n\n" \
+                        "You can also query the current UTC time from the simulator.\n"
+        super(TimePage, self).__init__(wizard, "Time", help,
+                                       completedHelp = completedHelp)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        table = gtk.Table(3, 2)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(False)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        label = gtk.Label("Departure:")
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 0, 1)
+
+        self._departure = gtk.Label()
+        self._departure.set_alignment(0.0, 0.5)
+        table.attach(self._departure, 1, 2, 0, 1)
+        
+        label = gtk.Label("Arrival:")
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 1, 2)
+
+        self._arrival = gtk.Label()
+        self._arrival.set_alignment(0.0, 0.5)
+        table.attach(self._arrival, 1, 2, 1, 2)
+
+        self._timeButton = gtk.Button("_Time from FS:")
+        self._timeButton.set_use_underline(True)
+        self._timeButton.connect("clicked", self._timeRequested)
+        table.attach(self._timeButton, 0, 1, 2, 3)
+
+        self._simulatorTime = gtk.Label("-")
+        self._simulatorTime.set_alignment(0.0, 0.5)
+        table.attach(self._simulatorTime, 1, 2, 2, 3)
+
+        self._backButton = self.addButton(gtk.STOCK_GO_BACK)
+        self._backButton.set_use_stock(True)
+        self._backButton.connect("clicked", self._backClicked)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.connect("clicked", self._forwardClicked)
+
+    def activate(self):
+        """Activate the page."""
+        self._timeButton.set_sensitive(True)
+        bookedFlight = self._wizard._bookedFlight
+        self._departure.set_text(str(bookedFlight.departureTime.time()))
+        self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
+        self._simulatorTime.set_text("-")
+
+    def _timeRequested(self, button):
+        """Request the time from the simulator."""
+        self._timeButton.set_sensitive(False)
+        self._backButton.set_sensitive(False)
+        self._button.set_sensitive(False)
+        self._wizard.gui.beginBusy("Querying time...")
+        self._wizard.gui.simulator.requestTime(self._handleTime)
+
+    def _handleTime(self, timestamp):
+        """Handle the result of a time retrieval."""
+        gobject.idle_add(self._processTime, timestamp)
+
+    def _processTime(self, timestamp):
+        """Process the given time."""
+        self._wizard.gui.endBusy()
+        self._timeButton.set_sensitive(True)
+        self._backButton.set_sensitive(True)
+        self._button.set_sensitive(True)
+        tm = time.gmtime(timestamp)
+        t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
+        self._simulatorTime.set_text(str(t))
+
+        ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
+        dt = self._wizard._bookedFlight.departureTime.time()
+        dts = dt.hour * 3600 + dt.minute * 60 + dt.second
+        diff = dts-ts
+
+        markupBegin = ""
+        markupEnd = ""
+        if diff < 0:
+            markupBegin = '<b><span foreground="red">'
+            markupEnd = '</span></b>'
+        elif diff < 3*60 or diff > 30*60:
+            markupBegin = '<b><span foreground="orange">'
+            markupEnd = '</span></b>'
+
+        self._departure.set_markup(markupBegin + str(dt) + markupEnd)
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+        
+    def _forwardClicked(self, button):
+        """Called when the forward button is clicked."""
+        self._wizard.nextPage()
+        
+#-----------------------------------------------------------------------------
+
+class RoutePage(Page):
+    """The page containing the route and the flight level."""
+    def __init__(self, wizard):
+        help = "Set your cruise flight level below, and\n" \
+               "if necessary, edit the flight plan."
+        completedHelp = "If necessary, you can modify the cruise level and\n" \
+                        "the flight plan below during flight.\n" \
+                        "If so, please, add a comment on why " \
+                        "the modification became necessary."
+        super(RoutePage, self).__init__(wizard, "Route", help,
+                                        completedHelp = completedHelp)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        mainBox = gtk.VBox()
+        alignment.add(mainBox)
+        self.setMainWidget(alignment)
+
+        levelBox = gtk.HBox()
+
+        label = gtk.Label("_Cruise level")
+        label.set_use_underline(True)
+        levelBox.pack_start(label, True, True, 0)
+
+        self._cruiseLevel = gtk.SpinButton()
+        self._cruiseLevel.set_increments(step = 10, page = 100)
+        self._cruiseLevel.set_range(min = 50, max = 500)
+        self._cruiseLevel.set_tooltip_text("The cruise flight level.")
+        self._cruiseLevel.set_numeric(True)
+        self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
+        label.set_mnemonic_widget(self._cruiseLevel)
+        self._filedCruiseLevel = 240
+
+        levelBox.pack_start(self._cruiseLevel, False, False, 8)
+
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+        alignment.add(levelBox)
+
+        mainBox.pack_start(alignment, False, False, 0)
+
+
+        routeBox = gtk.VBox()
+
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+        label = gtk.Label("_Route")
+        label.set_use_underline(True)
+        alignment.add(label)
+        routeBox.pack_start(alignment, True, True, 0)
+
+        routeWindow = gtk.ScrolledWindow()
+        routeWindow.set_size_request(400, 80)
+        routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
+                                    else gtk.SHADOW_IN)
+        routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                               else gtk.POLICY_AUTOMATIC,
+                               gtk.PolicyType.AUTOMATIC if pygobject
+                               else gtk.POLICY_AUTOMATIC)
+
+        self._route = gtk.TextView()
+        self._route.set_tooltip_text("The planned flight route.")
+        self._route.get_buffer().connect("changed", self._routeChanged)
+        routeWindow.add(self._route)
+
+        label.set_mnemonic_widget(self._route)
+        routeBox.pack_start(routeWindow, True, True, 0)        
+
+        mainBox.pack_start(routeBox, True, True, 8)
+
+        self._backButton = self.addButton(gtk.STOCK_GO_BACK)
+        self._backButton.set_use_stock(True)
+        self._backButton.connect("clicked", self._backClicked)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.connect("clicked", self._forwardClicked)
+
+    @property
+    def filedCruiseLevel(self):
+        """Get the filed cruise level."""
+        return self._filedCruiseLevel
+
+    @property
+    def cruiseLevel(self):
+        """Get the cruise level."""
+        return self._cruiseLevel.get_value_as_int()
+
+    @property
+    def route(self):
+        """Get the route."""
+        return self._getRoute()
+
+    def activate(self):
+        """Setup the route from the booked flight."""
+        self._cruiseLevel.set_value(240)
+        self._filedCruiseLevel = 240
+        self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
+        self._updateForwardButton()
+
+    def _getRoute(self):
+        """Get the text of the route."""
+        buffer = self._route.get_buffer()
+        return buffer.get_text(buffer.get_start_iter(),
+                               buffer.get_end_iter(), True)
+
+    def _updateForwardButton(self):
+        """Update the sensitivity of the forward button."""
+        self._button.set_sensitive(self._cruiseLevel.get_value_as_int()>=50 and \
+                                   self._getRoute()!="")
+                                   
+    def _cruiseLevelChanged(self, spinButton):
+        """Called when the cruise level has changed."""
+        self._updateForwardButton()
+
+    def _routeChanged(self, textBuffer):
+        """Called when the route has changed."""
+        self._updateForwardButton()
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+        
+    def _forwardClicked(self, button):
+        """Called when the Forward button is clicked."""
+        if self._completed:
+            self._wizard.nextPage()
+        else:
+            bookedFlight = self._wizard._bookedFlight
+            self._filedCruiseLevel = self.cruiseLevel
+            self._wizard.gui.beginBusy("Downloading NOTAMs...")
+            self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
+                                                  bookedFlight.departureICAO,
+                                                  bookedFlight.arrivalICAO)
+
+    def _notamsCallback(self, returned, result):
+        """Callback for the NOTAMs."""
+        gobject.idle_add(self._handleNOTAMs, returned, result)
+
+    def _handleNOTAMs(self, returned, result):
+        """Handle the NOTAMs."""
+        if returned:
+            self._wizard._departureNOTAMs = result.departureNOTAMs
+            self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
+        else:
+            self._wizard._departureNOTAMs = None
+            self._wizard._arrivalNOTAMs = None
+
+        bookedFlight = self._wizard._bookedFlight
+        self._wizard.gui.beginBusy("Downloading METARs...")
+        self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
+                                              [bookedFlight.departureICAO,
+                                               bookedFlight.arrivalICAO])
+
+    def _metarsCallback(self, returned, result):
+        """Callback for the METARs."""
+        gobject.idle_add(self._handleMETARs, returned, result)
+
+    def _handleMETARs(self, returned, result):
+        """Handle the METARs."""
+        self._wizard._departureMETAR = None
+        self._wizard._arrivalMETAR = None
+        bookedFlight = self._wizard._bookedFlight
+        if returned:
+            if bookedFlight.departureICAO in result.metars:
+                self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
+            if bookedFlight.arrivalICAO in result.metars:
+                self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
+
+        self._wizard.gui.endBusy()
+        self._backButton.set_sensitive(True)
+        self._button.set_sensitive(True)
+        self._wizard.nextPage()
+
+#-----------------------------------------------------------------------------
+
+class BriefingPage(Page):
+    """Page for the briefing."""
+    def __init__(self, wizard, departure):
+        """Construct the briefing page."""
+        self._departure = departure
+        
+        title = "Briefing (%d/2): %s" % (1 if departure else 2,
+                                        "departure" if departure
+                                         else "arrival")
+                                                                
+        help = "Read carefully the NOTAMs and METAR below.\n\n" \
+               "You can edit the METAR if your simulator or network\n" \
+               "provides different weather."
+        completedHelp = "If your simulator or network provides a different\n" \
+                        "weather, you can edit the METAR below."
+        super(BriefingPage, self).__init__(wizard, title, help,
+                                           completedHelp = completedHelp)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 1.0, yscale = 1.0)
+
+        mainBox = gtk.VBox()
+        alignment.add(mainBox)
+        self.setMainWidget(alignment)
+
+        self._notamsFrame = gtk.Frame()
+        self._notamsFrame.set_label("LHBP NOTAMs")
+        scrolledWindow = gtk.ScrolledWindow()
+        scrolledWindow.set_size_request(-1, 128)
+        # FIXME: these constants should be in common
+        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC,
+                                  gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC)
+        self._notams = gtk.TextView()
+        self._notams.set_editable(False)
+        self._notams.set_accepts_tab(False)
+        self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
+        scrolledWindow.add(self._notams)
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                  xscale = 1.0, yscale = 1.0)
+        alignment.set_padding(padding_top = 4, padding_bottom = 0,
+                              padding_left = 0, padding_right = 0)
+        alignment.add(scrolledWindow)
+        self._notamsFrame.add(alignment)
+        mainBox.pack_start(self._notamsFrame, True, True, 4)
+        
+        self._metarFrame = gtk.Frame()
+        self._metarFrame.set_label("LHBP METAR")
+        scrolledWindow = gtk.ScrolledWindow()
+        scrolledWindow.set_size_request(-1, 32)
+        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC,
+                                  gtk.PolicyType.AUTOMATIC if pygobject
+                                  else gtk.POLICY_AUTOMATIC)
+        self._metar = gtk.TextView()
+        self._metar.set_accepts_tab(False)
+        self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
+        scrolledWindow.add(self._metar)
+        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                  xscale = 1.0, yscale = 1.0)
+        alignment.set_padding(padding_top = 4, padding_bottom = 0,
+                              padding_left = 0, padding_right = 0)
+        alignment.add(scrolledWindow)
+        self._metarFrame.add(alignment)
+        mainBox.pack_start(self._metarFrame, True, True, 4)
+
+        button = self.addButton(gtk.STOCK_GO_BACK)
+        button.set_use_stock(True)
+        button.connect("clicked", self._backClicked)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.connect("clicked", self._forwardClicked)
+
+    @property
+    def metar(self):
+        """Get the METAR on the page."""
+        buffer = self._metar.get_buffer()
+        return buffer.get_text(buffer.get_start_iter(),
+                               buffer.get_end_iter(), True)        
+
+    def activate(self):
+        """Activate the page."""
+        if not self._departure:
+            self._button.set_label("I have read the briefing and am ready to fly!")
+            self._button.set_use_stock(False)
+
+        bookedFlight = self._wizard._bookedFlight
+
+        icao = bookedFlight.departureICAO if self._departure \
+               else bookedFlight.arrivalICAO
+        notams = self._wizard._departureNOTAMs if self._departure \
+                 else self._wizard._arrivalNOTAMs
+        metar = self._wizard._departureMETAR if self._departure \
+                 else self._wizard._arrivalMETAR
+
+        self._notamsFrame.set_label(icao + " NOTAMs")
+        buffer = self._notams.get_buffer()
+        if notams is None:
+            buffer.set_text("Could not download NOTAMs")
+        elif not notams:
+            buffer.set_text("Could not download NOTAM for this airport")
+        else:
+            s = ""
+            for notam in notams:
+                s += str(notam.begin)
+                if notam.end is not None:
+                    s += " - " + str(notam.end)
+                elif notam.permanent:
+                    s += " - PERMANENT"
+                s += "\n"
+                if notam.repeatCycle:
+                    s += "Repeat cycle: " + notam.repeatCycle + "\n"
+                s += notam.notice + "\n"
+                s += "-------------------- * --------------------\n"
+            buffer.set_text(s)
+
+        self._metarFrame.set_label(icao + " METAR")
+        buffer = self._metar.get_buffer()
+        if metar is None:
+            buffer.set_text("Could not download METAR")
+        else:
+            buffer.set_text(metar)
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+        
+    def _forwardClicked(self, button):
+        """Called when the forward button is clicked."""
+        if not self._departure:
+            if not self._completed:
+                self._wizard.gui.startMonitoring()
+                self._button.set_use_stock(True)
+                self._button.set_label(gtk.STOCK_GO_FORWARD)
+                self.complete()
+
+        self._wizard.nextPage()
+
+#-----------------------------------------------------------------------------
+
+class TakeoffPage(Page):
+    """Page for entering the takeoff data."""
+    def __init__(self, wizard):
+        """Construct the takeoff page."""
+        help = "Enter the runway and SID used, as well as the speeds."
+        completedHelp = "The runway, SID and takeoff speeds logged can be seen below."
+
+        super(TakeoffPage, self).__init__(wizard, "Takeoff", help,
+                                          completedHelp = completedHelp)
+
+        self._forwardAllowed = False
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        table = gtk.Table(5, 4)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(False)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        label = gtk.Label("Run_way:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 0, 1)
+
+        self._runway = gtk.Entry()
+        self._runway.set_width_chars(10)
+        self._runway.set_tooltip_text("The runway the takeoff is performed from.")
+        self._runway.connect("changed", self._valueChanged)
+        table.attach(self._runway, 1, 3, 0, 1)
+        label.set_mnemonic_widget(self._runway)
+        
+        label = gtk.Label("_SID:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 1, 2)
+
+        self._sid = gtk.Entry()
+        self._sid.set_width_chars(10)
+        self._sid.set_tooltip_text("The name of the Standard Instrument Deparature procedure followed.")
+        self._sid.connect("changed", self._valueChanged)
+        table.attach(self._sid, 1, 3, 1, 2)
+        label.set_mnemonic_widget(self._sid)
+        
+        label = gtk.Label("V<sub>_1</sub>:")
+        label.set_use_markup(True)
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 2, 3)
+
+        self._v1 = IntegerEntry()
+        self._v1.set_width_chars(4)
+        self._v1.set_tooltip_markup("The takeoff decision speed in knots.")
+        self._v1.connect("integer-changed", self._valueChanged)
+        table.attach(self._v1, 2, 3, 2, 3)
+        label.set_mnemonic_widget(self._v1)
+        
+        table.attach(gtk.Label("knots"), 3, 4, 2, 3)
+        
+        label = gtk.Label("V<sub>_R</sub>:")
+        label.set_use_markup(True)
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 3, 4)
+
+        self._vr = IntegerEntry()
+        self._vr.set_width_chars(4)
+        self._vr.set_tooltip_markup("The takeoff rotation speed in knots.")
+        self._vr.connect("integer-changed", self._valueChanged)
+        table.attach(self._vr, 2, 3, 3, 4)
+        label.set_mnemonic_widget(self._vr)
+        
+        table.attach(gtk.Label("knots"), 3, 4, 3, 4)
+        
+        label = gtk.Label("V<sub>_2</sub>:")
+        label.set_use_markup(True)
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 0, 1, 4, 5)
+
+        self._v2 = IntegerEntry()
+        self._v2.set_width_chars(4)
+        self._v2.set_tooltip_markup("The takeoff safety speed in knots.")
+        self._v2.connect("integer-changed", self._valueChanged)
+        table.attach(self._v2, 2, 3, 4, 5)
+        label.set_mnemonic_widget(self._v2)
+        
+        table.attach(gtk.Label("knots"), 3, 4, 4, 5)
+        
+        button = self.addButton(gtk.STOCK_GO_BACK)
+        button.set_use_stock(True)
+        button.connect("clicked", self._backClicked)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.connect("clicked", self._forwardClicked)
+
+    @property
+    def runway(self):
+        """Get the runway."""
+        return self._runway.get_text()
+
+    @property
+    def sid(self):
+        """Get the SID."""
+        return self._sid.get_text()
+
+    @property
+    def v1(self):
+        """Get the v1 speed."""
+        return self._v1.get_int()
+
+    @property
+    def vr(self):
+        """Get the vr speed."""
+        return self._vr.get_int()
+
+    @property
+    def v2(self):
+        """Get the v2 speed."""
+        return self._v2.get_int()
+
+    def activate(self):
+        """Activate the page."""
+        self._runway.set_text("")
+        self._runway.set_sensitive(True)
+        self._sid.set_text("")
+        self._sid.set_sensitive(True)
+        self._v1.set_int(None)
+        self._v1.set_sensitive(True)
+        self._vr.set_int(None)
+        self._vr.set_sensitive(True)
+        self._v2.set_int(None)
+        self._v2.set_sensitive(True)
+        self._button.set_sensitive(False)
+        
+    def finalize(self):
+        """Finalize the page."""
+        self._runway.set_sensitive(False)
+        self._sid.set_sensitive(False)
+        self._v1.set_sensitive(False)
+        self._vr.set_sensitive(False)
+        self._v2.set_sensitive(False)
+        self._wizard.gui.flight.aircraft.updateV1R2()
+
+    def allowForward(self):
+        """Allow going to the next page."""
+        self._forwardAllowed = True
+        self._updateForwardButton()
+
+    def _updateForwardButton(self):
+        """Update the sensitivity of the forward button based on some conditions."""
+        sensitive = self._forwardAllowed and \
+                    self._runway.get_text()!="" and \
+                    self._sid.get_text()!="" and \
+                    self.v1 is not None and \
+                    self.vr is not None and \
+                    self.v2 is not None and \
+                    self.v1 <= self.vr and \
+                    self.vr <= self.v2
+        self._button.set_sensitive(sensitive)
+
+    def _valueChanged(self, widget, arg = None):
+        """Called when the value of some widget has changed."""
+        self._updateForwardButton()
+        
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+        
+    def _forwardClicked(self, button):
+        """Called when the forward button is clicked."""
+        self._wizard.nextPage()
+
+#-----------------------------------------------------------------------------
+
+class LandingPage(Page):
+    """Page for entering landing data."""
+    def __init__(self, wizard):
+        """Construct the landing page."""
+        help = "Enter the STAR and/or transition, runway,\n" \
+               "approach type and V<sub>Ref</sub> used."
+        completedHelp = "The STAR and/or transition, runway, approach\n" \
+                        "type and V<sub>Ref</sub> logged can be seen below."
+
+        super(LandingPage, self).__init__(wizard, "Landing", help,
+                                          completedHelp = completedHelp)
+
+        self._flightEnded = False
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        table = gtk.Table(5, 5)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(False)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        self._starButton = gtk.CheckButton()
+        self._starButton.connect("clicked", self._starButtonClicked)
+        table.attach(self._starButton, 0, 1, 0, 1)
+
+        label = gtk.Label("_STAR:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 1, 2, 0, 1)
+
+        self._star = gtk.Entry()
+        self._star.set_width_chars(10)
+        self._star.set_tooltip_text("The name of Standard Terminal Arrival Route followed.")
+        self._star.connect("changed", self._updateForwardButton)
+        self._star.set_sensitive(False)
+        table.attach(self._star, 2, 4, 0, 1)
+        label.set_mnemonic_widget(self._starButton)
+
+        self._transitionButton = gtk.CheckButton()
+        self._transitionButton.connect("clicked", self._transitionButtonClicked)
+        table.attach(self._transitionButton, 0, 1, 1, 2)
+
+        label = gtk.Label("_Transition:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 1, 2, 1, 2)
+
+        self._transition = gtk.Entry()
+        self._transition.set_width_chars(10)
+        self._transition.set_tooltip_text("The name of transition executed or VECTORS if vectored by ATC.")
+        self._transition.connect("changed", self._updateForwardButton)
+        self._transition.set_sensitive(False)
+        table.attach(self._transition, 2, 4, 1, 2)
+        label.set_mnemonic_widget(self._transitionButton)
+
+        label = gtk.Label("Run_way:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 1, 2, 2, 3)
+
+        self._runway = gtk.Entry()
+        self._runway.set_width_chars(10)
+        self._runway.set_tooltip_text("The runway the landing is performed on.")
+        self._runway.connect("changed", self._updateForwardButton)
+        table.attach(self._runway, 2, 4, 2, 3)
+        label.set_mnemonic_widget(self._runway)
+
+        label = gtk.Label("_Approach type:")
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 1, 2, 3, 4)
+
+        self._approachType = gtk.Entry()
+        self._approachType.set_width_chars(10)
+        self._approachType.set_tooltip_text("The type of the approach, e.g. ILS or VISUAL.")
+        self._approachType.connect("changed", self._updateForwardButton)
+        table.attach(self._approachType, 2, 4, 3, 4)
+        label.set_mnemonic_widget(self._approachType)
+
+        label = gtk.Label("V<sub>_Ref</sub>:")
+        label.set_use_markup(True)
+        label.set_use_underline(True)
+        label.set_alignment(0.0, 0.5)
+        table.attach(label, 1, 2, 5, 6)
+
+        self._vref = IntegerEntry()
+        self._vref.set_width_chars(5)
+        self._vref.set_tooltip_markup("The approach reference speed in knots.")
+        self._vref.connect("integer-changed", self._vrefChanged)
+        table.attach(self._vref, 3, 4, 5, 6)
+        label.set_mnemonic_widget(self._vref)
+        
+        table.attach(gtk.Label("knots"), 4, 5, 5, 6)
+        
+        button = self.addButton(gtk.STOCK_GO_BACK)
+        button.set_use_stock(True)
+        button.connect("clicked", self._backClicked)
+
+        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
+        self._button.set_use_stock(True)
+        self._button.connect("clicked", self._forwardClicked)
+
+        # These are needed for correct size calculations
+        self._starButton.set_active(True)
+        self._transitionButton.set_active(True)
+
+    @property
+    def star(self):
+        """Get the STAR or None if none entered."""
+        return self._star.get_text() if self._starButton.get_active() else None
+
+    @property
+    def transition(self):
+        """Get the transition or None if none entered."""
+        return self._transition.get_text() \
+               if self._transitionButton.get_active() else None
+
+    @property
+    def approachType(self):
+        """Get the approach type."""
+        return self._approachType.get_text()
+
+    @property
+    def runway(self):
+        """Get the runway."""
+        return self._runway.get_text()
+
+    @property
+    def vref(self):
+        """Return the landing reference speed."""
+        return self._vref.get_int()
+
+    def activate(self):
+        """Called when the page is activated."""
+        self._starButton.set_sensitive(True)
+        self._starButton.set_active(False)
+        self._star.set_text("")
+
+        self._transitionButton.set_sensitive(True)
+        self._transitionButton.set_active(False)
+        self._transition.set_text("")
+
+        self._runway.set_text("")
+        self._runway.set_sensitive(True)
+
+        self._approachType.set_text("")
+        self._approachType.set_sensitive(True)
+
+        self._vref.set_int(None)
+        self._vref.set_sensitive(True)
+
+        self._updateForwardButton()
+
+    def flightEnded(self):
+        """Called when the flight has ended."""
+        self._flightEnded = True
+        self._updateForwardButton()
+
+    def finalize(self):
+        """Finalize the page."""
+        self._starButton.set_sensitive(False)
+        self._star.set_sensitive(False)
+
+        self._transitionButton.set_sensitive(False)
+        self._transition.set_sensitive(False)
+
+        self._runway.set_sensitive(False)
+
+        self._approachType.set_sensitive(False)
+
+        self._vref.set_sensitive(False)
+        self._wizard.gui.flight.aircraft.updateVRef()
+        # FIXME: Perhaps a separate initialize() call which would set up
+        # defaults? -> use reset()
+        self._flightEnded = False
+
+    def _starButtonClicked(self, button):
+        """Called when the STAR button is clicked."""
+        active = button.get_active()
+        self._star.set_sensitive(active)
+        if active:
+            self._star.grab_focus()
+        self._updateForwardButton()
+
+    def _transitionButtonClicked(self, button):
+        """Called when the Transition button is clicked."""
+        active = button.get_active()
+        self._transition.set_sensitive(active)
+        if active:
+            self._transition.grab_focus()        
+        self._updateForwardButton()    
+
+    def _updateForwardButton(self, widget = None):
+        """Update the sensitivity of the forward button."""
+        sensitive = self._flightEnded and \
+                    (self._starButton.get_active() or \
+                     self._transitionButton.get_active()) and \
+                    (self._star.get_text()!="" or
+                     not self._starButton.get_active()) and \
+                    (self._transition.get_text()!="" or
+                     not self._transitionButton.get_active()) and \
+                    self._runway.get_text()!="" and \
+                    self._approachType.get_text()!="" and \
+                    self.vref is not None
+        self._button.set_sensitive(sensitive)
+
+    def _vrefChanged(self, widget, value):
+        """Called when the Vref has changed."""
+        self._updateForwardButton()
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+        
+    def _forwardClicked(self, button):
+        """Called when the forward button is clicked."""
+        self._wizard.nextPage()
+
+#-----------------------------------------------------------------------------
+
+class FinishPage(Page):
+    """Flight finish page."""
+    _flightTypes = [ ("scheduled", const.FLIGHTTYPE_SCHEDULED),
+                     ("old-timer", const.FLIGHTTYPE_OLDTIMER),
+                     ("VIP", const.FLIGHTTYPE_VIP),
+                     ("charter", const.FLIGHTTYPE_CHARTER) ]
+    
+    def __init__(self, wizard):
+        """Construct the finish page."""
+        help = "There are some statistics about your flight below.\n\n" \
+               "Review the data, also on earlier pages, and if you are\n" \
+               "satisfied, you can save or send your PIREP."
+
+        super(FinishPage, self).__init__(wizard, "Finish", help)
+        
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+
+        table = gtk.Table(7, 2)
+        table.set_row_spacings(4)
+        table.set_col_spacings(16)
+        table.set_homogeneous(False)
+        alignment.add(table)
+        self.setMainWidget(alignment)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Flight rating:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 0, 1)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._flightRating = gtk.Label()
+        self._flightRating.set_width_chars(7)
+        self._flightRating.set_alignment(0.0, 0.5)
+        self._flightRating.set_use_markup(True)
+        labelAlignment.add(self._flightRating)
+        table.attach(labelAlignment, 1, 2, 0, 1)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Flight time:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 1, 2)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._flightTime = gtk.Label()
+        self._flightTime.set_width_chars(10)
+        self._flightTime.set_alignment(0.0, 0.5)
+        self._flightTime.set_use_markup(True)
+        labelAlignment.add(self._flightTime)
+        table.attach(labelAlignment, 1, 2, 1, 2)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Block time:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 2, 3)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._blockTime = gtk.Label()
+        self._blockTime.set_width_chars(10)
+        self._blockTime.set_alignment(0.0, 0.5)
+        self._blockTime.set_use_markup(True)
+        labelAlignment.add(self._blockTime)
+        table.attach(labelAlignment, 1, 2, 2, 3)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Distance flown:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 3, 4)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._distanceFlown = gtk.Label()
+        self._distanceFlown.set_width_chars(10)
+        self._distanceFlown.set_alignment(0.0, 0.5)
+        self._distanceFlown.set_use_markup(True)
+        labelAlignment.add(self._distanceFlown)
+        table.attach(labelAlignment, 1, 2, 3, 4)
+        
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("Fuel used:")
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 4, 5)
+
+        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        self._fuelUsed = gtk.Label()
+        self._fuelUsed.set_width_chars(10)
+        self._fuelUsed.set_alignment(0.0, 0.5)
+        self._fuelUsed.set_use_markup(True)
+        labelAlignment.add(self._fuelUsed)
+        table.attach(labelAlignment, 1, 2, 4, 5)
+
+        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
+        label = gtk.Label("_Type:")
+        label.set_use_underline(True)
+        labelAlignment.add(label)
+        table.attach(labelAlignment, 0, 1, 5, 6)
+
+        flightTypeModel = gtk.ListStore(str, int)
+        for (name, type) in FinishPage._flightTypes:
+            flightTypeModel.append([name, type])
+
+        self._flightType = gtk.ComboBox(model = flightTypeModel)
+        renderer = gtk.CellRendererText()
+        self._flightType.pack_start(renderer, True)
+        self._flightType.add_attribute(renderer, "text", 0)
+        self._flightType.set_tooltip_text("Select the type of the flight.")
+        self._flightType.set_active(0)
+        self._flightType.connect("changed", self._flightTypeChanged)
+        flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        flightTypeAlignment.add(self._flightType)
+        table.attach(flightTypeAlignment, 1, 2, 5, 6)
+        label.set_mnemonic_widget(self._flightType)        
+
+        self._onlineFlight = gtk.CheckButton("_Online flight")
+        self._onlineFlight.set_use_underline(True)
+        self._onlineFlight.set_tooltip_text("Check if your flight was online, uncheck otherwise.")
+        onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
+        onlineFlightAlignment.add(self._onlineFlight)
+        table.attach(onlineFlightAlignment, 1, 2, 6, 7)
+
+        button = self.addButton(gtk.STOCK_GO_BACK)
+        button.set_use_stock(True)
+        button.connect("clicked", self._backClicked)
+
+        self._saveButton = self.addButton("S_ave PIREP...")
+        self._saveButton.set_use_underline(True)
+        self._saveButton.set_sensitive(False)
+        #self._saveButton.connect("clicked", self._saveClicked)
+        
+        self._sendButton = self.addButton("_Send PIREP...", True)
+        self._sendButton.set_use_underline(True)
+        self._sendButton.set_sensitive(False)
+        self._sendButton.connect("clicked", self._sendClicked)
+        
+    @property
+    def flightType(self):
+        """Get the flight type."""
+        index = self._flightType.get_active()
+        return None if index<0 else self._flightType.get_model()[index][1]
+
+    @property
+    def online(self):
+        """Get whether the flight was an online flight or not."""
+        return self._onlineFlight.get_active()
+
+    def activate(self):
+        """Activate the page."""
+        flight = self._wizard.gui._flight
+        rating = flight.logger.getRating()
+        if rating<0:
+            self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
+        else:
+            self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
+
+        flightLength = flight.flightTimeEnd - flight.flightTimeStart
+        self._flightTime.set_markup("<b>%s</b>" % \
+                                    (util.getTimeIntervalString(flightLength),))
+        
+        blockLength = flight.blockTimeEnd - flight.blockTimeStart
+        self._blockTime.set_markup("<b>%s</b>" % \
+                                   (util.getTimeIntervalString(blockLength),))
+
+        self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
+                                       (flight.flownDistance,))
+        
+        self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
+                                  (flight.endFuel - flight.startFuel,))
+
+        self._flightType.set_active(-1)
+        self._onlineFlight.set_active(True)
+
+    def _backClicked(self, button):
+        """Called when the Back button is pressed."""
+        self.goBack()
+
+    def _flightTypeChanged(self, comboBox):
+        """Called when the flight type has changed."""
+        index = self._flightType.get_active()
+        flightTypeIsValid = index>=0
+        #self._saveButton.set_sensitive(flightTypeIsValid)
+        self._sendButton.set_sensitive(flightTypeIsValid)
+
+    def _sendClicked(self, button):
+        """Called when the Send button is clicked."""
+        pirep = PIREP(self._wizard.gui)
+        gui = self._wizard.gui
+        gui.beginBusy("Sending PIREP...")
+        gui.webHandler.sendPIREP(self._pirepSentCallback, pirep)
+
+    def _pirepSentCallback(self, returned, result):
+        """Callback for the PIREP sending result."""
+        gobject.idle_add(self._handlePIREPSent, returned, result)
+
+    def _handlePIREPSent(self, returned, result):
+        """Callback for the PIREP sending result."""
+        self._wizard.gui.endBusy()
+        secondaryMarkup = None
+        type = MESSAGETYPE_ERROR
+        if returned:
+            if result.success:
+                type = MESSAGETYPE_INFO
+                messageFormat = "The PIREP was sent successfully."
+                secondaryMarkup = "Await the thorough scrutiny from our PIREP correctors! :)"
+            elif result.alreadyFlown:
+                messageFormat = "The PIREP for this flight has already been sent!"
+                secondaryMarkup = "You may clear the old PIREP on the MAVA website."
+            elif result.notAvailable:
+                messageFormat = "This flight is not available anymore!"
+            else:
+                messageFormat = "The MAVA website returned with an unknown error."
+                secondaryMarkup = "See the debug log for more information."
+        else:
+            print "PIREP sending failed", result
+            messageFormat = "Could not send the PIREP to the MAVA website."
+            secondaryMarkup = "This can be a network problem, in which case\n" \
+                              "you may try again later. Or it can be a bug;\n" \
+                              "see the debug log for more information."
+        
+        dialog = gtk.MessageDialog(type = type, buttons = BUTTONSTYPE_OK,
+                                   message_format = messageFormat)
+        if secondaryMarkup is not None:
+            dialog.format_secondary_markup(secondaryMarkup)
+
+        dialog.run()
+        dialog.hide()
+        
+#-----------------------------------------------------------------------------
+
+class Wizard(gtk.VBox):
+    """The flight wizard."""
+    def __init__(self, gui):
+        """Construct the wizard."""
+        super(Wizard, self).__init__()
+
+        self.gui = gui
+
+        self._pages = []
+        self._currentPage = None
+        
+        self._pages.append(LoginPage(self))
+        self._pages.append(FlightSelectionPage(self))
+        self._pages.append(GateSelectionPage(self))
+        self._pages.append(ConnectPage(self))
+        self._payloadPage = PayloadPage(self) 
+        self._pages.append(self._payloadPage)
+        self._pages.append(TimePage(self))
+        self._routePage = RoutePage(self)
+        self._pages.append(self._routePage)
+        self._departureBriefingPage = BriefingPage(self, True)
+        self._pages.append(self._departureBriefingPage)
+        self._arrivalBriefingPage = BriefingPage(self, False)
+        self._pages.append(self._arrivalBriefingPage)
+        self._takeoffPage = TakeoffPage(self) 
+        self._pages.append(self._takeoffPage)
+        self._landingPage = LandingPage(self) 
+        self._pages.append(self._landingPage)
+        self._finishPage = FinishPage(self)
+        self._pages.append(self._finishPage)
+        
+        maxWidth = 0
+        maxHeight = 0
+        for page in self._pages:
+            page.show_all()
+            pageSizeRequest = page.size_request()
+            width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
+            height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
+            maxWidth = max(maxWidth, width)
+            maxHeight = max(maxHeight, height)
+        maxWidth += 16
+        maxHeight += 32
+        self.set_size_request(maxWidth, maxHeight)
+
+        self._initialize()
+        
+    @property
+    def loginResult(self):
+        """Get the login result."""
+        return self._loginResult
+
+    def setCurrentPage(self, index, finalize = False):
+        """Set the current page to the one with the given index."""
+        assert index < len(self._pages)
+
+        fromPage = self._currentPage
+        if fromPage is not None:
+            page = self._pages[fromPage]
+            if finalize and not page._completed:
+                page.complete()
+            self.remove(page)
+
+        self._currentPage = index
+        page = self._pages[index]
+        self.add(page)
+        if page._fromPage is None:
+            page._fromPage = fromPage
+            page.initialize()
+        self.show_all()
+        if fromPage is not None:
+            self.grabDefault()
+
+    @property
+    def bookedFlight(self):
+        """Get the booked flight selected."""
+        return self._bookedFlight
+
+    @property
+    def cargoWeight(self):
+        """Get the calculated ZFW value."""
+        return self._payloadPage.cargoWeight
+
+    @property
+    def zfw(self):
+        """Get the calculated ZFW value."""
+        return 0 if self._bookedFlight is None \
+               else self._payloadPage.calculateZFW()
+
+    @property
+    def filedCruiseAltitude(self):
+        """Get the filed cruise altitude."""
+        return self._routePage.filedCruiseLevel * 100
+
+    @property
+    def cruiseAltitude(self):
+        """Get the cruise altitude."""
+        return self._routePage.cruiseLevel * 100
+
+    @property
+    def route(self):
+        """Get the route."""
+        return self._routePage.route
+
+    @property
+    def departureMETAR(self):
+        """Get the METAR of the departure airport."""
+        return self._departureBriefingPage.metar
+
+    @property
+    def arrivalMETAR(self):
+        """Get the METAR of the arrival airport."""
+        return self._arrivalBriefingPage.metar
+
+    @property
+    def departureRunway(self):
+        """Get the departure runway."""
+        return self._takeoffPage.runway
+
+    @property
+    def sid(self):
+        """Get the SID."""
+        return self._takeoffPage.sid
+
+    @property
+    def v1(self):
+        """Get the V1 speed."""
+        return self._takeoffPage.v1
+
+    @property
+    def vr(self):
+        """Get the Vr speed."""
+        return self._takeoffPage.vr
+
+    @property
+    def v2(self):
+        """Get the V2 speed."""
+        return self._takeoffPage.v2
+
+    @property
+    def arrivalRunway(self):
+        """Get the arrival runway."""
+        return self._landingPage.runway
+
+    @property
+    def star(self):
+        """Get the STAR."""
+        return self._landingPage.star
+
+    @property
+    def transition(self):
+        """Get the transition."""
+        return self._landingPage.transition
+
+    @property
+    def approachType(self):
+        """Get the approach type."""
+        return self._landingPage.approachType
+
+    @property
+    def vref(self):
+        """Get the Vref speed."""
+        return self._landingPage.vref
+
+    @property
+    def flightType(self):
+        """Get the flight type."""
+        return self._finishPage.flightType
+
+    @property
+    def online(self):
+        """Get whether the flight was online or not."""
+        return self._finishPage.online
+
+    def nextPage(self, finalize = True):
+        """Go to the next page."""
+        self.jumpPage(1, finalize)
+
+    def jumpPage(self, count, finalize = True):
+        """Go to the page which is 'count' pages after the current one."""
+        self.setCurrentPage(self._currentPage + count, finalize = finalize)
+
+    def grabDefault(self):
+        """Make the default button of the current page the default."""
+        self._pages[self._currentPage].grabDefault()
+
+    def connected(self, fsType, descriptor):
+        """Called when the connection could be made to the simulator."""
+        self.nextPage()
+
+    def reset(self):
+        """Resets the wizard to go back to the login page."""
+        self._initialize()
+
+    def setStage(self, stage):
+        """Set the flight stage to the given one."""
+        if stage==const.STAGE_TAKEOFF:
+            self._takeoffPage.allowForward()
+        elif stage==const.STAGE_END:
+            self._landingPage.flightEnded()
+
+    def _initialize(self):
+        """Initialize the wizard."""
+        self._fleet = None
+        self._fleetCallback = None
+        self._updatePlaneCallback = None
+        
+        self._loginResult = None
+        self._bookedFlight = None
+        self._departureGate = "-"
+        self._departureNOTAMs = None
+        self._departureMETAR = None
+        self._arrivalNOTAMs = None
+        self._arrivalMETAR = None
+
+        for page in self._pages:
+            page.reset()
+        
+        self.setCurrentPage(0)
+        
+    def _getFleet(self, callback, force = False):
+        """Get the fleet, if needed.
+
+        callback is function that will be called, when the feet is retrieved,
+        or the retrieval fails. It should have a single argument that will
+        receive the fleet object on success, None otherwise.
+        """
+        if self._fleet is not None and not force:
+            callback(self._fleet)
+
+        self.gui.beginBusy("Retrieving fleet...")
+        self._fleetCallback = callback
+        self.gui.webHandler.getFleet(self._fleetResultCallback)
+
+    def _fleetResultCallback(self, returned, result):
+        """Called when the fleet has been queried."""
+        gobject.idle_add(self._handleFleetResult, returned, result)
+
+    def _handleFleetResult(self, returned, result):
+        """Handle the fleet result."""
+        self.gui.endBusy()
+        if returned:
+            self._fleet = result.fleet
+        else:
+            self._fleet = None
+
+            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                       buttons = BUTTONSTYPE_OK,
+                                       message_format =
+                                       "Failed to retrieve the information on "
+                                       "the fleet.")
+            dialog.run()
+            dialog.hide()
+
+        self._fleetCallback(self._fleet)
+
+    def _updatePlane(self, callback, tailNumber, status, gateNumber = None):
+        """Update the given plane's gate information."""
+        self.gui.beginBusy("Updating plane status...")
+        self._updatePlaneCallback = callback
+        self.gui.webHandler.updatePlane(self._updatePlaneResultCallback,
+                                        tailNumber, status, gateNumber)
+
+    def _updatePlaneResultCallback(self, returned, result):
+        """Callback for the plane updating operation."""
+        gobject.idle_add(self._handleUpdatePlaneResult, returned, result)
+
+    def _handleUpdatePlaneResult(self, returned, result):
+        """Handle the result of a plane update operation."""
+        self.gui.endBusy()
+        if returned:
+            success = result.success
+        else:
+            success = None
+
+            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                       buttons = BUTTONSTYPE_OK,
+                                       message_format =
+                                       "Failed to update the statuis of "
+                                       "the airplane.")
+            dialog.run()
+            dialog.hide()
+
+        self._updatePlaneCallback(success)
+
+    def _connectSimulator(self):
+        """Connect to the simulator."""
+        self.gui.connectSimulator(self._bookedFlight.aircraftType)
+    
+#-----------------------------------------------------------------------------
+
Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 97)
+++ 	(revision )
@@ -1,2181 +1,0 @@
-# The flight handling "wizard"
-
-from mlx.gui.common import *
-
-import mlx.const as const
-import mlx.fs as fs
-from mlx.checks import PayloadChecker
-import mlx.util as util
-from mlx.pirep import PIREP
-
-import datetime
-import time
-
-#------------------------------------------------------------------------------
-
-acftTypeNames = { const.AIRCRAFT_B736: "Boeing 737-600",
-                  const.AIRCRAFT_B737: "Boeing 737-700",
-                  const.AIRCRAFT_B738: "Boeing 737-800",
-                  const.AIRCRAFT_DH8D: "Bombardier Dash 8-Q400",
-                  const.AIRCRAFT_B733: "Boeing 737-300",
-                  const.AIRCRAFT_B734: "Boeing 737-400",
-                  const.AIRCRAFT_B735: "Boeing 737-500",
-                  const.AIRCRAFT_B762: "Boeing 767-200",
-                  const.AIRCRAFT_B763: "Boeing 767-300",
-                  const.AIRCRAFT_CRJ2: "Bombardier CRJ200",
-                  const.AIRCRAFT_F70:  "Fokker 70",
-                  const.AIRCRAFT_DC3:  "Lisunov Li-2",
-                  const.AIRCRAFT_T134: "Tupolev Tu-134",
-                  const.AIRCRAFT_T154: "Tupolev Tu-154",
-                  const.AIRCRAFT_YK40: "Yakovlev Yak-40" }
-
-#-----------------------------------------------------------------------------
-
-class Page(gtk.Alignment):
-    """A page in the flight wizard."""
-    def __init__(self, wizard, title, help, completedHelp = None):
-        """Construct the page."""
-        super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
-                                   xscale = 1.0, yscale = 1.0)
-        self.set_padding(padding_top = 4, padding_bottom = 4,
-                         padding_left = 12, padding_right = 12)
-
-        frame = gtk.Frame()
-        self.add(frame)
-
-        style = self.get_style() if pygobject else self.rc_get_style()
-
-        self._vbox = gtk.VBox()
-        self._vbox.set_homogeneous(False)
-        frame.add(self._vbox)
-
-        eventBox = gtk.EventBox()
-        eventBox.modify_bg(0, style.bg[3])
-
-        alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
-        
-        label = gtk.Label(title)
-        label.modify_fg(0, style.fg[3])
-        label.modify_font(pango.FontDescription("bold 24"))
-        alignment.set_padding(padding_top = 4, padding_bottom = 4,
-                              padding_left = 6, padding_right = 0)
-                              
-        alignment.add(label)
-        eventBox.add(alignment)
-        
-        self._vbox.pack_start(eventBox, False, False, 0)
-
-        mainBox = gtk.VBox()        
-
-        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
-                                  xscale = 1.0, yscale = 1.0)        
-        alignment.set_padding(padding_top = 16, padding_bottom = 16,
-                              padding_left = 16, padding_right = 16)
-        alignment.add(mainBox)
-        self._vbox.pack_start(alignment, True, True, 0)
-        
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
-                                  xscale = 0.0, yscale = 0.0)
-        alignment.set_padding(padding_top = 0, padding_bottom = 16,
-                              padding_left = 0, padding_right = 0)
-
-        self._help = help
-        self._completedHelp = completedHelp
-
-        if self._completedHelp is None or \
-           len(help.splitlines())>=len(completedHelp.splitlines()):
-            longerHelp = help
-        else:
-            longerHelp = completedHelp
-        
-        self._helpLabel = gtk.Label(completedHelp)
-        # FIXME: should be a constant in common
-        self._helpLabel.set_justify(gtk.Justification.CENTER if pygobject
-                                    else gtk.JUSTIFY_CENTER)
-        self._helpLabel.set_use_markup(True)
-        alignment.add(self._helpLabel)
-        mainBox.pack_start(alignment, False, False, 0)
-
-        self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                            xscale = 1.0, yscale = 1.0)
-        mainBox.pack_start(self._mainAlignment, True, True, 0)
-                                            
-        buttonAlignment =  gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
-        buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
-                                    padding_left = 16, padding_right = 16)
-
-        self._buttonBox = gtk.HBox()
-        self._buttonBox.set_homogeneous(False)
-        self._defaultButton = None
-        buttonAlignment.add(self._buttonBox)
-
-        self._vbox.pack_start(buttonAlignment, False, False, 0)
-
-        self._wizard = wizard
-
-        self._completed = False
-        self._fromPage = None
-
-    def setMainWidget(self, widget):
-        """Set the given widget as the main one."""
-        self._mainAlignment.add(widget)
-
-    def addButton(self, label, default = False):
-        """Add a button with the given label.
-
-        Return the button object created."""
-        button = gtk.Button(label)
-        self._buttonBox.pack_start(button, False, False, 4)
-        button.set_use_underline(True)
-        if default:
-            button.set_can_default(True)
-            self._defaultButton = button
-        return button
-
-    def initialize(self):
-        """Initialize the page.
-
-        It sets up the primary help, and calls the activate() function."""
-        self._helpLabel.set_markup(self._help)
-        self._helpLabel.set_sensitive(True)
-        self.activate()
-
-    def activate(self):
-        """Called when this page becomes active.
-
-        This default implementation does nothing."""
-        pass
-
-    def complete(self):
-        """Called when the page is completed.
-
-        It greys out/changes the help text and then calls finalize()."""
-        self.finalize()
-        if self._completedHelp is None:
-            self._helpLabel.set_sensitive(False)
-        else:
-            self._helpLabel.set_markup(self._completedHelp)
-        self._completed = True
-
-    def finalize(self):
-        """Called when the page is finalized."""
-        pass
-
-    def grabDefault(self):
-        """If the page has a default button, make it the default one."""
-        if self._defaultButton is not None:
-            self._defaultButton.grab_default()
-
-    def reset(self):
-        """Reset the page if the wizard is reset."""
-        self._completed = False
-        self._fromPage = None
-
-    def goBack(self):
-        """Go to the page we were invoked from."""
-        assert self._fromPage is not None
-        
-        self._wizard.setCurrentPage(self._fromPage, finalize = False)
-    
-#-----------------------------------------------------------------------------
-
-class LoginPage(Page):
-    """The login page."""
-    def __init__(self, wizard):
-        """Construct the login page."""
-        help = "Enter your MAVA pilot's ID and password to\n" \
-        "log in to the MAVA website and download\n" \
-        "your booked flights."
-        super(LoginPage, self).__init__(wizard, "Login", help)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-        
-        table = gtk.Table(2, 3)
-        table.set_row_spacings(4)
-        table.set_col_spacings(32)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Pilot _ID:")
-        label.set_use_underline(True)
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 0, 1)
-
-        self._pilotID = gtk.Entry()
-        self._pilotID.connect("changed", self._setLoginButton)
-        self._pilotID.set_tooltip_text("Enter your MAVA pilot's ID. This "
-                                       "usually starts with a "
-                                       "'P' followed by 3 digits.")
-        table.attach(self._pilotID, 1, 2, 0, 1)
-        label.set_mnemonic_widget(self._pilotID)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("_Password:")
-        label.set_use_underline(True)
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 1, 2)
-
-        self._password = gtk.Entry()
-        self._password.set_visibility(False)
-        self._password.connect("changed", self._setLoginButton)
-        self._password.set_tooltip_text("Enter the password for your pilot's ID")
-        table.attach(self._password, 1, 2, 1, 2)
-        label.set_mnemonic_widget(self._password)
-
-        self._rememberButton = gtk.CheckButton("_Remember password")
-        self._rememberButton.set_use_underline(True)
-        self._rememberButton.set_tooltip_text("If checked, your password will "
-                                              "be stored, so that you should "
-                                              "not have to enter it every time. "
-                                              "Note, however, that the password "
-                                              "is stored as text, and anybody "
-                                              "who can access your files will "
-                                              "be able to read it.")
-        table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
-
-        self._loginButton = self.addButton("_Login", default = True)
-        self._loginButton.set_sensitive(False)
-        self._loginButton.connect("clicked", self._loginClicked)
-        self._loginButton.set_tooltip_text("Click to log in.")        
-
-    def activate(self):
-        """Activate the page."""
-        config = self._wizard.gui.config
-        self._pilotID.set_text(config.pilotID)
-        self._password.set_text(config.password)
-        self._rememberButton.set_active(config.rememberPassword)
-
-    def _setLoginButton(self, entry):
-        """Set the login button's sensitivity.
-
-        The button is sensitive only if both the pilot ID and the password
-        fields contain values."""
-        self._loginButton.set_sensitive(self._pilotID.get_text()!="" and
-                                        self._password.get_text()!="")
-
-    def _loginClicked(self, button):
-        """Called when the login button was clicked."""
-        self._loginButton.set_sensitive(False)
-        gui = self._wizard.gui
-        gui.beginBusy("Logging in...")
-        gui.webHandler.login(self._loginResultCallback,
-                            self._pilotID.get_text(),
-                            self._password.get_text())
-
-    def _loginResultCallback(self, returned, result):
-        """The login result callback, called in the web handler's thread."""
-        gobject.idle_add(self._handleLoginResult, returned, result)
-
-    def _handleLoginResult(self, returned, result):
-        """Handle the login result."""
-        self._wizard.gui.endBusy()
-        self._loginButton.set_sensitive(True)
-        if returned:
-            if result.loggedIn:
-                config = self._wizard.gui.config
-
-                config.pilotID = self._pilotID.get_text()
-
-                rememberPassword = self._rememberButton.get_active()                
-                config.password = self._password.get_text() if rememberPassword  \
-                                  else ""
-
-                config.rememberPassword = rememberPassword
-                
-                config.save()
-                self._wizard._loginResult = result
-                self._wizard.nextPage()
-            else:
-                dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                           buttons = BUTTONSTYPE_OK,
-                                           message_format =
-                                           "Invalid pilot's ID or password.")
-                dialog.format_secondary_markup("Check the ID and try to reenter"
-                                               " the password.")
-                dialog.run()
-                dialog.hide()
-        else:
-            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                       buttons = BUTTONSTYPE_OK,
-                                       message_format = 
-                                       "Failed to connect to the MAVA website.")
-            dialog.format_secondary_markup("Try again in a few minutes.")
-            dialog.run()
-            dialog.hide()
-
-#-----------------------------------------------------------------------------
-
-class FlightSelectionPage(Page):
-    """The page to select the flight."""
-    def __init__(self, wizard):
-        """Construct the flight selection page."""
-        help = "Select the flight you want to perform."
-        completedHelp = "You have selected the flight highlighted below."
-        super(FlightSelectionPage, self).__init__(wizard, "Flight selection",
-                                                  help, completedHelp = completedHelp)
-
-
-        self._listStore = gtk.ListStore(str, str, str, str)
-        self._flightList = gtk.TreeView(self._listStore)
-        column = gtk.TreeViewColumn("Flight no.", gtk.CellRendererText(),
-                                    text = 1)
-        column.set_expand(True)
-        self._flightList.append_column(column)
-        column = gtk.TreeViewColumn("Departure time [UTC]", gtk.CellRendererText(),
-                                    text = 0)
-        column.set_expand(True)
-        self._flightList.append_column(column)
-        column = gtk.TreeViewColumn("From", gtk.CellRendererText(),
-                                    text = 2)
-        column.set_expand(True)
-        self._flightList.append_column(column)
-        column = gtk.TreeViewColumn("To", gtk.CellRendererText(),
-                                    text = 3)
-        column.set_expand(True)
-        self._flightList.append_column(column)
-
-        flightSelection = self._flightList.get_selection()
-        flightSelection.connect("changed", self._selectionChanged)
-
-        scrolledWindow = gtk.ScrolledWindow()
-        scrolledWindow.add(self._flightList)
-        scrolledWindow.set_size_request(400, -1)
-        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC,
-                                  gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC)
-        scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
-                                       else gtk.SHADOW_IN)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
-        alignment.add(scrolledWindow)
-
-        self.setMainWidget(alignment)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.set_sensitive(False)
-        self._button.connect("clicked", self._forwardClicked)
-
-    def activate(self):
-        """Fill the flight list."""
-        self._flightList.set_sensitive(True)
-        self._listStore.clear()
-        for flight in self._wizard.loginResult.flights:
-            self._listStore.append([str(flight.departureTime),
-                                    flight.callsign,
-                                    flight.departureICAO,
-                                    flight.arrivalICAO])
-
-    def finalize(self):
-        """Finalize the page."""
-        self._flightList.set_sensitive(False)
-
-    def _selectionChanged(self, selection):
-        """Called when the selection is changed."""
-        self._button.set_sensitive(selection.count_selected_rows()==1)
-
-    def _forwardClicked(self, button):
-        """Called when the forward button was clicked."""
-        if self._completed:
-            self._wizard.jumpPage(self._nextDistance, finalize = False)
-        else:
-            selection = self._flightList.get_selection()
-            (listStore, iter) = selection.get_selected()
-            path = listStore.get_path(iter)
-            [index] = path.get_indices() if pygobject else path
-
-            flight = self._wizard.loginResult.flights[index]
-            self._wizard._bookedFlight = flight
-            # FIXME: with PyGObject this call causes error messages to
-            # appear on the standard output
-            self._wizard.gui.enableFlightInfo()
-
-            self._updateDepartureGate()
-        
-    def _updateDepartureGate(self):
-        """Update the departure gate for the booked flight."""
-        flight = self._wizard._bookedFlight
-        if flight.departureICAO=="LHBP":
-            self._wizard._getFleet(self._fleetRetrieved)
-        else:
-            self._nextDistance = 2
-            self._wizard.jumpPage(2)
-
-    def _fleetRetrieved(self, fleet):
-        """Called when the fleet has been retrieved."""
-        if fleet is None:
-            self._nextDistance = 2
-            self._wizard.jumpPage(2)
-        else:
-            plane = fleet[self._wizard._bookedFlight.tailNumber]
-            if plane is None:
-                self._nextDistance = 2
-                self._wizard.jumpPage(2)
-            elif plane.gateNumber is not None and \
-                 not fleet.isGateConflicting(plane):
-                self._wizard._departureGate = plane.gateNumber
-                self._nextDistance = 2
-                self._wizard.jumpPage(2)
-            else:
-                self._nextDistance = 1
-                self._wizard.nextPage()
-        
-#-----------------------------------------------------------------------------
-
-class GateSelectionPage(Page):
-    """Page to select a free gate at LHBP.
-
-    This page should be displayed only if we have fleet information!."""
-    def __init__(self, wizard):
-        """Construct the gate selection page."""
-        help = "The airplane's gate position is invalid.\n\n" \
-               "Select the gate from which you\n" \
-               "would like to begin the flight."
-        super(GateSelectionPage, self).__init__(wizard,
-                                                "LHBP gate selection",
-                                                help)
-
-        self._listStore = gtk.ListStore(str)
-        self._gateList = gtk.TreeView(self._listStore)
-        column = gtk.TreeViewColumn(None, gtk.CellRendererText(),
-                                    text = 0)
-        column.set_expand(True)
-        self._gateList.append_column(column)
-        self._gateList.set_headers_visible(False)
-
-        gateSelection = self._gateList.get_selection()
-        gateSelection.connect("changed", self._selectionChanged)
-
-        scrolledWindow = gtk.ScrolledWindow()
-        scrolledWindow.add(self._gateList)
-        scrolledWindow.set_size_request(50, -1)
-        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC,
-                                  gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC)
-        scrolledWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
-                                       else gtk.SHADOW_IN)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
-        alignment.add(scrolledWindow)
-
-        self.setMainWidget(alignment)        
-
-        button = self.addButton(gtk.STOCK_GO_BACK)
-        button.set_use_stock(True)
-        button.connect("clicked", self._backClicked)
-        
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.set_sensitive(False)
-        self._button.connect("clicked", self._forwardClicked)
-
-    def activate(self):
-        """Fill the gate list."""
-        self._listStore.clear()
-        self._gateList.set_sensitive(True)
-        occupiedGateNumbers = self._wizard._fleet.getOccupiedGateNumbers()
-        for gateNumber in const.lhbpGateNumbers:
-            if gateNumber not in occupiedGateNumbers:
-                self._listStore.append([gateNumber])
-
-    def finalize(self):
-        """Finalize the page."""
-        self._gateList.set_sensitive(False)
-
-    def _selectionChanged(self, selection):
-        """Called when the selection is changed."""
-        self._button.set_sensitive(selection.count_selected_rows()==1)
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-
-    def _forwardClicked(self, button):
-        """Called when the forward button is clicked."""
-        if not self._completed:
-            selection = self._gateList.get_selection()
-            (listStore, iter) = selection.get_selected()
-            (gateNumber,) = listStore.get(iter, 0)
-
-            self._wizard._departureGate = gateNumber
-
-            #self._wizard._updatePlane(self._planeUpdated,
-            #                          self._wizard._bookedFlight.tailNumber,
-            #                          const.PLANE_HOME,
-            #                          gateNumber)
-        
-        self._wizard.nextPage()
-
-    def _planeUpdated(self, success):
-        """Callback for the plane updating call."""
-        if success is None or success:
-            self._wizard.nextPage()
-        else:
-            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                       buttons = BUTTONSTYPE_OK,
-                                       message_format = "Gate conflict detected again")
-            dialog.format_secondary_markup("Try to select a different gate.")
-            dialog.run()
-            dialog.hide()
-
-            self._wizard._getFleet(self._fleetRetrieved)
-
-    def _fleetRetrieved(self, fleet):
-        """Called when the fleet has been retrieved."""
-        if fleet is None:
-            self._wizard.nextPage()
-        else:
-            self.activate()
-            
-#-----------------------------------------------------------------------------
-
-class ConnectPage(Page):
-    """Page which displays the departure airport and gate (if at LHBP)."""
-    def __init__(self, wizard):
-        """Construct the connect page."""
-        help = "Load the aircraft below into the simulator and park it\n" \
-               "at the given airport, at the gate below, if present.\n\n" \
-               "Then press the Connect button to connect to the simulator."
-        completedHelp = "The basic data of your flight can be read below."
-        super(ConnectPage, self).__init__(wizard,
-                                          "Connect to the simulator",
-                                          help, completedHelp = completedHelp)
-        
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        table = gtk.Table(5, 2)
-        table.set_row_spacings(4)
-        table.set_col_spacings(16)
-        table.set_homogeneous(True)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Flight number:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 0, 1)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._flightNumber = gtk.Label()
-        self._flightNumber.set_width_chars(7)
-        self._flightNumber.set_alignment(0.0, 0.5)
-        labelAlignment.add(self._flightNumber)
-        table.attach(labelAlignment, 1, 2, 0, 1)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Aircraft:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 1, 2)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._aircraft = gtk.Label()
-        self._aircraft.set_width_chars(25)
-        self._aircraft.set_alignment(0.0, 0.5)
-        labelAlignment.add(self._aircraft)
-        table.attach(labelAlignment, 1, 2, 1, 2)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Tail number:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 2, 3)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._tailNumber = gtk.Label()
-        self._tailNumber.set_width_chars(10)
-        self._tailNumber.set_alignment(0.0, 0.5)
-        labelAlignment.add(self._tailNumber)
-        table.attach(labelAlignment, 1, 2, 2, 3)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Airport:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 3, 4)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._departureICAO = gtk.Label()
-        self._departureICAO.set_width_chars(6)
-        self._departureICAO.set_alignment(0.0, 0.5)
-        labelAlignment.add(self._departureICAO)
-        table.attach(labelAlignment, 1, 2, 3, 4)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Gate:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 4, 5)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._departureGate = gtk.Label()
-        self._departureGate.set_width_chars(5)
-        self._departureGate.set_alignment(0.0, 0.5)
-        labelAlignment.add(self._departureGate)
-        table.attach(labelAlignment, 1, 2, 4, 5)
-
-        button = self.addButton(gtk.STOCK_GO_BACK)
-        button.set_use_stock(True)
-        button.connect("clicked", self._backClicked)
-
-        self._button = self.addButton("_Connect", default = True)
-        self._button.set_use_underline(True)
-        self._clickedID = self._button.connect("clicked", self._connectClicked)
-
-    def activate(self):
-        """Setup the departure information."""
-        self._button.set_label("_Connect")
-        self._button.set_use_underline(True)
-        self._button.disconnect(self._clickedID)
-        self._clickedID = self._button.connect("clicked", self._connectClicked)
-
-        bookedFlight = self._wizard._bookedFlight
-
-        self._flightNumber.set_markup("<b>" + bookedFlight.callsign + "</b>")
-
-        aircraftType = acftTypeNames[bookedFlight.aircraftType]
-        self._aircraft.set_markup("<b>" + aircraftType + "</b>")
-        
-        self._tailNumber.set_markup("<b>" + bookedFlight.tailNumber + "</b>")
-
-        icao = bookedFlight.departureICAO
-        self._departureICAO.set_markup("<b>" + icao + "</b>")
-        gate = self._wizard._departureGate
-        if gate!="-":
-            gate = "<b>" + gate + "</b>"
-        self._departureGate.set_markup(gate)
-
-    def finalize(self):
-        """Finalize the page."""
-        self._button.set_label(gtk.STOCK_GO_FORWARD)
-        self._button.set_use_stock(True)
-        self._button.disconnect(self._clickedID)
-        self._clickedID = self._button.connect("clicked", self._forwardClicked)
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-
-    def _connectClicked(self, button):
-        """Called when the Connect button is pressed."""
-        self._wizard._connectSimulator()
-
-    def _forwardClicked(self, button):
-        """Called when the Forward button is pressed."""
-        self._wizard.nextPage()
-
-#-----------------------------------------------------------------------------
-
-class PayloadPage(Page):
-    """Page to allow setting up the payload."""
-    def __init__(self, wizard):
-        """Construct the page."""
-        help = "The briefing contains the weights below.\n" \
-               "Setup the cargo weight here and the payload weight in the simulator.\n\n" \
-               "You can also check here what the simulator reports as ZFW."
-        completedHelp = "You can see the weights in the briefing\n" \
-                        "and the cargo weight you have selected below.\n\n" \
-                        "You can also query the ZFW reported by the simulator."
-        super(PayloadPage, self).__init__(wizard, "Payload", help,
-                                          completedHelp = completedHelp)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        table = gtk.Table(7, 3)
-        table.set_row_spacings(4)
-        table.set_col_spacings(16)
-        table.set_homogeneous(False)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        label = gtk.Label("Crew:")
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 0, 1)
-
-        self._numCrew = gtk.Label()
-        self._numCrew.set_width_chars(6)
-        self._numCrew.set_alignment(1.0, 0.5)
-        table.attach(self._numCrew, 1, 2, 0, 1)
-        
-        label = gtk.Label("Passengers:")
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 1, 2)
-
-        self._numPassengers = gtk.Label()
-        self._numPassengers.set_width_chars(6)
-        self._numPassengers.set_alignment(1.0, 0.5)
-        table.attach(self._numPassengers, 1, 2, 1, 2)
-        
-        label = gtk.Label("Baggage:")
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 2, 3)
-
-        self._bagWeight = gtk.Label()
-        self._bagWeight.set_width_chars(6)
-        self._bagWeight.set_alignment(1.0, 0.5)
-        table.attach(self._bagWeight, 1, 2, 2, 3)
-
-        table.attach(gtk.Label("kg"), 2, 3, 2, 3)
-        
-        label = gtk.Label("_Cargo:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 3, 4)
-
-        self._cargoWeight = IntegerEntry(defaultValue = 0)
-        self._cargoWeight.set_width_chars(6)
-        self._cargoWeight.connect("integer-changed", self._cargoWeightChanged)
-        self._cargoWeight.set_tooltip_text("The weight of the cargo for your flight.")
-        table.attach(self._cargoWeight, 1, 2, 3, 4)
-        label.set_mnemonic_widget(self._cargoWeight)
-
-        table.attach(gtk.Label("kg"), 2, 3, 3, 4)
-        
-        label = gtk.Label("Mail:")
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 4, 5)
-
-        self._mailWeight = gtk.Label()
-        self._mailWeight.set_width_chars(6)
-        self._mailWeight.set_alignment(1.0, 0.5)
-        table.attach(self._mailWeight, 1, 2, 4, 5)
-
-        table.attach(gtk.Label("kg"), 2, 3, 4, 5)
-        
-        label = gtk.Label("<b>Calculated ZFW:</b>")
-        label.set_alignment(0.0, 0.5)
-        label.set_use_markup(True)
-        table.attach(label, 0, 1, 5, 6)
-
-        self._calculatedZFW = gtk.Label()
-        self._calculatedZFW.set_width_chars(6)
-        self._calculatedZFW.set_alignment(1.0, 0.5)
-        table.attach(self._calculatedZFW, 1, 2, 5, 6)
-
-        table.attach(gtk.Label("kg"), 2, 3, 5, 6)
-
-        self._zfwButton = gtk.Button("_ZFW from FS:")
-        self._zfwButton.set_use_underline(True)
-        self._zfwButton.connect("clicked", self._zfwRequested)
-        table.attach(self._zfwButton, 0, 1, 6, 7)
-
-        self._simulatorZFW = gtk.Label("-")
-        self._simulatorZFW.set_width_chars(6)
-        self._simulatorZFW.set_alignment(1.0, 0.5)
-        table.attach(self._simulatorZFW, 1, 2, 6, 7)
-        self._simulatorZFWValue = None
-
-        table.attach(gtk.Label("kg"), 2, 3, 6, 7)
-
-        self._backButton = self.addButton(gtk.STOCK_GO_BACK)
-        self._backButton.set_use_stock(True)
-        self._backButton.connect("clicked", self._backClicked)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.connect("clicked", self._forwardClicked)
-
-    @property
-    def cargoWeight(self):
-        """Get the cargo weight entered."""
-        return self._cargoWeight.get_int()
-
-    def activate(self):
-        """Setup the information."""
-        bookedFlight = self._wizard._bookedFlight
-        self._numCrew.set_text(str(bookedFlight.numCrew))
-        self._numPassengers.set_text(str(bookedFlight.numPassengers))
-        self._bagWeight.set_text(str(bookedFlight.bagWeight))
-        self._cargoWeight.set_int(bookedFlight.cargoWeight)
-        self._cargoWeight.set_sensitive(True)
-        self._mailWeight.set_text(str(bookedFlight.mailWeight))
-        self._simulatorZFW.set_text("-")
-        self._simulatorZFWValue = None
-        self._zfwButton.set_sensitive(True)
-        self._updateCalculatedZFW()
-
-    def finalize(self):
-        """Finalize the payload page."""
-        self._cargoWeight.set_sensitive(False)
-
-    def calculateZFW(self):
-        """Calculate the ZFW value."""
-        zfw = self._wizard.gui._flight.aircraft.dow
-        bookedFlight = self._wizard._bookedFlight
-        zfw += (bookedFlight.numCrew + bookedFlight.numPassengers) * 82
-        zfw += bookedFlight.bagWeight
-        zfw += self._cargoWeight.get_int()
-        zfw += bookedFlight.mailWeight
-        return zfw
-        
-    def _updateCalculatedZFW(self):
-        """Update the calculated ZFW"""
-        zfw = self.calculateZFW()
-
-        markupBegin = "<b>"
-        markupEnd = "</b>"
-        if self._simulatorZFWValue is not None and \
-           PayloadChecker.isZFWFaulty(self._simulatorZFWValue, zfw):
-            markupBegin += '<span foreground="red">'
-            markupEnd = "</span>" + markupEnd
-        self._calculatedZFW.set_markup(markupBegin + str(zfw) + markupEnd)
-
-    def _cargoWeightChanged(self, entry, weight):
-        """Called when the cargo weight has changed."""
-        self._updateCalculatedZFW()
-            
-    def _zfwRequested(self, button):
-        """Called when the ZFW is requested from the simulator."""
-        self._zfwButton.set_sensitive(False)
-        self._backButton.set_sensitive(False)
-        self._button.set_sensitive(False)
-        gui = self._wizard.gui
-        gui.beginBusy("Querying ZFW...")
-        gui.simulator.requestZFW(self._handleZFW)
-
-    def _handleZFW(self, zfw):
-        """Called when the ZFW value is retrieved."""
-        gobject.idle_add(self._processZFW, zfw)
-
-    def _processZFW(self, zfw):
-        """Process the given ZFW value received from the simulator."""
-        self._wizard.gui.endBusy()
-        self._zfwButton.set_sensitive(True)
-        self._backButton.set_sensitive(True)
-        self._button.set_sensitive(True)
-        self._simulatorZFWValue = zfw
-        self._simulatorZFW.set_text("%.0f" % (zfw,))
-        self._updateCalculatedZFW()
-
-    def _forwardClicked(self, button):
-        """Called when the forward button is clicked."""
-        self._wizard.nextPage()
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-        
-#-----------------------------------------------------------------------------
-
-class TimePage(Page):
-    """Page displaying the departure and arrival times and allows querying the
-    current time from the flight simulator."""
-    def __init__(self, wizard):
-        help = "The departure and arrival times are displayed below in UTC.\n\n" \
-               "You can also query the current UTC time from the simulator.\n" \
-               "Ensure that you have enough time to properly prepare for the flight."
-        completedHelp = "The departure and arrival times are displayed below in UTC.\n\n" \
-                        "You can also query the current UTC time from the simulator.\n"
-        super(TimePage, self).__init__(wizard, "Time", help,
-                                       completedHelp = completedHelp)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        table = gtk.Table(3, 2)
-        table.set_row_spacings(4)
-        table.set_col_spacings(16)
-        table.set_homogeneous(False)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        label = gtk.Label("Departure:")
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 0, 1)
-
-        self._departure = gtk.Label()
-        self._departure.set_alignment(0.0, 0.5)
-        table.attach(self._departure, 1, 2, 0, 1)
-        
-        label = gtk.Label("Arrival:")
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 1, 2)
-
-        self._arrival = gtk.Label()
-        self._arrival.set_alignment(0.0, 0.5)
-        table.attach(self._arrival, 1, 2, 1, 2)
-
-        self._timeButton = gtk.Button("_Time from FS:")
-        self._timeButton.set_use_underline(True)
-        self._timeButton.connect("clicked", self._timeRequested)
-        table.attach(self._timeButton, 0, 1, 2, 3)
-
-        self._simulatorTime = gtk.Label("-")
-        self._simulatorTime.set_alignment(0.0, 0.5)
-        table.attach(self._simulatorTime, 1, 2, 2, 3)
-
-        self._backButton = self.addButton(gtk.STOCK_GO_BACK)
-        self._backButton.set_use_stock(True)
-        self._backButton.connect("clicked", self._backClicked)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.connect("clicked", self._forwardClicked)
-
-    def activate(self):
-        """Activate the page."""
-        self._timeButton.set_sensitive(True)
-        bookedFlight = self._wizard._bookedFlight
-        self._departure.set_text(str(bookedFlight.departureTime.time()))
-        self._arrival.set_text(str(bookedFlight.arrivalTime.time()))
-        self._simulatorTime.set_text("-")
-
-    def _timeRequested(self, button):
-        """Request the time from the simulator."""
-        self._timeButton.set_sensitive(False)
-        self._backButton.set_sensitive(False)
-        self._button.set_sensitive(False)
-        self._wizard.gui.beginBusy("Querying time...")
-        self._wizard.gui.simulator.requestTime(self._handleTime)
-
-    def _handleTime(self, timestamp):
-        """Handle the result of a time retrieval."""
-        gobject.idle_add(self._processTime, timestamp)
-
-    def _processTime(self, timestamp):
-        """Process the given time."""
-        self._wizard.gui.endBusy()
-        self._timeButton.set_sensitive(True)
-        self._backButton.set_sensitive(True)
-        self._button.set_sensitive(True)
-        tm = time.gmtime(timestamp)
-        t = datetime.time(tm.tm_hour, tm.tm_min, tm.tm_sec)
-        self._simulatorTime.set_text(str(t))
-
-        ts = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec
-        dt = self._wizard._bookedFlight.departureTime.time()
-        dts = dt.hour * 3600 + dt.minute * 60 + dt.second
-        diff = dts-ts
-
-        markupBegin = ""
-        markupEnd = ""
-        if diff < 0:
-            markupBegin = '<b><span foreground="red">'
-            markupEnd = '</span></b>'
-        elif diff < 3*60 or diff > 30*60:
-            markupBegin = '<b><span foreground="orange">'
-            markupEnd = '</span></b>'
-
-        self._departure.set_markup(markupBegin + str(dt) + markupEnd)
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-        
-    def _forwardClicked(self, button):
-        """Called when the forward button is clicked."""
-        self._wizard.nextPage()
-        
-#-----------------------------------------------------------------------------
-
-class RoutePage(Page):
-    """The page containing the route and the flight level."""
-    def __init__(self, wizard):
-        help = "Set your cruise flight level below, and\n" \
-               "if necessary, edit the flight plan."
-        completedHelp = "If necessary, you can modify the cruise level and\n" \
-                        "the flight plan below during flight.\n" \
-                        "If so, please, add a comment on why " \
-                        "the modification became necessary."
-        super(RoutePage, self).__init__(wizard, "Route", help,
-                                        completedHelp = completedHelp)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        mainBox = gtk.VBox()
-        alignment.add(mainBox)
-        self.setMainWidget(alignment)
-
-        levelBox = gtk.HBox()
-
-        label = gtk.Label("_Cruise level")
-        label.set_use_underline(True)
-        levelBox.pack_start(label, True, True, 0)
-
-        self._cruiseLevel = gtk.SpinButton()
-        self._cruiseLevel.set_increments(step = 10, page = 100)
-        self._cruiseLevel.set_range(min = 50, max = 500)
-        self._cruiseLevel.set_tooltip_text("The cruise flight level.")
-        self._cruiseLevel.set_numeric(True)
-        self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
-        label.set_mnemonic_widget(self._cruiseLevel)
-        self._filedCruiseLevel = 240
-
-        levelBox.pack_start(self._cruiseLevel, False, False, 8)
-
-        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-        alignment.add(levelBox)
-
-        mainBox.pack_start(alignment, False, False, 0)
-
-
-        routeBox = gtk.VBox()
-
-        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-        label = gtk.Label("_Route")
-        label.set_use_underline(True)
-        alignment.add(label)
-        routeBox.pack_start(alignment, True, True, 0)
-
-        routeWindow = gtk.ScrolledWindow()
-        routeWindow.set_size_request(400, 80)
-        routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
-                                    else gtk.SHADOW_IN)
-        routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                               else gtk.POLICY_AUTOMATIC,
-                               gtk.PolicyType.AUTOMATIC if pygobject
-                               else gtk.POLICY_AUTOMATIC)
-
-        self._route = gtk.TextView()
-        self._route.set_tooltip_text("The planned flight route.")
-        self._route.get_buffer().connect("changed", self._routeChanged)
-        routeWindow.add(self._route)
-
-        label.set_mnemonic_widget(self._route)
-        routeBox.pack_start(routeWindow, True, True, 0)        
-
-        mainBox.pack_start(routeBox, True, True, 8)
-
-        self._backButton = self.addButton(gtk.STOCK_GO_BACK)
-        self._backButton.set_use_stock(True)
-        self._backButton.connect("clicked", self._backClicked)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.connect("clicked", self._forwardClicked)
-
-    @property
-    def filedCruiseLevel(self):
-        """Get the filed cruise level."""
-        return self._filedCruiseLevel
-
-    @property
-    def cruiseLevel(self):
-        """Get the cruise level."""
-        return self._cruiseLevel.get_value_as_int()
-
-    @property
-    def route(self):
-        """Get the route."""
-        return self._getRoute()
-
-    def activate(self):
-        """Setup the route from the booked flight."""
-        self._cruiseLevel.set_value(240)
-        self._filedCruiseLevel = 240
-        self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
-        self._updateForwardButton()
-
-    def _getRoute(self):
-        """Get the text of the route."""
-        buffer = self._route.get_buffer()
-        return buffer.get_text(buffer.get_start_iter(),
-                               buffer.get_end_iter(), True)
-
-    def _updateForwardButton(self):
-        """Update the sensitivity of the forward button."""
-        self._button.set_sensitive(self._cruiseLevel.get_value_as_int()>=50 and \
-                                   self._getRoute()!="")
-                                   
-    def _cruiseLevelChanged(self, spinButton):
-        """Called when the cruise level has changed."""
-        self._updateForwardButton()
-
-    def _routeChanged(self, textBuffer):
-        """Called when the route has changed."""
-        self._updateForwardButton()
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-        
-    def _forwardClicked(self, button):
-        """Called when the Forward button is clicked."""
-        if self._completed:
-            self._wizard.nextPage()
-        else:
-            bookedFlight = self._wizard._bookedFlight
-            self._filedCruiseLevel = self.cruiseLevel
-            self._wizard.gui.beginBusy("Downloading NOTAMs...")
-            self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
-                                                  bookedFlight.departureICAO,
-                                                  bookedFlight.arrivalICAO)
-
-    def _notamsCallback(self, returned, result):
-        """Callback for the NOTAMs."""
-        gobject.idle_add(self._handleNOTAMs, returned, result)
-
-    def _handleNOTAMs(self, returned, result):
-        """Handle the NOTAMs."""
-        if returned:
-            self._wizard._departureNOTAMs = result.departureNOTAMs
-            self._wizard._arrivalNOTAMs = result.arrivalNOTAMs
-        else:
-            self._wizard._departureNOTAMs = None
-            self._wizard._arrivalNOTAMs = None
-
-        bookedFlight = self._wizard._bookedFlight
-        self._wizard.gui.beginBusy("Downloading METARs...")
-        self._wizard.gui.webHandler.getMETARs(self._metarsCallback,
-                                              [bookedFlight.departureICAO,
-                                               bookedFlight.arrivalICAO])
-
-    def _metarsCallback(self, returned, result):
-        """Callback for the METARs."""
-        gobject.idle_add(self._handleMETARs, returned, result)
-
-    def _handleMETARs(self, returned, result):
-        """Handle the METARs."""
-        self._wizard._departureMETAR = None
-        self._wizard._arrivalMETAR = None
-        bookedFlight = self._wizard._bookedFlight
-        if returned:
-            if bookedFlight.departureICAO in result.metars:
-                self._wizard._departureMETAR = result.metars[bookedFlight.departureICAO]
-            if bookedFlight.arrivalICAO in result.metars:
-                self._wizard._arrivalMETAR = result.metars[bookedFlight.arrivalICAO]
-
-        self._wizard.gui.endBusy()
-        self._backButton.set_sensitive(True)
-        self._button.set_sensitive(True)
-        self._wizard.nextPage()
-
-#-----------------------------------------------------------------------------
-
-class BriefingPage(Page):
-    """Page for the briefing."""
-    def __init__(self, wizard, departure):
-        """Construct the briefing page."""
-        self._departure = departure
-        
-        title = "Briefing (%d/2): %s" % (1 if departure else 2,
-                                        "departure" if departure
-                                         else "arrival")
-                                                                
-        help = "Read carefully the NOTAMs and METAR below.\n\n" \
-               "You can edit the METAR if your simulator or network\n" \
-               "provides different weather."
-        completedHelp = "If your simulator or network provides a different\n" \
-                        "weather, you can edit the METAR below."
-        super(BriefingPage, self).__init__(wizard, title, help,
-                                           completedHelp = completedHelp)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 1.0, yscale = 1.0)
-
-        mainBox = gtk.VBox()
-        alignment.add(mainBox)
-        self.setMainWidget(alignment)
-
-        self._notamsFrame = gtk.Frame()
-        self._notamsFrame.set_label("LHBP NOTAMs")
-        scrolledWindow = gtk.ScrolledWindow()
-        scrolledWindow.set_size_request(-1, 128)
-        # FIXME: these constants should be in common
-        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC,
-                                  gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC)
-        self._notams = gtk.TextView()
-        self._notams.set_editable(False)
-        self._notams.set_accepts_tab(False)
-        self._notams.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
-        scrolledWindow.add(self._notams)
-        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
-                                  xscale = 1.0, yscale = 1.0)
-        alignment.set_padding(padding_top = 4, padding_bottom = 0,
-                              padding_left = 0, padding_right = 0)
-        alignment.add(scrolledWindow)
-        self._notamsFrame.add(alignment)
-        mainBox.pack_start(self._notamsFrame, True, True, 4)
-        
-        self._metarFrame = gtk.Frame()
-        self._metarFrame.set_label("LHBP METAR")
-        scrolledWindow = gtk.ScrolledWindow()
-        scrolledWindow.set_size_request(-1, 32)
-        scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC,
-                                  gtk.PolicyType.AUTOMATIC if pygobject
-                                  else gtk.POLICY_AUTOMATIC)
-        self._metar = gtk.TextView()
-        self._metar.set_accepts_tab(False)
-        self._metar.set_wrap_mode(gtk.WrapMode.WORD if pygobject else gtk.WRAP_WORD)
-        scrolledWindow.add(self._metar)
-        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
-                                  xscale = 1.0, yscale = 1.0)
-        alignment.set_padding(padding_top = 4, padding_bottom = 0,
-                              padding_left = 0, padding_right = 0)
-        alignment.add(scrolledWindow)
-        self._metarFrame.add(alignment)
-        mainBox.pack_start(self._metarFrame, True, True, 4)
-
-        button = self.addButton(gtk.STOCK_GO_BACK)
-        button.set_use_stock(True)
-        button.connect("clicked", self._backClicked)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.connect("clicked", self._forwardClicked)
-
-    @property
-    def metar(self):
-        """Get the METAR on the page."""
-        buffer = self._metar.get_buffer()
-        return buffer.get_text(buffer.get_start_iter(),
-                               buffer.get_end_iter(), True)        
-
-    def activate(self):
-        """Activate the page."""
-        if not self._departure:
-            self._button.set_label("I have read the briefing and am ready to fly!")
-            self._button.set_use_stock(False)
-
-        bookedFlight = self._wizard._bookedFlight
-
-        icao = bookedFlight.departureICAO if self._departure \
-               else bookedFlight.arrivalICAO
-        notams = self._wizard._departureNOTAMs if self._departure \
-                 else self._wizard._arrivalNOTAMs
-        metar = self._wizard._departureMETAR if self._departure \
-                 else self._wizard._arrivalMETAR
-
-        self._notamsFrame.set_label(icao + " NOTAMs")
-        buffer = self._notams.get_buffer()
-        if notams is None:
-            buffer.set_text("Could not download NOTAMs")
-        elif not notams:
-            buffer.set_text("Could not download NOTAM for this airport")
-        else:
-            s = ""
-            for notam in notams:
-                s += str(notam.begin)
-                if notam.end is not None:
-                    s += " - " + str(notam.end)
-                elif notam.permanent:
-                    s += " - PERMANENT"
-                s += "\n"
-                if notam.repeatCycle:
-                    s += "Repeat cycle: " + notam.repeatCycle + "\n"
-                s += notam.notice + "\n"
-                s += "-------------------- * --------------------\n"
-            buffer.set_text(s)
-
-        self._metarFrame.set_label(icao + " METAR")
-        buffer = self._metar.get_buffer()
-        if metar is None:
-            buffer.set_text("Could not download METAR")
-        else:
-            buffer.set_text(metar)
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-        
-    def _forwardClicked(self, button):
-        """Called when the forward button is clicked."""
-        if not self._departure:
-            if not self._completed:
-                self._wizard.gui.startMonitoring()
-                self._button.set_use_stock(True)
-                self._button.set_label(gtk.STOCK_GO_FORWARD)
-                self.complete()
-
-        self._wizard.nextPage()
-
-#-----------------------------------------------------------------------------
-
-class TakeoffPage(Page):
-    """Page for entering the takeoff data."""
-    def __init__(self, wizard):
-        """Construct the takeoff page."""
-        help = "Enter the runway and SID used, as well as the speeds."
-        completedHelp = "The runway, SID and takeoff speeds logged can be seen below."
-
-        super(TakeoffPage, self).__init__(wizard, "Takeoff", help,
-                                          completedHelp = completedHelp)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        table = gtk.Table(5, 4)
-        table.set_row_spacings(4)
-        table.set_col_spacings(16)
-        table.set_homogeneous(False)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        label = gtk.Label("Run_way:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 0, 1)
-
-        self._runway = gtk.Entry()
-        self._runway.set_width_chars(10)
-        self._runway.set_tooltip_text("The runway the takeoff is performed from.")
-        table.attach(self._runway, 1, 3, 0, 1)
-        label.set_mnemonic_widget(self._runway)
-        
-        label = gtk.Label("_SID:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 1, 2)
-
-        self._sid = gtk.Entry()
-        self._sid.set_width_chars(10)
-        self._sid.set_tooltip_text("The name of the Standard Instrument Deparature procedure followed.")
-        table.attach(self._sid, 1, 3, 1, 2)
-        label.set_mnemonic_widget(self._sid)
-        
-        label = gtk.Label("V<sub>_1</sub>:")
-        label.set_use_markup(True)
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 2, 3)
-
-        self._v1 = IntegerEntry()
-        self._v1.set_width_chars(4)
-        self._v1.set_tooltip_markup("The takeoff decision speed in knots.")
-        table.attach(self._v1, 2, 3, 2, 3)
-        label.set_mnemonic_widget(self._v1)
-        
-        table.attach(gtk.Label("knots"), 3, 4, 2, 3)
-        
-        label = gtk.Label("V<sub>_R</sub>:")
-        label.set_use_markup(True)
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 3, 4)
-
-        self._vr = IntegerEntry()
-        self._vr.set_width_chars(4)
-        self._vr.set_tooltip_markup("The takeoff rotation speed in knots.")
-        table.attach(self._vr, 2, 3, 3, 4)
-        label.set_mnemonic_widget(self._vr)
-        
-        table.attach(gtk.Label("knots"), 3, 4, 3, 4)
-        
-        label = gtk.Label("V<sub>_2</sub>:")
-        label.set_use_markup(True)
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 0, 1, 4, 5)
-
-        self._v2 = IntegerEntry()
-        self._v2.set_width_chars(4)
-        self._v2.set_tooltip_markup("The takeoff safety speed in knots.")
-        table.attach(self._v2, 2, 3, 4, 5)
-        label.set_mnemonic_widget(self._v2)
-        
-        table.attach(gtk.Label("knots"), 3, 4, 4, 5)
-        
-        button = self.addButton(gtk.STOCK_GO_BACK)
-        button.set_use_stock(True)
-        button.connect("clicked", self._backClicked)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.connect("clicked", self._forwardClicked)
-
-    @property
-    def runway(self):
-        """Get the runway."""
-        return self._runway.get_text()
-
-    @property
-    def sid(self):
-        """Get the SID."""
-        return self._sid.get_text()
-
-    @property
-    def v1(self):
-        """Get the v1 speed."""
-        return self._v1.get_int()
-
-    @property
-    def vr(self):
-        """Get the vr speed."""
-        return self._vr.get_int()
-
-    @property
-    def v2(self):
-        """Get the v2 speed."""
-        return self._v2.get_int()
-
-    def activate(self):
-        """Activate the page."""
-        self._runway.set_text("")
-        self._runway.set_sensitive(True)
-        self._sid.set_text("")
-        self._sid.set_sensitive(True)
-        self._v1.set_int(None)
-        self._v1.set_sensitive(True)
-        self._vr.set_int(None)
-        self._vr.set_sensitive(True)
-        self._v2.set_int(None)
-        self._v2.set_sensitive(True)
-        self._button.set_sensitive(False)
-        
-    def freezeValues(self):
-        """Freeze the values on the page, and enable the forward button."""
-        self._runway.set_sensitive(False)
-        self._sid.set_sensitive(False)
-        self._v1.set_sensitive(False)
-        self._vr.set_sensitive(False)
-        self._v2.set_sensitive(False)
-        self._button.set_sensitive(True)
-        
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-        
-    def _forwardClicked(self, button):
-        """Called when the forward button is clicked."""
-        self._wizard.nextPage()
-
-#-----------------------------------------------------------------------------
-
-class LandingPage(Page):
-    """Page for entering landing data."""
-    def __init__(self, wizard):
-        """Construct the landing page."""
-        help = "Enter the STAR and/or transition, runway,\n" \
-               "approach type and V<sub>Ref</sub> used."
-        completedHelp = "The STAR and/or transition, runway, approach\n" \
-                        "type and V<sub>Ref</sub> logged can be seen below."
-
-        super(LandingPage, self).__init__(wizard, "Landing", help,
-                                          completedHelp = completedHelp)
-
-        self._flightEnded = False
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        table = gtk.Table(5, 5)
-        table.set_row_spacings(4)
-        table.set_col_spacings(16)
-        table.set_homogeneous(False)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        self._starButton = gtk.CheckButton()
-        self._starButton.connect("clicked", self._starButtonClicked)
-        table.attach(self._starButton, 0, 1, 0, 1)
-
-        label = gtk.Label("_STAR:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 1, 2, 0, 1)
-
-        self._star = gtk.Entry()
-        self._star.set_width_chars(10)
-        self._star.set_tooltip_text("The name of Standard Terminal Arrival Route followed.")
-        self._star.connect("changed", self._updateForwardButton)
-        self._star.set_sensitive(False)
-        table.attach(self._star, 2, 4, 0, 1)
-        label.set_mnemonic_widget(self._starButton)
-
-        self._transitionButton = gtk.CheckButton()
-        self._transitionButton.connect("clicked", self._transitionButtonClicked)
-        table.attach(self._transitionButton, 0, 1, 1, 2)
-
-        label = gtk.Label("_Transition:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 1, 2, 1, 2)
-
-        self._transition = gtk.Entry()
-        self._transition.set_width_chars(10)
-        self._transition.set_tooltip_text("The name of transition executed or VECTORS if vectored by ATC.")
-        self._transition.connect("changed", self._updateForwardButton)
-        self._transition.set_sensitive(False)
-        table.attach(self._transition, 2, 4, 1, 2)
-        label.set_mnemonic_widget(self._transitionButton)
-
-        label = gtk.Label("Run_way:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 1, 2, 2, 3)
-
-        self._runway = gtk.Entry()
-        self._runway.set_width_chars(10)
-        self._runway.set_tooltip_text("The runway the landing is performed on.")
-        self._runway.connect("changed", self._updateForwardButton)
-        table.attach(self._runway, 2, 4, 2, 3)
-        label.set_mnemonic_widget(self._runway)
-
-        label = gtk.Label("_Approach type:")
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 1, 2, 3, 4)
-
-        self._approachType = gtk.Entry()
-        self._approachType.set_width_chars(10)
-        self._approachType.set_tooltip_text("The type of the approach, e.g. ILS or VISUAL.")
-        self._approachType.connect("changed", self._updateForwardButton)
-        table.attach(self._approachType, 2, 4, 3, 4)
-        label.set_mnemonic_widget(self._approachType)
-
-        label = gtk.Label("V<sub>_Ref</sub>:")
-        label.set_use_markup(True)
-        label.set_use_underline(True)
-        label.set_alignment(0.0, 0.5)
-        table.attach(label, 1, 2, 5, 6)
-
-        self._vref = IntegerEntry()
-        self._vref.set_width_chars(5)
-        self._vref.set_tooltip_markup("The approach reference speed in knots.")
-        self._vref.connect("integer-changed", self._vrefChanged)
-        table.attach(self._vref, 3, 4, 5, 6)
-        label.set_mnemonic_widget(self._vref)
-        
-        table.attach(gtk.Label("knots"), 4, 5, 5, 6)
-        
-        button = self.addButton(gtk.STOCK_GO_BACK)
-        button.set_use_stock(True)
-        button.connect("clicked", self._backClicked)
-
-        self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
-        self._button.set_use_stock(True)
-        self._button.connect("clicked", self._forwardClicked)
-
-        # These are needed for correct size calculations
-        self._starButton.set_active(True)
-        self._transitionButton.set_active(True)
-
-    @property
-    def star(self):
-        """Get the STAR or None if none entered."""
-        return self._star.get_text() if self._starButton.get_active() else None
-
-    @property
-    def transition(self):
-        """Get the transition or None if none entered."""
-        return self._transition.get_text() \
-               if self._transitionButton.get_active() else None
-
-    @property
-    def approachType(self):
-        """Get the approach type."""
-        return self._approachType.get_text()
-
-    @property
-    def runway(self):
-        """Get the runway."""
-        return self._runway.get_text()
-
-    @property
-    def vref(self):
-        """Return the landing reference speed."""
-        return self._vref.get_int()
-
-    def activate(self):
-        """Called when the page is activated."""
-        self._starButton.set_sensitive(True)
-        self._starButton.set_active(False)
-        self._star.set_text("")
-
-        self._transitionButton.set_sensitive(True)
-        self._transitionButton.set_active(False)
-        self._transition.set_text("")
-
-        self._runway.set_text("")
-        self._runway.set_sensitive(True)
-
-        self._approachType.set_text("")
-        self._approachType.set_sensitive(True)
-
-        self._vref.set_int(None)
-        self._vref.set_sensitive(True)
-
-        self._updateForwardButton()
-
-    def flightEnded(self):
-        """Called when the flight has ended."""
-        self._flightEnded = True
-        self._updateForwardButton()
-
-    def finalize(self):
-        """Finalize the page."""
-        self._starButton.set_sensitive(False)
-        self._star.set_sensitive(False)
-
-        self._transitionButton.set_sensitive(False)
-        self._transition.set_sensitive(False)
-
-        self._runway.set_sensitive(False)
-
-        self._approachType.set_sensitive(False)
-
-        self._vref.set_sensitive(False)
-        self._wizard.gui.flight.aircraft.updateVRef()
-        # FIXME: Perhaps a separate initialize() call which would set up
-        # defaults? -> use reset()
-        self._flightEnded = False
-
-    def _starButtonClicked(self, button):
-        """Called when the STAR button is clicked."""
-        active = button.get_active()
-        self._star.set_sensitive(active)
-        if active:
-            self._star.grab_focus()
-        self._updateForwardButton()
-
-    def _transitionButtonClicked(self, button):
-        """Called when the Transition button is clicked."""
-        active = button.get_active()
-        self._transition.set_sensitive(active)
-        if active:
-            self._transition.grab_focus()        
-        self._updateForwardButton()    
-
-    def _updateForwardButton(self, widget = None):
-        """Update the sensitivity of the forward button."""
-        sensitive = self._flightEnded and \
-                    (self._starButton.get_active() or \
-                     self._transitionButton.get_active()) and \
-                    (self._star.get_text()!="" or
-                     not self._starButton.get_active()) and \
-                    (self._transition.get_text()!="" or
-                     not self._transitionButton.get_active()) and \
-                    self._runway.get_text()!="" and \
-                    self._approachType.get_text()!="" and \
-                    self.vref is not None
-        self._button.set_sensitive(sensitive)
-
-    def _vrefChanged(self, widget, value):
-        """Called when the Vref has changed."""
-        self._updateForwardButton()
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-        
-    def _forwardClicked(self, button):
-        """Called when the forward button is clicked."""
-        self._wizard.nextPage()
-
-#-----------------------------------------------------------------------------
-
-class FinishPage(Page):
-    """Flight finish page."""
-    _flightTypes = [ ("scheduled", const.FLIGHTTYPE_SCHEDULED),
-                     ("old-timer", const.FLIGHTTYPE_OLDTIMER),
-                     ("VIP", const.FLIGHTTYPE_VIP),
-                     ("charter", const.FLIGHTTYPE_CHARTER) ]
-    
-    def __init__(self, wizard):
-        """Construct the finish page."""
-        help = "There are some statistics about your flight below.\n\n" \
-               "Review the data, also on earlier pages, and if you are\n" \
-               "satisfied, you can save or send your PIREP."
-
-        super(FinishPage, self).__init__(wizard, "Finish", help)
-        
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-
-        table = gtk.Table(7, 2)
-        table.set_row_spacings(4)
-        table.set_col_spacings(16)
-        table.set_homogeneous(False)
-        alignment.add(table)
-        self.setMainWidget(alignment)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Flight rating:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 0, 1)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._flightRating = gtk.Label()
-        self._flightRating.set_width_chars(7)
-        self._flightRating.set_alignment(0.0, 0.5)
-        self._flightRating.set_use_markup(True)
-        labelAlignment.add(self._flightRating)
-        table.attach(labelAlignment, 1, 2, 0, 1)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Flight time:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 1, 2)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._flightTime = gtk.Label()
-        self._flightTime.set_width_chars(10)
-        self._flightTime.set_alignment(0.0, 0.5)
-        self._flightTime.set_use_markup(True)
-        labelAlignment.add(self._flightTime)
-        table.attach(labelAlignment, 1, 2, 1, 2)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Block time:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 2, 3)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._blockTime = gtk.Label()
-        self._blockTime.set_width_chars(10)
-        self._blockTime.set_alignment(0.0, 0.5)
-        self._blockTime.set_use_markup(True)
-        labelAlignment.add(self._blockTime)
-        table.attach(labelAlignment, 1, 2, 2, 3)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Distance flown:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 3, 4)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._distanceFlown = gtk.Label()
-        self._distanceFlown.set_width_chars(10)
-        self._distanceFlown.set_alignment(0.0, 0.5)
-        self._distanceFlown.set_use_markup(True)
-        labelAlignment.add(self._distanceFlown)
-        table.attach(labelAlignment, 1, 2, 3, 4)
-        
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("Fuel used:")
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 4, 5)
-
-        labelAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        self._fuelUsed = gtk.Label()
-        self._fuelUsed.set_width_chars(10)
-        self._fuelUsed.set_alignment(0.0, 0.5)
-        self._fuelUsed.set_use_markup(True)
-        labelAlignment.add(self._fuelUsed)
-        table.attach(labelAlignment, 1, 2, 4, 5)
-
-        labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
-        label = gtk.Label("_Type:")
-        label.set_use_underline(True)
-        labelAlignment.add(label)
-        table.attach(labelAlignment, 0, 1, 5, 6)
-
-        flightTypeModel = gtk.ListStore(str, int)
-        for (name, type) in FinishPage._flightTypes:
-            flightTypeModel.append([name, type])
-
-        self._flightType = gtk.ComboBox(model = flightTypeModel)
-        renderer = gtk.CellRendererText()
-        self._flightType.pack_start(renderer, True)
-        self._flightType.add_attribute(renderer, "text", 0)
-        self._flightType.set_tooltip_text("Select the type of the flight.")
-        self._flightType.set_active(0)
-        self._flightType.connect("changed", self._flightTypeChanged)
-        flightTypeAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        flightTypeAlignment.add(self._flightType)
-        table.attach(flightTypeAlignment, 1, 2, 5, 6)
-        label.set_mnemonic_widget(self._flightType)        
-
-        self._onlineFlight = gtk.CheckButton("_Online flight")
-        self._onlineFlight.set_use_underline(True)
-        self._onlineFlight.set_tooltip_text("Check if your flight was online, uncheck otherwise.")
-        onlineFlightAlignment = gtk.Alignment(xalign=0.0, xscale=0.0)
-        onlineFlightAlignment.add(self._onlineFlight)
-        table.attach(onlineFlightAlignment, 1, 2, 6, 7)
-
-        button = self.addButton(gtk.STOCK_GO_BACK)
-        button.set_use_stock(True)
-        button.connect("clicked", self._backClicked)
-
-        self._saveButton = self.addButton("S_ave PIREP...")
-        self._saveButton.set_use_underline(True)
-        self._saveButton.set_sensitive(False)
-        #self._saveButton.connect("clicked", self._saveClicked)
-        
-        self._sendButton = self.addButton("_Send PIREP...", True)
-        self._sendButton.set_use_underline(True)
-        self._sendButton.set_sensitive(False)
-        self._sendButton.connect("clicked", self._sendClicked)
-        
-    @property
-    def flightType(self):
-        """Get the flight type."""
-        index = self._flightType.get_active()
-        return None if index<0 else self._flightType.get_model()[index][1]
-
-    @property
-    def online(self):
-        """Get whether the flight was an online flight or not."""
-        return self._onlineFlight.get_active()
-
-    def activate(self):
-        """Activate the page."""
-        flight = self._wizard.gui._flight
-        rating = flight.logger.getRating()
-        if rating<0:
-            self._flightRating.set_markup('<b><span foreground="red">NO GO</span></b>')
-        else:
-            self._flightRating.set_markup("<b>%.1f %%</b>" % (rating,))
-
-        flightLength = flight.flightTimeEnd - flight.flightTimeStart
-        self._flightTime.set_markup("<b>%s</b>" % \
-                                    (util.getTimeIntervalString(flightLength),))
-        
-        blockLength = flight.blockTimeEnd - flight.blockTimeStart
-        self._blockTime.set_markup("<b>%s</b>" % \
-                                   (util.getTimeIntervalString(blockLength),))
-
-        self._distanceFlown.set_markup("<b>%.2f NM</b>" % \
-                                       (flight.flownDistance,))
-        
-        self._fuelUsed.set_markup("<b>%.0f kg</b>" % \
-                                  (flight.endFuel - flight.startFuel,))
-
-        self._flightType.set_active(-1)
-        self._onlineFlight.set_active(True)
-
-    def _backClicked(self, button):
-        """Called when the Back button is pressed."""
-        self.goBack()
-
-    def _flightTypeChanged(self, comboBox):
-        """Called when the flight type has changed."""
-        index = self._flightType.get_active()
-        flightTypeIsValid = index>=0
-        #self._saveButton.set_sensitive(flightTypeIsValid)
-        self._sendButton.set_sensitive(flightTypeIsValid)
-
-    def _sendClicked(self, button):
-        """Called when the Send button is clicked."""
-        pirep = PIREP(self._wizard.gui)
-        gui = self._wizard.gui
-        gui.beginBusy("Sending PIREP...")
-        gui.webHandler.sendPIREP(self._pirepSentCallback, pirep)
-
-    def _pirepSentCallback(self, returned, result):
-        """Callback for the PIREP sending result."""
-        gobject.idle_add(self._handlePIREPSent, returned, result)
-
-    def _handlePIREPSent(self, returned, result):
-        """Callback for the PIREP sending result."""
-        self._wizard.gui.endBusy()
-        secondaryMarkup = None
-        type = MESSAGETYPE_ERROR
-        if returned:
-            if result.success:
-                type = MESSAGETYPE_INFO
-                messageFormat = "The PIREP was sent successfully."
-                secondaryMarkup = "Await the thorough scrutiny from our PIREP correctors! :)"
-            elif result.alreadyFlown:
-                messageFormat = "The PIREP for this flight has already been sent!"
-                secondaryMarkup = "You may clear the old PIREP on the MAVA website."
-            elif result.notAvailable:
-                messageFormat = "This flight is not available anymore!"
-            else:
-                messageFormat = "The MAVA website returned with an unknown error."
-                secondaryMarkup = "See the debug log for more information."
-        else:
-            print "PIREP sending failed", result
-            messageFormat = "Could not send the PIREP to the MAVA website."
-            secondaryMarkup = "This can be a network problem, in which case\n" \
-                              "you may try again later. Or it can be a bug;\n" \
-                              "see the debug log for more information."
-        
-        dialog = gtk.MessageDialog(type = type, buttons = BUTTONSTYPE_OK,
-                                   message_format = messageFormat)
-        if secondaryMarkup is not None:
-            dialog.format_secondary_markup(secondaryMarkup)
-
-        dialog.run()
-        dialog.hide()
-        
-#-----------------------------------------------------------------------------
-
-class Wizard(gtk.VBox):
-    """The flight wizard."""
-    def __init__(self, gui):
-        """Construct the wizard."""
-        super(Wizard, self).__init__()
-
-        self.gui = gui
-
-        self._pages = []
-        self._currentPage = None
-        
-        self._pages.append(LoginPage(self))
-        self._pages.append(FlightSelectionPage(self))
-        self._pages.append(GateSelectionPage(self))
-        self._pages.append(ConnectPage(self))
-        self._payloadPage = PayloadPage(self) 
-        self._pages.append(self._payloadPage)
-        self._pages.append(TimePage(self))
-        self._routePage = RoutePage(self)
-        self._pages.append(self._routePage)
-        self._departureBriefingPage = BriefingPage(self, True)
-        self._pages.append(self._departureBriefingPage)
-        self._arrivalBriefingPage = BriefingPage(self, False)
-        self._pages.append(self._arrivalBriefingPage)
-        self._takeoffPage = TakeoffPage(self) 
-        self._pages.append(self._takeoffPage)
-        self._landingPage = LandingPage(self) 
-        self._pages.append(self._landingPage)
-        self._finishPage = FinishPage(self)
-        self._pages.append(self._finishPage)
-        
-        maxWidth = 0
-        maxHeight = 0
-        for page in self._pages:
-            page.show_all()
-            pageSizeRequest = page.size_request()
-            width = pageSizeRequest.width if pygobject else pageSizeRequest[0]
-            height = pageSizeRequest.height if pygobject else pageSizeRequest[1]
-            maxWidth = max(maxWidth, width)
-            maxHeight = max(maxHeight, height)
-        maxWidth += 16
-        maxHeight += 32
-        self.set_size_request(maxWidth, maxHeight)
-
-        self._initialize()
-        
-    @property
-    def loginResult(self):
-        """Get the login result."""
-        return self._loginResult
-
-    def setCurrentPage(self, index, finalize = False):
-        """Set the current page to the one with the given index."""
-        assert index < len(self._pages)
-
-        fromPage = self._currentPage
-        if fromPage is not None:
-            page = self._pages[fromPage]
-            if finalize and not page._completed:
-                page.complete()
-            self.remove(page)
-
-        self._currentPage = index
-        page = self._pages[index]
-        self.add(page)
-        if page._fromPage is None:
-            page._fromPage = fromPage
-            page.initialize()
-        self.show_all()
-        if fromPage is not None:
-            self.grabDefault()
-
-    @property
-    def bookedFlight(self):
-        """Get the booked flight selected."""
-        return self._bookedFlight
-
-    @property
-    def cargoWeight(self):
-        """Get the calculated ZFW value."""
-        return self._payloadPage.cargoWeight
-
-    @property
-    def zfw(self):
-        """Get the calculated ZFW value."""
-        return 0 if self._bookedFlight is None \
-               else self._payloadPage.calculateZFW()
-
-    @property
-    def filedCruiseAltitude(self):
-        """Get the filed cruise altitude."""
-        return self._routePage.filedCruiseLevel * 100
-
-    @property
-    def cruiseAltitude(self):
-        """Get the cruise altitude."""
-        return self._routePage.cruiseLevel * 100
-
-    @property
-    def route(self):
-        """Get the route."""
-        return self._routePage.route
-
-    @property
-    def departureMETAR(self):
-        """Get the METAR of the departure airport."""
-        return self._departureBriefingPage.metar
-
-    @property
-    def arrivalMETAR(self):
-        """Get the METAR of the arrival airport."""
-        return self._arrivalBriefingPage.metar
-
-    @property
-    def departureRunway(self):
-        """Get the departure runway."""
-        return self._takeoffPage.runway
-
-    @property
-    def sid(self):
-        """Get the SID."""
-        return self._takeoffPage.sid
-
-    @property
-    def v1(self):
-        """Get the V1 speed."""
-        return self._takeoffPage.v1
-
-    @property
-    def vr(self):
-        """Get the Vr speed."""
-        return self._takeoffPage.vr
-
-    @property
-    def v2(self):
-        """Get the V2 speed."""
-        return self._takeoffPage.v2
-
-    @property
-    def arrivalRunway(self):
-        """Get the arrival runway."""
-        return self._landingPage.runway
-
-    @property
-    def star(self):
-        """Get the STAR."""
-        return self._landingPage.star
-
-    @property
-    def transition(self):
-        """Get the transition."""
-        return self._landingPage.transition
-
-    @property
-    def approachType(self):
-        """Get the approach type."""
-        return self._landingPage.approachType
-
-    @property
-    def vref(self):
-        """Get the Vref speed."""
-        return self._landingPage.vref
-
-    @property
-    def flightType(self):
-        """Get the flight type."""
-        return self._finishPage.flightType
-
-    @property
-    def online(self):
-        """Get whether the flight was online or not."""
-        return self._finishPage.online
-
-    def nextPage(self, finalize = True):
-        """Go to the next page."""
-        self.jumpPage(1, finalize)
-
-    def jumpPage(self, count, finalize = True):
-        """Go to the page which is 'count' pages after the current one."""
-        self.setCurrentPage(self._currentPage + count, finalize = finalize)
-
-    def grabDefault(self):
-        """Make the default button of the current page the default."""
-        self._pages[self._currentPage].grabDefault()
-
-    def connected(self, fsType, descriptor):
-        """Called when the connection could be made to the simulator."""
-        self.nextPage()
-
-    def reset(self):
-        """Resets the wizard to go back to the login page."""
-        self._initialize()
-
-    def setStage(self, stage):
-        """Set the flight stage to the given one."""
-        if stage==const.STAGE_TAKEOFF:
-            self._takeoffPage.freezeValues()
-        elif stage==const.STAGE_END:
-            self._landingPage.flightEnded()
-
-    def _initialize(self):
-        """Initialize the wizard."""
-        self._fleet = None
-        self._fleetCallback = None
-        self._updatePlaneCallback = None
-        
-        self._loginResult = None
-        self._bookedFlight = None
-        self._departureGate = "-"
-        self._departureNOTAMs = None
-        self._departureMETAR = None
-        self._arrivalNOTAMs = None
-        self._arrivalMETAR = None
-
-        for page in self._pages:
-            page.reset()
-        
-        self.setCurrentPage(0)
-        
-    def _getFleet(self, callback, force = False):
-        """Get the fleet, if needed.
-
-        callback is function that will be called, when the feet is retrieved,
-        or the retrieval fails. It should have a single argument that will
-        receive the fleet object on success, None otherwise.
-        """
-        if self._fleet is not None and not force:
-            callback(self._fleet)
-
-        self.gui.beginBusy("Retrieving fleet...")
-        self._fleetCallback = callback
-        self.gui.webHandler.getFleet(self._fleetResultCallback)
-
-    def _fleetResultCallback(self, returned, result):
-        """Called when the fleet has been queried."""
-        gobject.idle_add(self._handleFleetResult, returned, result)
-
-    def _handleFleetResult(self, returned, result):
-        """Handle the fleet result."""
-        self.gui.endBusy()
-        if returned:
-            self._fleet = result.fleet
-        else:
-            self._fleet = None
-
-            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                       buttons = BUTTONSTYPE_OK,
-                                       message_format =
-                                       "Failed to retrieve the information on "
-                                       "the fleet.")
-            dialog.run()
-            dialog.hide()
-
-        self._fleetCallback(self._fleet)
-
-    def _updatePlane(self, callback, tailNumber, status, gateNumber = None):
-        """Update the given plane's gate information."""
-        self.gui.beginBusy("Updating plane status...")
-        self._updatePlaneCallback = callback
-        self.gui.webHandler.updatePlane(self._updatePlaneResultCallback,
-                                        tailNumber, status, gateNumber)
-
-    def _updatePlaneResultCallback(self, returned, result):
-        """Callback for the plane updating operation."""
-        gobject.idle_add(self._handleUpdatePlaneResult, returned, result)
-
-    def _handleUpdatePlaneResult(self, returned, result):
-        """Handle the result of a plane update operation."""
-        self.gui.endBusy()
-        if returned:
-            success = result.success
-        else:
-            success = None
-
-            dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                       buttons = BUTTONSTYPE_OK,
-                                       message_format =
-                                       "Failed to update the statuis of "
-                                       "the airplane.")
-            dialog.run()
-            dialog.hide()
-
-        self._updatePlaneCallback(success)
-
-    def _connectSimulator(self):
-        """Connect to the simulator."""
-        self.gui.connectSimulator(self._bookedFlight.aircraftType)
-    
-#-----------------------------------------------------------------------------
-
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 99)
+++ src/mlx/gui/gui.py	(revision 99)
@@ -0,0 +1,692 @@
+# The main file for the GUI
+
+from statusicon import StatusIcon
+from statusbar import Statusbar
+from info import FlightInfo
+from update import Updater
+from mlx.gui.common import *
+from mlx.gui.flight import Wizard
+from mlx.gui.monitor import MonitorWindow
+
+import mlx.const as const
+import mlx.fs as fs
+import mlx.flight as flight
+import mlx.logger as logger
+import mlx.acft as acft
+import mlx.web as web
+
+import time
+import threading
+import sys
+
+#------------------------------------------------------------------------------
+
+class GUI(fs.ConnectionListener):
+    """The main GUI class."""
+    @staticmethod
+    def _formatFlightLogLine(timeStr, line):
+        """Format the given line for flight logging."""
+        if timeStr is not None:
+            line = timeStr + ": " + line
+        return line + "\n"
+        
+    def __init__(self, programDirectory, config):
+        """Construct the GUI."""
+        gobject.threads_init()
+
+        self._programDirectory = programDirectory
+        self.config = config
+        self._connecting = False
+        self._reconnecting = False
+        self._connected = False
+        self._logger = logger.Logger(self)
+        self._flight = None
+        self._simulator = None
+        self._monitoring = False
+
+        self._stdioLock = threading.Lock()
+        self._stdioText = ""
+
+        self.webHandler = web.Handler()
+        self.webHandler.start()
+
+        self.toRestart = False
+
+    def build(self, iconDirectory):
+        """Build the GUI."""
+        
+        window = gtk.Window()
+        window.set_title("MAVA Logger X " + const.VERSION)
+        window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
+        window.connect("delete-event",
+                       lambda a, b: self.hideMainWindow())
+        window.connect("window-state-event", self._handleMainWindowState)
+        accelGroup = gtk.AccelGroup()
+        window.add_accel_group(accelGroup)
+
+        mainVBox = gtk.VBox()
+        window.add(mainVBox)
+
+        menuBar = self._buildMenuBar(accelGroup)
+        mainVBox.pack_start(menuBar, False, False, 0)
+
+        self._notebook = gtk.Notebook()
+        mainVBox.pack_start(self._notebook, True, True, 4)
+
+        self._wizard = Wizard(self)
+        label = gtk.Label("Fligh_t")
+        label.set_use_underline(True)
+        label.set_tooltip_text("Flight wizard")
+        self._notebook.append_page(self._wizard, label)
+
+        self._flightInfo = FlightInfo(self)
+        label = gtk.Label("Flight _info")
+        label.set_use_underline(True)
+        label.set_tooltip_text("Flight information")
+        self._notebook.append_page(self._flightInfo, label)
+        self._flightInfo.disable()
+
+        (logWidget, self._logView)  = self._buildLogWidget()
+        label = gtk.Label("_Log")
+        label.set_use_underline(True)
+        label.set_tooltip_text("The log of your flight that will be sent to the MAVA website")
+        self._notebook.append_page(logWidget, label)
+
+        (self._debugLogWidget, self._debugLogView) = self._buildLogWidget()
+        self._debugLogWidget.show_all()
+
+        mainVBox.pack_start(gtk.HSeparator(), False, False, 0)
+
+        self._statusbar = Statusbar()
+        mainVBox.pack_start(self._statusbar, False, False, 0)
+
+        self._notebook.connect("switch-page", self._notebookPageSwitch)
+
+        self._monitorWindow = MonitorWindow(self, iconDirectory)
+        self._monitorWindow.add_accel_group(accelGroup)
+        self._monitorWindowX = None
+        self._monitorWindowY = None
+        self._selfToggling = False
+
+        window.show_all()
+        self._wizard.grabDefault()
+
+        self._mainWindow = window
+
+        self._statusIcon = StatusIcon(iconDirectory, self)
+
+        self._busyCursor = gdk.Cursor(gdk.CursorType.WATCH if pygobject
+                                      else gdk.WATCH)
+
+    @property
+    def logger(self):
+        """Get the logger used by us."""
+        return self._logger
+        
+    @property
+    def simulator(self):
+        """Get the simulator used by us."""
+        return self._simulator
+        
+    @property
+    def flight(self):
+        """Get the flight being performed."""
+        return self._flight
+
+    @property
+    def bookedFlight(self):
+        """Get the booked flight selected, if any."""
+        return self._wizard.bookedFlight
+
+    @property
+    def cargoWeight(self):
+        """Get the cargo weight."""
+        return self._wizard.cargoWeight
+
+    @property
+    def zfw(self):
+        """Get Zero-Fuel Weight calculated for the current flight."""
+        return self._wizard.zfw
+        
+    @property
+    def filedCruiseAltitude(self):
+        """Get cruise altitude filed for the current flight."""
+        return self._wizard.filedCruiseAltitude
+        
+    @property
+    def cruiseAltitude(self):
+        """Get cruise altitude set for the current flight."""
+        return self._wizard.cruiseAltitude
+
+    @property
+    def route(self):
+        """Get the flight route."""
+        return self._wizard.route
+
+    @property
+    def departureMETAR(self):
+        """Get the METAR of the deprature airport."""
+        return self._wizard.departureMETAR
+        
+    @property
+    def arrivalMETAR(self):
+        """Get the METAR of the deprature airport."""
+        return self._wizard.arrivalMETAR
+
+    @property
+    def departureRunway(self):
+        """Get the name of the departure runway."""
+        return self._wizard.departureRunway
+        
+    @property
+    def sid(self):
+        """Get the SID."""
+        return self._wizard.sid
+
+    @property
+    def v1(self):
+        """Get the V1 speed calculated for the flight."""
+        return self._wizard.v1
+        
+    @property
+    def vr(self):
+        """Get the Vr speed calculated for the flight."""
+        return self._wizard.vr
+        
+    @property
+    def v2(self):
+        """Get the V2 speed calculated for the flight."""
+        return self._wizard.v2
+        
+    @property
+    def arrivalRunway(self):
+        """Get the arrival runway."""
+        return self._wizard.arrivalRunway
+
+    @property
+    def star(self):
+        """Get the STAR."""
+        return self._wizard.star
+
+    @property
+    def transition(self):
+        """Get the transition."""
+        return self._wizard.transition
+
+    @property
+    def approachType(self):
+        """Get the approach type."""
+        return self._wizard.approachType
+
+    @property
+    def vref(self):
+        """Get the Vref speed calculated for the flight."""
+        return self._wizard.vref
+        
+    @property
+    def flightType(self):
+        """Get the flight type."""
+        return self._wizard.flightType
+
+    @property
+    def online(self):
+        """Get whether the flight was online or not."""
+        return self._wizard.online
+
+    @property
+    def comments(self):
+        """Get the comments."""
+        return self._flightInfo.comments
+
+    @property
+    def flightDefects(self):
+        """Get the flight defects."""
+        return self._flightInfo.flightDefects
+
+    @property
+    def delayCodes(self):
+        """Get the delay codes."""
+        return self._flightInfo.delayCodes
+
+    def run(self):
+        """Run the GUI."""
+        if self.config.autoUpdate:
+            self._updater = Updater(self,
+                                    self._programDirectory,
+                                    self.config.updateURL,
+                                    self._mainWindow)
+            self._updater.start()
+
+        gtk.main()
+
+        self._disconnect()
+
+    def connected(self, fsType, descriptor):
+        """Called when we have connected to the simulator."""
+        self._connected = True
+        self._logger.untimedMessage("Connected to the simulator %s" % (descriptor,))
+        gobject.idle_add(self._handleConnected, fsType, descriptor)
+
+    def _handleConnected(self, fsType, descriptor):
+        """Called when the connection to the simulator has succeeded."""
+        self._statusbar.updateConnection(self._connecting, self._connected)
+        self.endBusy()
+        if not self._reconnecting:
+            self._wizard.connected(fsType, descriptor)
+        self._reconnecting = False
+
+    def connectionFailed(self):
+        """Called when the connection failed."""
+        self._logger.untimedMessage("Connection to the simulator failed")
+        gobject.idle_add(self._connectionFailed)
+
+    def _connectionFailed(self):
+        """Called when the connection failed."""
+        self.endBusy()
+        self._statusbar.updateConnection(self._connecting, self._connected)
+
+        dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                   message_format =
+                                   "Cannot connect to the simulator.",
+                                   parent = self._mainWindow)
+        dialog.format_secondary_markup("Rectify the situation, and press <b>Try again</b> "
+                                       "to try the connection again, " 
+                                       "or <b>Cancel</b> to cancel the flight.")
+        
+        dialog.add_button("_Cancel", 0)
+        dialog.add_button("_Try again", 1)
+        dialog.set_default_response(1)
+        
+        result = dialog.run()
+        dialog.hide()
+        if result == 1:
+            self.beginBusy("Connecting to the simulator.")
+            self._simulator.reconnect()
+        else:
+            self.reset()
+        
+    def disconnected(self):
+        """Called when we have disconnected from the simulator."""
+        self._connected = False
+        self._logger.untimedMessage("Disconnected from the simulator")
+
+        gobject.idle_add(self._disconnected)
+
+    def _disconnected(self):
+        """Called when we have disconnected from the simulator unexpectedly."""        
+        self._statusbar.updateConnection(self._connecting, self._connected)
+
+        dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                   message_format =
+                                   "The connection to the simulator failed unexpectedly.",
+                                   parent = self._mainWindow)
+        dialog.format_secondary_markup("If the simulator has crashed, restart it "
+                                       "and restore your flight as much as possible "
+                                       "to the state it was in before the crash.\n"
+                                       "Then press <b>Reconnect</b> to reconnect.\n\n"
+                                       "If you want to cancel the flight, press <b>Cancel</b>.")
+
+        dialog.add_button("_Cancel", 0)
+        dialog.add_button("_Reconnect", 1)
+        dialog.set_default_response(1)
+
+        result = dialog.run()
+        dialog.hide()
+        if result == 1:
+            self.beginBusy("Connecting to the simulator.")
+            self._reconnecting = True
+            self._simulator.reconnect()
+        else:
+            self.reset()
+
+    def enableFlightInfo(self):
+        """Enable the flight info tab."""
+        self._flightInfo.enable()
+
+    def reset(self):
+        """Reset the GUI."""
+        self._disconnect()
+
+        self._flightInfo.reset()
+        self._flightInfo.disable()
+        self.resetFlightStatus()
+
+        self._wizard.reset()
+        self._notebook.set_current_page(0)
+
+        self._logView.get_buffer().set_text("")
+
+    def _disconnect(self):
+        """Disconnect from the simulator if connected."""
+        self.stopMonitoring()
+
+        if self._connected:
+            self._flight.simulator.disconnect()
+            self._connected = False
+
+        self._connecting = False
+        self._reconnecting = False
+        self._statusbar.updateConnection(False, False)
+            
+    def addFlightLogLine(self, timeStr, line):
+        """Write the given message line to the log."""
+        gobject.idle_add(self._writeLog,
+                         GUI._formatFlightLogLine(timeStr, line),
+                         self._logView)
+
+    def updateFlightLogLine(self, index, timeStr, line):
+        """Update the line with the given index."""
+        gobject.idle_add(self._updateFlightLogLine, index,
+                         GUI._formatFlightLogLine(timeStr, line))
+
+    def _updateFlightLogLine(self, index, line):
+        """Replace the contents of the given line in the log."""
+        buffer = self._logView.get_buffer()
+        startIter = buffer.get_iter_at_line(index)
+        endIter = buffer.get_iter_at_line(index + 1)
+        buffer.delete(startIter, endIter)
+        buffer.insert(startIter, line)
+        self._logView.scroll_mark_onscreen(buffer.get_insert())
+
+    def check(self, flight, aircraft, logger, oldState, state):
+        """Update the data."""
+        gobject.idle_add(self._monitorWindow.setData, state)
+        gobject.idle_add(self._statusbar.updateTime, state.timestamp)
+
+    def resetFlightStatus(self):
+        """Reset the status of the flight."""
+        self._statusbar.resetFlightStatus()
+        self._statusbar.updateTime()
+        self._statusIcon.resetFlightStatus()
+
+    def setStage(self, stage):
+        """Set the stage of the flight."""
+        gobject.idle_add(self._setStage, stage)
+
+    def _setStage(self, stage):
+        """Set the stage of the flight."""
+        self._statusbar.setStage(stage)
+        self._statusIcon.setStage(stage)
+        self._wizard.setStage(stage)
+        if stage==const.STAGE_END:
+            self._disconnect()
+
+    def setRating(self, rating):
+        """Set the rating of the flight."""
+        gobject.idle_add(self._setRating, rating)
+
+    def _setRating(self, rating):
+        """Set the rating of the flight."""
+        self._statusbar.setRating(rating)
+        self._statusIcon.setRating(rating)
+
+    def setNoGo(self, reason):
+        """Set the rating of the flight to No-Go with the given reason."""
+        gobject.idle_add(self._setNoGo, reason)
+
+    def _setNoGo(self, reason):
+        """Set the rating of the flight."""
+        self._statusbar.setNoGo(reason)
+        self._statusIcon.setNoGo(reason)
+
+    def _handleMainWindowState(self, window, event):
+        """Hande a change in the state of the window"""
+        iconified = gdk.WindowState.ICONIFIED if pygobject \
+                    else gdk.WINDOW_STATE_ICONIFIED
+        if (event.changed_mask&iconified)!=0 and (event.new_window_state&iconified)!=0:
+            self.hideMainWindow(savePosition = False)
+
+    def hideMainWindow(self, savePosition = True):
+        """Hide the main window and save its position."""
+        if savePosition:
+            (self._mainWindowX, self._mainWindowY) = \
+                 self._mainWindow.get_window().get_root_origin()
+        else:
+            self._mainWindowX = self._mainWindowY = None
+        self._mainWindow.hide()
+        self._statusIcon.mainWindowHidden()
+        return True
+
+    def showMainWindow(self):
+        """Show the main window at its former position."""
+        if self._mainWindowX is not None and self._mainWindowY is not None:
+            self._mainWindow.move(self._mainWindowX, self._mainWindowY)
+
+        self._mainWindow.show()
+        self._mainWindow.deiconify()
+            
+        self._statusIcon.mainWindowShown()
+
+    def toggleMainWindow(self):
+        """Toggle the main window."""
+        if self._mainWindow.get_visible():
+            self.hideMainWindow()
+        else:
+            self.showMainWindow()
+
+    def hideMonitorWindow(self, savePosition = True):
+        """Hide the monitor window."""
+        if savePosition:
+            (self._monitorWindowX, self._monitorWindowY) = \
+                 self._monitorWindow.get_window().get_root_origin()
+        else:
+            self._monitorWindowX = self._monitorWindowY = None
+        self._monitorWindow.hide()
+        self._statusIcon.monitorWindowHidden()
+        if self._showMonitorMenuItem.get_active():
+            self._selfToggling = True
+            self._showMonitorMenuItem.set_active(False)
+        return True
+
+    def showMonitorWindow(self):
+        """Show the monitor window."""
+        if self._monitorWindowX is not None and self._monitorWindowY is not None:
+            self._monitorWindow.move(self._monitorWindowX, self._monitorWindowY)
+        self._monitorWindow.show_all()
+        self._statusIcon.monitorWindowShown()
+        if not self._showMonitorMenuItem.get_active():
+            self._selfToggling = True
+            self._showMonitorMenuItem.set_active(True)
+
+    def _toggleMonitorWindow(self, menuItem):
+        if self._selfToggling:
+            self._selfToggling = False
+        elif self._monitorWindow.get_visible():
+            self.hideMonitorWindow()
+        else:
+            self.showMonitorWindow()
+
+    def restart(self):
+        """Quit and restart the application."""
+        self.toRestart = True
+        self._quit(force = True)
+
+    def flushStdIO(self):
+        """Flush any text to the standard error that could not be logged."""
+        if self._stdioText:
+            sys.__stderr__.write(self._stdioText)
+            
+    def writeStdIO(self, text):
+        """Write the given text into standard I/O log."""
+        with self._stdioLock:
+            self._stdioText += text
+
+        gobject.idle_add(self._writeStdIO)
+
+    def beginBusy(self, message):
+        """Begin a period of background processing."""
+        self._wizard.set_sensitive(False)
+        self._mainWindow.get_window().set_cursor(self._busyCursor)
+        self._statusbar.updateBusyState(message)
+
+    def endBusy(self):
+        """End a period of background processing."""
+        self._mainWindow.get_window().set_cursor(None)
+        self._wizard.set_sensitive(True)
+        self._statusbar.updateBusyState(None)
+
+    def _writeStdIO(self):
+        """Perform the real writing."""
+        with self._stdioLock:
+            text = self._stdioText
+            self._stdioText = ""
+        if not text: return
+            
+        lines = text.splitlines()
+        if text[-1]=="\n":
+            text = ""
+        else:
+            text = lines[-1]
+            lines = lines[:-1]
+            
+        for line in lines:
+            #print >> sys.__stdout__, line
+            self._writeLog(line + "\n", self._debugLogView)
+
+        if text:
+            #print >> sys.__stdout__, text,
+            self._writeLog(text, self._debugLogView)
+
+    def connectSimulator(self, aircraftType):
+        """Connect to the simulator for the first time."""
+        self._logger.reset()
+
+        self._flight = flight.Flight(self._logger, self)
+        self._flight.aircraftType = aircraftType
+        self._flight.aircraft = acft.Aircraft.create(self._flight)
+        self._flight.aircraft._checkers.append(self)
+        
+        if self._simulator is None:
+            self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
+
+        self._flight.simulator = self._simulator
+
+        self.beginBusy("Connecting to the simulator...")
+        self._statusbar.updateConnection(self._connecting, self._connected)
+
+        self._connecting = True
+        self._simulator.connect(self._flight.aircraft)        
+
+    def startMonitoring(self):
+        """Start monitoring."""
+        if not self._monitoring:
+            self.simulator.startMonitoring()
+            self._monitoring = True
+
+    def stopMonitoring(self):
+        """Stop monitoring."""
+        if self._monitoring:
+            self.simulator.stopMonitoring()
+            self._monitoring = False
+
+    def _buildMenuBar(self, accelGroup):
+        """Build the main menu bar."""
+        menuBar = gtk.MenuBar()
+        
+        fileMenuItem = gtk.MenuItem("File")
+        fileMenu = gtk.Menu()
+        fileMenuItem.set_submenu(fileMenu)
+        menuBar.append(fileMenuItem)
+
+        quitMenuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
+        quitMenuItem.set_use_stock(True)
+        quitMenuItem.add_accelerator("activate", accelGroup,
+                                     ord("q"), CONTROL_MASK,
+                                     ACCEL_VISIBLE)
+        quitMenuItem.connect("activate", self._quit)
+        fileMenu.append(quitMenuItem)
+
+
+        viewMenuItem = gtk.MenuItem("View")
+        viewMenu = gtk.Menu()
+        viewMenuItem.set_submenu(viewMenu)
+        menuBar.append(viewMenuItem)
+
+        self._showMonitorMenuItem = gtk.CheckMenuItem()
+        self._showMonitorMenuItem.set_label("Show _monitor window")
+        self._showMonitorMenuItem.set_use_underline(True)
+        self._showMonitorMenuItem.set_active(False)
+        self._showMonitorMenuItem.add_accelerator("activate", accelGroup,
+                                                  ord("m"), CONTROL_MASK,
+                                                  ACCEL_VISIBLE)
+        self._showMonitorMenuItem.connect("toggled", self._toggleMonitorWindow)
+        viewMenu.append(self._showMonitorMenuItem)
+
+        showDebugMenuItem = gtk.CheckMenuItem()
+        showDebugMenuItem.set_label("Show _debug log")
+        showDebugMenuItem.set_use_underline(True)
+        showDebugMenuItem.set_active(False)
+        showDebugMenuItem.add_accelerator("activate", accelGroup,
+                                          ord("d"), CONTROL_MASK,
+                                          ACCEL_VISIBLE)
+        showDebugMenuItem.connect("toggled", self._toggleDebugLog)
+        viewMenu.append(showDebugMenuItem)
+
+        return menuBar
+
+    def _toggleDebugLog(self, menuItem):
+        """Toggle the debug log."""
+        if menuItem.get_active():
+            label = gtk.Label("_Debug log")
+            label.set_use_underline(True)
+            label.set_tooltip_text("Log with debugging information.")        
+            self._debugLogPage = self._notebook.append_page(self._debugLogWidget, label)
+            self._notebook.set_current_page(self._debugLogPage)
+        else:
+            self._notebook.remove_page(self._debugLogPage)
+
+    def _buildLogWidget(self):
+        """Build the widget for the log."""
+        alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
+
+        alignment.set_padding(padding_top = 8, padding_bottom = 8,
+                              padding_left = 16, padding_right = 16)
+
+        logScroller = gtk.ScrolledWindow()
+        # FIXME: these should be constants in common
+        logScroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                               else gtk.POLICY_AUTOMATIC,
+                               gtk.PolicyType.AUTOMATIC if pygobject
+                               else gtk.POLICY_AUTOMATIC)
+        logScroller.set_shadow_type(gtk.ShadowType.IN if pygobject
+                                    else gtk.SHADOW_IN)
+        logView = gtk.TextView()
+        logView.set_editable(False)
+        logScroller.add(logView)
+
+        logBox = gtk.VBox()
+        logBox.pack_start(logScroller, True, True, 0)
+        logBox.set_size_request(-1, 200)
+
+        alignment.add(logBox)
+
+        return (alignment, logView)
+
+    def _writeLog(self, msg, logView):
+        """Write the given message to the log."""
+        buffer = logView.get_buffer()
+        buffer.insert(buffer.get_end_iter(), msg)
+        logView.scroll_mark_onscreen(buffer.get_insert())
+
+    def _quit(self, what = None, force = False):
+        """Quit from the application."""
+        if force:
+            result=RESPONSETYPE_YES
+        else:
+            dialog = gtk.MessageDialog(type = MESSAGETYPE_QUESTION,
+                                       buttons = BUTTONSTYPE_YES_NO,
+                                       message_format =
+                                       "Are you sure to quit the logger?")
+            result = dialog.run()
+            dialog.hide()
+        
+        if result==RESPONSETYPE_YES:
+            self._statusIcon.destroy()
+            return gtk.main_quit()
+
+    def _notebookPageSwitch(self, notebook, page, page_num):
+        """Called when the current page of the notebook has changed."""
+        if page_num==0:
+            gobject.idle_add(self._wizard.grabDefault)
+        else:
+            self._mainWindow.set_default(None)
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 99)
+++ 	(revision )
@@ -1,692 +1,0 @@
-# The main file for the GUI
-
-from statusicon import StatusIcon
-from statusbar import Statusbar
-from info import FlightInfo
-from update import Updater
-from mlx.gui.common import *
-from mlx.gui.flight import Wizard
-from mlx.gui.monitor import MonitorWindow
-
-import mlx.const as const
-import mlx.fs as fs
-import mlx.flight as flight
-import mlx.logger as logger
-import mlx.acft as acft
-import mlx.web as web
-
-import time
-import threading
-import sys
-
-#------------------------------------------------------------------------------
-
-class GUI(fs.ConnectionListener):
-    """The main GUI class."""
-    @staticmethod
-    def _formatFlightLogLine(timeStr, line):
-        """Format the given line for flight logging."""
-        if timeStr is not None:
-            line = timeStr + ": " + line
-        return line + "\n"
-        
-    def __init__(self, programDirectory, config):
-        """Construct the GUI."""
-        gobject.threads_init()
-
-        self._programDirectory = programDirectory
-        self.config = config
-        self._connecting = False
-        self._reconnecting = False
-        self._connected = False
-        self._logger = logger.Logger(self)
-        self._flight = None
-        self._simulator = None
-        self._monitoring = False
-
-        self._stdioLock = threading.Lock()
-        self._stdioText = ""
-
-        self.webHandler = web.Handler()
-        self.webHandler.start()
-
-        self.toRestart = False
-
-    def build(self, iconDirectory):
-        """Build the GUI."""
-        
-        window = gtk.Window()
-        window.set_title("MAVA Logger X " + const.VERSION)
-        window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
-        window.connect("delete-event",
-                       lambda a, b: self.hideMainWindow())
-        window.connect("window-state-event", self._handleMainWindowState)
-        accelGroup = gtk.AccelGroup()
-        window.add_accel_group(accelGroup)
-
-        mainVBox = gtk.VBox()
-        window.add(mainVBox)
-
-        menuBar = self._buildMenuBar(accelGroup)
-        mainVBox.pack_start(menuBar, False, False, 0)
-
-        self._notebook = gtk.Notebook()
-        mainVBox.pack_start(self._notebook, True, True, 4)
-
-        self._wizard = Wizard(self)
-        label = gtk.Label("Fligh_t")
-        label.set_use_underline(True)
-        label.set_tooltip_text("Flight wizard")
-        self._notebook.append_page(self._wizard, label)
-
-        self._flightInfo = FlightInfo(self)
-        label = gtk.Label("Flight _info")
-        label.set_use_underline(True)
-        label.set_tooltip_text("Flight information")
-        self._notebook.append_page(self._flightInfo, label)
-        self._flightInfo.disable()
-
-        (logWidget, self._logView)  = self._buildLogWidget()
-        label = gtk.Label("_Log")
-        label.set_use_underline(True)
-        label.set_tooltip_text("The log of your flight that will be sent to the MAVA website")
-        self._notebook.append_page(logWidget, label)
-
-        (self._debugLogWidget, self._debugLogView) = self._buildLogWidget()
-        self._debugLogWidget.show_all()
-
-        mainVBox.pack_start(gtk.HSeparator(), False, False, 0)
-
-        self._statusbar = Statusbar()
-        mainVBox.pack_start(self._statusbar, False, False, 0)
-
-        self._notebook.connect("switch-page", self._notebookPageSwitch)
-
-        self._monitorWindow = MonitorWindow(self, iconDirectory)
-        self._monitorWindow.add_accel_group(accelGroup)
-        self._monitorWindowX = None
-        self._monitorWindowY = None
-        self._selfToggling = False
-
-        window.show_all()
-        self._wizard.grabDefault()
-
-        self._mainWindow = window
-
-        self._statusIcon = StatusIcon(iconDirectory, self)
-
-        self._busyCursor = gdk.Cursor(gdk.CursorType.WATCH if pygobject
-                                      else gdk.WATCH)
-
-    @property
-    def logger(self):
-        """Get the logger used by us."""
-        return self._logger
-        
-    @property
-    def simulator(self):
-        """Get the simulator used by us."""
-        return self._simulator
-        
-    @property
-    def flight(self):
-        """Get the flight being performed."""
-        return self._flight
-
-    @property
-    def bookedFlight(self):
-        """Get the booked flight selected, if any."""
-        return self._wizard.bookedFlight
-
-    @property
-    def cargoWeight(self):
-        """Get the cargo weight."""
-        return self._wizard.cargoWeight
-
-    @property
-    def zfw(self):
-        """Get Zero-Fuel Weight calculated for the current flight."""
-        return self._wizard.zfw
-        
-    @property
-    def filedCruiseAltitude(self):
-        """Get cruise altitude filed for the current flight."""
-        return self._wizard.filedCruiseAltitude
-        
-    @property
-    def cruiseAltitude(self):
-        """Get cruise altitude set for the current flight."""
-        return self._wizard.cruiseAltitude
-
-    @property
-    def route(self):
-        """Get the flight route."""
-        return self._wizard.route
-
-    @property
-    def departureMETAR(self):
-        """Get the METAR of the deprature airport."""
-        return self._wizard.departureMETAR
-        
-    @property
-    def arrivalMETAR(self):
-        """Get the METAR of the deprature airport."""
-        return self._wizard.arrivalMETAR
-
-    @property
-    def departureRunway(self):
-        """Get the name of the departure runway."""
-        return self._wizard.departureRunway
-        
-    @property
-    def sid(self):
-        """Get the SID."""
-        return self._wizard.sid
-
-    @property
-    def v1(self):
-        """Get the V1 speed calculated for the flight."""
-        return self._wizard.v1
-        
-    @property
-    def vr(self):
-        """Get the Vr speed calculated for the flight."""
-        return self._wizard.vr
-        
-    @property
-    def v2(self):
-        """Get the V2 speed calculated for the flight."""
-        return self._wizard.v2
-        
-    @property
-    def arrivalRunway(self):
-        """Get the arrival runway."""
-        return self._wizard.arrivalRunway
-
-    @property
-    def star(self):
-        """Get the STAR."""
-        return self._wizard.star
-
-    @property
-    def transition(self):
-        """Get the transition."""
-        return self._wizard.transition
-
-    @property
-    def approachType(self):
-        """Get the approach type."""
-        return self._wizard.approachType
-
-    @property
-    def vref(self):
-        """Get the Vref speed calculated for the flight."""
-        return self._wizard.vref
-        
-    @property
-    def flightType(self):
-        """Get the flight type."""
-        return self._wizard.flightType
-
-    @property
-    def online(self):
-        """Get whether the flight was online or not."""
-        return self._wizard.online
-
-    @property
-    def comments(self):
-        """Get the comments."""
-        return self._flightInfo.comments
-
-    @property
-    def flightDefects(self):
-        """Get the flight defects."""
-        return self._flightInfo.flightDefects
-
-    @property
-    def delayCodes(self):
-        """Get the delay codes."""
-        return self._flightInfo.delayCodes
-
-    def run(self):
-        """Run the GUI."""
-        if self.config.autoUpdate:
-            self._updater = Updater(self,
-                                    self._programDirectory,
-                                    self.config.updateURL,
-                                    self._mainWindow)
-            self._updater.start()
-
-        gtk.main()
-
-        self._disconnect()
-
-    def connected(self, fsType, descriptor):
-        """Called when we have connected to the simulator."""
-        self._connected = True
-        self._logger.untimedMessage("Connected to the simulator %s" % (descriptor,))
-        gobject.idle_add(self._handleConnected, fsType, descriptor)
-
-    def _handleConnected(self, fsType, descriptor):
-        """Called when the connection to the simulator has succeeded."""
-        self._statusbar.updateConnection(self._connecting, self._connected)
-        self.endBusy()
-        if not self._reconnecting:
-            self._wizard.connected(fsType, descriptor)
-        self._reconnecting = False
-
-    def connectionFailed(self):
-        """Called when the connection failed."""
-        self._logger.untimedMessage("Connection to the simulator failed")
-        gobject.idle_add(self._connectionFailed)
-
-    def _connectionFailed(self):
-        """Called when the connection failed."""
-        self.endBusy()
-        self._statusbar.updateConnection(self._connecting, self._connected)
-
-        dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                   message_format =
-                                   "Cannot connect to the simulator.",
-                                   parent = self._mainWindow)
-        dialog.format_secondary_markup("Rectify the situation, and press <b>Try again</b> "
-                                       "to try the connection again, " 
-                                       "or <b>Cancel</b> to cancel the flight.")
-        
-        dialog.add_button("_Cancel", 0)
-        dialog.add_button("_Try again", 1)
-        dialog.set_default_response(1)
-        
-        result = dialog.run()
-        dialog.hide()
-        if result == 1:
-            self.beginBusy("Connecting to the simulator.")
-            self._simulator.reconnect()
-        else:
-            self.reset()
-        
-    def disconnected(self):
-        """Called when we have disconnected from the simulator."""
-        self._connected = False
-        self._logger.untimedMessage("Disconnected from the simulator")
-
-        gobject.idle_add(self._disconnected)
-
-    def _disconnected(self):
-        """Called when we have disconnected from the simulator unexpectedly."""        
-        self._statusbar.updateConnection(self._connecting, self._connected)
-
-        dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
-                                   message_format =
-                                   "The connection to the simulator failed unexpectedly.",
-                                   parent = self._mainWindow)
-        dialog.format_secondary_markup("If the simulator has crashed, restart it "
-                                       "and restore your flight as much as possible "
-                                       "to the state it was in before the crash.\n"
-                                       "Then press <b>Reconnect</b> to reconnect.\n\n"
-                                       "If you want to cancel the flight, press <b>Cancel</b>.")
-
-        dialog.add_button("_Cancel", 0)
-        dialog.add_button("_Reconnect", 1)
-        dialog.set_default_response(1)
-
-        result = dialog.run()
-        dialog.hide()
-        if result == 1:
-            self.beginBusy("Connecting to the simulator.")
-            self._reconnecting = True
-            self._simulator.reconnect()
-        else:
-            self.reset()
-
-    def enableFlightInfo(self):
-        """Enable the flight info tab."""
-        self._flightInfo.enable()
-
-    def reset(self):
-        """Reset the GUI."""
-        self._disconnect()
-
-        self._flightInfo.reset()
-        self._flightInfo.disable()
-        self.resetFlightStatus()
-
-        self._wizard.reset()
-        self._notebook.set_current_page(0)
-
-        self._logView.get_buffer().set_text("")
-
-    def _disconnect(self):
-        """Disconnect from the simulator if connected."""
-        self.stopMonitoring()
-
-        if self._connected:
-            self._flight.simulator.disconnect()
-            self._connected = False
-
-        self._connecting = False
-        self._reconnecting = False
-        self._statusbar.updateConnection(False, False)
-            
-    def addFlightLogLine(self, timeStr, line):
-        """Write the given message line to the log."""
-        gobject.idle_add(self._writeLog,
-                         GUI._formatFlightLogLine(timeStr, line),
-                         self._logView)
-
-    def updateFlightLogLine(self, index, timeStr, line):
-        """Update the line with the given index."""
-        gobject.idle_add(self._updateFlightLogLine, index,
-                         GUI._formatFlightLogLine(timeStr, line))
-
-    def _updateFlightLogLine(self, index, line):
-        """Replace the contents of the given line in the log."""
-        buffer = self._logView.get_buffer()
-        startIter = buffer.get_iter_at_line(index)
-        endIter = buffer.get_iter_at_line(index + 1)
-        buffer.delete(startIter, endIter)
-        buffer.insert(startIter, line)
-        self._logView.scroll_mark_onscreen(buffer.get_insert())
-
-    def check(self, flight, aircraft, logger, oldState, state):
-        """Update the data."""
-        gobject.idle_add(self._monitorWindow.setData, state)
-        gobject.idle_add(self._statusbar.updateTime, state.timestamp)
-
-    def resetFlightStatus(self):
-        """Reset the status of the flight."""
-        self._statusbar.resetFlightStatus()
-        self._statusbar.updateTime()
-        self._statusIcon.resetFlightStatus()
-
-    def setStage(self, stage):
-        """Set the stage of the flight."""
-        gobject.idle_add(self._setStage, stage)
-
-    def _setStage(self, stage):
-        """Set the stage of the flight."""
-        self._statusbar.setStage(stage)
-        self._statusIcon.setStage(stage)
-        self._wizard.setStage(stage)
-        if stage==const.STAGE_END:
-            self._disconnect()
-
-    def setRating(self, rating):
-        """Set the rating of the flight."""
-        gobject.idle_add(self._setRating, rating)
-
-    def _setRating(self, rating):
-        """Set the rating of the flight."""
-        self._statusbar.setRating(rating)
-        self._statusIcon.setRating(rating)
-
-    def setNoGo(self, reason):
-        """Set the rating of the flight to No-Go with the given reason."""
-        gobject.idle_add(self._setNoGo, reason)
-
-    def _setNoGo(self, reason):
-        """Set the rating of the flight."""
-        self._statusbar.setNoGo(reason)
-        self._statusIcon.setNoGo(reason)
-
-    def _handleMainWindowState(self, window, event):
-        """Hande a change in the state of the window"""
-        iconified = gdk.WindowState.ICONIFIED if pygobject \
-                    else gdk.WINDOW_STATE_ICONIFIED
-        if (event.changed_mask&iconified)!=0 and (event.new_window_state&iconified)!=0:
-            self.hideMainWindow(savePosition = False)
-
-    def hideMainWindow(self, savePosition = True):
-        """Hide the main window and save its position."""
-        if savePosition:
-            (self._mainWindowX, self._mainWindowY) = \
-                 self._mainWindow.get_window().get_root_origin()
-        else:
-            self._mainWindowX = self._mainWindowY = None
-        self._mainWindow.hide()
-        self._statusIcon.mainWindowHidden()
-        return True
-
-    def showMainWindow(self):
-        """Show the main window at its former position."""
-        if self._mainWindowX is not None and self._mainWindowY is not None:
-            self._mainWindow.move(self._mainWindowX, self._mainWindowY)
-
-        self._mainWindow.show()
-        self._mainWindow.deiconify()
-            
-        self._statusIcon.mainWindowShown()
-
-    def toggleMainWindow(self):
-        """Toggle the main window."""
-        if self._mainWindow.get_visible():
-            self.hideMainWindow()
-        else:
-            self.showMainWindow()
-
-    def hideMonitorWindow(self, savePosition = True):
-        """Hide the monitor window."""
-        if savePosition:
-            (self._monitorWindowX, self._monitorWindowY) = \
-                 self._monitorWindow.get_window().get_root_origin()
-        else:
-            self._monitorWindowX = self._monitorWindowY = None
-        self._monitorWindow.hide()
-        self._statusIcon.monitorWindowHidden()
-        if self._showMonitorMenuItem.get_active():
-            self._selfToggling = True
-            self._showMonitorMenuItem.set_active(False)
-        return True
-
-    def showMonitorWindow(self):
-        """Show the monitor window."""
-        if self._monitorWindowX is not None and self._monitorWindowY is not None:
-            self._monitorWindow.move(self._monitorWindowX, self._monitorWindowY)
-        self._monitorWindow.show_all()
-        self._statusIcon.monitorWindowShown()
-        if not self._showMonitorMenuItem.get_active():
-            self._selfToggling = True
-            self._showMonitorMenuItem.set_active(True)
-
-    def _toggleMonitorWindow(self, menuItem):
-        if self._selfToggling:
-            self._selfToggling = False
-        elif self._monitorWindow.get_visible():
-            self.hideMonitorWindow()
-        else:
-            self.showMonitorWindow()
-
-    def restart(self):
-        """Quit and restart the application."""
-        self.toRestart = True
-        self._quit(force = True)
-
-    def flushStdIO(self):
-        """Flush any text to the standard error that could not be logged."""
-        if self._stdioText:
-            sys.__stderr__.write(self._stdioText)
-            
-    def writeStdIO(self, text):
-        """Write the given text into standard I/O log."""
-        with self._stdioLock:
-            self._stdioText += text
-
-        gobject.idle_add(self._writeStdIO)
-
-    def beginBusy(self, message):
-        """Begin a period of background processing."""
-        self._wizard.set_sensitive(False)
-        self._mainWindow.get_window().set_cursor(self._busyCursor)
-        self._statusbar.updateBusyState(message)
-
-    def endBusy(self):
-        """End a period of background processing."""
-        self._mainWindow.get_window().set_cursor(None)
-        self._wizard.set_sensitive(True)
-        self._statusbar.updateBusyState(None)
-
-    def _writeStdIO(self):
-        """Perform the real writing."""
-        with self._stdioLock:
-            text = self._stdioText
-            self._stdioText = ""
-        if not text: return
-            
-        lines = text.splitlines()
-        if text[-1]=="\n":
-            text = ""
-        else:
-            text = lines[-1]
-            lines = lines[:-1]
-            
-        for line in lines:
-            #print >> sys.__stdout__, line
-            self._writeLog(line + "\n", self._debugLogView)
-
-        if text:
-            #print >> sys.__stdout__, text,
-            self._writeLog(text, self._debugLogView)
-
-    def connectSimulator(self, aircraftType):
-        """Connect to the simulator for the first time."""
-        self._logger.reset()
-
-        self._flight = flight.Flight(self._logger, self)
-        self._flight.aircraftType = aircraftType
-        self._flight.aircraft = acft.Aircraft.create(self._flight)
-        self._flight.aircraft._checkers.append(self)
-        
-        if self._simulator is None:
-            self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
-
-        self._flight.simulator = self._simulator
-
-        self.beginBusy("Connecting to the simulator...")
-        self._statusbar.updateConnection(self._connecting, self._connected)
-
-        self._connecting = True
-        self._simulator.connect(self._flight.aircraft)        
-
-    def startMonitoring(self):
-        """Start monitoring."""
-        if not self._monitoring:
-            self.simulator.startMonitoring()
-            self._monitoring = True
-
-    def stopMonitoring(self):
-        """Stop monitoring."""
-        if self._monitoring:
-            self.simulator.stopMonitoring()
-            self._monitoring = False
-
-    def _buildMenuBar(self, accelGroup):
-        """Build the main menu bar."""
-        menuBar = gtk.MenuBar()
-        
-        fileMenuItem = gtk.MenuItem("File")
-        fileMenu = gtk.Menu()
-        fileMenuItem.set_submenu(fileMenu)
-        menuBar.append(fileMenuItem)
-
-        quitMenuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
-        quitMenuItem.set_use_stock(True)
-        quitMenuItem.add_accelerator("activate", accelGroup,
-                                     ord("q"), CONTROL_MASK,
-                                     ACCEL_VISIBLE)
-        quitMenuItem.connect("activate", self._quit)
-        fileMenu.append(quitMenuItem)
-
-
-        viewMenuItem = gtk.MenuItem("View")
-        viewMenu = gtk.Menu()
-        viewMenuItem.set_submenu(viewMenu)
-        menuBar.append(viewMenuItem)
-
-        self._showMonitorMenuItem = gtk.CheckMenuItem()
-        self._showMonitorMenuItem.set_label("Show _monitor window")
-        self._showMonitorMenuItem.set_use_underline(True)
-        self._showMonitorMenuItem.set_active(False)
-        self._showMonitorMenuItem.add_accelerator("activate", accelGroup,
-                                                  ord("m"), CONTROL_MASK,
-                                                  ACCEL_VISIBLE)
-        self._showMonitorMenuItem.connect("toggled", self._toggleMonitorWindow)
-        viewMenu.append(self._showMonitorMenuItem)
-
-        showDebugMenuItem = gtk.CheckMenuItem()
-        showDebugMenuItem.set_label("Show _debug log")
-        showDebugMenuItem.set_use_underline(True)
-        showDebugMenuItem.set_active(False)
-        showDebugMenuItem.add_accelerator("activate", accelGroup,
-                                          ord("d"), CONTROL_MASK,
-                                          ACCEL_VISIBLE)
-        showDebugMenuItem.connect("toggled", self._toggleDebugLog)
-        viewMenu.append(showDebugMenuItem)
-
-        return menuBar
-
-    def _toggleDebugLog(self, menuItem):
-        """Toggle the debug log."""
-        if menuItem.get_active():
-            label = gtk.Label("_Debug log")
-            label.set_use_underline(True)
-            label.set_tooltip_text("Log with debugging information.")        
-            self._debugLogPage = self._notebook.append_page(self._debugLogWidget, label)
-            self._notebook.set_current_page(self._debugLogPage)
-        else:
-            self._notebook.remove_page(self._debugLogPage)
-
-    def _buildLogWidget(self):
-        """Build the widget for the log."""
-        alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
-
-        alignment.set_padding(padding_top = 8, padding_bottom = 8,
-                              padding_left = 16, padding_right = 16)
-
-        logScroller = gtk.ScrolledWindow()
-        # FIXME: these should be constants in common
-        logScroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                               else gtk.POLICY_AUTOMATIC,
-                               gtk.PolicyType.AUTOMATIC if pygobject
-                               else gtk.POLICY_AUTOMATIC)
-        logScroller.set_shadow_type(gtk.ShadowType.IN if pygobject
-                                    else gtk.SHADOW_IN)
-        logView = gtk.TextView()
-        logView.set_editable(False)
-        logScroller.add(logView)
-
-        logBox = gtk.VBox()
-        logBox.pack_start(logScroller, True, True, 0)
-        logBox.set_size_request(-1, 200)
-
-        alignment.add(logBox)
-
-        return (alignment, logView)
-
-    def _writeLog(self, msg, logView):
-        """Write the given message to the log."""
-        buffer = logView.get_buffer()
-        buffer.insert(buffer.get_end_iter(), msg)
-        logView.scroll_mark_onscreen(buffer.get_insert())
-
-    def _quit(self, what = None, force = False):
-        """Quit from the application."""
-        if force:
-            result=RESPONSETYPE_YES
-        else:
-            dialog = gtk.MessageDialog(type = MESSAGETYPE_QUESTION,
-                                       buttons = BUTTONSTYPE_YES_NO,
-                                       message_format =
-                                       "Are you sure to quit the logger?")
-            result = dialog.run()
-            dialog.hide()
-        
-        if result==RESPONSETYPE_YES:
-            self._statusIcon.destroy()
-            return gtk.main_quit()
-
-    def _notebookPageSwitch(self, notebook, page, page_num):
-        """Called when the current page of the notebook has changed."""
-        if page_num==0:
-            gobject.idle_add(self._wizard.grabDefault)
-        else:
-            self._mainWindow.set_default(None)
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 99)
+++ src/mlx/gui/info.py	(revision 99)
@@ -0,0 +1,157 @@
+#The Flight Info tab
+
+from common import *
+
+import mlx.const as const
+
+class FlightInfo(gtk.VBox):
+    """The flight info tab."""
+    _delayCodes = [ (const.DELAYCODE_LOADING, "L_oading problems"),
+                    (const.DELAYCODE_VATSIM, "_VATSIM problem"),
+                    (const.DELAYCODE_NETWORK, "_Net problems"),
+                    (const.DELAYCODE_CONTROLLER, "Controller's _fault"),
+                    (const.DELAYCODE_SYSTEM, "S_ystem crash/freeze"),
+                    (const.DELAYCODE_NAVIGATION, "Navi_gation problem"),
+                    (const.DELAYCODE_TRAFFIC, "T_raffic problems"),
+                    (const.DELAYCODE_APRON, "_Apron navigation problem"),
+                    (const.DELAYCODE_WEATHER, "_Weather problems"),
+                    (const.DELAYCODE_PERSONAL, "_Personal reasons") ]
+    
+    @staticmethod
+    def _createCommentArea(label):
+        """Create a comment area.
+
+        Returns a tuple of two items:
+        - the top-level widget of the comment area, and
+        - the comment text editor."""
+
+        frame = gtk.Frame(label = label)
+        label = frame.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()
+        # FIXME: these should be constants
+        scroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
+                            else gtk.POLICY_AUTOMATIC,
+                            gtk.PolicyType.AUTOMATIC if pygobject
+                            else gtk.POLICY_AUTOMATIC)
+        scroller.set_shadow_type(gtk.ShadowType.IN if pygobject
+                                 else gtk.SHADOW_IN)
+        comments = gtk.TextView()
+        scroller.add(comments)
+        alignment.add(scroller)
+        frame.add(alignment)
+
+        label.set_mnemonic_widget(comments)
+
+        return (frame, comments)
+
+    def __init__(self, gui):
+        """Construct the flight info tab."""
+        super(FlightInfo, self).__init__()
+        self._gui = gui
+
+        self._commentsAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                                xscale = 1.0, yscale = 1.0)
+        commentsBox = gtk.HBox()
+
+        (frame, self._comments) = FlightInfo._createCommentArea("_Comments")
+        commentsBox.pack_start(frame, True, True, 8)
+
+        (frame, self._flightDefects) = FlightInfo._createCommentArea("Flight _defects")
+        commentsBox.pack_start(frame, True, True, 8)
+
+        self._commentsAlignment.add(commentsBox)
+        self.pack_start(self._commentsAlignment, True, True, 8)
+
+        frame = gtk.Frame(label = "Delay codes")
+        label = frame.get_label_widget()
+        label.set_use_underline(True)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                  xscale = 0.0, yscale = 0.0)
+        alignment.set_padding(padding_top = 4, padding_bottom = 4,
+                              padding_left = 8, padding_right = 8)
+
+        table = gtk.Table(5, 2)
+        table.set_col_spacings(16)
+
+        row = 0
+        column = 0
+
+        self._delayCodeWidgets = []
+        for (_code, label) in FlightInfo._delayCodes:
+            button = gtk.CheckButton(label)
+            button.set_use_underline(True)
+            table.attach(button, column, column + 1, row, row + 1)
+            self._delayCodeWidgets.append(button)
+            if column==0:
+                column += 1
+            else:
+                row += 1
+                column = 0
+
+        alignment.add(table)
+        frame.add(alignment)
+
+        self._delayAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
+                                             xscale = 0.0, yscale = 0.0)
+        self._delayAlignment.add(frame)
+
+        self.pack_start(self._delayAlignment, False, False, 8)
+
+    @property
+    def comments(self):
+        """Get the comments."""
+        buffer = self._comments.get_buffer()
+        return text2unicode(buffer.get_text(buffer.get_start_iter(),
+                                            buffer.get_end_iter(), True))
+    
+    @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))
+
+    @property
+    def delayCodes(self):
+        """Get the list of delay codes checked by the user."""
+        codes =  []
+        for index in range(0, len(FlightInfo._delayCodes)):
+            if self._delayCodeWidgets[index].get_active():
+                codes.append(FlightInfo._delayCodes[index][0])
+        return codes
+            
+    def enable(self):
+        """Enable the flight info tab."""
+        #gobject.idle_add(self.set_sensitive, True)
+        self._commentsAlignment.set_sensitive(True)
+        self._delayAlignment.set_sensitive(True)
+        
+    def disable(self):
+        """Enable the flight info tab."""
+        #gobject.idle_add(self.set_sensitive, False)
+        self._commentsAlignment.set_sensitive(False)
+        self._delayAlignment.set_sensitive(False)
+
+    def reset(self):
+        """Reset the flight info tab."""
+        self._comments.get_buffer().set_text("")
+        self._flightDefects.get_buffer().set_text("")
+
+        self._loadingProblems.set_active(False)
+        self._vatsimProblem.set_active(False)
+        self._netProblems.set_active(False)
+        self._controllersFault.set_active(False)
+        self._systemCrash.set_active(False)
+        self._navigationProblem.set_active(False)
+        self._trafficProblems.set_active(False)
+        self._apronProblem.set_active(False)
+        self._weatherProblems.set_active(False)
+        self._personalReasons.set_active(False)
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 99)
+++ 	(revision )
@@ -1,157 +1,0 @@
-#The Flight Info tab
-
-from common import *
-
-import mlx.const as const
-
-class FlightInfo(gtk.VBox):
-    """The flight info tab."""
-    _delayCodes = [ (const.DELAYCODE_LOADING, "L_oading problems"),
-                    (const.DELAYCODE_VATSIM, "_VATSIM problem"),
-                    (const.DELAYCODE_NETWORK, "_Net problems"),
-                    (const.DELAYCODE_CONTROLLER, "Controller's _fault"),
-                    (const.DELAYCODE_SYSTEM, "S_ystem crash/freeze"),
-                    (const.DELAYCODE_NAVIGATION, "Navi_gation problem"),
-                    (const.DELAYCODE_TRAFFIC, "T_raffic problems"),
-                    (const.DELAYCODE_APRON, "_Apron navigation problem"),
-                    (const.DELAYCODE_WEATHER, "_Weather problems"),
-                    (const.DELAYCODE_PERSONAL, "_Personal reasons") ]
-    
-    @staticmethod
-    def _createCommentArea(label):
-        """Create a comment area.
-
-        Returns a tuple of two items:
-        - the top-level widget of the comment area, and
-        - the comment text editor."""
-
-        frame = gtk.Frame(label = label)
-        label = frame.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()
-        # FIXME: these should be constants
-        scroller.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
-                            else gtk.POLICY_AUTOMATIC,
-                            gtk.PolicyType.AUTOMATIC if pygobject
-                            else gtk.POLICY_AUTOMATIC)
-        scroller.set_shadow_type(gtk.ShadowType.IN if pygobject
-                                 else gtk.SHADOW_IN)
-        comments = gtk.TextView()
-        scroller.add(comments)
-        alignment.add(scroller)
-        frame.add(alignment)
-
-        label.set_mnemonic_widget(comments)
-
-        return (frame, comments)
-
-    def __init__(self, gui):
-        """Construct the flight info tab."""
-        super(FlightInfo, self).__init__()
-        self._gui = gui
-
-        self._commentsAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                                xscale = 1.0, yscale = 1.0)
-        commentsBox = gtk.HBox()
-
-        (frame, self._comments) = FlightInfo._createCommentArea("_Comments")
-        commentsBox.pack_start(frame, True, True, 8)
-
-        (frame, self._flightDefects) = FlightInfo._createCommentArea("Flight _defects")
-        commentsBox.pack_start(frame, True, True, 8)
-
-        self._commentsAlignment.add(commentsBox)
-        self.pack_start(self._commentsAlignment, True, True, 8)
-
-        frame = gtk.Frame(label = "Delay codes")
-        label = frame.get_label_widget()
-        label.set_use_underline(True)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                  xscale = 0.0, yscale = 0.0)
-        alignment.set_padding(padding_top = 4, padding_bottom = 4,
-                              padding_left = 8, padding_right = 8)
-
-        table = gtk.Table(5, 2)
-        table.set_col_spacings(16)
-
-        row = 0
-        column = 0
-
-        self._delayCodeWidgets = []
-        for (_code, label) in FlightInfo._delayCodes:
-            button = gtk.CheckButton(label)
-            button.set_use_underline(True)
-            table.attach(button, column, column + 1, row, row + 1)
-            self._delayCodeWidgets.append(button)
-            if column==0:
-                column += 1
-            else:
-                row += 1
-                column = 0
-
-        alignment.add(table)
-        frame.add(alignment)
-
-        self._delayAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
-                                             xscale = 0.0, yscale = 0.0)
-        self._delayAlignment.add(frame)
-
-        self.pack_start(self._delayAlignment, False, False, 8)
-
-    @property
-    def comments(self):
-        """Get the comments."""
-        buffer = self._comments.get_buffer()
-        return text2unicode(buffer.get_text(buffer.get_start_iter(),
-                                            buffer.get_end_iter(), True))
-    
-    @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))
-
-    @property
-    def delayCodes(self):
-        """Get the list of delay codes checked by the user."""
-        codes =  []
-        for index in range(0, len(FlightInfo._delayCodes)):
-            if self._delayCodeWidgets[index].get_active():
-                codes.append(FlightInfo._delayCodes[index][0])
-        return codes
-            
-    def enable(self):
-        """Enable the flight info tab."""
-        #gobject.idle_add(self.set_sensitive, True)
-        self._commentsAlignment.set_sensitive(True)
-        self._delayAlignment.set_sensitive(True)
-        
-    def disable(self):
-        """Enable the flight info tab."""
-        #gobject.idle_add(self.set_sensitive, False)
-        self._commentsAlignment.set_sensitive(False)
-        self._delayAlignment.set_sensitive(False)
-
-    def reset(self):
-        """Reset the flight info tab."""
-        self._comments.get_buffer().set_text("")
-        self._flightDefects.get_buffer().set_text("")
-
-        self._loadingProblems.set_active(False)
-        self._vatsimProblem.set_active(False)
-        self._netProblems.set_active(False)
-        self._controllersFault.set_active(False)
-        self._systemCrash.set_active(False)
-        self._navigationProblem.set_active(False)
-        self._trafficProblems.set_active(False)
-        self._apronProblem.set_active(False)
-        self._weatherProblems.set_active(False)
-        self._personalReasons.set_active(False)
Index: src/mlx/gui/monitor.py
===================================================================
--- src/mlx/gui/monitor.py	(revision 89)
+++ src/mlx/gui/monitor.py	(revision 89)
@@ -0,0 +1,315 @@
+# The monitoring window
+
+from mlx.gui.common import *
+
+import mlx.const as const
+import mlx.util as util
+
+import time
+
+#------------------------------------------------------------------------------
+
+class MonitorWindow(gtk.Window):
+    """The window for the data monitor."""
+    def __init__(self, gui, iconDirectory):
+        """Construct the monitor window."""
+        super(MonitorWindow, self).__init__()
+        
+        self._gui = gui
+
+        self.set_title("MAVA Logger X " + const.VERSION + " - Data Monitor")
+        self.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
+        self.connect("delete-event",
+                     lambda a, b: self._gui.hideMonitorWindow())
+
+        alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
+
+        alignment.set_padding(padding_top = 4, padding_bottom = 10,
+                              padding_left = 16, padding_right = 16)
+
+        table = gtk.Table(rows = 7, columns = 12)
+        table.set_homogeneous(False)
+        table.set_row_spacings(4)
+        table.set_col_spacings(8)
+
+        (label, self._timestamp) = self._createLabeledEntry("Time:")
+        table.attach(label, 0, 1, 0, 1)
+        table.attach(self._timestamp, 1, 2, 0, 1)
+
+        self._paused = gtk.Label("PAUSED")
+        table.attach(self._paused, 2, 4, 0, 1)
+        
+        self._trickMode = gtk.Label("TRICKMODE")
+        table.attach(self._trickMode, 4, 6, 0, 1, xoptions = 0)
+        
+        self._overspeed = gtk.Label("OVERSPEED")
+        table.attach(self._overspeed, 6, 8, 0, 1)
+        
+        self._stalled = gtk.Label("STALLED")
+        table.attach(self._stalled, 8, 10, 0, 1)
+        
+        self._onTheGround = gtk.Label("ONTHEGROUND")
+        table.attach(self._onTheGround, 10, 12, 0, 1)
+        
+        (label, self._zfw) = self._createLabeledEntry("ZFW:", 6)
+        table.attach(label, 0, 1, 1, 2)
+        table.attach(self._zfw, 1, 2, 1, 2)
+
+        (label, self._grossWeight) = self._createLabeledEntry("Weight:", 6)
+        table.attach(label, 2, 3, 1, 2)
+        table.attach(self._grossWeight, 3, 4, 1, 2)
+
+        (label, self._heading) = self._createLabeledEntry("Heading:", 3)
+        table.attach(label, 4, 5, 1, 2)
+        table.attach(self._heading, 5, 6, 1, 2)
+
+        (label, self._pitch) = self._createLabeledEntry("Pitch:", 3)
+        table.attach(label, 6, 7, 1, 2)
+        table.attach(self._pitch, 7, 8, 1, 2)
+
+        (label, self._bank) = self._createLabeledEntry("Bank:", 3)
+        table.attach(label, 8, 9, 1, 2)
+        table.attach(self._bank, 9, 10, 1, 2)
+
+        (label, self._vs) = self._createLabeledEntry("VS:", 5)
+        table.attach(label, 10, 11, 1, 2)
+        table.attach(self._vs, 11, 12, 1, 2)
+
+        (label, self._ias) = self._createLabeledEntry("IAS:", 4)
+        table.attach(label, 0, 1, 2, 3)
+        table.attach(self._ias, 1, 2, 2, 3)
+
+        (label, self._mach) = self._createLabeledEntry("Mach:", 4)
+        table.attach(label, 2, 3, 2, 3)
+        table.attach(self._mach, 3, 4, 2, 3)
+
+        (label, self._groundSpeed) = self._createLabeledEntry("GS:", 4)
+        table.attach(label, 4, 5, 2, 3)
+        table.attach(self._groundSpeed, 5, 6, 2, 3)
+
+        (label, self._radioAltitude) = self._createLabeledEntry("Radio alt.:", 6)
+        table.attach(label, 6, 7, 2, 3)
+        table.attach(self._radioAltitude, 7, 8, 2, 3)
+
+        (label, self._altitude) = self._createLabeledEntry("Altitude:", 6)
+        table.attach(label, 8, 9, 2, 3)
+        table.attach(self._altitude, 9, 10, 2, 3)
+
+        (label, self._gLoad) = self._createLabeledEntry("G-Load:", 4)
+        table.attach(label, 10, 11, 2, 3)
+        table.attach(self._gLoad, 11, 12, 2, 3)
+
+        (label, self._flapsSet) = self._createLabeledEntry("Flaps set:", 2)
+        table.attach(label, 0, 1, 3, 4)
+        table.attach(self._flapsSet, 1, 2, 3, 4)
+
+        (label, self._flaps) = self._createLabeledEntry("Flaps:", 2)
+        table.attach(label, 2, 3, 3, 4)
+        table.attach(self._flaps, 3, 4, 3, 4)
+
+        (label, self._altimeter) = self._createLabeledEntry("Altimeter:", 4)
+        table.attach(label, 4, 5, 3, 4)
+        table.attach(self._altimeter, 5, 6, 3, 4)
+
+        (label, self._squawk) = self._createLabeledEntry("Squawk:", 4)
+        table.attach(label, 6, 7, 3, 4)
+        table.attach(self._squawk, 7, 8, 3, 4)
+
+        (label, self._nav1) = self._createLabeledEntry("NAV1:", 5)
+        table.attach(label, 8, 9, 3, 4)
+        table.attach(self._nav1, 9, 10, 3, 4)
+
+        (label, self._nav2) = self._createLabeledEntry("NAV2:", 5)
+        table.attach(label, 10, 11, 3, 4)
+        table.attach(self._nav2, 11, 12, 3, 4)
+
+        (label, self._fuel) = self._createLabeledEntry("Fuel:", 40, xalign = 0.0)
+        table.attach(label, 0, 1, 4, 5)
+        table.attach(self._fuel, 1, 4, 4, 5)
+
+        (label, self._n1) = self._createLabeledEntry("N1/RPM:", 20, xalign = 0.0)
+        table.attach(label, 4, 5, 4, 5)
+        table.attach(self._n1, 5, 8, 4, 5)
+
+        (label, self._reverser) = self._createLabeledEntry("Reverser:", 20, xalign = 0.0)
+        table.attach(label, 8, 9, 4, 5)
+        table.attach(self._reverser, 9, 12, 4, 5)
+
+        self._navLightsOn = gtk.Label("NAV")
+        table.attach(self._navLightsOn, 0, 1, 5, 6)
+
+        self._antiCollisionLightsOn = gtk.Label("ANTICOLLISION")
+        table.attach(self._antiCollisionLightsOn, 1, 3, 5, 6)
+
+        self._strobeLightsOn = gtk.Label("STROBE")
+        table.attach(self._strobeLightsOn, 3, 4, 5, 6)
+
+        self._landingLightsOn = gtk.Label("LANDING")
+        table.attach(self._landingLightsOn, 4, 5, 5, 6)
+
+        self._pitotHeatOn = gtk.Label("PITOT HEAT")
+        table.attach(self._pitotHeatOn, 5, 7, 5, 6)
+
+        self._parking = gtk.Label("PARKING")
+        table.attach(self._parking, 7, 8, 5, 6)
+
+        self._gearsDown = gtk.Label("GEARS DOWN")
+        table.attach(self._gearsDown, 8, 10, 5, 6)
+
+        self._spoilersArmed = gtk.Label("SPOILERS ARMED")
+        table.attach(self._spoilersArmed, 10, 12, 5, 6)
+
+        (label, self._spoilersExtension) = self._createLabeledEntry("Spoilers:", 3)
+        table.attach(label, 0, 1, 6, 7)
+        table.attach(self._spoilersExtension, 1, 2, 6, 7)
+
+        (label, self._windSpeed) = self._createLabeledEntry("Wind speed:", 3)
+        table.attach(label, 2, 3, 6, 7)
+        table.attach(self._windSpeed, 3, 4, 6, 7)
+
+        (label, self._windDirection) = self._createLabeledEntry("Wind from:", 3)
+        table.attach(label, 4, 5, 6, 7)
+        table.attach(self._windDirection, 5, 6, 6, 7)
+
+        (label, self._position) = self._createLabeledEntry("Position:", 25)
+        table.attach(label, 6, 7, 6, 7)
+        table.attach(self._position, 7, 10, 6, 7)
+
+        alignment.add(table)
+
+        self.add(alignment)
+
+        self.setData()
+
+    def _createLabeledEntry(self, label, width = 8, xalign = 1.0):
+        """Create a labeled entry.
+
+        Return a tuple consisting of:
+        - the box
+        - the entry."""
+        
+        alignment = gtk.Alignment(xalign = 1.0, yalign = 0.5, xscale = 1.0)
+        alignment.set_padding(padding_top = 0, padding_bottom = 0,
+                              padding_left = 0, padding_right = 16)
+        alignment.add(gtk.Label(label))
+
+        entry = gtk.Entry()
+        entry.set_editable(False)
+        entry.set_width_chars(width)
+        entry.set_max_length(width)
+        entry.set_alignment(xalign)
+
+        return (alignment, entry)
+
+    def setData(self, aircraftState = None):
+        """Set the data.
+
+        If aircraftState is None, everything will be set to its default."""
+        if aircraftState is None:
+            self._timestamp.set_text("--:--:--")
+            self._paused.set_sensitive(False)
+            self._trickMode.set_sensitive(False)
+            self._overspeed.set_sensitive(False)
+            self._stalled.set_sensitive(False)
+            self._onTheGround.set_sensitive(False)
+            self._zfw.set_text("-")
+            self._grossWeight.set_text("-")
+            self._heading.set_text("-")
+            self._pitch.set_text("-")
+            self._bank.set_text("-")
+            self._vs.set_text("-")
+            self._ias.set_text("-")
+            self._mach.set_text("-")
+            self._groundSpeed.set_text("-")
+            self._radioAltitude.set_text("-")
+            self._altitude.set_text("-")
+            self._gLoad.set_text("-")
+            self._flapsSet.set_text("-")
+            self._flaps.set_text("-")
+            self._altimeter.set_text("-")
+            self._squawk.set_text("-")
+            self._nav1.set_text("-")
+            self._nav2.set_text("-")
+            self._fuel.set_text("-")
+            self._n1.set_text("-")
+            self._reverser.set_text("-")
+            self._navLightsOn.set_sensitive(False)
+            self._antiCollisionLightsOn.set_sensitive(False)
+            self._strobeLightsOn.set_sensitive(False)
+            self._landingLightsOn.set_sensitive(False)
+            self._pitotHeatOn.set_sensitive(False)
+            self._parking.set_sensitive(False)
+            self._gearsDown.set_sensitive(False)
+            self._spoilersArmed.set_sensitive(False)
+            self._spoilersExtension.set_text("-")
+            self._windSpeed.set_text("-")
+            self._windDirection.set_text("-")
+            self._position.set_text("-")
+        else:
+            self._timestamp.set_text(time.strftime("%H:%M:%S",
+                                                   time.gmtime(aircraftState.timestamp)))
+            self._paused.set_sensitive(aircraftState.paused)
+            self._trickMode.set_sensitive(aircraftState.trickMode)
+            self._overspeed.set_sensitive(aircraftState.overspeed)
+            self._stalled.set_sensitive(aircraftState.stalled)
+            self._onTheGround.set_sensitive(aircraftState.onTheGround)
+            self._zfw.set_text("%.0f" % (aircraftState.zfw,))
+            self._grossWeight.set_text("%.0f" % (aircraftState.grossWeight,))
+            self._heading.set_text("%03.0f" % (aircraftState.heading,))
+            self._pitch.set_text("%.0f" % (aircraftState.pitch,))
+            self._bank.set_text("%.0f" % (aircraftState.bank,))
+            self._vs.set_text("%.0f" % (aircraftState.vs,))
+            self._ias.set_text("%.0f" % (aircraftState.ias,))
+            self._mach.set_text("%.2f" % (aircraftState.mach,))
+            self._groundSpeed.set_text("%.0f" % (aircraftState.groundSpeed,))
+            self._radioAltitude.set_text("%.0f" % (aircraftState.radioAltitude,))
+            self._altitude.set_text("%.0f" % (aircraftState.altitude,))
+            self._gLoad.set_text("%.2f" % (aircraftState.gLoad,))
+            self._flapsSet.set_text("%.0f" % (aircraftState.flapsSet,))
+            self._flaps.set_text("%.0f" % (aircraftState.flaps,))
+            self._altimeter.set_text("%.0f" % (aircraftState.altimeter,))
+            self._squawk.set_text(aircraftState.squawk)
+            self._nav1.set_text(aircraftState.nav1)
+            self._nav2.set_text(aircraftState.nav2)
+
+            fuelStr = ""
+            for fuel in aircraftState.fuel:
+                if fuelStr: fuelStr += ", "
+                fuelStr += "%.0f" % (fuel,)                
+            self._fuel.set_text(fuelStr)
+
+            if hasattr(aircraftState, "n1"):
+                n1Str = ""
+                for n1 in aircraftState.n1:
+                    if n1Str: n1Str += ", "
+                    n1Str += "%.0f" % (n1,)
+            elif hasattr(aircraftState, "rpm"):
+                n1Str = ""
+                for rpm in aircraftState.rpm:
+                    if n1Str: n1Str += ", "
+                    n1Str += "%.0f" % (rpm,)
+            else:
+                n1Str = "-"
+            self._n1.set_text(n1Str)
+
+            reverserStr = ""
+            for reverser in aircraftState.reverser:
+                if reverserStr: reverserStr += ", "
+                reverserStr += "ON" if reverser else "OFF"
+            self._reverser.set_text(reverserStr)
+
+            self._navLightsOn.set_sensitive(aircraftState.navLightsOn)
+            self._antiCollisionLightsOn.set_sensitive(aircraftState.antiCollisionLightsOn)
+            self._strobeLightsOn.set_sensitive(aircraftState.strobeLightsOn)
+            self._landingLightsOn.set_sensitive(aircraftState.landingLightsOn)
+            self._pitotHeatOn.set_sensitive(aircraftState.pitotHeatOn)
+            self._parking.set_sensitive(aircraftState.parking)
+            self._gearsDown.set_sensitive(aircraftState.gearsDown)
+            self._spoilersArmed.set_sensitive(aircraftState.spoilersArmed)
+            self._spoilersExtension.set_text("%.0f" % (aircraftState.spoilersExtension,))
+            self._windSpeed.set_text("%.0f" % (aircraftState.windSpeed,))
+            self._windDirection.set_text("%03.0f" % (aircraftState.windDirection,))
+            self._position.set_text(util.getCoordinateString((aircraftState.latitude,
+                                                              aircraftState.longitude)))
+
+#------------------------------------------------------------------------------
Index: src/mlx/gui/monitor.py
===================================================================
--- src/mlx/gui/monitor.py	(revision 89)
+++ 	(revision )
@@ -1,315 +1,0 @@
-# The monitoring window
-
-from mlx.gui.common import *
-
-import mlx.const as const
-import mlx.util as util
-
-import time
-
-#------------------------------------------------------------------------------
-
-class MonitorWindow(gtk.Window):
-    """The window for the data monitor."""
-    def __init__(self, gui, iconDirectory):
-        """Construct the monitor window."""
-        super(MonitorWindow, self).__init__()
-        
-        self._gui = gui
-
-        self.set_title("MAVA Logger X " + const.VERSION + " - Data Monitor")
-        self.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
-        self.connect("delete-event",
-                     lambda a, b: self._gui.hideMonitorWindow())
-
-        alignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
-
-        alignment.set_padding(padding_top = 4, padding_bottom = 10,
-                              padding_left = 16, padding_right = 16)
-
-        table = gtk.Table(rows = 7, columns = 12)
-        table.set_homogeneous(False)
-        table.set_row_spacings(4)
-        table.set_col_spacings(8)
-
-        (label, self._timestamp) = self._createLabeledEntry("Time:")
-        table.attach(label, 0, 1, 0, 1)
-        table.attach(self._timestamp, 1, 2, 0, 1)
-
-        self._paused = gtk.Label("PAUSED")
-        table.attach(self._paused, 2, 4, 0, 1)
-        
-        self._trickMode = gtk.Label("TRICKMODE")
-        table.attach(self._trickMode, 4, 6, 0, 1, xoptions = 0)
-        
-        self._overspeed = gtk.Label("OVERSPEED")
-        table.attach(self._overspeed, 6, 8, 0, 1)
-        
-        self._stalled = gtk.Label("STALLED")
-        table.attach(self._stalled, 8, 10, 0, 1)
-        
-        self._onTheGround = gtk.Label("ONTHEGROUND")
-        table.attach(self._onTheGround, 10, 12, 0, 1)
-        
-        (label, self._zfw) = self._createLabeledEntry("ZFW:", 6)
-        table.attach(label, 0, 1, 1, 2)
-        table.attach(self._zfw, 1, 2, 1, 2)
-
-        (label, self._grossWeight) = self._createLabeledEntry("Weight:", 6)
-        table.attach(label, 2, 3, 1, 2)
-        table.attach(self._grossWeight, 3, 4, 1, 2)
-
-        (label, self._heading) = self._createLabeledEntry("Heading:", 3)
-        table.attach(label, 4, 5, 1, 2)
-        table.attach(self._heading, 5, 6, 1, 2)
-
-        (label, self._pitch) = self._createLabeledEntry("Pitch:", 3)
-        table.attach(label, 6, 7, 1, 2)
-        table.attach(self._pitch, 7, 8, 1, 2)
-
-        (label, self._bank) = self._createLabeledEntry("Bank:", 3)
-        table.attach(label, 8, 9, 1, 2)
-        table.attach(self._bank, 9, 10, 1, 2)
-
-        (label, self._vs) = self._createLabeledEntry("VS:", 5)
-        table.attach(label, 10, 11, 1, 2)
-        table.attach(self._vs, 11, 12, 1, 2)
-
-        (label, self._ias) = self._createLabeledEntry("IAS:", 4)
-        table.attach(label, 0, 1, 2, 3)
-        table.attach(self._ias, 1, 2, 2, 3)
-
-        (label, self._mach) = self._createLabeledEntry("Mach:", 4)
-        table.attach(label, 2, 3, 2, 3)
-        table.attach(self._mach, 3, 4, 2, 3)
-
-        (label, self._groundSpeed) = self._createLabeledEntry("GS:", 4)
-        table.attach(label, 4, 5, 2, 3)
-        table.attach(self._groundSpeed, 5, 6, 2, 3)
-
-        (label, self._radioAltitude) = self._createLabeledEntry("Radio alt.:", 6)
-        table.attach(label, 6, 7, 2, 3)
-        table.attach(self._radioAltitude, 7, 8, 2, 3)
-
-        (label, self._altitude) = self._createLabeledEntry("Altitude:", 6)
-        table.attach(label, 8, 9, 2, 3)
-        table.attach(self._altitude, 9, 10, 2, 3)
-
-        (label, self._gLoad) = self._createLabeledEntry("G-Load:", 4)
-        table.attach(label, 10, 11, 2, 3)
-        table.attach(self._gLoad, 11, 12, 2, 3)
-
-        (label, self._flapsSet) = self._createLabeledEntry("Flaps set:", 2)
-        table.attach(label, 0, 1, 3, 4)
-        table.attach(self._flapsSet, 1, 2, 3, 4)
-
-        (label, self._flaps) = self._createLabeledEntry("Flaps:", 2)
-        table.attach(label, 2, 3, 3, 4)
-        table.attach(self._flaps, 3, 4, 3, 4)
-
-        (label, self._altimeter) = self._createLabeledEntry("Altimeter:", 4)
-        table.attach(label, 4, 5, 3, 4)
-        table.attach(self._altimeter, 5, 6, 3, 4)
-
-        (label, self._squawk) = self._createLabeledEntry("Squawk:", 4)
-        table.attach(label, 6, 7, 3, 4)
-        table.attach(self._squawk, 7, 8, 3, 4)
-
-        (label, self._nav1) = self._createLabeledEntry("NAV1:", 5)
-        table.attach(label, 8, 9, 3, 4)
-        table.attach(self._nav1, 9, 10, 3, 4)
-
-        (label, self._nav2) = self._createLabeledEntry("NAV2:", 5)
-        table.attach(label, 10, 11, 3, 4)
-        table.attach(self._nav2, 11, 12, 3, 4)
-
-        (label, self._fuel) = self._createLabeledEntry("Fuel:", 40, xalign = 0.0)
-        table.attach(label, 0, 1, 4, 5)
-        table.attach(self._fuel, 1, 4, 4, 5)
-
-        (label, self._n1) = self._createLabeledEntry("N1/RPM:", 20, xalign = 0.0)
-        table.attach(label, 4, 5, 4, 5)
-        table.attach(self._n1, 5, 8, 4, 5)
-
-        (label, self._reverser) = self._createLabeledEntry("Reverser:", 20, xalign = 0.0)
-        table.attach(label, 8, 9, 4, 5)
-        table.attach(self._reverser, 9, 12, 4, 5)
-
-        self._navLightsOn = gtk.Label("NAV")
-        table.attach(self._navLightsOn, 0, 1, 5, 6)
-
-        self._antiCollisionLightsOn = gtk.Label("ANTICOLLISION")
-        table.attach(self._antiCollisionLightsOn, 1, 3, 5, 6)
-
-        self._strobeLightsOn = gtk.Label("STROBE")
-        table.attach(self._strobeLightsOn, 3, 4, 5, 6)
-
-        self._landingLightsOn = gtk.Label("LANDING")
-        table.attach(self._landingLightsOn, 4, 5, 5, 6)
-
-        self._pitotHeatOn = gtk.Label("PITOT HEAT")
-        table.attach(self._pitotHeatOn, 5, 7, 5, 6)
-
-        self._parking = gtk.Label("PARKING")
-        table.attach(self._parking, 7, 8, 5, 6)
-
-        self._gearsDown = gtk.Label("GEARS DOWN")
-        table.attach(self._gearsDown, 8, 10, 5, 6)
-
-        self._spoilersArmed = gtk.Label("SPOILERS ARMED")
-        table.attach(self._spoilersArmed, 10, 12, 5, 6)
-
-        (label, self._spoilersExtension) = self._createLabeledEntry("Spoilers:", 3)
-        table.attach(label, 0, 1, 6, 7)
-        table.attach(self._spoilersExtension, 1, 2, 6, 7)
-
-        (label, self._windSpeed) = self._createLabeledEntry("Wind speed:", 3)
-        table.attach(label, 2, 3, 6, 7)
-        table.attach(self._windSpeed, 3, 4, 6, 7)
-
-        (label, self._windDirection) = self._createLabeledEntry("Wind from:", 3)
-        table.attach(label, 4, 5, 6, 7)
-        table.attach(self._windDirection, 5, 6, 6, 7)
-
-        (label, self._position) = self._createLabeledEntry("Position:", 25)
-        table.attach(label, 6, 7, 6, 7)
-        table.attach(self._position, 7, 10, 6, 7)
-
-        alignment.add(table)
-
-        self.add(alignment)
-
-        self.setData()
-
-    def _createLabeledEntry(self, label, width = 8, xalign = 1.0):
-        """Create a labeled entry.
-
-        Return a tuple consisting of:
-        - the box
-        - the entry."""
-        
-        alignment = gtk.Alignment(xalign = 1.0, yalign = 0.5, xscale = 1.0)
-        alignment.set_padding(padding_top = 0, padding_bottom = 0,
-                              padding_left = 0, padding_right = 16)
-        alignment.add(gtk.Label(label))
-
-        entry = gtk.Entry()
-        entry.set_editable(False)
-        entry.set_width_chars(width)
-        entry.set_max_length(width)
-        entry.set_alignment(xalign)
-
-        return (alignment, entry)
-
-    def setData(self, aircraftState = None):
-        """Set the data.
-
-        If aircraftState is None, everything will be set to its default."""
-        if aircraftState is None:
-            self._timestamp.set_text("--:--:--")
-            self._paused.set_sensitive(False)
-            self._trickMode.set_sensitive(False)
-            self._overspeed.set_sensitive(False)
-            self._stalled.set_sensitive(False)
-            self._onTheGround.set_sensitive(False)
-            self._zfw.set_text("-")
-            self._grossWeight.set_text("-")
-            self._heading.set_text("-")
-            self._pitch.set_text("-")
-            self._bank.set_text("-")
-            self._vs.set_text("-")
-            self._ias.set_text("-")
-            self._mach.set_text("-")
-            self._groundSpeed.set_text("-")
-            self._radioAltitude.set_text("-")
-            self._altitude.set_text("-")
-            self._gLoad.set_text("-")
-            self._flapsSet.set_text("-")
-            self._flaps.set_text("-")
-            self._altimeter.set_text("-")
-            self._squawk.set_text("-")
-            self._nav1.set_text("-")
-            self._nav2.set_text("-")
-            self._fuel.set_text("-")
-            self._n1.set_text("-")
-            self._reverser.set_text("-")
-            self._navLightsOn.set_sensitive(False)
-            self._antiCollisionLightsOn.set_sensitive(False)
-            self._strobeLightsOn.set_sensitive(False)
-            self._landingLightsOn.set_sensitive(False)
-            self._pitotHeatOn.set_sensitive(False)
-            self._parking.set_sensitive(False)
-            self._gearsDown.set_sensitive(False)
-            self._spoilersArmed.set_sensitive(False)
-            self._spoilersExtension.set_text("-")
-            self._windSpeed.set_text("-")
-            self._windDirection.set_text("-")
-            self._position.set_text("-")
-        else:
-            self._timestamp.set_text(time.strftime("%H:%M:%S",
-                                                   time.gmtime(aircraftState.timestamp)))
-            self._paused.set_sensitive(aircraftState.paused)
-            self._trickMode.set_sensitive(aircraftState.trickMode)
-            self._overspeed.set_sensitive(aircraftState.overspeed)
-            self._stalled.set_sensitive(aircraftState.stalled)
-            self._onTheGround.set_sensitive(aircraftState.onTheGround)
-            self._zfw.set_text("%.0f" % (aircraftState.zfw,))
-            self._grossWeight.set_text("%.0f" % (aircraftState.grossWeight,))
-            self._heading.set_text("%03.0f" % (aircraftState.heading,))
-            self._pitch.set_text("%.0f" % (aircraftState.pitch,))
-            self._bank.set_text("%.0f" % (aircraftState.bank,))
-            self._vs.set_text("%.0f" % (aircraftState.vs,))
-            self._ias.set_text("%.0f" % (aircraftState.ias,))
-            self._mach.set_text("%.2f" % (aircraftState.mach,))
-            self._groundSpeed.set_text("%.0f" % (aircraftState.groundSpeed,))
-            self._radioAltitude.set_text("%.0f" % (aircraftState.radioAltitude,))
-            self._altitude.set_text("%.0f" % (aircraftState.altitude,))
-            self._gLoad.set_text("%.2f" % (aircraftState.gLoad,))
-            self._flapsSet.set_text("%.0f" % (aircraftState.flapsSet,))
-            self._flaps.set_text("%.0f" % (aircraftState.flaps,))
-            self._altimeter.set_text("%.0f" % (aircraftState.altimeter,))
-            self._squawk.set_text(aircraftState.squawk)
-            self._nav1.set_text(aircraftState.nav1)
-            self._nav2.set_text(aircraftState.nav2)
-
-            fuelStr = ""
-            for fuel in aircraftState.fuel:
-                if fuelStr: fuelStr += ", "
-                fuelStr += "%.0f" % (fuel,)                
-            self._fuel.set_text(fuelStr)
-
-            if hasattr(aircraftState, "n1"):
-                n1Str = ""
-                for n1 in aircraftState.n1:
-                    if n1Str: n1Str += ", "
-                    n1Str += "%.0f" % (n1,)
-            elif hasattr(aircraftState, "rpm"):
-                n1Str = ""
-                for rpm in aircraftState.rpm:
-                    if n1Str: n1Str += ", "
-                    n1Str += "%.0f" % (rpm,)
-            else:
-                n1Str = "-"
-            self._n1.set_text(n1Str)
-
-            reverserStr = ""
-            for reverser in aircraftState.reverser:
-                if reverserStr: reverserStr += ", "
-                reverserStr += "ON" if reverser else "OFF"
-            self._reverser.set_text(reverserStr)
-
-            self._navLightsOn.set_sensitive(aircraftState.navLightsOn)
-            self._antiCollisionLightsOn.set_sensitive(aircraftState.antiCollisionLightsOn)
-            self._strobeLightsOn.set_sensitive(aircraftState.strobeLightsOn)
-            self._landingLightsOn.set_sensitive(aircraftState.landingLightsOn)
-            self._pitotHeatOn.set_sensitive(aircraftState.pitotHeatOn)
-            self._parking.set_sensitive(aircraftState.parking)
-            self._gearsDown.set_sensitive(aircraftState.gearsDown)
-            self._spoilersArmed.set_sensitive(aircraftState.spoilersArmed)
-            self._spoilersExtension.set_text("%.0f" % (aircraftState.spoilersExtension,))
-            self._windSpeed.set_text("%.0f" % (aircraftState.windSpeed,))
-            self._windDirection.set_text("%03.0f" % (aircraftState.windDirection,))
-            self._position.set_text(util.getCoordinateString((aircraftState.latitude,
-                                                              aircraftState.longitude)))
-
-#------------------------------------------------------------------------------
Index: src/mlx/gui/statusbar.py
===================================================================
--- src/mlx/gui/statusbar.py	(revision 80)
+++ src/mlx/gui/statusbar.py	(revision 80)
@@ -0,0 +1,135 @@
+# Implementation of the status bar.
+
+#-------------------------------------------------------------------------------
+
+from common import *
+
+import mlx.const as const
+
+import math
+import time
+
+#-------------------------------------------------------------------------------
+
+class Statusbar(gtk.Frame, FlightStatusHandler):
+    """A status bar for the logger."""
+    def __init__(self):
+        """Construct the status bar."""
+        gtk.Frame.__init__(self)
+        FlightStatusHandler.__init__(self)
+
+        self._connecting = False
+        self._connected = False
+        
+        self.set_shadow_type(gtk.ShadowType.NONE if pygobject
+                             else gtk.SHADOW_NONE)
+
+        frameAlignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
+
+        frameAlignment.set_padding(padding_top = 2, padding_bottom = 2,
+                                   padding_left = 16, padding_right = 16)
+        self.add(frameAlignment)
+
+        statusBox = gtk.HBox()
+        frameAlignment.add(statusBox)
+
+        self._connStateArea = gtk.DrawingArea()
+        self._connStateArea.set_size_request(16, 16)
+        self._connStateArea.set_tooltip_markup('The state of the connection.\n'
+                                               '<span foreground="grey">Grey</span> means idle.\n'
+                                               '<span foreground="red">Red</span> means trying to connect.\n'
+                                               '<span foreground="green">Green</span> means connected.')
+
+        if pygobject:
+            self._connStateArea.connect("draw", self._drawConnState)
+        else:
+            self._connStateArea.connect("expose_event", self._drawConnState)
+
+        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5)
+        alignment.add(self._connStateArea)        
+
+        statusBox.pack_start(alignment, False, False, 8)
+
+        statusBox.pack_start(gtk.VSeparator(), False, False, 8)
+
+        self._stageLabel = gtk.Label()
+        self._stageLabel.set_width_chars(20)
+        self._stageLabel.set_tooltip_text("The flight stage")
+        self._stageLabel.set_alignment(0.0, 0.5)
+        
+        statusBox.pack_start(self._stageLabel, False, False, 8)
+
+        statusBox.pack_start(gtk.VSeparator(), False, False, 8)
+
+        self._timeLabel = gtk.Label("--:--:--")
+        self._timeLabel.set_width_chars(8)
+        self._timeLabel.set_tooltip_text("The simulator time in UTC")
+        self._timeLabel.set_alignment(1.0, 0.5)
+        
+        statusBox.pack_start(self._timeLabel, False, False, 8)
+
+        statusBox.pack_start(gtk.VSeparator(), False, False, 8)
+
+        self._ratingLabel = gtk.Label()
+        self._ratingLabel.set_width_chars(12)
+        self._ratingLabel.set_tooltip_text("The flight rating")
+        self._ratingLabel.set_alignment(0.0, 0.5)
+        
+        statusBox.pack_start(self._ratingLabel, False, False, 8)
+
+        self._busyLabel = gtk.Label()
+        self._busyLabel.set_width_chars(30)
+        self._busyLabel.set_tooltip_text("The status of the background tasks.")
+        self._busyLabel.set_alignment(1.0, 0.5)
+        statusBox.pack_start(self._busyLabel, True, True, 8)
+        
+        self._updateFlightStatus()
+        self.updateTime()
+
+    def updateConnection(self, connecting, connected):
+        """Update the connection status."""
+        self._connecting = connecting
+        self._connected = connected
+        self._connStateArea.queue_draw()
+
+    def updateBusyState(self, message):
+        """Update the busy state."""
+        self._busyLabel.set_text("" if message is None else message)
+
+    def updateTime(self, t = None):
+        """Update the time"""
+        timeStr = "--:--:--" if t is None \
+                  else time.strftime("%H:%M:%S", time.gmtime(t))
+        
+        self._timeLabel.set_text(timeStr)
+
+    def _drawConnState(self, connStateArea, eventOrContext):
+        """Draw the connection state."""        
+        context = eventOrContext if pygobject else connStateArea.window.cairo_create()
+
+        if self._connecting:
+            if self._connected:
+                context.set_source_rgb(0.0, 1.0, 0.0)
+            else:
+                context.set_source_rgb(1.0, 0.0, 0.0)
+        else:
+            context.set_source_rgb(0.75, 0.75, 0.75)
+
+        width = connStateArea.get_allocated_width() if pygobject \
+                else connStateArea.allocation.width
+        height = connStateArea.get_allocated_height() if pygobject \
+                 else connStateArea.allocation.height
+        context.arc(width/2, height/2, width/2, 0, 2*math.pi)
+
+        context.fill()
+
+    def _updateFlightStatus(self):
+        """Update the flight status information."""
+        self._stageLabel.set_text("-" if self._stage is None
+                                  else const.stage2string(self._stage).upper())
+    
+        if self._noGoReason is None:
+            rating = "%.0f%%" % (self._rating,)
+        else:
+            rating = '<span foreground="red">' + self._noGoReason + '</span>'
+        self._ratingLabel.set_markup(rating)
Index: src/mlx/gui/statusbar.py
===================================================================
--- src/mlx/gui/statusbar.py	(revision 80)
+++ 	(revision )
@@ -1,135 +1,0 @@
-# Implementation of the status bar.
-
-#-------------------------------------------------------------------------------
-
-from common import *
-
-import mlx.const as const
-
-import math
-import time
-
-#-------------------------------------------------------------------------------
-
-class Statusbar(gtk.Frame, FlightStatusHandler):
-    """A status bar for the logger."""
-    def __init__(self):
-        """Construct the status bar."""
-        gtk.Frame.__init__(self)
-        FlightStatusHandler.__init__(self)
-
-        self._connecting = False
-        self._connected = False
-        
-        self.set_shadow_type(gtk.ShadowType.NONE if pygobject
-                             else gtk.SHADOW_NONE)
-
-        frameAlignment = gtk.Alignment(xscale = 1.0, yscale = 1.0)
-
-        frameAlignment.set_padding(padding_top = 2, padding_bottom = 2,
-                                   padding_left = 16, padding_right = 16)
-        self.add(frameAlignment)
-
-        statusBox = gtk.HBox()
-        frameAlignment.add(statusBox)
-
-        self._connStateArea = gtk.DrawingArea()
-        self._connStateArea.set_size_request(16, 16)
-        self._connStateArea.set_tooltip_markup('The state of the connection.\n'
-                                               '<span foreground="grey">Grey</span> means idle.\n'
-                                               '<span foreground="red">Red</span> means trying to connect.\n'
-                                               '<span foreground="green">Green</span> means connected.')
-
-        if pygobject:
-            self._connStateArea.connect("draw", self._drawConnState)
-        else:
-            self._connStateArea.connect("expose_event", self._drawConnState)
-
-        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5)
-        alignment.add(self._connStateArea)        
-
-        statusBox.pack_start(alignment, False, False, 8)
-
-        statusBox.pack_start(gtk.VSeparator(), False, False, 8)
-
-        self._stageLabel = gtk.Label()
-        self._stageLabel.set_width_chars(20)
-        self._stageLabel.set_tooltip_text("The flight stage")
-        self._stageLabel.set_alignment(0.0, 0.5)
-        
-        statusBox.pack_start(self._stageLabel, False, False, 8)
-
-        statusBox.pack_start(gtk.VSeparator(), False, False, 8)
-
-        self._timeLabel = gtk.Label("--:--:--")
-        self._timeLabel.set_width_chars(8)
-        self._timeLabel.set_tooltip_text("The simulator time in UTC")
-        self._timeLabel.set_alignment(1.0, 0.5)
-        
-        statusBox.pack_start(self._timeLabel, False, False, 8)
-
-        statusBox.pack_start(gtk.VSeparator(), False, False, 8)
-
-        self._ratingLabel = gtk.Label()
-        self._ratingLabel.set_width_chars(12)
-        self._ratingLabel.set_tooltip_text("The flight rating")
-        self._ratingLabel.set_alignment(0.0, 0.5)
-        
-        statusBox.pack_start(self._ratingLabel, False, False, 8)
-
-        self._busyLabel = gtk.Label()
-        self._busyLabel.set_width_chars(30)
-        self._busyLabel.set_tooltip_text("The status of the background tasks.")
-        self._busyLabel.set_alignment(1.0, 0.5)
-        statusBox.pack_start(self._busyLabel, True, True, 8)
-        
-        self._updateFlightStatus()
-        self.updateTime()
-
-    def updateConnection(self, connecting, connected):
-        """Update the connection status."""
-        self._connecting = connecting
-        self._connected = connected
-        self._connStateArea.queue_draw()
-
-    def updateBusyState(self, message):
-        """Update the busy state."""
-        self._busyLabel.set_text("" if message is None else message)
-
-    def updateTime(self, t = None):
-        """Update the time"""
-        timeStr = "--:--:--" if t is None \
-                  else time.strftime("%H:%M:%S", time.gmtime(t))
-        
-        self._timeLabel.set_text(timeStr)
-
-    def _drawConnState(self, connStateArea, eventOrContext):
-        """Draw the connection state."""        
-        context = eventOrContext if pygobject else connStateArea.window.cairo_create()
-
-        if self._connecting:
-            if self._connected:
-                context.set_source_rgb(0.0, 1.0, 0.0)
-            else:
-                context.set_source_rgb(1.0, 0.0, 0.0)
-        else:
-            context.set_source_rgb(0.75, 0.75, 0.75)
-
-        width = connStateArea.get_allocated_width() if pygobject \
-                else connStateArea.allocation.width
-        height = connStateArea.get_allocated_height() if pygobject \
-                 else connStateArea.allocation.height
-        context.arc(width/2, height/2, width/2, 0, 2*math.pi)
-
-        context.fill()
-
-    def _updateFlightStatus(self):
-        """Update the flight status information."""
-        self._stageLabel.set_text("-" if self._stage is None
-                                  else const.stage2string(self._stage).upper())
-    
-        if self._noGoReason is None:
-            rating = "%.0f%%" % (self._rating,)
-        else:
-            rating = '<span foreground="red">' + self._noGoReason + '</span>'
-        self._ratingLabel.set_markup(rating)
Index: src/mlx/gui/statusicon.py
===================================================================
--- src/mlx/gui/statusicon.py	(revision 77)
+++ src/mlx/gui/statusicon.py	(revision 77)
@@ -0,0 +1,159 @@
+# Implementation of the status icon
+
+#-------------------------------------------------------------------------------
+
+from common import *
+
+import mlx.const as const
+
+#-------------------------------------------------------------------------------
+
+class StatusIcon(FlightStatusHandler):
+    """The class handling the status icon."""
+    def __init__(self, iconDirectory, gui):
+        """Construct the status icon."""
+        super(StatusIcon, self).__init__()
+
+        self._gui = gui
+        self._selfToggling = False
+
+        menu = gtk.Menu()
+
+        if appIndicator:
+            self._stageMenuItem = gtk.MenuItem()
+            self._stageMenuItem.show()
+            menu.append(self._stageMenuItem)
+
+            self._ratingMenuItem = gtk.MenuItem()
+            self._ratingMenuItem.show()
+            menu.append(self._ratingMenuItem)
+
+            separator = gtk.SeparatorMenuItem()
+            separator.show()
+            menu.append(separator)
+
+        self._showHideMenuItem = gtk.CheckMenuItem()  
+        self._showHideMenuItem.set_label("Show main window")  
+        self._showHideMenuItem.set_active(True)
+        self._showHideMenuItem.connect("toggled", self._showHideToggled)
+        self._showHideMenuItem.show()  
+        menu.append(self._showHideMenuItem)  
+
+        self._showMonitorMenuItem = gtk.CheckMenuItem()  
+        self._showMonitorMenuItem.set_label("Show monitor window")  
+        self._showMonitorMenuItem.set_active(False)
+        self._showMonitorMenuItem.connect("toggled", self._showMonitorToggled)
+        self._showMonitorMenuItem.show()  
+        menu.append(self._showMonitorMenuItem)  
+
+        separator = gtk.SeparatorMenuItem()
+        separator.show()
+        menu.append(separator)
+
+        self._quitMenuItem = gtk.MenuItem()  
+        self._quitMenuItem.set_label("Quit")  
+        self._quitMenuItem.show()  
+        self._quitMenuItem.connect("activate", self._gui._quit)
+        menu.append(self._quitMenuItem)  
+
+        menu.show()  
+
+        iconFile = os.path.join(iconDirectory, "logo.ico")
+
+        if appIndicator:
+            if pygobject:
+                indicator = appindicator.Indicator.new ("mava-logger-x", iconFile,
+                                                        appindicator.IndicatorCategory.APPLICATION_STATUS)
+                indicator.set_status (appindicator.IndicatorStatus.ACTIVE)
+            else:
+                indicator = appindicator.Indicator ("mava-logger-x", iconFile,
+                                                    appindicator.CATEGORY_APPLICATION_STATUS)
+                indicator.set_status (appindicator.STATUS_ACTIVE)
+
+            indicator.set_menu(menu)
+            self._indicator = indicator
+        else:
+            def popup_menu(status, button, time):
+                menu.popup(None, None, gtk.status_icon_position_menu,
+                           button, time, status)
+
+            statusIcon = gtk.StatusIcon()
+            statusIcon.set_from_file(iconFile)
+            statusIcon.set_visible(True)
+            statusIcon.connect('popup-menu', popup_menu)
+            statusIcon.connect('activate',
+                               lambda status: self._gui.toggleMainWindow())
+            self._statusIcon = statusIcon
+
+        self._updateFlightStatus()
+
+    def mainWindowHidden(self):
+        """Called when the main window is hidden."""
+        if self._showHideMenuItem.get_active():
+            self._selfToggling = True
+            self._showHideMenuItem.set_active(False)
+
+    def mainWindowShown(self):
+        """Called when the main window is shown."""
+        if not self._showHideMenuItem.get_active():
+            self._selfToggling = True
+            self._showHideMenuItem.set_active(True)
+
+    def monitorWindowHidden(self):
+        """Called when the monitor window is hidden."""
+        if self._showMonitorMenuItem.get_active():
+            self._selfToggling = True
+            self._showMonitorMenuItem.set_active(False)
+
+    def monitorWindowShown(self):
+        """Called when the monitor window is shown."""
+        if not self._showMonitorMenuItem.get_active():
+            self._selfToggling = True
+            self._showMonitorMenuItem.set_active(True)
+
+    def destroy(self):
+        """Hide and destroy the status icon."""
+        if appIndicator:
+            if pygobject:
+                self._indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
+            else:
+                self._indicator.set_status(appindicator.STATUS_PASSIVE)
+        else:
+            self._statusIcon.set_visible(False)
+        
+    def _showHideToggled(self, menuitem):
+        """Called when the show/hide menu item is toggled."""
+        if self._selfToggling:
+            self._selfToggling = False
+        elif self._showHideMenuItem.get_active():
+            self._gui.showMainWindow()
+        else:
+            self._gui.hideMainWindow()
+
+    def _showMonitorToggled(self, menuitem):
+        """Called when the show/hide monitor window menu item is toggled."""
+        if self._selfToggling:
+            self._selfToggling = False
+        elif self._showMonitorMenuItem.get_active():
+            self._gui.showMonitorWindow()
+        else:
+            self._gui.hideMonitorWindow()
+
+    def _updateFlightStatus(self):
+        """Update the flight status."""
+        stage = "-" if self._stage is None else const.stage2string(self._stage)
+        
+        if self._noGoReason is None:
+            rating = "%.0f%%" % (self._rating,)
+        else:
+            rating = self._noGoReason
+
+        if appIndicator:
+            self._stageMenuItem.set_label("Stage: %s" % (stage,))
+            self._ratingMenuItem.set_label("Rating: %s" % (rating,))
+        else:
+            if self._noGoReason is not None:
+                rating = '<span foreground="red">' + rating + '</span>'
+            markup = "MAVA Logger X %s\n\nStage: %s\nRating: %s" %\
+                     (const.VERSION, stage, rating)
+            self._statusIcon.set_tooltip_markup(markup)
Index: src/mlx/gui/statusicon.py
===================================================================
--- src/mlx/gui/statusicon.py	(revision 77)
+++ 	(revision )
@@ -1,159 +1,0 @@
-# Implementation of the status icon
-
-#-------------------------------------------------------------------------------
-
-from common import *
-
-import mlx.const as const
-
-#-------------------------------------------------------------------------------
-
-class StatusIcon(FlightStatusHandler):
-    """The class handling the status icon."""
-    def __init__(self, iconDirectory, gui):
-        """Construct the status icon."""
-        super(StatusIcon, self).__init__()
-
-        self._gui = gui
-        self._selfToggling = False
-
-        menu = gtk.Menu()
-
-        if appIndicator:
-            self._stageMenuItem = gtk.MenuItem()
-            self._stageMenuItem.show()
-            menu.append(self._stageMenuItem)
-
-            self._ratingMenuItem = gtk.MenuItem()
-            self._ratingMenuItem.show()
-            menu.append(self._ratingMenuItem)
-
-            separator = gtk.SeparatorMenuItem()
-            separator.show()
-            menu.append(separator)
-
-        self._showHideMenuItem = gtk.CheckMenuItem()  
-        self._showHideMenuItem.set_label("Show main window")  
-        self._showHideMenuItem.set_active(True)
-        self._showHideMenuItem.connect("toggled", self._showHideToggled)
-        self._showHideMenuItem.show()  
-        menu.append(self._showHideMenuItem)  
-
-        self._showMonitorMenuItem = gtk.CheckMenuItem()  
-        self._showMonitorMenuItem.set_label("Show monitor window")  
-        self._showMonitorMenuItem.set_active(False)
-        self._showMonitorMenuItem.connect("toggled", self._showMonitorToggled)
-        self._showMonitorMenuItem.show()  
-        menu.append(self._showMonitorMenuItem)  
-
-        separator = gtk.SeparatorMenuItem()
-        separator.show()
-        menu.append(separator)
-
-        self._quitMenuItem = gtk.MenuItem()  
-        self._quitMenuItem.set_label("Quit")  
-        self._quitMenuItem.show()  
-        self._quitMenuItem.connect("activate", self._gui._quit)
-        menu.append(self._quitMenuItem)  
-
-        menu.show()  
-
-        iconFile = os.path.join(iconDirectory, "logo.ico")
-
-        if appIndicator:
-            if pygobject:
-                indicator = appindicator.Indicator.new ("mava-logger-x", iconFile,
-                                                        appindicator.IndicatorCategory.APPLICATION_STATUS)
-                indicator.set_status (appindicator.IndicatorStatus.ACTIVE)
-            else:
-                indicator = appindicator.Indicator ("mava-logger-x", iconFile,
-                                                    appindicator.CATEGORY_APPLICATION_STATUS)
-                indicator.set_status (appindicator.STATUS_ACTIVE)
-
-            indicator.set_menu(menu)
-            self._indicator = indicator
-        else:
-            def popup_menu(status, button, time):
-                menu.popup(None, None, gtk.status_icon_position_menu,
-                           button, time, status)
-
-            statusIcon = gtk.StatusIcon()
-            statusIcon.set_from_file(iconFile)
-            statusIcon.set_visible(True)
-            statusIcon.connect('popup-menu', popup_menu)
-            statusIcon.connect('activate',
-                               lambda status: self._gui.toggleMainWindow())
-            self._statusIcon = statusIcon
-
-        self._updateFlightStatus()
-
-    def mainWindowHidden(self):
-        """Called when the main window is hidden."""
-        if self._showHideMenuItem.get_active():
-            self._selfToggling = True
-            self._showHideMenuItem.set_active(False)
-
-    def mainWindowShown(self):
-        """Called when the main window is shown."""
-        if not self._showHideMenuItem.get_active():
-            self._selfToggling = True
-            self._showHideMenuItem.set_active(True)
-
-    def monitorWindowHidden(self):
-        """Called when the monitor window is hidden."""
-        if self._showMonitorMenuItem.get_active():
-            self._selfToggling = True
-            self._showMonitorMenuItem.set_active(False)
-
-    def monitorWindowShown(self):
-        """Called when the monitor window is shown."""
-        if not self._showMonitorMenuItem.get_active():
-            self._selfToggling = True
-            self._showMonitorMenuItem.set_active(True)
-
-    def destroy(self):
-        """Hide and destroy the status icon."""
-        if appIndicator:
-            if pygobject:
-                self._indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
-            else:
-                self._indicator.set_status(appindicator.STATUS_PASSIVE)
-        else:
-            self._statusIcon.set_visible(False)
-        
-    def _showHideToggled(self, menuitem):
-        """Called when the show/hide menu item is toggled."""
-        if self._selfToggling:
-            self._selfToggling = False
-        elif self._showHideMenuItem.get_active():
-            self._gui.showMainWindow()
-        else:
-            self._gui.hideMainWindow()
-
-    def _showMonitorToggled(self, menuitem):
-        """Called when the show/hide monitor window menu item is toggled."""
-        if self._selfToggling:
-            self._selfToggling = False
-        elif self._showMonitorMenuItem.get_active():
-            self._gui.showMonitorWindow()
-        else:
-            self._gui.hideMonitorWindow()
-
-    def _updateFlightStatus(self):
-        """Update the flight status."""
-        stage = "-" if self._stage is None else const.stage2string(self._stage)
-        
-        if self._noGoReason is None:
-            rating = "%.0f%%" % (self._rating,)
-        else:
-            rating = self._noGoReason
-
-        if appIndicator:
-            self._stageMenuItem.set_label("Stage: %s" % (stage,))
-            self._ratingMenuItem.set_label("Rating: %s" % (rating,))
-        else:
-            if self._noGoReason is not None:
-                rating = '<span foreground="red">' + rating + '</span>'
-            markup = "MAVA Logger X %s\n\nStage: %s\nRating: %s" %\
-                     (const.VERSION, stage, rating)
-            self._statusIcon.set_tooltip_markup(markup)
Index: src/mlx/gui/update.py
===================================================================
--- src/mlx/gui/update.py	(revision 38)
+++ src/mlx/gui/update.py	(revision 38)
@@ -0,0 +1,286 @@
+# The GUI part of the update
+
+#-------------------------------------------------------------------------------
+
+from mlx.gui.common import *
+
+from mlx.update import update
+
+import mlx.const as const
+
+import threading
+import os
+import sys
+
+#-------------------------------------------------------------------------------
+
+class Updater(threading.Thread):
+    """The updater thread."""
+
+    # The removal or renaming of one file equals to the downloading of this
+    # many bytes in time (for the progress calculation)
+    REMOVE2BYTES = 100
+
+    _progressWindow = None
+
+    _progressLabel = None
+    
+    _progressBar = None
+    
+    _progressOKButton = None
+
+    _sudoDialog = None
+
+    @staticmethod
+    def _createGUI(parentWindow):
+        """Create the GUI elements, if needed."""
+        if Updater._progressWindow is not None:
+            return
+
+        Updater._progressWindow = window = gtk.Window()
+        window.set_title("MAVA Logger X " + const.VERSION + " Update")
+        window.set_transient_for(parentWindow)
+        #win.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
+        window.set_size_request(400, -1)
+        window.set_resizable(False)
+        window.set_modal(True)
+        window.connect("delete-event", lambda a, b: True)
+        window.set_deletable(False)
+        window.set_position(gtk.WindowPosition.CENTER_ON_PARENT if pygobject
+                            else gtk.WIN_POS_CENTER_ON_PARENT)
+
+        mainAlignment = gtk.Alignment(xscale = 1.0)
+        mainAlignment.set_padding(padding_top = 4, padding_bottom = 10,
+                                  padding_left = 16, padding_right = 16)
+        window.add(mainAlignment)
+
+        mainVBox = gtk.VBox()
+        mainAlignment.add(mainVBox)
+
+        labelAlignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
+        Updater._progressLabel = progressLabel = gtk.Label()
+        labelAlignment.add(progressLabel)
+        mainVBox.pack_start(labelAlignment, True, True, 4)
+        
+        Updater._progressBar = progressBar = gtk.ProgressBar()
+        mainVBox.pack_start(progressBar, True, True, 4)
+
+        buttonAlignment = gtk.Alignment(xalign = 0.5, xscale = 0.1)
+        Updater._progressOKButton = progressOKButton = gtk.Button("OK")
+        buttonAlignment.add(progressOKButton)        
+        mainVBox.pack_start(buttonAlignment, True, True, 4)
+
+        Updater._sudoDialog = sudoDialog = \
+            gtk.Dialog("MAVA Logger X " + const.VERSION + " Update",
+                       parentWindow,
+                       gtk.DialogFlags.MODAL if pygobject else gtk.DIALOG_MODAL,
+                       (gtk.STOCK_CANCEL, 0,
+                        gtk.STOCK_OK, 1))
+
+        infoLabelAlignment = gtk.Alignment(xalign = 0.5, xscale = 0.1)
+        infoLabelAlignment.set_padding(padding_top = 4, padding_bottom = 10,
+                                       padding_left = 16, padding_right = 16)
+
+        infoLabel = gtk.Label("There is an update available, but the program cannot write\n"
+                              "its directory due to insufficient privileges.\n\n"
+                              "Click OK, if you want to run a helper program\n"
+                              "with administrator privileges "
+                              "to complete the update,\n"
+                              "Cancel otherwise.")
+        infoLabel.set_justify(gtk.Justification.CENTER if pygobject
+                              else gtk.JUSTIFY_CENTER)
+        infoLabelAlignment.add(infoLabel)
+        sudoDialog.vbox.pack_start(infoLabelAlignment, True, True, 4)
+
+        sudoDialog.set_position(gtk.WindowPosition.CENTER_ON_PARENT if pygobject
+                                else gtk.WIN_POS_CENTER_ON_PARENT)
+
+    def __init__(self, gui, programDirectory, updateURL, parentWindow):
+        """Construct the updater. If not created yet, the windows used by the
+        updater are also created."""
+        super(Updater, self).__init__()
+
+        self._gui = gui
+        
+        self._programDirectory = programDirectory
+        self._updateURL = updateURL
+
+        self._totalProgress = 0
+        self._waitAfterFinish = False
+        self._restart = False
+
+        self._sudoReply = None
+        self._sudoCondition = threading.Condition()
+
+        Updater._createGUI(parentWindow)
+
+    def run(self):
+        """Execute the thread's operation."""
+        gobject.idle_add(self._startUpdate)
+        update(self._programDirectory, self._updateURL, self, fromGUI = True)
+        if not self._waitAfterFinish:
+            gobject.idle_add(self._progressWindow.hide)
+
+    def downloadingManifest(self):
+        """Called when the downloading of the manifest has started."""
+        gobject.idle_add(self._downloadingManifest)
+
+    def _downloadingManifest(self):
+        """Called when the downloading of the manifest has started."""
+        self._progressLabel.set_text("Downloading manifest...")
+        self._progressBar.set_fraction(0)
+
+    def downloadedManifest(self):
+        """Called when the downloading of the manifest has finished."""
+        gobject.idle_add(self._downloadedManifest)
+
+    def _downloadedManifest(self):
+        """Called when the downloading of the manifest has finished."""
+        self._progressLabel.set_text("Downloaded manifest...")
+        self._progressBar.set_fraction(0.05)
+
+    def needSudo(self):
+        """Called when the program is interested in whether we want to run a
+        program with administrator rights to do the update."""
+        gobject.idle_add(self._needSudo)
+        with self._sudoCondition:
+            while self._sudoReply is None:
+                self._sudoCondition.wait(1)
+            return self._sudoReply
+
+    def _needSudo(self):
+        """Called when the program is interested in whether we want to run a
+        program with administrator rights to do the update."""
+        self._sudoDialog.show_all()
+        result = self._sudoDialog.run()
+        self._sudoDialog.hide()
+        with self._sudoCondition:
+            self._sudoReply = result!=0
+            self._sudoCondition.notify()
+        
+    def setTotalSize(self, numToModifyAndNew, totalSize, numToRemove,
+                     numToRemoveLocal):
+        """Called when the downloading of the files has started."""
+        self._numToModifyAndNew = numToModifyAndNew
+        self._numModifiedOrNew = 0
+        self._totalSize = totalSize
+        self._downloaded = 0
+        self._numToRemove = numToRemove
+        self._numToRemoveLocal = numToRemoveLocal
+        self._numRemoved = 0
+
+        self._totalProgress = self._totalSize + \
+                              (self._numToModifyAndNew + \
+                               self._numToRemove + self._numToRemoveLocal) * \
+                              Updater.REMOVE2BYTES
+        self._waitAfterFinish = self._totalSize > 0 or self._numToRemove > 0
+
+    def _startDownload(self):
+        """Called when the download has started."""
+        self._progressLabel.set_text("Downloading files...")
+
+    def setDownloaded(self, downloaded):
+        """Called when a certain number of bytes are downloaded."""
+        self._downloaded = downloaded
+        gobject.idle_add(self._setDownloaded, downloaded)
+
+    def _setDownloaded(self, downloaded):
+        """Called when a certain number of bytes are downloaded."""
+        self._progressLabel.set_text("Downloaded %d of %d" % \
+                                     (downloaded, self._totalSize))
+        self._setProgress()
+
+    def startRenaming(self):
+        """Called when the renaming of files has started."""
+        gobject.idle_add(self._startRenaming)
+
+    def _startRenaming(self):
+        """Called when the renaming of files has started."""
+        self._progressLabel.set_text("Renaming downloaded files...")
+
+    def renamed(self, path, count):
+        """Called when a file has been renamed."""
+        self._numModifiedOrNew = count
+        gobject.idle_add(self._renamed, path, count)
+
+    def _renamed(self, path, count):
+        """Called when a file has been renamed."""
+        self._progressLabel.set_text("Renamed %s" % (path,))
+        self._setProgress()
+
+    def startRemoving(self):
+        """Called when the removing of files has started."""
+        gobject.idle_add(self._startRemoving)
+
+    def _startRemoving(self):
+        """Called when the removing of files has started."""
+        self._progressLabel.set_text("Removing files...")
+
+    def removed(self, path, count):
+        """Called when a file has been removed."""
+        self._numRemoved = count
+        gobject.idle_add(self._removed, path, count)
+
+    def _removed(self, path, count):
+        """Called when a file has been removed."""
+        self._progressLabel.set_text("Removed %s" % (path,))
+        self._setProgress()
+
+    def writingManifest(self):
+        """Called when the writing of the new manifest file has started."""
+        gobject.idle_add(self._writingManifest)
+
+    def _writingManifest(self):
+        """Called when the writing of the new manifest file has started."""
+        self._progressLabel.set_text("Writing the new manifest")
+        
+    def done(self):
+        """Called when the update has been done."""
+        gobject.idle_add(self._done)
+        self._restart = self._waitAfterFinish
+
+    def _done(self):
+        """Called when the writing of the new manifest file has started."""
+        self._progressBar.set_fraction(1)
+        if self._totalProgress>0:
+            self._progressLabel.set_text("Finished updating. Press OK to restart the program.")
+            self._progressOKButton.set_sensitive(True)
+        else:
+            self._progressLabel.set_text("There was nothing to update")
+        
+    def _setProgress(self):
+        """Set the progress bar based on the current stage."""
+        if self._totalProgress>0:
+            progress = self._downloaded + \
+                       (self._numModifiedOrNew + self._numRemoved) * \
+                       Updater.REMOVE2BYTES
+            self._progressBar.set_fraction(0.05 + 0.94 * progress / self._totalProgress)
+
+    def failed(self, what):
+        """Called when the downloading has failed."""
+        self._waitAfterFinish = True
+        gobject.idle_add(self._failed, what)
+
+    def _failed(self, what):
+        """Called when the downloading has failed."""        
+        self._progressLabel.set_text("Failed, see the debug log for details.")
+        self._progressBar.set_fraction(1)
+        self._progressOKButton.set_sensitive(True)
+
+    def _startUpdate(self):
+        """Start the update.
+
+        It resets the GUI elements."""
+        self._progressLabel.set_text("")
+        self._progressBar.set_fraction(0)
+        self._progressWindow.show_all()
+        self._progressOKButton.set_sensitive(False)
+        self._progressOKButton.connect("clicked", self._progressOKClicked)
+
+    def _progressOKClicked(self, button):
+        """Called when the OK button on the progress window is clicked."""
+        self._progressWindow.hide()
+        if self._restart:
+            self._gui.restart()
+
+#-------------------------------------------------------------------------------
Index: src/mlx/gui/update.py
===================================================================
--- src/mlx/gui/update.py	(revision 38)
+++ 	(revision )
@@ -1,286 +1,0 @@
-# The GUI part of the update
-
-#-------------------------------------------------------------------------------
-
-from mlx.gui.common import *
-
-from mlx.update import update
-
-import mlx.const as const
-
-import threading
-import os
-import sys
-
-#-------------------------------------------------------------------------------
-
-class Updater(threading.Thread):
-    """The updater thread."""
-
-    # The removal or renaming of one file equals to the downloading of this
-    # many bytes in time (for the progress calculation)
-    REMOVE2BYTES = 100
-
-    _progressWindow = None
-
-    _progressLabel = None
-    
-    _progressBar = None
-    
-    _progressOKButton = None
-
-    _sudoDialog = None
-
-    @staticmethod
-    def _createGUI(parentWindow):
-        """Create the GUI elements, if needed."""
-        if Updater._progressWindow is not None:
-            return
-
-        Updater._progressWindow = window = gtk.Window()
-        window.set_title("MAVA Logger X " + const.VERSION + " Update")
-        window.set_transient_for(parentWindow)
-        #win.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
-        window.set_size_request(400, -1)
-        window.set_resizable(False)
-        window.set_modal(True)
-        window.connect("delete-event", lambda a, b: True)
-        window.set_deletable(False)
-        window.set_position(gtk.WindowPosition.CENTER_ON_PARENT if pygobject
-                            else gtk.WIN_POS_CENTER_ON_PARENT)
-
-        mainAlignment = gtk.Alignment(xscale = 1.0)
-        mainAlignment.set_padding(padding_top = 4, padding_bottom = 10,
-                                  padding_left = 16, padding_right = 16)
-        window.add(mainAlignment)
-
-        mainVBox = gtk.VBox()
-        mainAlignment.add(mainVBox)
-
-        labelAlignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
-        Updater._progressLabel = progressLabel = gtk.Label()
-        labelAlignment.add(progressLabel)
-        mainVBox.pack_start(labelAlignment, True, True, 4)
-        
-        Updater._progressBar = progressBar = gtk.ProgressBar()
-        mainVBox.pack_start(progressBar, True, True, 4)
-
-        buttonAlignment = gtk.Alignment(xalign = 0.5, xscale = 0.1)
-        Updater._progressOKButton = progressOKButton = gtk.Button("OK")
-        buttonAlignment.add(progressOKButton)        
-        mainVBox.pack_start(buttonAlignment, True, True, 4)
-
-        Updater._sudoDialog = sudoDialog = \
-            gtk.Dialog("MAVA Logger X " + const.VERSION + " Update",
-                       parentWindow,
-                       gtk.DialogFlags.MODAL if pygobject else gtk.DIALOG_MODAL,
-                       (gtk.STOCK_CANCEL, 0,
-                        gtk.STOCK_OK, 1))
-
-        infoLabelAlignment = gtk.Alignment(xalign = 0.5, xscale = 0.1)
-        infoLabelAlignment.set_padding(padding_top = 4, padding_bottom = 10,
-                                       padding_left = 16, padding_right = 16)
-
-        infoLabel = gtk.Label("There is an update available, but the program cannot write\n"
-                              "its directory due to insufficient privileges.\n\n"
-                              "Click OK, if you want to run a helper program\n"
-                              "with administrator privileges "
-                              "to complete the update,\n"
-                              "Cancel otherwise.")
-        infoLabel.set_justify(gtk.Justification.CENTER if pygobject
-                              else gtk.JUSTIFY_CENTER)
-        infoLabelAlignment.add(infoLabel)
-        sudoDialog.vbox.pack_start(infoLabelAlignment, True, True, 4)
-
-        sudoDialog.set_position(gtk.WindowPosition.CENTER_ON_PARENT if pygobject
-                                else gtk.WIN_POS_CENTER_ON_PARENT)
-
-    def __init__(self, gui, programDirectory, updateURL, parentWindow):
-        """Construct the updater. If not created yet, the windows used by the
-        updater are also created."""
-        super(Updater, self).__init__()
-
-        self._gui = gui
-        
-        self._programDirectory = programDirectory
-        self._updateURL = updateURL
-
-        self._totalProgress = 0
-        self._waitAfterFinish = False
-        self._restart = False
-
-        self._sudoReply = None
-        self._sudoCondition = threading.Condition()
-
-        Updater._createGUI(parentWindow)
-
-    def run(self):
-        """Execute the thread's operation."""
-        gobject.idle_add(self._startUpdate)
-        update(self._programDirectory, self._updateURL, self, fromGUI = True)
-        if not self._waitAfterFinish:
-            gobject.idle_add(self._progressWindow.hide)
-
-    def downloadingManifest(self):
-        """Called when the downloading of the manifest has started."""
-        gobject.idle_add(self._downloadingManifest)
-
-    def _downloadingManifest(self):
-        """Called when the downloading of the manifest has started."""
-        self._progressLabel.set_text("Downloading manifest...")
-        self._progressBar.set_fraction(0)
-
-    def downloadedManifest(self):
-        """Called when the downloading of the manifest has finished."""
-        gobject.idle_add(self._downloadedManifest)
-
-    def _downloadedManifest(self):
-        """Called when the downloading of the manifest has finished."""
-        self._progressLabel.set_text("Downloaded manifest...")
-        self._progressBar.set_fraction(0.05)
-
-    def needSudo(self):
-        """Called when the program is interested in whether we want to run a
-        program with administrator rights to do the update."""
-        gobject.idle_add(self._needSudo)
-        with self._sudoCondition:
-            while self._sudoReply is None:
-                self._sudoCondition.wait(1)
-            return self._sudoReply
-
-    def _needSudo(self):
-        """Called when the program is interested in whether we want to run a
-        program with administrator rights to do the update."""
-        self._sudoDialog.show_all()
-        result = self._sudoDialog.run()
-        self._sudoDialog.hide()
-        with self._sudoCondition:
-            self._sudoReply = result!=0
-            self._sudoCondition.notify()
-        
-    def setTotalSize(self, numToModifyAndNew, totalSize, numToRemove,
-                     numToRemoveLocal):
-        """Called when the downloading of the files has started."""
-        self._numToModifyAndNew = numToModifyAndNew
-        self._numModifiedOrNew = 0
-        self._totalSize = totalSize
-        self._downloaded = 0
-        self._numToRemove = numToRemove
-        self._numToRemoveLocal = numToRemoveLocal
-        self._numRemoved = 0
-
-        self._totalProgress = self._totalSize + \
-                              (self._numToModifyAndNew + \
-                               self._numToRemove + self._numToRemoveLocal) * \
-                              Updater.REMOVE2BYTES
-        self._waitAfterFinish = self._totalSize > 0 or self._numToRemove > 0
-
-    def _startDownload(self):
-        """Called when the download has started."""
-        self._progressLabel.set_text("Downloading files...")
-
-    def setDownloaded(self, downloaded):
-        """Called when a certain number of bytes are downloaded."""
-        self._downloaded = downloaded
-        gobject.idle_add(self._setDownloaded, downloaded)
-
-    def _setDownloaded(self, downloaded):
-        """Called when a certain number of bytes are downloaded."""
-        self._progressLabel.set_text("Downloaded %d of %d" % \
-                                     (downloaded, self._totalSize))
-        self._setProgress()
-
-    def startRenaming(self):
-        """Called when the renaming of files has started."""
-        gobject.idle_add(self._startRenaming)
-
-    def _startRenaming(self):
-        """Called when the renaming of files has started."""
-        self._progressLabel.set_text("Renaming downloaded files...")
-
-    def renamed(self, path, count):
-        """Called when a file has been renamed."""
-        self._numModifiedOrNew = count
-        gobject.idle_add(self._renamed, path, count)
-
-    def _renamed(self, path, count):
-        """Called when a file has been renamed."""
-        self._progressLabel.set_text("Renamed %s" % (path,))
-        self._setProgress()
-
-    def startRemoving(self):
-        """Called when the removing of files has started."""
-        gobject.idle_add(self._startRemoving)
-
-    def _startRemoving(self):
-        """Called when the removing of files has started."""
-        self._progressLabel.set_text("Removing files...")
-
-    def removed(self, path, count):
-        """Called when a file has been removed."""
-        self._numRemoved = count
-        gobject.idle_add(self._removed, path, count)
-
-    def _removed(self, path, count):
-        """Called when a file has been removed."""
-        self._progressLabel.set_text("Removed %s" % (path,))
-        self._setProgress()
-
-    def writingManifest(self):
-        """Called when the writing of the new manifest file has started."""
-        gobject.idle_add(self._writingManifest)
-
-    def _writingManifest(self):
-        """Called when the writing of the new manifest file has started."""
-        self._progressLabel.set_text("Writing the new manifest")
-        
-    def done(self):
-        """Called when the update has been done."""
-        gobject.idle_add(self._done)
-        self._restart = self._waitAfterFinish
-
-    def _done(self):
-        """Called when the writing of the new manifest file has started."""
-        self._progressBar.set_fraction(1)
-        if self._totalProgress>0:
-            self._progressLabel.set_text("Finished updating. Press OK to restart the program.")
-            self._progressOKButton.set_sensitive(True)
-        else:
-            self._progressLabel.set_text("There was nothing to update")
-        
-    def _setProgress(self):
-        """Set the progress bar based on the current stage."""
-        if self._totalProgress>0:
-            progress = self._downloaded + \
-                       (self._numModifiedOrNew + self._numRemoved) * \
-                       Updater.REMOVE2BYTES
-            self._progressBar.set_fraction(0.05 + 0.94 * progress / self._totalProgress)
-
-    def failed(self, what):
-        """Called when the downloading has failed."""
-        self._waitAfterFinish = True
-        gobject.idle_add(self._failed, what)
-
-    def _failed(self, what):
-        """Called when the downloading has failed."""        
-        self._progressLabel.set_text("Failed, see the debug log for details.")
-        self._progressBar.set_fraction(1)
-        self._progressOKButton.set_sensitive(True)
-
-    def _startUpdate(self):
-        """Start the update.
-
-        It resets the GUI elements."""
-        self._progressLabel.set_text("")
-        self._progressBar.set_fraction(0)
-        self._progressWindow.show_all()
-        self._progressOKButton.set_sensitive(False)
-        self._progressOKButton.connect("clicked", self._progressOKClicked)
-
-    def _progressOKClicked(self, button):
-        """Called when the OK button on the progress window is clicked."""
-        self._progressWindow.hide()
-        if self._restart:
-            self._gui.restart()
-
-#-------------------------------------------------------------------------------
