Index: src/mlx/gui/common.py
===================================================================
--- src/mlx/gui/common.py	(revision 105)
+++ src/mlx/gui/common.py	(revision 123)
@@ -27,6 +27,9 @@
     BUTTONSTYPE_YES_NO = gtk.BUTTONS_YES_NO
     RESPONSETYPE_YES = gtk.RESPONSE_YES
+    RESPONSETYPE_ACCEPT = gtk.RESPONSE_ACCEPT
+    RESPONSETYPE_REJECT = gtk.RESPONSE_REJECT
     ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
     CONTROL_MASK = gdk.CONTROL_MASK
+    DIALOG_MODAL = gtk.DIALOG_MODAL
 
     def text2unicode(text):
@@ -49,6 +52,9 @@
     BUTTONSTYPE_YES_NO = gtk.ButtonsType.YES_NO
     RESPONSETYPE_YES = gtk.ResponseType.YES
+    RESPONSETYPE_ACCEPT = gtk.ResponseType.ACCEPT
+    RESPONSETYPE_REJECT = gtk.ResponseType.REJECT
     ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
     CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
+    DIALOG_MODAL = gtk.DialogFlags.MODAL
 
     import codecs
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 120)
+++ src/mlx/gui/gui.py	(revision 123)
@@ -10,4 +10,5 @@
 from mlx.gui.weighthelp import WeightHelp
 from mlx.gui.gates import FleetGateStatus
+from mlx.gui.prefs import Preferences
 
 import mlx.const as const
@@ -61,5 +62,5 @@
         """Build the GUI."""
         
-        window = gtk.Window()
+        self._mainWindow = window = gtk.Window()
         window.set_title(WINDOW_TITLE_BASE)
         window.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
@@ -73,4 +74,6 @@
         window.add(mainVBox)
 
+        self._preferences = Preferences(self)
+
         menuBar = self._buildMenuBar(accelGroup)
         mainVBox.pack_start(menuBar, False, False, 0)
@@ -130,6 +133,4 @@
         self._weightHelp.reset()
         self._weightHelp.disable()
-
-        self._mainWindow = window
 
         self._statusIcon = StatusIcon(iconDirectory, self)
@@ -663,4 +664,17 @@
         fileMenu.append(quitMenuItem)
 
+        toolsMenuItem = gtk.MenuItem(xstr("menu_tools"))
+        toolsMenu = gtk.Menu()
+        toolsMenuItem.set_submenu(toolsMenu)
+        menuBar.append(toolsMenuItem)
+
+        prefsMenuItem = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
+        prefsMenuItem.set_use_stock(True)
+        prefsMenuItem.set_label(xstr("menu_tools_prefs"))
+        prefsMenuItem.add_accelerator("activate", accelGroup,
+                                      ord(xstr("menu_tools_prefs_key")),
+                                      CONTROL_MASK, ACCEL_VISIBLE)
+        prefsMenuItem.connect("activate", self._editPreferences)
+        toolsMenu.append(prefsMenuItem)
 
         viewMenuItem = gtk.MenuItem(xstr("menu_view"))
@@ -759,2 +773,6 @@
         else:
             self._mainWindow.set_default(None)
+
+    def _editPreferences(self, menuItem):
+        """Callback for editing the preferences."""
+        self._preferences.run(self.config)
Index: src/mlx/gui/info.py
===================================================================
--- src/mlx/gui/info.py	(revision 122)
+++ src/mlx/gui/info.py	(revision 123)
@@ -5,4 +5,6 @@
 from mlx.i18n import xstr
 import mlx.const as const
+
+#------------------------------------------------------------------------------
 
 class FlightInfo(gtk.VBox):
