Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 201)
+++ src/mlx/gui/flight.py	(revision 208)
@@ -107,10 +107,10 @@
 
     def addButton(self, label, default = False, sensitive = True,
-                  tooltip = None, clicked = None):
+                  tooltip = None, clicked = None, padding = 4):
         """Add a button with the given label.
 
         Return the button object created."""
         button = gtk.Button(label)
-        self._buttonBox.pack_start(button, False, False, 4)
+        self._buttonBox.pack_start(button, False, False, padding)
         button.set_use_underline(True)
         if default:
@@ -124,4 +124,12 @@
         return button
 
+    def addCancelFlightButton(self):
+        """Add the 'Cancel flight' button to the page."""
+        return self.addButton(xstr("button_cancelFlight"),
+                              sensitive = True,
+                              tooltip = xstr("button_cancelFlight_tooltip"),
+                              clicked = self._cancelFlight,
+                              padding = 16)
+
     def addPreviousButton(self, sensitive = True, clicked = None):
         """Add the 'Next' button to the page."""
@@ -191,4 +199,8 @@
         
         self._wizard.setCurrentPage(self._fromPage, finalize = False)
+
+    def _cancelFlight(self, button):
+        """Called when the Cancel flight button is clicked."""
+        self._wizard.gui.cancelFlight()
     
 #-----------------------------------------------------------------------------
@@ -279,5 +291,5 @@
         contains text.
 
-        The entrance exam checkbox is senstive only, if the pilot ID is not
+        The entrance exam checkbox is sensitive only, if the pilot ID is not
         empty."""
         pilotID = self._pilotID.get_text()
@@ -292,59 +304,24 @@
     def _loginClicked(self, button):
         """Called when the login button was clicked."""
-        gui = self._wizard.gui
-        gui.beginBusy(xstr("login_busy"))
-        gui.webHandler.login(self._loginResultCallback,
-                             self._pilotID.get_text(),
-                             self._password.get_text(),
-                             entranceExam = self.entranceExam)
-
-    def _loginResultCallback(self, returned, result):
-        """The login result callback, called in the web handler's thread."""
-        gobject.idle_add(self._handleLoginResult, returned, result)
+        self._wizard.login(self._handleLoginResult,
+                           self._pilotID.get_text(),
+                           self._password.get_text(),
+                           self.entranceExam)
 
     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:
-                message = xstr("login_entranceExam_invalid"
-                               if self.entranceExam else
-                               xstr("login_invalid"))
-                dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
-                                           type = MESSAGETYPE_ERROR,
-                                           message_format = message)
-                dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
-                dialog.set_title(WINDOW_TITLE_BASE)
-                secondary = xstr("login_entranceExam_invalid_sec"
-                                 if self.entranceExam else
-                                 xstr("login_invalid_sec"))
-                dialog.format_secondary_markup(secondary)
-                dialog.run()
-                dialog.hide()
-        else:
-            dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
-                                       type = MESSAGETYPE_ERROR,
-                                       message_format = xstr("login_failconn"))
-            dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
-            dialog.set_title(WINDOW_TITLE_BASE)
-            dialog.format_secondary_markup(xstr("login_failconn_sec"))
-            
-            dialog.run()
-            dialog.hide()
+        if returned and result.loggedIn:
+            config = self._wizard.gui.config
+
+            config.pilotID = self._pilotID.get_text()
+
+            rememberPassword = self._rememberButton.get_active()                
+            config.password = result.password if rememberPassword else ""
+
+            config.rememberPassword = rememberPassword
+
+            config.save()
+            self._wizard.nextPage()
 
 #-----------------------------------------------------------------------------
@@ -398,4 +375,9 @@
         self.setMainWidget(alignment)
 
+        self._refreshButton = self.addButton(xstr("flightsel_refresh"),
+                                             sensitive = True,
+                                             clicked = self._refreshClicked,
+                                             tooltip = xstr("flightsel_refresh_tooltip"))
+
         self._loadButton = self.addButton(xstr("flightsel_load"),
                                           sensitive = True,
@@ -412,12 +394,20 @@
         """Fill the flight list."""
         self._flightList.set_sensitive(True)
+        self._loadButton.set_sensitive(True)
+        self._refreshButton.set_sensitive(True)
+        self._buildFlights()
+            
+    def finalize(self):
+        """Finalize the page."""
+        self._flightList.set_sensitive(False)
+        self._loadButton.set_sensitive(False)
+        self._refreshButton.set_sensitive(False)
+
+    def _buildFlights(self):
+        """Rebuild the flights from the login result."""
         self._flights = []
         self._listStore.clear()
         for flight in self._wizard.loginResult.flights:
             self._addFlight(flight)
-            
-    def finalize(self):
-        """Finalize the page."""
-        self._flightList.set_sensitive(False)
 
     def _addFlight(self, flight):
@@ -428,4 +418,13 @@
                                 flight.departureICAO,
                                 flight.arrivalICAO])
