Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 3795)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 3796)
@@ -16,4 +16,6 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.SourceEntry;
+import org.openstreetmap.josm.gui.preferences.MapPaintPreference.MapPaintPrefMigration;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -71,22 +73,10 @@
         }
 
-        Collection<String> files = Main.pref.getCollection("mappaint.style.sources", Collections.<String>emptySet());
-        if (Main.pref.getBoolean("mappaint.style.enable-defaults", true)) {
-            LinkedList<String> f = new LinkedList<String>();
-            f.add("resource://data/elemstyles.xml");
-            f.addAll(files);
-            files = f;
-        }
+        Collection<? extends SourceEntry> sourceEntries = (new MapPaintPrefMigration()).get();
 
-        for (String file : files) {
-            String[] a = null;
+        for (SourceEntry entry : sourceEntries) {
             try {
-                if (file.indexOf("=") >= 0) {
-                    a = file.split("=", 2);
-                } else {
-                    a = new String[] { null, file };
-                }
-                XmlObjectParser parser = new XmlObjectParser(new ElemStyleHandler(a[0]));
-                MirroredInputStream in = new MirroredInputStream(a[1]);
+                XmlObjectParser parser = new XmlObjectParser(new ElemStyleHandler(entry.name));
+                MirroredInputStream in = new MirroredInputStream(entry.url);
                 InputStream zip = in.getZipEntry("xml","style");
                 InputStreamReader ins;
@@ -103,11 +93,11 @@
                 }
             } catch(IOException e) {
-                System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", a[1], e.toString()));
+                System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", entry.url, e.toString()));
                 e.printStackTrace();
             } catch(SAXParseException e) {
-                System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: [{1}:{2}] {3}", a[1], e.getLineNumber(), e.getColumnNumber(), e.getMessage()));
+                System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: [{1}:{2}] {3}", entry.url, e.getLineNumber(), e.getColumnNumber(), e.getMessage()));
                 e.printStackTrace();
             } catch(SAXException e) {
-                System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: {1}", a[1], e.getMessage()));
+                System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: {1}", entry.url, e.getMessage()));
                 e.printStackTrace();
             }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 3795)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 3796)
@@ -2,8 +2,12 @@
 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.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.TreeSet;
 
@@ -20,4 +24,5 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
+import org.openstreetmap.josm.gui.preferences.StyleSourceEditor.StyleSourceInfo;
 import org.openstreetmap.josm.tools.GBC;
 
@@ -40,6 +45,5 @@
                 Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
 
-        sources = new StyleSourceEditor("mappaint.style.sources", "mappaint.icon.sources",
-        "http://josm.openstreetmap.de/styles");
+        sources = new MapPaintSourceEditor();
 
         Collection<String> styles = new TreeSet<String>(MapPaintStyles.getStyles().getStyleNames());
@@ -60,6 +64,4 @@
         final JPanel panel = new JPanel(new GridBagLayout());
         panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        panel.add(enableDefault, GBC.std().insets(5,5,5,0));
-        panel.add(enableIconDefault, GBC.eol().insets(5,5,5,0));
 
         panel.add(new JLabel(tr("Used style")), GBC.std().insets(5,5,0,5));
@@ -68,4 +70,6 @@
 
         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);
 
@@ -84,4 +88,81 @@
     }
 
