Index: /trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/Main.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/Main.java	(revision 4968)
@@ -66,9 +66,9 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
-import org.openstreetmap.josm.gui.preferences.ImageryPreference;
-import org.openstreetmap.josm.gui.preferences.MapPaintPreference;
-import org.openstreetmap.josm.gui.preferences.ProjectionPreference;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
+import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
+import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference;
+import org.openstreetmap.josm.gui.preferences.map.ProjectionPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitorExecutor;
Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/RelationChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/RelationChecker.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/RelationChecker.java	(revision 4968)
@@ -18,5 +18,5 @@
 import org.openstreetmap.josm.data.validation.Test;
 import org.openstreetmap.josm.data.validation.TestError;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 4968)
@@ -53,6 +53,6 @@
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.data.validation.util.Entities;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.preferences.ValidatorPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
Index: /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 4968)
@@ -42,5 +42,5 @@
 import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.gui.help.Helpful;
-import org.openstreetmap.josm.gui.preferences.ProjectionPreference;
+import org.openstreetmap.josm.gui.preferences.map.ProjectionPreference;
 import org.openstreetmap.josm.tools.Predicate;
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java	(revision 4968)
@@ -22,5 +22,5 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Tag;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Check;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 4968)
@@ -89,5 +89,5 @@
 import org.openstreetmap.josm.gui.layer.markerlayer.AudioMarker;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
-import org.openstreetmap.josm.gui.preferences.GPXSettingsPanel;
+import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 4968)
@@ -4,5 +4,4 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Dimension;
 import java.io.IOException;
 import java.io.InputStream;
@@ -22,5 +21,5 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
 import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
-import org.openstreetmap.josm.gui.preferences.MapPaintPreference.MapPaintPrefHelper;
+import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference.MapPaintPrefHelper;
 import org.openstreetmap.josm.gui.preferences.SourceEntry;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
Index: unk/src/org/openstreetmap/josm/gui/preferences/AddWMSLayerPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/AddWMSLayerPanel.java	(revision 4967)
+++ 	(revision )
@@ -1,622 +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.Component;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.HeadlessException;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTextArea;
-import javax.swing.JTextField;
-import javax.swing.JTree;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.MutableTreeNode;
-import javax.swing.tree.TreePath;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.imagery.ImageryInfo;
-import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
-import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
-import org.openstreetmap.josm.data.projection.Projections;
-import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
-import org.openstreetmap.josm.gui.layer.TMSLayer;
-import org.openstreetmap.josm.io.UTFInputStreamReader;
-import org.openstreetmap.josm.tools.GBC;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-
-public class AddWMSLayerPanel extends JPanel {
-    private List<LayerDetails> selectedLayers;
-    private URL serviceUrl;
-    private LayerDetails selectedLayer;
-
-    private JTextField menuName;
-    private JTextArea resultingLayerField;
-    private MutableTreeNode treeRootNode;
-    private DefaultTreeModel treeData;
-    private JTree layerTree;
-    private JButton showBoundsButton;
-
-    private boolean previouslyShownUnsupportedCrsError = false;
-    private JTextArea tmsURL;
-    private JTextField tmsZoom;
-
-    public AddWMSLayerPanel() {
-        super(new GridBagLayout());
-        add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0));
-        menuName = new JTextField(40);
-        menuName.setText(tr("Unnamed Imagery Layer"));
-        add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-
-        final JTabbedPane tabbedPane = new JTabbedPane();
-
-        final JPanel wmsFetchPanel = new JPanel(new GridBagLayout());
-        tabbedPane.addTab(tr("WMS"), wmsFetchPanel);
-        add(tabbedPane, GBC.eop().insets(5,0,0,0).weight(1.0, 1.0).fill(GridBagConstraints.BOTH));
-
-        final JTextArea serviceUrlText = new JTextArea(3, 40);
-        serviceUrlText.setLineWrap(true);
-        serviceUrlText.setText("http://sample.com/wms?");
-        wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0));
-        JScrollPane scrollPane = new JScrollPane(serviceUrlText,
-                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
-                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        scrollPane.setMinimumSize(new Dimension(60, 60));
-        wmsFetchPanel.add(scrollPane, GBC.eol().weight(1.0, 0.0).insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-        JButton getLayersButton = new JButton(tr("Get Layers"));
-        getLayersButton.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                Cursor beforeCursor = getCursor();
-                try {
-                    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-                    attemptGetCapabilities(sanitize(serviceUrlText.getText()));
-                } finally {
-                    setCursor(beforeCursor);
-                }
-            }
-        });
-        wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST));
-
-        treeRootNode = new DefaultMutableTreeNode();
-        treeData = new DefaultTreeModel(treeRootNode);
-        layerTree = new JTree(treeData);
-        layerTree.setCellRenderer(new LayerTreeCellRenderer());
-        layerTree.addTreeSelectionListener(new TreeSelectionListener() {
-
-            @Override
-            public void valueChanged(TreeSelectionEvent e) {
-                TreePath[] selectionRows = layerTree.getSelectionPaths();
-                if(selectionRows == null) {
-                    showBoundsButton.setEnabled(false);
-                    selectedLayer = null;
-                    return;
-                }
-
-                selectedLayers = new LinkedList<LayerDetails>();
-                for (TreePath i : selectionRows) {
-                    Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
-                    if(userObject instanceof LayerDetails) {
-                        LayerDetails detail = (LayerDetails) userObject;
-                        if(!detail.isSupported()) {
-                            layerTree.removeSelectionPath(i);
-                            if(!previouslyShownUnsupportedCrsError) {
-                                JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM''s projections,\n" +
-                                        "so you can not use it. This message will not show again."),
-                                        tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-                                previouslyShownUnsupportedCrsError = true;
-                            }
-                        } else if(detail.ident != null) {
-                            selectedLayers.add(detail);
-                        }
-                    }
-                }
-
-                if (!selectedLayers.isEmpty()) {
-                    resultingLayerField.setText(buildGetMapUrl());
-
-                    if(selectedLayers.size() == 1) {
-                        showBoundsButton.setEnabled(true);
-                        selectedLayer = selectedLayers.get(0);
-                    }
-                } else {
-                    showBoundsButton.setEnabled(false);
-                    selectedLayer = null;
-                }
-            }
-        });
-        wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eol().weight(1.0, 1.0).insets(5,0,0,0).fill(GridBagConstraints.BOTH));
-
-        JPanel layerManipulationButtons = new JPanel();
-        showBoundsButton = new JButton(tr("Show Bounds"));
-        showBoundsButton.setEnabled(false);
-        showBoundsButton.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                if(selectedLayer.bounds != null) {
-                    SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
-                    mapPanel.setBoundingBox(selectedLayer.bounds);
-                    JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
-                } else {
-                    JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
-                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-                }
-            }
-        });
-        layerManipulationButtons.add(showBoundsButton);
-
-        wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0));
-
-        final JPanel tmsView = new JPanel(new GridBagLayout());
-        tmsView.add(new JLabel(tr("TMS URL")), GBC.std().insets(0,0,5,0));
-        tmsURL = new JTextArea(3, 40);
-        tmsURL.setLineWrap(true);
-        tmsURL.setText("http://sample.com/tms/{zoom}/{x}/{y}.jpg");
-        tmsURL.addKeyListener(new KeyAdapter() {
-            @Override
-            public void keyReleased(KeyEvent e) {
-                resultingLayerField.setText(buildTMSUrl());
-            }
-        });
-        JScrollPane tmsUrlScrollPane = new JScrollPane(tmsURL,
-                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
-                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        tmsUrlScrollPane.setMinimumSize(new Dimension(60, 60));
-        tmsView.add(tmsUrlScrollPane, GBC.eol().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-        tmsView.add(new JLabel(trc("layer", "Zoom")), GBC.std().insets(0,0,5,0));
-        tmsZoom = new JTextField(3);
-        tmsZoom.addKeyListener(new KeyAdapter() {
-            @Override
-            public void keyReleased(KeyEvent e) {
-                resultingLayerField.setText(buildTMSUrl());
-            }
-        });
-        tmsView.add(tmsZoom, GBC.eol().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-        tmsView.add(new JLabel(), GBC.eop().weight(1.0, 1.0).fill(GridBagConstraints.BOTH));
-        tabbedPane.addTab(tr("TMS"), tmsView);
-
-        add(new JLabel(tr("Imagery URL")), GBC.std().insets(0,0,5,0));
-        resultingLayerField = new JTextArea(3, 40);
-        resultingLayerField.setLineWrap(true);
-        JScrollPane bottomScrollPane = new JScrollPane(resultingLayerField,
-                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        bottomScrollPane.setMinimumSize(new Dimension(60, 60));
-        add(bottomScrollPane, GBC.eol().weight(1.0, 0.0).insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-
-        tabbedPane.addChangeListener(new ChangeListener() {
-            @Override
-            public void stateChanged(ChangeEvent e) {
-                Component sel = tabbedPane.getSelectedComponent();
-                if(tmsView == sel) {
-                    resultingLayerField.setText(buildTMSUrl());
-                } else if(wmsFetchPanel == sel) {
-                    if(serviceUrl != null) {
-                        resultingLayerField.setText(buildGetMapUrl());
-                    }
-                }
-            }
-        });
-    }
-
-    private String sanitize(String s) {
-        return s.replaceAll("[\r\n]+","").trim();
-    }
-
-    private String buildTMSUrl() {
-        StringBuilder a = new StringBuilder("tms");
-        String z = sanitize(tmsZoom.getText());
-        if(!z.isEmpty()) {
-            a.append("["+z+"]");
-        }
-        a.append(":");
-        a.append(sanitize(tmsURL.getText()));
-        return a.toString();
-    }
-
-    private String buildRootUrl() {
-        StringBuilder a = new StringBuilder(serviceUrl.getProtocol());
-        a.append("://");
-        a.append(serviceUrl.getHost());
-        if(serviceUrl.getPort() != -1) {
-            a.append(":");
-            a.append(serviceUrl.getPort());
-        }
-        a.append(serviceUrl.getPath());
-        a.append("?");
-        if(serviceUrl.getQuery() != null) {
-            a.append(serviceUrl.getQuery());
-            if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) {
-                a.append("&");
-            }
-        }
-        return a.toString();
-    }
-
-    private String buildGetMapUrl() {
-        StringBuilder a = new StringBuilder();
-        a.append(buildRootUrl());
-        a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=");
-        a.append(commaSepLayerList());
-        a.append("&STYLES=&SRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}");
-
-        return a.toString();
-    }
-
-    private String commaSepLayerList() {
-        StringBuilder b = new StringBuilder();
-
-        if (selectedLayers != null) {
-            Iterator<LayerDetails> iterator = selectedLayers.iterator();
-            while (iterator.hasNext()) {
-                LayerDetails layerDetails = iterator.next();
-                b.append(layerDetails.ident);
-                if(iterator.hasNext()) {
-                    b.append(",");
-                }
-            }
-        }
-
-        return b.toString();
-    }
-
-    private void showError(String incomingData, Exception e) {
-        JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
-                tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-        System.err.println("Could not parse WMS layer list. Incoming data:");
-        System.err.println(incomingData);
-        e.printStackTrace();
-    }
-
-    private void attemptGetCapabilities(String serviceUrlStr) {
-        URL getCapabilitiesUrl = null;
-        try {
-            if (!Pattern.compile(".*GetCapabilities.*", Pattern.CASE_INSENSITIVE).matcher(serviceUrlStr).matches()) {
-                // If the url doesn't already have GetCapabilities, add it in
-                getCapabilitiesUrl = new URL(serviceUrlStr);
-                final String getCapabilitiesQuery = "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities";
-                if (getCapabilitiesUrl.getQuery() == null) {
-                    getCapabilitiesUrl = new URL(serviceUrlStr + "?" + getCapabilitiesQuery);
-                } else if (!getCapabilitiesUrl.getQuery().isEmpty() && !getCapabilitiesUrl.getQuery().endsWith("&")) {
-                    getCapabilitiesUrl = new URL(serviceUrlStr + "&" + getCapabilitiesQuery);
-                } else {
-                    getCapabilitiesUrl = new URL(serviceUrlStr + getCapabilitiesQuery);
-                }
-            } else {
-                // Otherwise assume it's a good URL and let the subsequent error
-                // handling systems deal with problems
-                getCapabilitiesUrl = new URL(serviceUrlStr);
-            }
-            serviceUrl = new URL(serviceUrlStr);
-        } catch (HeadlessException e) {
-            return;
-        } catch (MalformedURLException e) {
-            JOptionPane.showMessageDialog(this, tr("Invalid service URL."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        }
-
-        String incomingData;
-        try {
-            System.out.println("GET "+getCapabilitiesUrl.toString());
-            URLConnection openConnection = getCapabilitiesUrl.openConnection();
-            InputStream inputStream = openConnection.getInputStream();
-            BufferedReader br = new BufferedReader(UTFInputStreamReader.create(inputStream, "UTF-8"));
-            String line;
-            StringBuilder ba = new StringBuilder();
-            while ((line = br.readLine()) != null) {
-                ba.append(line);
-                ba.append("\n");
-            }
-            incomingData = ba.toString();
-        } catch (IOException e) {
-            JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        }
-
-        Document document;
-        try {
-            //System.out.println("WMS capabilities:\n"+incomingData+"\n");
-            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
-            builderFactory.setValidating(false);
-            builderFactory.setNamespaceAware(true);
-            DocumentBuilder builder = builderFactory.newDocumentBuilder();
-            builder.setEntityResolver(new EntityResolver() {
-                @Override
-                public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
-                    System.out.println("Ignoring DTD " + publicId + ", " + systemId);
-                    return new InputSource(new StringReader(""));
-                }
-            });
-            document = builder.parse(new InputSource(new StringReader(incomingData)));
-        } catch (ParserConfigurationException e) {
-            showError(incomingData, e);
-            return;
-        } catch (SAXException e) {
-            showError(incomingData, e);
-            return;
-        } catch (IOException e) {
-            showError(incomingData, e);
-            return;
-        }
-
-        // Some WMS service URLs specify a different base URL for their GetMap service
-        Element child = getChild(document.getDocumentElement(), "Capability");
-        child = getChild(child, "Request");
-        child = getChild(child, "GetMap");
-        child = getChild(child, "DCPType");
-        child = getChild(child, "HTTP");
-        child = getChild(child, "Get");
-        child = getChild(child, "OnlineResource");
-        if (child != null) {
-            String baseURL = child.getAttribute("xlink:href");
-            if (baseURL != null && !baseURL.equals(serviceUrlStr)) {
-                try {
-                    System.out.println("GetCapabilities specifies a different service URL: " + baseURL);
-                    serviceUrl = new URL(baseURL);
-                } catch (MalformedURLException e1) {
-                }
-            }
-        }
-
-        try {
-            treeRootNode.setUserObject(getCapabilitiesUrl.getHost());
-            Element capabilityElem = getChild(document.getDocumentElement(), "Capability");
-            List<Element> children = getChildren(capabilityElem, "Layer");
-            List<LayerDetails> layers = parseLayers(children, new HashSet<String>());
-            updateTreeList(layers);
-        } catch(Exception e) {
-            showError(incomingData, e);
-            return;
-        }
-    }
-
-    private void updateTreeList(List<LayerDetails> layers) {
-        addLayersToTreeData(treeRootNode, layers);
-        layerTree.expandRow(0);
-    }
-
-    private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) {
-        for (LayerDetails layerDetails : layers) {
-            DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
-            addLayersToTreeData(treeNode, layerDetails.children);
-            treeData.insertNodeInto(treeNode, parent, 0);
-        }
-    }
-
-    private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) {
-        List<LayerDetails> details = new LinkedList<LayerDetails>();
-        for (Element element : children) {
-            details.add(parseLayer(element, parentCrs));
-        }
-        return details;
-    }
-
-    private LayerDetails parseLayer(Element element, Set<String> parentCrs) {
-        String name = getChildContent(element, "Title", null, null);
-        String ident = getChildContent(element, "Name", null, null);
-
-        // The set of supported CRS/SRS for this layer
-        Set<String> crsList = new HashSet<String>();
-        // ...including this layer's already-parsed parent projections
-        crsList.addAll(parentCrs);
-
-        // Parse the CRS/SRS pulled out of this layer's XML element
-        // I think CRS and SRS are the same at this point
-        List<Element> crsChildren = getChildren(element, "CRS");
-        crsChildren.addAll(getChildren(element, "SRS"));
-        for (Element child : crsChildren) {
-            String crs = (String) getContent(child);
-            if(crs != null) {
-                String upperCase = crs.trim().toUpperCase();
-                crsList.add(upperCase);
-            }
-        }
-
-        // Check to see if any of the specified projections are supported by JOSM
-        boolean josmSupportsThisLayer = false;
-        for (String crs : crsList) {
-            josmSupportsThisLayer |= isProjSupported(crs);
-        }
-
-        Bounds bounds = null;
-        Element bboxElem = getChild(element, "EX_GeographicBoundingBox");
-        if(bboxElem != null) {
-            // Attempt to use EX_GeographicBoundingBox for bounding box
-            double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null));
-            double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null));
-            double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null));
-            double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null));
-            bounds = new Bounds(bot, left, top, right);
-        } else {
-            // If that's not available, try LatLonBoundingBox
-            bboxElem = getChild(element, "LatLonBoundingBox");
-            if(bboxElem != null) {
-                double left = Double.parseDouble(bboxElem.getAttribute("minx"));
-                double top = Double.parseDouble(bboxElem.getAttribute("maxy"));
-                double right = Double.parseDouble(bboxElem.getAttribute("maxx"));
-                double bot = Double.parseDouble(bboxElem.getAttribute("miny"));
-                bounds = new Bounds(bot, left, top, right);
-            }
-        }
-
-        List<Element> layerChildren = getChildren(element, "Layer");
-        List<LayerDetails> childLayers = parseLayers(layerChildren, crsList);
-
-        return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers);
-    }
-
-    private boolean isProjSupported(String crs) {
-        for (Projection proj : Projections.getProjections()) {
-            if (proj instanceof ProjectionSubPrefs) {
-                if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null)
-                    return true;
-            } else {
-                if (proj.toCode().equals(crs))
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    public ImageryInfo getImageryInfo() {
-        ImageryInfo info = new ImageryInfo(menuName.getText(), resultingLayerField.getText());
-        if (ImageryType.TMS.equals(info.getImageryType())) {
-            TMSLayer.checkUrl(info.getUrl());
-        } else if (selectedLayers != null) {
-            HashSet<String> proj = new HashSet<String>();
-            for(LayerDetails l : selectedLayers) {
-                proj.addAll(l.getProjections());
-            }
-            info.setServerProjections(proj);
-        }
-        return info;
-    }
-
-    private static String getChildContent(Element parent, String name, String missing, String empty) {
-        Element child = getChild(parent, name);
-        if (child == null)
-            return missing;
-        else {
-            String content = (String) getContent(child);
-            return (content != null) ? content : empty;
-        }
-    }
-
-    private static Object getContent(Element element) {
-        NodeList nl = element.getChildNodes();
-        StringBuffer content = new StringBuffer();
-        for (int i = 0; i < nl.getLength(); i++) {
-            Node node = nl.item(i);
-            switch (node.getNodeType()) {
-            case Node.ELEMENT_NODE:
-                return node;
-            case Node.CDATA_SECTION_NODE:
-            case Node.TEXT_NODE:
-                content.append(node.getNodeValue());
-                break;
-            }
-        }
-        return content.toString().trim();
-    }
-
-    private static List<Element> getChildren(Element parent, String name) {
-        List<Element> retVal = new LinkedList<Element>();
-        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
-            if (child instanceof Element && name.equals(child.getNodeName())) {
-                retVal.add((Element) child);
-            }
-        }
-        return retVal;
-    }
-
-    private static Element getChild(Element parent, String name) {
-        if (parent == null)
-            return null;
-        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
-            if (child instanceof Element && name.equals(child.getNodeName()))
-                return (Element) child;
-        }
-        return null;
-    }
-
-    static class LayerDetails {
-
-        private String name;
-        private String ident;
-        private List<LayerDetails> children;
-        private Bounds bounds;
-        private Set<String> crsList;
-        private boolean supported;
-
-        public LayerDetails(String name, String ident, Set<String> crsList,
-                boolean supportedLayer, Bounds bounds,
-                List<LayerDetails> childLayers) {
-            this.name = name;
-            this.ident = ident;
-            this.supported = supportedLayer;
-            this.children = childLayers;
-            this.bounds = bounds;
-            this.crsList = crsList;
-        }
-
-        public boolean isSupported() {
-            return this.supported;
-        }
-
-        public Set<String> getProjections() {
-            return crsList;
-        }
-
-        @Override
-        public String toString() {
-            if(this.name == null || this.name.isEmpty())
-                return this.ident;
-            else
-                return this.name;
-        }
-
-    }
-
-    static class LayerTreeCellRenderer extends DefaultTreeCellRenderer {
-        @Override
-        public Component getTreeCellRendererComponent(JTree tree, Object value,
-                boolean sel, boolean expanded, boolean leaf, int row,
-                boolean hasFocus) {
-            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
-                    row, hasFocus);
-            DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
-            Object userObject = treeNode.getUserObject();
-            if (userObject instanceof LayerDetails) {
-                LayerDetails layer = (LayerDetails) userObject;
-                setEnabled(layer.isSupported());
-            }
-            return this;
-        }
-    }
-
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 4968)
@@ -10,4 +10,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.PreferencePanel;
 import org.openstreetmap.josm.tools.GBC;
 
@@ -24,5 +25,5 @@
  */
 
-public class AudioPreference implements PreferenceSetting {
+public class AudioPreference extends DefaultTabPreferenceSetting {
 
     public static class Factory implements PreferenceSettingFactory {
@@ -30,4 +31,8 @@
             return new AudioPreference();
         }
+    }
+    
+    private AudioPreference() {
+        super("audio", tr("Audio Settings"), tr("Settings for the audio player and audio markers."));
     }
 
@@ -49,67 +54,69 @@
 
     public void addGui(PreferenceTabbedPane gui) {
+        PreferencePanel audio = gui.createPreferenceTab(this);
+        
         // audioMenuVisible
         audioMenuVisible.setSelected(! Main.pref.getBoolean("audio.menuinvisible"));
         audioMenuVisible.setToolTipText(tr("Show or hide the audio menu entry on the main menu bar."));
-        gui.audio.add(audioMenuVisible, GBC.eol().insets(0,0,0,0));
+        audio.add(audioMenuVisible, GBC.eol().insets(0,0,0,0));
 
         // audioTraceVisible
         markerAudioTraceVisible.setSelected(Main.pref.getBoolean("marker.traceaudio", true));
         markerAudioTraceVisible.setToolTipText(tr("Display a moving icon representing the point on the synchronized track where the audio currently playing was recorded."));
-        gui.audio.add(markerAudioTraceVisible, GBC.eol().insets(0,0,0,0));
+        audio.add(markerAudioTraceVisible, GBC.eol().insets(0,0,0,0));
 
         // buttonLabels
         markerButtonLabels.setSelected(Main.pref.getBoolean("marker.buttonlabels", true));
         markerButtonLabels.setToolTipText(tr("Put text labels against audio (and image and web) markers as well as their button icons."));
-        gui.audio.add(markerButtonLabels, GBC.eol().insets(0,0,0,0));
+        audio.add(markerButtonLabels, GBC.eol().insets(0,0,0,0));
 
-        gui.audio.add(new JLabel(tr("When importing audio, make markers from...")), GBC.eol());
+        audio.add(new JLabel(tr("When importing audio, make markers from...")), GBC.eol());
 
         // audioMarkersFromExplicitWaypoints
         audioMarkersFromExplicitWaypoints.setSelected(Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true));
         audioMarkersFromExplicitWaypoints.setToolTipText(tr("When importing audio, apply it to any waypoints in the GPX layer."));
-        gui.audio.add(audioMarkersFromExplicitWaypoints, GBC.eol().insets(10,0,0,0));
+        audio.add(audioMarkersFromExplicitWaypoints, GBC.eol().insets(10,0,0,0));
 
         // audioMarkersFromUntimedWaypoints
         audioMarkersFromUntimedWaypoints.setSelected(Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true));
         audioMarkersFromUntimedWaypoints.setToolTipText(tr("When importing audio, apply it to any waypoints in the GPX layer."));
-        gui.audio.add(audioMarkersFromUntimedWaypoints, GBC.eol().insets(10,0,0,0));
+        audio.add(audioMarkersFromUntimedWaypoints, GBC.eol().insets(10,0,0,0));
 
         // audioMarkersFromNamedTrackpoints
         audioMarkersFromNamedTrackpoints.setSelected(Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false));
         audioMarkersFromNamedTrackpoints.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
-        gui.audio.add(audioMarkersFromNamedTrackpoints, GBC.eol().insets(10,0,0,0));
+        audio.add(audioMarkersFromNamedTrackpoints, GBC.eol().insets(10,0,0,0));
 
         // audioMarkersFromWavTimestamps
         audioMarkersFromWavTimestamps.setSelected(Main.pref.getBoolean("marker.audiofromwavtimestamps", false));
         audioMarkersFromWavTimestamps.setToolTipText(tr("Create audio markers at the position on the track corresponding to the modified time of each audio WAV file imported."));
-        gui.audio.add(audioMarkersFromWavTimestamps, GBC.eol().insets(10,0,0,0));
+        audio.add(audioMarkersFromWavTimestamps, GBC.eol().insets(10,0,0,0));
 
         // audioMarkersFromStart
         audioMarkersFromStart.setSelected(Main.pref.getBoolean("marker.audiofromstart"));
         audioMarkersFromStart.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
-        gui.audio.add(audioMarkersFromStart, GBC.eol().insets(10,0,0,0));
+        audio.add(audioMarkersFromStart, GBC.eol().insets(10,0,0,0));
 
         audioForwardBackAmount.setText(Main.pref.get("audio.forwardbackamount", "10.0"));
         audioForwardBackAmount.setToolTipText(tr("The number of seconds to jump forward or back when the relevant button is pressed"));
-        gui.audio.add(new JLabel(tr("Forward/back time (seconds)")), GBC.std());
-        gui.audio.add(audioForwardBackAmount, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        audio.add(new JLabel(tr("Forward/back time (seconds)")), GBC.std());
+        audio.add(audioForwardBackAmount, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
         audioFastForwardMultiplier.setText(Main.pref.get("audio.fastfwdmultiplier", "1.3"));
         audioFastForwardMultiplier.setToolTipText(tr("The amount by which the speed is multiplied for fast forwarding"));
-        gui.audio.add(new JLabel(tr("Fast forward multiplier")), GBC.std());
-        gui.audio.add(audioFastForwardMultiplier, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        audio.add(new JLabel(tr("Fast forward multiplier")), GBC.std());
+        audio.add(audioFastForwardMultiplier, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
         audioLeadIn.setText(Main.pref.get("audio.leadin", "1.0"));
         audioLeadIn.setToolTipText(tr("Playback starts this number of seconds before (or after, if negative) the audio track position requested"));
-        gui.audio.add(new JLabel(tr("Lead-in time (seconds)")), GBC.std());
-        gui.audio.add(audioLeadIn, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        audio.add(new JLabel(tr("Lead-in time (seconds)")), GBC.std());
+        audio.add(audioLeadIn, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
         audioCalibration.setText(Main.pref.get("audio.calibration", "1.0"));
         audioCalibration.setToolTipText(tr("The ratio of voice recorder elapsed time to true elapsed time"));
-        gui.audio.add(new JLabel(tr("Voice recorder calibration")), GBC.std());
-        gui.audio.add(audioCalibration, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        audio.add(new JLabel(tr("Voice recorder calibration")), GBC.std());
+        audio.add(audioCalibration, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
-        gui.audio.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+        audio.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
     }
 
Index: unk/src/org/openstreetmap/josm/gui/preferences/BackupPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/BackupPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,112 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
-import javax.swing.JTextField;
-
-import org.openstreetmap.josm.data.AutosaveTask;
-import org.openstreetmap.josm.data.preferences.BooleanProperty;
-import org.openstreetmap.josm.gui.widgets.HtmlPanel;
-import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
-import org.openstreetmap.josm.tools.GBC;
-
-public class BackupPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        @Override
-        public BackupPreference createPreferenceSetting() {
-            return new BackupPreference();
-        }
-    }
-    private static final BooleanProperty PROP_KEEP_BACKUP = new BooleanProperty("save.keepbackup", false);
-    private JCheckBox keepBackup;
-    private JCheckBox autosave;
-    private final JTextField autosaveInterval = new JTextField(8);
-    private final JTextField backupPerLayer = new JTextField(8);
-
-    @Override
-    public void addGui(PreferenceTabbedPane gui) {
-        JPanel panel = new VerticallyScrollablePanel();
-        panel.setLayout(new GridBagLayout());
-        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-
-        autosave = new JCheckBox(tr("Auto save enabled"));
-        autosave.setSelected(AutosaveTask.PROP_AUTOSAVE_ENABLED.get());
-        panel.add(autosave, GBC.eol());
-
-        final JLabel autosaveIntervalLabel = new JLabel(tr("Auto save interval (seconds)"));
-        panel.add(autosaveIntervalLabel, GBC.std().insets(60,0,0,0));
-        autosaveInterval.setText(Integer.toString(AutosaveTask.PROP_INTERVAL.get()));
-        autosaveInterval.setToolTipText(tr("Default value: {0}", AutosaveTask.PROP_INTERVAL.getDefaultValue()));
-        autosaveInterval.setMinimumSize(autosaveInterval.getPreferredSize());
-        panel.add(autosaveInterval, GBC.eol().insets(5,0,0,5));
-
-        final JLabel backupPerLayerLabel = new JLabel(tr("Auto saved files per layer"));
-        panel.add(backupPerLayerLabel, GBC.std().insets(60,0,0,0));
-        backupPerLayer.setText(Integer.toString(AutosaveTask.PROP_FILES_PER_LAYER.get()));
-        backupPerLayer.setToolTipText(tr("Default value: {0}", AutosaveTask.PROP_FILES_PER_LAYER.getDefaultValue()));
-        backupPerLayer.setMinimumSize(backupPerLayer.getPreferredSize());
-        panel.add(backupPerLayer, GBC.eol().insets(5,0,0,10));
-
-        panel.add(new HtmlPanel(
-            tr("<i>(Autosave stores the changed data layers in periodic intervals. " +
-                "The backups are saved in JOSM''s preference folder. " +
-                "In case of a crash, JOSM tries to recover the unsaved changes " +
-                "on next start.)</i>")),
-            GBC.eop().fill(GBC.HORIZONTAL).insets(5,0,0,10));
-
-        panel.add(new JSeparator(), GBC.eop().fill(GBC.HORIZONTAL));
-
-        keepBackup = new JCheckBox(tr("Keep backup files when saving data layers"));
-        keepBackup.setSelected(PROP_KEEP_BACKUP.get());
-        keepBackup.setToolTipText(tr("When saving, keep backup files ending with a ~"));
-        panel.add(keepBackup, GBC.eop());
-
-        panel.add(new HtmlPanel(
-            tr("<i>(JOSM can keep a backup file when saving data layers. "+
-                "It appends ''~'' to the file name and saves it in the same folder.)</i>")),
-            GBC.eop().fill(GBC.HORIZONTAL).insets(5,0,0,0));
-
-        ActionListener autosaveEnabled = new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                boolean enabled = autosave.isSelected();
-                autosaveIntervalLabel.setEnabled(enabled);
-                autosaveInterval.setEnabled(enabled);
-                backupPerLayerLabel.setEnabled(enabled);
-                backupPerLayer.setEnabled(enabled);
-            }
-        };
-        autosave.addActionListener(autosaveEnabled);
-        autosaveEnabled.actionPerformed(null);
-
-        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-        JScrollPane sp = new JScrollPane(panel);
-        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
-
-        gui.mapcontent.addTab(tr("File backup"), null, sp, tr("Configure whether to create backup files"));
-    }
-
-    @Override
-    public boolean ok() {
-        boolean restartRequired = false;
-        PROP_KEEP_BACKUP.put(keepBackup.isSelected());
-
-        restartRequired |= AutosaveTask.PROP_AUTOSAVE_ENABLED.put(autosave.isSelected());
-        restartRequired |= AutosaveTask.PROP_INTERVAL.parseAndPut(autosaveInterval.getText());
-        AutosaveTask.PROP_FILES_PER_LAYER.parseAndPut(backupPerLayer.getText());
-        return restartRequired;
-    }
-}
Index: unk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,276 +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 java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-import java.util.Vector;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JButton;
-import javax.swing.JColorChooser;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableCellRenderer;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
-import org.openstreetmap.josm.data.validation.Severity;
-import org.openstreetmap.josm.gui.MapScaler;
-import org.openstreetmap.josm.gui.conflict.ConflictColors;
-import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
-import org.openstreetmap.josm.gui.layer.GpxLayer;
-import org.openstreetmap.josm.gui.layer.ImageryLayer;
-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
-import org.openstreetmap.josm.tools.ColorHelper;
-import org.openstreetmap.josm.tools.GBC;
-
-public class ColorPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new ColorPreference();
-        }
-    }
-
-    private DefaultTableModel tableModel;
-    private JTable colors;
-    private ArrayList<String> del = new ArrayList<String>();
-
-    JButton colorEdit;
-    JButton defaultSet;
-    JButton remove;
-
-    /**
-     * Set the colors to be shown in the preference table. This method creates a table model if
-     * none exists and overwrites all existing values.
-     * @param colorMap the map holding the colors
-     * (key = color id (without prefixes, so only <code>background</code>; not <code>color.background</code>),
-     * value = html representation of the color.
-     */
-    public void setColorModel(Map<String, String> colorMap) {
-        if(tableModel == null) {
-            tableModel = new DefaultTableModel();
-            tableModel.addColumn(tr("Name"));
-            tableModel.addColumn(tr("Color"));
-        }
-
-        // clear old model:
-        while(tableModel.getRowCount() > 0) {
-            tableModel.removeRow(0);
-        }
-        // fill model with colors:
-        Map<String, String> colorKeyList = new TreeMap<String, String>();
-        Map<String, String> colorKeyList_mappaint = new TreeMap<String, String>();
-        Map<String, String> colorKeyList_layer = new TreeMap<String, String>();
-        for(String key : colorMap.keySet()) {
-            if(key.startsWith("layer ")) {
-                colorKeyList_layer.put(getName(key), key);
-            } else if(key.startsWith("mappaint.")) {
-                /* use getName(key)+key, as getName() may be ambiguous */
-                colorKeyList_mappaint.put(getName(key)+key, key);
-            } else {
-                colorKeyList.put(getName(key), key);
-            }
-        }
-        for (Entry<String, String> k : colorKeyList.entrySet()) {
-            Vector<Object> row = new Vector<Object>(2);
-            row.add(k.getValue());
-            row.add(ColorHelper.html2color(colorMap.get(k.getValue())));
-            tableModel.addRow(row);
-        }
-        for (Entry<String, String> k : colorKeyList_mappaint.entrySet()) {
-            Vector<Object> row = new Vector<Object>(2);
-            row.add(k.getValue());
-            row.add(ColorHelper.html2color(colorMap.get(k.getValue())));
-            tableModel.addRow(row);
-        }
-        for (Entry<String, String> k : colorKeyList_layer.entrySet()) {
-            Vector<Object> row = new Vector<Object>(2);
-            row.add(k.getValue());
-            row.add(ColorHelper.html2color(colorMap.get(k.getValue())));
-            tableModel.addRow(row);
-        }
-        if(this.colors != null) {
-            this.colors.repaint();
-        }
-    }
-
-    /**
-     * Returns a map with the colors in the table (key = color name without prefix, value = html color code).
-     * @return a map holding the colors.
-     */
-    public Map<String, String> getColorModel() {
-        String key;
-        String value;
-        Map<String, String> colorMap = new HashMap<String, String>();
-        for(int row = 0; row < tableModel.getRowCount(); ++row) {
-            key = (String)tableModel.getValueAt(row, 0);
-            value = ColorHelper.color2html((Color)tableModel.getValueAt(row, 1));
-            colorMap.put(key, value);
-        }
-        return colorMap;
-    }
-
-    private String getName(String o)
-    {
-        return Main.pref.getColorName(o);
-    }
-
-    public void addGui(final PreferenceTabbedPane gui) {
-        fixColorPrefixes();
-        setColorModel(Main.pref.getAllColors());
-
-        colorEdit = new JButton(tr("Choose"));
-        colorEdit.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                int sel = colors.getSelectedRow();
-                JColorChooser chooser = new JColorChooser((Color)colors.getValueAt(sel, 1));
-                int answer = JOptionPane.showConfirmDialog(
-                        gui, chooser,
-                        tr("Choose a color for {0}", getName((String)colors.getValueAt(sel, 0))),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.PLAIN_MESSAGE);
-                if (answer == JOptionPane.OK_OPTION) {
-                    colors.setValueAt(chooser.getColor(), sel, 1);
-                }
-            }
-        });
-        defaultSet = new JButton(tr("Set to default"));
-        defaultSet.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                int sel = colors.getSelectedRow();
-                String name = (String)colors.getValueAt(sel, 0);
-                Color c = Main.pref.getDefaultColor(name);
-                if (c != null) {
-                    colors.setValueAt(c, sel, 1);
-                }
-            }
-        });
-        JButton defaultAll = new JButton(tr("Set all to default"));
-        defaultAll.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                for(int i = 0; i < colors.getRowCount(); ++i)
-                {
-                    String name = (String)colors.getValueAt(i, 0);
-                    Color c = Main.pref.getDefaultColor(name);
-                    if (c != null) {
-                        colors.setValueAt(c, i, 1);
-                    }
-                }
-            }
-        });
-        remove = new JButton(tr("Remove"));
-        remove.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                int sel = colors.getSelectedRow();
-                del.add((String)colors.getValueAt(sel, 0));
-                tableModel.removeRow(sel);
-            }
-        });
-        remove.setEnabled(false);
-        colorEdit.setEnabled(false);
-        defaultSet.setEnabled(false);
-
-        colors = new JTable(tableModel) {
-            @Override public boolean isCellEditable(int row, int column) {
-                return false;
-            }
-            @Override public void valueChanged(ListSelectionEvent e) {
-                super.valueChanged(e);
-                int sel = getSelectedRow();
-                remove.setEnabled(sel >= 0 && isRemoveColor(sel));
-                colorEdit.setEnabled(sel >= 0);
-                defaultSet.setEnabled(sel >= 0);
-            }
-        };
-        colors.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        final TableCellRenderer oldColorsRenderer = colors.getDefaultRenderer(Object.class);
-        colors.setDefaultRenderer(Object.class, new TableCellRenderer(){
-            public Component getTableCellRendererComponent(JTable t, Object o, boolean selected, boolean focus, int row, int column) {
-                if (o == null)
-                    return new JLabel();
-                if (column == 1) {
-                    JLabel l = new JLabel(ColorHelper.color2html((Color)o));
-                    l.setBackground((Color)o);
-                    l.setOpaque(true);
-                    return l;
-                }
-                return oldColorsRenderer.getTableCellRendererComponent(t,getName(o.toString()),selected,focus,row,column);
-            }
-        });
-        colors.getColumnModel().getColumn(1).setWidth(100);
-        colors.setToolTipText(tr("Colors used by different objects in JOSM."));
-        colors.setPreferredScrollableViewportSize(new Dimension(100,112));
-
-        JPanel panel = new JPanel(new GridBagLayout());
-        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-        JScrollPane scrollpane = new JScrollPane(colors);
-        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        panel.add(scrollpane, GBC.eol().fill(GBC.BOTH));
-        JPanel buttonPanel = new JPanel(new GridBagLayout());
-        panel.add(buttonPanel, GBC.eol().insets(5,0,5,5).fill(GBC.HORIZONTAL));
-        buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
-        buttonPanel.add(colorEdit, GBC.std().insets(0,5,0,0));
-        buttonPanel.add(defaultSet, GBC.std().insets(5,5,5,0));
-        buttonPanel.add(defaultAll, GBC.std().insets(0,5,0,0));
-        buttonPanel.add(remove, GBC.std().insets(0,5,0,0));
-        gui.displaycontent.addTab(tr("Colors"), panel);
-    }
-
-    Boolean isRemoveColor(int row)
-    {
-        return ((String)colors.getValueAt(row, 0)).startsWith("layer ");
-    }
-
-    /**
-     * Add all missing color entries.
-     */
-    private void fixColorPrefixes() {
-        PaintColors.getColors();
-        ConflictColors.getColors();
-        Severity.getColors();
-        MarkerLayer.getGenericColor();
-        GpxLayer.getGenericColor();
-        OsmDataLayer.getOutsideColor();
-        ImageryLayer.getFadeColor();
-        MapScaler.getColor();
-        ConflictDialog.getColor();
-    }
-
-    public boolean ok() {
-        Boolean ret = false;
-        for(String d : del) {
-            Main.pref.put("color."+d, null);
-        }
-        for (int i = 0; i < colors.getRowCount(); ++i) {
-            String key = (String)colors.getValueAt(i, 0);
-            if(Main.pref.putColor(key, (Color)colors.getValueAt(i, 1)))
-            {
-                if(key.startsWith("mappaint.")) {
-                    ret = true;
-                }
-            }
-        }
-        org.openstreetmap.josm.gui.layer.OsmDataLayer.createHatchTexture();
-        return ret;
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/DefaultPreferenceSetting.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/DefaultPreferenceSetting.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/DefaultPreferenceSetting.java	(revision 4968)
@@ -0,0 +1,20 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences;
+
+public abstract class DefaultPreferenceSetting implements PreferenceSetting {
+
+    private final boolean isExpert;
+    
+    public DefaultPreferenceSetting() {
+        this(false);
+    }
+
+    public DefaultPreferenceSetting(boolean isExpert) {
+        this.isExpert = isExpert;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return isExpert;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java	(revision 4968)
@@ -0,0 +1,48 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences;
+
+public abstract class DefaultTabPreferenceSetting extends DefaultPreferenceSetting implements TabPreferenceSetting {
+
+    private final String iconName;
+    private final String description;
+    private final String title;
+    
+    public DefaultTabPreferenceSetting() {
+        this(null, null, null);
+    }
+
+    public DefaultTabPreferenceSetting(String iconName, String title, String description) {
+        this(iconName, title, description, false);
+    }
+
+    public DefaultTabPreferenceSetting(String iconName, String title, String description, boolean isExpert) {
+        super(isExpert);
+        this.iconName = iconName;
+        this.description = description;
+        this.title = title;
+    }
+
+    @Override
+    public String getIconName() {
+        return iconName;
+    }
+
+    @Override
+    public String getTooltip() {
+        if (getDescription() != null) {
+            return "<html>"+getDescription()+"</html>";
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String getTitle() {
+        return title;
+    }
+}
Index: unk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,160 +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 java.awt.Dimension;
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.ExpertToggleAction;
-import org.openstreetmap.josm.tools.GBC;
-
-public class DrawingPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new DrawingPreference();
-        }
-    }
-
-    private GPXSettingsPanel gpxPanel;
-    private JCheckBox directionHint = new JCheckBox(tr("Draw Direction Arrows"));
-    private JCheckBox headArrow = new JCheckBox(tr("Only on the head of a way."));
-    private JCheckBox onewayArrow = new JCheckBox(tr("Draw oneway arrows."));
-    private JCheckBox segmentOrderNumber = new JCheckBox(tr("Draw segment order numbers"));
-    private JCheckBox sourceBounds = new JCheckBox(tr("Draw boundaries of downloaded data"));
-    private JCheckBox virtualNodes = new JCheckBox(tr("Draw virtual nodes in select mode"));
-    private JCheckBox inactive = new JCheckBox(tr("Draw inactive layers in other color"));
-
-    // Options that affect performance
-    private JCheckBox useHighlighting = new JCheckBox(tr("Highlight target ways and nodes"));
-    private JCheckBox drawHelperLine = new JCheckBox(tr("Draw rubber-band helper line"));
-    private JCheckBox useAntialiasing = new JCheckBox(tr("Smooth map graphics (antialiasing)"));
-    private JCheckBox outlineOnly = new JCheckBox(tr("Draw only outlines of areas"));
-
-    public void addGui(PreferenceTabbedPane gui) {
-        gui.display.setPreferredSize(new Dimension(400,600));
-        gpxPanel = new GPXSettingsPanel();
-        gui.addValidationListener(gpxPanel);
-        JPanel panel = gpxPanel;
-
-        JScrollPane scrollpane = new JScrollPane(panel);
-        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        gui.displaycontent.addTab(tr("GPS Points"), scrollpane);
-        panel = new JPanel(new GridBagLayout());
-        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-
-        // directionHint
-        directionHint.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                if (directionHint.isSelected()){
-                    headArrow.setSelected(Main.pref.getBoolean("draw.segment.head_only", false));
-                }else{
-                    headArrow.setSelected(false);
-                }
-                headArrow.setEnabled(directionHint.isSelected());
-            }
-        });
-        directionHint.setToolTipText(tr("Draw direction hints for way segments."));
-        directionHint.setSelected(Main.pref.getBoolean("draw.segment.direction", false));
-        panel.add(directionHint, GBC.eop().insets(20,0,0,0));
-
-        // only on the head of a way
-        headArrow.setToolTipText(tr("Only on the head of a way."));
-        headArrow.setSelected(Main.pref.getBoolean("draw.segment.head_only", false));
-        headArrow.setEnabled(directionHint.isSelected());
-        panel.add(headArrow, GBC.eop().insets(40, 0, 0, 0));
-
-        // draw oneway arrows
-        onewayArrow.setToolTipText(tr("Draw arrows in the direction of oneways and other directed features."));
-        onewayArrow.setSelected(Main.pref.getBoolean("draw.oneway", true));
-        panel.add(onewayArrow, GBC.eop().insets(20,0,0,0));
-
-        // segment order number
-        segmentOrderNumber.setToolTipText(tr("Draw the order numbers of all segments within their way."));
-        segmentOrderNumber.setSelected(Main.pref.getBoolean("draw.segment.order_number", false));
-        panel.add(segmentOrderNumber, GBC.eop().insets(20,0,0,0));
-
-        // downloaded area
-        sourceBounds.setToolTipText(tr("Draw the boundaries of data loaded from the server."));
-        sourceBounds.setSelected(Main.pref.getBoolean("draw.data.downloaded_area", true));
-        panel.add(sourceBounds, GBC.eop().insets(20,0,0,0));
-
-        // virtual nodes
-        virtualNodes.setToolTipText(tr("Draw virtual nodes in select mode for easy way modification."));
-        virtualNodes.setSelected(Main.pref.getInteger("mappaint.node.virtual-size", 8) != 0);
-        panel.add(virtualNodes, GBC.eop().insets(20,0,0,0));
-
-        // background layers in inactive color
-        inactive.setToolTipText(tr("Draw the inactive data layers in a different color."));
-        inactive.setSelected(Main.pref.getBoolean("draw.data.inactive_color", true));
-        panel.add(inactive, GBC.eop().insets(20,0,0,0));
-
-        // antialiasing
-        useAntialiasing.setToolTipText(tr("Apply antialiasing to the map view resulting in a smoother appearance."));
-        useAntialiasing.setSelected(Main.pref.getBoolean("mappaint.use-antialiasing", true));
-
-        // highlighting
-        useHighlighting.setToolTipText(tr("Hightlight target nodes and ways while drawing or selecting"));
-        useHighlighting.setSelected(Main.pref.getBoolean("draw.target-highlight", true));
-
-        drawHelperLine.setToolTipText(tr("Draw rubber-band helper line"));
-        drawHelperLine.setSelected(Main.pref.getBoolean("draw.helper-line", true));
-        panel.add(drawHelperLine, GBC.eop().insets(20, 0, 0, 0));
-
-        // outlineOnly
-        outlineOnly.setSelected(Main.pref.getBoolean("draw.data.area_outline_only", false));
-        outlineOnly.setToolTipText(tr("This option suppresses the filling of areas, overriding anything specified in the selected style."));
-
-        JLabel performanceLabel = new JLabel(tr("Options that affect drawing performance"));
-        panel.add(performanceLabel, GBC.eop().insets(5,10,0,0));
-        panel.add(useAntialiasing, GBC.eop().insets(20,5,0,0));
-        panel.add(useHighlighting, GBC.eop().insets(20,0,0,0));
-        panel.add(outlineOnly, GBC.eol().insets(20,0,0,5));
-
-        ExpertToggleAction.addVisibilitySwitcher(performanceLabel);
-        ExpertToggleAction.addVisibilitySwitcher(useAntialiasing);
-        ExpertToggleAction.addVisibilitySwitcher(useHighlighting);
-        ExpertToggleAction.addVisibilitySwitcher(outlineOnly);
-
-        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-        scrollpane = new JScrollPane(panel);
-        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        gui.displaycontent.addTab(tr("OSM Data"), scrollpane);
-    }
-
-    public boolean ok() {
-        gpxPanel.savePreferences();
-        Main.pref.put("draw.data.area_outline_only", outlineOnly.isSelected());
-        Main.pref.put("draw.segment.direction", directionHint.isSelected());
-        Main.pref.put("draw.segment.head_only", headArrow.isSelected());
-        Main.pref.put("draw.oneway", onewayArrow.isSelected());
-        Main.pref.put("draw.segment.order_number", segmentOrderNumber.isSelected());
-        Main.pref.put("draw.data.downloaded_area", sourceBounds.isSelected());
-        Main.pref.put("draw.data.inactive_color", inactive.isSelected());
-        Main.pref.put("mappaint.use-antialiasing", useAntialiasing.isSelected());
-        Main.pref.put("draw.target-highlight", useHighlighting.isSelected());
-        Main.pref.put("draw.helper-line", drawHelperLine.isSelected());
-        int vn = Main.pref.getInteger("mappaint.node.virtual-size", 8);
-        if (virtualNodes.isSelected()) {
-            if (vn < 1) {
-                vn = 8;
-            }
-        }
-        else {
-            vn = 0;
-        }
-        Main.pref.putInteger("mappaint.node.virtual-size", vn);
-        return false;
-    }
-}
Index: unk/src/org/openstreetmap/josm/gui/preferences/GPXSettingsPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/GPXSettingsPanel.java	(revision 4967)
+++ 	(revision )
@@ -1,463 +1,0 @@
-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.Component;
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.ExpertToggleAction;
-import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
-import org.openstreetmap.josm.gui.layer.markerlayer.Marker.TemplateEntryProperty;
-import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.template_engine.ParseError;
-import org.openstreetmap.josm.tools.template_engine.TemplateParser;
-
-public class GPXSettingsPanel extends JPanel implements ValidationListener {
-
-    private static final int WAYPOINT_LABEL_CUSTOM = 6;
-    private static final String[] LABEL_PATTERN_TEMPLATE = new String[] {Marker.LABEL_PATTERN_AUTO, Marker.LABEL_PATTERN_NAME,
-        Marker.LABEL_PATTERN_DESC, "{special:everything}", "?{ '{name}' | '{desc}' | '{formattedWaypointOffset}' }", ""};
-    private static final String[] LABEL_PATTERN_DESC = new String[] {tr("Auto"), /* gpx data field name */ trc("gpx_field", "Name"),
-        /* gpx data field name */ trc("gpx_field", "Desc(ription)"), tr("Everything"), tr("Name or offset"), tr("None"), tr("Custom")};
-
-
-    private JRadioButton drawRawGpsLinesGlobal = new JRadioButton(tr("Use global settings"));
-    private JRadioButton drawRawGpsLinesAll = new JRadioButton(tr("All"));
-    private JRadioButton drawRawGpsLinesLocal = new JRadioButton(tr("Local files"));
-    private JRadioButton drawRawGpsLinesNone = new JRadioButton(tr("None"));
-    private ActionListener drawRawGpsLinesActionListener;
-    private JTextField drawRawGpsMaxLineLength = new JTextField(8);
-    private JTextField drawRawGpsMaxLineLengthLocal = new JTextField(8);
-    private JTextField drawLineWidth = new JTextField(2);
-    private JCheckBox forceRawGpsLines = new JCheckBox(tr("Force lines if no segments imported"));
-    private JCheckBox largeGpsPoints = new JCheckBox(tr("Draw large GPS points"));
-    private JCheckBox hdopCircleGpsPoints = new JCheckBox(tr("Draw a circle from HDOP value"));
-    private ButtonGroup colorGroup;
-    private JRadioButton colorTypeVelocity = new JRadioButton(tr("Velocity (red = slow, green = fast)"));
-    private JRadioButton colorTypeDirection = new JRadioButton(tr("Direction (red = west, yellow = north, green = east, blue = south)"));
-    private JRadioButton colorTypeDilution = new JRadioButton(tr("Dilution of Position (red = high, green = low, if available)"));
-    private JRadioButton colorTypeTime = new JRadioButton(tr("Track date"));
-    private JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized for named layers)"));
-    private JRadioButton colorTypeGlobal  = new JRadioButton(tr("Use global settings"));
-    private JComboBox colorTypeVelocityTune = new JComboBox(new String[] {tr("Car"), tr("Bicycle"), tr("Foot")});
-    private JCheckBox makeAutoMarkers = new JCheckBox(tr("Create markers when reading GPX"));
-    private JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows"));
-    private JCheckBox drawGpsArrowsFast = new JCheckBox(tr("Fast drawing (looks uglier)"));
-    private JTextField drawGpsArrowsMinDist = new JTextField(8);
-    private JCheckBox colorDynamic = new JCheckBox(tr("Dynamic color range based on data limits"));
-    private JComboBox waypointLabel = new JComboBox(LABEL_PATTERN_DESC);
-    private JTextField waypointLabelPattern = new JTextField();
-    private JComboBox audioWaypointLabel = new JComboBox(LABEL_PATTERN_DESC);
-    private JTextField audioWaypointLabelPattern = new JTextField();
-
-    private String layerName;
-    private boolean local; // flag to display LocalOnly checkbox
-    private boolean nonlocal; // flag to display AllLines checkbox
-
-    public GPXSettingsPanel(String layerName, boolean local, boolean nonlocal) {
-        super(new GridBagLayout());
-        this.local=local; this.nonlocal=nonlocal;
-        this.layerName = "layer "+layerName;
-        initComponents();
-        loadPreferences();
-    }
-
-    public GPXSettingsPanel() {
-        super(new GridBagLayout());
-        initComponents();
-        local=false; nonlocal=false;
-        loadPreferences(); // preferences -> controls
-    }
-
-    private void initComponents() {
-        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-
-        // makeAutoMarkers
-        makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
-        ExpertToggleAction.addVisibilitySwitcher(makeAutoMarkers);
-        add(makeAutoMarkers, GBC.eol().insets(20,0,0,5));
-
-        // drawRawGpsLines
-        ButtonGroup gpsLinesGroup = new ButtonGroup();
-        if (layerName!=null) {
-            gpsLinesGroup.add(drawRawGpsLinesGlobal);
-        }
-        gpsLinesGroup.add(drawRawGpsLinesNone);
-        gpsLinesGroup.add(drawRawGpsLinesLocal);
-        gpsLinesGroup.add(drawRawGpsLinesAll);
-
-        /* ensure that default is in data base */
-
-        JLabel label = new JLabel(tr("Draw lines between raw GPS points"));
-        add(label, GBC.eol().insets(20,0,0,0));
-        if (layerName!=null) {
-            add(drawRawGpsLinesGlobal, GBC.eol().insets(40,0,0,0));
-        }
-        add(drawRawGpsLinesNone, GBC.eol().insets(40,0,0,0));
-        if (layerName==null || local) {
-            add(drawRawGpsLinesLocal, GBC.eol().insets(40,0,0,0));
-        }
-        if (layerName==null || nonlocal) {
-            add(drawRawGpsLinesAll, GBC.eol().insets(40,0,0,0));
-        }
-        ExpertToggleAction.addVisibilitySwitcher(label);
-        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesGlobal);
-        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesNone);
-        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesLocal);
-        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesAll);
-
-        drawRawGpsLinesActionListener = new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                boolean f=drawRawGpsLinesNone.isSelected()||drawRawGpsLinesGlobal.isSelected();
-                forceRawGpsLines.setEnabled(!f);
-                drawRawGpsMaxLineLength.setEnabled(!(f || drawRawGpsLinesLocal.isSelected()));
-                drawRawGpsMaxLineLengthLocal.setEnabled(!f);
-                drawGpsArrows.setEnabled(!f);
-                drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-                drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-            }
-        };
-
-        drawRawGpsLinesGlobal.addActionListener(drawRawGpsLinesActionListener);
-        drawRawGpsLinesNone.addActionListener(drawRawGpsLinesActionListener);
-        drawRawGpsLinesLocal.addActionListener(drawRawGpsLinesActionListener);
-        drawRawGpsLinesAll.addActionListener(drawRawGpsLinesActionListener);
-
-        // drawRawGpsMaxLineLengthLocal
-        drawRawGpsMaxLineLengthLocal.setToolTipText(tr("Maximum length (in meters) to draw lines for local files. Set to ''-1'' to draw all lines."));
-        label = new JLabel(tr("Maximum length for local files (meters)"));
-        add(label, GBC.std().insets(40,0,0,0));
-        add(drawRawGpsMaxLineLengthLocal, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-        ExpertToggleAction.addVisibilitySwitcher(label);
-        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsMaxLineLengthLocal);
-
-        // drawRawGpsMaxLineLength
-        drawRawGpsMaxLineLength.setToolTipText(tr("Maximum length (in meters) to draw lines. Set to ''-1'' to draw all lines."));
-        label = new JLabel(tr("Maximum length (meters)"));
-        add(label, GBC.std().insets(40,0,0,0));
-        add(drawRawGpsMaxLineLength, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-        ExpertToggleAction.addVisibilitySwitcher(label);
-        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsMaxLineLength);
-
-        // forceRawGpsLines
-        forceRawGpsLines.setToolTipText(tr("Force drawing of lines if the imported data contain no line information."));
-        add(forceRawGpsLines, GBC.eop().insets(40,0,0,0));
-        ExpertToggleAction.addVisibilitySwitcher(forceRawGpsLines);
-
-        // drawGpsArrows
-        drawGpsArrows.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-                drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-            }
-        });
-        drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points."));
-        add(drawGpsArrows, GBC.eop().insets(40,0,0,0));
-
-        // drawGpsArrowsFast
-        drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math."));
-        add(drawGpsArrowsFast, GBC.eop().insets(60,0,0,0));
-        ExpertToggleAction.addVisibilitySwitcher(drawGpsArrowsFast);
-
-        // drawGpsArrowsMinDist
-        drawGpsArrowsMinDist.setToolTipText(tr("Do not draw arrows if they are not at least this distance away from the last one."));
-        add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(60,0,0,0));
-        add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-
-        // hdopCircleGpsPoints
-        hdopCircleGpsPoints.setToolTipText(tr("Draw a circle from HDOP value."));
-        add(hdopCircleGpsPoints, GBC.eop().insets(20,0,0,0));
-        ExpertToggleAction.addVisibilitySwitcher(hdopCircleGpsPoints);
-
-        // largeGpsPoints
-        largeGpsPoints.setToolTipText(tr("Draw larger dots for the GPS points."));
-        add(largeGpsPoints, GBC.eop().insets(20,0,0,0));
-
-        // drawLineWidth
-        drawLineWidth.setToolTipText(tr("Width of drawn GPX line (0 for default)"));
-        add(new JLabel(tr("Drawing width of GPX lines")), GBC.std().insets(20,0,0,0));
-        add(drawLineWidth, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-
-        // colorTracks
-        colorGroup = new ButtonGroup();
-        if (layerName!=null) {
-            colorGroup.add(colorTypeGlobal);
-        }
-        colorGroup.add(colorTypeNone);
-        colorGroup.add(colorTypeVelocity);
-        colorGroup.add(colorTypeDirection);
-        colorGroup.add(colorTypeDilution);
-        colorGroup.add(colorTypeTime);
-
-        colorTypeVelocity.addChangeListener(new ChangeListener(){
-            public void stateChanged(ChangeEvent e) {
-                colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected());
-                colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
-            }
-        });
-        colorTypeDilution.addChangeListener(new ChangeListener(){
-            public void stateChanged(ChangeEvent e) {
-                colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
-            }
-        });
-
-        colorTypeNone.setToolTipText(tr("All points and track segments will have the same color. Can be customized in Layer Manager."));
-        colorTypeVelocity.setToolTipText(tr("Colors points and track segments by velocity."));
-        colorTypeDirection.setToolTipText(tr("Colors points and track segments by direction."));
-        colorTypeDilution.setToolTipText(tr("Colors points and track segments by dilution of position (HDOP). Your capture device needs to log that information."));
-        colorTypeTime.setToolTipText(tr("Colors points and track segments by its timestamp."));
-
-        // color Tracks by Velocity Tune
-        colorTypeVelocityTune.setToolTipText(tr("Allows to tune the track coloring for different average speeds."));
-
-        add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
-
-        add(new JLabel(tr("Track and Point Coloring")), GBC.eol().insets(20,0,0,0));
-        if (layerName!=null) {
-            add(colorTypeGlobal, GBC.eol().insets(40,0,0,0));
-        }
-        add(colorTypeNone, GBC.eol().insets(40,0,0,0));
-        add(colorTypeVelocity, GBC.std().insets(40,0,0,0));
-        add(colorTypeVelocityTune, GBC.eop().insets(5,0,0,5));
-        add(colorTypeDirection, GBC.eol().insets(40,0,0,0));
-        add(colorTypeDilution, GBC.eol().insets(40,0,0,0));
-        add(colorTypeTime, GBC.eol().insets(40,0,0,0));
-        ExpertToggleAction.addVisibilitySwitcher(colorTypeDirection);
-        ExpertToggleAction.addVisibilitySwitcher(colorTypeDilution);
-
-        colorDynamic.setToolTipText(tr("Colors points and track segments by data limits."));
-        add(colorDynamic, GBC.eop().insets(40,0,0,0));
-        ExpertToggleAction.addVisibilitySwitcher(colorDynamic);
-
-        if (layerName == null) {
-            // Setting waypoints for gpx layer doesn't make sense - waypoints are shown in marker layer that has different name - so show
-            // this only for global config
-
-            // waypointLabel
-            label = new JLabel(tr("Waypoint labelling"));
-            add(label, GBC.std().insets(20,0,0,0));
-            add(waypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-            waypointLabel.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) {
-                    updateWaypointPattern(waypointLabel, waypointLabelPattern);
-                }
-            });
-            updateWaypointLabelCombobox(waypointLabel, waypointLabelPattern, TemplateEntryProperty.forMarker(layerName));
-            add(waypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
-            ExpertToggleAction.addVisibilitySwitcher(label);
-            ExpertToggleAction.addVisibilitySwitcher(waypointLabel);
-            ExpertToggleAction.addVisibilitySwitcher(waypointLabelPattern);
-
-            // audioWaypointLabel
-            Component glue = Box.createVerticalGlue();
-            add(glue, GBC.eol().insets(0, 20, 0, 0));
-            ExpertToggleAction.addVisibilitySwitcher(glue);
-
-            label = new JLabel(tr("Audio waypoint labelling"));
-            add(label, GBC.std().insets(20,0,0,0));
-            add(audioWaypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-            audioWaypointLabel.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) {
-                    updateWaypointPattern(audioWaypointLabel, audioWaypointLabelPattern);
-                }
-            });
-            updateWaypointLabelCombobox(audioWaypointLabel, audioWaypointLabelPattern, TemplateEntryProperty.forAudioMarker(layerName));
-            add(audioWaypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
-            ExpertToggleAction.addVisibilitySwitcher(label);
-            ExpertToggleAction.addVisibilitySwitcher(audioWaypointLabel);
-            ExpertToggleAction.addVisibilitySwitcher(audioWaypointLabelPattern);
-        }
-
-        add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-    }
-
-    /**
-     * Loads preferences to UI controls
-     */
-    public void loadPreferences () {
-        makeAutoMarkers.setSelected(Main.pref.getBoolean("marker.makeautomarkers", true));
-        if(layerName!=null && Main.pref.get("draw.rawgps.lines."+layerName).isEmpty()
-                && Main.pref.get("draw.rawgps.lines.local."+layerName).isEmpty()){
-            // no line preferences for layer is found
-            drawRawGpsLinesGlobal.setSelected(true);
-        } else {
-            Boolean lf = Main.pref.getBoolean("draw.rawgps.lines.local",layerName, true);
-            if(Main.pref.getBoolean("draw.rawgps.lines",layerName, true)) {
-                drawRawGpsLinesAll.setSelected(true);
-            } else if (lf) {
-                drawRawGpsLinesLocal.setSelected(true);
-            } else {
-                drawRawGpsLinesNone.setSelected(true);
-            }
-        }
-
-        drawRawGpsMaxLineLengthLocal.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length.local",layerName, -1)));
-        drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length",layerName, 200)));
-        drawLineWidth.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.linewidth",layerName, 0)));
-        forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force",layerName, false));
-        drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction",layerName, false));
-        drawGpsArrowsFast.setSelected(Main.pref.getBoolean("draw.rawgps.alternatedirection",layerName, false));
-        drawGpsArrowsMinDist.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.min-arrow-distance",layerName, 40)));
-        hdopCircleGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.hdopcircle",layerName, false));
-        largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large",layerName, false));
-        drawRawGpsLinesActionListener.actionPerformed(null);
-
-        if(layerName!=null && Main.pref.get("draw.rawgps.colors."+layerName).isEmpty()) {
-            colorTypeGlobal.setSelected(true);
-            colorDynamic.setSelected(false);
-            colorDynamic.setEnabled(false);
-        } else {
-            switch(Main.pref.getInteger("draw.rawgps.colors",layerName, 0)) {
-            case 0: colorTypeNone.setSelected(true);   break;
-            case 1: colorTypeVelocity.setSelected(true);  break;
-            case 2: colorTypeDilution.setSelected(true);  break;
-            case 3: colorTypeDirection.setSelected(true); break;
-            case 4: colorTypeTime.setSelected(true);  break;
-            }
-            int ccts = Main.pref.getInteger("draw.rawgps.colorTracksTune",layerName, 45);
-            colorTypeVelocityTune.setSelectedIndex(ccts==10 ? 2 : (ccts==20 ? 1 : 0));
-            colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected() && colorTypeVelocity.isEnabled());
-            colorDynamic.setSelected(Main.pref.getBoolean("draw.rawgps.colors.dynamic",layerName, false));
-            colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
-        }
-    }
-
-
-    /**
-     * Save preferences from UI controls for specified layer
-     * if layerName==null, global preferences are written
-     */
-    public boolean savePreferences (String layerName, boolean locLayer) {
-        String layerNameDot = ".layer "+layerName;
-        if (layerName==null) {
-            layerNameDot="";
-        }
-        Main.pref.put("marker.makeautomarkers"+layerNameDot, makeAutoMarkers.isSelected());
-        if (drawRawGpsLinesGlobal.isSelected()) {
-            Main.pref.put("draw.rawgps.lines" + layerNameDot, null);
-            Main.pref.put("draw.rawgps.max-line-length" + layerNameDot, null);
-            Main.pref.put("draw.rawgps.lines.local" + layerNameDot, null);
-            Main.pref.put("draw.rawgps.max-line-length.local" + layerNameDot, null);
-            Main.pref.put("draw.rawgps.lines.force"+layerNameDot, null);
-            Main.pref.put("draw.rawgps.direction"+layerNameDot, null);
-            Main.pref.put("draw.rawgps.alternatedirection"+layerNameDot, null);
-            Main.pref.put("draw.rawgps.min-arrow-distance"+layerNameDot, null);
-        } else {
-            if (layerName==null || !locLayer) {
-                Main.pref.put("draw.rawgps.lines" +  layerNameDot, drawRawGpsLinesAll.isSelected());
-                Main.pref.put("draw.rawgps.max-line-length" + layerNameDot, drawRawGpsMaxLineLength.getText());
-            }
-            if (layerName==null || locLayer) {
-                Main.pref.put("draw.rawgps.lines.local" + layerNameDot, drawRawGpsLinesAll.isSelected() || drawRawGpsLinesLocal.isSelected());
-                Main.pref.put("draw.rawgps.max-line-length.local" + layerNameDot, drawRawGpsMaxLineLengthLocal.getText());
-            }
-            Main.pref.put("draw.rawgps.lines.force"+layerNameDot, forceRawGpsLines.isSelected());
-            Main.pref.put("draw.rawgps.direction"+layerNameDot, drawGpsArrows.isSelected());
-            Main.pref.put("draw.rawgps.alternatedirection"+layerNameDot, drawGpsArrowsFast.isSelected());
-            Main.pref.put("draw.rawgps.min-arrow-distance"+layerNameDot, drawGpsArrowsMinDist.getText());
-        }
-
-        Main.pref.put("draw.rawgps.hdopcircle"+layerNameDot, hdopCircleGpsPoints.isSelected());
-        Main.pref.put("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected());
-        Main.pref.put("draw.rawgps.linewidth"+layerNameDot, drawLineWidth.getText());
-
-        TemplateEntryProperty.forMarker(layerName).put(waypointLabelPattern.getText());
-        TemplateEntryProperty.forAudioMarker(layerName).put(audioWaypointLabelPattern.getText());
-
-        if(colorTypeGlobal.isSelected()) {
-            Main.pref.put("draw.rawgps.colors"+layerNameDot, null);
-            Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, null);
-            Main.pref.put("draw.rawgps.colorTracksTunec"+layerNameDot, null);
-            return false;
-        } else if(colorTypeVelocity.isSelected()) {
-            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 1);
-        } else if(colorTypeDilution.isSelected()) {
-            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 2);
-        } else if(colorTypeDirection.isSelected()) {
-            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 3);
-        } else if(colorTypeTime.isSelected()) {
-            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 4);
-        } else {
-            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 0);
-        }
-        Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, colorDynamic.isSelected());
-        int ccti=colorTypeVelocityTune.getSelectedIndex();
-        Main.pref.putInteger("draw.rawgps.colorTracksTune"+layerNameDot, ccti==2 ? 10 : (ccti==1 ? 20 : 45));
-        return false;
-    }
-
-    /**
-     * Save preferences from UI controls for initial layer or globally
-     */
-    public void savePreferences() {
-        savePreferences(null, false);
-    }
-
-    private void updateWaypointLabelCombobox(JComboBox cb, JTextField tf, TemplateEntryProperty property) {
-        String labelPattern = property.getAsString();
-        boolean found = false;
-        for (int i=0; i<LABEL_PATTERN_TEMPLATE.length; i++) {
-            if (LABEL_PATTERN_TEMPLATE[i].equals(labelPattern)) {
-                cb.setSelectedIndex(i);
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            cb.setSelectedIndex(WAYPOINT_LABEL_CUSTOM);
-            tf.setEnabled(true);
-            tf.setText(labelPattern);
-        }
-    }
-
-    private void updateWaypointPattern(JComboBox cb, JTextField tf) {
-        if (cb.getSelectedIndex() == WAYPOINT_LABEL_CUSTOM) {
-            tf.setEnabled(true);
-        } else {
-            tf.setEnabled(false);
-            tf.setText(LABEL_PATTERN_TEMPLATE[cb.getSelectedIndex()]);
-        }
-    }
-
-    @Override
-    public boolean validatePreferences() {
-        TemplateParser parser = new TemplateParser(waypointLabelPattern.getText());
-        try {
-            parser.parse();
-        } catch (ParseError e) {
-            JOptionPane.showMessageDialog(Main.parent, tr("Incorrect waypoint label pattern: {0}", e.getMessage()), tr("Incorrect pattern"), JOptionPane.ERROR_MESSAGE);
-            waypointLabelPattern.requestFocus();
-            return false;
-        }
-        parser = new TemplateParser(audioWaypointLabelPattern.getText());
-        try {
-            parser.parse();
-        } catch (ParseError e) {
-            JOptionPane.showMessageDialog(Main.parent, tr("Incorrect audio waypoint label pattern: {0}", e.getMessage()), tr("Incorrect pattern"), JOptionPane.ERROR_MESSAGE);
-            audioWaypointLabelPattern.requestFocus();
-            return false;
-        }
-        return true;
-    }
-
-}
Index: unk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,1032 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dialog;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.HierarchyEvent;
-import java.awt.event.HierarchyListener;
-import java.awt.event.MouseEvent;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JColorChooser;
-import javax.swing.JComboBox;
-import javax.swing.JEditorPane;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
-import javax.swing.JSlider;
-import javax.swing.JSpinner;
-import javax.swing.JTabbedPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.JToolBar;
-import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.TableModelEvent;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableColumnModel;
-
-import org.openstreetmap.gui.jmapviewer.Coordinate;
-import org.openstreetmap.gui.jmapviewer.JMapViewer;
-import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
-import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
-import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
-import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.imagery.ImageryInfo;
-import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
-import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
-import org.openstreetmap.josm.data.imagery.OffsetBookmark;
-import org.openstreetmap.josm.data.imagery.Shape;
-import org.openstreetmap.josm.gui.layer.ImageryLayer;
-import org.openstreetmap.josm.gui.layer.TMSLayer;
-import org.openstreetmap.josm.gui.layer.WMSLayer;
-import org.openstreetmap.josm.io.imagery.HTMLGrabber;
-import org.openstreetmap.josm.io.imagery.OffsetServer;
-import org.openstreetmap.josm.io.imagery.OsmosnimkiOffsetServer;
-import org.openstreetmap.josm.tools.ColorHelper;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
-
-public class ImageryPreference implements PreferenceSetting {
-    public static class Factory implements PreferenceSettingFactory {
-        @Override
-        public PreferenceSetting createPreferenceSetting() {
-            return new ImageryPreference();
-        }
-    }
-    private ImageryProvidersPanel imageryProviders;
-    private ImageryLayerInfo layerInfo;
-
-    // Common settings
-    private Color colFadeColor;
-    private JButton btnFadeColor;
-    private JSlider fadeAmount = new JSlider(0, 100);
-    private JComboBox sharpen;
-    private JCheckBox useOffsetServer;
-    private JTextField offsetServerUrl;
-
-    // WMS Settings
-    private JComboBox browser;
-    private JCheckBox overlapCheckBox;
-    private JSpinner spinEast;
-    private JSpinner spinNorth;
-    private JSpinner spinSimConn;
-
-    //TMS settings controls
-    private JCheckBox autozoomActive = new JCheckBox();
-    private JCheckBox autoloadTiles = new JCheckBox();
-    private JSpinner minZoomLvl;
-    private JSpinner maxZoomLvl;
-    private JCheckBox addToSlippyMapChosser = new JCheckBox();
-    private JTextField tilecacheDir = new JTextField();
-
-    private JPanel buildCommonSettingsPanel(final PreferenceTabbedPane gui) {
-        final JPanel p = new JPanel(new GridBagLayout());
-
-        this.colFadeColor = ImageryLayer.getFadeColor();
-        this.btnFadeColor = new JButton();
-
-        this.btnFadeColor.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                JColorChooser chooser = new JColorChooser(colFadeColor);
-                int answer = JOptionPane.showConfirmDialog(
-                        gui, chooser,
-                        tr("Choose a color for {0}", tr("imagery fade")),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.PLAIN_MESSAGE);
-                if (answer == JOptionPane.OK_OPTION) {
-                    colFadeColor = chooser.getColor();
-                    btnFadeColor.setBackground(colFadeColor);
-                    btnFadeColor.setText(ColorHelper.color2html(colFadeColor));
-                }
-            }
-        });
-
-        p.add(new JLabel(tr("Fade Color: ")), GBC.std());
-        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
-        p.add(this.btnFadeColor, GBC.eol().fill(GBC.HORIZONTAL));
-
-        p.add(new JLabel(tr("Fade amount: ")), GBC.std());
-        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
-        p.add(this.fadeAmount, GBC.eol().fill(GBC.HORIZONTAL));
-
-        this.sharpen = new JComboBox(new String[] {
-                tr("None"),
-                tr("Soft"),
-                tr("Strong")});
-        p.add(new JLabel(tr("Sharpen (requires layer re-add): ")));
-        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
-        p.add(this.sharpen, GBC.eol().fill(GBC.HORIZONTAL));
-
-        this.useOffsetServer = new JCheckBox(tr("Use offset server: "));
-        this.offsetServerUrl = new JTextField();
-        this.useOffsetServer.addChangeListener(new ChangeListener() {
-            @Override
-            public void stateChanged(ChangeEvent e) {
-                offsetServerUrl.setEnabled(useOffsetServer.isSelected());
-            }
-        });
-        offsetServerUrl.setEnabled(useOffsetServer.isSelected());
-        p.add(this.useOffsetServer, GBC.eol().fill(GBC.HORIZONTAL));
-        p.add(this.offsetServerUrl, GBC.eol().fill(GBC.HORIZONTAL));
-        return p;
-    }
-
-    private JPanel buildWMSSettingsPanel() {
-        final JPanel p = new JPanel(new GridBagLayout());
-        browser = new JComboBox(new String[] {
-                "webkit-image {0}",
-                "gnome-web-photo --mode=photo --format=png {0} /dev/stdout",
-                "gnome-web-photo-fixed {0}",
-        "webkit-image-gtk {0}"});
-        browser.setEditable(true);
-        p.add(new JLabel(tr("Downloader:")), GBC.eol().fill(GBC.HORIZONTAL));
-        p.add(browser);
-
-        // Overlap
-        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GBC.HORIZONTAL));
-
-        overlapCheckBox = new JCheckBox(tr("Overlap tiles"));
-        JLabel labelEast = new JLabel(tr("% of east:"));
-        JLabel labelNorth = new JLabel(tr("% of north:"));
-        spinEast = new JSpinner(new SpinnerNumberModel(WMSLayer.PROP_OVERLAP_EAST.get(), 1, 50, 1));
-        spinNorth = new JSpinner(new SpinnerNumberModel(WMSLayer.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
-
-        JPanel overlapPanel = new JPanel(new FlowLayout());
-        overlapPanel.add(overlapCheckBox);
-        overlapPanel.add(labelEast);
-        overlapPanel.add(spinEast);
-        overlapPanel.add(labelNorth);
-        overlapPanel.add(spinNorth);
-
-        p.add(overlapPanel);
-
-        // Simultaneous connections
-        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GBC.HORIZONTAL));
-        JLabel labelSimConn = new JLabel(tr("Simultaneous connections"));
-        spinSimConn = new JSpinner(new SpinnerNumberModel(WMSLayer.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
-        JPanel overlapPanelSimConn = new JPanel(new FlowLayout(FlowLayout.LEFT));
-        overlapPanelSimConn.add(labelSimConn);
-        overlapPanelSimConn.add(spinSimConn);
-        p.add(overlapPanelSimConn, GBC.eol().fill(GBC.HORIZONTAL));
-
-        return p;
-    }
-
-    private JPanel buildTMSSettingsPanel() {
-        JPanel tmsTab = new JPanel(new GridBagLayout());
-
-        minZoomLvl = new JSpinner(new SpinnerNumberModel(TMSLayer.DEFAULT_MIN_ZOOM, TMSLayer.MIN_ZOOM, TMSLayer.MAX_ZOOM, 1));
-        maxZoomLvl = new JSpinner(new SpinnerNumberModel(TMSLayer.DEFAULT_MAX_ZOOM, TMSLayer.MIN_ZOOM, TMSLayer.MAX_ZOOM, 1));
-
-        tmsTab.add(new JLabel(tr("Auto zoom by default: ")), GBC.std());
-        tmsTab.add(GBC.glue(5, 0), GBC.std());
-        tmsTab.add(autozoomActive, GBC.eol().fill(GBC.HORIZONTAL));
-
-        tmsTab.add(new JLabel(tr("Autoload tiles by default: ")), GBC.std());
-        tmsTab.add(GBC.glue(5, 0), GBC.std());
-        tmsTab.add(autoloadTiles, GBC.eol().fill(GBC.HORIZONTAL));
-
-        tmsTab.add(new JLabel(tr("Min. zoom level: ")), GBC.std());
-        tmsTab.add(GBC.glue(5, 0), GBC.std());
-        tmsTab.add(this.minZoomLvl, GBC.eol());
-
-        tmsTab.add(new JLabel(tr("Max. zoom level: ")), GBC.std());
-        tmsTab.add(GBC.glue(5, 0), GBC.std());
-        tmsTab.add(this.maxZoomLvl, GBC.eol());
-
-        tmsTab.add(new JLabel(tr("Add to slippymap chooser: ")), GBC.std());
-        tmsTab.add(GBC.glue(5, 0), GBC.std());
-        tmsTab.add(addToSlippyMapChosser, GBC.eol().fill(GBC.HORIZONTAL));
-
-        tmsTab.add(new JLabel(tr("Tile cache directory: ")), GBC.std());
-        tmsTab.add(GBC.glue(5, 0), GBC.std());
-        tmsTab.add(tilecacheDir, GBC.eol().fill(GBC.HORIZONTAL));
-
-        return tmsTab;
-    }
-
-    private void addSettingsSection(final JPanel p, String name, JPanel section) {
-        addSettingsSection(p, name, section, GBC.eol());
-    }
-    private void addSettingsSection(final JPanel p, String name, JPanel section, GBC gbc) {
-        final JLabel lbl = new JLabel(name);
-        lbl.setFont(lbl.getFont().deriveFont(Font.BOLD));
-        p.add(lbl,GBC.std());
-        p.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
-        p.add(section, gbc.insets(20,5,0,10));
-    }
-
-    private Component buildSettingsPanel(final PreferenceTabbedPane gui) {
-        final JPanel p = new JPanel(new GridBagLayout());
-        p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-
-        addSettingsSection(p, tr("Common Settings"), buildCommonSettingsPanel(gui));
-        addSettingsSection(p, tr("WMS Settings"), buildWMSSettingsPanel());
-        addSettingsSection(p, tr("TMS Settings"), buildTMSSettingsPanel(),
-                GBC.eol().fill(GBC.HORIZONTAL));
-
-        p.add(new JPanel(),GBC.eol().fill(GBC.BOTH));
-        return new JScrollPane(p);
-    }
-
-    @Override
-    public void addGui(final PreferenceTabbedPane gui) {
-        JPanel p = gui.createPreferenceTab("imagery", tr("Imagery Preferences"), tr("Modify list of imagery layers displayed in the Imagery menu"));
-        JTabbedPane pane = new JTabbedPane();
-        layerInfo = new ImageryLayerInfo(ImageryLayerInfo.instance);
-        imageryProviders = new ImageryProvidersPanel(gui, layerInfo);
-        pane.add(imageryProviders);
-        pane.add(buildSettingsPanel(gui));
-        pane.add(new OffsetBookmarksPanel(gui));
-        loadSettings();
-        pane.setTitleAt(0, tr("Imagery providers"));
-        pane.setTitleAt(1, tr("Settings"));
-        pane.setTitleAt(2, tr("Offset bookmarks"));
-        p.add(pane,GBC.std().fill(GBC.BOTH));
-    }
-
-    public ImageryProvidersPanel getProvidersPanel() {
-        return imageryProviders;
-    }
-
-    private void loadSettings() {
-        // Common settings
-        this.btnFadeColor.setBackground(colFadeColor);
-        this.btnFadeColor.setText(ColorHelper.color2html(colFadeColor));
-        this.fadeAmount.setValue(ImageryLayer.PROP_FADE_AMOUNT.get());
-        this.sharpen.setSelectedIndex(Math.max(0, Math.min(2, ImageryLayer.PROP_SHARPEN_LEVEL.get())));
-        this.useOffsetServer.setSelected(OffsetServer.PROP_SERVER_ENABLED.get());
-        this.offsetServerUrl.setText(OsmosnimkiOffsetServer.PROP_SERVER_URL.get());
-
-        // WMS Settings
-        this.browser.setSelectedItem(HTMLGrabber.PROP_BROWSER.get());
-        this.overlapCheckBox.setSelected(WMSLayer.PROP_OVERLAP.get());
-        this.spinEast.setValue(WMSLayer.PROP_OVERLAP_EAST.get());
-        this.spinNorth.setValue(WMSLayer.PROP_OVERLAP_NORTH.get());
-        this.spinSimConn.setValue(WMSLayer.PROP_SIMULTANEOUS_CONNECTIONS.get());
-
-        // TMS Settings
-        this.autozoomActive.setSelected(TMSLayer.PROP_DEFAULT_AUTOZOOM.get());
-        this.autoloadTiles.setSelected(TMSLayer.PROP_DEFAULT_AUTOLOAD.get());
-        this.addToSlippyMapChosser.setSelected(TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get());
-        this.maxZoomLvl.setValue(TMSLayer.getMaxZoomLvl(null));
-        this.minZoomLvl.setValue(TMSLayer.getMinZoomLvl(null));
-        this.tilecacheDir.setText(TMSLayer.PROP_TILECACHE_DIR.get());
-    }
-
-    @Override
-    public boolean ok() {
-        boolean restartRequired = false;
-        layerInfo.save();
-        ImageryLayerInfo.instance.clear();
-        ImageryLayerInfo.instance.load();
-        Main.main.menu.imageryMenu.refreshImageryMenu();
-        Main.main.menu.imageryMenu.refreshOffsetMenu();
-        OffsetBookmark.saveBookmarks();
-
-        WMSLayer.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
-        WMSLayer.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
-        WMSLayer.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
-        WMSLayer.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
-
-        HTMLGrabber.PROP_BROWSER.put(browser.getEditor().getItem().toString());
-        OffsetServer.PROP_SERVER_ENABLED.put(useOffsetServer.isSelected());
-        OsmosnimkiOffsetServer.PROP_SERVER_URL.put(offsetServerUrl.getText());
-
-        if (TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get() != this.addToSlippyMapChosser.isSelected()) {
-            restartRequired = true;
-        }
-        TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.put(this.addToSlippyMapChosser.isSelected());
-        TMSLayer.PROP_DEFAULT_AUTOZOOM.put(this.autozoomActive.isSelected());
-        TMSLayer.PROP_DEFAULT_AUTOLOAD.put(this.autoloadTiles.isSelected());
-        TMSLayer.setMaxZoomLvl((Integer)this.maxZoomLvl.getValue());
-        TMSLayer.setMinZoomLvl((Integer)this.minZoomLvl.getValue());
-        TMSLayer.PROP_TILECACHE_DIR.put(this.tilecacheDir.getText());
-
-        ImageryLayer.PROP_FADE_AMOUNT.put(this.fadeAmount.getValue());
-        ImageryLayer.setFadeColor(this.colFadeColor);
-        ImageryLayer.PROP_SHARPEN_LEVEL.put(sharpen.getSelectedIndex());
-
-        return restartRequired;
-    }
-
-
-    /**
-     * Updates a server URL in the preferences dialog. Used by plugins.
-     *
-     * @param server
-     *            The server name
-     * @param url
-     *            The server URL
-     */
-    public void setServerUrl(String server, String url) {
-        for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) {
-            if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString())) {
-                imageryProviders.activeModel.setValueAt(url, i, 1);
-                return;
-            }
-        }
-        imageryProviders.activeModel.addRow(new String[] { server, url });
-    }
-
-    /**
-     * Gets a server URL in the preferences dialog. Used by plugins.
-     *
-     * @param server
-     *            The server name
-     * @return The server URL
-     */
-    public String getServerUrl(String server) {
-        for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) {
-            if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString()))
-                return imageryProviders.activeModel.getValueAt(i, 1).toString();
-        }
-        return null;
-    }
-
-    public static class ImageryProvidersPanel extends JPanel {
-        // Public JTables and JMapViewer
-        public final JTable activeTable;
-        public final JTable defaultTable;
-        public final JMapViewer defaultMap;
-
-        // Public models
-        public final ImageryLayerTableModel activeModel;
-        public final ImageryDefaultLayerTableModel defaultModel;
-
-        // Public JToolbars
-        public final JToolBar activeToolbar;
-        public final JToolBar middleToolbar;
-        public final JToolBar defaultToolbar;
-
-        // Private members
-        private final PreferenceTabbedPane gui;
-        private final ImageryLayerInfo layerInfo;
-
-        private static class ImageryTableCellRenderer extends DefaultTableCellRenderer {
-
-            private List<ImageryInfo> layers;
-
-            public ImageryTableCellRenderer(List<ImageryInfo> layers) {
-                this.layers = layers;
-            }
-
-            @Override
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean
-                    isSelected, boolean hasFocus, int row, int column) {
-                JLabel label = (JLabel) super.getTableCellRendererComponent(
-                        table, value, isSelected, hasFocus, row, column);
-                String t = value.toString();
-                label.setBackground(Main.pref.getUIColor("Table.background"));
-                if (isSelected) {
-                    label.setForeground(Main.pref.getUIColor("Table.foreground"));
-                }
-                for(ImageryInfo l : layers)
-                {
-                    if(l.getExtendedUrl().equals(t)) {
-                        label.setBackground(Main.pref.getColor(
-                                marktr("Imagery Background: Default"),
-                                new Color(200,255,200)));
-                        break;
-                    }
-                }
-                return label;
-            }
-        }
-
-        public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) {
-            super(new GridBagLayout());
-            this.gui = gui;
-            this.layerInfo = layerInfoArg;
-            this.activeModel = new ImageryLayerTableModel();
-
-            activeTable = new JTable(activeModel) {
-                @Override
-                public String getToolTipText(MouseEvent e) {
-                    java.awt.Point p = e.getPoint();
-                    return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
-                }
-            };
-
-            defaultModel = new ImageryDefaultLayerTableModel();
-            defaultTable = new JTable(defaultModel) {
-                @Override
-                public String getToolTipText(MouseEvent e) {
-                    java.awt.Point p = e.getPoint();
-                    return (String) defaultModel.getValueAt(rowAtPoint(p), columnAtPoint(p));
-                }
-            };
-
-            defaultModel.addTableModelListener(
-                    new TableModelListener() {
-                        @Override
-                        public void tableChanged(TableModelEvent e) {
-                            activeTable.repaint();
-                        }
-                    }
-                    );
-
-            activeModel.addTableModelListener(
-                    new TableModelListener() {
-                        @Override
-                        public void tableChanged(TableModelEvent e) {
-                            defaultTable.repaint();
-                        }
-                    }
-                    );
-
-            TableColumnModel mod = defaultTable.getColumnModel();
-            mod.getColumn(2).setPreferredWidth(800);
-            mod.getColumn(2).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getLayers()));
-            mod.getColumn(1).setPreferredWidth(400);
-            mod.getColumn(0).setPreferredWidth(50);
-
-            mod = activeTable.getColumnModel();
-            mod.getColumn(1).setPreferredWidth(800);
-            mod.getColumn(1).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getDefaultLayers()));
-            mod.getColumn(0).setPreferredWidth(200);
-
-            RemoveEntryAction remove = new RemoveEntryAction();
-            activeTable.getSelectionModel().addListSelectionListener(remove);
-
-            add(new JLabel(tr("Available default entries:")), GBC.eol().insets(5, 5, 0, 0));
-            // Add default item list
-            JScrollPane scrolldef = new JScrollPane(defaultTable);
-            scrolldef.setPreferredSize(new Dimension(200, 200));
-            add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
-
-            // Add default item map
-            defaultMap = new JMapViewer();
-            defaultMap.setZoomContolsVisible(false);
-            defaultMap.setMinimumSize(new Dimension(100, 200));
-            add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
-
-            defaultTable.getSelectionModel().addListSelectionListener(new DefListSelectionListener());
-
-            defaultToolbar = new JToolBar(JToolBar.VERTICAL);
-            defaultToolbar.setFloatable(false);
-            defaultToolbar.setBorderPainted(false);
-            defaultToolbar.setOpaque(false);
-            defaultToolbar.add(new ReloadAction());
-            add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
-
-            ActivateAction activate = new ActivateAction();
-            defaultTable.getSelectionModel().addListSelectionListener(activate);
-            JButton btnActivate = new JButton(activate);
-
-            middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
-            middleToolbar.setFloatable(false);
-            middleToolbar.setBorderPainted(false);
-            middleToolbar.setOpaque(false);
-            middleToolbar.add(btnActivate);
-            add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 15, 5, 0));
-
-            add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-
-            add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0));
-            JScrollPane scroll = new JScrollPane(activeTable);
-            add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5));
-            scroll.setPreferredSize(new Dimension(200, 200));
-
-            activeToolbar = new JToolBar(JToolBar.VERTICAL);
-            activeToolbar.setFloatable(false);
-            activeToolbar.setBorderPainted(false);
-            activeToolbar.setOpaque(false);
-            activeToolbar.add(new NewEntryAction());
-            //activeToolbar.add(edit); TODO
-            activeToolbar.add(remove);
-            add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5));
-
-        }
-
-        // Listener of default providers list selection
-        private final class DefListSelectionListener implements ListSelectionListener {
-            // The current drawn rectangles and polygons
-            private final Map<Integer, MapRectangle> mapRectangles;
-            private final Map<Integer, List<MapPolygon>> mapPolygons;
-
-            private DefListSelectionListener() {
-                this.mapRectangles = new HashMap<Integer, MapRectangle>();
-                this.mapPolygons = new HashMap<Integer, List<MapPolygon>>();
-            }
-
-            @Override
-            public void valueChanged(ListSelectionEvent e) {
-                // First index is set to -1 when the list is refreshed, so discard all map rectangles and polygons
-                if (e.getFirstIndex() == -1) {
-                    defaultMap.removeAllMapRectangles();
-                    defaultMap.removeAllMapPolygons();
-                    mapRectangles.clear();
-                    mapPolygons.clear();
-                    // Only process complete (final) selection events
-                } else if (!e.getValueIsAdjusting()) {
-                    for (int i = e.getFirstIndex(); i<=e.getLastIndex(); i++) {
-                        updateBoundsAndShapes(i);
-                    }
-                    // If needed, adjust map to show all map rectangles and polygons
-                    if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
-                        defaultMap.setDisplayToFitMapElements(false, true, true);
-                        defaultMap.zoomOut();
-                    }
-                }
-            }
-
-            private void updateBoundsAndShapes(int i) {
-                ImageryBounds bounds = defaultModel.getRow(i).getBounds();
-                if (bounds != null) {
-                    List<Shape> shapes = bounds.getShapes();
-                    if (shapes != null && !shapes.isEmpty()) {
-                        if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
-                            if (!mapPolygons.containsKey(i)) {
-                                List<MapPolygon> list = new ArrayList<MapPolygon>();
-                                mapPolygons.put(i, list);
-                                // Add new map polygons
-                                for (Shape shape : shapes) {
-                                    MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
-                                    list.add(polygon);
-                                    defaultMap.addMapPolygon(polygon);
-                                }
-                            }
-                        } else if (mapPolygons.containsKey(i)) {
-                            // Remove previously drawn map polygons
-                            for (MapPolygon polygon : mapPolygons.get(i)) {
-                                defaultMap.removeMapPolygon(polygon);
-                            }
-                            mapPolygons.remove(i);
-                        }
-                        // Only display bounds when no polygons (shapes) are defined for this provider
-                    } else {
-                        if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
-                            if (!mapRectangles.containsKey(i)) {
-                                // Add new map rectangle
-                                Coordinate topLeft = new Coordinate(bounds.getMax().lat(), bounds.getMin().lon());
-                                Coordinate bottomRight = new Coordinate(bounds.getMin().lat(), bounds.getMax().lon());
-                                MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight);
-                                mapRectangles.put(i, rectangle);
-                                defaultMap.addMapRectangle(rectangle);
-                            }
-                        } else if (mapRectangles.containsKey(i)) {
-                            // Remove previously drawn map rectangle
-                            defaultMap.removeMapRectangle(mapRectangles.get(i));
-                            mapRectangles.remove(i);
-                        }
-                    }
-                }
-            }
-        }
-
-        private class NewEntryAction extends AbstractAction {
-            public NewEntryAction() {
-                putValue(NAME, tr("New"));
-                putValue(SHORT_DESCRIPTION, tr("Add a new WMS/TMS entry by entering the URL"));
-                putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
-            }
-
-            public void actionPerformed(ActionEvent evt) {
-                final AddWMSLayerPanel p = new AddWMSLayerPanel();
-                // This code snippet allows to resize the JOptionPane (fix #6090)
-                p.addHierarchyListener(new HierarchyListener() {
-                    public void hierarchyChanged(HierarchyEvent e) {
-                        Window window = SwingUtilities.getWindowAncestor(p);
-                        if (window instanceof Dialog) {
-                            Dialog dialog = (Dialog)window;
-                            if (!dialog.isResizable()) {
-                                dialog.setResizable(true);
-                                dialog.setMinimumSize(new Dimension(250, 350));
-                            }
-                        }
-                    }
-                });
-                int answer = JOptionPane.showConfirmDialog(
-                        gui, p,
-                        tr("Add Imagery URL"),
-                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
-                if (answer == JOptionPane.OK_OPTION) {
-                    try {
-                        activeModel.addRow(p.getImageryInfo());
-                    } catch (IllegalArgumentException ex) {
-                        if (ex.getMessage() == null || ex.getMessage().isEmpty())
-                            throw ex;
-                        else {
-                            JOptionPane.showMessageDialog(Main.parent,
-                                    ex.getMessage(), tr("Error"),
-                                    JOptionPane.ERROR_MESSAGE);
-                        }
-                    }
-                }
-            }
-        }
-
-        private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
-
-            public RemoveEntryAction() {
-                putValue(NAME, tr("Remove"));
-                putValue(SHORT_DESCRIPTION, tr("Remove entry"));
-                putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
-                updateEnabledState();
-            }
-
-            protected void updateEnabledState() {
-                setEnabled(activeTable.getSelectedRowCount() > 0);
-            }
-
-            @Override
-            public void valueChanged(ListSelectionEvent e) {
-                updateEnabledState();
-            }
-
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                Integer i;
-                while ((i = activeTable.getSelectedRow()) != -1) {
-                    activeModel.removeRow(i);
-                }
-            }
-        }
-
-        private class ActivateAction extends AbstractAction implements ListSelectionListener {
-            public ActivateAction() {
-                putValue(NAME, tr("Activate"));
-                putValue(SHORT_DESCRIPTION, tr("copy selected defaults"));
-                putValue(SMALL_ICON, ImageProvider.get("preferences", "activate-down"));
-            }
-
-            protected void updateEnabledState() {
-                setEnabled(defaultTable.getSelectedRowCount() > 0);
-            }
-
-            @Override
-            public void valueChanged(ListSelectionEvent e) {
-                updateEnabledState();
-            }
-
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                int[] lines = defaultTable.getSelectedRows();
-                if (lines.length == 0) {
-                    JOptionPane.showMessageDialog(
-                            gui,
-                            tr("Please select at least one row to copy."),
-                            tr("Information"),
-                            JOptionPane.INFORMATION_MESSAGE);
-                    return;
-                }
-
-                Set<String> acceptedEulas = new HashSet<String>();
-
-                outer: for (int i = 0; i < lines.length; i++) {
-                    ImageryInfo info = defaultModel.getRow(lines[i]);
-
-                    // Check if an entry with exactly the same values already
-                    // exists
-                    for (int j = 0; j < activeModel.getRowCount(); j++) {
-                        if (info.equalsBaseValues(activeModel.getRow(j))) {
-                            // Select the already existing row so the user has
-                            // some feedback in case an entry exists
-                            activeTable.getSelectionModel().setSelectionInterval(j, j);
-                            activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true));
-                            continue outer;
-                        }
-                    }
-
-                    String eulaURL = info.getEulaAcceptanceRequired();
-                    // If set and not already accepted, ask for EULA acceptance
-                    if (eulaURL != null && !acceptedEulas.contains(eulaURL)) {
-                        if (confirmEulaAcceptance(gui, eulaURL)) {
-                            acceptedEulas.add(eulaURL);
-                        } else {
-                            continue outer;
-                        }
-                    }
-
-                    activeModel.addRow(new ImageryInfo(info));
-                    int lastLine = activeModel.getRowCount() - 1;
-                    activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
-                    activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true));
-                }
-            }
-        }
-
-        private class ReloadAction extends AbstractAction {
-            public ReloadAction() {
-                putValue(SHORT_DESCRIPTION, tr("reload defaults"));
-                putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
-            }
-
-            public void actionPerformed(ActionEvent evt) {
-                layerInfo.loadDefaults(true);
-                defaultModel.fireTableDataChanged();
-            }
-        }
-
-        /**
-         * The table model for imagery layer list
-         */
-        public class ImageryLayerTableModel extends DefaultTableModel {
-            public ImageryLayerTableModel() {
-                setColumnIdentifiers(new String[] { tr("Menu Name"), tr("Imagery URL")});
-            }
-
-            public ImageryInfo getRow(int row) {
-                return layerInfo.getLayers().get(row);
-            }
-
-            public void addRow(ImageryInfo i) {
-                layerInfo.add(i);
-                int p = getRowCount() - 1;
-                fireTableRowsInserted(p, p);
-            }
-
-            @Override
-            public void removeRow(int i) {
-                layerInfo.remove(getRow(i));
-                fireTableRowsDeleted(i, i);
-            }
-
-            @Override
-            public int getRowCount() {
-                return layerInfo.getLayers().size();
-            }
-
-            @Override
-            public Object getValueAt(int row, int column) {
-                ImageryInfo info = layerInfo.getLayers().get(row);
-                switch (column) {
-                case 0:
-                    return info.getName();
-                case 1:
-                    return info.getExtendedUrl();
-                default:
-                    throw new ArrayIndexOutOfBoundsException();
-                }
-            }
-
-            @Override
-            public void setValueAt(Object o, int row, int column) {
-                ImageryInfo info = layerInfo.getLayers().get(row);
-                switch (column) {
-                case 0:
-                    info.setName((String) o);
-                    break;
-                case 1:
-                    info.setExtendedUrl((String)o);
-                    break;
-                default:
-                    throw new ArrayIndexOutOfBoundsException();
-                }
-            }
-
-            @Override
-            public boolean isCellEditable(int row, int column) {
-                return true;
-            }
-        }
-
-        /**
-         * The table model for the default imagery layer list
-         */
-        public class ImageryDefaultLayerTableModel extends DefaultTableModel {
-            public ImageryDefaultLayerTableModel() {
-                setColumnIdentifiers(new String[]{"", tr("Menu Name (Default)"), tr("Imagery URL (Default)")});
-            }
-
-            public ImageryInfo getRow(int row) {
-                return layerInfo.getDefaultLayers().get(row);
-            }
-
-            @Override
-            public int getRowCount() {
-                return layerInfo.getDefaultLayers().size();
-            }
-
-            @Override
-            public Object getValueAt(int row, int column) {
-                ImageryInfo info = layerInfo.getDefaultLayers().get(row);
-                switch (column) {
-                case 0:
-                    return info.getCountryCode();
-                case 1:
-                    return info.getName();
-                case 2:
-                    return info.getExtendedUrl();
-                }
-                return null;
-            }
-
-            @Override
-            public boolean isCellEditable(int row, int column) {
-                return false;
-            }
-        }
-
-        private boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
-            URL url = null;
-            try {
-                url = new URL(eulaUrl.replaceAll("\\{lang\\}", Locale.getDefault().toString()));
-                JEditorPane htmlPane = null;
-                try {
-                    htmlPane = new JEditorPane(url);
-                } catch (IOException e1) {
-                    // give a second chance with a default Locale 'en'
-                    try {
-                        url = new URL(eulaUrl.replaceAll("\\{lang\\}", "en"));
-                        htmlPane = new JEditorPane(url);
-                    } catch (IOException e2) {
-                        JOptionPane.showMessageDialog(gui ,tr("EULA license URL not available: {0}", eulaUrl));
-                        return false;
-                    }
-                }
-                Box box = Box.createVerticalBox();
-                htmlPane.setEditable(false);
-                JScrollPane scrollPane = new JScrollPane(htmlPane);
-                scrollPane.setPreferredSize(new Dimension(400, 400));
-                box.add(scrollPane);
-                int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"), JOptionPane.YES_NO_OPTION,
-                        JOptionPane.WARNING_MESSAGE);
-                if (option == JOptionPane.YES_OPTION)
-                    return true;
-            } catch (MalformedURLException e2) {
-                JOptionPane.showMessageDialog(gui ,tr("Malformed URL for the EULA licence: {0}", eulaUrl));
-            }
-            return false;
-        }
-    }
-
-    static class OffsetBookmarksPanel extends JPanel {
-        List<OffsetBookmark> bookmarks = OffsetBookmark.allBookmarks;
-        OffsetsBookmarksModel model = new OffsetsBookmarksModel();
-
-        public OffsetBookmarksPanel(final PreferenceTabbedPane gui) {
-            super(new GridBagLayout());
-            final JTable list = new JTable(model) {
-                @Override
-                public String getToolTipText(MouseEvent e) {
-                    java.awt.Point p = e.getPoint();
-                    return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
-                }
-            };
-            JScrollPane scroll = new JScrollPane(list);
-            add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
-            scroll.setPreferredSize(new Dimension(200, 200));
-
-            TableColumnModel mod = list.getColumnModel();
-            mod.getColumn(0).setPreferredWidth(150);
-            mod.getColumn(1).setPreferredWidth(200);
-            mod.getColumn(2).setPreferredWidth(300);
-            mod.getColumn(3).setPreferredWidth(150);
-            mod.getColumn(4).setPreferredWidth(150);
-
-            JPanel buttonPanel = new JPanel(new FlowLayout());
-
-            JButton add = new JButton(tr("Add"));
-            buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
-            add.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) {
-                    OffsetBookmark b = new OffsetBookmark(Main.getProjection(),"","",0,0);
-                    model.addRow(b);
-                }
-            });
-
-            JButton delete = new JButton(tr("Delete"));
-            buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
-            delete.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) {
-                    if (list.getSelectedRow() == -1) {
-                        JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
-                    } else {
-                        Integer i;
-                        while ((i = list.getSelectedRow()) != -1) {
-                            model.removeRow(i);
-                        }
-                    }
-                }
-            });
-
-            add(buttonPanel,GBC.eol());
-        }
-
-        /**
-         * The table model for imagery offsets list
-         */
-        class OffsetsBookmarksModel extends DefaultTableModel {
-            public OffsetsBookmarksModel() {
-                setColumnIdentifiers(new String[] { tr("Projection"),  tr("Layer"), tr("Name"), tr("Easting"), tr("Northing"),});
-            }
-
-            public OffsetBookmark getRow(int row) {
-                return bookmarks.get(row);
-            }
-
-            public void addRow(OffsetBookmark i) {
-                bookmarks.add(i);
-                int p = getRowCount() - 1;
-                fireTableRowsInserted(p, p);
-            }
-
-            @Override
-            public void removeRow(int i) {
-                bookmarks.remove(getRow(i));
-                fireTableRowsDeleted(i, i);
-            }
-
-            @Override
-            public int getRowCount() {
-                return bookmarks.size();
-            }
-
-            @Override
-            public Object getValueAt(int row, int column) {
-                OffsetBookmark info = bookmarks.get(row);
-                switch (column) {
-                case 0:
-                    if (info.proj == null) return "";
-                    return info.proj.toString();
-                case 1:
-                    return info.layerName;
-                case 2:
-                    return info.name;
-                case 3:
-                    return info.dx;
-                case 4:
-                    return info.dy;
-                default:
-                    throw new ArrayIndexOutOfBoundsException();
-                }
-            }
-
-            @Override
-            public void setValueAt(Object o, int row, int column) {
-                OffsetBookmark info = bookmarks.get(row);
-                switch (column) {
-                case 1:
-                    info.layerName = o.toString();
-                    break;
-                case 2:
-                    info.name = o.toString();
-                    break;
-                case 3:
-                    info.dx = Double.parseDouble((String) o);
-                    break;
-                case 4:
-                    info.dy = Double.parseDouble((String) o);
-                    break;
-                default:
-                    throw new ArrayIndexOutOfBoundsException();
-                }
-            }
-
-            @Override
-            public boolean isCellEditable(int row, int column) {
-                return column >= 1;
-            }
-        }
-    }
-
-    public static void initialize() {
-        ImageryLayerInfo.instance.clear();
-        ImageryLayerInfo.instance.loadDefaults(false);
-        ImageryLayerInfo.instance.load();
-        OffsetBookmark.loadBookmarks();
-        Main.main.menu.imageryMenu.refreshImageryMenu();
-        Main.main.menu.imageryMenu.refreshOffsetMenu();
-    }
-}
Index: unk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,126 +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 java.awt.Component;
-import java.awt.GridBagLayout;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.ListCellRenderer;
-import javax.swing.UIManager;
-import javax.swing.UIManager.LookAndFeelInfo;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.ExpertToggleAction;
-import org.openstreetmap.josm.tools.GBC;
-
-public class LafPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new LafPreference();
-        }
-    }
-
-    /**
-     * ComboBox with all look and feels.
-     */
-    private JComboBox lafCombo;
-    public JPanel panel;
-    private JCheckBox showSplashScreen = new JCheckBox(tr("Show splash screen at startup"));
-    private JCheckBox showID = new JCheckBox(tr("Show object ID in selection lists"));
-    private JCheckBox showLocalizedName = new JCheckBox(tr("Show localized name in selection lists"));
-    private JCheckBox modeless = new JCheckBox(tr("Modeless working (Potlatch style)"));
-    private JCheckBox dynamicButtons = new JCheckBox(tr("Dynamic buttons in side menus"));
-
-    public void addGui(PreferenceTabbedPane gui) {
-        lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
-
-        // let's try to load additional LookAndFeels and put them into the list
-        try {
-            Class<?> Cquaqua = Class.forName("ch.randelshofer.quaqua.QuaquaLookAndFeel");
-            Object Oquaqua = Cquaqua.getConstructor((Class[])null).newInstance((Object[])null);
-            // no exception? Then Go!
-            lafCombo.addItem(
-                    new UIManager.LookAndFeelInfo(((javax.swing.LookAndFeel)Oquaqua).getName(), "ch.randelshofer.quaqua.QuaquaLookAndFeel")
-            );
-        } catch (Exception ex) {
-            // just ignore, Quaqua may not even be installed...
-            //System.out.println("Failed to load Quaqua: " + ex);
-        }
-
-        String laf = Main.pref.get("laf", Main.platform.getDefaultStyle());
-        for (int i = 0; i < lafCombo.getItemCount(); ++i) {
-            if (((LookAndFeelInfo)lafCombo.getItemAt(i)).getClassName().equals(laf)) {
-                lafCombo.setSelectedIndex(i);
-                break;
-            }
-        }
-
-        final ListCellRenderer oldRenderer = lafCombo.getRenderer();
-        lafCombo.setRenderer(new DefaultListCellRenderer(){
-            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-                return oldRenderer.getListCellRendererComponent(list, ((LookAndFeelInfo)value).getName(), index, isSelected, cellHasFocus);
-            }
-        });
-
-        panel = new JPanel(new GridBagLayout());
-        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-
-        // Show splash screen on startup
-        showSplashScreen.setToolTipText(tr("Show splash screen at startup"));
-        showSplashScreen.setSelected(Main.pref.getBoolean("draw.splashscreen", true));
-        panel.add(showSplashScreen, GBC.eop().insets(20, 0, 0, 0));
-
-        // Show ID in selection
-        showID.setToolTipText(tr("Show object ID in selection lists"));
-        showID.setSelected(Main.pref.getBoolean("osm-primitives.showid", false));
-
-        // Show localized names
-        showLocalizedName.setToolTipText(tr("Show localized name in selection lists, if available"));
-        showLocalizedName.setSelected(Main.pref.getBoolean("osm-primitives.localize-name", true));
-        ExpertToggleAction.addVisibilitySwitcher(showLocalizedName);
-
-        modeless.setToolTipText(tr("Do not require to switch modes (potlatch style workflow)"));
-        modeless.setSelected(Main.pref.getBoolean("modeless", false));
-        ExpertToggleAction.addVisibilitySwitcher(modeless);
-
-        panel.add(showID, GBC.eop().insets(20, 0, 0, 0));
-        panel.add(showLocalizedName, GBC.eop().insets(20, 0, 0, 0));
-        panel.add(modeless, GBC.eop().insets(20, 0, 0, 0));
-
-        dynamicButtons.setToolTipText(tr("Display buttons in right side menus only when mouse is inside the element"));
-        dynamicButtons.setSelected(Main.pref.getBoolean("dialog.dynamic.buttons", true));
-        panel.add(dynamicButtons, GBC.eop().insets(20, 0, 0, 0));
-
-        panel.add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
-
-        panel.add(new JLabel(tr("Look and Feel")), GBC.std().insets(20, 0, 0, 0));
-        panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        panel.add(lafCombo, GBC.eol().fill(GBC.HORIZONTAL));
-
-        JScrollPane scrollpane = new JScrollPane(panel);
-        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        gui.displaycontent.addTab(tr("Look and Feel"), scrollpane);
-    }
-
-    public boolean ok() {
-        boolean mod = false;
-        Main.pref.put("draw.splashscreen", showSplashScreen.isSelected());
-        Main.pref.put("osm-primitives.showid", showID.isSelected());
-        Main.pref.put("osm-primitives.localize-name", showLocalizedName.isSelected());
-        Main.pref.put("modeless", modeless.isSelected());
-        Main.pref.put("dialog.dynamic.buttons", dynamicButtons.isSelected());
-        mod |= Main.pref.put("laf", ((LookAndFeelInfo)lafCombo.getSelectedItem()).getClassName());
-        return mod;
-    }
-}
Index: unk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 4967)
+++ 	(revision )
@@ -1,109 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-import javax.swing.Box;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.ListCellRenderer;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.I18n;
-
-public class LanguagePreference implements PreferenceSetting {
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new LanguagePreference();
-        }
-    }
-
-    /** the combo box with the available locales */
-    private JComboBox langCombo;
-    /** the model for the combo box */
-    private LanguageComboBoxModel model;
-
-    public void addGui(final PreferenceTabbedPane gui) {
-        model = new LanguageComboBoxModel();
-        // Selecting the language BEFORE the JComboBox listens to model changes speed up initialization by ~35ms (see #7386)
-        // See http://stackoverflow.com/questions/3194958/fast-replacement-for-jcombobox-basiccomboboxui 
-        model.selectLanguage(Main.pref.get("language"));
-        langCombo = new JComboBox(model);
-        langCombo.setRenderer(new LanguageCellRenderer(langCombo.getRenderer()));
-
-        LafPreference lafPreference = gui.getSetting(LafPreference.class);
-        final JPanel panel = lafPreference.panel;
-        panel.add(new JLabel(tr("Language")), GBC.std().insets(20, 0, 0, 0));
-        panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        panel.add(langCombo, GBC.eol().fill(GBC.HORIZONTAL));
-        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-    }
-
-    public boolean ok() {
-        if(langCombo.getSelectedItem() == null)
-            return Main.pref.put("language", null);
-        else
-            return Main.pref.put("language",
-                    ((Locale)langCombo.getSelectedItem()).toString());
-    }
-
-    private static class LanguageComboBoxModel extends DefaultComboBoxModel {
-        private final List<Locale> data = new ArrayList<Locale>();
-
-        public LanguageComboBoxModel(){
-            data.add(0,null);
-            data.addAll(Arrays.asList(I18n.getAvailableTranslations()));
-        }
-
-        public void selectLanguage(String language) {
-            setSelectedItem(null);
-            if (language != null) {
-                for (Locale locale: data) {
-                    if (locale == null) {
-                        continue;
-                    }
-                    if (locale.toString().equals(language)) {
-                        setSelectedItem(locale);
-                        return;
-                    }
-                }
-            }
-        }
-
-        @Override
-        public Object getElementAt(int index) {
-            return data.get(index);
-        }
-
-        @Override
-        public int getSize() {
-            return data.size();
-        }
-    }
-
-    static private class LanguageCellRenderer extends DefaultListCellRenderer {
-        private ListCellRenderer dispatch;
-        public LanguageCellRenderer(ListCellRenderer dispatch) {
-            this.dispatch = dispatch;
-        }
-        @Override
-        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
-                boolean cellHasFocus) {
-            Locale l = (Locale) value;
-            return dispatch.getListCellRendererComponent(list,
-                    l == null ? tr("Default (Auto determined)") : l.getDisplayName(l),
-                            index, isSelected, cellHasFocus);
-        }
-    }
-}
Index: unk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,265 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.TreeSet;
-
-import javax.swing.BorderFactory;
-import javax.swing.JCheckBox;
-import javax.swing.JPanel;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
-import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.Predicate;
-import org.openstreetmap.josm.tools.Utils;
-
-public class MapPaintPreference implements PreferenceSetting {
-    private SourceEditor sources;
-    private JCheckBox enableIconDefault;
-
-    private static final List<SourceProvider> styleSourceProviders = new ArrayList<SourceProvider>();
-
-    public static final boolean registerSourceProvider(SourceProvider provider) {
-        if (provider != null)
-            return styleSourceProviders.add(provider);
-        return false;
-    }
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new MapPaintPreference();
-        }
-    }
-
-    public void addGui(final PreferenceTabbedPane gui) {
-        enableIconDefault = new JCheckBox(tr("Enable built-in icon defaults"),
-                Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
-
-        sources = new MapPaintSourceEditor();
-
-        final JPanel panel = new JPanel(new GridBagLayout());
-        panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-
-        panel.add(sources, GBC.eol().fill(GBC.BOTH));
-        panel.add(enableIconDefault, GBC.eol().insets(11,2,5,0));
-
-        gui.mapcontent.addTab(tr("Map Paint Styles"), panel);
-
-        // this defers loading of style sources to the first time the tab
-        // with the map paint preferences is selected by the user
-        //
-        gui.mapcontent.addChangeListener(
-                new ChangeListener() {
-                    public void stateChanged(ChangeEvent e) {
-                        if (gui.mapcontent.getSelectedComponent() == panel) {
-                            sources.initiallyLoadAvailableSources();
-                        }
-                    }
-                }
-                );
-    }
-
-    static class MapPaintSourceEditor extends SourceEditor {
-
-        final private String iconpref = "mappaint.icon.sources";
-
-        public MapPaintSourceEditor() {
-            super(true, "http://josm.openstreetmap.de/styles", styleSourceProviders);
-        }
-
-        @Override
-        public Collection<? extends SourceEntry> getInitialSourcesList() {
-            return MapPaintPrefHelper.INSTANCE.get();
-        }
-
-        @Override
-        public boolean finish() {
-            List<SourceEntry> activeStyles = activeSourcesModel.getSources();
-
-            boolean changed = MapPaintPrefHelper.INSTANCE.put(activeStyles);
-
-            if (tblIconPaths != null) {
-                List<String> iconPaths = iconPathsModel.getIconPaths();
-
-                if (!iconPaths.isEmpty()) {
-                    if (Main.pref.putCollection(iconpref, iconPaths)) {
-                        changed = true;
-                    }
-                } else if (Main.pref.putCollection(iconpref, null)) {
-                    changed = true;
-                }
-            }
-            return changed;
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            return MapPaintPrefHelper.INSTANCE.getDefault();
-        }
-
-        @Override
-        public Collection<String> getInitialIconPathsList() {
-            return Main.pref.getCollection(iconpref, null);
-        }
-
-        @Override
-        public String getStr(I18nString ident) {
-            switch (ident) {
-            case AVAILABLE_SOURCES:
-                return tr("Available styles:");
-            case ACTIVE_SOURCES:
-                return tr("Active styles:");
-            case NEW_SOURCE_ENTRY_TOOLTIP:
-                return tr("Add a new style by entering filename or URL");
-            case NEW_SOURCE_ENTRY:
-                return tr("New style entry:");
-            case REMOVE_SOURCE_TOOLTIP:
-                return tr("Remove the selected styles from the list of active styles");
-            case EDIT_SOURCE_TOOLTIP:
-                return tr("Edit the filename or URL for the selected active style");
-            case ACTIVATE_TOOLTIP:
-                return tr("Add the selected available styles to the list of active styles");
-            case RELOAD_ALL_AVAILABLE:
-                return marktr("Reloads the list of available styles from ''{0}''");
-            case LOADING_SOURCES_FROM:
-                return marktr("Loading style sources from ''{0}''");
-            case FAILED_TO_LOAD_SOURCES_FROM:
-                return marktr("<html>Failed to load the list of style sources from<br>"
-                        + "''{0}''.<br>"
-                        + "<br>"
-                        + "Details (untranslated):<br>{1}</html>");
-            case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC:
-                return "/Preferences/Styles#FailedToLoadStyleSources";
-            case ILLEGAL_FORMAT_OF_ENTRY:
-                return marktr("Warning: illegal format of entry in style list ''{0}''. Got ''{1}''");
-            default: throw new AssertionError();
-            }
-        }
-
-    }
-
-    public boolean ok() {
-        boolean reload = Main.pref.put("mappaint.icon.enable-defaults", enableIconDefault.isSelected());
-        reload |= sources.finish();
-        if (reload) {
-            MapPaintStyles.readFromPreferences();
-        }
-        if (Main.isDisplayingMapView())
-        {
-            MapPaintStyles.getStyles().clearCached();
-        }
-        return false;
-    }
-
-    /**
-     * Initialize the styles
-     */
-    public static void initialize() {
-        MapPaintStyles.readFromPreferences();
-    }
-
-    public static class MapPaintPrefHelper extends SourceEditor.SourcePrefHelper {
-
-        public final static MapPaintPrefHelper INSTANCE = new MapPaintPrefHelper();
-
-        public MapPaintPrefHelper() {
-            super("mappaint.style.sources-list");
-        }
-
-        @Override
-        public List<SourceEntry> get() {
-            List<SourceEntry> ls = super.get();
-            if (insertNewDefaults(ls)) {
-                put(ls);
-            }
-            return ls;
-        }
-
-        /**
-         * If the selection of default styles changes in future releases, add
-         * the new entries to the user-configured list. Remember the known URLs,
-         * so an item that was deleted explicitly is not added again.
-         */
-        private boolean insertNewDefaults(List<SourceEntry> list) {
-            boolean changed = false;
-
-            Collection<String> knownDefaults = new TreeSet<String>(Main.pref.getCollection("mappaint.style.known-defaults"));
-
-            Collection<ExtendedSourceEntry> defaults = getDefault();
-            int insertionIdx = 0;
-            for (final SourceEntry def : defaults) {
-                int i = Utils.indexOf(list,
-                        new Predicate<SourceEntry>() {
-                    @Override
-                    public boolean evaluate(SourceEntry se) {
-                        return Utils.equal(def.url, se.url);
-                    }
-                });
-                if (i == -1 && !knownDefaults.contains(def.url)) {
-                    list.add(insertionIdx, def);
-                    insertionIdx++;
-                    changed = true;
-                } else {
-                    if (i >= insertionIdx) {
-                        insertionIdx = i + 1;
-                    }
-                }
-            }
-
-            for (SourceEntry def : defaults) {
-                knownDefaults.add(def.url);
-            }
-            Main.pref.putCollection("mappaint.style.known-defaults", knownDefaults);
-
-            return changed;
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            ExtendedSourceEntry defJOSM = new ExtendedSourceEntry("elemstyles.xml", "resource://styles/standard/elemstyles.xml");
-            defJOSM.active = true;
-            defJOSM.name = "standard";
-            defJOSM.title = tr("JOSM Internal Style");
-            defJOSM.description = tr("Internal style to be used as base for runtime switchable overlay styles");
-            ExtendedSourceEntry defPL2 = new ExtendedSourceEntry("potlatch2.mapcss", "resource://styles/standard/potlatch2.mapcss");
-            defPL2.active = false;
-            defPL2.name = "standard";
-            defPL2.title = tr("Potlatch 2");
-            defPL2.description = tr("the main Potlatch 2 style");
-
-            return Arrays.asList(new ExtendedSourceEntry[] { defJOSM, defPL2 });
-        }
-
-        @Override
-        public Collection<String> serialize(SourceEntry entry) {
-            return Arrays.asList(new String[] {
-                    entry.url,
-                    entry.name == null ? "" : entry.name,
-                            entry.title == null ? "" : entry.title,
-                                    Boolean.toString(entry.active)
-            });
-        }
-
-        @Override
-        public SourceEntry deserialize(List<String> entryStr) {
-            if (entryStr.size() < 4)
-                return null;
-            String url = entryStr.get(0);
-            String name = entryStr.get(1);
-            String shortdescription = entryStr.get(2);
-            boolean active = Boolean.parseBoolean(entryStr.get(3));
-            return new SourceEntry(url, name, shortdescription, active);
-        }
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 4968)
@@ -43,4 +43,5 @@
 import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
 import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.PreferencePanel;
 import org.openstreetmap.josm.gui.preferences.plugin.PluginListPanel;
 import org.openstreetmap.josm.gui.preferences.plugin.PluginPreferencesModel;
@@ -54,9 +55,13 @@
 import org.openstreetmap.josm.tools.ImageProvider;
 
-public class PluginPreference implements PreferenceSetting {
+public class PluginPreference extends DefaultTabPreferenceSetting {
     public static class Factory implements PreferenceSettingFactory {
         public PreferenceSetting createPreferenceSetting() {
             return new PluginPreference();
         }
+    }
+    
+    private PluginPreference() {
+        super("plugin", tr("Plugins"), tr("Configure available plugins."));
     }
 
@@ -178,7 +183,8 @@
         gc.anchor = GridBagConstraints.NORTHWEST;
         gc.fill = GridBagConstraints.BOTH;
-        gui.plugins.add(buildContentPanel(), gc);
+        PreferencePanel plugins = gui.createPreferenceTab(this);
+        plugins.add(buildContentPanel(), gc);
         pnlPluginPreferences.refreshView();
-        gui.addChangeListener(new PluginPreferenceActivationListener(gui.plugins));
+        gui.addChangeListener(new PluginPreferenceActivationListener(plugins));
     }
 
Index: unk/src/org/openstreetmap/josm/gui/preferences/PrefJPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/PrefJPanel.java	(revision 4967)
+++ 	(revision )
@@ -1,511 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Toolkit;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.KeyEvent;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.HashMap;
-import java.util.Map;
-
-import java.util.regex.PatternSyntaxException;
-import javax.swing.AbstractAction;
-import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JEditorPane;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.KeyStroke;
-import javax.swing.ListSelectionModel;
-import javax.swing.RowFilter;
-import javax.swing.SwingConstants;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.TableModel;
-
-import javax.swing.table.TableRowSorter;
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
-import org.openstreetmap.josm.tools.Shortcut;
-
-/**
- * This is the keyboard preferences content.
- * If someone wants to merge it with ShortcutPreference.java, feel free.
- */
-public class PrefJPanel extends JPanel {
-
-    // table of shortcuts
-    private AbstractTableModel model;
-    // comboboxes of modifier groups, mapping selectedIndex to real data
-    private static int[] modifInts = new int[]{
-        -1,
-        0,
-        KeyEvent.SHIFT_DOWN_MASK,
-        KeyEvent.CTRL_DOWN_MASK,
-        KeyEvent.ALT_DOWN_MASK,
-        KeyEvent.META_DOWN_MASK,
-        KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
-        KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
-        KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
-        KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
-        KeyEvent.CTRL_DOWN_MASK | KeyEvent.META_DOWN_MASK,
-        KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK,
-        KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
-        KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK
-    };
-    // and here are the texts fro the comboboxes
-    private static String[] modifList = new String[] {
-        tr("disabled"),
-        tr("no modifier"),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[2]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[3]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[4]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[5]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[6]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[7]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[8]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[9]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[10]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[11]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[12]).getModifiers()),
-        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[13]).getModifiers())
-    };
-    // this are the display(!) texts for the checkboxes. Let the JVM do the i18n for us <g>.
-    // Ok, there's a real reason for this: The JVM should know best how the keys are labelled
-    // on the physical keyboard. What language pack is installed in JOSM is completely
-    // independent from the keyboard's labelling. But the operation system's locale
-    // usually matches the keyboard. This even works with my English Windows and my German
-    // keyboard.
-    private static String SHIFT = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.SHIFT_DOWN_MASK).getModifiers());
-    private static String CTRL  = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK).getModifiers());
-    private static String ALT   = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_DOWN_MASK).getModifiers());
-    private static String META  = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK).getModifiers());
-
-    // A list of keys to present the user. Sadly this really is a list of keys Java knows about,
-    // not a list of real physical keys. If someone knows how to get that list?
-    private static Map<Integer, String> keyList = setKeyList();
-
-    private static Map<Integer, String> setKeyList() {
-        Map<Integer, String> list = new LinkedHashMap<Integer, String>();
-        String unknown = Toolkit.getProperty("AWT.unknown", "Unknown");
-        // Assume all known keys are declared in KeyEvent as "public static int VK_*"
-        for (Field field : KeyEvent.class.getFields()) {
-            if (field.getName().startsWith("VK_")) {
-                try {
-                    int i = field.getInt(null);
-                    String s = KeyEvent.getKeyText(i);
-                    if (s != null && s.length() > 0 && !s.contains(unknown)) {
-                        list.put(Integer.valueOf(i), s);
-                        //System.out.println(i+": "+s);
-                    }
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-        list.put(Integer.valueOf(-1), "");
-        return list;
-    }
-
-    private JComboBox bxPrim1 = new JComboBox();
-    private JComboBox bxPrim2 = new JComboBox();
-    private JComboBox bxPrim3 = new JComboBox();
-    private JComboBox bxPrim4 = new JComboBox();
-    private JComboBox bxSec1 = new JComboBox();
-    private JComboBox bxSec2 = new JComboBox();
-    private JComboBox bxSec3 = new JComboBox();
-    private JComboBox bxSec4 = new JComboBox();
-    private JComboBox bxTer1 = new JComboBox();
-    private JComboBox bxTer2 = new JComboBox();
-    private JComboBox bxTer3 = new JComboBox();
-    private JComboBox bxTer4 = new JComboBox();
-    private JCheckBox cbAlt = new JCheckBox();
-    private JCheckBox cbCtrl = new JCheckBox();
-    private JCheckBox cbMeta = new JCheckBox();
-    private JCheckBox cbShift = new JCheckBox();
-    private JCheckBox cbDefault = new JCheckBox();
-    private JCheckBox cbDisable = new JCheckBox();
-    private JComboBox tfKey = new JComboBox();
-
-    JTable shortcutTable = new JTable();
-
-    private JTextField filterField = new JTextField();
-
-    /** Creates new form prefJPanel */
-    // Ain't those auto-generated comments helpful or what? <g>
-    public PrefJPanel(AbstractTableModel model) {
-        this.model = model;
-        initComponents();
-    }
-
-    private void initComponents() {
-        JPanel editGroupPane = new JPanel();
-        JPanel hotkeyGroupPane = new JPanel();
-
-        JPanel listPane = new JPanel();
-        JScrollPane listScrollPane = new JScrollPane();
-        JPanel menuGroupPane = new JPanel();
-        JPanel modifierTab = new JPanel();
-        JTabbedPane prefTabPane = new JTabbedPane();
-        JPanel shortcutEditPane = new JPanel();
-        JPanel shortcutTab = new JPanel();
-        JPanel subwindowGroupPane = new JPanel();
-        JPanel infoTab = new JPanel();
-
-        CbAction action = new CbAction(this);
-        BxAction action2 = new BxAction();
-
-        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
-
-        // If someone wants to move this text into some resource, feel free.
-        infoTab.setLayout(new BoxLayout(shortcutTab, BoxLayout.Y_AXIS));
-        JEditorPane editor = new JEditorPane();
-        editor.setEditable(false);
-        editor.setContentType("text/html");
-        editor.setText(
-                tr("<h1><a name=\"top\">Keyboard Shortcuts</a></h1>")+
-                tr("<p>Please note that shortcut keys are assigned to the actions when JOSM is started. So you need to <b>restart</b> "
-                        +"JOSM to see your changes.</p>")+
-                        tr("<p>Furthermore, the shortcuts are activated when the actions are assigned to a menu entry of a button for the first "
-                                +"time. So some of your changes may become active even without restart --- but also without collision handling. "
-                                +"This is another reason to <b>restart</b> JOSM after making any changes here.</p>")+
-                                tr("<p>You may notice that the key selection list on the next page lists all keys that exist on all kinds of keyboards "
-                                        +"Java knows about, not just those keys that exist on your keyboard. Please only use values that correspond to "
-                                        +"a real key on your keyboard. If your keyboard has no ''Copy'' key (PC keyboard do not have them, Sun keyboards do), "
-                                        +"then do not use it. Also there are ''keys'' listed that correspond to a shortcut on your keyboard (e.g. '':''/Colon). "
-                                        +"Please do not use them either, use the base key ('';''/Semicolon on US keyboards, ''.''/Period on German keyboards, etc.) "
-                                        +"instead. Not doing so may result in conflicts, as there is no way for JOSM to know that Ctrl+Shift+; and Ctrl+: "
-                                        +"actually is the same thing on an US keyboard.</p>")+
-                                        tr("<h1>Modifier Groups</h1>")+
-                                        tr("<p>The last page lists the modifier keys JOSM will automatically assign to shortcuts. For every of the four kinds "
-                                                +"of shortcuts there are three alternatives. JOSM will try those alternatives in the listed order when managing a "
-                                                +"conflict. If all alternatives result in shortcuts that are already taken, it will assign a random shortcut "
-                                                +"instead.</p>")+
-                                                tr("<p>The pseudo-modifier ''disabled'' will disable the shortcut when encountered.</p>")
-        );
-        editor.setCaretPosition(0); // scroll up
-        prefTabPane.addTab(tr("Read First"), new JScrollPane(editor));
-
-        shortcutTab.setLayout(new BoxLayout(shortcutTab, BoxLayout.Y_AXIS));
-
-        shortcutTab.add(buildFilterPanel());
-        listPane.setLayout(new java.awt.GridLayout());
-
-        // This is the list of shortcuts:
-        shortcutTable.setModel(model);
-        shortcutTable.getSelectionModel().addListSelectionListener(new CbAction(this));
-        shortcutTable.setFillsViewportHeight(true);
-        shortcutTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        shortcutTable.setAutoCreateRowSorter(true);
-        listScrollPane.setViewportView(shortcutTable);
-
-        listPane.add(listScrollPane);
-
-        shortcutTab.add(listPane);
-
-        // and here follows the edit area. I won't object to someone re-designing it, it looks, um, "minimalistic" ;)
-        shortcutEditPane.setLayout(new java.awt.GridLayout(5, 2));
-
-        cbDefault.setAction(action);
-        cbDefault.setText(tr("Use default"));
-        cbShift.setAction(action);
-        cbShift.setText(SHIFT); // see above for why no tr()
-        cbDisable.setAction(action);
-        cbDisable.setText(tr("Disable"));
-        cbCtrl.setAction(action);
-        cbCtrl.setText(CTRL); // see above for why no tr()
-        cbAlt.setAction(action);
-        cbAlt.setText(ALT); // see above for why no tr()
-        tfKey.setAction(action);
-        tfKey.setModel(new DefaultComboBoxModel(keyList.values().toArray()));
-        cbMeta.setAction(action);
-        cbMeta.setText(META); // see above for why no tr()
-
-
-        shortcutEditPane.add(cbDefault);
-        shortcutEditPane.add(new JLabel());
-        shortcutEditPane.add(cbShift);
-        shortcutEditPane.add(cbDisable);
-        shortcutEditPane.add(cbCtrl);
-        shortcutEditPane.add(new JLabel(tr("Key:"), SwingConstants.LEFT));
-        shortcutEditPane.add(cbAlt);
-        shortcutEditPane.add(tfKey);
-        shortcutEditPane.add(cbMeta);
-
-        shortcutEditPane.add(new JLabel(tr("Attention: Use real keyboard keys only!")));
-
-        action.actionPerformed(null); // init checkboxes
-
-        shortcutTab.add(shortcutEditPane);
-
-        prefTabPane.addTab(tr("Keyboard Shortcuts"), shortcutTab);
-
-        // next is the modfier group tab.
-        // Would be a nice array if I had done it by hand. But then, it would be finished next year or so...
-        modifierTab.setLayout(new java.awt.GridLayout(0, 1));
-        JScrollPane modifierScroller = new JScrollPane(modifierTab);
-
-        editGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Edit Shortcuts")));
-        editGroupPane.setLayout(new java.awt.GridLayout(3, 5));
-
-        JComboBox[] bxArray = new JComboBox[] {
-                    bxPrim1,bxSec1,bxTer1,bxPrim2,bxSec2,bxTer2,
-                    bxPrim3,bxSec3,bxTer3,bxPrim4,bxSec4,bxTer4};
-        for (JComboBox bxi: bxArray) bxi.setModel(new DefaultComboBoxModel(modifList));
-
-        editGroupPane.add(new JLabel(tr("Primary modifier:")));
-        editGroupPane.add(bxPrim1);
-        editGroupPane.add(new JLabel(tr("Secondary modifier:")));
-        editGroupPane.add(bxSec1);
-        editGroupPane.add(new JLabel(tr("Tertiary modifier:")));
-        editGroupPane.add(bxTer1);
-        modifierTab.add(editGroupPane);
-
-        menuGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Menu Shortcuts")));
-        menuGroupPane.setLayout(new java.awt.GridLayout(3, 5));
-        menuGroupPane.add(new JLabel(tr("Primary modifier:")));
-        menuGroupPane.add(bxPrim2);
-        menuGroupPane.add(new JLabel(tr("Secondary modifier:")));
-        menuGroupPane.add(bxSec2);
-        menuGroupPane.add(new JLabel(tr("Tertiary modifier:")));
-        menuGroupPane.add(bxTer2);
-        modifierTab.add(menuGroupPane);
-
-        hotkeyGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Hotkey Shortcuts")));
-        hotkeyGroupPane.setLayout(new java.awt.GridLayout(3, 5));
-        hotkeyGroupPane.add(new JLabel(tr("Primary modifier:")));
-        hotkeyGroupPane.add(bxPrim3);
-        hotkeyGroupPane.add(new JLabel((tr("Secondary modifier:"))));
-        hotkeyGroupPane.add(bxSec3);
-        hotkeyGroupPane.add(new JLabel(tr("Tertiary modifier:")));
-        hotkeyGroupPane.add(bxTer3);
-        modifierTab.add(hotkeyGroupPane);
-
-        subwindowGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Subwindow Shortcuts")));
-        subwindowGroupPane.setLayout(new java.awt.GridLayout(3, 5));
-        subwindowGroupPane.add(new JLabel(tr("Primary modifier:")));
-        subwindowGroupPane.add(bxPrim4);
-        subwindowGroupPane.add(new JLabel(tr("Secondary modifier:")));
-        subwindowGroupPane.add(bxSec4);
-        subwindowGroupPane.add(new JLabel(tr("Tertiary modifier:")));
-        subwindowGroupPane.add(bxTer4);
-
-        initbx();
-        for (JComboBox bxi: bxArray) bxi.setAction(action2);
-
-        modifierTab.add(subwindowGroupPane);
-
-        prefTabPane.addTab(tr("Modifier Groups"), modifierScroller);
-
-        add(prefTabPane);
-    }
-
-    private JPanel buildFilterPanel() {
-        // copied from PluginPreference
-        JPanel pnl  = new JPanel(new GridBagLayout());
-        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-        GridBagConstraints gc = new GridBagConstraints();
-
-        gc.anchor = GridBagConstraints.NORTHWEST;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.weightx = 0.0;
-        gc.insets = new Insets(0,0,0,5);
-        pnl.add(new JLabel(tr("Search:")), gc);
-
-        gc.gridx = 1;
-        gc.weightx = 1.0;
-        pnl.add(filterField, gc);
-        filterField.setToolTipText(tr("Enter a search expression"));
-        SelectAllOnFocusGainedDecorator.decorate(filterField);
-        filterField.getDocument().addDocumentListener(new FilterFieldAdapter());
-        pnl.setMaximumSize(new Dimension(300,10));
-        return pnl;
-    }
-
-    private void disableAllModifierCheckboxes() {
-        cbDefault.setEnabled(false);
-        cbDisable.setEnabled(false);
-        cbShift.setEnabled(false);
-        cbCtrl.setEnabled(false);
-        cbAlt.setEnabled(false);
-        cbMeta.setEnabled(false);
-    }
-
-    // this allows to edit shortcuts. it:
-    //  * sets the edit controls to the selected shortcut
-    //  * enabled/disables the controls as needed
-    //  * writes the user's changes to the shortcut
-    // And after I finally had it working, I realized that those two methods
-    // are playing ping-pong (politically correct: table tennis, I know) and
-    // even have some duplicated code. Feel free to refactor, If you have
-    // more expirience with GUI coding than I have.
-    private class CbAction extends AbstractAction implements ListSelectionListener {
-        private PrefJPanel panel;
-        public CbAction (PrefJPanel panel) {
-            this.panel = panel;
-        }
-        public void valueChanged(ListSelectionEvent e) {
-            ListSelectionModel lsm = panel.shortcutTable.getSelectionModel(); // can't use e here
-            if (!lsm.isSelectionEmpty()) {
-                int row = panel.shortcutTable.convertRowIndexToModel(lsm.getMinSelectionIndex());
-                Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
-                panel.cbDefault.setSelected(!sc.getAssignedUser());
-                panel.cbDisable.setSelected(sc.getKeyStroke() == null);
-                panel.cbShift.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.SHIFT_DOWN_MASK) != 0);
-                panel.cbCtrl.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.CTRL_DOWN_MASK) != 0);
-                panel.cbAlt.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.ALT_DOWN_MASK) != 0);
-                panel.cbMeta.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.META_DOWN_MASK) != 0);
-                if (sc.getKeyStroke() != null) {
-                    tfKey.setSelectedItem(keyList.get(sc.getKeyStroke().getKeyCode()));
-                } else {
-                    tfKey.setSelectedItem(keyList.get(-1));
-                }
-                if (!sc.isChangeable()) {
-                    disableAllModifierCheckboxes();
-                    panel.tfKey.setEnabled(false);
-                } else {
-                    panel.cbDefault.setEnabled(true);
-                    actionPerformed(null);
-                }
-                model.fireTableCellUpdated(row, 1);
-            } else {
-                panel.disableAllModifierCheckboxes();
-                panel.tfKey.setEnabled(false);
-            }
-        }
-        public void actionPerformed(java.awt.event.ActionEvent e) {
-            ListSelectionModel lsm = panel.shortcutTable.getSelectionModel();
-            if (lsm != null && !lsm.isSelectionEmpty()) {
-                if (e != null) { // only if we've been called by a user action
-                    int row = panel.shortcutTable.convertRowIndexToModel(lsm.getMinSelectionIndex());
-                    Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
-                    if (panel.cbDisable.isSelected()) {
-                        sc.setAssignedModifier(-1);
-                    } else if (panel.tfKey.getSelectedItem().equals("")) {
-                        sc.setAssignedModifier(KeyEvent.VK_CANCEL);
-                    } else {
-                        sc.setAssignedModifier(
-                                (panel.cbShift.isSelected() ? KeyEvent.SHIFT_DOWN_MASK : 0) |
-                                (panel.cbCtrl.isSelected() ? KeyEvent.CTRL_DOWN_MASK : 0) |
-                                (panel.cbAlt.isSelected() ? KeyEvent.ALT_DOWN_MASK : 0) |
-                                (panel.cbMeta.isSelected() ? KeyEvent.META_DOWN_MASK : 0)
-                        );
-                        for (Map.Entry<Integer, String> entry : keyList.entrySet()) {
-                            if (entry.getValue().equals(panel.tfKey.getSelectedItem())) {
-                                sc.setAssignedKey(entry.getKey());
-                            }
-                        }
-                    }
-                    sc.setAssignedUser(!panel.cbDefault.isSelected());
-                    valueChanged(null);
-                }
-                boolean state = !panel.cbDefault.isSelected();
-                panel.cbDisable.setEnabled(state);
-                state = state && !panel.cbDisable.isSelected();
-                panel.cbShift.setEnabled(state);
-                panel.cbCtrl.setEnabled(state);
-                panel.cbAlt.setEnabled(state);
-                panel.cbMeta.setEnabled(state);
-                panel.tfKey.setEnabled(state);
-            } else {
-                panel.disableAllModifierCheckboxes();
-                panel.tfKey.setEnabled(false);
-            }
-        }
-    }
-
-    // this handles the modifier groups
-    private class BxAction extends AbstractAction {
-        public void actionPerformed(java.awt.event.ActionEvent e) {
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    modifInts[bxPrim1.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT),    modifInts[ bxSec1.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT),    modifInts[ bxTer1.getSelectedIndex()]);
-
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    modifInts[bxPrim2.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU),    modifInts[ bxSec2.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU),    modifInts[ bxTer2.getSelectedIndex()]);
-
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  modifInts[bxPrim3.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY),  modifInts[ bxSec3.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY),  modifInts[ bxTer3.getSelectedIndex()]);
-
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   modifInts[bxPrim4.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER),   modifInts[ bxSec4.getSelectedIndex()]);
-            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER),   modifInts[ bxTer4.getSelectedIndex()]);
-        }
-    }
-
-    private void initbx() {
-        HashMap<Integer, Integer> groups = Main.platform.initShortcutGroups(false);
-        setBx(bxPrim1, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT);
-        setBx(bxSec1,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT);
-        setBx(bxTer1,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT);
-
-        setBx(bxPrim2, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU);
-        setBx(bxSec2,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU);
-        setBx(bxTer2,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU);
-
-        setBx(bxPrim3, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY);
-        setBx(bxSec3,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY);
-        setBx(bxTer3,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY);
-
-        setBx(bxPrim4, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER);
-        setBx(bxSec4,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER);
-        setBx(bxTer4,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER);
-    }
-    private void setBx(JComboBox bx, HashMap<Integer, Integer> groups, int key) {
-        int target = Main.pref.getInteger("shortcut.groups."+key, groups.get(key));
-        for (int i = 0; i < modifInts.length; i++) {
-            if (modifInts[i] == target) {
-                bx.setSelectedIndex(i);
-            }
-        }
-    }
-
-
-     class FilterFieldAdapter implements DocumentListener {
-        public void filter() {
-            String expr = filterField.getText().trim();
-            if (expr.length()==0) { expr=null; }
-            try {
-                final TableRowSorter<? extends TableModel> sorter =
-                    ((TableRowSorter<? extends TableModel> )shortcutTable.getRowSorter());
-                if (expr == null) {
-                    sorter.setRowFilter(null);
-                } else {
-                    // split search string on whitespace, do case-insensitive AND search
-                    ArrayList<RowFilter<Object, Object>> andFilters = new ArrayList<RowFilter<Object, Object>>();
-                    for (String word : expr.split("\\s+")) {
-                        andFilters.add(RowFilter.regexFilter("(?i)" + word));
-                    }
-                    sorter.setRowFilter(RowFilter.andFilter(andFilters));
-                }
-            }
-            catch (PatternSyntaxException ex) { }
-            catch (ClassCastException ex2) { /* eliminate warning */  }
-        }
-
-        public void changedUpdate(DocumentEvent arg0) { filter(); }
-        public void insertUpdate(DocumentEvent arg0) {  filter(); }
-        public void removeUpdate(DocumentEvent arg0) { filter(); }
-    }
-
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 4968)
@@ -32,4 +32,5 @@
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
+import org.openstreetmap.josm.gui.preferences.map.MapPreference;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -167,6 +168,6 @@
 
     public void selectMapPaintPreferenceTab() {
-        tpPreferences.setSelectedComponent(tpPreferences.map);
-        tpPreferences.mapcontent.setSelectedIndex(1);
+        tpPreferences.selectTabByPref(MapPreference.class);
+        tpPreferences.getMapPreference().mapcontent.setSelectedIndex(1);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java	(revision 4968)
@@ -14,3 +14,9 @@
      */
     boolean ok();
+    
+    /**
+     * Called to know if the preferences tab has only to be displayed in expert mode.
+     * @return true if the tab has only to be displayed in expert mode, false otherwise.
+     */
+    public boolean isExpert();
 }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 4968)
@@ -7,15 +7,14 @@
 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 javax.swing.BorderFactory;
-import javax.swing.JComponent;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
@@ -24,4 +23,6 @@
 import javax.swing.JTabbedPane;
 import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 
 import org.openstreetmap.josm.Main;
@@ -29,10 +30,22 @@
 import org.openstreetmap.josm.actions.ExpertToggleAction.ExpertModeChangeListener;
 import org.openstreetmap.josm.gui.preferences.advanced.AdvancedPreference;
+import org.openstreetmap.josm.gui.preferences.display.ColorPreference;
+import org.openstreetmap.josm.gui.preferences.display.DisplayPreference;
+import org.openstreetmap.josm.gui.preferences.display.DrawingPreference;
+import org.openstreetmap.josm.gui.preferences.display.LafPreference;
+import org.openstreetmap.josm.gui.preferences.display.LanguagePreference;
+import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
+import org.openstreetmap.josm.gui.preferences.map.BackupPreference;
+import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference;
+import org.openstreetmap.josm.gui.preferences.map.MapPreference;
+import org.openstreetmap.josm.gui.preferences.map.ProjectionPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
+import org.openstreetmap.josm.gui.preferences.shortcut.ShortcutPreference;
 import org.openstreetmap.josm.plugins.PluginDownloadTask;
 import org.openstreetmap.josm.plugins.PluginHandler;
 import org.openstreetmap.josm.plugins.PluginInformation;
 import org.openstreetmap.josm.tools.BugReportExceptionHandler;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.I18n;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -42,5 +55,5 @@
  * @author imi
  */
-public class PreferenceTabbedPane extends JTabbedPane implements MouseWheelListener, ExpertModeChangeListener {
+public class PreferenceTabbedPane extends JTabbedPane implements MouseWheelListener, ExpertModeChangeListener, ChangeListener {
     /**
      * Allows PreferenceSettings to do validation of entered values when ok was pressed.
@@ -55,26 +68,71 @@
         boolean validatePreferences();
     }
-
-    private static class TabData {
-        public String icon;
-        public JComponent tab;
-        public String toolTip;
-        public boolean isExpert;
+    
+    private static interface PreferenceTab {
+        public TabPreferenceSetting getTabPreferenceSetting();
+        public Component getComponent();
+    }
+    
+    public static class PreferencePanel extends JPanel implements PreferenceTab {
+        private final TabPreferenceSetting preferenceSetting;
+
+        private PreferencePanel(TabPreferenceSetting preferenceSetting) {
+            super(new GridBagLayout());
+            CheckParameterUtil.ensureParameterNotNull(preferenceSetting);
+            this.preferenceSetting = preferenceSetting;
+            buildPanel();
+        }
+        
+        protected void buildPanel() {
+            setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+            add(new JLabel(preferenceSetting.getTitle()), GBC.eol().insets(0,5,0,10).anchor(GBC.NORTHWEST));
+
+            JLabel descLabel = new JLabel("<html>"+preferenceSetting.getDescription()+"</html>");
+            descLabel.setFont(descLabel.getFont().deriveFont(Font.ITALIC));
+            add(descLabel, GBC.eol().insets(5,0,5,20).fill(GBC.HORIZONTAL));
+        }
+
+        @Override
+        public final TabPreferenceSetting getTabPreferenceSetting() {
+            return preferenceSetting;
+        }
+
+        @Override
+        public Component getComponent() {
+            return this;
+        }
+    }
+
+    public static class PreferenceScrollPane extends JScrollPane implements PreferenceTab {
+        private final TabPreferenceSetting preferenceSetting;
+
+        private PreferenceScrollPane(Component view, TabPreferenceSetting preferenceSetting) {
+            super(view);
+            this.preferenceSetting = preferenceSetting;
+        }
+
+        private PreferenceScrollPane(PreferencePanel preferencePanel) {
+            super(preferencePanel.getComponent());
+            this.preferenceSetting = preferencePanel.getTabPreferenceSetting();
+        }
+
+        @Override
+        public final TabPreferenceSetting getTabPreferenceSetting() {
+            return preferenceSetting;
+        }
+
+        @Override
+        public Component getComponent() {
+            return this;
+        }
     }
 
     // all created tabs
-    private final List<TabData> tabs = new ArrayList<TabData>();
+    private final List<PreferenceTab> tabs = new ArrayList<PreferenceTab>();
     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 JPanel plugins = createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
-
-    public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane();
-    public final javax.swing.JTabbedPane mapcontent = new javax.swing.JTabbedPane();
+    
+    // distinct list of tabs that have been initialized (we do not initialize tabs until they are displayed to speed up dialog startup)
+    private final List<PreferenceSetting> settingsInitialized = new ArrayList<PreferenceSetting>();
 
     List<ValidationListener> validationListeners = new ArrayList<ValidationListener>();
@@ -90,73 +148,75 @@
 
     /**
-     * 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.
+     * Construct a PreferencePanel for the preference settings. Layout is GridBagLayout
+     * and a centered title label and the description are added.
      * @return The created panel ready to add other controls.
      */
-    public JPanel createPreferenceTab(String icon, String title, String desc) {
-        return createPreferenceTab(icon, title, desc, false);
-    }
-
-    public JPanel createPreferenceTab(String icon, String title, String desc, boolean inScrollPane) {
-        return createPreferenceTab(icon, title, desc, inScrollPane, false);
-    }
-
-    /**
-     * Construct a JPanel for the preference settings. Layout is GridBagLayout
+    public PreferencePanel createPreferenceTab(TabPreferenceSetting caller) {
+        return createPreferenceTab(caller, false);
+    }
+
+    /**
+     * Construct a PreferencePanel 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, boolean isExpert) {
-        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;
+    public PreferencePanel createPreferenceTab(TabPreferenceSetting caller, boolean inScrollPane) {
+        CheckParameterUtil.ensureParameterNotNull(caller);
+        PreferencePanel p = new PreferencePanel(caller);
+
+        PreferenceTab tab = p;
         if (inScrollPane) {
-            JScrollPane sp = new JScrollPane(p);
+            PreferenceScrollPane sp = new PreferenceScrollPane(p);
             tab = sp;
         }
-        TabData data = new TabData();
-        data.icon = icon;
-        data.tab = tab;
-        data.isExpert = isExpert;
-        data.toolTip = "<html>"+desc+"</html>";
-        tabs.add(data);
+        tabs.add(tab);
         return p;
     }
 
+    private static interface TabIdentifier {
+        public boolean identify(TabPreferenceSetting tps, Object param);
+    }
+    
+    private void selectTabBy(TabIdentifier method, Object param) {
+        for (int i=0; i<getTabCount(); i++) {
+            Component c = getComponentAt(i);
+            if (c instanceof PreferenceTab) {
+                PreferenceTab tab = (PreferenceTab) c;
+                if (method.identify(tab.getTabPreferenceSetting(), param)) {
+                    setSelectedIndex(i);
+                    return;
+                }
+            }
+        }
+    }
+    
     public void selectTabByName(String name) {
-        for (TabData data : tabs) {
-            if (data.icon.equals(name)) {
-                Component c = data.tab;
-                if (c != null) {
-                    setSelectedComponent(c);
-                }
-                return;
-            }
-        }
-    }
-
-    protected PluginPreference getPluginPreference() {
-        for (PreferenceSetting setting: settings) {
-            if (setting instanceof PluginPreference)
-                return (PluginPreference) setting;
-        }
-        return null;
+        selectTabBy(new TabIdentifier(){
+            @Override
+            public boolean identify(TabPreferenceSetting tps, Object name) {
+                return tps.getIconName().equals(name);
+            }}, name);
+    }
+
+    public void selectTabByPref(Class<? extends TabPreferenceSetting> clazz) {
+        selectTabBy(new TabIdentifier(){
+            @Override
+            public boolean identify(TabPreferenceSetting tps, Object clazz) {
+                return tps.getClass().isAssignableFrom((Class<?>) clazz);
+            }}, clazz);
+    }
+    
+    public final DisplayPreference getDisplayPreference() {
+        return getSetting(DisplayPreference.class);
+    }
+    
+    public final MapPreference getMapPreference() {
+        return getSetting(MapPreference.class);
+    }
+    
+    public final PluginPreference getPluginPreference() {
+        return getSetting(PluginPreference.class);
     }
 
@@ -248,4 +308,5 @@
         super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
         super.addMouseWheelListener(this);
+        super.getModel().addChangeListener(this);
         ExpertToggleAction.addExpertModeChangeListener(this);
     }
@@ -258,21 +319,38 @@
             }
         }
-
-        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();
-                settings.addGui(this);
+                PreferenceSetting ps = it.next();
+                long start = System.currentTimeMillis();
+                ps.addGui(this);
+                System.out.println(ps.getClass()+" -> "+(System.currentTimeMillis()-start));
             } catch (SecurityException e) {
                 it.remove();
             } catch (Throwable e) {
-                /* allow to change most settings even if e.g. a plugin fails */
+                // allow to change most settings even if e.g. a plugin fails
                 BugReportExceptionHandler.handleException(e);
             }
-        }
+        }*/
         addGUITabs(false);
     }
 
+    private void addGUITabsForSetting(Icon icon, TabPreferenceSetting tps) {
+        for (PreferenceTab tab : tabs) {
+            if (tab.getTabPreferenceSetting().equals(tps)) {
+                insertGUITabsForSetting(icon, tps, getTabCount());
+            }
+        }
+    }
+    
+    private void insertGUITabsForSetting(Icon icon, TabPreferenceSetting tps, int index) {
+        int position = index;
+        for (PreferenceTab tab : tabs) {
+            if (tab.getTabPreferenceSetting().equals(tps)) {
+                insertTab(null, icon, tab.getComponent(), tps.getTooltip(), position++);
+            }
+        }
+    }
+    
     private void addGUITabs(boolean clear) {
         boolean expert = ExpertToggleAction.isExpert();
@@ -281,14 +359,34 @@
             removeAll();
         }
-        for (TabData data : tabs) {
-            if (expert || !data.isExpert) {
-                addTab(null, ImageProvider.get("preferences", data.icon), data.tab, data.toolTip);
-            }
-        }
+        // Inspect each tab setting
+        for (PreferenceSetting setting : settings) {
+            if (setting instanceof TabPreferenceSetting) {
+                TabPreferenceSetting tps = (TabPreferenceSetting) setting;
+                if (expert || !tps.isExpert()) {
+                    // Get icon
+                    ImageIcon icon = ImageProvider.get("preferences", tps.getIconName());
+                    if (settingsInitialized.contains(tps)) {
+                        // If it has been initialized, add corresponding tab(s)
+                        addGUITabsForSetting(icon, tps);
+                    } else {
+                        // If it has not been initialized, create an empty tab with only icon and tooltip
+                        addTab(null, icon, new PreferencePanel(tps), tps.getTooltip());
+                    }
+                }
+            }
+        }
+        /*for (PreferenceTab tab : tabs) {
+            TabPreferenceSetting s = tab.getTabPreferenceSetting();
+            if (expert || !s.isExpert()) {
+                addTab(null, ImageProvider.get("preferences", s.getIconName()), tab.getComponent(), "<html>"+s.getTooltip()+"</html>");
+            }
+        }*/
         try {
-            setSelectedComponent(sel);
+            if (sel != null) {
+                setSelectedComponent(sel);
+            }
         } catch (IllegalArgumentException e) {}
     }
-
+    
     @Override
     public void expertChanged(boolean isExpert) {
@@ -311,4 +409,5 @@
     static {
         // order is important!
+        settingsFactory.add(new DisplayPreference.Factory());
         settingsFactory.add(new DrawingPreference.Factory());
         settingsFactory.add(new ColorPreference.Factory());
@@ -316,4 +415,5 @@
         settingsFactory.add(new LanguagePreference.Factory());
         settingsFactory.add(new ServerAccessPreference.Factory());
+        settingsFactory.add(new MapPreference.Factory());
         settingsFactory.add(new ProjectionPreference.Factory());
         settingsFactory.add(new MapPaintPreference.Factory());
@@ -355,3 +455,43 @@
         super.setSelectedIndex(newTab);
     }
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+        int index = getSelectedIndex();
+        Component sel = getSelectedComponent();
+        if (index > -1 && sel instanceof PreferenceTab) {
+            PreferenceTab tab = (PreferenceTab) sel;
+            TabPreferenceSetting preferenceSettings = tab.getTabPreferenceSetting();
+            //System.out.println(preferenceSettings);
+            if (!settingsInitialized.contains(preferenceSettings)) {
+                try {
+                    //System.out.println("adding GUI for "+preferenceSettings);
+                    getModel().removeChangeListener(this);
+                    preferenceSettings.addGui(this);
+                    // Add GUI for sub preferences
+                    for (PreferenceSetting setting : settings) {
+                        if (setting instanceof SubPreferenceSetting) {
+                            SubPreferenceSetting sps = (SubPreferenceSetting) setting;
+                            if (sps.getTabPreferenceSetting(this) == preferenceSettings) {
+                                //System.out.println("adding GUI for "+sps);
+                                sps.addGui(this);
+                            }
+                        }
+                    }
+                    Icon icon = getIconAt(index);
+                    remove(index);
+                    insertGUITabsForSetting(icon, preferenceSettings, index);
+                    setSelectedIndex(index);
+                } catch (SecurityException ex) {
+                    ex.printStackTrace();
+                } catch (Throwable ex) {
+                    // allow to change most settings even if e.g. a plugin fails
+                    BugReportExceptionHandler.handleException(ex);
+                } finally {
+                    settingsInitialized.add(preferenceSettings);
+                    getModel().addChangeListener(this);
+                }
+            }
+        }
+    }
 }
Index: unk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,290 +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 java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.ArrayList;
-import java.util.Collection;
-
-import javax.swing.BorderFactory;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
-import org.openstreetmap.josm.data.preferences.CollectionProperty;
-import org.openstreetmap.josm.data.preferences.ParametrizedCollectionProperty;
-import org.openstreetmap.josm.data.preferences.StringProperty;
-import org.openstreetmap.josm.data.projection.Mercator;
-import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
-import org.openstreetmap.josm.data.projection.Projections;
-import org.openstreetmap.josm.gui.NavigatableComponent;
-import org.openstreetmap.josm.plugins.PluginHandler;
-import org.openstreetmap.josm.tools.GBC;
-
-public class ProjectionPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new ProjectionPreference();
-        }
-    }
-
-    private static final StringProperty PROP_PROJECTION = new StringProperty("projection", Mercator.class.getName());
-    private static final StringProperty PROP_COORDINATES = new StringProperty("coordinates", null);
-    private static final CollectionProperty PROP_SUB_PROJECTION = new CollectionProperty("projection.sub", null);
-    private static final ParametrizedCollectionProperty PROP_PROJECTION_SUBPROJECTION = new ParametrizedCollectionProperty(null) {
-        @Override
-        protected String getKey(String... params) {
-            String name = params[0];
-            String sname = name.substring(name.lastIndexOf(".")+1);
-            return "projection.sub."+sname;
-        }
-    };
-    public static final StringProperty PROP_SYSTEM_OF_MEASUREMENT = new StringProperty("system_of_measurement", "Metric");
-    private static final String[] unitsValues = (new ArrayList<String>(NavigatableComponent.SYSTEMS_OF_MEASUREMENT.keySet())).toArray(new String[0]);
-    private static final String[] unitsValuesTr = new String[unitsValues.length];
-    static {
-        for (int i=0; i<unitsValues.length; ++i) {
-            unitsValuesTr[i] = tr(unitsValues[i]);
-        }
-    }
-
-    /**
-     * Combobox with all projections available
-     */
-    private JComboBox projectionCombo = new JComboBox(Projections.getProjections().toArray());
-
-    /**
-     * Combobox with all coordinate display possibilities
-     */
-    private JComboBox coordinatesCombo = new JComboBox(CoordinateFormat.values());
-
-    private JComboBox unitsCombo = new JComboBox(unitsValuesTr);
-
-    /**
-     * This variable holds the JPanel with the projection's preferences. If the
-     * selected projection does not implement this, it will be set to an empty
-     * Panel.
-     */
-    private JPanel projSubPrefPanel;
-    private JPanel projSubPrefPanelWrapper = new JPanel(new GridBagLayout());
-
-    private JLabel projectionCode = new JLabel();
-    private JLabel bounds = new JLabel();
-
-    /**
-     * This is the panel holding all projection preferences
-     */
-    private JPanel projPanel = new JPanel(new GridBagLayout());
-
-    /**
-     * The GridBagConstraints for the Panel containing the ProjectionSubPrefs.
-     * This is required twice in the code, creating it here keeps both occurrences
-     * in sync
-     */
-    static private GBC projSubPrefPanelGBC = GBC.std().fill(GBC.BOTH).weight(1.0, 1.0);
-
-    public void addGui(PreferenceTabbedPane gui) {
-        setupProjectionCombo();
-
-        for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
-            if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(PROP_COORDINATES.get())) {
-                coordinatesCombo.setSelectedIndex(i);
-                break;
-            }
-        }
-
-        for (int i = 0; i < unitsValues.length; ++i) {
-            if (unitsValues[i].equals(PROP_SYSTEM_OF_MEASUREMENT.get())) {
-                unitsCombo.setSelectedIndex(i);
-                break;
-            }
-        }
-
-        projPanel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        projPanel.setLayout(new GridBagLayout());
-        projPanel.add(new JLabel(tr("Projection method")), GBC.std().insets(5,5,0,5));
-        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        projPanel.add(projectionCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-        projPanel.add(new JLabel(tr("Projection code")), GBC.std().insets(25,5,0,5));
-        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        projPanel.add(projectionCode, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-        projPanel.add(new JLabel(tr("Bounds")), GBC.std().insets(25,5,0,5));
-        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        projPanel.add(bounds, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-        projSubPrefPanelWrapper.add(projSubPrefPanel, projSubPrefPanelGBC);
-        projPanel.add(projSubPrefPanelWrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(20,5,5,5));
-
-        projPanel.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(0,5,0,10));
-        projPanel.add(new JLabel(tr("Display coordinates as")), GBC.std().insets(5,5,0,5));
-        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        projPanel.add(coordinatesCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-        projPanel.add(new JLabel(tr("System of measurement")), GBC.std().insets(5,5,0,5));
-        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-        projPanel.add(unitsCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-        projPanel.add(GBC.glue(1,1), GBC.std().fill(GBC.HORIZONTAL).weight(1.0, 1.0));
-
-        JScrollPane scrollpane = new JScrollPane(projPanel);
-        gui.mapcontent.addTab(tr("Map Projection"), scrollpane);
-
-        updateMeta(Main.getProjection());
-    }
-
-    private void updateMeta(Projection proj)
-    {
-        projectionCode.setText(proj.toCode());
-        Bounds b = proj.getWorldBoundsLatLon();
-        CoordinateFormat cf = CoordinateFormat.getDefaultFormat();
-        bounds.setText(b.getMin().latToString(cf)+"; "+b.getMin().lonToString(cf)+" : "+b.getMax().latToString(cf)+"; "+b.getMax().lonToString(cf));
-    }
-
-    public boolean ok() {
-        Projection proj = (Projection) projectionCombo.getSelectedItem();
-
-        String projname = proj.getClass().getName();
-        Collection<String> prefs = null;
-        if(proj instanceof ProjectionSubPrefs) {
-            prefs = ((ProjectionSubPrefs) proj).getPreferences(projSubPrefPanel);
-        }
-
-        PROP_PROJECTION.put(projname);
-        setProjection(projname, prefs);
-
-        if(PROP_COORDINATES.put(((CoordinateFormat)coordinatesCombo.getSelectedItem()).name())) {
-            CoordinateFormat.setCoordinateFormat((CoordinateFormat)coordinatesCombo.getSelectedItem());
-        }
-
-        int i = unitsCombo.getSelectedIndex();
-        PROP_SYSTEM_OF_MEASUREMENT.put(unitsValues[i]);
-
-        return false;
-    }
-
-    static public void setProjection()
-    {
-        setProjection(PROP_PROJECTION.get(), PROP_SUB_PROJECTION.get());
-    }
-
-    static public void setProjection(String name, Collection<String> coll)
-    {
-        Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
-
-        Projection proj = null;
-        for (ClassLoader cl : PluginHandler.getResourceClassLoaders()) {
-            try {
-                proj = (Projection) Class.forName(name, true, cl).newInstance();
-            } catch (final Exception e) {
-            }
-            if (proj != null) {
-                break;
-            }
-        }
-        if (proj == null) {
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    tr("The projection {0} could not be activated. Using Mercator", name),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-            coll = null;
-            proj = new Mercator();
-            name = proj.getClass().getName();
-            PROP_PROJECTION.put(name);
-        }
-        PROP_SUB_PROJECTION.put(coll);
-        PROP_PROJECTION_SUBPROJECTION.put(coll, name);
-        if (proj instanceof ProjectionSubPrefs) {
-            ((ProjectionSubPrefs) proj).setPreferences(coll);
-        }
-        Projection oldProj = Main.getProjection();
-        Main.setProjection(proj);
-        if (b != null && (!proj.getClass().getName().equals(oldProj.getClass().getName()) || proj.hashCode() != oldProj.hashCode()))
-        {
-            Main.map.mapView.zoomTo(b);
-            /* TODO - remove layers with fixed projection */
-        }
-    }
-
-    private class SBPanel extends JPanel implements ActionListener
-    {
-        private ProjectionSubPrefs p;
-        public SBPanel(ProjectionSubPrefs pr)
-        {
-            super();
-            p = pr;
-        }
-
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            p.setPreferences(p.getPreferences(this));
-            updateMeta(p);
-        }
-    }
-
-    /**
-     * Handles all the work related to update the projection-specific
-     * preferences
-     * @param proj
-     */
-    private void selectedProjectionChanged(Projection proj) {
-        if(!(proj instanceof ProjectionSubPrefs)) {
-            projSubPrefPanel = new JPanel();
-        } else {
-            ProjectionSubPrefs projPref = (ProjectionSubPrefs) proj;
-            projSubPrefPanel = new SBPanel(projPref);
-            projPref.setupPreferencePanel(projSubPrefPanel, (SBPanel)projSubPrefPanel);
-        }
-
-        // Don't try to update if we're still starting up
-        int size = projPanel.getComponentCount();
-        if(size < 1)
-            return;
-
-        // Replace old panel with new one
-        projSubPrefPanelWrapper.removeAll();
-        projSubPrefPanelWrapper.add(projSubPrefPanel, projSubPrefPanelGBC);
-        projPanel.revalidate();
-        projSubPrefPanel.repaint();
-        updateMeta(proj);
-    }
-
-    /**
-     * Sets up projection combobox with default values and action listener
-     */
-    private void setupProjectionCombo() {
-        boolean found = false;
-        for (int i = 0; i < projectionCombo.getItemCount(); ++i) {
-            Projection proj = (Projection)projectionCombo.getItemAt(i);
-            String name = proj.getClass().getName();
-            if(proj instanceof ProjectionSubPrefs) {
-                ((ProjectionSubPrefs) proj).setPreferences(PROP_PROJECTION_SUBPROJECTION.get(name));
-            }
-            if (name.equals(PROP_PROJECTION.get())) {
-                projectionCombo.setSelectedIndex(i);
-                selectedProjectionChanged(proj);
-                found = true;
-                break;
-            }
-        }
-        if (!found)
-            throw new RuntimeException("Couldn't find the current projection in the list of available projections!");
-
-        projectionCombo.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                JComboBox cb = (JComboBox)e.getSource();
-                Projection proj = (Projection)cb.getSelectedItem();
-                selectedProjectionChanged(proj);
-            }
-        });
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/RemoteControlPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/RemoteControlPreference.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/RemoteControlPreference.java	(revision 4968)
@@ -34,5 +34,5 @@
  * @author Frederik Ramm
  */
-public class RemoteControlPreference implements PreferenceSetting
+public class RemoteControlPreference extends DefaultTabPreferenceSetting
 {
     public static class Factory implements PreferenceSettingFactory {
@@ -41,4 +41,8 @@
             return new RemoteControlPreference();
         }
+    }
+    
+    private RemoteControlPreference() {
+        super("remotecontrol", tr("Remote Control"), tr("Settings for the remote control feature."));
     }
 
@@ -57,5 +61,5 @@
     public void addGui(final PreferenceTabbedPane gui) {
 
-        JPanel remote = gui.createPreferenceTab("remotecontrol", tr("Remote Control"), tr("Settings for the remote control feature."));
+        JPanel remote = gui.createPreferenceTab(this);
 
         remote.add(enableRemoteControl = new JCheckBox(tr("Enable remote control"), RemoteControl.PROP_REMOTECONTROL_ENABLED.get()), GBC.eol());
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java	(revision 4968)
@@ -18,5 +18,5 @@
 import org.openstreetmap.josm.gui.preferences.server.ProxyPreferencesPanel;
 import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
-public class ServerAccessPreference implements PreferenceSetting {
+public class ServerAccessPreference extends DefaultTabPreferenceSetting {
 
     public static class Factory implements PreferenceSettingFactory {
@@ -24,4 +24,8 @@
             return new ServerAccessPreference();
         }
+    }
+    
+    private ServerAccessPreference() {
+        super("connection", tr("Connection Settings"), tr("Connection Settings for the OSM server."));
     }
 
@@ -109,5 +113,5 @@
         gc.weighty = 1.0;
         gc.anchor = GridBagConstraints.NORTHWEST;
-        gui.connection.add(buildContentPanel(), gc);
+        gui.createPreferenceTab(this).add(buildContentPanel(), gc);
 
         initFromPreferences();
Index: unk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,76 +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 java.util.List;
-
-import javax.swing.JPanel;
-import javax.swing.table.AbstractTableModel;
-
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.Shortcut;
-
-public class ShortcutPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new ShortcutPreference();
-        }
-    }
-
-    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
-        // icon designer: Paolino, http://www.paolinoland.it/
-        // icon original filename: keyboard.png
-        // icon original size: 128x128
-        // modifications: icon was cropped, then resized
-        JPanel p = gui.createPreferenceTab("shortcuts", tr("Shortcut Preferences"),
-                tr("Changing keyboard shortcuts manually."), false);
-
-        PrefJPanel prefpanel = new PrefJPanel(new scListModel());
-        p.add(prefpanel, GBC.eol().fill(GBC.BOTH));
-
-    }
-
-    public boolean ok() {
-        return Shortcut.savePrefs();
-    }
-
-    // Maybe move this to prefPanel? There's no need for it to be here.
-    private static class scListModel extends AbstractTableModel {
-        private String[] columnNames = new String[]{tr("Action"), tr("Shortcut")};
-        private List<Shortcut> data;
-
-        public scListModel() {
-            data = Shortcut.listAll();
-        }
-        public int getColumnCount() {
-            return columnNames.length;
-        }
-        public int getRowCount() {
-            return data.size();
-        }
-        @Override
-        public String getColumnName(int col) {
-            return columnNames[col];
-        }
-        public Object getValueAt(int row, int col) {
-            Shortcut sc = data.get(row);
-            if (col == 0)
-                return sc.getLongText();
-            else if (col == 1)
-                return sc.getKeyText();
-            else
-                // This is a kind of hack that allows the actions on the editing controls
-                // to access the underlying shortcut object without introducing another
-                // method. I opted to stay within the interface.
-                return sc;
-        }
-        @Override
-        public boolean isCellEditable(int row, int col) {
-            return false;
-        }
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 4968)
@@ -32,5 +32,4 @@
 import java.util.EventObject;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -372,5 +371,5 @@
      * Identifiers for strings that need to be provided.
      */
-    protected enum I18nString { AVAILABLE_SOURCES, ACTIVE_SOURCES, NEW_SOURCE_ENTRY_TOOLTIP, NEW_SOURCE_ENTRY,
+    public enum I18nString { AVAILABLE_SOURCES, ACTIVE_SOURCES, NEW_SOURCE_ENTRY_TOOLTIP, NEW_SOURCE_ENTRY,
         REMOVE_SOURCE_TOOLTIP, EDIT_SOURCE_TOOLTIP, ACTIVATE_TOOLTIP, RELOAD_ALL_AVAILABLE,
         LOADING_SOURCES_FROM, FAILED_TO_LOAD_SOURCES_FROM, FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC,
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/SubPreferenceSetting.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/SubPreferenceSetting.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/SubPreferenceSetting.java	(revision 4968)
@@ -0,0 +1,10 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences;
+
+public interface SubPreferenceSetting extends PreferenceSetting {
+    
+    /**
+     * Returns the preference setting (displayed in the specified preferences tab pane) that contains this preference setting.
+     */
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui);
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/TabPreferenceSetting.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/TabPreferenceSetting.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/TabPreferenceSetting.java	(revision 4968)
@@ -0,0 +1,30 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences;
+
+public interface TabPreferenceSetting extends PreferenceSetting {
+    
+    /**
+     * Called during preferences dialog initialization to display the preferences tab with the returned icon.
+     * @return The icon name in the preferences folder.
+     */
+    public String getIconName();
+
+    /**
+     * Called during preferences tab initialization to display its title.
+     * @return The title of this preferences tab.
+     */
+    String getTitle();
+    
+    /**
+     * Called during preferences dialog initialization to display the preferences tab with the returned tooltip.
+     * @return The tooltip of this preferences tab.
+     */
+    public String getTooltip();
+
+    /**
+     * Called during preferences tab initialization to display a description in one sentence for this tab. 
+     * Will be displayedin italic under the title.
+     * @return The description of this preferences tab.
+     */
+    public String getDescription();
+}
Index: unk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 4967)
+++ 	(revision )
@@ -1,329 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.swing.BorderFactory;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JSeparator;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
-import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
-import org.openstreetmap.josm.gui.tagging.TaggingPreset;
-import org.openstreetmap.josm.gui.tagging.TaggingPresetMenu;
-import org.openstreetmap.josm.gui.tagging.TaggingPresetSeparator;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
-import org.openstreetmap.josm.tools.GBC;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-
-public class TaggingPresetPreference implements PreferenceSetting {
-
-    public static class Factory implements PreferenceSettingFactory {
-        public PreferenceSetting createPreferenceSetting() {
-            return new TaggingPresetPreference();
-        }
-    }
-
-    private static final List<SourceProvider> presetSourceProviders = new ArrayList<SourceProvider>();
-    public static Collection<TaggingPreset> taggingPresets;
-    private SourceEditor sources;
-    private JCheckBox sortMenu;
-
-    public static final boolean registerSourceProvider(SourceProvider provider) {
-        if (provider != null)
-            return presetSourceProviders.add(provider);
-        return false;
-    }
-
-    private ValidationListener validationListener = new ValidationListener() {
-        public boolean validatePreferences() {
-            if (sources.hasActiveSourcesChanged()) {
-                List<Integer> sourcesToRemove = new ArrayList<Integer>();
-                int i = -1;
-                SOURCES:
-                    for (SourceEntry source: sources.getActiveSources()) {
-                        i++;
-                        boolean canLoad = false;
-                        try {
-                            TaggingPreset.readAll(source.url, false);
-                            canLoad = true;
-                        } catch (IOException e) {
-                            System.err.println(tr("Warning: Could not read tagging preset source: {0}", source));
-                            ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Error"),
-                                    new String[] {tr("Yes"), tr("No"), tr("Cancel")});
-                            ed.setContent(tr("Could not read tagging preset source: {0}\nDo you want to keep it?", source));
-                            switch (ed.showDialog().getValue()) {
-                            case 1:
-                                continue SOURCES;
-                            case 2:
-                                sourcesToRemove.add(i);
-                                continue SOURCES;
-                            default:
-                                return false;
-                            }
-                        } catch (SAXException e) {
-                            // We will handle this in step with validation
-                        }
-
-                        String errorMessage = null;
-
-                        try {
-                            TaggingPreset.readAll(source.url, true);
-                        } catch (IOException e) {
-                            // Should not happen, but at least show message
-                            String msg = tr("Could not read tagging preset source {0}", source);
-                            System.err.println(msg);
-                            JOptionPane.showMessageDialog(Main.parent, msg);
-                            return false;
-                        } catch (SAXParseException e) {
-                            if (canLoad) {
-                                errorMessage = tr("<html>Tagging preset source {0} can be loaded but it contains errors. " +
-                                        "Do you really want to use it?<br><br><table width=600>Error is: [{1}:{2}] {3}</table></html>",
-                                        source, e.getLineNumber(), e.getColumnNumber(), e.getMessage());
-                            } else {
-                                errorMessage = tr("<html>Unable to parse tagging preset source: {0}. " +
-                                        "Do you really want to use it?<br><br><table width=400>Error is: [{1}:{2}] {3}</table></html>",
-                                        source, e.getLineNumber(), e.getColumnNumber(), e.getMessage());
-                            }
-                        } catch (SAXException e) {
-                            if (canLoad) {
-                                errorMessage = tr("<html>Tagging preset source {0} can be loaded but it contains errors. " +
-                                        "Do you really want to use it?<br><br><table width=600>Error is: {1}</table></html>",
-                                        source,  e.getMessage());
-                            } else {
-                                errorMessage = tr("<html>Unable to parse tagging preset source: {0}. " +
-                                        "Do you really want to use it?<br><br><table width=600>Error is: {1}</table></html>",
-                                        source, e.getMessage());
-                            }
-
-                        }
-
-                        if (errorMessage != null) {
-                            System.err.println("Error: "+errorMessage);
-                            int result = JOptionPane.showConfirmDialog(Main.parent, new JLabel(errorMessage), tr("Error"),
-                                    JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE);
-
-                            switch (result) {
-                            case JOptionPane.YES_OPTION:
-                                continue SOURCES;
-                            case JOptionPane.NO_OPTION:
-                                sourcesToRemove.add(i);
-                                continue SOURCES;
-                            default:
-                                return false;
-                            }
-                        }
-                    }
-                sources.removeSources(sourcesToRemove);
-                return true;
-            }  else
-                return true;
-        }
-    };
-
-    public void addGui(final PreferenceTabbedPane gui) {
-        sortMenu = new JCheckBox(tr("Sort presets menu"),
-                Main.pref.getBoolean("taggingpreset.sortmenu", false));
-
-        final JPanel panel = new JPanel(new GridBagLayout());
-        panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        panel.add(sortMenu, GBC.eol().insets(5,5,5,0));
-        sources = new TaggingPresetSourceEditor();
-        panel.add(sources, GBC.eol().fill(GBC.BOTH));
-        gui.mapcontent.addTab(tr("Tagging Presets"), panel);
-
-        // this defers loading of tagging preset sources to the first time the tab
-        // with the tagging presets is selected by the user
-        //
-        gui.mapcontent.addChangeListener(
-                new ChangeListener() {
-                    public void stateChanged(ChangeEvent e) {
-                        if (gui.mapcontent.getSelectedComponent() == panel) {
-                            sources.initiallyLoadAvailableSources();
-                        }
-                    }
-                }
-                );
-        gui.addValidationListener(validationListener);
-    }
-
-    static class TaggingPresetSourceEditor extends SourceEditor {
-
-        final private String iconpref = "taggingpreset.icon.sources";
-
-        public TaggingPresetSourceEditor() {
-            super(false, "http://josm.openstreetmap.de/presets", presetSourceProviders);
-        }
-
-        @Override
-        public Collection<? extends SourceEntry> getInitialSourcesList() {
-            return PresetPrefHelper.INSTANCE.get();
-        }
-
-        @Override
-        public boolean finish() {
-            List<SourceEntry> activeStyles = activeSourcesModel.getSources();
-
-            boolean changed = PresetPrefHelper.INSTANCE.put(activeStyles);
-
-            if (tblIconPaths != null) {
-                List<String> iconPaths = iconPathsModel.getIconPaths();
-
-                if (!iconPaths.isEmpty()) {
-                    if (Main.pref.putCollection(iconpref, iconPaths)) {
-                        changed = true;
-                    }
-                } else if (Main.pref.putCollection(iconpref, null)) {
-                    changed = true;
-                }
-            }
-            return changed;
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            return PresetPrefHelper.INSTANCE.getDefault();
-        }
-
-        @Override
-        public Collection<String> getInitialIconPathsList() {
-            return Main.pref.getCollection(iconpref, null);
-        }
-
-        @Override
-        public String getStr(I18nString ident) {
-            switch (ident) {
-            case AVAILABLE_SOURCES:
-                return tr("Available presets:");
-            case ACTIVE_SOURCES:
-                return tr("Active presets:");
-            case NEW_SOURCE_ENTRY_TOOLTIP:
-                return tr("Add a new preset by entering filename or URL");
-            case NEW_SOURCE_ENTRY:
-                return tr("New preset entry:");
-            case REMOVE_SOURCE_TOOLTIP:
-                return tr("Remove the selected presets from the list of active presets");
-            case EDIT_SOURCE_TOOLTIP:
-                return tr("Edit the filename or URL for the selected active preset");
-            case ACTIVATE_TOOLTIP:
-                return tr("Add the selected available presets to the list of active presets");
-            case RELOAD_ALL_AVAILABLE:
-                return marktr("Reloads the list of available presets from ''{0}''");
-            case LOADING_SOURCES_FROM:
-                return marktr("Loading preset sources from ''{0}''");
-            case FAILED_TO_LOAD_SOURCES_FROM:
-                return marktr("<html>Failed to load the list of preset sources from<br>"
-                        + "''{0}''.<br>"
-                        + "<br>"
-                        + "Details (untranslated):<br>{1}</html>");
-            case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC:
-                return "/Preferences/Presets#FailedToLoadPresetSources";
-            case ILLEGAL_FORMAT_OF_ENTRY:
-                return marktr("Warning: illegal format of entry in preset list ''{0}''. Got ''{1}''");
-            default: throw new AssertionError();
-            }
-        }
-    }
-
-    public boolean ok() {
-        boolean restart = Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null);
-        restart |= sources.finish();
-
-        return restart;
-    }
-
-    /**
-     * Initialize the tagging presets (load and may display error)
-     */
-    public static void initialize() {
-        taggingPresets = TaggingPreset.readFromPreferences(false);
-        for (TaggingPreset tp: taggingPresets) {
-            if (!(tp instanceof TaggingPresetSeparator)) {
-                Main.toolbar.register(tp);
-            }
-        }
-        if (taggingPresets.isEmpty()) {
-            Main.main.menu.presetsMenu.setVisible(false);
-        }
-        else
-        {
-            AutoCompletionManager.cachePresets(taggingPresets);
-            HashMap<TaggingPresetMenu,JMenu> submenus = new HashMap<TaggingPresetMenu,JMenu>();
-            for (final TaggingPreset p : taggingPresets)
-            {
-                JMenu m = p.group != null ? submenus.get(p.group) : Main.main.menu.presetsMenu;
-                if (p instanceof TaggingPresetSeparator) {
-                    m.add(new JSeparator());
-                } else if (p instanceof TaggingPresetMenu)
-                {
-                    JMenu submenu = new JMenu(p);
-                    submenu.setText(p.getLocaleName());
-                    ((TaggingPresetMenu)p).menu = submenu;
-                    submenus.put((TaggingPresetMenu)p, submenu);
-                    m.add(submenu);
-                }
-                else
-                {
-                    JMenuItem mi = new JMenuItem(p);
-                    mi.setText(p.getLocaleName());
-                    m.add(mi);
-                }
-            }
-        }
-        if(Main.pref.getBoolean("taggingpreset.sortmenu")) {
-            TaggingPresetMenu.sortMenu(Main.main.menu.presetsMenu);
-        }
-    }
-
-    public static class PresetPrefHelper extends SourceEditor.SourcePrefHelper {
-
-        public final static PresetPrefHelper INSTANCE = new PresetPrefHelper();
-
-        public PresetPrefHelper() {
-            super("taggingpreset.sources-list");
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            ExtendedSourceEntry i = new ExtendedSourceEntry("defaultpresets.xml", "resource://data/defaultpresets.xml");
-            i.title = tr("Internal Preset");
-            i.description = tr("The default preset for JOSM");
-            return Collections.singletonList(i);
-        }
-
-        @Override
-        public Collection<String> serialize(SourceEntry entry) {
-            return Arrays.asList(new String[] {entry.url, entry.title == null ? "" : entry.title});
-        }
-
-        @Override
-        public SourceEntry deserialize(List<String> entryStr) {
-            if (entryStr.size() < 2)
-                return null;
-            String url = entryStr.get(0);
-            String shortdescription = entryStr.get(1);
-            return new SourceEntry(url, null, shortdescription, true);
-        }
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 4968)
@@ -410,5 +410,5 @@
     }
 
-    public class Settings implements PreferenceSetting {
+    public class Settings extends DefaultTabPreferenceSetting {
 
         private final class Move implements ActionListener {
@@ -497,4 +497,5 @@
 
         public Settings(DefaultMutableTreeNode rootActionsNode) {
+            super("toolbar", tr("Toolbar customization"), tr("Customize the elements on the toolbar."));
             actionsTreeModel = new DefaultTreeModel(rootActionsNode);
             actionsTree = new JTree(actionsTreeModel);
@@ -766,6 +767,5 @@
             actionParametersPanel.setVisible(false);
 
-            JPanel panel = gui.createPreferenceTab("toolbar", tr("Toolbar customization"),
-                    tr("Customize the elements on the toolbar."), false);
+            JPanel panel = gui.createPreferenceTab(this);
             panel.add(p, GBC.eol().fill(GBC.BOTH));
             panel.add(actionParametersPanel, GBC.eol().fill(GBC.HORIZONTAL));
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/ValidatorPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/ValidatorPreference.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/ValidatorPreference.java	(revision 4968)
@@ -25,5 +25,5 @@
  * @author frsantos
  */
-public class ValidatorPreference implements PreferenceSetting {
+public class ValidatorPreference extends DefaultTabPreferenceSetting {
 
     public static class Factory implements PreferenceSettingFactory {
@@ -32,4 +32,9 @@
             return new ValidatorPreference();
         }
+    }
+    
+    private ValidatorPreference() {
+        super("validator", tr("Data validator"), 
+                tr("An OSM data validator that checks for common errors made by users and editor programs."));
     }
 
@@ -112,6 +117,5 @@
         testPane.setBorder(null);
 
-        String description = tr("An OSM data validator that checks for common errors made by users and editor programs.");
-        JPanel tab = gui.createPreferenceTab("validator", tr("Data validator"), description);
+        JPanel tab = gui.createPreferenceTab(this);
         tab.add(testPane, GBC.eol().fill(GBC.BOTH));
         tab.add(GBC.glue(0,10), a);
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java	(revision 4968)
@@ -0,0 +1,291 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.display;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.Vector;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JColorChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableCellRenderer;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
+import org.openstreetmap.josm.data.validation.Severity;
+import org.openstreetmap.josm.gui.MapScaler;
+import org.openstreetmap.josm.gui.conflict.ConflictColors;
+import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.ImageryLayer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.tools.ColorHelper;
+import org.openstreetmap.josm.tools.GBC;
+
+public class ColorPreference implements SubPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new ColorPreference();
+        }
+    }
+
+    private DefaultTableModel tableModel;
+    private JTable colors;
+    private ArrayList<String> del = new ArrayList<String>();
+
+    JButton colorEdit;
+    JButton defaultSet;
+    JButton remove;
+
+    /**
+     * Set the colors to be shown in the preference table. This method creates a table model if
+     * none exists and overwrites all existing values.
+     * @param colorMap the map holding the colors
+     * (key = color id (without prefixes, so only <code>background</code>; not <code>color.background</code>),
+     * value = html representation of the color.
+     */
+    public void setColorModel(Map<String, String> colorMap) {
+        if(tableModel == null) {
+            tableModel = new DefaultTableModel();
+            tableModel.addColumn(tr("Name"));
+            tableModel.addColumn(tr("Color"));
+        }
+
+        // clear old model:
+        while(tableModel.getRowCount() > 0) {
+            tableModel.removeRow(0);
+        }
+        // fill model with colors:
+        Map<String, String> colorKeyList = new TreeMap<String, String>();
+        Map<String, String> colorKeyList_mappaint = new TreeMap<String, String>();
+        Map<String, String> colorKeyList_layer = new TreeMap<String, String>();
+        for(String key : colorMap.keySet()) {
+            if(key.startsWith("layer ")) {
+                colorKeyList_layer.put(getName(key), key);
+            } else if(key.startsWith("mappaint.")) {
+                /* use getName(key)+key, as getName() may be ambiguous */
+                colorKeyList_mappaint.put(getName(key)+key, key);
+            } else {
+                colorKeyList.put(getName(key), key);
+            }
+        }
+        for (Entry<String, String> k : colorKeyList.entrySet()) {
+            Vector<Object> row = new Vector<Object>(2);
+            row.add(k.getValue());
+            row.add(ColorHelper.html2color(colorMap.get(k.getValue())));
+            tableModel.addRow(row);
+        }
+        for (Entry<String, String> k : colorKeyList_mappaint.entrySet()) {
+            Vector<Object> row = new Vector<Object>(2);
+            row.add(k.getValue());
+            row.add(ColorHelper.html2color(colorMap.get(k.getValue())));
+            tableModel.addRow(row);
+        }
+        for (Entry<String, String> k : colorKeyList_layer.entrySet()) {
+            Vector<Object> row = new Vector<Object>(2);
+            row.add(k.getValue());
+            row.add(ColorHelper.html2color(colorMap.get(k.getValue())));
+            tableModel.addRow(row);
+        }
+        if(this.colors != null) {
+            this.colors.repaint();
+        }
+    }
+
+    /**
+     * Returns a map with the colors in the table (key = color name without prefix, value = html color code).
+     * @return a map holding the colors.
+     */
+    public Map<String, String> getColorModel() {
+        String key;
+        String value;
+        Map<String, String> colorMap = new HashMap<String, String>();
+        for(int row = 0; row < tableModel.getRowCount(); ++row) {
+            key = (String)tableModel.getValueAt(row, 0);
+            value = ColorHelper.color2html((Color)tableModel.getValueAt(row, 1));
+            colorMap.put(key, value);
+        }
+        return colorMap;
+    }
+
+    private String getName(String o)
+    {
+        return Main.pref.getColorName(o);
+    }
+
+    public void addGui(final PreferenceTabbedPane gui) {
+        fixColorPrefixes();
+        setColorModel(Main.pref.getAllColors());
+
+        colorEdit = new JButton(tr("Choose"));
+        colorEdit.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                int sel = colors.getSelectedRow();
+                JColorChooser chooser = new JColorChooser((Color)colors.getValueAt(sel, 1));
+                int answer = JOptionPane.showConfirmDialog(
+                        gui, chooser,
+                        tr("Choose a color for {0}", getName((String)colors.getValueAt(sel, 0))),
+                        JOptionPane.OK_CANCEL_OPTION,
+                        JOptionPane.PLAIN_MESSAGE);
+                if (answer == JOptionPane.OK_OPTION) {
+                    colors.setValueAt(chooser.getColor(), sel, 1);
+                }
+            }
+        });
+        defaultSet = new JButton(tr("Set to default"));
+        defaultSet.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                int sel = colors.getSelectedRow();
+                String name = (String)colors.getValueAt(sel, 0);
+                Color c = Main.pref.getDefaultColor(name);
+                if (c != null) {
+                    colors.setValueAt(c, sel, 1);
+                }
+            }
+        });
+        JButton defaultAll = new JButton(tr("Set all to default"));
+        defaultAll.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                for(int i = 0; i < colors.getRowCount(); ++i)
+                {
+                    String name = (String)colors.getValueAt(i, 0);
+                    Color c = Main.pref.getDefaultColor(name);
+                    if (c != null) {
+                        colors.setValueAt(c, i, 1);
+                    }
+                }
+            }
+        });
+        remove = new JButton(tr("Remove"));
+        remove.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                int sel = colors.getSelectedRow();
+                del.add((String)colors.getValueAt(sel, 0));
+                tableModel.removeRow(sel);
+            }
+        });
+        remove.setEnabled(false);
+        colorEdit.setEnabled(false);
+        defaultSet.setEnabled(false);
+
+        colors = new JTable(tableModel) {
+            @Override public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+            @Override public void valueChanged(ListSelectionEvent e) {
+                super.valueChanged(e);
+                int sel = getSelectedRow();
+                remove.setEnabled(sel >= 0 && isRemoveColor(sel));
+                colorEdit.setEnabled(sel >= 0);
+                defaultSet.setEnabled(sel >= 0);
+            }
+        };
+        colors.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        final TableCellRenderer oldColorsRenderer = colors.getDefaultRenderer(Object.class);
+        colors.setDefaultRenderer(Object.class, new TableCellRenderer(){
+            public Component getTableCellRendererComponent(JTable t, Object o, boolean selected, boolean focus, int row, int column) {
+                if (o == null)
+                    return new JLabel();
+                if (column == 1) {
+                    JLabel l = new JLabel(ColorHelper.color2html((Color)o));
+                    l.setBackground((Color)o);
+                    l.setOpaque(true);
+                    return l;
+                }
+                return oldColorsRenderer.getTableCellRendererComponent(t,getName(o.toString()),selected,focus,row,column);
+            }
+        });
+        colors.getColumnModel().getColumn(1).setWidth(100);
+        colors.setToolTipText(tr("Colors used by different objects in JOSM."));
+        colors.setPreferredScrollableViewportSize(new Dimension(100,112));
+
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        JScrollPane scrollpane = new JScrollPane(colors);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        panel.add(scrollpane, GBC.eol().fill(GBC.BOTH));
+        JPanel buttonPanel = new JPanel(new GridBagLayout());
+        panel.add(buttonPanel, GBC.eol().insets(5,0,5,5).fill(GBC.HORIZONTAL));
+        buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
+        buttonPanel.add(colorEdit, GBC.std().insets(0,5,0,0));
+        buttonPanel.add(defaultSet, GBC.std().insets(5,5,5,0));
+        buttonPanel.add(defaultAll, GBC.std().insets(0,5,0,0));
+        buttonPanel.add(remove, GBC.std().insets(0,5,0,0));
+        gui.getDisplayPreference().displaycontent.addTab(tr("Colors"), panel);
+    }
+
+    Boolean isRemoveColor(int row)
+    {
+        return ((String)colors.getValueAt(row, 0)).startsWith("layer ");
+    }
+
+    /**
+     * Add all missing color entries.
+     */
+    private void fixColorPrefixes() {
+        PaintColors.getColors();
+        ConflictColors.getColors();
+        Severity.getColors();
+        MarkerLayer.getGenericColor();
+        GpxLayer.getGenericColor();
+        OsmDataLayer.getOutsideColor();
+        ImageryLayer.getFadeColor();
+        MapScaler.getColor();
+        ConflictDialog.getColor();
+    }
+
+    public boolean ok() {
+        Boolean ret = false;
+        for(String d : del) {
+            Main.pref.put("color."+d, null);
+        }
+        for (int i = 0; i < colors.getRowCount(); ++i) {
+            String key = (String)colors.getValueAt(i, 0);
+            if(Main.pref.putColor(key, (Color)colors.getValueAt(i, 1)))
+            {
+                if(key.startsWith("mappaint.")) {
+                    ret = true;
+                }
+            }
+        }
+        OsmDataLayer.createHatchTexture();
+        return ret;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getDisplayPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/DrawingPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/DrawingPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/DrawingPreference.java	(revision 4968)
@@ -0,0 +1,174 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.display;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExpertToggleAction;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.tools.GBC;
+
+public class DrawingPreference implements SubPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new DrawingPreference();
+        }
+    }
+
+    private GPXSettingsPanel gpxPanel;
+    private JCheckBox directionHint = new JCheckBox(tr("Draw Direction Arrows"));
+    private JCheckBox headArrow = new JCheckBox(tr("Only on the head of a way."));
+    private JCheckBox onewayArrow = new JCheckBox(tr("Draw oneway arrows."));
+    private JCheckBox segmentOrderNumber = new JCheckBox(tr("Draw segment order numbers"));
+    private JCheckBox sourceBounds = new JCheckBox(tr("Draw boundaries of downloaded data"));
+    private JCheckBox virtualNodes = new JCheckBox(tr("Draw virtual nodes in select mode"));
+    private JCheckBox inactive = new JCheckBox(tr("Draw inactive layers in other color"));
+
+    // Options that affect performance
+    private JCheckBox useHighlighting = new JCheckBox(tr("Highlight target ways and nodes"));
+    private JCheckBox drawHelperLine = new JCheckBox(tr("Draw rubber-band helper line"));
+    private JCheckBox useAntialiasing = new JCheckBox(tr("Smooth map graphics (antialiasing)"));
+    private JCheckBox outlineOnly = new JCheckBox(tr("Draw only outlines of areas"));
+
+    public void addGui(PreferenceTabbedPane gui) {
+        //gui.display.setPreferredSize(new Dimension(400,600));
+        gpxPanel = new GPXSettingsPanel();
+        gui.addValidationListener(gpxPanel);
+        JPanel panel = gpxPanel;
+
+        JScrollPane scrollpane = new JScrollPane(panel);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        gui.getDisplayPreference().displaycontent.addTab(tr("GPS Points"), scrollpane);
+        panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        // directionHint
+        directionHint.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (directionHint.isSelected()){
+                    headArrow.setSelected(Main.pref.getBoolean("draw.segment.head_only", false));
+                }else{
+                    headArrow.setSelected(false);
+                }
+                headArrow.setEnabled(directionHint.isSelected());
+            }
+        });
+        directionHint.setToolTipText(tr("Draw direction hints for way segments."));
+        directionHint.setSelected(Main.pref.getBoolean("draw.segment.direction", false));
+        panel.add(directionHint, GBC.eop().insets(20,0,0,0));
+
+        // only on the head of a way
+        headArrow.setToolTipText(tr("Only on the head of a way."));
+        headArrow.setSelected(Main.pref.getBoolean("draw.segment.head_only", false));
+        headArrow.setEnabled(directionHint.isSelected());
+        panel.add(headArrow, GBC.eop().insets(40, 0, 0, 0));
+
+        // draw oneway arrows
+        onewayArrow.setToolTipText(tr("Draw arrows in the direction of oneways and other directed features."));
+        onewayArrow.setSelected(Main.pref.getBoolean("draw.oneway", true));
+        panel.add(onewayArrow, GBC.eop().insets(20,0,0,0));
+
+        // segment order number
+        segmentOrderNumber.setToolTipText(tr("Draw the order numbers of all segments within their way."));
+        segmentOrderNumber.setSelected(Main.pref.getBoolean("draw.segment.order_number", false));
+        panel.add(segmentOrderNumber, GBC.eop().insets(20,0,0,0));
+
+        // downloaded area
+        sourceBounds.setToolTipText(tr("Draw the boundaries of data loaded from the server."));
+        sourceBounds.setSelected(Main.pref.getBoolean("draw.data.downloaded_area", true));
+        panel.add(sourceBounds, GBC.eop().insets(20,0,0,0));
+
+        // virtual nodes
+        virtualNodes.setToolTipText(tr("Draw virtual nodes in select mode for easy way modification."));
+        virtualNodes.setSelected(Main.pref.getInteger("mappaint.node.virtual-size", 8) != 0);
+        panel.add(virtualNodes, GBC.eop().insets(20,0,0,0));
+
+        // background layers in inactive color
+        inactive.setToolTipText(tr("Draw the inactive data layers in a different color."));
+        inactive.setSelected(Main.pref.getBoolean("draw.data.inactive_color", true));
+        panel.add(inactive, GBC.eop().insets(20,0,0,0));
+
+        // antialiasing
+        useAntialiasing.setToolTipText(tr("Apply antialiasing to the map view resulting in a smoother appearance."));
+        useAntialiasing.setSelected(Main.pref.getBoolean("mappaint.use-antialiasing", true));
+
+        // highlighting
+        useHighlighting.setToolTipText(tr("Hightlight target nodes and ways while drawing or selecting"));
+        useHighlighting.setSelected(Main.pref.getBoolean("draw.target-highlight", true));
+
+        drawHelperLine.setToolTipText(tr("Draw rubber-band helper line"));
+        drawHelperLine.setSelected(Main.pref.getBoolean("draw.helper-line", true));
+        panel.add(drawHelperLine, GBC.eop().insets(20, 0, 0, 0));
+
+        // outlineOnly
+        outlineOnly.setSelected(Main.pref.getBoolean("draw.data.area_outline_only", false));
+        outlineOnly.setToolTipText(tr("This option suppresses the filling of areas, overriding anything specified in the selected style."));
+
+        JLabel performanceLabel = new JLabel(tr("Options that affect drawing performance"));
+        panel.add(performanceLabel, GBC.eop().insets(5,10,0,0));
+        panel.add(useAntialiasing, GBC.eop().insets(20,5,0,0));
+        panel.add(useHighlighting, GBC.eop().insets(20,0,0,0));
+        panel.add(outlineOnly, GBC.eol().insets(20,0,0,5));
+
+        ExpertToggleAction.addVisibilitySwitcher(performanceLabel);
+        ExpertToggleAction.addVisibilitySwitcher(useAntialiasing);
+        ExpertToggleAction.addVisibilitySwitcher(useHighlighting);
+        ExpertToggleAction.addVisibilitySwitcher(outlineOnly);
+
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+        scrollpane = new JScrollPane(panel);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        gui.getDisplayPreference().displaycontent.addTab(tr("OSM Data"), scrollpane);
+    }
+
+    public boolean ok() {
+        gpxPanel.savePreferences();
+        Main.pref.put("draw.data.area_outline_only", outlineOnly.isSelected());
+        Main.pref.put("draw.segment.direction", directionHint.isSelected());
+        Main.pref.put("draw.segment.head_only", headArrow.isSelected());
+        Main.pref.put("draw.oneway", onewayArrow.isSelected());
+        Main.pref.put("draw.segment.order_number", segmentOrderNumber.isSelected());
+        Main.pref.put("draw.data.downloaded_area", sourceBounds.isSelected());
+        Main.pref.put("draw.data.inactive_color", inactive.isSelected());
+        Main.pref.put("mappaint.use-antialiasing", useAntialiasing.isSelected());
+        Main.pref.put("draw.target-highlight", useHighlighting.isSelected());
+        Main.pref.put("draw.helper-line", drawHelperLine.isSelected());
+        int vn = Main.pref.getInteger("mappaint.node.virtual-size", 8);
+        if (virtualNodes.isSelected()) {
+            if (vn < 1) {
+                vn = 8;
+            }
+        }
+        else {
+            vn = 0;
+        }
+        Main.pref.putInteger("mappaint.node.virtual-size", vn);
+        return false;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getDisplayPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java	(revision 4968)
@@ -0,0 +1,463 @@
+package org.openstreetmap.josm.gui.preferences.display;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trc;
+
+import java.awt.Component;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExpertToggleAction;
+import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
+import org.openstreetmap.josm.gui.layer.markerlayer.Marker.TemplateEntryProperty;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.template_engine.ParseError;
+import org.openstreetmap.josm.tools.template_engine.TemplateParser;
+
+public class GPXSettingsPanel extends JPanel implements ValidationListener {
+
+    private static final int WAYPOINT_LABEL_CUSTOM = 6;
+    private static final String[] LABEL_PATTERN_TEMPLATE = new String[] {Marker.LABEL_PATTERN_AUTO, Marker.LABEL_PATTERN_NAME,
+        Marker.LABEL_PATTERN_DESC, "{special:everything}", "?{ '{name}' | '{desc}' | '{formattedWaypointOffset}' }", ""};
+    private static final String[] LABEL_PATTERN_DESC = new String[] {tr("Auto"), /* gpx data field name */ trc("gpx_field", "Name"),
+        /* gpx data field name */ trc("gpx_field", "Desc(ription)"), tr("Everything"), tr("Name or offset"), tr("None"), tr("Custom")};
+
+
+    private JRadioButton drawRawGpsLinesGlobal = new JRadioButton(tr("Use global settings"));
+    private JRadioButton drawRawGpsLinesAll = new JRadioButton(tr("All"));
+    private JRadioButton drawRawGpsLinesLocal = new JRadioButton(tr("Local files"));
+    private JRadioButton drawRawGpsLinesNone = new JRadioButton(tr("None"));
+    private ActionListener drawRawGpsLinesActionListener;
+    private JTextField drawRawGpsMaxLineLength = new JTextField(8);
+    private JTextField drawRawGpsMaxLineLengthLocal = new JTextField(8);
+    private JTextField drawLineWidth = new JTextField(2);
+    private JCheckBox forceRawGpsLines = new JCheckBox(tr("Force lines if no segments imported"));
+    private JCheckBox largeGpsPoints = new JCheckBox(tr("Draw large GPS points"));
+    private JCheckBox hdopCircleGpsPoints = new JCheckBox(tr("Draw a circle from HDOP value"));
+    private ButtonGroup colorGroup;
+    private JRadioButton colorTypeVelocity = new JRadioButton(tr("Velocity (red = slow, green = fast)"));
+    private JRadioButton colorTypeDirection = new JRadioButton(tr("Direction (red = west, yellow = north, green = east, blue = south)"));
+    private JRadioButton colorTypeDilution = new JRadioButton(tr("Dilution of Position (red = high, green = low, if available)"));
+    private JRadioButton colorTypeTime = new JRadioButton(tr("Track date"));
+    private JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized for named layers)"));
+    private JRadioButton colorTypeGlobal  = new JRadioButton(tr("Use global settings"));
+    private JComboBox colorTypeVelocityTune = new JComboBox(new String[] {tr("Car"), tr("Bicycle"), tr("Foot")});
+    private JCheckBox makeAutoMarkers = new JCheckBox(tr("Create markers when reading GPX"));
+    private JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows"));
+    private JCheckBox drawGpsArrowsFast = new JCheckBox(tr("Fast drawing (looks uglier)"));
+    private JTextField drawGpsArrowsMinDist = new JTextField(8);
+    private JCheckBox colorDynamic = new JCheckBox(tr("Dynamic color range based on data limits"));
+    private JComboBox waypointLabel = new JComboBox(LABEL_PATTERN_DESC);
+    private JTextField waypointLabelPattern = new JTextField();
+    private JComboBox audioWaypointLabel = new JComboBox(LABEL_PATTERN_DESC);
+    private JTextField audioWaypointLabelPattern = new JTextField();
+
+    private String layerName;
+    private boolean local; // flag to display LocalOnly checkbox
+    private boolean nonlocal; // flag to display AllLines checkbox
+
+    public GPXSettingsPanel(String layerName, boolean local, boolean nonlocal) {
+        super(new GridBagLayout());
+        this.local=local; this.nonlocal=nonlocal;
+        this.layerName = "layer "+layerName;
+        initComponents();
+        loadPreferences();
+    }
+
+    public GPXSettingsPanel() {
+        super(new GridBagLayout());
+        initComponents();
+        local=false; nonlocal=false;
+        loadPreferences(); // preferences -> controls
+    }
+
+    private void initComponents() {
+        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        // makeAutoMarkers
+        makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
+        ExpertToggleAction.addVisibilitySwitcher(makeAutoMarkers);
+        add(makeAutoMarkers, GBC.eol().insets(20,0,0,5));
+
+        // drawRawGpsLines
+        ButtonGroup gpsLinesGroup = new ButtonGroup();
+        if (layerName!=null) {
+            gpsLinesGroup.add(drawRawGpsLinesGlobal);
+        }
+        gpsLinesGroup.add(drawRawGpsLinesNone);
+        gpsLinesGroup.add(drawRawGpsLinesLocal);
+        gpsLinesGroup.add(drawRawGpsLinesAll);
+
+        /* ensure that default is in data base */
+
+        JLabel label = new JLabel(tr("Draw lines between raw GPS points"));
+        add(label, GBC.eol().insets(20,0,0,0));
+        if (layerName!=null) {
+            add(drawRawGpsLinesGlobal, GBC.eol().insets(40,0,0,0));
+        }
+        add(drawRawGpsLinesNone, GBC.eol().insets(40,0,0,0));
+        if (layerName==null || local) {
+            add(drawRawGpsLinesLocal, GBC.eol().insets(40,0,0,0));
+        }
+        if (layerName==null || nonlocal) {
+            add(drawRawGpsLinesAll, GBC.eol().insets(40,0,0,0));
+        }
+        ExpertToggleAction.addVisibilitySwitcher(label);
+        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesGlobal);
+        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesNone);
+        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesLocal);
+        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesAll);
+
+        drawRawGpsLinesActionListener = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                boolean f=drawRawGpsLinesNone.isSelected()||drawRawGpsLinesGlobal.isSelected();
+                forceRawGpsLines.setEnabled(!f);
+                drawRawGpsMaxLineLength.setEnabled(!(f || drawRawGpsLinesLocal.isSelected()));
+                drawRawGpsMaxLineLengthLocal.setEnabled(!f);
+                drawGpsArrows.setEnabled(!f);
+                drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
+                drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
+            }
+        };
+
+        drawRawGpsLinesGlobal.addActionListener(drawRawGpsLinesActionListener);
+        drawRawGpsLinesNone.addActionListener(drawRawGpsLinesActionListener);
+        drawRawGpsLinesLocal.addActionListener(drawRawGpsLinesActionListener);
+        drawRawGpsLinesAll.addActionListener(drawRawGpsLinesActionListener);
+
+        // drawRawGpsMaxLineLengthLocal
+        drawRawGpsMaxLineLengthLocal.setToolTipText(tr("Maximum length (in meters) to draw lines for local files. Set to ''-1'' to draw all lines."));
+        label = new JLabel(tr("Maximum length for local files (meters)"));
+        add(label, GBC.std().insets(40,0,0,0));
+        add(drawRawGpsMaxLineLengthLocal, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        ExpertToggleAction.addVisibilitySwitcher(label);
+        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsMaxLineLengthLocal);
+
+        // drawRawGpsMaxLineLength
+        drawRawGpsMaxLineLength.setToolTipText(tr("Maximum length (in meters) to draw lines. Set to ''-1'' to draw all lines."));
+        label = new JLabel(tr("Maximum length (meters)"));
+        add(label, GBC.std().insets(40,0,0,0));
+        add(drawRawGpsMaxLineLength, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        ExpertToggleAction.addVisibilitySwitcher(label);
+        ExpertToggleAction.addVisibilitySwitcher(drawRawGpsMaxLineLength);
+
+        // forceRawGpsLines
+        forceRawGpsLines.setToolTipText(tr("Force drawing of lines if the imported data contain no line information."));
+        add(forceRawGpsLines, GBC.eop().insets(40,0,0,0));
+        ExpertToggleAction.addVisibilitySwitcher(forceRawGpsLines);
+
+        // drawGpsArrows
+        drawGpsArrows.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
+                drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
+            }
+        });
+        drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points."));
+        add(drawGpsArrows, GBC.eop().insets(40,0,0,0));
+
+        // drawGpsArrowsFast
+        drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math."));
+        add(drawGpsArrowsFast, GBC.eop().insets(60,0,0,0));
+        ExpertToggleAction.addVisibilitySwitcher(drawGpsArrowsFast);
+
+        // drawGpsArrowsMinDist
+        drawGpsArrowsMinDist.setToolTipText(tr("Do not draw arrows if they are not at least this distance away from the last one."));
+        add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(60,0,0,0));
+        add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+        // hdopCircleGpsPoints
+        hdopCircleGpsPoints.setToolTipText(tr("Draw a circle from HDOP value."));
+        add(hdopCircleGpsPoints, GBC.eop().insets(20,0,0,0));
+        ExpertToggleAction.addVisibilitySwitcher(hdopCircleGpsPoints);
+
+        // largeGpsPoints
+        largeGpsPoints.setToolTipText(tr("Draw larger dots for the GPS points."));
+        add(largeGpsPoints, GBC.eop().insets(20,0,0,0));
+
+        // drawLineWidth
+        drawLineWidth.setToolTipText(tr("Width of drawn GPX line (0 for default)"));
+        add(new JLabel(tr("Drawing width of GPX lines")), GBC.std().insets(20,0,0,0));
+        add(drawLineWidth, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+        // colorTracks
+        colorGroup = new ButtonGroup();
+        if (layerName!=null) {
+            colorGroup.add(colorTypeGlobal);
+        }
+        colorGroup.add(colorTypeNone);
+        colorGroup.add(colorTypeVelocity);
+        colorGroup.add(colorTypeDirection);
+        colorGroup.add(colorTypeDilution);
+        colorGroup.add(colorTypeTime);
+
+        colorTypeVelocity.addChangeListener(new ChangeListener(){
+            public void stateChanged(ChangeEvent e) {
+                colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected());
+                colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
+            }
+        });
+        colorTypeDilution.addChangeListener(new ChangeListener(){
+            public void stateChanged(ChangeEvent e) {
+                colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
+            }
+        });
+
+        colorTypeNone.setToolTipText(tr("All points and track segments will have the same color. Can be customized in Layer Manager."));
+        colorTypeVelocity.setToolTipText(tr("Colors points and track segments by velocity."));
+        colorTypeDirection.setToolTipText(tr("Colors points and track segments by direction."));
+        colorTypeDilution.setToolTipText(tr("Colors points and track segments by dilution of position (HDOP). Your capture device needs to log that information."));
+        colorTypeTime.setToolTipText(tr("Colors points and track segments by its timestamp."));
+
+        // color Tracks by Velocity Tune
+        colorTypeVelocityTune.setToolTipText(tr("Allows to tune the track coloring for different average speeds."));
+
+        add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
+
+        add(new JLabel(tr("Track and Point Coloring")), GBC.eol().insets(20,0,0,0));
+        if (layerName!=null) {
+            add(colorTypeGlobal, GBC.eol().insets(40,0,0,0));
+        }
+        add(colorTypeNone, GBC.eol().insets(40,0,0,0));
+        add(colorTypeVelocity, GBC.std().insets(40,0,0,0));
+        add(colorTypeVelocityTune, GBC.eop().insets(5,0,0,5));
+        add(colorTypeDirection, GBC.eol().insets(40,0,0,0));
+        add(colorTypeDilution, GBC.eol().insets(40,0,0,0));
+        add(colorTypeTime, GBC.eol().insets(40,0,0,0));
+        ExpertToggleAction.addVisibilitySwitcher(colorTypeDirection);
+        ExpertToggleAction.addVisibilitySwitcher(colorTypeDilution);
+
+        colorDynamic.setToolTipText(tr("Colors points and track segments by data limits."));
+        add(colorDynamic, GBC.eop().insets(40,0,0,0));
+        ExpertToggleAction.addVisibilitySwitcher(colorDynamic);
+
+        if (layerName == null) {
+            // Setting waypoints for gpx layer doesn't make sense - waypoints are shown in marker layer that has different name - so show
+            // this only for global config
+
+            // waypointLabel
+            label = new JLabel(tr("Waypoint labelling"));
+            add(label, GBC.std().insets(20,0,0,0));
+            add(waypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+            waypointLabel.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    updateWaypointPattern(waypointLabel, waypointLabelPattern);
+                }
+            });
+            updateWaypointLabelCombobox(waypointLabel, waypointLabelPattern, TemplateEntryProperty.forMarker(layerName));
+            add(waypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
+            ExpertToggleAction.addVisibilitySwitcher(label);
+            ExpertToggleAction.addVisibilitySwitcher(waypointLabel);
+            ExpertToggleAction.addVisibilitySwitcher(waypointLabelPattern);
+
+            // audioWaypointLabel
+            Component glue = Box.createVerticalGlue();
+            add(glue, GBC.eol().insets(0, 20, 0, 0));
+            ExpertToggleAction.addVisibilitySwitcher(glue);
+
+            label = new JLabel(tr("Audio waypoint labelling"));
+            add(label, GBC.std().insets(20,0,0,0));
+            add(audioWaypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+            audioWaypointLabel.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    updateWaypointPattern(audioWaypointLabel, audioWaypointLabelPattern);
+                }
+            });
+            updateWaypointLabelCombobox(audioWaypointLabel, audioWaypointLabelPattern, TemplateEntryProperty.forAudioMarker(layerName));
+            add(audioWaypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
+            ExpertToggleAction.addVisibilitySwitcher(label);
+            ExpertToggleAction.addVisibilitySwitcher(audioWaypointLabel);
+            ExpertToggleAction.addVisibilitySwitcher(audioWaypointLabelPattern);
+        }
+
+        add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+    }
+
+    /**
+     * Loads preferences to UI controls
+     */
+    public void loadPreferences () {
+        makeAutoMarkers.setSelected(Main.pref.getBoolean("marker.makeautomarkers", true));
+        if(layerName!=null && Main.pref.get("draw.rawgps.lines."+layerName).isEmpty()
+                && Main.pref.get("draw.rawgps.lines.local."+layerName).isEmpty()){
+            // no line preferences for layer is found
+            drawRawGpsLinesGlobal.setSelected(true);
+        } else {
+            Boolean lf = Main.pref.getBoolean("draw.rawgps.lines.local",layerName, true);
+            if(Main.pref.getBoolean("draw.rawgps.lines",layerName, true)) {
+                drawRawGpsLinesAll.setSelected(true);
+            } else if (lf) {
+                drawRawGpsLinesLocal.setSelected(true);
+            } else {
+                drawRawGpsLinesNone.setSelected(true);
+            }
+        }
+
+        drawRawGpsMaxLineLengthLocal.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length.local",layerName, -1)));
+        drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length",layerName, 200)));
+        drawLineWidth.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.linewidth",layerName, 0)));
+        forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force",layerName, false));
+        drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction",layerName, false));
+        drawGpsArrowsFast.setSelected(Main.pref.getBoolean("draw.rawgps.alternatedirection",layerName, false));
+        drawGpsArrowsMinDist.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.min-arrow-distance",layerName, 40)));
+        hdopCircleGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.hdopcircle",layerName, false));
+        largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large",layerName, false));
+        drawRawGpsLinesActionListener.actionPerformed(null);
+
+        if(layerName!=null && Main.pref.get("draw.rawgps.colors."+layerName).isEmpty()) {
+            colorTypeGlobal.setSelected(true);
+            colorDynamic.setSelected(false);
+            colorDynamic.setEnabled(false);
+        } else {
+            switch(Main.pref.getInteger("draw.rawgps.colors",layerName, 0)) {
+            case 0: colorTypeNone.setSelected(true);   break;
+            case 1: colorTypeVelocity.setSelected(true);  break;
+            case 2: colorTypeDilution.setSelected(true);  break;
+            case 3: colorTypeDirection.setSelected(true); break;
+            case 4: colorTypeTime.setSelected(true);  break;
+            }
+            int ccts = Main.pref.getInteger("draw.rawgps.colorTracksTune",layerName, 45);
+            colorTypeVelocityTune.setSelectedIndex(ccts==10 ? 2 : (ccts==20 ? 1 : 0));
+            colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected() && colorTypeVelocity.isEnabled());
+            colorDynamic.setSelected(Main.pref.getBoolean("draw.rawgps.colors.dynamic",layerName, false));
+            colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
+        }
+    }
+
+
+    /**
+     * Save preferences from UI controls for specified layer
+     * if layerName==null, global preferences are written
+     */
+    public boolean savePreferences (String layerName, boolean locLayer) {
+        String layerNameDot = ".layer "+layerName;
+        if (layerName==null) {
+            layerNameDot="";
+        }
+        Main.pref.put("marker.makeautomarkers"+layerNameDot, makeAutoMarkers.isSelected());
+        if (drawRawGpsLinesGlobal.isSelected()) {
+            Main.pref.put("draw.rawgps.lines" + layerNameDot, null);
+            Main.pref.put("draw.rawgps.max-line-length" + layerNameDot, null);
+            Main.pref.put("draw.rawgps.lines.local" + layerNameDot, null);
+            Main.pref.put("draw.rawgps.max-line-length.local" + layerNameDot, null);
+            Main.pref.put("draw.rawgps.lines.force"+layerNameDot, null);
+            Main.pref.put("draw.rawgps.direction"+layerNameDot, null);
+            Main.pref.put("draw.rawgps.alternatedirection"+layerNameDot, null);
+            Main.pref.put("draw.rawgps.min-arrow-distance"+layerNameDot, null);
+        } else {
+            if (layerName==null || !locLayer) {
+                Main.pref.put("draw.rawgps.lines" +  layerNameDot, drawRawGpsLinesAll.isSelected());
+                Main.pref.put("draw.rawgps.max-line-length" + layerNameDot, drawRawGpsMaxLineLength.getText());
+            }
+            if (layerName==null || locLayer) {
+                Main.pref.put("draw.rawgps.lines.local" + layerNameDot, drawRawGpsLinesAll.isSelected() || drawRawGpsLinesLocal.isSelected());
+                Main.pref.put("draw.rawgps.max-line-length.local" + layerNameDot, drawRawGpsMaxLineLengthLocal.getText());
+            }
+            Main.pref.put("draw.rawgps.lines.force"+layerNameDot, forceRawGpsLines.isSelected());
+            Main.pref.put("draw.rawgps.direction"+layerNameDot, drawGpsArrows.isSelected());
+            Main.pref.put("draw.rawgps.alternatedirection"+layerNameDot, drawGpsArrowsFast.isSelected());
+            Main.pref.put("draw.rawgps.min-arrow-distance"+layerNameDot, drawGpsArrowsMinDist.getText());
+        }
+
+        Main.pref.put("draw.rawgps.hdopcircle"+layerNameDot, hdopCircleGpsPoints.isSelected());
+        Main.pref.put("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected());
+        Main.pref.put("draw.rawgps.linewidth"+layerNameDot, drawLineWidth.getText());
+
+        TemplateEntryProperty.forMarker(layerName).put(waypointLabelPattern.getText());
+        TemplateEntryProperty.forAudioMarker(layerName).put(audioWaypointLabelPattern.getText());
+
+        if(colorTypeGlobal.isSelected()) {
+            Main.pref.put("draw.rawgps.colors"+layerNameDot, null);
+            Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, null);
+            Main.pref.put("draw.rawgps.colorTracksTunec"+layerNameDot, null);
+            return false;
+        } else if(colorTypeVelocity.isSelected()) {
+            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 1);
+        } else if(colorTypeDilution.isSelected()) {
+            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 2);
+        } else if(colorTypeDirection.isSelected()) {
+            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 3);
+        } else if(colorTypeTime.isSelected()) {
+            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 4);
+        } else {
+            Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 0);
+        }
+        Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, colorDynamic.isSelected());
+        int ccti=colorTypeVelocityTune.getSelectedIndex();
+        Main.pref.putInteger("draw.rawgps.colorTracksTune"+layerNameDot, ccti==2 ? 10 : (ccti==1 ? 20 : 45));
+        return false;
+    }
+
+    /**
+     * Save preferences from UI controls for initial layer or globally
+     */
+    public void savePreferences() {
+        savePreferences(null, false);
+    }
+
+    private void updateWaypointLabelCombobox(JComboBox cb, JTextField tf, TemplateEntryProperty property) {
+        String labelPattern = property.getAsString();
+        boolean found = false;
+        for (int i=0; i<LABEL_PATTERN_TEMPLATE.length; i++) {
+            if (LABEL_PATTERN_TEMPLATE[i].equals(labelPattern)) {
+                cb.setSelectedIndex(i);
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            cb.setSelectedIndex(WAYPOINT_LABEL_CUSTOM);
+            tf.setEnabled(true);
+            tf.setText(labelPattern);
+        }
+    }
+
+    private void updateWaypointPattern(JComboBox cb, JTextField tf) {
+        if (cb.getSelectedIndex() == WAYPOINT_LABEL_CUSTOM) {
+            tf.setEnabled(true);
+        } else {
+            tf.setEnabled(false);
+            tf.setText(LABEL_PATTERN_TEMPLATE[cb.getSelectedIndex()]);
+        }
+    }
+
+    @Override
+    public boolean validatePreferences() {
+        TemplateParser parser = new TemplateParser(waypointLabelPattern.getText());
+        try {
+            parser.parse();
+        } catch (ParseError e) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Incorrect waypoint label pattern: {0}", e.getMessage()), tr("Incorrect pattern"), JOptionPane.ERROR_MESSAGE);
+            waypointLabelPattern.requestFocus();
+            return false;
+        }
+        parser = new TemplateParser(audioWaypointLabelPattern.getText());
+        try {
+            parser.parse();
+        } catch (ParseError e) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Incorrect audio waypoint label pattern: {0}", e.getMessage()), tr("Incorrect pattern"), JOptionPane.ERROR_MESSAGE);
+            audioWaypointLabelPattern.requestFocus();
+            return false;
+        }
+        return true;
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/LafPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/LafPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/LafPreference.java	(revision 4968)
@@ -0,0 +1,141 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.display;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.GridBagLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+import javax.swing.UIManager.LookAndFeelInfo;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExpertToggleAction;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.tools.GBC;
+
+public class LafPreference implements SubPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new LafPreference();
+        }
+    }
+
+    /**
+     * ComboBox with all look and feels.
+     */
+    private JComboBox lafCombo;
+    public JPanel panel;
+    private JCheckBox showSplashScreen = new JCheckBox(tr("Show splash screen at startup"));
+    private JCheckBox showID = new JCheckBox(tr("Show object ID in selection lists"));
+    private JCheckBox showLocalizedName = new JCheckBox(tr("Show localized name in selection lists"));
+    private JCheckBox modeless = new JCheckBox(tr("Modeless working (Potlatch style)"));
+    private JCheckBox dynamicButtons = new JCheckBox(tr("Dynamic buttons in side menus"));
+
+    public void addGui(PreferenceTabbedPane gui) {
+        lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
+
+        // let's try to load additional LookAndFeels and put them into the list
+        try {
+            Class<?> Cquaqua = Class.forName("ch.randelshofer.quaqua.QuaquaLookAndFeel");
+            Object Oquaqua = Cquaqua.getConstructor((Class[])null).newInstance((Object[])null);
+            // no exception? Then Go!
+            lafCombo.addItem(
+                    new UIManager.LookAndFeelInfo(((javax.swing.LookAndFeel)Oquaqua).getName(), "ch.randelshofer.quaqua.QuaquaLookAndFeel")
+            );
+        } catch (Exception ex) {
+            // just ignore, Quaqua may not even be installed...
+            //System.out.println("Failed to load Quaqua: " + ex);
+        }
+
+        String laf = Main.pref.get("laf", Main.platform.getDefaultStyle());
+        for (int i = 0; i < lafCombo.getItemCount(); ++i) {
+            if (((LookAndFeelInfo)lafCombo.getItemAt(i)).getClassName().equals(laf)) {
+                lafCombo.setSelectedIndex(i);
+                break;
+            }
+        }
+
+        final ListCellRenderer oldRenderer = lafCombo.getRenderer();
+        lafCombo.setRenderer(new DefaultListCellRenderer(){
+            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                return oldRenderer.getListCellRendererComponent(list, ((LookAndFeelInfo)value).getName(), index, isSelected, cellHasFocus);
+            }
+        });
+
+        panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        // Show splash screen on startup
+        showSplashScreen.setToolTipText(tr("Show splash screen at startup"));
+        showSplashScreen.setSelected(Main.pref.getBoolean("draw.splashscreen", true));
+        panel.add(showSplashScreen, GBC.eop().insets(20, 0, 0, 0));
+
+        // Show ID in selection
+        showID.setToolTipText(tr("Show object ID in selection lists"));
+        showID.setSelected(Main.pref.getBoolean("osm-primitives.showid", false));
+
+        // Show localized names
+        showLocalizedName.setToolTipText(tr("Show localized name in selection lists, if available"));
+        showLocalizedName.setSelected(Main.pref.getBoolean("osm-primitives.localize-name", true));
+        ExpertToggleAction.addVisibilitySwitcher(showLocalizedName);
+
+        modeless.setToolTipText(tr("Do not require to switch modes (potlatch style workflow)"));
+        modeless.setSelected(Main.pref.getBoolean("modeless", false));
+        ExpertToggleAction.addVisibilitySwitcher(modeless);
+
+        panel.add(showID, GBC.eop().insets(20, 0, 0, 0));
+        panel.add(showLocalizedName, GBC.eop().insets(20, 0, 0, 0));
+        panel.add(modeless, GBC.eop().insets(20, 0, 0, 0));
+
+        dynamicButtons.setToolTipText(tr("Display buttons in right side menus only when mouse is inside the element"));
+        dynamicButtons.setSelected(Main.pref.getBoolean("dialog.dynamic.buttons", true));
+        panel.add(dynamicButtons, GBC.eop().insets(20, 0, 0, 0));
+
+        panel.add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
+
+        panel.add(new JLabel(tr("Look and Feel")), GBC.std().insets(20, 0, 0, 0));
+        panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        panel.add(lafCombo, GBC.eol().fill(GBC.HORIZONTAL));
+
+        JScrollPane scrollpane = new JScrollPane(panel);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        gui.getDisplayPreference().displaycontent.addTab(tr("Look and Feel"), scrollpane);
+    }
+
+    public boolean ok() {
+        boolean mod = false;
+        Main.pref.put("draw.splashscreen", showSplashScreen.isSelected());
+        Main.pref.put("osm-primitives.showid", showID.isSelected());
+        Main.pref.put("osm-primitives.localize-name", showLocalizedName.isSelected());
+        Main.pref.put("modeless", modeless.isSelected());
+        Main.pref.put("dialog.dynamic.buttons", dynamicButtons.isSelected());
+        mod |= Main.pref.put("laf", ((LookAndFeelInfo)lafCombo.getSelectedItem()).getClassName());
+        return mod;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getDisplayPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/LanguagePreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/LanguagePreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/LanguagePreference.java	(revision 4968)
@@ -0,0 +1,124 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.display;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import javax.swing.Box;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.I18n;
+
+public class LanguagePreference implements SubPreferenceSetting {
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new LanguagePreference();
+        }
+    }
+
+    /** the combo box with the available locales */
+    private JComboBox langCombo;
+    /** the model for the combo box */
+    private LanguageComboBoxModel model;
+
+    public void addGui(final PreferenceTabbedPane gui) {
+        model = new LanguageComboBoxModel();
+        // Selecting the language BEFORE the JComboBox listens to model changes speed up initialization by ~35ms (see #7386)
+        // See http://stackoverflow.com/questions/3194958/fast-replacement-for-jcombobox-basiccomboboxui 
+        model.selectLanguage(Main.pref.get("language"));
+        langCombo = new JComboBox(model);
+        langCombo.setRenderer(new LanguageCellRenderer(langCombo.getRenderer()));
+
+        LafPreference lafPreference = gui.getSetting(LafPreference.class);
+        final JPanel panel = lafPreference.panel;
+        panel.add(new JLabel(tr("Language")), GBC.std().insets(20, 0, 0, 0));
+        panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        panel.add(langCombo, GBC.eol().fill(GBC.HORIZONTAL));
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+    }
+
+    public boolean ok() {
+        if(langCombo.getSelectedItem() == null)
+            return Main.pref.put("language", null);
+        else
+            return Main.pref.put("language",
+                    ((Locale)langCombo.getSelectedItem()).toString());
+    }
+
+    private static class LanguageComboBoxModel extends DefaultComboBoxModel {
+        private final List<Locale> data = new ArrayList<Locale>();
+
+        public LanguageComboBoxModel(){
+            data.add(0,null);
+            data.addAll(Arrays.asList(I18n.getAvailableTranslations()));
+        }
+
+        public void selectLanguage(String language) {
+            setSelectedItem(null);
+            if (language != null) {
+                for (Locale locale: data) {
+                    if (locale == null) {
+                        continue;
+                    }
+                    if (locale.toString().equals(language)) {
+                        setSelectedItem(locale);
+                        return;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public Object getElementAt(int index) {
+            return data.get(index);
+        }
+
+        @Override
+        public int getSize() {
+            return data.size();
+        }
+    }
+
+    static private class LanguageCellRenderer extends DefaultListCellRenderer {
+        private ListCellRenderer dispatch;
+        public LanguageCellRenderer(ListCellRenderer dispatch) {
+            this.dispatch = dispatch;
+        }
+        @Override
+        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+                boolean cellHasFocus) {
+            Locale l = (Locale) value;
+            return dispatch.getListCellRendererComponent(list,
+                    l == null ? tr("Default (Auto determined)") : l.getDisplayName(l),
+                            index, isSelected, cellHasFocus);
+        }
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getDisplayPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java	(revision 4968)
@@ -0,0 +1,622 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.imagery;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trc;
+
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.HeadlessException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
+import org.openstreetmap.josm.gui.layer.TMSLayer;
+import org.openstreetmap.josm.io.UTFInputStreamReader;
+import org.openstreetmap.josm.tools.GBC;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+public class AddWMSLayerPanel extends JPanel {
+    private List<LayerDetails> selectedLayers;
+    private URL serviceUrl;
+    private LayerDetails selectedLayer;
+
+    private JTextField menuName;
+    private JTextArea resultingLayerField;
+    private MutableTreeNode treeRootNode;
+    private DefaultTreeModel treeData;
+    private JTree layerTree;
+    private JButton showBoundsButton;
+
+    private boolean previouslyShownUnsupportedCrsError = false;
+    private JTextArea tmsURL;
+    private JTextField tmsZoom;
+
+    public AddWMSLayerPanel() {
+        super(new GridBagLayout());
+        add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0));
+        menuName = new JTextField(40);
+        menuName.setText(tr("Unnamed Imagery Layer"));
+        add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+
+        final JTabbedPane tabbedPane = new JTabbedPane();
+
+        final JPanel wmsFetchPanel = new JPanel(new GridBagLayout());
+        tabbedPane.addTab(tr("WMS"), wmsFetchPanel);
+        add(tabbedPane, GBC.eop().insets(5,0,0,0).weight(1.0, 1.0).fill(GridBagConstraints.BOTH));
+
+        final JTextArea serviceUrlText = new JTextArea(3, 40);
+        serviceUrlText.setLineWrap(true);
+        serviceUrlText.setText("http://sample.com/wms?");
+        wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0));
+        JScrollPane scrollPane = new JScrollPane(serviceUrlText,
+                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        scrollPane.setMinimumSize(new Dimension(60, 60));
+        wmsFetchPanel.add(scrollPane, GBC.eol().weight(1.0, 0.0).insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+        JButton getLayersButton = new JButton(tr("Get Layers"));
+        getLayersButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                Cursor beforeCursor = getCursor();
+                try {
+                    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+                    attemptGetCapabilities(sanitize(serviceUrlText.getText()));
+                } finally {
+                    setCursor(beforeCursor);
+                }
+            }
+        });
+        wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST));
+
+        treeRootNode = new DefaultMutableTreeNode();
+        treeData = new DefaultTreeModel(treeRootNode);
+        layerTree = new JTree(treeData);
+        layerTree.setCellRenderer(new LayerTreeCellRenderer());
+        layerTree.addTreeSelectionListener(new TreeSelectionListener() {
+
+            @Override
+            public void valueChanged(TreeSelectionEvent e) {
+                TreePath[] selectionRows = layerTree.getSelectionPaths();
+                if(selectionRows == null) {
+                    showBoundsButton.setEnabled(false);
+                    selectedLayer = null;
+                    return;
+                }
+
+                selectedLayers = new LinkedList<LayerDetails>();
+                for (TreePath i : selectionRows) {
+                    Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
+                    if(userObject instanceof LayerDetails) {
+                        LayerDetails detail = (LayerDetails) userObject;
+                        if(!detail.isSupported()) {
+                            layerTree.removeSelectionPath(i);
+                            if(!previouslyShownUnsupportedCrsError) {
+                                JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM''s projections,\n" +
+                                        "so you can not use it. This message will not show again."),
+                                        tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+                                previouslyShownUnsupportedCrsError = true;
+                            }
+                        } else if(detail.ident != null) {
+                            selectedLayers.add(detail);
+                        }
+                    }
+                }
+
+                if (!selectedLayers.isEmpty()) {
+                    resultingLayerField.setText(buildGetMapUrl());
+
+                    if(selectedLayers.size() == 1) {
+                        showBoundsButton.setEnabled(true);
+                        selectedLayer = selectedLayers.get(0);
+                    }
+                } else {
+                    showBoundsButton.setEnabled(false);
+                    selectedLayer = null;
+                }
+            }
+        });
+        wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eol().weight(1.0, 1.0).insets(5,0,0,0).fill(GridBagConstraints.BOTH));
+
+        JPanel layerManipulationButtons = new JPanel();
+        showBoundsButton = new JButton(tr("Show Bounds"));
+        showBoundsButton.setEnabled(false);
+        showBoundsButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if(selectedLayer.bounds != null) {
+                    SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
+                    mapPanel.setBoundingBox(selectedLayer.bounds);
+                    JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
+                } else {
+                    JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
+                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+                }
+            }
+        });
+        layerManipulationButtons.add(showBoundsButton);
+
+        wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0));
+
+        final JPanel tmsView = new JPanel(new GridBagLayout());
+        tmsView.add(new JLabel(tr("TMS URL")), GBC.std().insets(0,0,5,0));
+        tmsURL = new JTextArea(3, 40);
+        tmsURL.setLineWrap(true);
+        tmsURL.setText("http://sample.com/tms/{zoom}/{x}/{y}.jpg");
+        tmsURL.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyReleased(KeyEvent e) {
+                resultingLayerField.setText(buildTMSUrl());
+            }
+        });
+        JScrollPane tmsUrlScrollPane = new JScrollPane(tmsURL,
+                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        tmsUrlScrollPane.setMinimumSize(new Dimension(60, 60));
+        tmsView.add(tmsUrlScrollPane, GBC.eol().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+        tmsView.add(new JLabel(trc("layer", "Zoom")), GBC.std().insets(0,0,5,0));
+        tmsZoom = new JTextField(3);
+        tmsZoom.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyReleased(KeyEvent e) {
+                resultingLayerField.setText(buildTMSUrl());
+            }
+        });
+        tmsView.add(tmsZoom, GBC.eol().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+        tmsView.add(new JLabel(), GBC.eop().weight(1.0, 1.0).fill(GridBagConstraints.BOTH));
+        tabbedPane.addTab(tr("TMS"), tmsView);
+
+        add(new JLabel(tr("Imagery URL")), GBC.std().insets(0,0,5,0));
+        resultingLayerField = new JTextArea(3, 40);
+        resultingLayerField.setLineWrap(true);
+        JScrollPane bottomScrollPane = new JScrollPane(resultingLayerField,
+                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        bottomScrollPane.setMinimumSize(new Dimension(60, 60));
+        add(bottomScrollPane, GBC.eol().weight(1.0, 0.0).insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+
+        tabbedPane.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent e) {
+                Component sel = tabbedPane.getSelectedComponent();
+                if(tmsView == sel) {
+                    resultingLayerField.setText(buildTMSUrl());
+                } else if(wmsFetchPanel == sel) {
+                    if(serviceUrl != null) {
+                        resultingLayerField.setText(buildGetMapUrl());
+                    }
+                }
+            }
+        });
+    }
+
+    private String sanitize(String s) {
+        return s.replaceAll("[\r\n]+","").trim();
+    }
+
+    private String buildTMSUrl() {
+        StringBuilder a = new StringBuilder("tms");
+        String z = sanitize(tmsZoom.getText());
+        if(!z.isEmpty()) {
+            a.append("["+z+"]");
+        }
+        a.append(":");
+        a.append(sanitize(tmsURL.getText()));
+        return a.toString();
+    }
+
+    private String buildRootUrl() {
+        StringBuilder a = new StringBuilder(serviceUrl.getProtocol());
+        a.append("://");
+        a.append(serviceUrl.getHost());
+        if(serviceUrl.getPort() != -1) {
+            a.append(":");
+            a.append(serviceUrl.getPort());
+        }
+        a.append(serviceUrl.getPath());
+        a.append("?");
+        if(serviceUrl.getQuery() != null) {
+            a.append(serviceUrl.getQuery());
+            if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) {
+                a.append("&");
+            }
+        }
+        return a.toString();
+    }
+
+    private String buildGetMapUrl() {
+        StringBuilder a = new StringBuilder();
+        a.append(buildRootUrl());
+        a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=");
+        a.append(commaSepLayerList());
+        a.append("&STYLES=&SRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}");
+
+        return a.toString();
+    }
+
+    private String commaSepLayerList() {
+        StringBuilder b = new StringBuilder();
+
+        if (selectedLayers != null) {
+            Iterator<LayerDetails> iterator = selectedLayers.iterator();
+            while (iterator.hasNext()) {
+                LayerDetails layerDetails = iterator.next();
+                b.append(layerDetails.ident);
+                if(iterator.hasNext()) {
+                    b.append(",");
+                }
+            }
+        }
+
+        return b.toString();
+    }
+
+    private void showError(String incomingData, Exception e) {
+        JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
+                tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+        System.err.println("Could not parse WMS layer list. Incoming data:");
+        System.err.println(incomingData);
+        e.printStackTrace();
+    }
+
+    private void attemptGetCapabilities(String serviceUrlStr) {
+        URL getCapabilitiesUrl = null;
+        try {
+            if (!Pattern.compile(".*GetCapabilities.*", Pattern.CASE_INSENSITIVE).matcher(serviceUrlStr).matches()) {
+                // If the url doesn't already have GetCapabilities, add it in
+                getCapabilitiesUrl = new URL(serviceUrlStr);
+                final String getCapabilitiesQuery = "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities";
+                if (getCapabilitiesUrl.getQuery() == null) {
+                    getCapabilitiesUrl = new URL(serviceUrlStr + "?" + getCapabilitiesQuery);
+                } else if (!getCapabilitiesUrl.getQuery().isEmpty() && !getCapabilitiesUrl.getQuery().endsWith("&")) {
+                    getCapabilitiesUrl = new URL(serviceUrlStr + "&" + getCapabilitiesQuery);
+                } else {
+                    getCapabilitiesUrl = new URL(serviceUrlStr + getCapabilitiesQuery);
+                }
+            } else {
+                // Otherwise assume it's a good URL and let the subsequent error
+                // handling systems deal with problems
+                getCapabilitiesUrl = new URL(serviceUrlStr);
+            }
+            serviceUrl = new URL(serviceUrlStr);
+        } catch (HeadlessException e) {
+            return;
+        } catch (MalformedURLException e) {
+            JOptionPane.showMessageDialog(this, tr("Invalid service URL."),
+                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+
+        String incomingData;
+        try {
+            System.out.println("GET "+getCapabilitiesUrl.toString());
+            URLConnection openConnection = getCapabilitiesUrl.openConnection();
+            InputStream inputStream = openConnection.getInputStream();
+            BufferedReader br = new BufferedReader(UTFInputStreamReader.create(inputStream, "UTF-8"));
+            String line;
+            StringBuilder ba = new StringBuilder();
+            while ((line = br.readLine()) != null) {
+                ba.append(line);
+                ba.append("\n");
+            }
+            incomingData = ba.toString();
+        } catch (IOException e) {
+            JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."),
+                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+
+        Document document;
+        try {
+            //System.out.println("WMS capabilities:\n"+incomingData+"\n");
+            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+            builderFactory.setValidating(false);
+            builderFactory.setNamespaceAware(true);
+            DocumentBuilder builder = builderFactory.newDocumentBuilder();
+            builder.setEntityResolver(new EntityResolver() {
+                @Override
+                public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+                    System.out.println("Ignoring DTD " + publicId + ", " + systemId);
+                    return new InputSource(new StringReader(""));
+                }
+            });
+            document = builder.parse(new InputSource(new StringReader(incomingData)));
+        } catch (ParserConfigurationException e) {
+            showError(incomingData, e);
+            return;
+        } catch (SAXException e) {
+            showError(incomingData, e);
+            return;
+        } catch (IOException e) {
+            showError(incomingData, e);
+            return;
+        }
+
+        // Some WMS service URLs specify a different base URL for their GetMap service
+        Element child = getChild(document.getDocumentElement(), "Capability");
+        child = getChild(child, "Request");
+        child = getChild(child, "GetMap");
+        child = getChild(child, "DCPType");
+        child = getChild(child, "HTTP");
+        child = getChild(child, "Get");
+        child = getChild(child, "OnlineResource");
+        if (child != null) {
+            String baseURL = child.getAttribute("xlink:href");
+            if (baseURL != null && !baseURL.equals(serviceUrlStr)) {
+                try {
+                    System.out.println("GetCapabilities specifies a different service URL: " + baseURL);
+                    serviceUrl = new URL(baseURL);
+                } catch (MalformedURLException e1) {
+                }
+            }
+        }
+
+        try {
+            treeRootNode.setUserObject(getCapabilitiesUrl.getHost());
+            Element capabilityElem = getChild(document.getDocumentElement(), "Capability");
+            List<Element> children = getChildren(capabilityElem, "Layer");
+            List<LayerDetails> layers = parseLayers(children, new HashSet<String>());
+            updateTreeList(layers);
+        } catch(Exception e) {
+            showError(incomingData, e);
+            return;
+        }
+    }
+
+    private void updateTreeList(List<LayerDetails> layers) {
+        addLayersToTreeData(treeRootNode, layers);
+        layerTree.expandRow(0);
+    }
+
+    private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) {
+        for (LayerDetails layerDetails : layers) {
+            DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
+            addLayersToTreeData(treeNode, layerDetails.children);
+            treeData.insertNodeInto(treeNode, parent, 0);
+        }
+    }
+
+    private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) {
+        List<LayerDetails> details = new LinkedList<LayerDetails>();
+        for (Element element : children) {
+            details.add(parseLayer(element, parentCrs));
+        }
+        return details;
+    }
+
+    private LayerDetails parseLayer(Element element, Set<String> parentCrs) {
+        String name = getChildContent(element, "Title", null, null);
+        String ident = getChildContent(element, "Name", null, null);
+
+        // The set of supported CRS/SRS for this layer
+        Set<String> crsList = new HashSet<String>();
+        // ...including this layer's already-parsed parent projections
+        crsList.addAll(parentCrs);
+
+        // Parse the CRS/SRS pulled out of this layer's XML element
+        // I think CRS and SRS are the same at this point
+        List<Element> crsChildren = getChildren(element, "CRS");
+        crsChildren.addAll(getChildren(element, "SRS"));
+        for (Element child : crsChildren) {
+            String crs = (String) getContent(child);
+            if(crs != null) {
+                String upperCase = crs.trim().toUpperCase();
+                crsList.add(upperCase);
+            }
+        }
+
+        // Check to see if any of the specified projections are supported by JOSM
+        boolean josmSupportsThisLayer = false;
+        for (String crs : crsList) {
+            josmSupportsThisLayer |= isProjSupported(crs);
+        }
+
+        Bounds bounds = null;
+        Element bboxElem = getChild(element, "EX_GeographicBoundingBox");
+        if(bboxElem != null) {
+            // Attempt to use EX_GeographicBoundingBox for bounding box
+            double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null));
+            double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null));
+            double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null));
+            double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null));
+            bounds = new Bounds(bot, left, top, right);
+        } else {
+            // If that's not available, try LatLonBoundingBox
+            bboxElem = getChild(element, "LatLonBoundingBox");
+            if(bboxElem != null) {
+                double left = Double.parseDouble(bboxElem.getAttribute("minx"));
+                double top = Double.parseDouble(bboxElem.getAttribute("maxy"));
+                double right = Double.parseDouble(bboxElem.getAttribute("maxx"));
+                double bot = Double.parseDouble(bboxElem.getAttribute("miny"));
+                bounds = new Bounds(bot, left, top, right);
+            }
+        }
+
+        List<Element> layerChildren = getChildren(element, "Layer");
+        List<LayerDetails> childLayers = parseLayers(layerChildren, crsList);
+
+        return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers);
+    }
+
+    private boolean isProjSupported(String crs) {
+        for (Projection proj : Projections.getProjections()) {
+            if (proj instanceof ProjectionSubPrefs) {
+                if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null)
+                    return true;
+            } else {
+                if (proj.toCode().equals(crs))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    public ImageryInfo getImageryInfo() {
+        ImageryInfo info = new ImageryInfo(menuName.getText(), resultingLayerField.getText());
+        if (ImageryType.TMS.equals(info.getImageryType())) {
+            TMSLayer.checkUrl(info.getUrl());
+        } else if (selectedLayers != null) {
+            HashSet<String> proj = new HashSet<String>();
+            for(LayerDetails l : selectedLayers) {
+                proj.addAll(l.getProjections());
+            }
+            info.setServerProjections(proj);
+        }
+        return info;
+    }
+
+    private static String getChildContent(Element parent, String name, String missing, String empty) {
+        Element child = getChild(parent, name);
+        if (child == null)
+            return missing;
+        else {
+            String content = (String) getContent(child);
+            return (content != null) ? content : empty;
+        }
+    }
+
+    private static Object getContent(Element element) {
+        NodeList nl = element.getChildNodes();
+        StringBuffer content = new StringBuffer();
+        for (int i = 0; i < nl.getLength(); i++) {
+            Node node = nl.item(i);
+            switch (node.getNodeType()) {
+            case Node.ELEMENT_NODE:
+                return node;
+            case Node.CDATA_SECTION_NODE:
+            case Node.TEXT_NODE:
+                content.append(node.getNodeValue());
+                break;
+            }
+        }
+        return content.toString().trim();
+    }
+
+    private static List<Element> getChildren(Element parent, String name) {
+        List<Element> retVal = new LinkedList<Element>();
+        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+            if (child instanceof Element && name.equals(child.getNodeName())) {
+                retVal.add((Element) child);
+            }
+        }
+        return retVal;
+    }
+
+    private static Element getChild(Element parent, String name) {
+        if (parent == null)
+            return null;
+        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+            if (child instanceof Element && name.equals(child.getNodeName()))
+                return (Element) child;
+        }
+        return null;
+    }
+
+    static class LayerDetails {
+
+        private String name;
+        private String ident;
+        private List<LayerDetails> children;
+        private Bounds bounds;
+        private Set<String> crsList;
+        private boolean supported;
+
+        public LayerDetails(String name, String ident, Set<String> crsList,
+                boolean supportedLayer, Bounds bounds,
+                List<LayerDetails> childLayers) {
+            this.name = name;
+            this.ident = ident;
+            this.supported = supportedLayer;
+            this.children = childLayers;
+            this.bounds = bounds;
+            this.crsList = crsList;
+        }
+
+        public boolean isSupported() {
+            return this.supported;
+        }
+
+        public Set<String> getProjections() {
+            return crsList;
+        }
+
+        @Override
+        public String toString() {
+            if(this.name == null || this.name.isEmpty())
+                return this.ident;
+            else
+                return this.name;
+        }
+
+    }
+
+    static class LayerTreeCellRenderer extends DefaultTreeCellRenderer {
+        @Override
+        public Component getTreeCellRendererComponent(JTree tree, Object value,
+                boolean sel, boolean expanded, boolean leaf, int row,
+                boolean hasFocus) {
+            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
+                    row, hasFocus);
+            DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
+            Object userObject = treeNode.getUserObject();
+            if (userObject instanceof LayerDetails) {
+                LayerDetails layer = (LayerDetails) userObject;
+                setEnabled(layer.isSupported());
+            }
+            return this;
+        }
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java	(revision 4968)
@@ -0,0 +1,1041 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.imagery;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JColorChooser;
+import javax.swing.JComboBox;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.JToolBar;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumnModel;
+
+import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
+import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
+import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
+import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
+import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
+import org.openstreetmap.josm.data.imagery.OffsetBookmark;
+import org.openstreetmap.josm.data.imagery.Shape;
+import org.openstreetmap.josm.gui.layer.ImageryLayer;
+import org.openstreetmap.josm.gui.layer.TMSLayer;
+import org.openstreetmap.josm.gui.layer.WMSLayer;
+import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.io.imagery.HTMLGrabber;
+import org.openstreetmap.josm.io.imagery.OffsetServer;
+import org.openstreetmap.josm.io.imagery.OsmosnimkiOffsetServer;
+import org.openstreetmap.josm.tools.ColorHelper;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class ImageryPreference extends DefaultTabPreferenceSetting {
+    public static class Factory implements PreferenceSettingFactory {
+        @Override
+        public PreferenceSetting createPreferenceSetting() {
+            return new ImageryPreference();
+        }
+    }
+    
+    private ImageryPreference() {
+        super("imagery", tr("Imagery Preferences"), tr("Modify list of imagery layers displayed in the Imagery menu"));
+    }
+    
+    private ImageryProvidersPanel imageryProviders;
+    private ImageryLayerInfo layerInfo;
+
+    // Common settings
+    private Color colFadeColor;
+    private JButton btnFadeColor;
+    private JSlider fadeAmount = new JSlider(0, 100);
+    private JComboBox sharpen;
+    private JCheckBox useOffsetServer;
+    private JTextField offsetServerUrl;
+
+    // WMS Settings
+    private JComboBox browser;
+    private JCheckBox overlapCheckBox;
+    private JSpinner spinEast;
+    private JSpinner spinNorth;
+    private JSpinner spinSimConn;
+
+    //TMS settings controls
+    private JCheckBox autozoomActive = new JCheckBox();
+    private JCheckBox autoloadTiles = new JCheckBox();
+    private JSpinner minZoomLvl;
+    private JSpinner maxZoomLvl;
+    private JCheckBox addToSlippyMapChosser = new JCheckBox();
+    private JTextField tilecacheDir = new JTextField();
+
+    private JPanel buildCommonSettingsPanel(final PreferenceTabbedPane gui) {
+        final JPanel p = new JPanel(new GridBagLayout());
+
+        this.colFadeColor = ImageryLayer.getFadeColor();
+        this.btnFadeColor = new JButton();
+
+        this.btnFadeColor.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                JColorChooser chooser = new JColorChooser(colFadeColor);
+                int answer = JOptionPane.showConfirmDialog(
+                        gui, chooser,
+                        tr("Choose a color for {0}", tr("imagery fade")),
+                        JOptionPane.OK_CANCEL_OPTION,
+                        JOptionPane.PLAIN_MESSAGE);
+                if (answer == JOptionPane.OK_OPTION) {
+                    colFadeColor = chooser.getColor();
+                    btnFadeColor.setBackground(colFadeColor);
+                    btnFadeColor.setText(ColorHelper.color2html(colFadeColor));
+                }
+            }
+        });
+
+        p.add(new JLabel(tr("Fade Color: ")), GBC.std());
+        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(this.btnFadeColor, GBC.eol().fill(GBC.HORIZONTAL));
+
+        p.add(new JLabel(tr("Fade amount: ")), GBC.std());
+        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(this.fadeAmount, GBC.eol().fill(GBC.HORIZONTAL));
+
+        this.sharpen = new JComboBox(new String[] {
+                tr("None"),
+                tr("Soft"),
+                tr("Strong")});
+        p.add(new JLabel(tr("Sharpen (requires layer re-add): ")));
+        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(this.sharpen, GBC.eol().fill(GBC.HORIZONTAL));
+
+        this.useOffsetServer = new JCheckBox(tr("Use offset server: "));
+        this.offsetServerUrl = new JTextField();
+        this.useOffsetServer.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent e) {
+                offsetServerUrl.setEnabled(useOffsetServer.isSelected());
+            }
+        });
+        offsetServerUrl.setEnabled(useOffsetServer.isSelected());
+        p.add(this.useOffsetServer, GBC.eol().fill(GBC.HORIZONTAL));
+        p.add(this.offsetServerUrl, GBC.eol().fill(GBC.HORIZONTAL));
+        return p;
+    }
+
+    private JPanel buildWMSSettingsPanel() {
+        final JPanel p = new JPanel(new GridBagLayout());
+        browser = new JComboBox(new String[] {
+                "webkit-image {0}",
+                "gnome-web-photo --mode=photo --format=png {0} /dev/stdout",
+                "gnome-web-photo-fixed {0}",
+        "webkit-image-gtk {0}"});
+        browser.setEditable(true);
+        p.add(new JLabel(tr("Downloader:")), GBC.eol().fill(GBC.HORIZONTAL));
+        p.add(browser);
+
+        // Overlap
+        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GBC.HORIZONTAL));
+
+        overlapCheckBox = new JCheckBox(tr("Overlap tiles"));
+        JLabel labelEast = new JLabel(tr("% of east:"));
+        JLabel labelNorth = new JLabel(tr("% of north:"));
+        spinEast = new JSpinner(new SpinnerNumberModel(WMSLayer.PROP_OVERLAP_EAST.get(), 1, 50, 1));
+        spinNorth = new JSpinner(new SpinnerNumberModel(WMSLayer.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
+
+        JPanel overlapPanel = new JPanel(new FlowLayout());
+        overlapPanel.add(overlapCheckBox);
+        overlapPanel.add(labelEast);
+        overlapPanel.add(spinEast);
+        overlapPanel.add(labelNorth);
+        overlapPanel.add(spinNorth);
+
+        p.add(overlapPanel);
+
+        // Simultaneous connections
+        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel labelSimConn = new JLabel(tr("Simultaneous connections"));
+        spinSimConn = new JSpinner(new SpinnerNumberModel(WMSLayer.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
+        JPanel overlapPanelSimConn = new JPanel(new FlowLayout(FlowLayout.LEFT));
+        overlapPanelSimConn.add(labelSimConn);
+        overlapPanelSimConn.add(spinSimConn);
+        p.add(overlapPanelSimConn, GBC.eol().fill(GBC.HORIZONTAL));
+
+        return p;
+    }
+
+    private JPanel buildTMSSettingsPanel() {
+        JPanel tmsTab = new JPanel(new GridBagLayout());
+
+        minZoomLvl = new JSpinner(new SpinnerNumberModel(TMSLayer.DEFAULT_MIN_ZOOM, TMSLayer.MIN_ZOOM, TMSLayer.MAX_ZOOM, 1));
+        maxZoomLvl = new JSpinner(new SpinnerNumberModel(TMSLayer.DEFAULT_MAX_ZOOM, TMSLayer.MIN_ZOOM, TMSLayer.MAX_ZOOM, 1));
+
+        tmsTab.add(new JLabel(tr("Auto zoom by default: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std());
+        tmsTab.add(autozoomActive, GBC.eol().fill(GBC.HORIZONTAL));
+
+        tmsTab.add(new JLabel(tr("Autoload tiles by default: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std());
+        tmsTab.add(autoloadTiles, GBC.eol().fill(GBC.HORIZONTAL));
+
+        tmsTab.add(new JLabel(tr("Min. zoom level: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std());
+        tmsTab.add(this.minZoomLvl, GBC.eol());
+
+        tmsTab.add(new JLabel(tr("Max. zoom level: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std());
+        tmsTab.add(this.maxZoomLvl, GBC.eol());
+
+        tmsTab.add(new JLabel(tr("Add to slippymap chooser: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std());
+        tmsTab.add(addToSlippyMapChosser, GBC.eol().fill(GBC.HORIZONTAL));
+
+        tmsTab.add(new JLabel(tr("Tile cache directory: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std());
+        tmsTab.add(tilecacheDir, GBC.eol().fill(GBC.HORIZONTAL));
+
+        return tmsTab;
+    }
+
+    private void addSettingsSection(final JPanel p, String name, JPanel section) {
+        addSettingsSection(p, name, section, GBC.eol());
+    }
+    private void addSettingsSection(final JPanel p, String name, JPanel section, GBC gbc) {
+        final JLabel lbl = new JLabel(name);
+        lbl.setFont(lbl.getFont().deriveFont(Font.BOLD));
+        p.add(lbl,GBC.std());
+        p.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
+        p.add(section, gbc.insets(20,5,0,10));
+    }
+
+    private Component buildSettingsPanel(final PreferenceTabbedPane gui) {
+        final JPanel p = new JPanel(new GridBagLayout());
+        p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        addSettingsSection(p, tr("Common Settings"), buildCommonSettingsPanel(gui));
+        addSettingsSection(p, tr("WMS Settings"), buildWMSSettingsPanel());
+        addSettingsSection(p, tr("TMS Settings"), buildTMSSettingsPanel(),
+                GBC.eol().fill(GBC.HORIZONTAL));
+
+        p.add(new JPanel(),GBC.eol().fill(GBC.BOTH));
+        return new JScrollPane(p);
+    }
+
+    @Override
+    public void addGui(final PreferenceTabbedPane gui) {
+        JPanel p = gui.createPreferenceTab(this);
+        JTabbedPane pane = new JTabbedPane();
+        layerInfo = new ImageryLayerInfo(ImageryLayerInfo.instance);
+        imageryProviders = new ImageryProvidersPanel(gui, layerInfo);
+        pane.add(imageryProviders);
+        pane.add(buildSettingsPanel(gui));
+        pane.add(new OffsetBookmarksPanel(gui));
+        loadSettings();
+        pane.setTitleAt(0, tr("Imagery providers"));
+        pane.setTitleAt(1, tr("Settings"));
+        pane.setTitleAt(2, tr("Offset bookmarks"));
+        p.add(pane,GBC.std().fill(GBC.BOTH));
+    }
+
+    public ImageryProvidersPanel getProvidersPanel() {
+        return imageryProviders;
+    }
+
+    private void loadSettings() {
+        // Common settings
+        this.btnFadeColor.setBackground(colFadeColor);
+        this.btnFadeColor.setText(ColorHelper.color2html(colFadeColor));
+        this.fadeAmount.setValue(ImageryLayer.PROP_FADE_AMOUNT.get());
+        this.sharpen.setSelectedIndex(Math.max(0, Math.min(2, ImageryLayer.PROP_SHARPEN_LEVEL.get())));
+        this.useOffsetServer.setSelected(OffsetServer.PROP_SERVER_ENABLED.get());
+        this.offsetServerUrl.setText(OsmosnimkiOffsetServer.PROP_SERVER_URL.get());
+
+        // WMS Settings
+        this.browser.setSelectedItem(HTMLGrabber.PROP_BROWSER.get());
+        this.overlapCheckBox.setSelected(WMSLayer.PROP_OVERLAP.get());
+        this.spinEast.setValue(WMSLayer.PROP_OVERLAP_EAST.get());
+        this.spinNorth.setValue(WMSLayer.PROP_OVERLAP_NORTH.get());
+        this.spinSimConn.setValue(WMSLayer.PROP_SIMULTANEOUS_CONNECTIONS.get());
+
+        // TMS Settings
+        this.autozoomActive.setSelected(TMSLayer.PROP_DEFAULT_AUTOZOOM.get());
+        this.autoloadTiles.setSelected(TMSLayer.PROP_DEFAULT_AUTOLOAD.get());
+        this.addToSlippyMapChosser.setSelected(TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get());
+        this.maxZoomLvl.setValue(TMSLayer.getMaxZoomLvl(null));
+        this.minZoomLvl.setValue(TMSLayer.getMinZoomLvl(null));
+        this.tilecacheDir.setText(TMSLayer.PROP_TILECACHE_DIR.get());
+    }
+
+    @Override
+    public boolean ok() {
+        boolean restartRequired = false;
+        layerInfo.save();
+        ImageryLayerInfo.instance.clear();
+        ImageryLayerInfo.instance.load();
+        Main.main.menu.imageryMenu.refreshImageryMenu();
+        Main.main.menu.imageryMenu.refreshOffsetMenu();
+        OffsetBookmark.saveBookmarks();
+
+        WMSLayer.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
+        WMSLayer.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
+        WMSLayer.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
+        WMSLayer.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
+
+        HTMLGrabber.PROP_BROWSER.put(browser.getEditor().getItem().toString());
+        OffsetServer.PROP_SERVER_ENABLED.put(useOffsetServer.isSelected());
+        OsmosnimkiOffsetServer.PROP_SERVER_URL.put(offsetServerUrl.getText());
+
+        if (TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get() != this.addToSlippyMapChosser.isSelected()) {
+            restartRequired = true;
+        }
+        TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.put(this.addToSlippyMapChosser.isSelected());
+        TMSLayer.PROP_DEFAULT_AUTOZOOM.put(this.autozoomActive.isSelected());
+        TMSLayer.PROP_DEFAULT_AUTOLOAD.put(this.autoloadTiles.isSelected());
+        TMSLayer.setMaxZoomLvl((Integer)this.maxZoomLvl.getValue());
+        TMSLayer.setMinZoomLvl((Integer)this.minZoomLvl.getValue());
+        TMSLayer.PROP_TILECACHE_DIR.put(this.tilecacheDir.getText());
+
+        ImageryLayer.PROP_FADE_AMOUNT.put(this.fadeAmount.getValue());
+        ImageryLayer.setFadeColor(this.colFadeColor);
+        ImageryLayer.PROP_SHARPEN_LEVEL.put(sharpen.getSelectedIndex());
+
+        return restartRequired;
+    }
+
+
+    /**
+     * Updates a server URL in the preferences dialog. Used by plugins.
+     *
+     * @param server
+     *            The server name
+     * @param url
+     *            The server URL
+     */
+    public void setServerUrl(String server, String url) {
+        for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) {
+            if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString())) {
+                imageryProviders.activeModel.setValueAt(url, i, 1);
+                return;
+            }
+        }
+        imageryProviders.activeModel.addRow(new String[] { server, url });
+    }
+
+    /**
+     * Gets a server URL in the preferences dialog. Used by plugins.
+     *
+     * @param server
+     *            The server name
+     * @return The server URL
+     */
+    public String getServerUrl(String server) {
+        for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) {
+            if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString()))
+                return imageryProviders.activeModel.getValueAt(i, 1).toString();
+        }
+        return null;
+    }
+
+    public static class ImageryProvidersPanel extends JPanel {
+        // Public JTables and JMapViewer
+        public final JTable activeTable;
+        public final JTable defaultTable;
+        public final JMapViewer defaultMap;
+
+        // Public models
+        public final ImageryLayerTableModel activeModel;
+        public final ImageryDefaultLayerTableModel defaultModel;
+
+        // Public JToolbars
+        public final JToolBar activeToolbar;
+        public final JToolBar middleToolbar;
+        public final JToolBar defaultToolbar;
+
+        // Private members
+        private final PreferenceTabbedPane gui;
+        private final ImageryLayerInfo layerInfo;
+
+        private static class ImageryTableCellRenderer extends DefaultTableCellRenderer {
+
+            private List<ImageryInfo> layers;
+
+            public ImageryTableCellRenderer(List<ImageryInfo> layers) {
+                this.layers = layers;
+            }
+
+            @Override
+            public Component getTableCellRendererComponent(JTable table, Object value, boolean
+                    isSelected, boolean hasFocus, int row, int column) {
+                JLabel label = (JLabel) super.getTableCellRendererComponent(
+                        table, value, isSelected, hasFocus, row, column);
+                String t = value.toString();
+                label.setBackground(Main.pref.getUIColor("Table.background"));
+                if (isSelected) {
+                    label.setForeground(Main.pref.getUIColor("Table.foreground"));
+                }
+                for(ImageryInfo l : layers)
+                {
+                    if(l.getExtendedUrl().equals(t)) {
+                        label.setBackground(Main.pref.getColor(
+                                marktr("Imagery Background: Default"),
+                                new Color(200,255,200)));
+                        break;
+                    }
+                }
+                return label;
+            }
+        }
+
+        public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) {
+            super(new GridBagLayout());
+            this.gui = gui;
+            this.layerInfo = layerInfoArg;
+            this.activeModel = new ImageryLayerTableModel();
+
+            activeTable = new JTable(activeModel) {
+                @Override
+                public String getToolTipText(MouseEvent e) {
+                    java.awt.Point p = e.getPoint();
+                    return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
+                }
+            };
+
+            defaultModel = new ImageryDefaultLayerTableModel();
+            defaultTable = new JTable(defaultModel) {
+                @Override
+                public String getToolTipText(MouseEvent e) {
+                    java.awt.Point p = e.getPoint();
+                    return (String) defaultModel.getValueAt(rowAtPoint(p), columnAtPoint(p));
+                }
+            };
+
+            defaultModel.addTableModelListener(
+                    new TableModelListener() {
+                        @Override
+                        public void tableChanged(TableModelEvent e) {
+                            activeTable.repaint();
+                        }
+                    }
+                    );
+
+            activeModel.addTableModelListener(
+                    new TableModelListener() {
+                        @Override
+                        public void tableChanged(TableModelEvent e) {
+                            defaultTable.repaint();
+                        }
+                    }
+                    );
+
+            TableColumnModel mod = defaultTable.getColumnModel();
+            mod.getColumn(2).setPreferredWidth(800);
+            mod.getColumn(2).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getLayers()));
+            mod.getColumn(1).setPreferredWidth(400);
+            mod.getColumn(0).setPreferredWidth(50);
+
+            mod = activeTable.getColumnModel();
+            mod.getColumn(1).setPreferredWidth(800);
+            mod.getColumn(1).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getDefaultLayers()));
+            mod.getColumn(0).setPreferredWidth(200);
+
+            RemoveEntryAction remove = new RemoveEntryAction();
+            activeTable.getSelectionModel().addListSelectionListener(remove);
+
+            add(new JLabel(tr("Available default entries:")), GBC.eol().insets(5, 5, 0, 0));
+            // Add default item list
+            JScrollPane scrolldef = new JScrollPane(defaultTable);
+            scrolldef.setPreferredSize(new Dimension(200, 200));
+            add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
+
+            // Add default item map
+            defaultMap = new JMapViewer();
+            defaultMap.setZoomContolsVisible(false);
+            defaultMap.setMinimumSize(new Dimension(100, 200));
+            add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
+
+            defaultTable.getSelectionModel().addListSelectionListener(new DefListSelectionListener());
+
+            defaultToolbar = new JToolBar(JToolBar.VERTICAL);
+            defaultToolbar.setFloatable(false);
+            defaultToolbar.setBorderPainted(false);
+            defaultToolbar.setOpaque(false);
+            defaultToolbar.add(new ReloadAction());
+            add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
+
+            ActivateAction activate = new ActivateAction();
+            defaultTable.getSelectionModel().addListSelectionListener(activate);
+            JButton btnActivate = new JButton(activate);
+
+            middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
+            middleToolbar.setFloatable(false);
+            middleToolbar.setBorderPainted(false);
+            middleToolbar.setOpaque(false);
+            middleToolbar.add(btnActivate);
+            add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 15, 5, 0));
+
+            add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+
+            add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0));
+            JScrollPane scroll = new JScrollPane(activeTable);
+            add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5));
+            scroll.setPreferredSize(new Dimension(200, 200));
+
+            activeToolbar = new JToolBar(JToolBar.VERTICAL);
+            activeToolbar.setFloatable(false);
+            activeToolbar.setBorderPainted(false);
+            activeToolbar.setOpaque(false);
+            activeToolbar.add(new NewEntryAction());
+            //activeToolbar.add(edit); TODO
+            activeToolbar.add(remove);
+            add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5));
+
+        }
+
+        // Listener of default providers list selection
+        private final class DefListSelectionListener implements ListSelectionListener {
+            // The current drawn rectangles and polygons
+            private final Map<Integer, MapRectangle> mapRectangles;
+            private final Map<Integer, List<MapPolygon>> mapPolygons;
+
+            private DefListSelectionListener() {
+                this.mapRectangles = new HashMap<Integer, MapRectangle>();
+                this.mapPolygons = new HashMap<Integer, List<MapPolygon>>();
+            }
+
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                // First index is set to -1 when the list is refreshed, so discard all map rectangles and polygons
+                if (e.getFirstIndex() == -1) {
+                    defaultMap.removeAllMapRectangles();
+                    defaultMap.removeAllMapPolygons();
+                    mapRectangles.clear();
+                    mapPolygons.clear();
+                    // Only process complete (final) selection events
+                } else if (!e.getValueIsAdjusting()) {
+                    for (int i = e.getFirstIndex(); i<=e.getLastIndex(); i++) {
+                        updateBoundsAndShapes(i);
+                    }
+                    // If needed, adjust map to show all map rectangles and polygons
+                    if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
+                        defaultMap.setDisplayToFitMapElements(false, true, true);
+                        defaultMap.zoomOut();
+                    }
+                }
+            }
+
+            private void updateBoundsAndShapes(int i) {
+                ImageryBounds bounds = defaultModel.getRow(i).getBounds();
+                if (bounds != null) {
+                    List<Shape> shapes = bounds.getShapes();
+                    if (shapes != null && !shapes.isEmpty()) {
+                        if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
+                            if (!mapPolygons.containsKey(i)) {
+                                List<MapPolygon> list = new ArrayList<MapPolygon>();
+                                mapPolygons.put(i, list);
+                                // Add new map polygons
+                                for (Shape shape : shapes) {
+                                    MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
+                                    list.add(polygon);
+                                    defaultMap.addMapPolygon(polygon);
+                                }
+                            }
+                        } else if (mapPolygons.containsKey(i)) {
+                            // Remove previously drawn map polygons
+                            for (MapPolygon polygon : mapPolygons.get(i)) {
+                                defaultMap.removeMapPolygon(polygon);
+                            }
+                            mapPolygons.remove(i);
+                        }
+                        // Only display bounds when no polygons (shapes) are defined for this provider
+                    } else {
+                        if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
+                            if (!mapRectangles.containsKey(i)) {
+                                // Add new map rectangle
+                                Coordinate topLeft = new Coordinate(bounds.getMax().lat(), bounds.getMin().lon());
+                                Coordinate bottomRight = new Coordinate(bounds.getMin().lat(), bounds.getMax().lon());
+                                MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight);
+                                mapRectangles.put(i, rectangle);
+                                defaultMap.addMapRectangle(rectangle);
+                            }
+                        } else if (mapRectangles.containsKey(i)) {
+                            // Remove previously drawn map rectangle
+                            defaultMap.removeMapRectangle(mapRectangles.get(i));
+                            mapRectangles.remove(i);
+                        }
+                    }
+                }
+            }
+        }
+
+        private class NewEntryAction extends AbstractAction {
+            public NewEntryAction() {
+                putValue(NAME, tr("New"));
+                putValue(SHORT_DESCRIPTION, tr("Add a new WMS/TMS entry by entering the URL"));
+                putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
+            }
+
+            public void actionPerformed(ActionEvent evt) {
+                final AddWMSLayerPanel p = new AddWMSLayerPanel();
+                // This code snippet allows to resize the JOptionPane (fix #6090)
+                p.addHierarchyListener(new HierarchyListener() {
+                    public void hierarchyChanged(HierarchyEvent e) {
+                        Window window = SwingUtilities.getWindowAncestor(p);
+                        if (window instanceof Dialog) {
+                            Dialog dialog = (Dialog)window;
+                            if (!dialog.isResizable()) {
+                                dialog.setResizable(true);
+                                dialog.setMinimumSize(new Dimension(250, 350));
+                            }
+                        }
+                    }
+                });
+                int answer = JOptionPane.showConfirmDialog(
+                        gui, p,
+                        tr("Add Imagery URL"),
+                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
+                if (answer == JOptionPane.OK_OPTION) {
+                    try {
+                        activeModel.addRow(p.getImageryInfo());
+                    } catch (IllegalArgumentException ex) {
+                        if (ex.getMessage() == null || ex.getMessage().isEmpty())
+                            throw ex;
+                        else {
+                            JOptionPane.showMessageDialog(Main.parent,
+                                    ex.getMessage(), tr("Error"),
+                                    JOptionPane.ERROR_MESSAGE);
+                        }
+                    }
+                }
+            }
+        }
+
+        private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
+
+            public RemoveEntryAction() {
+                putValue(NAME, tr("Remove"));
+                putValue(SHORT_DESCRIPTION, tr("Remove entry"));
+                putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
+                updateEnabledState();
+            }
+
+            protected void updateEnabledState() {
+                setEnabled(activeTable.getSelectedRowCount() > 0);
+            }
+
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                updateEnabledState();
+            }
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                Integer i;
+                while ((i = activeTable.getSelectedRow()) != -1) {
+                    activeModel.removeRow(i);
+                }
+            }
+        }
+
+        private class ActivateAction extends AbstractAction implements ListSelectionListener {
+            public ActivateAction() {
+                putValue(NAME, tr("Activate"));
+                putValue(SHORT_DESCRIPTION, tr("copy selected defaults"));
+                putValue(SMALL_ICON, ImageProvider.get("preferences", "activate-down"));
+            }
+
+            protected void updateEnabledState() {
+                setEnabled(defaultTable.getSelectedRowCount() > 0);
+            }
+
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                updateEnabledState();
+            }
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                int[] lines = defaultTable.getSelectedRows();
+                if (lines.length == 0) {
+                    JOptionPane.showMessageDialog(
+                            gui,
+                            tr("Please select at least one row to copy."),
+                            tr("Information"),
+                            JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+
+                Set<String> acceptedEulas = new HashSet<String>();
+
+                outer: for (int i = 0; i < lines.length; i++) {
+                    ImageryInfo info = defaultModel.getRow(lines[i]);
+
+                    // Check if an entry with exactly the same values already
+                    // exists
+                    for (int j = 0; j < activeModel.getRowCount(); j++) {
+                        if (info.equalsBaseValues(activeModel.getRow(j))) {
+                            // Select the already existing row so the user has
+                            // some feedback in case an entry exists
+                            activeTable.getSelectionModel().setSelectionInterval(j, j);
+                            activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true));
+                            continue outer;
+                        }
+                    }
+
+                    String eulaURL = info.getEulaAcceptanceRequired();
+                    // If set and not already accepted, ask for EULA acceptance
+                    if (eulaURL != null && !acceptedEulas.contains(eulaURL)) {
+                        if (confirmEulaAcceptance(gui, eulaURL)) {
+                            acceptedEulas.add(eulaURL);
+                        } else {
+                            continue outer;
+                        }
+                    }
+
+                    activeModel.addRow(new ImageryInfo(info));
+                    int lastLine = activeModel.getRowCount() - 1;
+                    activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
+                    activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true));
+                }
+            }
+        }
+
+        private class ReloadAction extends AbstractAction {
+            public ReloadAction() {
+                putValue(SHORT_DESCRIPTION, tr("reload defaults"));
+                putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
+            }
+
+            public void actionPerformed(ActionEvent evt) {
+                layerInfo.loadDefaults(true);
+                defaultModel.fireTableDataChanged();
+            }
+        }
+
+        /**
+         * The table model for imagery layer list
+         */
+        public class ImageryLayerTableModel extends DefaultTableModel {
+            public ImageryLayerTableModel() {
+                setColumnIdentifiers(new String[] { tr("Menu Name"), tr("Imagery URL")});
+            }
+
+            public ImageryInfo getRow(int row) {
+                return layerInfo.getLayers().get(row);
+            }
+
+            public void addRow(ImageryInfo i) {
+                layerInfo.add(i);
+                int p = getRowCount() - 1;
+                fireTableRowsInserted(p, p);
+            }
+
+            @Override
+            public void removeRow(int i) {
+                layerInfo.remove(getRow(i));
+                fireTableRowsDeleted(i, i);
+            }
+
+            @Override
+            public int getRowCount() {
+                return layerInfo.getLayers().size();
+            }
+
+            @Override
+            public Object getValueAt(int row, int column) {
+                ImageryInfo info = layerInfo.getLayers().get(row);
+                switch (column) {
+                case 0:
+                    return info.getName();
+                case 1:
+                    return info.getExtendedUrl();
+                default:
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+            }
+
+            @Override
+            public void setValueAt(Object o, int row, int column) {
+                ImageryInfo info = layerInfo.getLayers().get(row);
+                switch (column) {
+                case 0:
+                    info.setName((String) o);
+                    break;
+                case 1:
+                    info.setExtendedUrl((String)o);
+                    break;
+                default:
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+            }
+
+            @Override
+            public boolean isCellEditable(int row, int column) {
+                return true;
+            }
+        }
+
+        /**
+         * The table model for the default imagery layer list
+         */
+        public class ImageryDefaultLayerTableModel extends DefaultTableModel {
+            public ImageryDefaultLayerTableModel() {
+                setColumnIdentifiers(new String[]{"", tr("Menu Name (Default)"), tr("Imagery URL (Default)")});
+            }
+
+            public ImageryInfo getRow(int row) {
+                return layerInfo.getDefaultLayers().get(row);
+            }
+
+            @Override
+            public int getRowCount() {
+                return layerInfo.getDefaultLayers().size();
+            }
+
+            @Override
+            public Object getValueAt(int row, int column) {
+                ImageryInfo info = layerInfo.getDefaultLayers().get(row);
+                switch (column) {
+                case 0:
+                    return info.getCountryCode();
+                case 1:
+                    return info.getName();
+                case 2:
+                    return info.getExtendedUrl();
+                }
+                return null;
+            }
+
+            @Override
+            public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+        }
+
+        private boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
+            URL url = null;
+            try {
+                url = new URL(eulaUrl.replaceAll("\\{lang\\}", Locale.getDefault().toString()));
+                JEditorPane htmlPane = null;
+                try {
+                    htmlPane = new JEditorPane(url);
+                } catch (IOException e1) {
+                    // give a second chance with a default Locale 'en'
+                    try {
+                        url = new URL(eulaUrl.replaceAll("\\{lang\\}", "en"));
+                        htmlPane = new JEditorPane(url);
+                    } catch (IOException e2) {
+                        JOptionPane.showMessageDialog(gui ,tr("EULA license URL not available: {0}", eulaUrl));
+                        return false;
+                    }
+                }
+                Box box = Box.createVerticalBox();
+                htmlPane.setEditable(false);
+                JScrollPane scrollPane = new JScrollPane(htmlPane);
+                scrollPane.setPreferredSize(new Dimension(400, 400));
+                box.add(scrollPane);
+                int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"), JOptionPane.YES_NO_OPTION,
+                        JOptionPane.WARNING_MESSAGE);
+                if (option == JOptionPane.YES_OPTION)
+                    return true;
+            } catch (MalformedURLException e2) {
+                JOptionPane.showMessageDialog(gui ,tr("Malformed URL for the EULA licence: {0}", eulaUrl));
+            }
+            return false;
+        }
+    }
+
+    static class OffsetBookmarksPanel extends JPanel {
+        List<OffsetBookmark> bookmarks = OffsetBookmark.allBookmarks;
+        OffsetsBookmarksModel model = new OffsetsBookmarksModel();
+
+        public OffsetBookmarksPanel(final PreferenceTabbedPane gui) {
+            super(new GridBagLayout());
+            final JTable list = new JTable(model) {
+                @Override
+                public String getToolTipText(MouseEvent e) {
+                    java.awt.Point p = e.getPoint();
+                    return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
+                }
+            };
+            JScrollPane scroll = new JScrollPane(list);
+            add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
+            scroll.setPreferredSize(new Dimension(200, 200));
+
+            TableColumnModel mod = list.getColumnModel();
+            mod.getColumn(0).setPreferredWidth(150);
+            mod.getColumn(1).setPreferredWidth(200);
+            mod.getColumn(2).setPreferredWidth(300);
+            mod.getColumn(3).setPreferredWidth(150);
+            mod.getColumn(4).setPreferredWidth(150);
+
+            JPanel buttonPanel = new JPanel(new FlowLayout());
+
+            JButton add = new JButton(tr("Add"));
+            buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
+            add.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    OffsetBookmark b = new OffsetBookmark(Main.getProjection(),"","",0,0);
+                    model.addRow(b);
+                }
+            });
+
+            JButton delete = new JButton(tr("Delete"));
+            buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
+            delete.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    if (list.getSelectedRow() == -1) {
+                        JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
+                    } else {
+                        Integer i;
+                        while ((i = list.getSelectedRow()) != -1) {
+                            model.removeRow(i);
+                        }
+                    }
+                }
+            });
+
+            add(buttonPanel,GBC.eol());
+        }
+
+        /**
+         * The table model for imagery offsets list
+         */
+        class OffsetsBookmarksModel extends DefaultTableModel {
+            public OffsetsBookmarksModel() {
+                setColumnIdentifiers(new String[] { tr("Projection"),  tr("Layer"), tr("Name"), tr("Easting"), tr("Northing"),});
+            }
+
+            public OffsetBookmark getRow(int row) {
+                return bookmarks.get(row);
+            }
+
+            public void addRow(OffsetBookmark i) {
+                bookmarks.add(i);
+                int p = getRowCount() - 1;
+                fireTableRowsInserted(p, p);
+            }
+
+            @Override
+            public void removeRow(int i) {
+                bookmarks.remove(getRow(i));
+                fireTableRowsDeleted(i, i);
+            }
+
+            @Override
+            public int getRowCount() {
+                return bookmarks.size();
+            }
+
+            @Override
+            public Object getValueAt(int row, int column) {
+                OffsetBookmark info = bookmarks.get(row);
+                switch (column) {
+                case 0:
+                    if (info.proj == null) return "";
+                    return info.proj.toString();
+                case 1:
+                    return info.layerName;
+                case 2:
+                    return info.name;
+                case 3:
+                    return info.dx;
+                case 4:
+                    return info.dy;
+                default:
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+            }
+
+            @Override
+            public void setValueAt(Object o, int row, int column) {
+                OffsetBookmark info = bookmarks.get(row);
+                switch (column) {
+                case 1:
+                    info.layerName = o.toString();
+                    break;
+                case 2:
+                    info.name = o.toString();
+                    break;
+                case 3:
+                    info.dx = Double.parseDouble((String) o);
+                    break;
+                case 4:
+                    info.dy = Double.parseDouble((String) o);
+                    break;
+                default:
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+            }
+
+            @Override
+            public boolean isCellEditable(int row, int column) {
+                return column >= 1;
+            }
+        }
+    }
+
+    public static void initialize() {
+        ImageryLayerInfo.instance.clear();
+        ImageryLayerInfo.instance.loadDefaults(false);
+        ImageryLayerInfo.instance.load();
+        OffsetBookmark.loadBookmarks();
+        Main.main.menu.imageryMenu.refreshImageryMenu();
+        Main.main.menu.imageryMenu.refreshOffsetMenu();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/map/BackupPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/map/BackupPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/map/BackupPreference.java	(revision 4968)
@@ -0,0 +1,126 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.map;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.data.AutosaveTask;
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
+import org.openstreetmap.josm.tools.GBC;
+
+public class BackupPreference implements SubPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        @Override
+        public BackupPreference createPreferenceSetting() {
+            return new BackupPreference();
+        }
+    }
+    private static final BooleanProperty PROP_KEEP_BACKUP = new BooleanProperty("save.keepbackup", false);
+    private JCheckBox keepBackup;
+    private JCheckBox autosave;
+    private final JTextField autosaveInterval = new JTextField(8);
+    private final JTextField backupPerLayer = new JTextField(8);
+
+    @Override
+    public void addGui(PreferenceTabbedPane gui) {
+        JPanel panel = new VerticallyScrollablePanel();
+        panel.setLayout(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        autosave = new JCheckBox(tr("Auto save enabled"));
+        autosave.setSelected(AutosaveTask.PROP_AUTOSAVE_ENABLED.get());
+        panel.add(autosave, GBC.eol());
+
+        final JLabel autosaveIntervalLabel = new JLabel(tr("Auto save interval (seconds)"));
+        panel.add(autosaveIntervalLabel, GBC.std().insets(60,0,0,0));
+        autosaveInterval.setText(Integer.toString(AutosaveTask.PROP_INTERVAL.get()));
+        autosaveInterval.setToolTipText(tr("Default value: {0}", AutosaveTask.PROP_INTERVAL.getDefaultValue()));
+        autosaveInterval.setMinimumSize(autosaveInterval.getPreferredSize());
+        panel.add(autosaveInterval, GBC.eol().insets(5,0,0,5));
+
+        final JLabel backupPerLayerLabel = new JLabel(tr("Auto saved files per layer"));
+        panel.add(backupPerLayerLabel, GBC.std().insets(60,0,0,0));
+        backupPerLayer.setText(Integer.toString(AutosaveTask.PROP_FILES_PER_LAYER.get()));
+        backupPerLayer.setToolTipText(tr("Default value: {0}", AutosaveTask.PROP_FILES_PER_LAYER.getDefaultValue()));
+        backupPerLayer.setMinimumSize(backupPerLayer.getPreferredSize());
+        panel.add(backupPerLayer, GBC.eol().insets(5,0,0,10));
+
+        panel.add(new HtmlPanel(
+            tr("<i>(Autosave stores the changed data layers in periodic intervals. " +
+                "The backups are saved in JOSM''s preference folder. " +
+                "In case of a crash, JOSM tries to recover the unsaved changes " +
+                "on next start.)</i>")),
+            GBC.eop().fill(GBC.HORIZONTAL).insets(5,0,0,10));
+
+        panel.add(new JSeparator(), GBC.eop().fill(GBC.HORIZONTAL));
+
+        keepBackup = new JCheckBox(tr("Keep backup files when saving data layers"));
+        keepBackup.setSelected(PROP_KEEP_BACKUP.get());
+        keepBackup.setToolTipText(tr("When saving, keep backup files ending with a ~"));
+        panel.add(keepBackup, GBC.eop());
+
+        panel.add(new HtmlPanel(
+            tr("<i>(JOSM can keep a backup file when saving data layers. "+
+                "It appends ''~'' to the file name and saves it in the same folder.)</i>")),
+            GBC.eop().fill(GBC.HORIZONTAL).insets(5,0,0,0));
+
+        ActionListener autosaveEnabled = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                boolean enabled = autosave.isSelected();
+                autosaveIntervalLabel.setEnabled(enabled);
+                autosaveInterval.setEnabled(enabled);
+                backupPerLayerLabel.setEnabled(enabled);
+                backupPerLayer.setEnabled(enabled);
+            }
+        };
+        autosave.addActionListener(autosaveEnabled);
+        autosaveEnabled.actionPerformed(null);
+
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+        JScrollPane sp = new JScrollPane(panel);
+        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+
+        gui.getMapPreference().mapcontent.addTab(tr("File backup"), null, sp, tr("Configure whether to create backup files"));
+    }
+
+    @Override
+    public boolean ok() {
+        boolean restartRequired = false;
+        PROP_KEEP_BACKUP.put(keepBackup.isSelected());
+
+        restartRequired |= AutosaveTask.PROP_AUTOSAVE_ENABLED.put(autosave.isSelected());
+        restartRequired |= AutosaveTask.PROP_INTERVAL.parseAndPut(autosaveInterval.getText());
+        AutosaveTask.PROP_FILES_PER_LAYER.parseAndPut(backupPerLayer.getText());
+        return restartRequired;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getMapPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java	(revision 4968)
@@ -0,0 +1,283 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.map;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.TreeSet;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SourceEditor;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
+import org.openstreetmap.josm.gui.preferences.SourceEntry;
+import org.openstreetmap.josm.gui.preferences.SourceProvider;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.Predicate;
+import org.openstreetmap.josm.tools.Utils;
+
+public class MapPaintPreference implements SubPreferenceSetting {
+    private SourceEditor sources;
+    private JCheckBox enableIconDefault;
+
+    private static final List<SourceProvider> styleSourceProviders = new ArrayList<SourceProvider>();
+
+    public static final boolean registerSourceProvider(SourceProvider provider) {
+        if (provider != null)
+            return styleSourceProviders.add(provider);
+        return false;
+    }
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new MapPaintPreference();
+        }
+    }
+
+    public void addGui(final PreferenceTabbedPane gui) {
+        enableIconDefault = new JCheckBox(tr("Enable built-in icon defaults"),
+                Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
+
+        sources = new MapPaintSourceEditor();
+
+        final JPanel panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+
+        panel.add(sources, GBC.eol().fill(GBC.BOTH));
+        panel.add(enableIconDefault, GBC.eol().insets(11,2,5,0));
+
+        gui.getMapPreference().mapcontent.addTab(tr("Map Paint Styles"), panel);
+
+        // this defers loading of style sources to the first time the tab
+        // with the map paint preferences is selected by the user
+        //
+        gui.getMapPreference().mapcontent.addChangeListener(
+                new ChangeListener() {
+                    public void stateChanged(ChangeEvent e) {
+                        if (gui.getMapPreference().mapcontent.getSelectedComponent() == panel) {
+                            sources.initiallyLoadAvailableSources();
+                        }
+                    }
+                }
+                );
+    }
+
+    static class MapPaintSourceEditor extends SourceEditor {
+
+        final private String iconpref = "mappaint.icon.sources";
+
+        public MapPaintSourceEditor() {
+            super(true, "http://josm.openstreetmap.de/styles", styleSourceProviders);
+        }
+
+        @Override
+        public Collection<? extends SourceEntry> getInitialSourcesList() {
+            return MapPaintPrefHelper.INSTANCE.get();
+        }
+
+        @Override
+        public boolean finish() {
+            List<SourceEntry> activeStyles = activeSourcesModel.getSources();
+
+            boolean changed = MapPaintPrefHelper.INSTANCE.put(activeStyles);
+
+            if (tblIconPaths != null) {
+                List<String> iconPaths = iconPathsModel.getIconPaths();
+
+                if (!iconPaths.isEmpty()) {
+                    if (Main.pref.putCollection(iconpref, iconPaths)) {
+                        changed = true;
+                    }
+                } else if (Main.pref.putCollection(iconpref, null)) {
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        @Override
+        public Collection<ExtendedSourceEntry> getDefault() {
+            return MapPaintPrefHelper.INSTANCE.getDefault();
+        }
+
+        @Override
+        public Collection<String> getInitialIconPathsList() {
+            return Main.pref.getCollection(iconpref, null);
+        }
+
+        @Override
+        public String getStr(I18nString ident) {
+            switch (ident) {
+            case AVAILABLE_SOURCES:
+                return tr("Available styles:");
+            case ACTIVE_SOURCES:
+                return tr("Active styles:");
+            case NEW_SOURCE_ENTRY_TOOLTIP:
+                return tr("Add a new style by entering filename or URL");
+            case NEW_SOURCE_ENTRY:
+                return tr("New style entry:");
+            case REMOVE_SOURCE_TOOLTIP:
+                return tr("Remove the selected styles from the list of active styles");
+            case EDIT_SOURCE_TOOLTIP:
+                return tr("Edit the filename or URL for the selected active style");
+            case ACTIVATE_TOOLTIP:
+                return tr("Add the selected available styles to the list of active styles");
+            case RELOAD_ALL_AVAILABLE:
+                return marktr("Reloads the list of available styles from ''{0}''");
+            case LOADING_SOURCES_FROM:
+                return marktr("Loading style sources from ''{0}''");
+            case FAILED_TO_LOAD_SOURCES_FROM:
+                return marktr("<html>Failed to load the list of style sources from<br>"
+                        + "''{0}''.<br>"
+                        + "<br>"
+                        + "Details (untranslated):<br>{1}</html>");
+            case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC:
+                return "/Preferences/Styles#FailedToLoadStyleSources";
+            case ILLEGAL_FORMAT_OF_ENTRY:
+                return marktr("Warning: illegal format of entry in style list ''{0}''. Got ''{1}''");
+            default: throw new AssertionError();
+            }
+        }
+
+    }
+
+    public boolean ok() {
+        boolean reload = Main.pref.put("mappaint.icon.enable-defaults", enableIconDefault.isSelected());
+        reload |= sources.finish();
+        if (reload) {
+            MapPaintStyles.readFromPreferences();
+        }
+        if (Main.isDisplayingMapView())
+        {
+            MapPaintStyles.getStyles().clearCached();
+        }
+        return false;
+    }
+
+    /**
+     * Initialize the styles
+     */
+    public static void initialize() {
+        MapPaintStyles.readFromPreferences();
+    }
+
+    public static class MapPaintPrefHelper extends SourceEditor.SourcePrefHelper {
+
+        public final static MapPaintPrefHelper INSTANCE = new MapPaintPrefHelper();
+
+        public MapPaintPrefHelper() {
+            super("mappaint.style.sources-list");
+        }
+
+        @Override
+        public List<SourceEntry> get() {
+            List<SourceEntry> ls = super.get();
+            if (insertNewDefaults(ls)) {
+                put(ls);
+            }
+            return ls;
+        }
+
+        /**
+         * If the selection of default styles changes in future releases, add
+         * the new entries to the user-configured list. Remember the known URLs,
+         * so an item that was deleted explicitly is not added again.
+         */
+        private boolean insertNewDefaults(List<SourceEntry> list) {
+            boolean changed = false;
+
+            Collection<String> knownDefaults = new TreeSet<String>(Main.pref.getCollection("mappaint.style.known-defaults"));
+
+            Collection<ExtendedSourceEntry> defaults = getDefault();
+            int insertionIdx = 0;
+            for (final SourceEntry def : defaults) {
+                int i = Utils.indexOf(list,
+                        new Predicate<SourceEntry>() {
+                    @Override
+                    public boolean evaluate(SourceEntry se) {
+                        return Utils.equal(def.url, se.url);
+                    }
+                });
+                if (i == -1 && !knownDefaults.contains(def.url)) {
+                    list.add(insertionIdx, def);
+                    insertionIdx++;
+                    changed = true;
+                } else {
+                    if (i >= insertionIdx) {
+                        insertionIdx = i + 1;
+                    }
+                }
+            }
+
+            for (SourceEntry def : defaults) {
+                knownDefaults.add(def.url);
+            }
+            Main.pref.putCollection("mappaint.style.known-defaults", knownDefaults);
+
+            return changed;
+        }
+
+        @Override
+        public Collection<ExtendedSourceEntry> getDefault() {
+            ExtendedSourceEntry defJOSM = new ExtendedSourceEntry("elemstyles.xml", "resource://styles/standard/elemstyles.xml");
+            defJOSM.active = true;
+            defJOSM.name = "standard";
+            defJOSM.title = tr("JOSM Internal Style");
+            defJOSM.description = tr("Internal style to be used as base for runtime switchable overlay styles");
+            ExtendedSourceEntry defPL2 = new ExtendedSourceEntry("potlatch2.mapcss", "resource://styles/standard/potlatch2.mapcss");
+            defPL2.active = false;
+            defPL2.name = "standard";
+            defPL2.title = tr("Potlatch 2");
+            defPL2.description = tr("the main Potlatch 2 style");
+
+            return Arrays.asList(new ExtendedSourceEntry[] { defJOSM, defPL2 });
+        }
+
+        @Override
+        public Collection<String> serialize(SourceEntry entry) {
+            return Arrays.asList(new String[] {
+                    entry.url,
+                    entry.name == null ? "" : entry.name,
+                            entry.title == null ? "" : entry.title,
+                                    Boolean.toString(entry.active)
+            });
+        }
+
+        @Override
+        public SourceEntry deserialize(List<String> entryStr) {
+            if (entryStr.size() < 4)
+                return null;
+            String url = entryStr.get(0);
+            String name = entryStr.get(1);
+            String shortdescription = entryStr.get(2);
+            boolean active = Boolean.parseBoolean(entryStr.get(3));
+            return new SourceEntry(url, name, shortdescription, active);
+        }
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getMapPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/map/ProjectionPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/map/ProjectionPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/map/ProjectionPreference.java	(revision 4968)
@@ -0,0 +1,305 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.map;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.CoordinateFormat;
+import org.openstreetmap.josm.data.preferences.CollectionProperty;
+import org.openstreetmap.josm.data.preferences.ParametrizedCollectionProperty;
+import org.openstreetmap.josm.data.preferences.StringProperty;
+import org.openstreetmap.josm.data.projection.Mercator;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.plugins.PluginHandler;
+import org.openstreetmap.josm.tools.GBC;
+
+public class ProjectionPreference implements SubPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new ProjectionPreference();
+        }
+    }
+
+    private static final StringProperty PROP_PROJECTION = new StringProperty("projection", Mercator.class.getName());
+    private static final StringProperty PROP_COORDINATES = new StringProperty("coordinates", null);
+    private static final CollectionProperty PROP_SUB_PROJECTION = new CollectionProperty("projection.sub", null);
+    private static final ParametrizedCollectionProperty PROP_PROJECTION_SUBPROJECTION = new ParametrizedCollectionProperty(null) {
+        @Override
+        protected String getKey(String... params) {
+            String name = params[0];
+            String sname = name.substring(name.lastIndexOf(".")+1);
+            return "projection.sub."+sname;
+        }
+    };
+    public static final StringProperty PROP_SYSTEM_OF_MEASUREMENT = new StringProperty("system_of_measurement", "Metric");
+    private static final String[] unitsValues = (new ArrayList<String>(NavigatableComponent.SYSTEMS_OF_MEASUREMENT.keySet())).toArray(new String[0]);
+    private static final String[] unitsValuesTr = new String[unitsValues.length];
+    static {
+        for (int i=0; i<unitsValues.length; ++i) {
+            unitsValuesTr[i] = tr(unitsValues[i]);
+        }
+    }
+
+    /**
+     * Combobox with all projections available
+     */
+    private JComboBox projectionCombo = new JComboBox(Projections.getProjections().toArray());
+
+    /**
+     * Combobox with all coordinate display possibilities
+     */
+    private JComboBox coordinatesCombo = new JComboBox(CoordinateFormat.values());
+
+    private JComboBox unitsCombo = new JComboBox(unitsValuesTr);
+
+    /**
+     * This variable holds the JPanel with the projection's preferences. If the
+     * selected projection does not implement this, it will be set to an empty
+     * Panel.
+     */
+    private JPanel projSubPrefPanel;
+    private JPanel projSubPrefPanelWrapper = new JPanel(new GridBagLayout());
+
+    private JLabel projectionCode = new JLabel();
+    private JLabel bounds = new JLabel();
+
+    /**
+     * This is the panel holding all projection preferences
+     */
+    private JPanel projPanel = new JPanel(new GridBagLayout());
+
+    /**
+     * The GridBagConstraints for the Panel containing the ProjectionSubPrefs.
+     * This is required twice in the code, creating it here keeps both occurrences
+     * in sync
+     */
+    static private GBC projSubPrefPanelGBC = GBC.std().fill(GBC.BOTH).weight(1.0, 1.0);
+
+    public void addGui(PreferenceTabbedPane gui) {
+        setupProjectionCombo();
+
+        for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
+            if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(PROP_COORDINATES.get())) {
+                coordinatesCombo.setSelectedIndex(i);
+                break;
+            }
+        }
+
+        for (int i = 0; i < unitsValues.length; ++i) {
+            if (unitsValues[i].equals(PROP_SYSTEM_OF_MEASUREMENT.get())) {
+                unitsCombo.setSelectedIndex(i);
+                break;
+            }
+        }
+
+        projPanel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        projPanel.setLayout(new GridBagLayout());
+        projPanel.add(new JLabel(tr("Projection method")), GBC.std().insets(5,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(projectionCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projPanel.add(new JLabel(tr("Projection code")), GBC.std().insets(25,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(projectionCode, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projPanel.add(new JLabel(tr("Bounds")), GBC.std().insets(25,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(bounds, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projSubPrefPanelWrapper.add(projSubPrefPanel, projSubPrefPanelGBC);
+        projPanel.add(projSubPrefPanelWrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(20,5,5,5));
+
+        projPanel.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(0,5,0,10));
+        projPanel.add(new JLabel(tr("Display coordinates as")), GBC.std().insets(5,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(coordinatesCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projPanel.add(new JLabel(tr("System of measurement")), GBC.std().insets(5,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(unitsCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projPanel.add(GBC.glue(1,1), GBC.std().fill(GBC.HORIZONTAL).weight(1.0, 1.0));
+
+        JScrollPane scrollpane = new JScrollPane(projPanel);
+        gui.getMapPreference().mapcontent.addTab(tr("Map Projection"), scrollpane);
+
+        updateMeta(Main.getProjection());
+    }
+
+    private void updateMeta(Projection proj)
+    {
+        projectionCode.setText(proj.toCode());
+        Bounds b = proj.getWorldBoundsLatLon();
+        CoordinateFormat cf = CoordinateFormat.getDefaultFormat();
+        bounds.setText(b.getMin().latToString(cf)+"; "+b.getMin().lonToString(cf)+" : "+b.getMax().latToString(cf)+"; "+b.getMax().lonToString(cf));
+    }
+
+    public boolean ok() {
+        Projection proj = (Projection) projectionCombo.getSelectedItem();
+
+        String projname = proj.getClass().getName();
+        Collection<String> prefs = null;
+        if(proj instanceof ProjectionSubPrefs) {
+            prefs = ((ProjectionSubPrefs) proj).getPreferences(projSubPrefPanel);
+        }
+
+        PROP_PROJECTION.put(projname);
+        setProjection(projname, prefs);
+
+        if(PROP_COORDINATES.put(((CoordinateFormat)coordinatesCombo.getSelectedItem()).name())) {
+            CoordinateFormat.setCoordinateFormat((CoordinateFormat)coordinatesCombo.getSelectedItem());
+        }
+
+        int i = unitsCombo.getSelectedIndex();
+        PROP_SYSTEM_OF_MEASUREMENT.put(unitsValues[i]);
+
+        return false;
+    }
+
+    static public void setProjection()
+    {
+        setProjection(PROP_PROJECTION.get(), PROP_SUB_PROJECTION.get());
+    }
+
+    static public void setProjection(String name, Collection<String> coll)
+    {
+        Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
+
+        Projection proj = null;
+        for (ClassLoader cl : PluginHandler.getResourceClassLoaders()) {
+            try {
+                proj = (Projection) Class.forName(name, true, cl).newInstance();
+            } catch (final Exception e) {
+            }
+            if (proj != null) {
+                break;
+            }
+        }
+        if (proj == null) {
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("The projection {0} could not be activated. Using Mercator", name),
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+            coll = null;
+            proj = new Mercator();
+            name = proj.getClass().getName();
+            PROP_PROJECTION.put(name);
+        }
+        PROP_SUB_PROJECTION.put(coll);
+        PROP_PROJECTION_SUBPROJECTION.put(coll, name);
+        if (proj instanceof ProjectionSubPrefs) {
+            ((ProjectionSubPrefs) proj).setPreferences(coll);
+        }
+        Projection oldProj = Main.getProjection();
+        Main.setProjection(proj);
+        if (b != null && (!proj.getClass().getName().equals(oldProj.getClass().getName()) || proj.hashCode() != oldProj.hashCode()))
+        {
+            Main.map.mapView.zoomTo(b);
+            /* TODO - remove layers with fixed projection */
+        }
+    }
+
+    private class SBPanel extends JPanel implements ActionListener
+    {
+        private ProjectionSubPrefs p;
+        public SBPanel(ProjectionSubPrefs pr)
+        {
+            super();
+            p = pr;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            p.setPreferences(p.getPreferences(this));
+            updateMeta(p);
+        }
+    }
+
+    /**
+     * Handles all the work related to update the projection-specific
+     * preferences
+     * @param proj
+     */
+    private void selectedProjectionChanged(Projection proj) {
+        if(!(proj instanceof ProjectionSubPrefs)) {
+            projSubPrefPanel = new JPanel();
+        } else {
+            ProjectionSubPrefs projPref = (ProjectionSubPrefs) proj;
+            projSubPrefPanel = new SBPanel(projPref);
+            projPref.setupPreferencePanel(projSubPrefPanel, (SBPanel)projSubPrefPanel);
+        }
+
+        // Don't try to update if we're still starting up
+        int size = projPanel.getComponentCount();
+        if(size < 1)
+            return;
+
+        // Replace old panel with new one
+        projSubPrefPanelWrapper.removeAll();
+        projSubPrefPanelWrapper.add(projSubPrefPanel, projSubPrefPanelGBC);
+        projPanel.revalidate();
+        projSubPrefPanel.repaint();
+        updateMeta(proj);
+    }
+
+    /**
+     * Sets up projection combobox with default values and action listener
+     */
+    private void setupProjectionCombo() {
+        boolean found = false;
+        for (int i = 0; i < projectionCombo.getItemCount(); ++i) {
+            Projection proj = (Projection)projectionCombo.getItemAt(i);
+            String name = proj.getClass().getName();
+            if(proj instanceof ProjectionSubPrefs) {
+                ((ProjectionSubPrefs) proj).setPreferences(PROP_PROJECTION_SUBPROJECTION.get(name));
+            }
+            if (name.equals(PROP_PROJECTION.get())) {
+                projectionCombo.setSelectedIndex(i);
+                selectedProjectionChanged(proj);
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            throw new RuntimeException("Couldn't find the current projection in the list of available projections!");
+
+        projectionCombo.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                JComboBox cb = (JComboBox)e.getSource();
+                Projection proj = (Projection)cb.getSelectedItem();
+                selectedProjectionChanged(proj);
+            }
+        });
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getMapPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java	(revision 4968)
@@ -0,0 +1,350 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.map;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
+import org.openstreetmap.josm.gui.preferences.SourceEditor;
+import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
+import org.openstreetmap.josm.gui.preferences.SourceEntry;
+import org.openstreetmap.josm.gui.preferences.SourceProvider;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset;
+import org.openstreetmap.josm.gui.tagging.TaggingPresetMenu;
+import org.openstreetmap.josm.gui.tagging.TaggingPresetSeparator;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
+import org.openstreetmap.josm.tools.GBC;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+public class TaggingPresetPreference implements SubPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new TaggingPresetPreference();
+        }
+    }
+    
+    private TaggingPresetPreference() {
+        super();
+    }
+
+    private static final List<SourceProvider> presetSourceProviders = new ArrayList<SourceProvider>();
+    public static Collection<TaggingPreset> taggingPresets;
+    private SourceEditor sources;
+    private JCheckBox sortMenu;
+
+    public static final boolean registerSourceProvider(SourceProvider provider) {
+        if (provider != null)
+            return presetSourceProviders.add(provider);
+        return false;
+    }
+
+    private ValidationListener validationListener = new ValidationListener() {
+        public boolean validatePreferences() {
+            if (sources.hasActiveSourcesChanged()) {
+                List<Integer> sourcesToRemove = new ArrayList<Integer>();
+                int i = -1;
+                SOURCES:
+                    for (SourceEntry source: sources.getActiveSources()) {
+                        i++;
+                        boolean canLoad = false;
+                        try {
+                            TaggingPreset.readAll(source.url, false);
+                            canLoad = true;
+                        } catch (IOException e) {
+                            System.err.println(tr("Warning: Could not read tagging preset source: {0}", source));
+                            ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Error"),
+                                    new String[] {tr("Yes"), tr("No"), tr("Cancel")});
+                            ed.setContent(tr("Could not read tagging preset source: {0}\nDo you want to keep it?", source));
+                            switch (ed.showDialog().getValue()) {
+                            case 1:
+                                continue SOURCES;
+                            case 2:
+                                sourcesToRemove.add(i);
+                                continue SOURCES;
+                            default:
+                                return false;
+                            }
+                        } catch (SAXException e) {
+                            // We will handle this in step with validation
+                        }
+
+                        String errorMessage = null;
+
+                        try {
+                            TaggingPreset.readAll(source.url, true);
+                        } catch (IOException e) {
+                            // Should not happen, but at least show message
+                            String msg = tr("Could not read tagging preset source {0}", source);
+                            System.err.println(msg);
+                            JOptionPane.showMessageDialog(Main.parent, msg);
+                            return false;
+                        } catch (SAXParseException e) {
+                            if (canLoad) {
+                                errorMessage = tr("<html>Tagging preset source {0} can be loaded but it contains errors. " +
+                                        "Do you really want to use it?<br><br><table width=600>Error is: [{1}:{2}] {3}</table></html>",
+                                        source, e.getLineNumber(), e.getColumnNumber(), e.getMessage());
+                            } else {
+                                errorMessage = tr("<html>Unable to parse tagging preset source: {0}. " +
+                                        "Do you really want to use it?<br><br><table width=400>Error is: [{1}:{2}] {3}</table></html>",
+                                        source, e.getLineNumber(), e.getColumnNumber(), e.getMessage());
+                            }
+                        } catch (SAXException e) {
+                            if (canLoad) {
+                                errorMessage = tr("<html>Tagging preset source {0} can be loaded but it contains errors. " +
+                                        "Do you really want to use it?<br><br><table width=600>Error is: {1}</table></html>",
+                                        source,  e.getMessage());
+                            } else {
+                                errorMessage = tr("<html>Unable to parse tagging preset source: {0}. " +
+                                        "Do you really want to use it?<br><br><table width=600>Error is: {1}</table></html>",
+                                        source, e.getMessage());
+                            }
+
+                        }
+
+                        if (errorMessage != null) {
+                            System.err.println("Error: "+errorMessage);
+                            int result = JOptionPane.showConfirmDialog(Main.parent, new JLabel(errorMessage), tr("Error"),
+                                    JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE);
+
+                            switch (result) {
+                            case JOptionPane.YES_OPTION:
+                                continue SOURCES;
+                            case JOptionPane.NO_OPTION:
+                                sourcesToRemove.add(i);
+                                continue SOURCES;
+                            default:
+                                return false;
+                            }
+                        }
+                    }
+                sources.removeSources(sourcesToRemove);
+                return true;
+            }  else
+                return true;
+        }
+    };
+
+    public void addGui(final PreferenceTabbedPane gui) {
+        sortMenu = new JCheckBox(tr("Sort presets menu"),
+                Main.pref.getBoolean("taggingpreset.sortmenu", false));
+
+        final JPanel panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        panel.add(sortMenu, GBC.eol().insets(5,5,5,0));
+        sources = new TaggingPresetSourceEditor();
+        panel.add(sources, GBC.eol().fill(GBC.BOTH));
+        gui.getMapPreference().mapcontent.addTab(tr("Tagging Presets"), panel);
+
+        // this defers loading of tagging preset sources to the first time the tab
+        // with the tagging presets is selected by the user
+        //
+        gui.getMapPreference().mapcontent.addChangeListener(
+                new ChangeListener() {
+                    public void stateChanged(ChangeEvent e) {
+                        if (gui.getMapPreference().mapcontent.getSelectedComponent() == panel) {
+                            sources.initiallyLoadAvailableSources();
+                        }
+                    }
+                }
+                );
+        gui.addValidationListener(validationListener);
+    }
+
+    static class TaggingPresetSourceEditor extends SourceEditor {
+
+        final private String iconpref = "taggingpreset.icon.sources";
+
+        public TaggingPresetSourceEditor() {
+            super(false, "http://josm.openstreetmap.de/presets", presetSourceProviders);
+        }
+
+        @Override
+        public Collection<? extends SourceEntry> getInitialSourcesList() {
+            return PresetPrefHelper.INSTANCE.get();
+        }
+
+        @Override
+        public boolean finish() {
+            List<SourceEntry> activeStyles = activeSourcesModel.getSources();
+
+            boolean changed = PresetPrefHelper.INSTANCE.put(activeStyles);
+
+            if (tblIconPaths != null) {
+                List<String> iconPaths = iconPathsModel.getIconPaths();
+
+                if (!iconPaths.isEmpty()) {
+                    if (Main.pref.putCollection(iconpref, iconPaths)) {
+                        changed = true;
+                    }
+                } else if (Main.pref.putCollection(iconpref, null)) {
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        @Override
+        public Collection<ExtendedSourceEntry> getDefault() {
+            return PresetPrefHelper.INSTANCE.getDefault();
+        }
+
+        @Override
+        public Collection<String> getInitialIconPathsList() {
+            return Main.pref.getCollection(iconpref, null);
+        }
+
+        @Override
+        public String getStr(I18nString ident) {
+            switch (ident) {
+            case AVAILABLE_SOURCES:
+                return tr("Available presets:");
+            case ACTIVE_SOURCES:
+                return tr("Active presets:");
+            case NEW_SOURCE_ENTRY_TOOLTIP:
+                return tr("Add a new preset by entering filename or URL");
+            case NEW_SOURCE_ENTRY:
+                return tr("New preset entry:");
+            case REMOVE_SOURCE_TOOLTIP:
+                return tr("Remove the selected presets from the list of active presets");
+            case EDIT_SOURCE_TOOLTIP:
+                return tr("Edit the filename or URL for the selected active preset");
+            case ACTIVATE_TOOLTIP:
+                return tr("Add the selected available presets to the list of active presets");
+            case RELOAD_ALL_AVAILABLE:
+                return marktr("Reloads the list of available presets from ''{0}''");
+            case LOADING_SOURCES_FROM:
+                return marktr("Loading preset sources from ''{0}''");
+            case FAILED_TO_LOAD_SOURCES_FROM:
+                return marktr("<html>Failed to load the list of preset sources from<br>"
+                        + "''{0}''.<br>"
+                        + "<br>"
+                        + "Details (untranslated):<br>{1}</html>");
+            case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC:
+                return "/Preferences/Presets#FailedToLoadPresetSources";
+            case ILLEGAL_FORMAT_OF_ENTRY:
+                return marktr("Warning: illegal format of entry in preset list ''{0}''. Got ''{1}''");
+            default: throw new AssertionError();
+            }
+        }
+    }
+
+    public boolean ok() {
+        boolean restart = Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null);
+        restart |= sources.finish();
+
+        return restart;
+    }
+
+    /**
+     * Initialize the tagging presets (load and may display error)
+     */
+    public static void initialize() {
+        taggingPresets = TaggingPreset.readFromPreferences(false);
+        for (TaggingPreset tp: taggingPresets) {
+            if (!(tp instanceof TaggingPresetSeparator)) {
+                Main.toolbar.register(tp);
+            }
+        }
+        if (taggingPresets.isEmpty()) {
+            Main.main.menu.presetsMenu.setVisible(false);
+        }
+        else
+        {
+            AutoCompletionManager.cachePresets(taggingPresets);
+            HashMap<TaggingPresetMenu,JMenu> submenus = new HashMap<TaggingPresetMenu,JMenu>();
+            for (final TaggingPreset p : taggingPresets)
+            {
+                JMenu m = p.group != null ? submenus.get(p.group) : Main.main.menu.presetsMenu;
+                if (p instanceof TaggingPresetSeparator) {
+                    m.add(new JSeparator());
+                } else if (p instanceof TaggingPresetMenu)
+                {
+                    JMenu submenu = new JMenu(p);
+                    submenu.setText(p.getLocaleName());
+                    ((TaggingPresetMenu)p).menu = submenu;
+                    submenus.put((TaggingPresetMenu)p, submenu);
+                    m.add(submenu);
+                }
+                else
+                {
+                    JMenuItem mi = new JMenuItem(p);
+                    mi.setText(p.getLocaleName());
+                    m.add(mi);
+                }
+            }
+        }
+        if(Main.pref.getBoolean("taggingpreset.sortmenu")) {
+            TaggingPresetMenu.sortMenu(Main.main.menu.presetsMenu);
+        }
+    }
+
+    public static class PresetPrefHelper extends SourceEditor.SourcePrefHelper {
+
+        public final static PresetPrefHelper INSTANCE = new PresetPrefHelper();
+
+        public PresetPrefHelper() {
+            super("taggingpreset.sources-list");
+        }
+
+        @Override
+        public Collection<ExtendedSourceEntry> getDefault() {
+            ExtendedSourceEntry i = new ExtendedSourceEntry("defaultpresets.xml", "resource://data/defaultpresets.xml");
+            i.title = tr("Internal Preset");
+            i.description = tr("The default preset for JOSM");
+            return Collections.singletonList(i);
+        }
+
+        @Override
+        public Collection<String> serialize(SourceEntry entry) {
+            return Arrays.asList(new String[] {entry.url, entry.title == null ? "" : entry.title});
+        }
+
+        @Override
+        public SourceEntry deserialize(List<String> entryStr) {
+            if (entryStr.size() < 2)
+                return null;
+            String url = entryStr.get(0);
+            String shortdescription = entryStr.get(1);
+            return new SourceEntry(url, null, shortdescription, true);
+        }
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
+        return gui.getMapPreference();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java	(revision 4968)
@@ -0,0 +1,511 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.shortcut;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.KeyEvent;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import java.util.regex.PatternSyntaxException;
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.RowFilter;
+import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+
+import javax.swing.table.TableRowSorter;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * This is the keyboard preferences content.
+ * If someone wants to merge it with ShortcutPreference.java, feel free.
+ */
+public class PrefJPanel extends JPanel {
+
+    // table of shortcuts
+    private AbstractTableModel model;
+    // comboboxes of modifier groups, mapping selectedIndex to real data
+    private static int[] modifInts = new int[]{
+        -1,
+        0,
+        KeyEvent.SHIFT_DOWN_MASK,
+        KeyEvent.CTRL_DOWN_MASK,
+        KeyEvent.ALT_DOWN_MASK,
+        KeyEvent.META_DOWN_MASK,
+        KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
+        KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
+        KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
+        KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
+        KeyEvent.CTRL_DOWN_MASK | KeyEvent.META_DOWN_MASK,
+        KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK,
+        KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
+        KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK
+    };
+    // and here are the texts fro the comboboxes
+    private static String[] modifList = new String[] {
+        tr("disabled"),
+        tr("no modifier"),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[2]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[3]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[4]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[5]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[6]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[7]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[8]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[9]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[10]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[11]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[12]).getModifiers()),
+        KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[13]).getModifiers())
+    };
+    // this are the display(!) texts for the checkboxes. Let the JVM do the i18n for us <g>.
+    // Ok, there's a real reason for this: The JVM should know best how the keys are labelled
+    // on the physical keyboard. What language pack is installed in JOSM is completely
+    // independent from the keyboard's labelling. But the operation system's locale
+    // usually matches the keyboard. This even works with my English Windows and my German
+    // keyboard.
+    private static String SHIFT = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.SHIFT_DOWN_MASK).getModifiers());
+    private static String CTRL  = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK).getModifiers());
+    private static String ALT   = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_DOWN_MASK).getModifiers());
+    private static String META  = KeyEvent.getKeyModifiersText(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK).getModifiers());
+
+    // A list of keys to present the user. Sadly this really is a list of keys Java knows about,
+    // not a list of real physical keys. If someone knows how to get that list?
+    private static Map<Integer, String> keyList = setKeyList();
+
+    private static Map<Integer, String> setKeyList() {
+        Map<Integer, String> list = new LinkedHashMap<Integer, String>();
+        String unknown = Toolkit.getProperty("AWT.unknown", "Unknown");
+        // Assume all known keys are declared in KeyEvent as "public static int VK_*"
+        for (Field field : KeyEvent.class.getFields()) {
+            if (field.getName().startsWith("VK_")) {
+                try {
+                    int i = field.getInt(null);
+                    String s = KeyEvent.getKeyText(i);
+                    if (s != null && s.length() > 0 && !s.contains(unknown)) {
+                        list.put(Integer.valueOf(i), s);
+                        //System.out.println(i+": "+s);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        list.put(Integer.valueOf(-1), "");
+        return list;
+    }
+
+    private JComboBox bxPrim1 = new JComboBox();
+    private JComboBox bxPrim2 = new JComboBox();
+    private JComboBox bxPrim3 = new JComboBox();
+    private JComboBox bxPrim4 = new JComboBox();
+    private JComboBox bxSec1 = new JComboBox();
+    private JComboBox bxSec2 = new JComboBox();
+    private JComboBox bxSec3 = new JComboBox();
+    private JComboBox bxSec4 = new JComboBox();
+    private JComboBox bxTer1 = new JComboBox();
+    private JComboBox bxTer2 = new JComboBox();
+    private JComboBox bxTer3 = new JComboBox();
+    private JComboBox bxTer4 = new JComboBox();
+    private JCheckBox cbAlt = new JCheckBox();
+    private JCheckBox cbCtrl = new JCheckBox();
+    private JCheckBox cbMeta = new JCheckBox();
+    private JCheckBox cbShift = new JCheckBox();
+    private JCheckBox cbDefault = new JCheckBox();
+    private JCheckBox cbDisable = new JCheckBox();
+    private JComboBox tfKey = new JComboBox();
+
+    JTable shortcutTable = new JTable();
+
+    private JTextField filterField = new JTextField();
+
+    /** Creates new form prefJPanel */
+    // Ain't those auto-generated comments helpful or what? <g>
+    public PrefJPanel(AbstractTableModel model) {
+        this.model = model;
+        initComponents();
+    }
+
+    private void initComponents() {
+        JPanel editGroupPane = new JPanel();
+        JPanel hotkeyGroupPane = new JPanel();
+
+        JPanel listPane = new JPanel();
+        JScrollPane listScrollPane = new JScrollPane();
+        JPanel menuGroupPane = new JPanel();
+        JPanel modifierTab = new JPanel();
+        JTabbedPane prefTabPane = new JTabbedPane();
+        JPanel shortcutEditPane = new JPanel();
+        JPanel shortcutTab = new JPanel();
+        JPanel subwindowGroupPane = new JPanel();
+        JPanel infoTab = new JPanel();
+
+        CbAction action = new CbAction(this);
+        BxAction action2 = new BxAction();
+
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+        // If someone wants to move this text into some resource, feel free.
+        infoTab.setLayout(new BoxLayout(shortcutTab, BoxLayout.Y_AXIS));
+        JEditorPane editor = new JEditorPane();
+        editor.setEditable(false);
+        editor.setContentType("text/html");
+        editor.setText(
+                tr("<h1><a name=\"top\">Keyboard Shortcuts</a></h1>")+
+                tr("<p>Please note that shortcut keys are assigned to the actions when JOSM is started. So you need to <b>restart</b> "
+                        +"JOSM to see your changes.</p>")+
+                        tr("<p>Furthermore, the shortcuts are activated when the actions are assigned to a menu entry of a button for the first "
+                                +"time. So some of your changes may become active even without restart --- but also without collision handling. "
+                                +"This is another reason to <b>restart</b> JOSM after making any changes here.</p>")+
+                                tr("<p>You may notice that the key selection list on the next page lists all keys that exist on all kinds of keyboards "
+                                        +"Java knows about, not just those keys that exist on your keyboard. Please only use values that correspond to "
+                                        +"a real key on your keyboard. If your keyboard has no ''Copy'' key (PC keyboard do not have them, Sun keyboards do), "
+                                        +"then do not use it. Also there are ''keys'' listed that correspond to a shortcut on your keyboard (e.g. '':''/Colon). "
+                                        +"Please do not use them either, use the base key ('';''/Semicolon on US keyboards, ''.''/Period on German keyboards, etc.) "
+                                        +"instead. Not doing so may result in conflicts, as there is no way for JOSM to know that Ctrl+Shift+; and Ctrl+: "
+                                        +"actually is the same thing on an US keyboard.</p>")+
+                                        tr("<h1>Modifier Groups</h1>")+
+                                        tr("<p>The last page lists the modifier keys JOSM will automatically assign to shortcuts. For every of the four kinds "
+                                                +"of shortcuts there are three alternatives. JOSM will try those alternatives in the listed order when managing a "
+                                                +"conflict. If all alternatives result in shortcuts that are already taken, it will assign a random shortcut "
+                                                +"instead.</p>")+
+                                                tr("<p>The pseudo-modifier ''disabled'' will disable the shortcut when encountered.</p>")
+        );
+        editor.setCaretPosition(0); // scroll up
+        prefTabPane.addTab(tr("Read First"), new JScrollPane(editor));
+
+        shortcutTab.setLayout(new BoxLayout(shortcutTab, BoxLayout.Y_AXIS));
+
+        shortcutTab.add(buildFilterPanel());
+        listPane.setLayout(new java.awt.GridLayout());
+
+        // This is the list of shortcuts:
+        shortcutTable.setModel(model);
+        shortcutTable.getSelectionModel().addListSelectionListener(new CbAction(this));
+        shortcutTable.setFillsViewportHeight(true);
+        shortcutTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        shortcutTable.setAutoCreateRowSorter(true);
+        listScrollPane.setViewportView(shortcutTable);
+
+        listPane.add(listScrollPane);
+
+        shortcutTab.add(listPane);
+
+        // and here follows the edit area. I won't object to someone re-designing it, it looks, um, "minimalistic" ;)
+        shortcutEditPane.setLayout(new java.awt.GridLayout(5, 2));
+
+        cbDefault.setAction(action);
+        cbDefault.setText(tr("Use default"));
+        cbShift.setAction(action);
+        cbShift.setText(SHIFT); // see above for why no tr()
+        cbDisable.setAction(action);
+        cbDisable.setText(tr("Disable"));
+        cbCtrl.setAction(action);
+        cbCtrl.setText(CTRL); // see above for why no tr()
+        cbAlt.setAction(action);
+        cbAlt.setText(ALT); // see above for why no tr()
+        tfKey.setAction(action);
+        tfKey.setModel(new DefaultComboBoxModel(keyList.values().toArray()));
+        cbMeta.setAction(action);
+        cbMeta.setText(META); // see above for why no tr()
+
+
+        shortcutEditPane.add(cbDefault);
+        shortcutEditPane.add(new JLabel());
+        shortcutEditPane.add(cbShift);
+        shortcutEditPane.add(cbDisable);
+        shortcutEditPane.add(cbCtrl);
+        shortcutEditPane.add(new JLabel(tr("Key:"), SwingConstants.LEFT));
+        shortcutEditPane.add(cbAlt);
+        shortcutEditPane.add(tfKey);
+        shortcutEditPane.add(cbMeta);
+
+        shortcutEditPane.add(new JLabel(tr("Attention: Use real keyboard keys only!")));
+
+        action.actionPerformed(null); // init checkboxes
+
+        shortcutTab.add(shortcutEditPane);
+
+        prefTabPane.addTab(tr("Keyboard Shortcuts"), shortcutTab);
+
+        // next is the modfier group tab.
+        // Would be a nice array if I had done it by hand. But then, it would be finished next year or so...
+        modifierTab.setLayout(new java.awt.GridLayout(0, 1));
+        JScrollPane modifierScroller = new JScrollPane(modifierTab);
+
+        editGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Edit Shortcuts")));
+        editGroupPane.setLayout(new java.awt.GridLayout(3, 5));
+
+        JComboBox[] bxArray = new JComboBox[] {
+                    bxPrim1,bxSec1,bxTer1,bxPrim2,bxSec2,bxTer2,
+                    bxPrim3,bxSec3,bxTer3,bxPrim4,bxSec4,bxTer4};
+        for (JComboBox bxi: bxArray) bxi.setModel(new DefaultComboBoxModel(modifList));
+
+        editGroupPane.add(new JLabel(tr("Primary modifier:")));
+        editGroupPane.add(bxPrim1);
+        editGroupPane.add(new JLabel(tr("Secondary modifier:")));
+        editGroupPane.add(bxSec1);
+        editGroupPane.add(new JLabel(tr("Tertiary modifier:")));
+        editGroupPane.add(bxTer1);
+        modifierTab.add(editGroupPane);
+
+        menuGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Menu Shortcuts")));
+        menuGroupPane.setLayout(new java.awt.GridLayout(3, 5));
+        menuGroupPane.add(new JLabel(tr("Primary modifier:")));
+        menuGroupPane.add(bxPrim2);
+        menuGroupPane.add(new JLabel(tr("Secondary modifier:")));
+        menuGroupPane.add(bxSec2);
+        menuGroupPane.add(new JLabel(tr("Tertiary modifier:")));
+        menuGroupPane.add(bxTer2);
+        modifierTab.add(menuGroupPane);
+
+        hotkeyGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Hotkey Shortcuts")));
+        hotkeyGroupPane.setLayout(new java.awt.GridLayout(3, 5));
+        hotkeyGroupPane.add(new JLabel(tr("Primary modifier:")));
+        hotkeyGroupPane.add(bxPrim3);
+        hotkeyGroupPane.add(new JLabel((tr("Secondary modifier:"))));
+        hotkeyGroupPane.add(bxSec3);
+        hotkeyGroupPane.add(new JLabel(tr("Tertiary modifier:")));
+        hotkeyGroupPane.add(bxTer3);
+        modifierTab.add(hotkeyGroupPane);
+
+        subwindowGroupPane.setBorder(BorderFactory.createTitledBorder(tr("Subwindow Shortcuts")));
+        subwindowGroupPane.setLayout(new java.awt.GridLayout(3, 5));
+        subwindowGroupPane.add(new JLabel(tr("Primary modifier:")));
+        subwindowGroupPane.add(bxPrim4);
+        subwindowGroupPane.add(new JLabel(tr("Secondary modifier:")));
+        subwindowGroupPane.add(bxSec4);
+        subwindowGroupPane.add(new JLabel(tr("Tertiary modifier:")));
+        subwindowGroupPane.add(bxTer4);
+
+        initbx();
+        for (JComboBox bxi: bxArray) bxi.setAction(action2);
+
+        modifierTab.add(subwindowGroupPane);
+
+        prefTabPane.addTab(tr("Modifier Groups"), modifierScroller);
+
+        add(prefTabPane);
+    }
+
+    private JPanel buildFilterPanel() {
+        // copied from PluginPreference
+        JPanel pnl  = new JPanel(new GridBagLayout());
+        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        GridBagConstraints gc = new GridBagConstraints();
+
+        gc.anchor = GridBagConstraints.NORTHWEST;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.weightx = 0.0;
+        gc.insets = new Insets(0,0,0,5);
+        pnl.add(new JLabel(tr("Search:")), gc);
+
+        gc.gridx = 1;
+        gc.weightx = 1.0;
+        pnl.add(filterField, gc);
+        filterField.setToolTipText(tr("Enter a search expression"));
+        SelectAllOnFocusGainedDecorator.decorate(filterField);
+        filterField.getDocument().addDocumentListener(new FilterFieldAdapter());
+        pnl.setMaximumSize(new Dimension(300,10));
+        return pnl;
+    }
+
+    private void disableAllModifierCheckboxes() {
+        cbDefault.setEnabled(false);
+        cbDisable.setEnabled(false);
+        cbShift.setEnabled(false);
+        cbCtrl.setEnabled(false);
+        cbAlt.setEnabled(false);
+        cbMeta.setEnabled(false);
+    }
+
+    // this allows to edit shortcuts. it:
+    //  * sets the edit controls to the selected shortcut
+    //  * enabled/disables the controls as needed
+    //  * writes the user's changes to the shortcut
+    // And after I finally had it working, I realized that those two methods
+    // are playing ping-pong (politically correct: table tennis, I know) and
+    // even have some duplicated code. Feel free to refactor, If you have
+    // more expirience with GUI coding than I have.
+    private class CbAction extends AbstractAction implements ListSelectionListener {
+        private PrefJPanel panel;
+        public CbAction (PrefJPanel panel) {
+            this.panel = panel;
+        }
+        public void valueChanged(ListSelectionEvent e) {
+            ListSelectionModel lsm = panel.shortcutTable.getSelectionModel(); // can't use e here
+            if (!lsm.isSelectionEmpty()) {
+                int row = panel.shortcutTable.convertRowIndexToModel(lsm.getMinSelectionIndex());
+                Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
+                panel.cbDefault.setSelected(!sc.getAssignedUser());
+                panel.cbDisable.setSelected(sc.getKeyStroke() == null);
+                panel.cbShift.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.SHIFT_DOWN_MASK) != 0);
+                panel.cbCtrl.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.CTRL_DOWN_MASK) != 0);
+                panel.cbAlt.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.ALT_DOWN_MASK) != 0);
+                panel.cbMeta.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.META_DOWN_MASK) != 0);
+                if (sc.getKeyStroke() != null) {
+                    tfKey.setSelectedItem(keyList.get(sc.getKeyStroke().getKeyCode()));
+                } else {
+                    tfKey.setSelectedItem(keyList.get(-1));
+                }
+                if (!sc.isChangeable()) {
+                    disableAllModifierCheckboxes();
+                    panel.tfKey.setEnabled(false);
+                } else {
+                    panel.cbDefault.setEnabled(true);
+                    actionPerformed(null);
+                }
+                model.fireTableCellUpdated(row, 1);
+            } else {
+                panel.disableAllModifierCheckboxes();
+                panel.tfKey.setEnabled(false);
+            }
+        }
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            ListSelectionModel lsm = panel.shortcutTable.getSelectionModel();
+            if (lsm != null && !lsm.isSelectionEmpty()) {
+                if (e != null) { // only if we've been called by a user action
+                    int row = panel.shortcutTable.convertRowIndexToModel(lsm.getMinSelectionIndex());
+                    Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
+                    if (panel.cbDisable.isSelected()) {
+                        sc.setAssignedModifier(-1);
+                    } else if (panel.tfKey.getSelectedItem().equals("")) {
+                        sc.setAssignedModifier(KeyEvent.VK_CANCEL);
+                    } else {
+                        sc.setAssignedModifier(
+                                (panel.cbShift.isSelected() ? KeyEvent.SHIFT_DOWN_MASK : 0) |
+                                (panel.cbCtrl.isSelected() ? KeyEvent.CTRL_DOWN_MASK : 0) |
+                                (panel.cbAlt.isSelected() ? KeyEvent.ALT_DOWN_MASK : 0) |
+                                (panel.cbMeta.isSelected() ? KeyEvent.META_DOWN_MASK : 0)
+                        );
+                        for (Map.Entry<Integer, String> entry : keyList.entrySet()) {
+                            if (entry.getValue().equals(panel.tfKey.getSelectedItem())) {
+                                sc.setAssignedKey(entry.getKey());
+                            }
+                        }
+                    }
+                    sc.setAssignedUser(!panel.cbDefault.isSelected());
+                    valueChanged(null);
+                }
+                boolean state = !panel.cbDefault.isSelected();
+                panel.cbDisable.setEnabled(state);
+                state = state && !panel.cbDisable.isSelected();
+                panel.cbShift.setEnabled(state);
+                panel.cbCtrl.setEnabled(state);
+                panel.cbAlt.setEnabled(state);
+                panel.cbMeta.setEnabled(state);
+                panel.tfKey.setEnabled(state);
+            } else {
+                panel.disableAllModifierCheckboxes();
+                panel.tfKey.setEnabled(false);
+            }
+        }
+    }
+
+    // this handles the modifier groups
+    private class BxAction extends AbstractAction {
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    modifInts[bxPrim1.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT),    modifInts[ bxSec1.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT),    modifInts[ bxTer1.getSelectedIndex()]);
+
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    modifInts[bxPrim2.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU),    modifInts[ bxSec2.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU),    modifInts[ bxTer2.getSelectedIndex()]);
+
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  modifInts[bxPrim3.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY),  modifInts[ bxSec3.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY),  modifInts[ bxTer3.getSelectedIndex()]);
+
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   modifInts[bxPrim4.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER),   modifInts[ bxSec4.getSelectedIndex()]);
+            Main.pref.putInteger("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER),   modifInts[ bxTer4.getSelectedIndex()]);
+        }
+    }
+
+    private void initbx() {
+        HashMap<Integer, Integer> groups = Main.platform.initShortcutGroups(false);
+        setBx(bxPrim1, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT);
+        setBx(bxSec1,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT);
+        setBx(bxTer1,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT);
+
+        setBx(bxPrim2, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU);
+        setBx(bxSec2,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU);
+        setBx(bxTer2,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU);
+
+        setBx(bxPrim3, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY);
+        setBx(bxSec3,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY);
+        setBx(bxTer3,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY);
+
+        setBx(bxPrim4, groups, Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER);
+        setBx(bxSec4,  groups, Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER);
+        setBx(bxTer4,  groups, Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER);
+    }
+    private void setBx(JComboBox bx, HashMap<Integer, Integer> groups, int key) {
+        int target = Main.pref.getInteger("shortcut.groups."+key, groups.get(key));
+        for (int i = 0; i < modifInts.length; i++) {
+            if (modifInts[i] == target) {
+                bx.setSelectedIndex(i);
+            }
+        }
+    }
+
+
+     class FilterFieldAdapter implements DocumentListener {
+        public void filter() {
+            String expr = filterField.getText().trim();
+            if (expr.length()==0) { expr=null; }
+            try {
+                final TableRowSorter<? extends TableModel> sorter =
+                    ((TableRowSorter<? extends TableModel> )shortcutTable.getRowSorter());
+                if (expr == null) {
+                    sorter.setRowFilter(null);
+                } else {
+                    // split search string on whitespace, do case-insensitive AND search
+                    ArrayList<RowFilter<Object, Object>> andFilters = new ArrayList<RowFilter<Object, Object>>();
+                    for (String word : expr.split("\\s+")) {
+                        andFilters.add(RowFilter.regexFilter("(?i)" + word));
+                    }
+                    sorter.setRowFilter(RowFilter.andFilter(andFilters));
+                }
+            }
+            catch (PatternSyntaxException ex) { }
+            catch (ClassCastException ex2) { /* eliminate warning */  }
+        }
+
+        public void changedUpdate(DocumentEvent arg0) { filter(); }
+        public void insertUpdate(DocumentEvent arg0) {  filter(); }
+        public void removeUpdate(DocumentEvent arg0) { filter(); }
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/ShortcutPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/ShortcutPreference.java	(revision 4968)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/ShortcutPreference.java	(revision 4968)
@@ -0,0 +1,83 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences.shortcut;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.List;
+
+import javax.swing.JPanel;
+import javax.swing.table.AbstractTableModel;
+
+import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public class ShortcutPreference extends DefaultTabPreferenceSetting {
+
+    public static class Factory implements PreferenceSettingFactory {
+        public PreferenceSetting createPreferenceSetting() {
+            return new ShortcutPreference();
+        }
+    }
+    
+    private ShortcutPreference() {
+        // 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
+        // icon designer: Paolino, http://www.paolinoland.it/
+        // icon original filename: keyboard.png
+        // icon original size: 128x128
+        // modifications: icon was cropped, then resized
+        super("shortcuts", tr("Shortcut Preferences"), tr("Changing keyboard shortcuts manually."));
+    }
+
+    public void addGui(PreferenceTabbedPane gui) {
+        JPanel p = gui.createPreferenceTab(this);
+
+        PrefJPanel prefpanel = new PrefJPanel(new scListModel());
+        p.add(prefpanel, GBC.eol().fill(GBC.BOTH));
+
+    }
+
+    public boolean ok() {
+        return Shortcut.savePrefs();
+    }
+
+    // Maybe move this to prefPanel? There's no need for it to be here.
+    private static class scListModel extends AbstractTableModel {
+        private String[] columnNames = new String[]{tr("Action"), tr("Shortcut")};
+        private List<Shortcut> data;
+
+        public scListModel() {
+            data = Shortcut.listAll();
+        }
+        public int getColumnCount() {
+            return columnNames.length;
+        }
+        public int getRowCount() {
+            return data.size();
+        }
+        @Override
+        public String getColumnName(int col) {
+            return columnNames[col];
+        }
+        public Object getValueAt(int row, int col) {
+            Shortcut sc = data.get(row);
+            if (col == 0)
+                return sc.getLongText();
+            else if (col == 1)
+                return sc.getKeyText();
+            else
+                // This is a kind of hack that allows the actions on the editing controls
+                // to access the underlying shortcut object without introducing another
+                // method. I opted to stay within the interface.
+                return sc;
+        }
+        @Override
+        public boolean isCellEditable(int row, int col) {
+            return false;
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 4968)
@@ -67,5 +67,5 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.preferences.SourceEntry;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference.PresetPrefHelper;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference.PresetPrefHelper;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java	(revision 4968)
@@ -42,5 +42,5 @@
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Check;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Combo;
Index: /trunk/src/org/openstreetmap/josm/tools/TaggingPresetNameTemplateList.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/TaggingPresetNameTemplateList.java	(revision 4967)
+++ /trunk/src/org/openstreetmap/josm/tools/TaggingPresetNameTemplateList.java	(revision 4968)
@@ -7,5 +7,5 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
+import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Check;
