Index: trunk/src/org/openstreetmap/josm/gui/preferences/AdvancedPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/AdvancedPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/AdvancedPreference.java	(revision 2745)
@@ -46,5 +46,5 @@
     protected JTextField txtFilter;
 
-    public void addGui(final PreferenceDialog gui) {
+    public void addGui(final PreferenceTabbedPane gui) {
         JPanel p = gui.createPreferenceTab("advanced", tr("Advanced Preferences"),
                 tr("Setting Preference entries directly. Use with caution!"), false);
@@ -215,5 +215,5 @@
     }
 
-    private void editPreference(final PreferenceDialog gui, final JTable list) {
+    private void editPreference(final PreferenceTabbedPane gui, final JTable list) {
         if (list.getSelectedRowCount() != 1) {
             JOptionPane.showMessageDialog(
@@ -240,5 +240,5 @@
     }
 
-    private void removePreference(final PreferenceDialog gui, final JTable list) {
+    private void removePreference(final PreferenceTabbedPane gui, final JTable list) {
         if (list.getSelectedRowCount() == 0) {
             JOptionPane.showMessageDialog(
@@ -256,5 +256,5 @@
     }
 
-    private void addPreference(final PreferenceDialog gui) {
+    private void addPreference(final PreferenceTabbedPane gui) {
         JPanel p = new JPanel(new GridBagLayout());
         p.add(new JLabel(tr("Key")), GBC.std().insets(0,0,5,0));
Index: trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 2745)
@@ -48,5 +48,5 @@
     private JTextField audioCalibration = new JTextField(8);
 
-    public void addGui(PreferenceDialog gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         // audioMenuVisible
         audioMenuVisible.setSelected(! Main.pref.getBoolean("audio.menuinvisible"));
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java	(revision 2745)
@@ -146,5 +146,5 @@
     }
 
-    public void addGui(final PreferenceDialog gui) {
+    public void addGui(final PreferenceTabbedPane gui) {
         fixColorPrefixes();
         setColorModel(Main.pref.getAllColors());
Index: trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java	(revision 2745)
@@ -60,5 +60,5 @@
     private JCheckBox useAntialiasing = new JCheckBox(tr("Smooth map graphics (antialiasing)"));
 
-    public void addGui(PreferenceDialog gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         gui.display.setPreferredSize(new Dimension(400,600));
         JPanel panel = new JPanel(new GridBagLayout());
Index: trunk/src/org/openstreetmap/josm/gui/preferences/FilePreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/FilePreferences.java	(revision 2742)
+++ 	(revision )
@@ -1,40 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import javax.swing.JCheckBox;
-import javax.swing.JSeparator;
-import javax.swing.SwingConstants;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.tools.GBC;
-
-/**
- * Out of pure laziness, I add the file stuff to connection tab.
- * Feel free to fix this.
- *
- * @author imi
- */
-public class FilePreferences implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new FilePreferences();
-        }
-    }
-
-    private JCheckBox keepBackup = new JCheckBox(tr("Keep backup files"));
-
-    public void addGui(PreferenceDialog gui) {
-        gui.connection.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-        keepBackup.setSelected(Main.pref.getBoolean("save.keepbackup"));
-        keepBackup.setToolTipText(tr("When saving, keep backup files ending with a ~"));
-        gui.connection.add(keepBackup, GBC.eol().insets(20,0,0,0));
-    }
-
-    public boolean ok() {
-        Main.pref.put("save.keepbackup", keepBackup.isSelected());
-        return false;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(revision 2745)
@@ -42,5 +42,5 @@
     private JCheckBox modeless = new JCheckBox(tr("Modeless working (Potlatch style)"));
 
-    public void addGui(PreferenceDialog gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 2745)
@@ -48,5 +48,5 @@
     private boolean translationsLoaded = false;
 
-    public void addGui(final PreferenceDialog gui) {
+    public void addGui(final PreferenceTabbedPane gui) {
         model = new LanguageComboBoxModel();
         langCombo = new JComboBox(model);
Index: trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 2745)
@@ -32,5 +32,5 @@
     }
 
-    public void addGui(final PreferenceDialog gui) {
+    public void addGui(final PreferenceTabbedPane gui) {
         enableDefault = new JCheckBox(tr("Enable built-in defaults"),
                 Main.pref.getBoolean("mappaint.style.enable-defaults", true));
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 2745)
@@ -40,10 +40,10 @@
     private JPanel plugin;
     private JPanel pluginPanel = new NoHorizontalScrollPanel(new GridBagLayout());
-    private PreferenceDialog gui;
+    private PreferenceTabbedPane gui;
     private JScrollPane pluginPane;
     private PluginSelection selection = new PluginSelection();
     private JTextField txtFilter;
 
-    public void addGui(final PreferenceDialog gui) {
+    public void addGui(final PreferenceTabbedPane gui) {
         this.gui = gui;
         plugin = gui.createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 2745)
@@ -1,204 +1,125 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.preferences;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Font;
-import java.awt.GridBagLayout;
-import java.awt.ScrollPane;
-import java.awt.event.MouseWheelEvent;
-import java.awt.event.MouseWheelListener;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.logging.Logger;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 
+import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
 import javax.swing.JComponent;
-import javax.swing.JLabel;
+import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
+import javax.swing.KeyStroke;
 
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.plugins.PluginHandler;
-import org.openstreetmap.josm.tools.BugReportExceptionHandler;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.I18n;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
+import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.WindowGeometry;
 
-/**
- * The preference settings.
- *
- * @author imi
- */
-public class PreferenceDialog extends JTabbedPane implements MouseWheelListener {
-    static private final Logger logger = Logger.getLogger(PreferenceDialog.class.getName());
+public class PreferenceDialog extends JDialog {
 
-    private final static Collection<PreferenceSettingFactory> settingsFactory = new LinkedList<PreferenceSettingFactory>();
-    private final List<PreferenceSetting> settings = new ArrayList<PreferenceSetting>();
+    private PreferenceTabbedPane tpPreferences;
+    private boolean canceled;
 
-    // some common tabs
-    public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
-    public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."),false);
-    public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
-    public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
-
-    public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane();
-    public final javax.swing.JTabbedPane mapcontent = new javax.swing.JTabbedPane();
-
-    /**
-     * Construct a JPanel for the preference settings. Layout is GridBagLayout
-     * and a centered title label and the description are added. The panel
-     * will be shown inside a {@link ScrollPane}
-     * @param icon The name of the icon.
-     * @param title The title of this preference tab.
-     * @param desc A description in one sentence for this tab. Will be displayed
-     *      italic under the title.
-     * @return The created panel ready to add other controls.
-     */
-    public JPanel createPreferenceTab(String icon, String title, String desc) {
-        return createPreferenceTab(icon, title, desc, false);
+    protected JPanel buildActionPanel() {
+        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        pnl.add(new SideButton(new OKAction()));
+        pnl.add(new SideButton(new CancelAction()));
+        pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Action/Preferences"))));
+        return pnl;
     }
 
-    /**
-     * Construct a JPanel for the preference settings. Layout is GridBagLayout
-     * and a centered title label and the description are added.
-     * @param icon The name of the icon.
-     * @param title The title of this preference tab.
-     * @param desc A description in one sentence for this tab. Will be displayed
-     *      italic under the title.
-     * @param inScrollPane if <code>true</code> the added tab will show scroll bars
-     *        if the panel content is larger than the available space
-     * @return The created panel ready to add other controls.
-     */
-    public JPanel createPreferenceTab(String icon, String title, String desc, boolean inScrollPane) {
-        JPanel p = new JPanel(new GridBagLayout());
-        p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-        p.add(new JLabel(title), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,10));
+    protected void build() {
+        Container c = getContentPane();
+        c.setLayout(new BorderLayout());
+        c.add(tpPreferences = new PreferenceTabbedPane(), BorderLayout.CENTER);
+        tpPreferences.buildGui();
+        tpPreferences.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        c.add(buildActionPanel(), BorderLayout.SOUTH);
 
-        JLabel descLabel = new JLabel("<html>"+desc+"</html>");
-        descLabel.setFont(descLabel.getFont().deriveFont(Font.ITALIC));
-        p.add(descLabel, GBC.eol().insets(5,0,5,20).fill(GBC.HORIZONTAL));
+        addWindowListener(new WindowEventHandler());
 
-        JComponent tab = p;
-        if (inScrollPane) {
-            JScrollPane sp = new JScrollPane(p);
-            tab = sp;
-        }
-        addTab(null, ImageProvider.get("preferences", icon), tab);
-        setToolTipTextAt(getTabCount()-1, "<html>"+desc+"</html>");
-        return p;
+        getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
+        getRootPane().getActionMap().put("cancel", new CancelAction());
+        HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Action/Preferences"));
     }
 
-    public void ok() {
-        boolean requiresRestart = false;
-        for (PreferenceSetting setting : settings)
-        {
-            if(setting.ok()) {
-                requiresRestart = true;
-            }
-        }
-        if (requiresRestart) {
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    tr("You have to restart JOSM for some settings to take effect."),
-                    tr("Warning"),
-                    JOptionPane.WARNING_MESSAGE
-            );
-        }
-        Main.parent.repaint();
+    public PreferenceDialog(Component parent) {
+        super(JOptionPane.getFrameForComponent(parent), tr("Preferences"), true /* modal */);
+        build();
     }
 
-    /**
-     * If the dialog is closed with Ok, the preferences will be stored to the preferences-
-     * file, otherwise no change of the file happens.
-     */
-    public PreferenceDialog() {
-        super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
+    public boolean isCanceled() {
+        return canceled;
+    }
 
-        super.addMouseWheelListener(this);
+    protected void setCanceled(boolean canceled) {
+        this.canceled = canceled;
+    }
 
-        for (PreferenceSettingFactory factory:settingsFactory) {
-            // logger.info("creating settings: " + factory);
-            PreferenceSetting setting = factory.createPreferenceSetting();
-            if (setting != null) {
-                settings.add(factory.createPreferenceSetting());
-            }
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            new WindowGeometry(
+                    getClass().getName() + ".geometry",
+                    WindowGeometry.centerInWindow(
+                            getParent(),
+                            new Dimension(600,800)
+                    )
+            ).apply(this);
+        } else if (!visible && isShowing()){
+            new WindowGeometry(this).remember(getClass().getName() + ".geometry");
+        }
+        super.setVisible(visible);
+    }
+
+    class CancelAction extends AbstractAction {
+        public CancelAction() {
+            putValue(NAME, tr("Cancel"));
+            putValue(SMALL_ICON, ImageProvider.get("cancel"));
+            putValue(SHORT_DESCRIPTION, tr("Close the prefereces dialog and discard preference updates"));
         }
 
-        display.add(displaycontent, GBC.eol().fill(GBC.BOTH));
-        map.add(mapcontent, GBC.eol().fill(GBC.BOTH));
-        for (Iterator<PreferenceSetting> it = settings.iterator(); it.hasNext();) {
-            try {
-                PreferenceSetting settings = it.next();
-                //logger.info("adding gui: " + settings);
-                settings.addGui(this);
-            } catch (SecurityException e) {
-                it.remove();
-            } catch (Throwable e) {
-                /* allow to change most settings even if e.g. a plugin fails */
-                BugReportExceptionHandler.handleException(e);
-            }
+        public void cancel() {
+            setCanceled(true);
+            setVisible(false);
+        }
+
+        public void actionPerformed(ActionEvent evt) {
+            cancel();
         }
     }
 
-    public List<PreferenceSetting> getSettings() {
-        return settings;
+    class OKAction extends AbstractAction {
+        public OKAction() {
+            putValue(NAME, tr("OK"));
+            putValue(SMALL_ICON, ImageProvider.get("ok"));
+            putValue(SHORT_DESCRIPTION, tr("Save the preferences and close the dialog"));
+        }
+
+        public void actionPerformed(ActionEvent evt) {
+            tpPreferences.savePreferences();
+            setCanceled(false);
+            setVisible(false);
+        }
     }
 
-    @SuppressWarnings("unchecked")
-    public <T>  T getSetting(Class<? extends T> clazz) {
-        for (PreferenceSetting setting:settings) {
-            if (clazz.isAssignableFrom(setting.getClass()))
-                return (T)setting;
+    class WindowEventHandler extends WindowAdapter {
+        @Override
+        public void windowClosing(WindowEvent arg0) {
+            new CancelAction().cancel();
         }
-        return null;
-    }
-
-    static {
-        // order is important!
-        settingsFactory.add(new DrawingPreference.Factory());
-        settingsFactory.add(new ColorPreference.Factory());
-        settingsFactory.add(new LafPreference.Factory());
-        settingsFactory.add(new LanguagePreference.Factory());
-        settingsFactory.add(new ServerAccessPreference.Factory());
-        settingsFactory.add(new FilePreferences.Factory());
-        settingsFactory.add(new ProxyPreferences.Factory());
-        settingsFactory.add(new ProjectionPreference.Factory());
-        settingsFactory.add(new MapPaintPreference.Factory());
-        settingsFactory.add(new TaggingPresetPreference.Factory());
-        settingsFactory.add(new PluginPreference.Factory());
-        settingsFactory.add(Main.toolbar);
-        settingsFactory.add(new AudioPreference.Factory());
-        settingsFactory.add(new ShortcutPreference.Factory());
-
-        PluginHandler.getPreferenceSetting(settingsFactory);
-
-        // always the last: advanced tab
-        settingsFactory.add(new AdvancedPreference.Factory());
-    }
-
-    /**
-     * This mouse wheel listener reacts when a scroll is carried out over the
-     * tab strip and scrolls one tab/down or up, selecting it immediately.
-     */
-    public void mouseWheelMoved(MouseWheelEvent wev) {
-        // Ensure the cursor is over the tab strip
-        if(super.indexAtLocation(wev.getPoint().x, wev.getPoint().y) < 0)
-            return;
-
-        // Get currently selected tab
-        int newTab = super.getSelectedIndex() + wev.getWheelRotation();
-
-        // Ensure the new tab index is sound
-        newTab = newTab < 0 ? 0 : newTab;
-        newTab = newTab >= super.getTabCount() ? super.getTabCount() - 1 : newTab;
-
-        // select new tab
-        super.setSelectedIndex(newTab);
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java	(revision 2745)
@@ -7,5 +7,5 @@
      * the current preferences.
      */
-    void addGui(PreferenceDialog gui);
+    void addGui(PreferenceTabbedPane gui);
 
     /**
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 2745)
@@ -0,0 +1,203 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.ScrollPane;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.PluginHandler;
+import org.openstreetmap.josm.tools.BugReportExceptionHandler;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.I18n;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * The preference settings.
+ *
+ * @author imi
+ */
+public class PreferenceTabbedPane extends JTabbedPane implements MouseWheelListener {
+    static private final Logger logger = Logger.getLogger(PreferenceTabbedPane.class.getName());
+
+    private final static Collection<PreferenceSettingFactory> settingsFactory = new LinkedList<PreferenceSettingFactory>();
+    private final List<PreferenceSetting> settings = new ArrayList<PreferenceSetting>();
+
+    // some common tabs
+    public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
+    public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."),false);
+    public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
+    public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
+
+    public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane();
+    public final javax.swing.JTabbedPane mapcontent = new javax.swing.JTabbedPane();
+
+    /**
+     * Construct a JPanel for the preference settings. Layout is GridBagLayout
+     * and a centered title label and the description are added. The panel
+     * will be shown inside a {@link ScrollPane}
+     * @param icon The name of the icon.
+     * @param title The title of this preference tab.
+     * @param desc A description in one sentence for this tab. Will be displayed
+     *      italic under the title.
+     * @return The created panel ready to add other controls.
+     */
+    public JPanel createPreferenceTab(String icon, String title, String desc) {
+        return createPreferenceTab(icon, title, desc, false);
+    }
+
+    /**
+     * Construct a JPanel for the preference settings. Layout is GridBagLayout
+     * and a centered title label and the description are added.
+     * @param icon The name of the icon.
+     * @param title The title of this preference tab.
+     * @param desc A description in one sentence for this tab. Will be displayed
+     *      italic under the title.
+     * @param inScrollPane if <code>true</code> the added tab will show scroll bars
+     *        if the panel content is larger than the available space
+     * @return The created panel ready to add other controls.
+     */
+    public JPanel createPreferenceTab(String icon, String title, String desc, boolean inScrollPane) {
+        JPanel p = new JPanel(new GridBagLayout());
+        p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        p.add(new JLabel(title), GBC.eol().insets(0,5,0,10).anchor(GBC.NORTHWEST));
+
+        JLabel descLabel = new JLabel("<html>"+desc+"</html>");
+        descLabel.setFont(descLabel.getFont().deriveFont(Font.ITALIC));
+        p.add(descLabel, GBC.eol().insets(5,0,5,20).fill(GBC.HORIZONTAL));
+
+        JComponent tab = p;
+        if (inScrollPane) {
+            JScrollPane sp = new JScrollPane(p);
+            tab = sp;
+        }
+        addTab(null, ImageProvider.get("preferences", icon), tab);
+        setToolTipTextAt(getTabCount()-1, "<html>"+desc+"</html>");
+        return p;
+    }
+
+    public void savePreferences() {
+        boolean requiresRestart = false;
+        for (PreferenceSetting setting : settings)
+        {
+            if(setting.ok()) {
+                requiresRestart = true;
+            }
+        }
+        if (requiresRestart) {
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("You have to restart JOSM for some settings to take effect."),
+                    tr("Warning"),
+                    JOptionPane.WARNING_MESSAGE
+            );
+        }
+        Main.parent.repaint();
+    }
+
+    /**
+     * If the dialog is closed with Ok, the preferences will be stored to the preferences-
+     * file, otherwise no change of the file happens.
+     */
+    public PreferenceTabbedPane() {
+        super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
+        super.addMouseWheelListener(this);
+    }
+
+    public void buildGui() {
+        for (PreferenceSettingFactory factory:settingsFactory) {
+            // logger.info("creating settings: " + factory);
+            PreferenceSetting setting = factory.createPreferenceSetting();
+            if (setting != null) {
+                settings.add(factory.createPreferenceSetting());
+            }
+        }
+
+        display.add(displaycontent, GBC.eol().fill(GBC.BOTH));
+        map.add(mapcontent, GBC.eol().fill(GBC.BOTH));
+        for (Iterator<PreferenceSetting> it = settings.iterator(); it.hasNext();) {
+            try {
+                PreferenceSetting settings = it.next();
+                //logger.info("adding gui: " + settings);
+                settings.addGui(this);
+            } catch (SecurityException e) {
+                it.remove();
+            } catch (Throwable e) {
+                /* allow to change most settings even if e.g. a plugin fails */
+                BugReportExceptionHandler.handleException(e);
+            }
+        }
+    }
+
+    public List<PreferenceSetting> getSettings() {
+        return settings;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T>  T getSetting(Class<? extends T> clazz) {
+        for (PreferenceSetting setting:settings) {
+            if (clazz.isAssignableFrom(setting.getClass()))
+                return (T)setting;
+        }
+        return null;
+    }
+
+    static {
+        // order is important!
+        settingsFactory.add(new DrawingPreference.Factory());
+        settingsFactory.add(new ColorPreference.Factory());
+        settingsFactory.add(new LafPreference.Factory());
+        settingsFactory.add(new LanguagePreference.Factory());
+        settingsFactory.add(new ServerAccessPreference.Factory());
+        settingsFactory.add(new ProjectionPreference.Factory());
+        settingsFactory.add(new MapPaintPreference.Factory());
+        settingsFactory.add(new TaggingPresetPreference.Factory());
+        settingsFactory.add(new PluginPreference.Factory());
+        settingsFactory.add(Main.toolbar);
+        settingsFactory.add(new AudioPreference.Factory());
+        settingsFactory.add(new ShortcutPreference.Factory());
+
+        PluginHandler.getPreferenceSetting(settingsFactory);
+
+        // always the last: advanced tab
+        settingsFactory.add(new AdvancedPreference.Factory());
+    }
+
+    /**
+     * This mouse wheel listener reacts when a scroll is carried out over the
+     * tab strip and scrolls one tab/down or up, selecting it immediately.
+     */
+    public void mouseWheelMoved(MouseWheelEvent wev) {
+        // Ensure the cursor is over the tab strip
+        if(super.indexAtLocation(wev.getPoint().x, wev.getPoint().y) < 0)
+            return;
+
+        // Get currently selected tab
+        int newTab = super.getSelectedIndex() + wev.getWheelRotation();
+
+        // Ensure the new tab index is sound
+        newTab = newTab < 0 ? 0 : newTab;
+        newTab = newTab >= super.getTabCount() ? super.getTabCount() - 1 : newTab;
+
+        // select new tab
+        super.setSelectedIndex(newTab);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 2745)
@@ -65,5 +65,5 @@
     static private GBC projSubPrefPanelGBC = GBC.eol().fill(GBC.BOTH).insets(20,5,5,5);
 
-    public void addGui(PreferenceDialog gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         setupProjectionCombo();
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ProxyPreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ProxyPreferences.java	(revision 2742)
+++ 	(revision )
@@ -1,333 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-import static org.openstreetmap.josm.tools.I18n.trc;
-
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.net.ProxySelector;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JPasswordField;
-import javax.swing.JRadioButton;
-import javax.swing.JSeparator;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.JMultilineLabel;
-import org.openstreetmap.josm.io.DefaultProxySelector;
-import org.openstreetmap.josm.tools.GBC;
-
-public class ProxyPreferences implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new ProxyPreferences();
-        }
-    }
-
-    public enum ProxyPolicy {
-        NO_PROXY("no-proxy"),
-        USE_SYSTEM_SETTINGS("use-system-settings"),
-        USE_HTTP_PROXY("use-http-proxy"),
-        USE_SOCKS_PROXY("use-socks-proxy");
-
-        private String policyName;
-        ProxyPolicy(String policyName) {
-            this.policyName = policyName;
-        }
-
-        public String getName() {
-            return policyName;
-        }
-
-        static public ProxyPolicy fromName(String policyName) {
-            if (policyName == null) return null;
-            policyName = policyName.trim().toLowerCase();
-            for(ProxyPolicy pp: values()) {
-                if (pp.getName().equals(policyName))
-                    return pp;
-            }
-            return null;
-        }
-    }
-
-    public static final String PROXY_POLICY = "proxy.policy";
-    public static final String PROXY_HTTP_HOST = "proxy.http.host";
-    public static final String PROXY_HTTP_PORT = "proxy.http.port";
-    public static final String PROXY_SOCKS_HOST = "proxy.socks.host";
-    public static final String PROXY_SOCKS_PORT = "proxy.socks.port";
-    public static final String PROXY_USER = "proxy.user";
-    public static final String PROXY_PASS = "proxy.pass";
-
-    private ButtonGroup bgProxyPolicy;
-    private Map<ProxyPolicy, JRadioButton> rbProxyPolicy;
-    private JTextField tfProxyHttpHost;
-    private JTextField tfProxyHttpPort;
-    private JTextField tfProxySocksHost;
-    private JTextField tfProxySocksPort;
-    private JTextField tfProxyHttpUser;
-    private JPasswordField tfProxyHttpPassword;
-
-    protected JPanel buildHttpProxyConfigurationPanel() {
-        JPanel pnl = new JPanel(new GridBagLayout()) {
-            @Override
-            public Dimension getMinimumSize() {
-                return getPreferredSize();
-            }
-        };
-        GridBagConstraints gc = new GridBagConstraints();
-
-        gc.anchor = GridBagConstraints.WEST;
-        gc.insets = new Insets(5,5,0,0);
-        pnl.add(new JLabel(tr("Host:")), gc);
-
-        gc.gridx = 1;
-        pnl.add(tfProxyHttpHost = new JTextField(20),gc);
-
-        gc.gridy = 1;
-        gc.gridx = 0;
-        pnl.add(new JLabel(trc("server", "Port:")), gc);
-
-        gc.gridx = 1;
-        gc.weightx = 0.0;
-        pnl.add(tfProxyHttpPort = new JTextField(5),gc);
-
-        gc.gridy = 2;
-        gc.gridx = 0;
-        gc.gridwidth = 2;
-        gc.fill = GridBagConstraints.BOTH;
-        gc.weightx = 1.0;
-        gc.weighty = 1.0;
-        pnl.add(new JMultilineLabel(tr("Please enter a username and a password if your proxy requires authentication.")), gc);
-
-        gc.gridy = 3;
-        gc.gridx = 0;
-        gc.gridwidth = 1;
-        gc.weightx = 0.0;
-        gc.fill = GridBagConstraints.NONE;
-        pnl.add(new JLabel(tr("User:")), gc);
-
-        gc.gridy = 3;
-        gc.gridx = 1;
-        pnl.add(tfProxyHttpUser = new JTextField(20),gc);
-
-        gc.gridy = 4;
-        gc.gridx = 0;
-        pnl.add(new JLabel(tr("Password:")), gc);
-
-        gc.gridx = 1;
-        pnl.add(tfProxyHttpPassword = new JPasswordField(20),gc);
-        return pnl;
-    }
-
-    protected JPanel buildSocksProxyConfigurationPanel() {
-        JPanel pnl = new JPanel(new GridBagLayout()) {
-            @Override
-            public Dimension getMinimumSize() {
-                return getPreferredSize();
-            }
-        };
-        GridBagConstraints gc = new GridBagConstraints();
-        gc.anchor = GridBagConstraints.WEST;
-        gc.insets = new Insets(5,5,0,0);
-        pnl.add(new JLabel(tr("Host:")), gc);
-
-        gc.gridx = 1;
-        pnl.add(tfProxySocksHost = new JTextField(20),gc);
-
-        gc.gridy = 1;
-        gc.gridx = 0;
-        pnl.add(new JLabel(trc("server", "Port:")), gc);
-
-        gc.gridx = 1;
-        pnl.add(tfProxySocksPort = new JTextField(5),gc);
-
-        // add an extra spacer, otherwise the layout is broken
-        gc.gridy = 2;
-        gc.gridx = 0;
-        gc.gridwidth = 2;
-        gc.fill = GridBagConstraints.BOTH;
-        gc.weightx = 1.0;
-        gc.weighty = 1.0;
-        pnl.add(new JPanel(), gc);
-        return pnl;
-    }
-
-    protected JPanel buildProxySettingsPanel() {
-        JPanel pnl = new JPanel(new GridBagLayout());
-        GridBagConstraints gc = new GridBagConstraints();
-
-        bgProxyPolicy = new ButtonGroup();
-        rbProxyPolicy = new HashMap<ProxyPolicy, JRadioButton>();
-        ProxyPolicyChangeListener policyChangeListener = new ProxyPolicyChangeListener();
-        for (ProxyPolicy pp: ProxyPolicy.values()) {
-            rbProxyPolicy.put(pp, new JRadioButton());
-            bgProxyPolicy.add(rbProxyPolicy.get(pp));
-            rbProxyPolicy.get(pp).addItemListener(policyChangeListener);
-        }
-        gc.gridx = 0;
-        gc.gridy = 0;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        pnl.add(rbProxyPolicy.get(ProxyPolicy.NO_PROXY),gc);
-        gc.gridx = 1;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.weightx = 1.0;
-        pnl.add(new JLabel(tr("No proxy")), gc);
-
-        gc.gridx = 0;
-        gc.gridy = 1;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS),gc);
-        gc.gridx = 1;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.weightx = 1.0;
-        gc.weighty = 0.0;
-        String msg;
-        if (DefaultProxySelector.willJvmRetrieveSystemProxies()) {
-            msg = tr("Use standard system settings");
-        } else {
-            msg = tr("Use standard system settings (disabled. Start JOSM with <tt>-Djava.net.useSystemProxies=true</tt> to enable)");
-        }
-        pnl.add(new JMultilineLabel("<html>" + msg + "</html>"), gc);
-
-        gc.gridx = 0;
-        gc.gridy = 2;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY),gc);
-        gc.gridx = 1;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.weightx = 1.0;
-        pnl.add(new JLabel(tr("Manually configure a HTTP proxy")),gc);
-
-        gc.gridx = 1;
-        gc.gridy = 3;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.weightx = 1.0;
-        gc.weighty = 0.0;
-        pnl.add(buildHttpProxyConfigurationPanel(),gc);
-
-        gc.gridx = 0;
-        gc.gridy = 4;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY),gc);
-        gc.gridx = 1;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.weightx = 1.0;
-        pnl.add(new JLabel(tr("Use a SOCKS proxy")),gc);
-
-        gc.gridx = 1;
-        gc.gridy = 5;
-        gc.fill = GridBagConstraints.BOTH;
-        gc.anchor = GridBagConstraints.WEST;
-        gc.weightx = 1.0;
-        gc.weighty = 0.0;
-        pnl.add(buildSocksProxyConfigurationPanel(),gc);
-
-        return pnl;
-    }
-
-    protected void initFromPreferences() {
-        String policy = Main.pref.get(PROXY_POLICY, null);
-        ProxyPolicy pp = ProxyPolicy.fromName(policy);
-        pp = pp == null? ProxyPolicy.NO_PROXY: pp;
-        rbProxyPolicy.get(pp).setSelected(true);
-        String value = Main.pref.get("proxy.host", null);
-        if (value != null) {
-            // legacy support
-            tfProxyHttpHost.setText(value);
-            Main.pref.put("proxy.host", null);
-        } else {
-            tfProxyHttpHost.setText(Main.pref.get(PROXY_HTTP_HOST, ""));
-        }
-        value = Main.pref.get("proxy.port", null);
-        if (value != null) {
-            // legacy support
-            tfProxyHttpPort.setText(value);
-            Main.pref.put("proxy.port", null);
-        } else {
-            tfProxyHttpPort.setText(Main.pref.get(PROXY_HTTP_PORT, ""));
-        }
-        tfProxySocksHost.setText(Main.pref.get(PROXY_SOCKS_HOST, ""));
-        tfProxySocksPort.setText(Main.pref.get(PROXY_SOCKS_PORT, ""));
-        tfProxyHttpUser.setText(Main.pref.get(PROXY_USER, ""));
-        tfProxyHttpPassword.setText(Main.pref.get(PROXY_PASS, ""));
-
-        if (pp.equals(ProxyPolicy.USE_SYSTEM_SETTINGS) && ! DefaultProxySelector.willJvmRetrieveSystemProxies()) {
-            System.err.println(tr("Warning: JOSM is configured to use proxies from the system setting, but the JVM is not configured to retrieve them. Resetting preferences to ''No proxy''"));
-            pp = ProxyPolicy.NO_PROXY;
-            rbProxyPolicy.get(pp).setSelected(true);
-        }
-    }
-
-    protected void updateEnabledState() {
-        tfProxyHttpHost.setEnabled(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected());
-        tfProxyHttpPort.setEnabled(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected());
-        tfProxyHttpUser.setEnabled(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected());
-        tfProxyHttpPassword.setEnabled(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected());
-        tfProxySocksHost.setEnabled(rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY).isSelected());
-        tfProxySocksPort.setEnabled(rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY).isSelected());
-
-        rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS).setEnabled(DefaultProxySelector.willJvmRetrieveSystemProxies());
-    }
-
-    class ProxyPolicyChangeListener implements ItemListener {
-        public void itemStateChanged(ItemEvent arg0) {
-            updateEnabledState();
-        }
-    }
-
-    public void addGui(PreferenceDialog gui) {
-        gui.connection.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-        gui.connection.add(new JLabel(tr("Proxy Settings")), GBC.eol());
-        gui.connection.add(buildProxySettingsPanel(), GBC.eol().insets(20,10,0,0));
-
-        initFromPreferences();
-        updateEnabledState();
-    }
-
-    public boolean ok() {
-        ProxyPolicy policy = null;
-        for (ProxyPolicy pp: ProxyPolicy.values()) {
-            if (rbProxyPolicy.get(pp).isSelected()) {
-                policy = pp;
-                break;
-            }
-        }
-        if (policy == null) {
-            policy = ProxyPolicy.NO_PROXY;
-        }
-        Main.pref.put(PROXY_POLICY, policy.getName());
-        Main.pref.put(PROXY_HTTP_HOST, tfProxyHttpHost.getText());
-        Main.pref.put(PROXY_HTTP_PORT, tfProxyHttpPort.getText());
-        Main.pref.put(PROXY_SOCKS_HOST, tfProxySocksHost.getText());
-        Main.pref.put(PROXY_SOCKS_PORT, tfProxySocksPort.getText());
-        Main.pref.put(PROXY_USER, tfProxyHttpUser.getText());
-        Main.pref.put(PROXY_PASS, String.valueOf(tfProxyHttpPassword.getPassword()));
-
-        // remove these legacy property keys
-        Main.pref.put("proxy.anonymous", null);
-        Main.pref.put("proxy.enable", null);
-
-        // update the proxy selector
-        ProxySelector selector = ProxySelector.getDefault();
-        if (selector instanceof DefaultProxySelector) {
-            ((DefaultProxySelector)selector).initFromPreferences();
-        }
-        return false;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java	(revision 2745)
@@ -4,18 +4,19 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Font;
-import java.net.PasswordAuthentication;
-import java.net.Authenticator.RequestorType;
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
 
-import javax.swing.JLabel;
-import javax.swing.JPasswordField;
-import javax.swing.JTextField;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
 
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.io.auth.CredentialsManager;
-import org.openstreetmap.josm.io.auth.CredentialsManagerException;
-import org.openstreetmap.josm.io.auth.CredentialsManagerFactory;
-import org.openstreetmap.josm.tools.GBC;
-
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.preferences.server.AuthenticationPreferencesPanel;
+import org.openstreetmap.josm.gui.preferences.server.BackupPreferencesPanel;
+import org.openstreetmap.josm.gui.preferences.server.OsmApiUrlInputPanel;
+import org.openstreetmap.josm.gui.preferences.server.ProxyPreferencesPanel;
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
 public class ServerAccessPreference implements PreferenceSetting {
 
@@ -26,65 +27,115 @@
     }
 
+    private OsmApiUrlInputPanel pnlApiUrlPreferences;
+
+    private JTabbedPane tpServerPreferences;
+    /** indicates whether to use the default OSM URL or not */
+    /** panel for configuring authentication preferences */
+    private AuthenticationPreferencesPanel pnlAuthPreferences;
+    /** panel for configuring proxy preferences */
+    private ProxyPreferencesPanel pnlProxyPreferences;
+    /** panel for backup preferences */
+    private BackupPreferencesPanel pnlBackupPreferences;
+
     /**
-     * Editfield for the Base url to the REST API from OSM.
+     * Embeds a vertically scrollable panel in a {@see JScrollPane}
+     * @param panel the panel
+     * @return the scroll pane
      */
-    final private JTextField osmDataServerURL = new JTextField(20);
-    /**
-     * Editfield for the username to the OSM account.
-     */
-    final private JTextField osmDataUsername = new JTextField(20);
-    /**
-     * Passwordfield for the userpassword of the REST API.
-     */
-    final private JPasswordField osmDataPassword = new JPasswordField(20);
-
-    public void addGui(PreferenceDialog gui) {
-        CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
-        String oldServerURL = Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api");
-        String oldUsername;
-        String oldPassword;
-        try {
-            PasswordAuthentication credentials =  cm.lookup(RequestorType.SERVER);
-            oldUsername = (credentials == null || credentials.getUserName() == null) ? "" : credentials.getUserName();
-            oldPassword = (credentials == null || credentials.getPassword() == null) ? "" : String.valueOf(credentials.getPassword());
-        } catch(CredentialsManagerException e) {
-            e.printStackTrace();
-            oldUsername = "";
-            oldPassword = "";
-        }
-
-        osmDataServerURL.setText(oldServerURL);
-        osmDataUsername.setText(oldUsername);
-        osmDataPassword.setText(oldPassword);
-        osmDataServerURL.setToolTipText(tr("The base URL for the OSM server (REST API)"));
-        osmDataUsername.setToolTipText(tr("Login name (e-mail) to the OSM account."));
-        osmDataPassword.setToolTipText(tr("Login password to the OSM account. Leave blank to not store any password."));
-
-        gui.connection.add(new JLabel(tr("Base Server URL")), GBC.std());
-        gui.connection.add(osmDataServerURL, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-        gui.connection.add(new JLabel(tr("OSM username (e-mail)")), GBC.std());
-        gui.connection.add(osmDataUsername, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-        gui.connection.add(new JLabel(tr("OSM password")), GBC.std());
-        gui.connection.add(osmDataPassword, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,0));
-        JLabel warning = new JLabel(tr("<html>" +
-                "WARNING: The password is stored in plain text in the preferences file.<br>" +
-                "The password is transferred in plain text to the server, encoded in the URL.<br>" +
-        "<b>Do not use a valuable Password.</b></html>"));
-        warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
-        gui.connection.add(warning, GBC.eop().fill(GBC.HORIZONTAL));
+    protected JScrollPane wrapVerticallyScrollablePanel(VerticallyScrollablePanel panel) {
+        JScrollPane sp = new JScrollPane(panel);
+        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+        return sp;
     }
 
+    /**
+     * Builds the tabbed pane with the server preferences
+     * 
+     * @return
+     */
+    protected JPanel buildTabbedServerPreferences() {
+        JPanel pnl = new JPanel(new BorderLayout());
+
+        tpServerPreferences = new JTabbedPane();
+        pnlAuthPreferences = new AuthenticationPreferencesPanel();
+        tpServerPreferences.add(wrapVerticallyScrollablePanel(pnlAuthPreferences));
+        pnlProxyPreferences = new ProxyPreferencesPanel();
+        tpServerPreferences.add(wrapVerticallyScrollablePanel(pnlProxyPreferences));
+        pnlBackupPreferences = new BackupPreferencesPanel();
+        tpServerPreferences.add(wrapVerticallyScrollablePanel(pnlBackupPreferences));
+
+        tpServerPreferences.setTitleAt(0, tr("Authentication"));
+        tpServerPreferences.setTitleAt(1, tr("Proxy settings"));
+        tpServerPreferences.setTitleAt(2, tr("File backup"));
+        tpServerPreferences.setToolTipTextAt(0, tr("Configure your identity and how to authenticate at the OSM server"));
+        tpServerPreferences.setToolTipTextAt(1, tr("Configure whether to use a proxy server"));
+        tpServerPreferences.setToolTipTextAt(2, tr("Configure whether to create backup files"));
+
+        pnl.add(tpServerPreferences, BorderLayout.CENTER);
+        return pnl;
+    }
+
+    /**
+     * Builds the panel for entering the server access preferences
+     * 
+     * @return
+     */
+    protected JPanel buildContentPanel() {
+        JPanel pnl = new JPanel(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+
+        // the checkbox for the default UL
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.weightx = 1.0;
+        gc.insets = new Insets(0,0,0,0);
+        pnl.add(pnlApiUrlPreferences = new OsmApiUrlInputPanel(), gc);
+
+        // the remaining access properties
+        gc.gridy = 1;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        gc.insets = new Insets(10,0,3,3);
+        pnl.add(buildTabbedServerPreferences(), gc);
+
+        // let the AuthPreferencesPanel know when the API URL changes
+        //
+        pnlApiUrlPreferences.addPropertyChangeListener(pnlAuthPreferences);
+
+        HelpUtil.setHelpContext(pnl, HelpUtil.ht("/Preferences/Connection"));
+        return pnl;
+    }
+
+    public void addGui(PreferenceTabbedPane gui) {
+        GridBagConstraints gc = new GridBagConstraints();
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gui.connection.add(buildContentPanel(), gc);
+
+        initFromPreferences();
+    }
+
+    /**
+     * Initializes the configuration panel with values from the preferences
+     */
+    public void initFromPreferences() {
+        pnlApiUrlPreferences.initFromPreferences();
+        pnlAuthPreferences.initFromPreferences();
+        pnlProxyPreferences.initFromPreferences();
+        pnlBackupPreferences.initFromPreferences();
+    }
+
+    /**
+     * Saves the values to the preferences
+     */
     public boolean ok() {
-        CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
-        Main.pref.put("osm-server.url", osmDataServerURL.getText());
-        try {
-            cm.store(RequestorType.SERVER, new PasswordAuthentication(
-                    osmDataUsername.getText(),
-                    osmDataPassword.getPassword()
-            ));
-        } catch(CredentialsManagerException e) {
-            // FIXME: Message dialog with an error message?
-            e.printStackTrace();
-        }
+        pnlApiUrlPreferences.saveToPreferences();
+        pnlAuthPreferences.saveToPreferences();
+        pnlProxyPreferences.saveToPreferences();
+        pnlBackupPreferences.saveToPreferences();
         return false;
     }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java	(revision 2745)
@@ -20,5 +20,5 @@
     }
 
-    public void addGui(PreferenceDialog gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         // icon source: http://www.iconfinder.net/index.php?q=key&page=icondetails&iconid=8553&size=128&q=key&s12=on&s16=on&s22=on&s32=on&s48=on&s64=on&s128=on
         // icon licence: GPL
Index: trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 2745)
@@ -36,5 +36,5 @@
     private JCheckBox enableDefault;
 
-    public void addGui(final PreferenceDialog gui) {
+    public void addGui(final PreferenceTabbedPane gui) {
         sortMenu = new JCheckBox(tr("Sort presets menu"),
                 Main.pref.getBoolean("taggingpreset.sortmenu", false));
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 2742)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 2745)
@@ -172,5 +172,5 @@
         }
 
-        public void addGui(PreferenceDialog gui) {
+        public void addGui(PreferenceTabbedPane gui) {
             actionsTree.setCellRenderer(new DefaultTreeCellRenderer() {
                 @Override
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java	(revision 2745)
@@ -0,0 +1,234 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.xml.sax.SAXException;
+
+/**
+ * This is an asynchronous task for testing whether an URL points to an OSM API server.
+ * It tries to retrieve a list of changesets from the given URL. If it succeeds, the method
+ * {@see #isSuccess()} replies true, otherwise false.
+ * 
+ * Note: it fetches a list of changesets instead of the much smaller capabilities because - strangely enough -
+ * an OSM server "http://x.y.y/api/0.6" not only responds to  "http://x.y.y/api/0.6/capabilities" but also
+ * to "http://x.y.y/api/0/capabilities" or "http://x.y.y/a/capabilities" with valid capabilities. If we get
+ * valid capabilities with an URL we therefore can't be sure that the base URL is valid API URL.
+ * 
+ */
+public class ApiUrlTestTask extends PleaseWaitRunnable{
+
+    private String url;
+    private boolean canceled;
+    private boolean success;
+    private Component parent;
+    private HttpURLConnection connection;
+
+    /**
+     * Creates the task
+     * 
+     * @param parent the parent component relative to which the {@see PleaseWaitRunnable}-Dialog is displayed
+     * @param url the url. Must not be null.
+     * @throws IllegalArgumentException thrown if url is null.
+     */
+    public ApiUrlTestTask(Component parent, String url) throws IllegalArgumentException {
+        super(parent, tr("Testing OSM API URL ''{0}''", url), false /* don't ignore exceptions */);
+        CheckParameterUtil.ensureParameterNotNull(url,"url");
+        this.parent = parent;
+        this.url = url;
+    }
+
+    protected void alertInvalidUrl(String url) {
+        HelpAwareOptionPane.showOptionDialog(
+                parent,
+                tr("<html>"
+                        + "''{0}'' isn't a valid OSM API URL.<br>"
+                        + "Please check the spelling and validate again."
+                        +"</html>",
+                        url
+                ),
+                tr("Invalid API URL"),
+                JOptionPane.ERROR_MESSAGE,
+                HelpUtil.ht("/Preferences/Connection#InvalidAPIUrl")
+        );
+    }
+
+    protected void alertInvalidChangesetUrl(String url) {
+        HelpAwareOptionPane.showOptionDialog(
+                parent,
+                tr("<html>"
+                        + "Failed to build URL ''{0}'' for validating the OSM API server.<br>"
+                        + "Please check the spelling of ''{1}'' and validate again."
+                        +"</html>",
+                        url,
+                        getNormalizedApiUrl()
+                ),
+                tr("Invalid API URL"),
+                JOptionPane.ERROR_MESSAGE,
+                HelpUtil.ht("/Preferences/Connection#InvalidAPIGetChangesetsUrl")
+        );
+    }
+
+    protected void alertConnectionFailed() {
+        HelpAwareOptionPane.showOptionDialog(
+                parent,
+                tr("<html>"
+                        + "Failed to connect to the URL ''{0}''.<br>"
+                        + "Please check the spelling of ''{1}'' and your Internet connection and validate again."
+                        +"</html>",
+                        url,
+                        getNormalizedApiUrl()
+                ),
+                tr("Connection to API failed"),
+                JOptionPane.ERROR_MESSAGE,
+                HelpUtil.ht("/Preferences/Connection#ConnectionToAPIFailed")
+        );
+    }
+
+    protected void alertInvalidServerResult(int retCode) {
+        HelpAwareOptionPane.showOptionDialog(
+                parent,
+                tr("<html>"
+                        + "Failed to retrieve a list of changesets from the OSM API server at<br>"
+                        + "''{1}''. The server responded with the return code {0} instead of 200.<br>"
+                        + "Please check the spelling of ''{1}'' and validate again."
+                        + "</html>",
+                        retCode,
+                        getNormalizedApiUrl()
+                ),
+                tr("Connection to API failed"),
+                JOptionPane.ERROR_MESSAGE,
+                HelpUtil.ht("/Preferences/Connection#InvalidServerResult")
+        );
+    }
+
+    protected void alertInvalidChangesetList() {
+        HelpAwareOptionPane.showOptionDialog(
+                parent,
+                tr("<html>"
+                        + "The OSM API server at ''{0}'' didn''t return a valid response.<br>"
+                        + "It is likely that ''{0}'' isn''t an OSM API server.<br>"
+                        + "Please check the spelling of ''{0}'' and validate again."
+                        + "</html>",
+                        getNormalizedApiUrl()
+                ),
+                tr("Connection to API failed"),
+                JOptionPane.ERROR_MESSAGE,
+                HelpUtil.ht("/Preferences/Connection#InvalidSettings")
+        );
+    }
+
+    @Override
+    protected void cancel() {
+        canceled = true;
+        synchronized(this) {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
+
+    @Override
+    protected void finish() {}
+
+    /**
+     * Removes leading and trailing whitespace from the API URL and removes trailing
+     * '/'.
+     * 
+     * @return the normalized API URL
+     */
+    protected String getNormalizedApiUrl() {
+        String apiUrl = url.trim();
+        while(apiUrl.endsWith("/")) {
+            apiUrl = apiUrl.substring(0, apiUrl.lastIndexOf("/"));
+        }
+        return apiUrl;
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        BufferedReader bin = null;
+        try {
+            try {
+                new URL(getNormalizedApiUrl());
+            } catch(MalformedURLException e) {
+                alertInvalidUrl(getNormalizedApiUrl());
+                return;
+            }
+            URL capabilitiesUrl;
+            String getChangesetsUrl = getNormalizedApiUrl() + "/0.6/changesets";
+            try {
+                capabilitiesUrl = new URL(getChangesetsUrl);
+            } catch(MalformedURLException e) {
+                alertInvalidChangesetUrl(getChangesetsUrl);
+                return;
+            }
+
+            synchronized(this) {
+                connection = (HttpURLConnection)capabilitiesUrl.openConnection();
+            }
+            connection.setDoInput(true);
+            connection.setDoOutput(false);
+            connection.setRequestMethod("GET");
+            connection.setRequestProperty("User-Agent", Version.getInstance().getAgentString());
+            connection.setRequestProperty("Host", connection.getURL().getHost());
+            connection.connect();
+
+            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                alertInvalidServerResult(connection.getResponseCode());
+                return;
+            }
+            StringBuilder changesets = new StringBuilder();
+            bin = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+            String line;
+            while ((line = bin.readLine()) != null) {
+                changesets.append(line).append("\n");
+            }
+            if (! (changesets.toString().contains("<osm") && changesets.toString().contains("</osm>"))) {
+                // heuristic: if there isn't an opening and closing "<osm>" tag in the returned content,
+                // then we didn't get a list of changesets in return. Could be replaced by explicitly parsing
+                // the result but currently not worth the effort.
+                alertInvalidChangesetList();
+                return;
+            }
+            success = true;
+        } catch(IOException e) {
+            if (canceled)
+                // ignore exceptions
+                return;
+            e.printStackTrace();
+            alertConnectionFailed();
+            return;
+        } finally {
+            if (bin != null) {
+                try {
+                    bin.close();
+                } catch(IOException e){/* ignore */}
+            }
+        }
+    }
+
+    public boolean isCanceled() {
+        return canceled;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java	(revision 2745)
@@ -0,0 +1,158 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
+import org.openstreetmap.josm.io.auth.CredentialsManagerFactory;
+
+/**
+ * This is the preference panel for the authentication method and the authentication
+ * parameters.
+ * 
+ */
+public class AuthenticationPreferencesPanel extends VerticallyScrollablePanel implements PropertyChangeListener{
+
+    /** indicates whether we use basic authentication */
+    private JRadioButton rbBasicAuthentication;
+    /** indicates whether we use OAuth as authentication scheme */
+    private JRadioButton rbOAuth;
+    /** the panel which contains the authentication parameters for the respective
+     * authentication scheme
+     */
+    private JPanel pnlAuthenticationParameteters;
+    /** the panel for the basic authentication parameters */
+    private BasicAuthenticationPreferencesPanel pnlBasicAuthPreferences;
+    /** the panel for the OAuth authentication parameters */
+    private OAuthAuthenticationPreferencesPanel pnlOAuthPreferences;
+
+    /**
+     * builds the UI
+     */
+    protected void build() {
+        setLayout(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+
+        AuthenticationMethodChangeListener  authChangeListener = new AuthenticationMethodChangeListener();
+
+        // -- radio button for basic authentication
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.weightx = 0.0;
+        gc.insets = new Insets(0,0,0, 3);
+        add(rbBasicAuthentication = new JRadioButton(), gc);
+        rbBasicAuthentication.setText(tr("Use Basic Authentication"));
+        rbBasicAuthentication.setToolTipText(tr("Select to use HTTP basic authentication with your OSM username and password"));
+        rbBasicAuthentication.addItemListener(authChangeListener);
+
+        //-- radio button for OAuth
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        add(rbOAuth = new JRadioButton(), gc);
+        rbOAuth.setText(tr("Use OAuth"));
+        rbOAuth.setToolTipText(tr("Select to use OAuth as authentication mechanism"));
+        rbOAuth.addItemListener(authChangeListener);
+
+        //-- radio button for OAuth
+        ButtonGroup bg = new ButtonGroup();
+        bg.add(rbBasicAuthentication);
+        bg.add(rbOAuth);
+
+        //-- add the panel which will hld the authentication parameters
+        gc.gridx = 0;
+        gc.gridy = 1;
+        gc.gridwidth = 2;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        add(pnlAuthenticationParameteters = new JPanel(), gc);
+        pnlAuthenticationParameteters.setLayout(new BorderLayout());
+
+        //-- the two panel for authentication parameters
+        pnlBasicAuthPreferences = new BasicAuthenticationPreferencesPanel();
+        pnlOAuthPreferences = new OAuthAuthenticationPreferencesPanel();
+
+        rbBasicAuthentication.setSelected(true);
+        pnlAuthenticationParameteters.add(pnlBasicAuthPreferences, BorderLayout.CENTER);
+    }
+
+    public AuthenticationPreferencesPanel() {
+        build();
+        HelpUtil.setHelpContext(this, HelpUtil.ht("/Preferences/Connection#AuthenticationSettings"));
+    }
+
+    public void initFromPreferences() {
+        String authMethod = Main.pref.get("osm-server.auth-method", "basic");
+        if (authMethod.equals("basic")) {
+            rbBasicAuthentication.setSelected(true);
+        } else if (authMethod.equals("oauth")) {
+            rbOAuth.setSelected(true);
+        } else {
+            System.err.println(tr("Warning: Unsupported value in preference ''{0}'', got {1}''. Using authentication method ''Basic Authentication''.", "osm-server.auth-method", authMethod));
+            rbBasicAuthentication.setSelected(true);
+        }
+        pnlBasicAuthPreferences.initFromPreferences();
+        pnlOAuthPreferences.initFromPreferences();
+    }
+
+    public void saveToPreferences() {
+        // save the authentication method
+        String authMethod;
+        if (rbBasicAuthentication.isSelected()) {
+            authMethod = "basic";
+        } else {
+            authMethod = "oauth";
+        }
+        Main.pref.put("osm-server.auth-method", authMethod);
+        if (authMethod.equals("basic")) {
+            // save username and password and clear the OAuth token
+            pnlBasicAuthPreferences.saveToPreferences();
+            OAuthAccessTokenHolder.getInstance().clear();
+            OAuthAccessTokenHolder.getInstance().save(Main.pref, CredentialsManagerFactory.getCredentialManager());
+        } else if (authMethod.equals("oauth")) {
+            // clear the password in the preferences
+            pnlBasicAuthPreferences.clearPassword();
+            pnlBasicAuthPreferences.saveToPreferences();
+            pnlOAuthPreferences.saveToPreferences();
+        }
+    }
+
+    /**
+     * Listens to changes in the authentication method
+     */
+    class AuthenticationMethodChangeListener implements ItemListener {
+        public void itemStateChanged(ItemEvent e) {
+            if (rbBasicAuthentication.isSelected()) {
+                pnlAuthenticationParameteters.removeAll();
+                pnlAuthenticationParameteters.add(pnlBasicAuthPreferences, BorderLayout.CENTER);
+                pnlBasicAuthPreferences.revalidate();
+            } else {
+                pnlAuthenticationParameteters.removeAll();
+                pnlAuthenticationParameteters.add(pnlOAuthPreferences, BorderLayout.CENTER);
+                pnlOAuthPreferences.revalidate();
+            }
+            repaint();
+        }
+    }
+
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (pnlOAuthPreferences != null) {
+            pnlOAuthPreferences.propertyChange(evt);
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/BackupPreferencesPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/BackupPreferencesPanel.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/BackupPreferencesPanel.java	(revision 2745)
@@ -0,0 +1,54 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
+
+public class BackupPreferencesPanel extends VerticallyScrollablePanel {
+
+    private JCheckBox keepBackup;
+
+    protected void build() {
+        setLayout(new GridBagLayout());
+        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        GridBagConstraints gc = new GridBagConstraints();
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.weightx = 1.0;
+        keepBackup = new JCheckBox(tr("Keep backup files"));
+        keepBackup.setSelected(Main.pref.getBoolean("save.keepbackup"));
+        keepBackup.setToolTipText(tr("When saving, keep backup files ending with a ~"));
+        add(keepBackup, gc);
+
+        // filler - grab remaining space
+        gc.gridy = 1;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        add(new JPanel(), gc);
+    }
+
+    public void saveToPreferences() {
+        Main.pref.put("save.keepbackup", keepBackup.isSelected());
+    }
+
+    public void initFromPreferences() {
+        keepBackup.setSelected(Main.pref.getBoolean("save.keepbackup", true));
+    }
+
+    public BackupPreferencesPanel() {
+        build();
+        HelpUtil.setHelpContext(this, HelpUtil.ht("/Preferences/Connection#BackupSettings"));
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java	(revision 2745)
@@ -0,0 +1,142 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.net.PasswordAuthentication;
+import java.net.Authenticator.RequestorType;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.text.html.HTMLEditorKit;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
+import org.openstreetmap.josm.io.auth.CredentialsManager;
+import org.openstreetmap.josm.io.auth.CredentialsManagerException;
+import org.openstreetmap.josm.io.auth.CredentialsManagerFactory;
+import org.openstreetmap.josm.io.auth.JosmPreferencesCredentialManager;
+
+/**
+ * The preferences panel for parameters necessary for the Basic Authentication
+ * Scheme.
+ * 
+ */
+public class BasicAuthenticationPreferencesPanel extends JPanel {
+
+    /** the OSM user name */
+    private JTextField tfOsmUserName;
+    private UserNameValidator valUserName;
+    /** the OSM password */
+    private JPasswordField tfOsmPassword;
+
+
+    /**
+     * builds the UI
+     */
+    protected void build() {
+        setLayout(new GridBagLayout());
+        setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
+        GridBagConstraints gc = new GridBagConstraints();
+
+        // -- OSM user name
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.weightx = 0.0;
+        gc.insets = new Insets(0,0,3,3);
+        add(new JLabel(tr("OSM username:")), gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        add(tfOsmUserName = new JTextField(), gc);
+        SelectAllOnFocusGainedDecorator.decorate(tfOsmUserName);
+        valUserName = new UserNameValidator(tfOsmUserName);
+        valUserName.validate();
+
+        // -- OSM password
+        gc.gridx = 0;
+        gc.gridy = 1;
+        gc.weightx = 0.0;
+        add(new JLabel(tr("OSM password:")), gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        add(tfOsmPassword = new JPasswordField(), gc);
+        SelectAllOnFocusGainedDecorator.decorate(tfOsmPassword);
+        tfOsmPassword.setToolTipText(tr("Please enter your OSM password"));
+
+        // -- an info panel with a warning message
+        gc.gridx = 0;
+        gc.gridy = 2;
+        gc.gridwidth = 2;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        gc.insets = new Insets(5,0,0,0);
+        gc.fill = GridBagConstraints.BOTH;
+        HtmlPanel pnlMessage = new HtmlPanel();
+        HTMLEditorKit kit = (HTMLEditorKit)pnlMessage.getEditorPane().getEditorKit();
+        kit.getStyleSheet().addRule(".warning-body {background-color:rgb(253,255,221);padding: 10pt; border-color:rgb(128,128,128);border-style: solid;border-width: 1px;}");
+        pnlMessage.setText(
+                tr(
+                        "<html><body>"
+                        + "<p class=\"warning-body\">"
+                        + "<strong>Warning:</strong> The password is stored in plain text in the JOSM preferences file. "
+                        + "Furthermore, it is transferred <strong>unencrypted</strong> in every request sent to the OSM server. "
+                        + "<strong>Do not use a valuable password.</strong>"
+                        + "</p>"
+                        + "</body></html>"
+                )
+        );
+        add(pnlMessage, gc);
+    }
+
+    public BasicAuthenticationPreferencesPanel() {
+        build();
+    }
+
+    public void initFromPreferences() {
+        CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
+        try {
+            PasswordAuthentication pa = cm.lookup(RequestorType.SERVER);
+            tfOsmUserName.setText(pa.getUserName() == null? "" : pa.getUserName());
+            tfOsmPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
+        } catch(CredentialsManagerException e) {
+            e.printStackTrace();
+            System.err.println(tr("Warning: failed to retrieve OSM credentials from credential manager."));
+            System.err.println(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
+            tfOsmUserName.setText("");
+            tfOsmPassword.setText("");
+        }
+    }
+
+    public void saveToPreferences() {
+        CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
+        try {
+            PasswordAuthentication pa = new PasswordAuthentication(
+                    tfOsmUserName.getText().trim(),
+                    tfOsmPassword.getPassword()
+            );
+            cm.store(RequestorType.SERVER, pa);
+            // always save the username to the preferences if it isn't already saved there
+            // by the credential manager
+            if (! (cm instanceof JosmPreferencesCredentialManager)) {
+                Main.pref.put("osm-server.username", tfOsmUserName.getText().trim());
+            }
+        } catch(CredentialsManagerException e) {
+            e.printStackTrace();
+            System.err.println(tr("Warning: failed to save OSM credentials to credential manager."));
+            System.err.println(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
+        }
+    }
+
+    public void clearPassword() {
+        tfOsmPassword.setText("");
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAccessTokenHolder.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAccessTokenHolder.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAccessTokenHolder.java	(revision 2745)
@@ -0,0 +1,193 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.logging.Logger;
+
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.oauth.OAuthToken;
+import org.openstreetmap.josm.io.auth.CredentialsManager;
+import org.openstreetmap.josm.io.auth.CredentialsManagerException;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+
+public class OAuthAccessTokenHolder {
+    static private final Logger logger = Logger.getLogger(OAuthAccessTokenHolder.class.getName());
+
+    private  static OAuthAccessTokenHolder instance;
+
+    public static OAuthAccessTokenHolder getInstance() {
+        if (instance == null) {
+            instance = new OAuthAccessTokenHolder();
+        }
+        return instance;
+    }
+
+    private boolean saveToPreferences;
+    private String accessTokenKey;
+    private String accessTokenSecret;
+
+    /**
+     * Replies true if current access token should be saved to the preferences file.
+     *
+     * @return true if current access token should be saved to the preferences file.
+     */
+    public boolean isSaveToPreferences() {
+        return saveToPreferences;
+    }
+
+    /**
+     * Sets whether the current access token should be saved to the preferences file.
+     * 
+     * If true, the access token is saved in clear text to the preferences file. The same
+     * access token can therefore be used in multiple JOSM sessions.
+     * 
+     * If false, the access token isn't saved to the preferences file. If JOSM is closed,
+     * the access token is lost and new token has to be generated by the OSM server the
+     * next time JOSM is used.
+     * 
+     * @param saveToPreferences
+     */
+    public void setSaveToPreferences(boolean saveToPreferences) {
+        this.saveToPreferences = saveToPreferences;
+    }
+
+    /**
+     * Replies the access token key. null, if no access token key is currently set.
+     * 
+     * @return the access token key
+     */
+    public String getAccessTokenKey() {
+        return accessTokenKey;
+    }
+
+    /**
+     * Sets the access token key. Pass in null to remove the current access token key.
+     * 
+     * @param accessTokenKey the access token key
+     */
+    public void setAccessTokenKey(String accessTokenKey) {
+        this.accessTokenKey = accessTokenKey;
+    }
+
+    /**
+     * Replies the access token secret. null, if no access token secret is currently set.
+     * 
+     * @return the access token secret
+     */
+    public String getAccessTokenSecret() {
+        return accessTokenSecret;
+    }
+
+    /**
+     * Sets the access token secret. Pass in null to remove the current access token secret.
+     * 
+     * @param accessTokenSecret
+     */
+    public void setAccessTokenSecret(String accessTokenSecret) {
+        this.accessTokenSecret = accessTokenSecret;
+    }
+
+    public OAuthToken getAccessToken() {
+        if (!containsAccessToken())
+            return null;
+        return new OAuthToken(accessTokenKey, accessTokenSecret);
+    }
+
+    /**
+     * Sets the access token hold by this holder.
+     * 
+     * @param accessTokenKey the access token key
+     * @param accessTokenSecret the access token secret
+     */
+    public void setAccessToken(String accessTokenKey, String accessTokenSecret) {
+        this.accessTokenKey = accessTokenKey;
+        this.accessTokenSecret = accessTokenSecret;
+    }
+
+    /**
+     * Sets the access token hold by this holder.
+     * 
+     * @param token the access token. Can be null to clear the content in this holder.
+     */
+    public void setAccessToken(OAuthToken token) {
+        if (token == null) {
+            this.accessTokenKey = null;
+            this.accessTokenSecret = null;
+        } else {
+            this.accessTokenKey = token.getKey();
+            this.accessTokenSecret = token.getSecret();
+        }
+    }
+
+    /**
+     * Replies true if this holder contains an complete access token, consisting of an
+     * Access Token Key and an Access Token Secret.
+     * 
+     * @return true if this holder contains an complete access token
+     */
+    public boolean containsAccessToken() {
+        return accessTokenKey != null && accessTokenSecret != null;
+    }
+
+    /**
+     * Initializes the content of this holder from the Access Token managed by the
+     * credential manager.
+     * 
+     * @param pref the preferences. Must not be null.
+     * @param cm the credential manager. Must not be null.
+     * @throws IllegalArgumentException thrown if cm is null
+     */
+    public void init(Preferences pref, CredentialsManager cm) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(pref, "pref");
+        CheckParameterUtil.ensureParameterNotNull(cm, "cm");
+        OAuthToken token = null;
+        try {
+            token = cm.lookupOAuthAccessToken();
+        } catch(CredentialsManagerException e) {
+            e.printStackTrace();
+            System.err.println(tr("Warning: Failed to retrieve OAuth Access Token from credential manager"));
+            System.err.println(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
+        }
+        saveToPreferences = pref.getBoolean("oauth.access-token.save-to-preferences", true);
+        if (token != null) {
+            accessTokenKey = token.getKey();
+            accessTokenSecret = token.getSecret();
+        }
+    }
+
+    /**
+     * Saves the content of this holder to the preferences and a credential store managed
+     * by a credential manager.
+     * 
+     * @param preferences the preferences. Must not be null.
+     * @param cm the credentials manager. Must not be null.
+     * @throws IllegalArgumentException thrown if preferences is null
+     * @throws IllegalArgumentException thrown if cm is null
+     */
+    public void save(Preferences preferences, CredentialsManager cm) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(preferences, "preferences");
+        CheckParameterUtil.ensureParameterNotNull(cm, "cm");
+        preferences.put("oauth.access-token.save-to-preferences", saveToPreferences);
+        try {
+            if (!saveToPreferences) {
+                cm.storeOAuthAccessToken(null);
+            } else {
+                cm.storeOAuthAccessToken(new OAuthToken(accessTokenKey, accessTokenSecret));
+            }
+        } catch(CredentialsManagerException e){
+            e.printStackTrace();
+            System.err.println(tr("Warning: Failed to store OAuth Access Token to credentials manager"));
+            System.err.println(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
+        }
+    }
+
+    /**
+     * Clears the content of this holder
+     */
+    public void clear() {
+        accessTokenKey = null;
+        accessTokenSecret = null;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java	(revision 2745)
@@ -0,0 +1,379 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.oauth.OAuthParameters;
+import org.openstreetmap.josm.data.oauth.OAuthToken;
+import org.openstreetmap.josm.gui.JMultilineLabel;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.oauth.AdvancedOAuthPropertiesPanel;
+import org.openstreetmap.josm.gui.oauth.OAuthAuthorisationWizard;
+import org.openstreetmap.josm.gui.oauth.TestAccessTokenTask;
+import org.openstreetmap.josm.io.auth.CredentialsManagerFactory;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * The preferences panel for the OAuth preferences. This just a summary panel
+ * showing the current Access Token Key and Access Token Secret, if the
+ * user already has an Access Token.
+ * 
+ * For initial authorisation see {@see OAuthAuthorisationWizard}.
+ * 
+ */
+public class OAuthAuthenticationPreferencesPanel extends JPanel implements PropertyChangeListener {
+    private static final Logger logger = Logger.getLogger(OAuthAuthenticationPreferencesPanel.class.getName());
+
+    private JPanel pnlAuthorisationMessage;
+    private NotYetAuthorisedPanel pnlNotYetAutorised;
+    private AlreadyAuthorisedPanel pnlAlreadyAutorised;
+    private AdvancedOAuthPropertiesPanel pnlAdvancedProperties;
+    private String apiUrl;
+    private JCheckBox cbShowAdvancedParameters;
+    private JCheckBox cbSaveToPreferences;
+
+    /**
+     * Builds the panel for entering the advanced OAuth parameters
+     * 
+     * @return
+     */
+    protected JPanel buildAdvancedPropertiesPanel() {
+        JPanel pnl = new JPanel(new GridBagLayout());
+        GridBagConstraints gc= new GridBagConstraints();
+
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.weightx = 0.0;
+        gc.insets = new Insets(0,0,0,3);
+        pnl.add(cbShowAdvancedParameters = new JCheckBox(), gc);
+        cbShowAdvancedParameters.setSelected(false);
+        cbShowAdvancedParameters.addItemListener(
+                new ItemListener() {
+                    public void itemStateChanged(ItemEvent evt) {
+                        pnlAdvancedProperties.setVisible(evt.getStateChange() == ItemEvent.SELECTED);
+                    }
+                }
+        );
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        JMultilineLabel lbl = new JMultilineLabel(tr("Display Advanced OAuth Parameters"));
+        lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
+        pnl.add(lbl, gc);
+
+        gc.gridy = 1;
+        gc.gridx = 1;
+        gc.insets = new Insets(3,0,3,0);
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        pnl.add(pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(), gc);
+        pnlAdvancedProperties.initFromPreferences(Main.pref);
+        pnlAdvancedProperties.setBorder(
+                BorderFactory.createCompoundBorder(
+                        BorderFactory.createLineBorder(Color.GRAY, 1),
+                        BorderFactory.createEmptyBorder(3,3,3,3)
+                )
+        );
+        pnlAdvancedProperties.setVisible(false);
+        return pnl;
+    }
+
+    /**
+     * builds the UI
+     */
+    protected void build() {
+        setLayout(new GridBagLayout());
+        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        GridBagConstraints gc = new GridBagConstraints();
+
+        // the panel for the OAuth parameters. pnlAuthorisationMessage is an
+        // empty panel. It is going to be filled later, depending on the
+        // current OAuth state in JOSM.
+        gc.fill = GridBagConstraints.BOTH;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.weighty = 1.0;
+        gc.weightx = 1.0;
+        gc.insets = new Insets(10,0,0,0);
+        add(pnlAuthorisationMessage = new JPanel(), gc);
+        pnlAuthorisationMessage.setLayout(new BorderLayout());
+
+        // create these two panels, they are going to be used later in refreshView
+        //
+        pnlAlreadyAutorised = new AlreadyAuthorisedPanel();
+        pnlNotYetAutorised = new NotYetAuthorisedPanel();
+    }
+
+    protected void refreshView() {
+        pnlAuthorisationMessage.removeAll();
+        if (OAuthAccessTokenHolder.getInstance().containsAccessToken()) {
+            pnlAuthorisationMessage.add(pnlAlreadyAutorised, BorderLayout.CENTER);
+            pnlAlreadyAutorised.refreshView();
+            pnlAlreadyAutorised.revalidate();
+        } else {
+            pnlAuthorisationMessage.add(pnlNotYetAutorised, BorderLayout.CENTER);
+            pnlNotYetAutorised.revalidate();
+        }
+        repaint();
+    }
+
+    /**
+     * Create the panel
+     */
+    public OAuthAuthenticationPreferencesPanel() {
+        build();
+        refreshView();
+    }
+
+    public void setApiUrl(String apiUrl) {
+        this.apiUrl = apiUrl;
+    }
+
+    /**
+     * Initializes the panel from preferences
+     */
+    public void initFromPreferences() {
+        refreshView();
+    }
+
+    /**
+     * Saves the current values to preferences
+     */
+    public void saveToPreferences() {
+        OAuthAccessTokenHolder.getInstance().setSaveToPreferences(cbSaveToPreferences.isSelected());
+        OAuthAccessTokenHolder.getInstance().save(Main.pref, CredentialsManagerFactory.getCredentialManager());
+        pnlAdvancedProperties.getAdvancedParameters().saveToPreferences(Main.pref);
+    }
+
+    /**
+     * The preferences panel displayed if there is currently no Access Token available.
+     * This means that the user didn't run through the OAuth authorisation procedure yet.
+     * 
+     */
+    private class NotYetAuthorisedPanel extends JPanel {
+        protected void build() {
+            setLayout(new GridBagLayout());
+            GridBagConstraints gc = new GridBagConstraints();
+
+            // A message explaining that the user isn't authorised yet
+            gc.anchor = GridBagConstraints.NORTHWEST;
+            gc.insets = new Insets(0,0,3,0);
+            gc.fill = GridBagConstraints.HORIZONTAL;
+            gc.weightx = 1.0;
+            JLabel lbl;
+            add(lbl = new JMultilineLabel(tr("You don't have an Access Token yet to access the OSM server using OAuth. Please authorise first.")), gc);
+            lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
+
+            // Action for authorising now
+            gc.gridy = 1;
+            gc.fill = GridBagConstraints.NONE;
+            gc.weightx = 0.0;
+            add(new SideButton(new AuthoriseNowAction()), gc);
+
+            // filler - grab remaining space
+            gc.gridy = 2;
+            gc.fill = GridBagConstraints.BOTH;
+            gc.weightx = 1.0;
+            gc.weighty = 1.0;
+            add(new JPanel(), gc);
+        }
+
+        public NotYetAuthorisedPanel() {
+            build();
+        }
+    }
+
+    /**
+     * The preferences panel displayed if there is currently an AccessToken available.
+     * 
+     */
+    private class AlreadyAuthorisedPanel extends JPanel {
+        private JTextField tfAccessTokenKey;
+        private JTextField tfAccessTokenSecret;
+
+        protected void build() {
+            setLayout(new GridBagLayout());
+            GridBagConstraints gc = new GridBagConstraints();
+            gc.anchor = GridBagConstraints.NORTHWEST;
+            gc.insets = new Insets(0,0,3,3);
+            gc.fill = GridBagConstraints.HORIZONTAL;
+            gc.weightx = 1.0;
+            gc.gridwidth = 2;
+            JLabel lbl;
+            add(lbl = new JMultilineLabel(tr("You already have an Access Token to access the OSM server using OAuth.")), gc);
+            lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
+
+            // -- access token key
+            gc.gridy = 1;
+            gc.gridx = 0;
+            gc.gridwidth = 1;
+            gc.weightx = 0.0;
+            add(new JLabel(tr("Access Token Key:")), gc);
+
+            gc.gridx = 1;
+            gc.weightx = 1.0;
+            add(tfAccessTokenKey = new JTextField(), gc);
+            tfAccessTokenKey.setEditable(false);
+
+            // -- access token secret
+            gc.gridy = 2;
+            gc.gridx = 0;
+            gc.gridwidth = 1;
+            gc.weightx = 0.0;
+            add(new JLabel(tr("Access Token Secret:")), gc);
+
+            gc.gridx = 1;
+            gc.weightx = 1.0;
+            add(tfAccessTokenSecret = new JTextField(), gc);
+            tfAccessTokenSecret.setEditable(false);
+
+            // -- access token secret
+            gc.gridy = 3;
+            gc.gridx = 0;
+            gc.gridwidth = 2;
+            gc.weightx = 1.0;
+            add(cbSaveToPreferences = new JCheckBox(tr("Save to preferences")), gc);
+            cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
+
+            // -- action buttons
+            JPanel btns = new JPanel(new FlowLayout(FlowLayout.LEFT));
+            btns.add(new SideButton(new RenewAuthorisationAction()));
+            btns.add(new SideButton(new TestAuthorisationAction()));
+            gc.gridy = 4;
+            gc.gridx = 0;
+            gc.gridwidth = 2;
+            gc.weightx = 1.0;
+            add(btns, gc);
+
+            // the panel with the advanced options
+            gc.gridy = 5;
+            gc.gridx = 0;
+            gc.gridwidth = 2;
+            gc.weightx = 1.0;
+            add(buildAdvancedPropertiesPanel(), gc);
+
+            // filler - grab the remaining space
+            gc.gridy = 6;
+            gc.fill = GridBagConstraints.BOTH;
+            gc.weightx = 1.0;
+            gc.weighty = 1.0;
+            add(new JPanel(), gc);
+
+        }
+
+        public void refreshView() {
+            String v = OAuthAccessTokenHolder.getInstance().getAccessTokenKey();
+            tfAccessTokenKey.setText(v == null? "" : v);
+            v = OAuthAccessTokenHolder.getInstance().getAccessTokenSecret();
+            tfAccessTokenSecret.setText(v == null? "" : v);
+            cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
+        }
+
+        public AlreadyAuthorisedPanel() {
+            build();
+            refreshView();
+        }
+    }
+
+    /**
+     * Action to authorise the current user
+     */
+    private class AuthoriseNowAction extends AbstractAction {
+        public AuthoriseNowAction() {
+            putValue(NAME, tr("Authorise now"));
+            putValue(SHORT_DESCRIPTION, tr("Click to step through the OAuth authorisation process"));
+            putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth"));
+
+        }
+        public void actionPerformed(ActionEvent arg0) {
+            OAuthAuthorisationWizard wizard = new OAuthAuthorisationWizard(
+                    OAuthAuthenticationPreferencesPanel.this,
+                    apiUrl
+            );
+            wizard.setVisible(true);
+            if (wizard.isCanceled()) return;
+            OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();
+            holder.setAccessToken(wizard.getAccessToken());
+            holder.setSaveToPreferences(wizard.isSaveAccessTokenToPreferences());
+            pnlAdvancedProperties.setAdvancedParameters(wizard.getOAuthParameters());
+            refreshView();
+        }
+    }
+
+    /**
+     * Launches the OAuthAuthorisationWizard to generate a new Access Token
+     */
+    private class RenewAuthorisationAction extends AbstractAction {
+        public RenewAuthorisationAction() {
+            putValue(NAME, tr("New Access Token"));
+            putValue(SHORT_DESCRIPTION, tr("Click to step through the OAuth authorisation process and generate a new Access Token"));
+            putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth"));
+
+        }
+        public void actionPerformed(ActionEvent arg0) {
+            OAuthAuthorisationWizard wizard = new OAuthAuthorisationWizard(
+                    OAuthAuthenticationPreferencesPanel.this,
+                    apiUrl
+            );
+            wizard.setVisible(true);
+            if (wizard.isCanceled()) return;
+            OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();
+            holder.setAccessToken(wizard.getAccessToken());
+            holder.setSaveToPreferences(wizard.isSaveAccessTokenToPreferences());
+            pnlAdvancedProperties.setAdvancedParameters(wizard.getOAuthParameters());
+            refreshView();
+        }
+    }
+
+    /**
+     * Runs a test whether we can access the OSM server with the current Access Token
+     */
+    private class TestAuthorisationAction extends AbstractAction {
+        public TestAuthorisationAction() {
+            putValue(NAME, tr("Test Access Token"));
+            putValue(SHORT_DESCRIPTION, tr("Click test access to the OSM server with the current access token"));
+            putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth"));
+
+        }
+
+        public void actionPerformed(ActionEvent evt) {
+            OAuthToken token = OAuthAccessTokenHolder.getInstance().getAccessToken();
+            OAuthParameters parameters = OAuthParameters.createFromPreferences(Main.pref);
+            TestAccessTokenTask task = new TestAccessTokenTask(
+                    OAuthAuthenticationPreferencesPanel.this,
+                    apiUrl,
+                    parameters,
+                    token
+            );
+            Main.worker.submit(task);
+        }
+    }
+
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (! evt.getPropertyName().equals(OsmApiUrlInputPanel.API_URL_PROP))
+            return;
+        apiUrl = (String)evt.getNewValue();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/OsmApiUrlInputPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/OsmApiUrlInputPanel.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/OsmApiUrlInputPanel.java	(revision 2745)
@@ -0,0 +1,279 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.AbstractAction;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.JTextComponent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
+import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class OsmApiUrlInputPanel extends JPanel {
+    static public final String API_URL_PROP = OsmApiUrlInputPanel.class.getName() + ".apiUrl";
+
+    private JLabel lblValid;
+    private JLabel lblApiUrl;
+    private JTextField tfOsmServerUrl;
+    private ApiUrlValidator valOsmServerUrl;
+    private SideButton btnTest;
+    /** indicates whether to use the default OSM URL or not */
+    private JCheckBox cbUseDefaultServerUrl;
+
+    protected JPanel buildDefultServerUrlPanel() {
+        JPanel pnl = new JPanel(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.weightx = 0.0;
+        gc.insets = new Insets(0,0,0,3);
+        gc.gridwidth  = 1;
+        pnl.add(cbUseDefaultServerUrl = new JCheckBox(), gc);
+        cbUseDefaultServerUrl.addItemListener(new UseDefaultServerUrlChangeHandler());
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        JLabel lbl = new JLabel("<html>Use the default OSM server URL (<strong>http://api.openstreetmap.org/api</strong>)</html>");
+        lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
+        pnl.add(lbl, gc);
+
+        return pnl;
+    }
+
+    protected void build() {
+        setLayout(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+
+        // the checkbox for the default UL
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.weightx = 1.0;
+        gc.insets = new Insets(0,0,0,0);
+        gc.gridwidth  = 4;
+        add(buildDefultServerUrlPanel(), gc);
+
+
+        // the input field for the URL
+        gc.gridx = 0;
+        gc.gridy = 1;
+        gc.gridwidth = 1;
+        gc.weightx = 0.0;
+        gc.insets = new Insets(0,0,0,3);
+        add(lblApiUrl = new JLabel(tr("OSM Server URL:")), gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        add(tfOsmServerUrl = new JTextField(), gc);
+        SelectAllOnFocusGainedDecorator.decorate(tfOsmServerUrl);
+        valOsmServerUrl = new ApiUrlValidator(tfOsmServerUrl);
+        valOsmServerUrl.validate();
+        ApiUrlPropagator propagator = new ApiUrlPropagator();
+        tfOsmServerUrl.addActionListener(propagator);
+        tfOsmServerUrl.addFocusListener(propagator);
+
+        gc.gridx = 2;
+        gc.weightx = 0.0;
+        add(lblValid = new JLabel(), gc);
+
+        gc.gridx = 3;
+        gc.weightx = 0.0;
+        ValidateApiUrlAction actTest = new ValidateApiUrlAction();
+        tfOsmServerUrl.getDocument().addDocumentListener(actTest);
+        add(btnTest = new SideButton(actTest), gc);
+    }
+
+    public OsmApiUrlInputPanel() {
+        build();
+        HelpUtil.setHelpContext(this, HelpUtil.ht("/Preferences/Connection#ApiUrl"));
+    }
+
+    /**
+     * Initializes the configuration panel with values from the preferences
+     */
+    public void initFromPreferences() {
+        String url =  Main.pref.get("osm-server.url", null);
+        if (url == null) {
+            cbUseDefaultServerUrl.setSelected(true);
+            firePropertyChange(API_URL_PROP, null, "http://api.openstreetmap.org/api");
+        } else if (url.trim().equals("http://api.openstreetmap.org/api")) {
+            cbUseDefaultServerUrl.setSelected(true);
+            firePropertyChange(API_URL_PROP, null, "http://api.openstreetmap.org/api");
+        } else {
+            cbUseDefaultServerUrl.setSelected(false);
+            tfOsmServerUrl.setText(url);
+            firePropertyChange(API_URL_PROP, null, url);
+        }
+    }
+
+    /**
+     * Saves the values to the preferences
+     */
+    public void saveToPreferences() {
+        if (cbUseDefaultServerUrl.isSelected()) {
+            Main.pref.put("osm-server.url", null);
+        } else if (tfOsmServerUrl.getText().trim().equals("http://api.openstreetmap.org/api")) {
+            Main.pref.put("osm-server.url", null);
+        } else {
+            Main.pref.put("osm-server.url", tfOsmServerUrl.getText().trim());
+        }
+
+    }
+
+    class ValidateApiUrlAction extends AbstractAction implements DocumentListener {
+        private String lastTestedUrl = null;
+
+        public ValidateApiUrlAction() {
+            putValue(NAME, tr("Validate"));
+            putValue(SHORT_DESCRIPTION, tr("Test the API URL"));
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent arg0) {
+            final String url = tfOsmServerUrl.getText().trim();
+            final ApiUrlTestTask task = new ApiUrlTestTask(OsmApiUrlInputPanel.this, url);
+            Main.worker.submit(task);
+            Runnable r = new Runnable() {
+                public void run() {
+                    if (task.isCanceled())
+                        return;
+                    Runnable r = new Runnable() {
+                        public void run() {
+                            if (task.isSuccess()) {
+                                lblValid.setIcon(ImageProvider.get("dialogs/changeset", "valid"));
+                                lblValid.setToolTipText(tr("The API URL is valid."));
+                                lastTestedUrl = url;
+                                updateEnabledState();
+                            } else {
+                                lblValid.setIcon(ImageProvider.get("warning-small"));
+                                lblValid.setToolTipText(tr("Validation failed. The API URL seems to be invalid."));
+                            }
+                        }
+                    };
+                    SwingUtilities.invokeLater(r);
+                }
+            };
+            Main.worker.submit(r);
+        }
+
+        protected void updateEnabledState() {
+            boolean enabled =
+                !tfOsmServerUrl.getText().trim().equals("")
+                && !tfOsmServerUrl.getText().trim().equals(lastTestedUrl);
+            if (enabled) {
+                lblValid.setIcon(null);
+            }
+            setEnabled(enabled);
+        }
+
+        public void changedUpdate(DocumentEvent arg0) {
+            updateEnabledState();
+        }
+
+        public void insertUpdate(DocumentEvent arg0) {
+            updateEnabledState();
+        }
+
+        public void removeUpdate(DocumentEvent arg0) {
+            updateEnabledState();
+        }
+    }
+
+    public void setApiUrlInputEnabled(boolean enabled) {
+        lblApiUrl.setEnabled(enabled);
+        tfOsmServerUrl.setEnabled(enabled);
+        lblValid.setEnabled(enabled);
+        btnTest.setEnabled(enabled);
+    }
+
+    static private class ApiUrlValidator extends AbstractTextComponentValidator {
+        public ApiUrlValidator(JTextComponent tc) throws IllegalArgumentException {
+            super(tc);
+        }
+
+        @Override
+        public boolean isValid() {
+            if (getComponent().getText().trim().equals(""))
+                return false;
+
+            try {
+                new URL(getComponent().getText().trim());
+                return true;
+            } catch(MalformedURLException e) {
+                return false;
+            }
+        }
+
+        @Override
+        public void validate() {
+            if (getComponent().getText().trim().equals("")) {
+                feedbackInvalid(tr("OSM API URL must not be empty. Please enter the OSM API URL."));
+                return;
+            }
+            if (!isValid()) {
+                feedbackInvalid(tr("The current value isn't a valid URL"));
+            } else {
+                feedbackValid(tr("Please enter the OSM API URL."));
+            }
+        }
+    }
+
+    /**
+     * Handles changes in the default URL
+     */
+    class UseDefaultServerUrlChangeHandler implements ItemListener {
+        public void itemStateChanged(ItemEvent e) {
+            switch(e.getStateChange()) {
+            case ItemEvent.SELECTED:
+                setApiUrlInputEnabled(false);
+                firePropertyChange(API_URL_PROP, null, "http://api.openstreetmap.org/api");
+                break;
+            case ItemEvent.DESELECTED:
+                setApiUrlInputEnabled(true);
+                valOsmServerUrl.validate();
+                tfOsmServerUrl.requestFocusInWindow();
+                firePropertyChange(API_URL_PROP, null, tfOsmServerUrl.getText());
+                break;
+            }
+        }
+    }
+
+    class ApiUrlPropagator extends FocusAdapter implements ActionListener {
+        public void propagate() {
+            firePropertyChange(API_URL_PROP, null, tfOsmServerUrl.getText());
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            propagate();
+        }
+
+        @Override
+        public void focusLost(FocusEvent arg0) {
+            propagate();
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/ProxyPreferencesPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/ProxyPreferencesPanel.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/ProxyPreferencesPanel.java	(revision 2745)
@@ -0,0 +1,382 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trc;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.net.PasswordAuthentication;
+import java.net.ProxySelector;
+import java.net.Authenticator.RequestorType;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.JMultilineLabel;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
+import org.openstreetmap.josm.io.DefaultProxySelector;
+import org.openstreetmap.josm.io.auth.CredentialsManager;
+import org.openstreetmap.josm.io.auth.CredentialsManagerException;
+import org.openstreetmap.josm.io.auth.CredentialsManagerFactory;
+import org.openstreetmap.josm.tools.GBC;
+
+public class ProxyPreferencesPanel extends VerticallyScrollablePanel {
+
+    public enum ProxyPolicy {
+        NO_PROXY("no-proxy"),
+        USE_SYSTEM_SETTINGS("use-system-settings"),
+        USE_HTTP_PROXY("use-http-proxy"),
+        USE_SOCKS_PROXY("use-socks-proxy");
+
+        private String policyName;
+        ProxyPolicy(String policyName) {
+            this.policyName = policyName;
+        }
+
+        public String getName() {
+            return policyName;
+        }
+
+        static public ProxyPolicy fromName(String policyName) {
+            if (policyName == null) return null;
+            policyName = policyName.trim().toLowerCase();
+            for(ProxyPolicy pp: values()) {
+                if (pp.getName().equals(policyName))
+                    return pp;
+            }
+            return null;
+        }
+    }
+
+    public static final String PROXY_POLICY = "proxy.policy";
+    public static final String PROXY_HTTP_HOST = "proxy.http.host";
+    public static final String PROXY_HTTP_PORT = "proxy.http.port";
+    public static final String PROXY_SOCKS_HOST = "proxy.socks.host";
+    public static final String PROXY_SOCKS_PORT = "proxy.socks.port";
+    public static final String PROXY_USER = "proxy.user";
+    public static final String PROXY_PASS = "proxy.pass";
+
+    private ButtonGroup bgProxyPolicy;
+    private Map<ProxyPolicy, JRadioButton> rbProxyPolicy;
+    private JTextField tfProxyHttpHost;
+    private JTextField tfProxyHttpPort;
+    private JTextField tfProxySocksHost;
+    private JTextField tfProxySocksPort;
+    private JTextField tfProxyHttpUser;
+    private JPasswordField tfProxyHttpPassword;
+
+    private JPanel pnlHttpProxyConfigurationPanel;
+    private JPanel pnlSocksProxyConfigurationPanel;
+
+    /**
+     * Builds the panel for the HTTP proxy configuration
+     * 
+     * @return
+     */
+    protected JPanel buildHttpProxyConfigurationPanel() {
+        JPanel pnl = new JPanel(new GridBagLayout()) {
+            @Override
+            public Dimension getMinimumSize() {
+                return getPreferredSize();
+            }
+        };
+        GridBagConstraints gc = new GridBagConstraints();
+
+        gc.anchor = GridBagConstraints.WEST;
+        gc.insets = new Insets(5,5,0,0);
+        pnl.add(new JLabel(tr("Host:")), gc);
+
+        gc.gridx = 1;
+        pnl.add(tfProxyHttpHost = new JTextField(20),gc);
+
+        gc.gridy = 1;
+        gc.gridx = 0;
+        pnl.add(new JLabel(trc("server", "Port:")), gc);
+
+        gc.gridx = 1;
+        gc.weightx = 0.0;
+        pnl.add(tfProxyHttpPort = new JTextField(5),gc);
+
+        gc.gridy = 2;
+        gc.gridx = 0;
+        gc.gridwidth = 2;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        pnl.add(new JLabel(tr("Please enter a username and a password if your proxy requires authentication.")), gc);
+
+        gc.gridy = 3;
+        gc.gridx = 0;
+        gc.gridwidth = 1;
+        gc.weightx = 0.0;
+        gc.fill = GridBagConstraints.NONE;
+        pnl.add(new JLabel(tr("User:")), gc);
+
+        gc.gridy = 3;
+        gc.gridx = 1;
+        pnl.add(tfProxyHttpUser = new JTextField(20),gc);
+
+        gc.gridy = 4;
+        gc.gridx = 0;
+        pnl.add(new JLabel(tr("Password:")), gc);
+
+        gc.gridx = 1;
+        pnl.add(tfProxyHttpPassword = new JPasswordField(20),gc);
+        return pnl;
+    }
+
+    /**
+     * Builds the panel for the SOCKS proxy configuration
+     * 
+     * @return
+     */
+    protected JPanel buildSocksProxyConfigurationPanel() {
+        JPanel pnl = new JPanel(new GridBagLayout()) {
+            @Override
+            public Dimension getMinimumSize() {
+                return getPreferredSize();
+            }
+        };
+        GridBagConstraints gc = new GridBagConstraints();
+        gc.anchor = GridBagConstraints.WEST;
+        gc.insets = new Insets(5,5,0,0);
+        pnl.add(new JLabel(tr("Host:")), gc);
+
+        gc.gridx = 1;
+        pnl.add(tfProxySocksHost = new JTextField(20),gc);
+
+        gc.gridy = 1;
+        gc.gridx = 0;
+        pnl.add(new JLabel(trc("server", "Port:")), gc);
+
+        gc.gridx = 1;
+        pnl.add(tfProxySocksPort = new JTextField(5),gc);
+
+        // add an extra spacer, otherwise the layout is broken
+        gc.gridy = 2;
+        gc.gridx = 0;
+        gc.gridwidth = 2;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        pnl.add(new JPanel(), gc);
+        return pnl;
+    }
+
+    protected JPanel buildProxySettingsPanel() {
+        JPanel pnl = new JPanel(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+
+        bgProxyPolicy = new ButtonGroup();
+        rbProxyPolicy = new HashMap<ProxyPolicy, JRadioButton>();
+        ProxyPolicyChangeListener policyChangeListener = new ProxyPolicyChangeListener();
+        for (ProxyPolicy pp: ProxyPolicy.values()) {
+            rbProxyPolicy.put(pp, new JRadioButton());
+            bgProxyPolicy.add(rbProxyPolicy.get(pp));
+            rbProxyPolicy.get(pp).addItemListener(policyChangeListener);
+        }
+
+        // radio button "No proxy"
+        gc.gridx = 0;
+        gc.gridy = 0;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.weightx = 0.0;
+        pnl.add(rbProxyPolicy.get(ProxyPolicy.NO_PROXY),gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        pnl.add(new JLabel(tr("No proxy")), gc);
+
+        // radio button "System settings"
+        gc.gridx = 0;
+        gc.gridy = 1;
+        gc.weightx = 0.0;
+        pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS),gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        String msg;
+        if (DefaultProxySelector.willJvmRetrieveSystemProxies()) {
+            msg = tr("Use standard system settings");
+        } else {
+            msg = tr("Use standard system settings (disabled. Start JOSM with <tt>-Djava.net.useSystemProxies=true</tt> to enable)");
+        }
+        pnl.add(new JMultilineLabel("<html>" + msg + "</html>"), gc);
+
+        // radio button http proxy
+        gc.gridx = 0;
+        gc.gridy = 2;
+        gc.weightx = 0.0;
+        pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY),gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        pnl.add(new JLabel(tr("Manually configure a HTTP proxy")),gc);
+
+        // the panel with the http proxy configuration parameters
+        gc.gridx = 1;
+        gc.gridy = 3;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.weightx = 1.0;
+        gc.weighty = 0.0;
+        pnl.add(pnlHttpProxyConfigurationPanel = buildHttpProxyConfigurationPanel(),gc);
+
+        // radio button SOCKS proxy
+        gc.gridx = 0;
+        gc.gridy = 4;
+        gc.weightx = 0.0;
+        pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY),gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        pnl.add(new JLabel(tr("Use a SOCKS proxy")),gc);
+
+        // the panel with the SOCKS configuration parameters
+        gc.gridx = 1;
+        gc.gridy = 5;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.anchor = GridBagConstraints.WEST;
+        gc.weightx = 1.0;
+        gc.weighty = 0.0;
+        pnl.add(pnlSocksProxyConfigurationPanel = buildSocksProxyConfigurationPanel(),gc);
+
+        return pnl;
+    }
+
+    /**
+     * Initializes the panel with the values from the preferences
+     */
+    public void initFromPreferences() {
+        String policy = Main.pref.get(PROXY_POLICY, null);
+        ProxyPolicy pp = ProxyPolicy.fromName(policy);
+        pp = pp == null? ProxyPolicy.NO_PROXY: pp;
+        rbProxyPolicy.get(pp).setSelected(true);
+        String value = Main.pref.get("proxy.host", null);
+        if (value != null) {
+            // legacy support
+            tfProxyHttpHost.setText(value);
+            Main.pref.put("proxy.host", null);
+        } else {
+            tfProxyHttpHost.setText(Main.pref.get(PROXY_HTTP_HOST, ""));
+        }
+        value = Main.pref.get("proxy.port", null);
+        if (value != null) {
+            // legacy support
+            tfProxyHttpPort.setText(value);
+            Main.pref.put("proxy.port", null);
+        } else {
+            tfProxyHttpPort.setText(Main.pref.get(PROXY_HTTP_PORT, ""));
+        }
+        tfProxySocksHost.setText(Main.pref.get(PROXY_SOCKS_HOST, ""));
+        tfProxySocksPort.setText(Main.pref.get(PROXY_SOCKS_PORT, ""));
+
+        if (pp.equals(ProxyPolicy.USE_SYSTEM_SETTINGS) && ! DefaultProxySelector.willJvmRetrieveSystemProxies()) {
+            System.err.println(tr("Warning: JOSM is configured to use proxies from the system setting, but the JVM is not configured to retrieve them. Resetting preferences to ''No proxy''"));
+            pp = ProxyPolicy.NO_PROXY;
+            rbProxyPolicy.get(pp).setSelected(true);
+        }
+
+        // save the proxy user and the proxy password to a credentials store managed by
+        // the credentials manager
+        CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
+        try {
+            PasswordAuthentication pa = cm.lookup(RequestorType.PROXY);
+            if (pa == null) {
+                tfProxyHttpUser.setText("");
+                tfProxyHttpPassword.setText("");
+            } else {
+                tfProxyHttpUser.setText(pa.getUserName() == null ? "" : pa.getUserName());
+                tfProxyHttpPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
+            }
+        } catch(CredentialsManagerException e) {
+            e.printStackTrace();
+            tfProxyHttpUser.setText("");
+            tfProxyHttpPassword.setText("");
+        }
+    }
+
+    protected void updateEnabledState() {
+        boolean isHttpProxy = rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected();
+        for (Component c: pnlHttpProxyConfigurationPanel.getComponents()) {
+            c.setEnabled(isHttpProxy);
+        }
+
+        boolean isSocksProxy = rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY).isSelected();
+        for (Component c: pnlSocksProxyConfigurationPanel.getComponents()) {
+            c.setEnabled(isSocksProxy);
+        }
+
+        rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS).setEnabled(DefaultProxySelector.willJvmRetrieveSystemProxies());
+    }
+
+    class ProxyPolicyChangeListener implements ItemListener {
+        public void itemStateChanged(ItemEvent arg0) {
+            updateEnabledState();
+        }
+    }
+
+    public ProxyPreferencesPanel() {
+        setLayout(new GridBagLayout());
+        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        add(buildProxySettingsPanel(), GBC.eop().anchor(GridBagConstraints.NORTHWEST).fill(GridBagConstraints.BOTH));
+
+        initFromPreferences();
+        updateEnabledState();
+
+        HelpUtil.setHelpContext(this, HelpUtil.ht("/Preferences/Connection#ProxySettings"));
+    }
+
+    /**
+     * Saves the current values to the preferences
+     */
+    public void saveToPreferences() {
+        ProxyPolicy policy = null;
+        for (ProxyPolicy pp: ProxyPolicy.values()) {
+            if (rbProxyPolicy.get(pp).isSelected()) {
+                policy = pp;
+                break;
+            }
+        }
+        if (policy == null) {
+            policy = ProxyPolicy.NO_PROXY;
+        }
+        Main.pref.put(PROXY_POLICY, policy.getName());
+        Main.pref.put(PROXY_HTTP_HOST, tfProxyHttpHost.getText());
+        Main.pref.put(PROXY_HTTP_PORT, tfProxyHttpPort.getText());
+        Main.pref.put(PROXY_SOCKS_HOST, tfProxySocksHost.getText());
+        Main.pref.put(PROXY_SOCKS_PORT, tfProxySocksPort.getText());
+
+        // update the proxy selector
+        ProxySelector selector = ProxySelector.getDefault();
+        if (selector instanceof DefaultProxySelector) {
+            ((DefaultProxySelector)selector).initFromPreferences();
+        }
+
+        CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
+        try {
+            PasswordAuthentication pa = new PasswordAuthentication(
+                    tfProxyHttpUser.getText().trim(),
+                    tfProxyHttpPassword.getPassword()
+            );
+            cm.store(RequestorType.PROXY, pa);
+        } catch(CredentialsManagerException e) {
+            e.printStackTrace();
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/server/UserNameValidator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/server/UserNameValidator.java	(revision 2745)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/server/UserNameValidator.java	(revision 2745)
@@ -0,0 +1,29 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.server;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.swing.text.JTextComponent;
+
+import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
+
+public class UserNameValidator extends AbstractTextComponentValidator {
+
+    public UserNameValidator(JTextComponent tc) {
+        super(tc);
+    }
+
+    @Override
+    public boolean isValid() {
+        return getComponent().getText().trim().length() > 0;
+    }
+
+    @Override
+    public void validate() {
+        if (isValid()) {
+            feedbackValid(tr("Please enter your OSM user name"));
+        } else {
+            feedbackInvalid(tr("The user name can't be empty. Please enter your OSM user name"));
+        }
+    }
+}