+    class MapPaintSourceEditor extends StyleSourceEditor {
+
+        final private String iconpref = "mappaint.icon.sources";
+
+        public MapPaintSourceEditor() {
+            super("http://josm.openstreetmap.de/styles");
+        }
+
+        @Override
+        public Collection<? extends SourceEntry> getInitialSourcesList() {
+            return (new MapPaintPrefMigration()).get();
+        }
+
+        @Override
+        public boolean finish() {
+            List<SourceEntry> activeStyles = activeStylesModel.getStyles();
+
+            boolean changed = (new MapPaintPrefMigration()).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<StyleSourceInfo> getDefault() {
+            return (new MapPaintPrefMigration()).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:
+                    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 restart = Main.pref.put("mappaint.style.enable-defaults", enableDefault.isSelected());
@@ -112,3 +193,37 @@
         MapPaintStyles.readFromPreferences();
     }
+
+    public static class MapPaintPrefMigration extends StyleSourceEditor.SourcePrefMigration {
+
+        public MapPaintPrefMigration() {
+            super("mappaint.style.sources",
+                  "mappaint.style.enable-defaults",
+                  "mappaint.style.sources-list");
+        }
+
+        @Override
+        public Collection<StyleSourceInfo> getDefault() {
+            StyleSourceInfo i = new StyleSourceInfo("elemstyles.xml", "resource://data/elemstyles.xml");
+            i.name = "standard";
+            i.shortdescription = tr("Internal Style");
+            i.description = tr("Internal style to be used as base for runtime switchable overlay styles");
+            return Collections.singletonList(i);
+        }
+
+        @Override
+        public Collection<String> serialize(SourceEntry entry) {
+            return Arrays.asList(new String[] {entry.url, entry.name, entry.shortdescription, 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/SourceEntry.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java	(revision 3796)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java	(revision 3796)
@@ -0,0 +1,73 @@
+package org.openstreetmap.josm.gui.preferences;
+
+import static org.openstreetmap.josm.tools.Utils.equal;
+
+/**
+ * A source entry primarily used to save the user's selection of mappaint styles, 
+ * but also for preset sources.
+ */
+public class SourceEntry {
+
+    /**
+     *  A URL can be anything that MirroredInputStream understands, i.e.
+     *  a local file, http://, or a file from the current jar
+     */
+    public String url;
+
+    /**
+     *  Name is used as a namespace for color preferences and (currently) only
+     *  one file with a name can be loaded at a time. Additional styles must
+     *  either have the same name as the main style or no name at all.
+     *  If no name is provided, it will be set to the default value "standard".
+     *  The name can also be given in the xml file as attribute for the rules tag.
+     *  (This overrides the name given in the preferences, otherwise both
+     *  methods are equivalent.)
+     */
+    public String name;
+
+    /**
+     * A short description that can be used as menu entry.
+     */
+    public String shortdescription;
+
+    /**
+     * active is a boolean flag that can be used to turn the style on or off
+     * at runtime.
+     */
+    public boolean active;
+
+    public SourceEntry(String url, String name, String shortdescription, Boolean active) {
+        this.url = url;
+        this.name = equal(name, "") ? null : name;
+        this.shortdescription = equal(shortdescription, "") ? null : shortdescription;
+        this.active = active;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        final SourceEntry other = (SourceEntry) obj;
+        return equal(other.url, url) && 
+                equal(other.name, name) &&
+                equal(other.shortdescription, shortdescription) &&
+                other.active == active;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 5;
+        hash = 89 * hash + (this.url != null ? this.url.hashCode() : 0);
+        hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0);
+        hash = 89 * hash + (this.shortdescription != null ? this.shortdescription.hashCode() : 0);
+        hash = 89 * hash + (this.active ? 1 : 0);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return shortdescription != null ? shortdescription : url;
+    }
+
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java	(revision 3795)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java	(revision 3796)
@@ -4,12 +4,17 @@
 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.Utils.equal;
 
 import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
+import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.awt.event.FocusAdapter;
 import java.awt.event.FocusEvent;
 import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.io.BufferedReader;
@@ -34,4 +39,5 @@
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
+import javax.swing.Box;
 import javax.swing.DefaultListModel;
 import javax.swing.DefaultListSelectionModel;
@@ -55,8 +61,13 @@
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
 import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
 import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
@@ -68,45 +79,61 @@
 import org.xml.sax.SAXException;
 
-public class StyleSourceEditor extends JPanel {
-    private JTable tblActiveStyles;
-    private ActiveStylesModel activeStylesModel;
-    private JList lstAvailableStyles;
-    private AvailableStylesListModel availableStylesModel;
-    private JTable tblIconPaths = null;
-    private IconPathTableModel iconPathsModel;
-    private String pref;
-    private String iconpref;
-    private boolean stylesInitiallyLoaded;
-    private String availableStylesUrl;
+public abstract class StyleSourceEditor extends JPanel {
+
+    protected JTable tblActiveStyles;
+    protected ActiveStylesModel activeStylesModel;
+    protected JList lstAvailableStyles;
+    protected AvailableStylesListModel availableStylesModel;
+    protected JTable tblIconPaths = null;
+    protected IconPathTableModel iconPathsModel;
+    protected boolean stylesInitiallyLoaded;
+    protected String availableStylesUrl;
 
     /**
-     *
-     * @param stylesPreferencesKey the preferences key with the list of active style sources (filenames and URLs)
-     * @param iconsPreferenceKey the preference key with the list of icon sources (can be null)
+     * constructor
      * @param availableStylesUrl the URL to the list of available style sources
      */
-    public StyleSourceEditor(String stylesPreferencesKey, String iconsPreferenceKey, final String availableStylesUrl) {
+    public StyleSourceEditor(final String availableStylesUrl) {
 
         DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
+        lstAvailableStyles = new JList(availableStylesModel = new AvailableStylesListModel(selectionModel));
+        lstAvailableStyles.setSelectionModel(selectionModel);
+        lstAvailableStyles.setCellRenderer(new StyleSourceCellRenderer());
+        this.availableStylesUrl = availableStylesUrl;
+
+        selectionModel = new DefaultListSelectionModel();
         tblActiveStyles = new JTable(activeStylesModel = new ActiveStylesModel(selectionModel));
         tblActiveStyles.putClientProperty("terminateEditOnFocusLost", true);
         tblActiveStyles.setSelectionModel(selectionModel);
         tblActiveStyles.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        tblActiveStyles.setShowGrid(false);
+        tblActiveStyles.setIntercellSpacing(new Dimension(0, 0));
         tblActiveStyles.setTableHeader(null);
-        tblActiveStyles.getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor(true));
-        tblActiveStyles.setRowHeight(20);
-        activeStylesModel.setActiveStyles(Main.pref.getCollection(stylesPreferencesKey, null));
-
-        selectionModel = new DefaultListSelectionModel();
-        lstAvailableStyles = new JList(availableStylesModel =new AvailableStylesListModel(selectionModel));
-        lstAvailableStyles.setSelectionModel(selectionModel);
-        lstAvailableStyles.setCellRenderer(new StyleSourceCellRenderer());
-        this.availableStylesUrl = availableStylesUrl;
-
-        this.pref = stylesPreferencesKey;
-        this.iconpref = iconsPreferenceKey;
-
-        EditActiveStyleAction editActiveStyleAction = new EditActiveStyleAction();
+        tblActiveStyles.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+        SourceEntryRenderer sourceEntryRenderer = new SourceEntryRenderer();
+        tblActiveStyles.getColumnModel().getColumn(0).setCellRenderer(sourceEntryRenderer);
+        activeStylesModel.addTableModelListener(new TableModelListener() {
+            // Force swing to show horizontal scrollbars for the JTable
+            // Yes, this is a little ugly, but should work
+            @Override
+            public void tableChanged(TableModelEvent e) {
+                adjustColumnWidth(tblActiveStyles, 0);
+            }
+        });
+        activeStylesModel.setActiveStyles(getInitialSourcesList());
+        
+        final EditActiveStyleAction editActiveStyleAction = new EditActiveStyleAction();
         tblActiveStyles.getSelectionModel().addListSelectionListener(editActiveStyleAction);
+        tblActiveStyles.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2) {
+                    int row = tblActiveStyles.rowAtPoint(e.getPoint());
+                    if (row < 0 || row >= tblActiveStyles.getRowCount())
+                        return;
+                    editActiveStyleAction.actionPerformed(null);
+                }
+            }
+        });
 
         RemoveActiveStylesAction removeActiveStylesAction = new RemoveActiveStylesAction();
@@ -121,8 +148,57 @@
         setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
         setLayout(new GridBagLayout());
-        add(new JLabel(tr("Active styles:")), GBC.eol().insets(11, 5, 5, 0));
+
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 0.5;
+        gbc.gridwidth = 2;
+        gbc.anchor = GBC.WEST;
+        gbc.insets = new Insets(5, 11, 0, 0);
+
+        add(new JLabel(getStr(I18nString.AVAILABLE_SOURCES)), gbc);
+
+        gbc.gridx = 2;
+        gbc.insets = new Insets(5, 0, 0, 6);
+
+        add(new JLabel(getStr(I18nString.ACTIVE_SOURCES)), gbc);
+
+        gbc.gridwidth = 1;
+        gbc.gridx = 0;
+        gbc.gridy++;
+        gbc.weighty = 0.8;
+        gbc.fill = GBC.BOTH;
+        gbc.anchor = GBC.CENTER;
+        gbc.insets = new Insets(0, 11, 0, 0);
+
+        JScrollPane sp1 = new JScrollPane(lstAvailableStyles);
+        add(sp1, gbc);
+
+        gbc.gridx = 1;
+        gbc.weightx = 0.0;
+        gbc.fill = GBC.VERTICAL;
+        gbc.insets = new Insets(0, 0, 0, 0);
+
+        JToolBar middleTB = new JToolBar();
+        middleTB.setFloatable(false);
+        middleTB.setBorderPainted(false);
+        middleTB.setOpaque(false);
+        middleTB.add(Box.createHorizontalGlue());
+        middleTB.add(activate);
+        middleTB.add(Box.createHorizontalGlue());
+        add(middleTB, gbc);
+
+        gbc.gridx++;
+        gbc.weightx = 0.5;
+        gbc.fill = GBC.BOTH;
+
         JScrollPane sp = new JScrollPane(tblActiveStyles);
-        add(sp, GBC.std().insets(10, 0, 3, 0).fill(GBC.BOTH));
+        add(sp, gbc);
         sp.setColumnHeaderView(null);
+
+        gbc.gridx++;
+        gbc.weightx = 0.0;
+        gbc.fill = GBC.VERTICAL;
+        gbc.insets = new Insets(0, 0, 0, 6);
 
         JToolBar sideButtonTB = new JToolBar(JToolBar.VERTICAL);
@@ -133,92 +209,165 @@
         sideButtonTB.add(editActiveStyleAction);
         sideButtonTB.add(removeActiveStylesAction);
-        add(sideButtonTB, GBC.eol().insets(0, 0, 10, 0).fill(GBC.VERTICAL));
-
-        JToolBar bottomButtonTB = new JToolBar();
-        bottomButtonTB.setFloatable(false);
-        bottomButtonTB.setBorderPainted(false);
-        bottomButtonTB.setOpaque(false);
-        bottomButtonTB.add(activate);
-        add(bottomButtonTB, GBC.eol().insets(12, 4, 5, 4).fill(GBC.HORIZONTAL));
-
-        add(new JLabel(tr("Available styles (from {0}):", availableStylesUrl)), GBC.eol().insets(11, 0, 5, 0));
-        add(new JScrollPane(lstAvailableStyles), GBC.std().insets(10, 0, 3, 0).fill(GBC.BOTH));
-
-        sideButtonTB = new JToolBar(JToolBar.VERTICAL);
-        sideButtonTB.setFloatable(false);
-        sideButtonTB.setBorderPainted(false);
-        sideButtonTB.setOpaque(false);
-        sideButtonTB.add(new ReloadStylesAction(availableStylesUrl));
-        add(sideButtonTB, GBC.eol().insets(0, 0, 10, 0).fill(GBC.VERTICAL));
-        
-        if (iconsPreferenceKey != null) {
-            selectionModel = new DefaultListSelectionModel();
-            tblIconPaths = new JTable(iconPathsModel = new IconPathTableModel(selectionModel));
-            tblIconPaths.setSelectionModel(selectionModel);
-            tblIconPaths.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-            tblIconPaths.setTableHeader(null);
-            tblIconPaths.getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor(false));
-            tblIconPaths.setRowHeight(20);
-            iconPathsModel.setIconPaths(Main.pref.getCollection(iconsPreferenceKey, null));
-
-            EditIconPathAction editIconPathAction = new EditIconPathAction();
-            tblIconPaths.getSelectionModel().addListSelectionListener(editIconPathAction);
-
-            RemoveIconPathAction removeIconPathAction = new RemoveIconPathAction();
-            tblIconPaths.getSelectionModel().addListSelectionListener(removeIconPathAction);
-            tblIconPaths.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "delete");
-            tblIconPaths.getActionMap().put("delete", removeIconPathAction);
-
-            add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(5, 10, 5, 10));
-            add(new JLabel(tr("Icon paths:")), GBC.eol().insets(11, 0, 5, 0));
-            add(sp = new JScrollPane(tblIconPaths), GBC.std().insets(10, 0, 3, 0).fill(GBC.BOTH));
-            sp.setColumnHeaderView(null);
-            sideButtonTB = new JToolBar(JToolBar.VERTICAL);
-            sideButtonTB.setFloatable(false);
-            sideButtonTB.setBorderPainted(false);
-            sideButtonTB.setOpaque(false);
-            add(sideButtonTB, GBC.eol().insets(0, 0, 10, 0).fill(GBC.VERTICAL));
-            sideButtonTB.add(new NewIconPathAction());
-            sideButtonTB.add(editIconPathAction);
-            sideButtonTB.add(removeIconPathAction);
-        }
+        add(sideButtonTB, gbc);
+
+        gbc.gridx = 0;
+        gbc.gridy++;
+        gbc.weighty = 0.0;
+        gbc.weightx = 0.5;
+        gbc.fill = GBC.HORIZONTAL;
+        gbc.anchor = GBC.WEST;
+        gbc.insets = new Insets(0, 11, 0, 0);
+
+        JToolBar bottomLeftTB = new JToolBar(JToolBar.VERTICAL);
+        bottomLeftTB.setFloatable(false);
+        bottomLeftTB.setBorderPainted(false);
+        bottomLeftTB.setOpaque(false);
+        bottomLeftTB.add(new ReloadStylesAction(availableStylesUrl));
+        middleTB.add(Box.createHorizontalGlue());
+        add(bottomLeftTB, gbc);
+
+        gbc.gridx = 2;
+        gbc.anchor = GBC.CENTER;
+        gbc.insets = new Insets(0, 0, 0, 0);
+
+        JToolBar bottomRightTB = new JToolBar();
+        bottomRightTB.setFloatable(false);
+        bottomRightTB.setBorderPainted(false);
+        bottomRightTB.setOpaque(false);
+        bottomRightTB.add(Box.createHorizontalGlue());
+        bottomRightTB.add(new JButton(new ResetAction()));
+        add(bottomRightTB, gbc);
+
+        /***
+         * Icon configuration
+         **/
+
+        selectionModel = new DefaultListSelectionModel();
+        tblIconPaths = new JTable(iconPathsModel = new IconPathTableModel(selectionModel));
+        tblIconPaths.setSelectionModel(selectionModel);
+        tblIconPaths.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        tblIconPaths.setTableHeader(null);
+        tblIconPaths.getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor(false));
+        tblIconPaths.setRowHeight(20);
+        tblIconPaths.putClientProperty("terminateEditOnFocusLost", true);
+        iconPathsModel.setIconPaths(getInitialIconPathsList());
+
+        EditIconPathAction editIconPathAction = new EditIconPathAction();
+        tblIconPaths.getSelectionModel().addListSelectionListener(editIconPathAction);
+
+        RemoveIconPathAction removeIconPathAction = new RemoveIconPathAction();
+        tblIconPaths.getSelectionModel().addListSelectionListener(removeIconPathAction);
+        tblIconPaths.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "delete");
+        tblIconPaths.getActionMap().put("delete", removeIconPathAction);
+
+        gbc.gridx = 0;
+        gbc.gridy++;
+        gbc.weightx = 1.0;
+        gbc.gridwidth = GBC.REMAINDER;
+        gbc.insets = new Insets(8, 11, 8, 6);
+
+        add(new JSeparator(), gbc);
+
+        gbc.gridy++;
+        gbc.insets = new Insets(0, 11, 0, 6);
+
+        add(new JLabel(tr("Icon paths:")), gbc);
+
+        gbc.gridy++;
+        gbc.weighty = 0.2;
+        gbc.gridwidth = 3;
+        gbc.fill = GBC.BOTH;
+        gbc.insets = new Insets(0, 11, 0, 0);
+
+        add(sp = new JScrollPane(tblIconPaths), gbc);
+        sp.setColumnHeaderView(null);
+
+        gbc.gridx = 3;
+        gbc.gridwidth = 1;
+        gbc.weightx = 0.0;
+        gbc.fill = GBC.VERTICAL;
+        gbc.insets = new Insets(0, 0, 0, 6);
+
+        JToolBar sideButtonTBIcons = new JToolBar(JToolBar.VERTICAL);
+        sideButtonTBIcons.setFloatable(false);
+        sideButtonTBIcons.setBorderPainted(false);
+        sideButtonTBIcons.setOpaque(false);
+        sideButtonTBIcons.add(new NewIconPathAction());
+        sideButtonTBIcons.add(editIconPathAction);
+        sideButtonTBIcons.add(removeIconPathAction);
+        add(sideButtonTBIcons, gbc);
+    }
+
+    /**
+     * Load the list of source entries that the user has configured.
+     */
+    abstract public Collection<? extends SourceEntry> getInitialSourcesList();
+
+    /**
+     * Load the list of configured icon paths.
+     */
+    abstract public Collection<String> getInitialIconPathsList();
+
+    /**
+     * Get the default list of entries (used when resetting the list).
+     */
+    abstract public Collection<StyleSourceInfo> getDefault();
+
+    /**
+     * Save the settings after user clicked "Ok".
+     * @return true if restart is required
+     */
+    abstract public boolean finish();
+
+    /**
+     * Provide the GUI strings. (There are differences for MapPaint and Preset)
+     */
+    abstract protected String getStr(I18nString ident);
+
+    /**
+     * Identifiers for strings that need to be provided.
+     */
+    protected enum I18nString { AVAILABLE_SOURCES, ACTIVE_SOURCES, 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,
+            ILLEGAL_FORMAT_OF_ENTRY }
+
+    /**
+     * adjust the preferred width of column col to the maximum preferred width of the cells
+     * requires JTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+     */
+    private static void adjustColumnWidth(JTable tbl, int col) {
+        int maxwidth = 0;
+		for (int row=0; row<tbl.getRowCount(); row++) {
+            TableCellRenderer tcr = tbl.getCellRenderer(row, col);
+                Object val = tbl.getValueAt(row, col);
+                Component comp = tcr.getTableCellRendererComponent(tbl, val, false, false, row, col);
+                maxwidth = Math.max(comp.getPreferredSize().width, maxwidth);
+		}
+		tbl.getColumnModel().getColumn(col).setPreferredWidth(maxwidth);
     }
 
     public boolean hasActiveStylesChanged() {
-        return !activeStylesModel.getStyles().equals(Main.pref.getCollection(pref, Collections.<String>emptyList()));
-    }
-
-    public Collection<String> getActiveStyles() {
+        Collection<? extends SourceEntry> prev = getInitialSourcesList();
+        List<SourceEntry> cur = activeStylesModel.getStyles();
+        if (prev.size() != cur.size())
+            return true;
+        Iterator<? extends SourceEntry> p = prev.iterator();
+        Iterator<SourceEntry> c = cur.iterator();
+        while (p.hasNext()) {
+            SourceEntry pe = p.next();
+            SourceEntry ce = c.next();
+            if (!equal(pe.url, ce.url) || !equal(pe.name, ce.name) || pe.active != ce.active)
+                return true;
+        }
+        return false;
+    }
+
+    public Collection<SourceEntry> getActiveStyles() {
         return activeStylesModel.getStyles();
     }
 