Index: src/mlx/gui/prefs.py
===================================================================
--- src/mlx/gui/prefs.py	(revision 123)
+++ src/mlx/gui/prefs.py	(revision 123)
@@ -0,0 +1,212 @@
+# Module for the preferences dialog
+
+#------------------------------------------------------------------------------
+
+from common import *
+
+from mlx.i18n import xstr
+import mlx.const as const
+
+import urlparse
+
+#------------------------------------------------------------------------------
+
+class Preferences(gtk.Dialog):
+    """The preferences dialog."""
+    def __init__(self, gui):
+        """Construct the dialog."""
+        super(Preferences, self).__init__(WINDOW_TITLE_BASE + " " +
+                                          xstr("prefs_title"),
+                                          gui.mainWindow,
+                                          DIALOG_MODAL,
+                                          (gtk.STOCK_CANCEL,
+                                           RESPONSETYPE_REJECT,
+                                           gtk.STOCK_OK,
+                                           RESPONSETYPE_ACCEPT))
+        self._gui = gui
+
+        contentArea = self.get_content_area()
+
+        notebook = gtk.Notebook()
+        contentArea.pack_start(notebook, True, True, 4)
+
+        general = self._buildGeneral()
+        label = gtk.Label(xstr("prefs_tab_general"))
+        label.set_use_underline(True)
+        label.set_tooltip_text(xstr("prefs_tab_general_tooltip"))
+        notebook.append_page(general, label)
+
+        advanced = self._buildAdvanced()
+        label = gtk.Label(xstr("prefs_tab_advanced"))
+        label.set_use_underline(True)
+        label.set_tooltip_text(xstr("prefs_tab_advanced_tooltip"))
+        notebook.append_page(advanced, label)
+
+    def run(self, config):
+        """Run the preferences dialog.
+
+        The dialog will be set up from data in the given configuration. If the
+        changes are accepted by the user, the configuration is updated and saved."""
+        self._fromConfig(config)
+
+        self.show_all()
+        response = super(Preferences, self).run()
+        self.hide()
+
+        if response==RESPONSETYPE_ACCEPT:
+            self._toConfig(config)
+            config.save()
+
+    def _fromConfig(self, config):
+        """Setup the dialog from the given configuration."""
+        self._setLanguage(config.language)
+
+        self._togglingAutoUpdate = True
+        self._autoUpdate.set_active(config.autoUpdate)
+        self._togglingAutoUpdate = False
+        if not config.autoUpdate:
+            self._warnedAutoUpdate = True
+
+        self._updateURL.set_text(config.updateURL)
+
+    def _toConfig(self, config):
+        """Setup the given config from the settings in the dialog."""
+        config.language = self._getLanguage()
+        config.autoUpdate = self._autoUpdate.get_active()
+        config.updateURL = self._updateURL.get_text()
+
+    def _buildGeneral(self):
+        """Build the page for the general settings."""
+        mainAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                      xscale = 0.0, yscale = 0.0)
+        mainAlignment.set_padding(padding_top = 16, padding_bottom = 32,
+                                  padding_left = 4, padding_right = 48)
+        mainBox = gtk.VBox()
+        mainAlignment.add(mainBox)
+
+        languageBox = gtk.HBox()
+        mainBox.pack_start(languageBox, False, False, 4)
+
+        label = gtk.Label(xstr("prefs_language"))
+        label.set_use_underline(True)
+
+        languageBox.pack_start(label, False, False, 4)
+
+        self._languageList = gtk.ListStore(str, str)
+        for language in const.languages:
+            self._languageList.append([xstr("prefs_lang_" + language),
+                                       language])
+
+        self._languageComboBox = languageComboBox = \
+            gtk.ComboBox(model = self._languageList)                   
+        cell = gtk.CellRendererText()
+        languageComboBox.pack_start(cell, True)
+        languageComboBox.add_attribute(cell, 'text', 0)
+        languageComboBox.set_tooltip_text(xstr("prefs_language_tooltip"))
+        languageComboBox.connect("changed", self._languageChanged)
+        languageBox.pack_start(languageComboBox, False, False, 4)
+
+        self._changingLanguage = False
+        self._warnedRestartNeeded = False
+
+        label.set_mnemonic_widget(languageComboBox)
+                                       
+        return mainAlignment
+
+    def _setLanguage(self, language):
+        """Set the language to the given one."""
+        iter = self._languageList.get_iter_first()
+        while iter is not None:
+            (lang,) = self._languageList.get(iter, 1)
+            if (not language and lang=="$system") or \
+               lang==language:
+                self._changingLanguage = True
+                self._languageComboBox.set_active_iter(iter)
+                self._changingLanguage = False
+                break
+            else:
+                iter = self._languageList.iter_next(iter)
+
+    def _getLanguage(self):
+        """Get the language selected by the user."""        
+        iter = self._languageComboBox.get_active_iter()
+        (lang,) = self._languageList.get(iter, 1)
+        return "" if lang=="$system" else lang
+
+    def _languageChanged(self, comboBox):
+        """Called when the language has changed."""
+        if not self._changingLanguage and not self._warnedRestartNeeded:
+            dialog = gtk.MessageDialog(parent = self,
+                                       type = MESSAGETYPE_INFO,
+                                       buttons = BUTTONSTYPE_OK,
+                                       message_format = xstr("prefs_restart"))
+            dialog.set_title(self.get_title())
+            dialog.format_secondary_markup(xstr("prefs_language_restart_sec"))
+            dialog.run()
+            dialog.hide()
+            self._warnedRestartNeeded = True
+
+    def _buildAdvanced(self):
+        """Build the page for the advanced settings."""
+
+        mainAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
+                                      xscale = 0.0, yscale = 0.0)
+        mainAlignment.set_padding(padding_top = 16, padding_bottom = 32,
+                                  padding_left = 4, padding_right = 48)
+        mainBox = gtk.VBox()
+        mainAlignment.add(mainBox)
+
+        self._autoUpdate = gtk.CheckButton(xstr("prefs_update_auto"))
+        mainBox.pack_start(self._autoUpdate, False, False, 4)
+
+        self._autoUpdate.set_use_underline(True)
+        self._autoUpdate.connect("toggled", self._autoUpdateToggled)
+        self._autoUpdate.set_tooltip_text(xstr("prefs_update_auto_tooltip"))
+        self._warnedAutoUpdate = False
+        self._togglingAutoUpdate = False
+        
+        updateURLBox = gtk.HBox()
+        mainBox.pack_start(updateURLBox, False, False, 4)
+        label = gtk.Label(xstr("prefs_update_url"))
+        label.set_use_underline(True)
+        updateURLBox.pack_start(label, False, False, 4)
+
+        self._updateURL = gtk.Entry()
+        label.set_mnemonic_widget(self._updateURL)
+        self._updateURL.set_width_chars(40)
+        self._updateURL.set_tooltip_text(xstr("prefs_update_url_tooltip"))
+        self._updateURL.connect("changed", self._updateURLChanged)
+        updateURLBox.pack_start(self._updateURL, False, False, 4)
+
+        return mainAlignment
+
+    def _setOKButtonSensitivity(self):
+        """Set the sensitive state of the OK button."""
+        sensitive = False
+        try:
+            result = urlparse.urlparse(self._updateURL.get_text())
+            sensitive = result.scheme!="" and (result.netloc + result.path)!=""
+        except:
+            pass
+
+        okButton = self.get_widget_for_response(RESPONSETYPE_ACCEPT)
+        okButton.set_sensitive(sensitive)
+
+    def _autoUpdateToggled(self, button):
+        """Called when the auto update check button is toggled."""
+        if not self._togglingAutoUpdate and not self._warnedAutoUpdate and \
+           not self._autoUpdate.get_active():
+            dialog = gtk.MessageDialog(parent = self,
+                                       type = MESSAGETYPE_INFO,
+                                       buttons = BUTTONSTYPE_OK,
+                                       message_format = xstr("prefs_update_auto_warning"))
+            dialog.set_title(self.get_title())
+            dialog.run()
+            dialog.hide()
+            self._warnedAutoUpdate = True
+            
+    def _updateURLChanged(self, entry):
+        """Called when the update URL is changed."""
+        self._setOKButtonSensitivity()
+        
+            