+
+    def _refreshClicked(self, button):
+        """Called when the refresh button is clicked."""
+        self._wizard.reloadFlights(self._refreshCallback)
+
+    def _refreshCallback(self, returned, result):
+        """Callback for the refresh."""
+        if returned and result.loggedIn:
+            self._buildFlights()
 
     def _selectionChanged(self, selection):
@@ -581,4 +580,6 @@
         self.setMainWidget(alignment)        
 
+        self.addCancelFlightButton()
+
         self.addPreviousButton(clicked = self._backClicked)
         
@@ -729,4 +730,6 @@
         table.attach(labelAlignment, 1, 2, 4, 5)
 
+        self.addCancelFlightButton()
+
         self.addPreviousButton(clicked = self._backClicked)
 
@@ -879,4 +882,5 @@
         table.attach(gtk.Label("kg"), 2, 3, 6, 7)
 
+        self.addCancelFlightButton()
         self._backButton = self.addPreviousButton(clicked = self._backClicked)
         self._button = self.addNextButton(clicked = self._forwardClicked)
@@ -1009,4 +1013,6 @@
         table.attach(self._simulatorTime, 1, 2, 2, 3)
 
+        self.addCancelFlightButton()
+
         self._backButton = self.addPreviousButton(clicked = self._backClicked)
         self._button = self.addNextButton(clicked = self._forwardClicked)
@@ -1282,4 +1288,6 @@
         tankData = ((2500, 3900),) * len(tanks)
         self._setupTanks(tanks, tankData)
+
+        self.addCancelFlightButton()
 
         self._backButton = self.addPreviousButton(clicked = self._backClicked)
@@ -1443,4 +1451,6 @@
 
         mainBox.pack_start(routeBox, True, True, 8)
+
+        self.addCancelFlightButton()
 
         self._backButton = self.addPreviousButton(clicked = self._backClicked)        
@@ -1630,4 +1640,6 @@
         self.metarEdited = False
 
+        self.addCancelFlightButton()
+
         self.addPreviousButton(clicked = self._backClicked)
         self._button = self.addNextButton(clicked = self._forwardClicked)
@@ -1824,4 +1836,6 @@
         table.attach(gtk.Label(xstr("label_knots")), 3, 4, 4, 5)
 
+        self.addCancelFlightButton()
+
         self.addPreviousButton(clicked = self._backClicked)
 
@@ -2006,4 +2020,6 @@
         table.attach(gtk.Label(xstr("label_knots")), 4, 5, 5, 6)
 
+        self.addCancelFlightButton()
+
         self.addPreviousButton(clicked = self._backClicked)
 
@@ -2281,4 +2297,10 @@
         self._gateLabel.set_mnemonic_widget(self._gate)
 
+        self.addButton(xstr("finish_newFlight"),
+                       sensitive = True,
+                       clicked = self._newFlightClicked,
+                       tooltip = xstr("finish_newFlight_tooltip"),
+                       padding = 16)
+
         self.addPreviousButton(clicked = self._backClicked)
 
@@ -2289,4 +2311,7 @@
         self._savePIREPDialog = None
         self._lastSavePath = None