-    public void removeSource(String source) {
-        activeStylesModel.remove(source);
-    }
-
-    public boolean finish() {
-        boolean changed = false;
-        List<String> activeStyles = activeStylesModel.getStyles();
-
-        if (activeStyles.size() > 0) {
-            if (Main.pref.putCollection(pref, activeStyles)) {
-                changed = true;
-            }
-        } else if (Main.pref.putCollection(pref, null)) {
-            changed = true;
-        }
-
-        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;
+    public void removeSources(Collection<Integer> idxs) {
+        activeStylesModel.removeIdxs(idxs);
     }
 
@@ -234,5 +383,5 @@
     }
 
-    static class AvailableStylesListModel extends DefaultListModel {
+    protected static class AvailableStylesListModel extends DefaultListModel {
         private ArrayList<StyleSourceInfo> data;
         private DefaultListSelectionModel selectionModel;
@@ -286,11 +435,11 @@
     }
 
-    static class ActiveStylesModel extends AbstractTableModel {
-        private ArrayList<String> data;
+    protected static class ActiveStylesModel extends AbstractTableModel {
+        private List<SourceEntry> data;
         private DefaultListSelectionModel selectionModel;
 
         public ActiveStylesModel(DefaultListSelectionModel selectionModel) {
             this.selectionModel = selectionModel;
-            this.data = new ArrayList<String>();
+            this.data = new ArrayList<SourceEntry>();
         }
 
@@ -303,5 +452,6 @@
         }
 
-        public Object getValueAt(int rowIndex, int columnIndex) {
+        @Override
+        public SourceEntry getValueAt(int rowIndex, int columnIndex) {
             return data.get(rowIndex);
         }
@@ -309,5 +459,5 @@
         @Override
         public boolean isCellEditable(int rowIndex, int columnIndex) {
-            return true;
+            return false;
         }
 
@@ -317,17 +467,16 @@
         }
 
-        public void setActiveStyles(Collection<String> styles) {
+        public void setActiveStyles(Collection<? extends SourceEntry> sources) {
+            //abstract public Collection<? extends StyleSourceEntry> getInitialStyleSources();
             data.clear();
-            if (styles !=null) {
-                data.addAll(styles);
-            }
-            sort();
+            if (sources != null) {
+                data.addAll(sources);
+            }
             fireTableDataChanged();
         }
 
-        public void addStyle(String style) {
+        public void addStyle(SourceEntry style) {
             if (style == null) return;
             data.add(style);
-            sort();
             fireTableDataChanged();
             int idx = data.indexOf(style);
@@ -340,8 +489,377 @@
             if (style == null) return;
             if (pos < 0 || pos >= getRowCount()) return;
-            data.set(pos, style);
+            data.get(pos).url = style;
+            fireTableDataChanged();
+            int idx = data.indexOf(style);
+            if (idx >= 0) {
+                selectionModel.setSelectionInterval(idx, idx);
+            }
+        }
+
+        public void removeSelected() {
+            Iterator<SourceEntry> it = data.iterator();
+            int i=0;
+            while(it.hasNext()) {
+                it.next();
+                if (selectionModel.isSelectedIndex(i)) {
+                    it.remove();
+                }
+                i++;
+            }
+            fireTableDataChanged();
+        }
+
+        public void removeIdxs(Collection<Integer> idxs) {
+            List<SourceEntry> newData = new ArrayList<SourceEntry>();
+            for (int i=0; i<data.size(); ++i) {
+                if (!idxs.contains(i)) {
+                    newData.add(data.get(i));
+                }
+            }
+            data = newData;
+            fireTableDataChanged();
+        }
+
+        public void addStylesFromSources(List<StyleSourceInfo> sources) {
+            if (sources == null) return;
+            for (StyleSourceInfo info: sources) {
+                data.add(new SourceEntry(info.url, info.name, info.getDisplayName(), true));
+            }
+            fireTableDataChanged();
+            selectionModel.clearSelection();
+            for (StyleSourceInfo info: sources) {
+                int pos = data.indexOf(info);
+                if (pos >=0) {
+                    selectionModel.addSelectionInterval(pos, pos);
+                }
+            }
+        }
+
+        public List<SourceEntry> getStyles() {
+            return new ArrayList<SourceEntry>(data);
+        }
+    }
+
+    public static class StyleSourceInfo extends SourceEntry {
+        public String simpleFileName;
+        public String version;
+        public String author;
+        public String link;
+        public String description;
+
+        public StyleSourceInfo(String simpleFileName, String url) {
+            super(url, null, null, true);
+            this.simpleFileName = simpleFileName;
+            version = author = link = description = shortdescription = null;
+        }
+
+        /**
+         * @return string representation for GUI list or menu entry
+         */
+        public String getDisplayName() {
+            return shortdescription == null ? simpleFileName : shortdescription;
+        }
+
+        public String getTooltip() {
+            String s = tr("Short Description: {0}", getDisplayName()) + "<br>" + tr("URL: {0}", url);
+            if (author != null) {
+                s += "<br>" + tr("Author: {0}", author);
+            }
+            if (link != null) {
+                s += "<br>" + tr("Webpage: {0}", link);
+            }
+            if (description != null) {
+                s += "<br>" + tr("Description: {0}", description);
+            }
+            if (version != null) {
+                s += "<br>" + tr("Version: {0}", version);
+            }
+            return "<html>" + s + "</html>";
+        }
+
+        @Override
+        public String toString() {
+            return "<html><b>" + getDisplayName() + "</b> (" + url + ")</html>";
+        }
+    }
+
+    protected class EditSourceEntryDialog extends ExtendedDialog {
+
+        /**
+         * We call this text field "name", but it is actually the shortdescription.
+         */
+        private JTextField tfName;
+        private JTextField tfURL;
+
+        public EditSourceEntryDialog(Component parent, String title, SourceEntry e) {
+            super(parent,
+                    title,
+                    new String[] {tr("Ok"), tr("Cancel")});
+
+            JPanel p = new JPanel(new GridBagLayout());
+
+            tfName = new JTextField(60);
+            p.add(new JLabel(tr("Name (optional):")), GBC.std().insets(15, 0, 5, 5));
+            p.add(tfName, GBC.eol().insets(0, 0, 5, 5));
+
+            tfURL = new JTextField(60);
+            p.add(new JLabel(tr("URL / File:")), GBC.std().insets(15, 0, 5, 0));
+            p.add(tfURL, GBC.std().insets(0, 0, 5, 0));
+            JButton fileChooser = new JButton(new LaunchFileChooserAction());
+            fileChooser.setMargin(new Insets(0, 0, 0, 0));
+            p.add(fileChooser, GBC.eol().insets(0, 0, 5, 0));
+
+            if (e != null) {
+                if (e.shortdescription != null) {
+                    tfName.setText(e.shortdescription);
+                }
+                tfURL.setText(e.url);
+            }
+
+            setButtonIcons(new String[] {"ok", "cancel"});
+            setContent(p);
+        }
+
+        class LaunchFileChooserAction extends AbstractAction {
+            public LaunchFileChooserAction() {
+                putValue(SMALL_ICON, ImageProvider.get("open"));
+                putValue(SHORT_DESCRIPTION, tr("Launch a file chooser to select a file"));
+            }
+
+            protected void prepareFileChooser(String url, JFileChooser fc) {
+                if (url == null || url.trim().length() == 0) return;
+                URL sourceUrl = null;
+                try {
+                    sourceUrl = new URL(url);
+                } catch(MalformedURLException e) {
+                    File f = new File(url);
+                    if (f.isFile()) {
+                        f = f.getParentFile();
+                    }
+                    if (f != null) {
+                        fc.setCurrentDirectory(f);
+                    }
+                    return;
+                }
+                if (sourceUrl.getProtocol().startsWith("file")) {
+                    File f = new File(sourceUrl.getPath());
+                    if (f.isFile()) {
+                        f = f.getParentFile();
+                    }
+                    if (f != null) {
+                        fc.setCurrentDirectory(f);
+                    }
+                }
+            }
+
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser fc= new JFileChooser();
+                prepareFileChooser(tfURL.getText(), fc);
+                int ret = fc.showOpenDialog(JOptionPane.getFrameForComponent(StyleSourceEditor.this));
+                if (ret != JFileChooser.APPROVE_OPTION)
+                    return;
+                tfURL.setText(fc.getSelectedFile().toString());
+            }
+        }
+
+        public String getShortdescription() {
+            return tfName.getText();
+        }
+
+        public String getURL() {
+            return tfURL.getText();
+        }
+    }
+
+    class NewActiveStyleAction extends AbstractAction {
+        public NewActiveStyleAction() {
+            putValue(NAME, tr("New"));
+            putValue(SHORT_DESCRIPTION, tr("Add a filename or an URL of an active style"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
+        }
+
+        public void actionPerformed(ActionEvent evt) {
+            EditSourceEntryDialog editEntryDialog = new EditSourceEntryDialog(
+                    StyleSourceEditor.this,
+                    getStr(I18nString.NEW_SOURCE_ENTRY),
+                    null);
+            editEntryDialog.showDialog();
+            if (editEntryDialog.getValue() == 1) {
+                activeStylesModel.addStyle(new SourceEntry(
+                        editEntryDialog.getURL(),
+                        null, editEntryDialog.getShortdescription(), true));
+                activeStylesModel.fireTableDataChanged();
+            }
+        }
+    }
+
+    class RemoveActiveStylesAction extends AbstractAction implements ListSelectionListener {
+
+        public RemoveActiveStylesAction() {
+            putValue(NAME, tr("Remove"));
+            putValue(SHORT_DESCRIPTION, getStr(I18nString.REMOVE_SOURCE_TOOLTIP));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
+            updateEnabledState();
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(tblActiveStyles.getSelectedRowCount() > 0);
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            activeStylesModel.removeSelected();
+        }
+    }
+
+    class EditActiveStyleAction extends AbstractAction implements ListSelectionListener {
+        public EditActiveStyleAction() {
+            putValue(NAME, tr("Edit"));
+            putValue(SHORT_DESCRIPTION, getStr(I18nString.EDIT_SOURCE_TOOLTIP));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
+            updateEnabledState();
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(tblActiveStyles.getSelectedRowCount() == 1);
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent evt) {
+            int pos = tblActiveStyles.getSelectedRow();
+            if (pos < 0 || pos >= tblActiveStyles.getRowCount())
+                return;
+
+            SourceEntry e = activeStylesModel.getValueAt(pos, 0);
+
+            EditSourceEntryDialog editEntryDialog = new EditSourceEntryDialog(
+                    StyleSourceEditor.this, tr("Edit source entry:"), e);
+            editEntryDialog.showDialog();
+            if (editEntryDialog.getValue() == 1) {
+                if (e.shortdescription != null || !equal(editEntryDialog.getShortdescription(), "")) {
+                    e.shortdescription = editEntryDialog.getShortdescription();
+                    if (equal(e.shortdescription, "")) {
+                        e.shortdescription = null;
+                    }
+                }
+                e.url = editEntryDialog.getURL();
+                activeStylesModel.fireTableCellUpdated(pos, 0);
+            }
+        }
+    }
+
+    class ActivateStylesAction extends AbstractAction implements ListSelectionListener {
+        public ActivateStylesAction() {
+            putValue(SHORT_DESCRIPTION, getStr(I18nString.ACTIVATE_TOOLTIP));
+            putValue(SMALL_ICON, ImageProvider.get("preferences", "activatestyle"));
+            updateEnabledState();
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(lstAvailableStyles.getSelectedIndices().length > 0);
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            List<StyleSourceInfo> styleSources = availableStylesModel.getSelected();
+            activeStylesModel.addStylesFromSources(styleSources);
+        }
+    }
+
+    class ResetAction extends AbstractAction {
+
+        public ResetAction() {
+            putValue(NAME, tr("Reset"));
+            putValue(SHORT_DESCRIPTION, tr("Reset to default"));
+            putValue(SMALL_ICON, ImageProvider.get("preferences", "reset"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            activeStylesModel.setActiveStyles(getDefault());
+        }
+    }
+
+    class ReloadStylesAction extends AbstractAction {
+        private String url;
+        public ReloadStylesAction(String url) {
+            putValue(NAME, tr("Reload"));
+            putValue(SHORT_DESCRIPTION, tr(getStr(I18nString.RELOAD_ALL_AVAILABLE), url));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs/refresh"));
+            this.url = url;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            MirroredInputStream.cleanup(url);
+            reloadAvailableStyles(url);
+        }
+    }
+
+    protected static class IconPathTableModel extends AbstractTableModel {
+        private ArrayList<String> data;
+        private DefaultListSelectionModel selectionModel;
+
+        public IconPathTableModel(DefaultListSelectionModel selectionModel) {
+            this.selectionModel = selectionModel;
+            this.data = new ArrayList<String>();
+        }
+
+        public int getColumnCount() {
+            return 1;
+        }
+
+        public int getRowCount() {
+            return data == null ? 0 : data.size();
+        }
+
+        public Object getValueAt(int rowIndex, int columnIndex) {
+            return data.get(rowIndex);
+        }
+
+        @Override
+        public boolean isCellEditable(int rowIndex, int columnIndex) {
+            return true;
+        }
+
+        @Override
+        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+            updatePath(rowIndex, (String)aValue);
+        }
+
+        public void setIconPaths(Collection<String> styles) {
+            data.clear();
+            if (styles !=null) {
+                data.addAll(styles);
+            }
             sort();
             fireTableDataChanged();
-            int idx = data.indexOf(style);
+        }
+
+        public void addPath(String path) {
+            if (path == null) return;
+            data.add(path);
+            sort();
+            fireTableDataChanged();
+            int idx = data.indexOf(path);
+            if (idx >= 0) {
+                selectionModel.setSelectionInterval(idx, idx);
+            }
+        }
+
+        public void updatePath(int pos, String path) {
+            if (path == null) return;
+            if (pos < 0 || pos >= getRowCount()) return;
+            data.set(pos, path);
+            sort();
+            fireTableDataChanged();
+            int idx = data.indexOf(path);
             if (idx >= 0) {
                 selectionModel.setSelectionInterval(idx, idx);
@@ -360,9 +878,5 @@
             }
             fireTableDataChanged();
-        }
-
-        public void remove(String source) {
-            data.remove(source);
-            fireTableDataChanged();
+            selectionModel.clearSelection();
         }
 
@@ -382,258 +896,4 @@
         }
 
-        public void addStylesFromSources(List<StyleSourceInfo> sources) {
-            if (sources == null) return;
-            for (StyleSourceInfo info: sources) {
-                data.add(info.url);
-            }
-            sort();
-            fireTableDataChanged();
-            selectionModel.clearSelection();
-            for (StyleSourceInfo info: sources) {
-                int pos = data.indexOf(info.url);
-                if (pos >=0) {
-                    selectionModel.addSelectionInterval(pos, pos);
-                }
-            }
-        }
-
-        public List<String> getStyles() {
-            return new ArrayList<String>(data);
-        }
-
-        public String getStyle(int pos) {
-            return data.get(pos);
-        }
-    }
-
-    public static class StyleSourceInfo {
-        String version;
-        String name;
-        String url;
-        String author;
-        String link;
-        String description;
-        String shortdescription;
-
-        public StyleSourceInfo(String name, String url) {
-            this.name = name;
-            this.url = url;
-            version = author = link = description = shortdescription = null;
-        }
-
-        public String getName() {
-            return shortdescription == null ? name : shortdescription;
-        }
-
-        public String getTooltip() {
-            String s = tr("Short Description: {0}", getName()) + "<br>" + tr("URL: {0}", url);
-            if (author != null) {
-                s += "<br>" + tr("Author: {0}", author);
-            }
-            if (link != null) {
-                s += "<br>" + tr("Webpage: {0}", link);
-            }
-            if (description != null) {
-                s += "<br>" + tr("Description: {0}", description);
-            }
-            if (version != null) {
-                s += "<br>" + tr("Version: {0}", version);
-            }
-            return "<html>" + s + "</html>";
-        }
-
-        @Override
-        public String toString() {
-            return getName() + " (" + url + ")";
-        }
-    }
-
-    class NewActiveStyleAction extends AbstractAction {
-        public NewActiveStyleAction() {
-            putValue(NAME, tr("New"));
-            putValue(SHORT_DESCRIPTION, tr("Add a filename or an URL of an active style"));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
-        }
-
-        public void actionPerformed(ActionEvent e) {
-            activeStylesModel.addStyle("");
-            tblActiveStyles.requestFocusInWindow();
-            tblActiveStyles.editCellAt(activeStylesModel.getRowCount()-1, 0);
-        }
-    }
-
-    class RemoveActiveStylesAction extends AbstractAction implements ListSelectionListener {
-
-        public RemoveActiveStylesAction() {
-            putValue(NAME, tr("Remove"));
-            putValue(SHORT_DESCRIPTION, tr("Remove the selected styles from the list of active styles"));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
-            updateEnabledState();
-        }
-
-        protected void updateEnabledState() {
-            setEnabled(tblActiveStyles.getSelectedRowCount() > 0);
-        }
-
-        public void valueChanged(ListSelectionEvent e) {
-            updateEnabledState();
-        }
-
-        public void actionPerformed(ActionEvent e) {
-            activeStylesModel.removeSelected();
-        }
-    }
-
-    class EditActiveStyleAction extends AbstractAction implements ListSelectionListener {
-        public EditActiveStyleAction() {
-            putValue(NAME, tr("Edit"));
-            putValue(SHORT_DESCRIPTION, tr("Edit the filename or URL for the selected active style"));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
-            updateEnabledState();
-        }
-
-        protected void updateEnabledState() {
-            setEnabled(tblActiveStyles.getSelectedRowCount() == 1);
-        }
-
-        public void valueChanged(ListSelectionEvent e) {
-            updateEnabledState();
-        }
-
-        public void actionPerformed(ActionEvent e) {
-            int pos = tblActiveStyles.getSelectedRow();
-            tblActiveStyles.editCellAt(pos, 0);
-        }
-    }
-
-    class ActivateStylesAction extends AbstractAction implements ListSelectionListener {
-        public ActivateStylesAction() {
-            putValue(NAME, tr("Activate"));
-            putValue(SHORT_DESCRIPTION, tr("Add the selected available styles to the list of active styles"));
-            putValue(SMALL_ICON, ImageProvider.get("preferences", "activatestyle"));
-            updateEnabledState();
-        }
-
-        protected void updateEnabledState() {
-            setEnabled(lstAvailableStyles.getSelectedIndices().length > 0);
-        }
-
-        public void valueChanged(ListSelectionEvent e) {
-            updateEnabledState();
-        }
-
-        public void actionPerformed(ActionEvent e) {
-            List<StyleSourceInfo> styleSources = availableStylesModel.getSelected();
-            activeStylesModel.addStylesFromSources(styleSources);
-        }
-    }
-
-    class ReloadStylesAction extends AbstractAction {
-        private String url;
-        public ReloadStylesAction(String url) {
-            putValue(NAME, tr("Reload"));
-            putValue(SHORT_DESCRIPTION, tr("Reloads the list of available styles from ''{0}''", url));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs/refresh"));
-            this.url = url;
-        }
-
-        public void actionPerformed(ActionEvent e) {
-            MirroredInputStream.cleanup(url);
-            reloadAvailableStyles(url);
-        }
-    }
-
-    static class IconPathTableModel extends AbstractTableModel {
-        private ArrayList<String> data;
-        private DefaultListSelectionModel selectionModel;
-
-        public IconPathTableModel(DefaultListSelectionModel selectionModel) {
-            this.selectionModel = selectionModel;
-            this.data = new ArrayList<String>();
-        }
-
-        public int getColumnCount() {
-            return 1;
-        }
-
-        public int getRowCount() {
-            return data == null ? 0 : data.size();
-        }
-
-        public Object getValueAt(int rowIndex, int columnIndex) {
-            return data.get(rowIndex);
-        }
-
-        @Override
-        public boolean isCellEditable(int rowIndex, int columnIndex) {
-            return true;
-        }
-
-        @Override
-        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
-            updatePath(rowIndex, (String)aValue);
-        }
-
-        public void setIconPaths(Collection<String> styles) {
-            data.clear();
-            if (styles !=null) {
-                data.addAll(styles);
-            }
-            sort();
-            fireTableDataChanged();
-        }
-
-        public void addPath(String path) {
-            if (path == null) return;
-            data.add(path);
-            sort();
-            fireTableDataChanged();
-            int idx = data.indexOf(path);
-            if (idx >= 0) {
-                selectionModel.setSelectionInterval(idx, idx);
-            }
-        }
-
-        public void updatePath(int pos, String path) {
-            if (path == null) return;
-            if (pos < 0 || pos >= getRowCount()) return;
-            data.set(pos, path);
-            sort();
-            fireTableDataChanged();
-            int idx = data.indexOf(path);
-            if (idx >= 0) {
-                selectionModel.setSelectionInterval(idx, idx);
-            }
-        }
-
-        public void removeSelected() {
-            Iterator<String> it = data.iterator();
-            int i=0;
-            while(it.hasNext()) {
-                it.next();
-                if (selectionModel.isSelectedIndex(i)) {
-                    it.remove();
-                }
-                i++;
-            }
-            fireTableDataChanged();
-            selectionModel.clearSelection();
-        }
-
-        protected void sort() {
-            Collections.sort(
-                    data,
-                    new Comparator<String>() {
-                        public int compare(String o1, String o2) {
-                            if (o1.equals("") && o2.equals(""))
-                                return 0;
-                            if (o1.equals("")) return 1;
-                            if (o2.equals("")) return -1;
-                            return o1.compareTo(o2);
-                        }
-                    }
-            );
-        }
-
         public List<String> getIconPaths() {
             return new ArrayList<String>(data);
@@ -711,4 +971,5 @@
             setEnabled(list.isEnabled());
             setFont(list.getFont());
+            setFont(getFont().deriveFont(Font.PLAIN));
             setOpaque(true);
             setToolTipText(((StyleSourceInfo) value).getTooltip());
@@ -723,5 +984,5 @@
 
         public StyleSourceLoader(String url) {
-            super(tr("Loading style sources from ''{0}''", url));
+            super(tr(getStr(I18nString.LOADING_SOURCES_FROM), url));
             this.url = url;
         }
@@ -745,10 +1006,5 @@
             String emsg = e.getMessage() != null ? e.getMessage() : e.toString();
             emsg = emsg.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
-            String msg = tr("<html>Failed to load the list of style sources from<br>"
-                    + "''{0}''.<br>"
-                    + "<br>"
-                    + "Details (untranslated):<br>{1}</html>",
-                    url, emsg
-            );
+            String msg = tr(getStr(I18nString.FAILED_TO_LOAD_SOURCES_FROM), url, emsg);
 
             HelpAwareOptionPane.showOptionDialog(
@@ -757,5 +1013,5 @@
                     tr("Error"),
                     JOptionPane.ERROR_MESSAGE,
-                    ht("/Preferences/Styles#FailedToLoadStyleSources")
+                    ht(getStr(I18nString.FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC))
             );
         }
@@ -766,8 +1022,5 @@
             String lang = LanguageInfo.getLanguageCodeXML();
             try {
-                StyleSourceInfo i = new StyleSourceInfo("elemstyles.xml", "resource://data/elemstyles.xml");
-                i.shortdescription = tr("Internal style");
-                i.description = tr("Internal style to be used as base for runtime switchable overlay styles");
-                styles.add(i);
+                styles.addAll(getDefault());
                 MirroredInputStream stream = new MirroredInputStream(url);
                 InputStreamReader r;
@@ -789,5 +1042,5 @@
                         Matcher m = Pattern.compile("^\t([^:]+): *(.+)$").matcher(line);
                         if (! m.matches()) {
-                            System.err.println(tr("Warning: illegal format of entry in style list ''{0}''. Got ''{1}''", url, line));
+                            System.err.println(tr(getStr(I18nString.ILLEGAL_FORMAT_OF_ENTRY), url, line));
                             continue;
                         }
@@ -805,4 +1058,6 @@
                             } else if ("shortdescription".equals(key) && last.shortdescription == null) {
                                 last.shortdescription = value;
+                            } else if ("name".equals(key) && last.name == null) {
+                                last.name = value;
                             } else if ((lang + "author").equals(key)) {
                                 last.author = value;
@@ -821,5 +1076,5 @@
                             styles.add(last = new StyleSourceInfo(m.group(1), m.group(2)));
                         } else {
-                            System.err.println(tr("Warning: illegal format of entry in style list ''{0}''. Got ''{1}''", url, line));
+                            System.err.println(tr(getStr(I18nString.ILLEGAL_FORMAT_OF_ENTRY), url, line));
                         }
                     }
@@ -835,4 +1090,27 @@
             }
             availableStylesModel.setStyleSources(styles);
+        }
+    }
+    
+    class SourceEntryRenderer extends DefaultTableCellRenderer {
+        @Override
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            SourceEntry se = (SourceEntry) value;
+            JLabel label = (JLabel)super.getTableCellRendererComponent(table,
+                    fromSourceEntry(se), isSelected, hasFocus, row, column);
+            return label;
+        }
+
+        private String fromSourceEntry(SourceEntry entry) {
+            StringBuilder s = new StringBuilder("<html><b>");
+            if (entry.shortdescription != null) {
+                s.append(entry.shortdescription).append("</b> (");
+            }
+            s.append(entry.url);
+            if (entry.name != null) {
+                s.append(")");
+            }
+            s.append("</html>");
+            return s.toString();
         }
     }
@@ -995,3 +1273,125 @@
     }
 
+
+    /**
+     * Convert mappaint and preset source preferences from a simple list to
+     * array with one line for each source entry.
+     *
+     * MapPaint:
+     *
+     *    Old format
+     *      key: mappaint.style.sources
+     *      value: list of "<name>=<url>" pairs. The "<name>=" part is optional.
+     *          The style is always active.
+     *      default: empty list
+     *
+     *      key: mappaint.style.enable-defaults
+     *      value: if true, the default style "resource://data/elemstyles.xml" should
+     *          be loaded.
+     *      default: true
+     *
+     *    New format
+     *      key: mappaint.style.sources-list
+     *      value: each line is a list with entries: url, name, shortdescription, active
+     *      default:
+     *          One line: "resource://data/elemstyles.xml", "standard", tr("Internal Style"), true
+     *
+     * Tagging Preset:
+     *
+     *      the same, but "name" and "active" are not needed and omitted
+     *
+     */
+    abstract public static class SourcePrefMigration {
+
+        private final String oldPref;
+        private final String oldPrefEnableDefaults;
+        private final String pref;
+
+        public SourcePrefMigration(String oldPref, String oldPrefEnableDefaults, String pref) {
+            this.oldPref = oldPref;
+            this.oldPrefEnableDefaults = oldPrefEnableDefaults;
+            this.pref = pref;
+        }
+
+        abstract public Collection<StyleSourceInfo> getDefault();
+
+        abstract public Collection<String> serialize(SourceEntry entry);
+
+        abstract public SourceEntry deserialize(List<String> entryStr);
+
+        public List<SourceEntry> get() {
+            List<SourceEntry> entries = readNewFormatImpl();
+            if (entries == null) {
+
+                entries = readOldFormat();
+                put(entries);
+                return entries;
+            }
+            return entries;
+        }
+
+        public boolean put(Collection<? extends SourceEntry> entries) {
+            boolean changed = false;
+            if (entries.isEmpty()) {
+                changed |= Main.pref.put(pref + "._empty_", true);
+                changed |= Main.pref.putArray(pref, null);
+            } else {
+                Collection<Collection<String>> setting = new ArrayList<Collection<String>>();
+                for (SourceEntry e : entries) {
+                    setting.add(serialize(e));
+                }
+                changed |= Main.pref.put(pref + "._empty_", null);
+                changed |= Main.pref.putArray(pref, setting);
+            }
+            return changed;
+        }
+
+        public List<SourceEntry> readOldFormat() {
+            List<SourceEntry> result = new ArrayList<SourceEntry>();
+            if (Main.pref.getBoolean(oldPrefEnableDefaults, true)) {
+                result.addAll(getDefault());
+            }
+
+            List<String> lines = new LinkedList<String>(Main.pref.getCollection(oldPref));
+            for (String line : lines) {
+                String[] a = null;
+                if (line.indexOf("=") >= 0) {
+                    a = line.split("=", 2);
+                } else {
+                    a = new String[] { null, line };
+                }
+                result.add(new SourceEntry(a[1], a[0], null, true));
+            }
+
+            return result;
+        }
+
+        public Collection<? extends SourceEntry> readNewFormat() {
+            List<SourceEntry> entries = readNewFormatImpl();
+            if (entries == null) {
+                return getDefault();
+            }
+            return entries;
+        }
+
+        private List<SourceEntry> readNewFormatImpl() {
+            List<SourceEntry> entries = new ArrayList<SourceEntry>();
+            Collection<Collection<String>> mappaintSrc = Main.pref.getArray(pref, null);
+            if (mappaintSrc == null || mappaintSrc.isEmpty()) {
+                if (Main.pref.getBoolean(pref + "._empty_", false)) {
+                    return Collections.<SourceEntry>emptyList();
+                }
+                return null;
+            }
+
+            for (Collection<String> sourcePref : mappaintSrc) {
+                SourceEntry e = deserialize(new ArrayList<String>(sourcePref));
+                if (e != null) {
+                    entries.add(e);
+                }
+            }
+            return entries;
+        }
+    }
+
 }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 3795)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 3796)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.preferences;
 
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -7,5 +8,7 @@
 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;