+
+        self._pirepSaved = False
+        self._pirepSent = False
         
         self._sendButton = self.addButton(xstr("sendPIREP"), default = True,
@@ -2308,4 +2333,7 @@
     def activate(self):
         """Activate the page."""
+        self._pirepSaved = False
+        self._pirepSent = False
+
         flight = self._wizard.gui._flight
         rating = flight.logger.getRating()
@@ -2369,4 +2397,23 @@
         self._updateButtons()
 
+    def _newFlightClicked(self, button):
+        """Called when the new flight button is clicked."""
+        gui = self._wizard.gui
+        if not self._pirepSent and not self._pirepSaved:
+            dialog = gtk.MessageDialog(parent = gui.mainWindow,
+                                       type = MESSAGETYPE_QUESTION,
+                                       message_format = xstr("finish_newFlight_question"))
+
+            dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
+            dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
+
+            dialog.set_title(WINDOW_TITLE_BASE)
+            result = dialog.run()
+            dialog.hide()
+            if result!=RESPONSETYPE_YES:
+                return
+            
+        gui.reset()
+
     def _saveClicked(self, button):
         """Called when the Save PIREP button is clicked."""
@@ -2405,4 +2452,5 @@
                 message = xstr("finish_save_done")
                 secondary = None
+                self._pirepSaved = True
             else:
                 type = MESSAGETYPE_ERROR
@@ -2459,4 +2507,5 @@
     def _handlePIREPSent(self, returned, result):
         """Callback for the PIREP sending result."""
+        self._pirepSent = returned and result.success
         if self._wizard.gui.config.onlineGateSystem and \
            not self._wizard.entranceExam and \
@@ -2683,7 +2732,8 @@
         self.nextPage()
 
-    def reset(self):
+    def reset(self, loginResult):
         """Resets the wizard to go back to the login page."""
-        self._initialize()
+        self._initialize(keepLoginResult = loginResult is None,
+                         loginResult = loginResult)
 
     def setStage(self, stage):
@@ -2700,10 +2750,14 @@
             self._landingPage.flightEnded()
 
-    def _initialize(self):
+    def _initialize(self, keepLoginResult = False, loginResult = None):
         """Initialize the wizard."""
+        if not keepLoginResult:
+            self._loginResult = loginResult
+
+        self._loginCallback = None
+
         self._fleet = None
         self._fleetCallback = None
         
-        self._loginResult = None
         self._bookedFlight = None
         self._departureGate = "-"
@@ -2714,8 +2768,84 @@
         self._arrivalMETAR = None
 
-        for page in self._pages:
+        firstPage = 0 if self._loginResult is None else 1
+        for page in self._pages[firstPage:]:
             page.reset()
         
-        self.setCurrentPage(0)
+        self.setCurrentPage(firstPage)
+
+    def login(self, callback, pilotID, password, entranceExam):
+        """Called when the login button was clicked."""
+        self._loginCallback = callback
+        if pilotID is None:
+            loginResult = self._loginResult
+            assert loginResult is not None and loginResult.loggedIn
+            pilotID = loginResult.pilotID
+            password = loginResult.password
+            entranceExam = loginResult.entranceExam
+            busyMessage = xstr("reload_busy")
+        else:
+            self._loginResult = None
+            busyMessage = xstr("login_busy")
+
+        self.gui.beginBusy(busyMessage)
+        
+        self.gui.webHandler.login(self._loginResultCallback,
+                                  pilotID, password,
+                                  entranceExam = entranceExam)
+
+    def reloadFlights(self, callback):
+        """Reload the flights from the MAVA server."""
+        self.login(callback, None, None, None)
+
+    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.gui.endBusy()
+        isReload = self._loginResult is not None
+        if returned:
+            if result.loggedIn:
+                self._loginResult = result
+            else:
+                if isReload:
+                    message = xstr("reload_failed")
+                else:
+                    message = xstr("login_entranceExam_invalid"
+                                   if self.entranceExam else
+                                   xstr("login_invalid"))
+                dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
+                                           type = MESSAGETYPE_ERROR,
+                                           message_format = message)
+                dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
+                dialog.set_title(WINDOW_TITLE_BASE)
+                if isReload:
+                    secondary = xstr("reload_failed_sec")
+                else:
+                    secondary = xstr("login_entranceExam_invalid_sec"
+                                     if self.entranceExam else
+                                     xstr("login_invalid_sec"))
+                dialog.format_secondary_markup(secondary)
+                dialog.run()
+                dialog.hide()
+        else:
+            message = xstr("reload_failconn") if isReload \
+                      else xstr("login_failconn")
+            dialog = gtk.MessageDialog(parent = self.gui.mainWindow,
+                                       type = MESSAGETYPE_ERROR,
+                                       message_format = message)
+            dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
+            dialog.set_title(WINDOW_TITLE_BASE)
+            secondary = xstr("reload_failconn_sec") if isReload \
+                        else xstr("login_failconn_sec")
+            dialog.format_secondary_markup(secondary)
+            
+            dialog.run()
+            dialog.hide()
+
+        callback = self._loginCallback
+        self._loginCallback = None
+        callback(returned, result)
 
     def getFleet(self, callback, force = False):