@@ -25,4 +28,5 @@
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
+import org.openstreetmap.josm.gui.preferences.StyleSourceEditor.StyleSourceInfo;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
 import org.openstreetmap.josm.gui.tagging.TaggingPresetMenu;
@@ -44,16 +48,16 @@
     private StyleSourceEditor sources;
     private JCheckBox sortMenu;
-    private JCheckBox enableDefault;
-
 
     private ValidationListener validationListener = new ValidationListener() {
         public boolean validatePreferences() {
             if (sources.hasActiveStylesChanged()) {
-                List<String> sourcesToRemove = new ArrayList<String>();
+                List<Integer> sourcesToRemove = new ArrayList<Integer>();
+                int i = -1;
                 SOURCES:
-                    for (String source: sources.getActiveStyles()) {
+                    for (SourceEntry source: sources.getActiveStyles()) {
+                        i++;
                         boolean canLoad = false;
                         try {
-                            TaggingPreset.readAll(source, false);
+                            TaggingPreset.readAll(source.url, false);
                             canLoad = true;
                         } catch (IOException e) {
@@ -66,5 +70,5 @@
                                 continue SOURCES;
                             case 2:
-                                sourcesToRemove.add(source);
+                                sourcesToRemove.add(i);
                                 continue SOURCES;
                             default:
@@ -78,5 +82,5 @@
 
                         try {
-                            TaggingPreset.readAll(source, true);
+                            TaggingPreset.readAll(source.url, true);
                         } catch (IOException e) {
                             // Should not happen, but at least show message
@@ -117,5 +121,5 @@
                                 continue SOURCES;
                             case JOptionPane.NO_OPTION:
-                                sourcesToRemove.add(source);
+                                sourcesToRemove.add(i);
                                 continue SOURCES;
                             default:
@@ -124,7 +128,5 @@
                         }
                     }
-                for (String toRemove:sourcesToRemove) {
-                    sources.removeSource(toRemove);
-                }
+                sources.removeSources(sourcesToRemove);
                 return true;
             }  else
@@ -136,13 +138,9 @@
         sortMenu = new JCheckBox(tr("Sort presets menu"),
                 Main.pref.getBoolean("taggingpreset.sortmenu", false));
-        enableDefault = new JCheckBox(tr("Enable built-in defaults"),
-                Main.pref.getBoolean("taggingpreset.enable-defaults", true));
 
         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));
-        panel.add(enableDefault, GBC.eol().insets(5,0,5,0));
-        sources = new StyleSourceEditor("taggingpreset.sources", "taggingpreset.icon.sources",
-        "http://josm.openstreetmap.de/presets");
+        sources = new TaggingPresetSourceEditor();
         panel.add(sources, GBC.eol().fill(GBC.BOTH));
         gui.mapcontent.addTab(tr("Tagging Presets"), panel);
@@ -163,13 +161,84 @@
     }
 
+    class TaggingPresetSourceEditor extends StyleSourceEditor {
+
+        final private String iconpref = "taggingpreset.icon.sources";
+
+        public TaggingPresetSourceEditor() {
+            super("http://josm.openstreetmap.de/presets");
+        }
+
+        @Override
+        public Collection<? extends SourceEntry> getInitialSourcesList() {
+            return (new PresetPrefMigration()).get();
+        }
+
+        @Override
+        public boolean finish() {
+            List<SourceEntry> activeStyles = activeStylesModel.getStyles();
+
+            boolean changed = (new PresetPrefMigration()).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<StyleSourceInfo> getDefault() {
+            return (new PresetPrefMigration()).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:
+                    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.enable-defaults",
-                enableDefault.getSelectedObjects() != null);
-        if(Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null)) {
-            restart = true;
-        }
-        if(sources.finish()) {
-            restart = true;
-        }
+        boolean restart = Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null);
+        restart |= sources.finish();
+
         return restart;
     }
@@ -217,3 +286,34 @@
         }
     }
+
+    public static class PresetPrefMigration extends StyleSourceEditor.SourcePrefMigration {
+
+        public PresetPrefMigration() {
+            super("taggingpreset.sources",
+                  "taggingpreset.enable-defaults",
+                  "taggingpreset.sources-list");
+        }
+
+        @Override
+        public Collection<StyleSourceInfo> getDefault() {
+            StyleSourceInfo i = new StyleSourceInfo("defaultpresets.xml", "resource://data/defaultpresets.xml");
+            i.shortdescription = 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.shortdescription});
+        }
+
+        @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/tagging/TaggingPreset.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 3795)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 3796)
@@ -64,4 +64,6 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.preferences.SourceEntry;
+import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference.PresetPrefMigration;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
@@ -1228,8 +1230,8 @@
         LinkedList<String> sources = new LinkedList<String>();
 
-        if(Main.pref.getBoolean("taggingpreset.enable-defaults", true)) {
-            sources.add("resource://data/defaultpresets.xml");
-        }
-        sources.addAll(Main.pref.getCollection("taggingpreset.sources", new LinkedList<String>()));
+        for (SourceEntry e : (new PresetPrefMigration()).get()) {
+            sources.add(e.url);
+        }
+
         return sources;
     }
Index: /trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 3795)
+++ /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 3796)
@@ -29,4 +29,13 @@
 
     /**
+     * for convenience: test whether 2 objects are either both null or a.equals(b)
+     */
+    public static <T> boolean equal(T a, T b) {
+        if (a == null && b == null)
+            return true;
+        return (a != null && a.equals(b));
+    }
+
+    /**
      * return the modulus in the range [0, n)
      */
