Index: /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 2399)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 2400)
@@ -13,5 +13,6 @@
 import javax.swing.JLabel;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 
 import org.openstreetmap.josm.Main;
@@ -20,5 +21,5 @@
 
 public class MapPaintPreference implements PreferenceSetting {
-    private StyleSources sources;
+    private StyleSourceEditor sources;
     private JCheckBox enableIconDefault;
     private JCheckBox enableDefault;
@@ -37,12 +38,13 @@
                 Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
 
-        sources = new StyleSources("mappaint.style.sources", "mappaint.icon.sources",
-        "http://josm.openstreetmap.de/styles", false, tr("Map Paint Styles"));
+        sources = new StyleSourceEditor("mappaint.style.sources", "mappaint.icon.sources",
+        "http://josm.openstreetmap.de/styles");
 
         Collection<String> styles = new TreeSet<String>(MapPaintStyles.getStyles().getStyleNames());
         String defstyle = Main.pref.get("mappaint.style", "standard");
         styles.add(defstyle);
-        for(String style : styles)
+        for(String style : styles) {
             styleCombo.addItem(style);
+        }
 
         styleCombo.setEditable(true);
@@ -54,6 +56,5 @@
         }
 
-        JPanel panel = new JPanel(new GridBagLayout());
-        JScrollPane scrollpane = new JScrollPane(panel);
+        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));
@@ -65,13 +66,28 @@
 
         panel.add(sources, GBC.eol().fill(GBC.BOTH));
-        gui.mapcontent.addTab(tr("Map Paint Styles"), scrollpane);
+        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.initiallyLoadAvailableStyles();
+                        }
+                    }
+                }
+        );
     }
 
     public boolean ok() {
         Boolean restart = Main.pref.put("mappaint.style.enable-defaults", enableDefault.getSelectedObjects() != null);
-        if(Main.pref.put("mappaint.icon.enable-defaults", enableIconDefault.getSelectedObjects() != null))
-          restart = true;
-        if(sources.finish())
-          restart = true;
+        if(Main.pref.put("mappaint.icon.enable-defaults", enableIconDefault.getSelectedObjects() != null)) {
+            restart = true;
+        }
+        if(sources.finish()) {
+            restart = true;
+        }
         Main.pref.put("mappaint.style", styleCombo.getEditor().getItem().toString());
         return restart;
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java	(revision 2400)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java	(revision 2400)
@@ -0,0 +1,971 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EventObject;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableCellEditor;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.io.MirroredInputStream;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.LanguageInfo;
+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;
+
+
+    /**
+     * 
+     * @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)
+     * @param availableStylesUrl the URL to the list of available style sources
+     */
+    public StyleSourceEditor(String stylesPreferencesKey, String iconsPreferenceKey, final String availableStylesUrl) {
+
+        DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
+        tblActiveStyles = new JTable(activeStylesModel = new ActiveStylesModel(selectionModel));
+        tblActiveStyles.setSelectionModel(selectionModel);
+        tblActiveStyles.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        tblActiveStyles.setTableHeader(null);
+        tblActiveStyles.getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor());
+        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());
+        //availableStylesModel.setStyleSources(reloadAvailableStyles(availableStylesUrl));
+        this.availableStylesUrl = availableStylesUrl;
+
+        this.pref = stylesPreferencesKey;
+        this.iconpref = iconsPreferenceKey;
+
+        JButton iconadd = null;
+        JButton iconedit = null;
+        JButton icondelete = null;
+
+        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());
+            tblIconPaths.setRowHeight(20);
+            iconPathsModel.setIconPaths(Main.pref.getCollection(iconsPreferenceKey, null));
+
+            iconadd = new JButton(new NewIconPathAction());
+
+            EditIconPathAction editIconPathAction = new EditIconPathAction();
+            tblIconPaths.getSelectionModel().addListSelectionListener(editIconPathAction);
+            iconedit = new JButton(editIconPathAction);
+
+            RemoveIconPathAction removeIconPathAction = new RemoveIconPathAction();
+            tblIconPaths.getSelectionModel().addListSelectionListener(removeIconPathAction);
+            icondelete = new JButton(removeIconPathAction);
+            tblIconPaths.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "delete");
+            tblIconPaths.getActionMap().put("delete", removeIconPathAction);
+        }
+
+        JButton add = new JButton(new NewActiveStyleAction());
+
+        EditActiveStyleAction editActiveStyleAction = new EditActiveStyleAction();
+        tblActiveStyles.getSelectionModel().addListSelectionListener(editActiveStyleAction);
+        JButton edit = new JButton(editActiveStyleAction);
+
+        RemoveActiveStylesAction removeActiveStylesAction = new RemoveActiveStylesAction();
+        tblActiveStyles.getSelectionModel().addListSelectionListener(removeActiveStylesAction);
+        tblActiveStyles.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "delete");
+        tblActiveStyles.getActionMap().put("delete", removeActiveStylesAction);
+        JButton delete = new JButton(removeActiveStylesAction);
+
+
+        ActivateStylesAction activateStylesAction = new ActivateStylesAction();
+        lstAvailableStyles.addListSelectionListener(activateStylesAction);
+        JButton copy = new JButton(activateStylesAction);
+
+        JButton update = new JButton(new ReloadStylesAction(availableStylesUrl));
+
+        setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+        setLayout(new GridBagLayout());
+        add(new JLabel(tr("Active styles")), GBC.eol().insets(5, 5, 5, 0));
+        JScrollPane sp;
+        add(sp = new JScrollPane(tblActiveStyles), GBC.eol().insets(5, 0, 5, 0).fill(GBC.BOTH));
+        sp.setColumnHeaderView(null);
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+        add(buttonPanel, GBC.eol().insets(5, 0, 5, 5).fill(GBC.HORIZONTAL));
+        buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
+        buttonPanel.add(edit, GBC.std().insets(5, 5, 5, 0));
+        buttonPanel.add(delete, GBC.std().insets(0, 5, 5, 0));
+        buttonPanel.add(copy, GBC.std().insets(0, 5, 5, 0));
+        add(new JLabel(tr("Available styles (from {0})", availableStylesUrl)), GBC.eol().insets(5, 5, 5, 0));
+        add(new JScrollPane(lstAvailableStyles), GBC.eol().insets(5, 0, 5, 0).fill(GBC.BOTH));
+        buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+        add(buttonPanel, GBC.eol().insets(5, 0, 5, 5).fill(GBC.HORIZONTAL));
+        buttonPanel.add(update, GBC.std().insets(0, 5, 0, 0));
+        if (tblIconPaths != null) {
+            add(new JLabel(tr("Icon paths")), GBC.eol().insets(5, -5, 5, 0));
+            add(sp = new JScrollPane(tblIconPaths), GBC.eol().insets(5, 0, 5, 0).fill(GBC.BOTH));
+            sp.setColumnHeaderView(null);
+            buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+            add(buttonPanel, GBC.eol().insets(5, 0, 5, 5).fill(GBC.HORIZONTAL));
+            buttonPanel.add(iconadd);
+            buttonPanel.add(iconedit);
+            buttonPanel.add(icondelete);
+        }
+    }
+
+    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;
+    }
+
+    protected void reloadAvailableStyles(String url) {
+        Main.worker.submit(new StyleSourceLoader(url));
+    }
+
+    public void initiallyLoadAvailableStyles() {
+        if (!stylesInitiallyLoaded) {
+            reloadAvailableStyles(this.availableStylesUrl);
+        }
+        stylesInitiallyLoaded = true;
+    }
+
+    class AvailableStylesListModel extends DefaultListModel {
+        private ArrayList<StyleSourceInfo> data;
+        private DefaultListSelectionModel selectionModel;
+
+        public AvailableStylesListModel(DefaultListSelectionModel selectionModel) {
+            data = new ArrayList<StyleSourceInfo>();
+            this.selectionModel = selectionModel;
+        }
+
+        public void setStyleSources(List<StyleSourceInfo> styleSources) {
+            data.clear();
+            if (styleSources != null) {
+                data.addAll(styleSources);
+            }
+            fireContentsChanged(this, 0, data.size());
+        }
+
+        @Override
+        public Object getElementAt(int index) {
+            return data.get(index);
+        }
+
+        @Override
+        public int getSize() {
+            if (data == null) return 0;
+            return data.size();
+        }
+
+        public void deleteSelected() {
+            Iterator<StyleSourceInfo> it = data.iterator();
+            int i=0;
+            while(it.hasNext()) {
+                it.next();
+                if (selectionModel.isSelectedIndex(i)) {
+                    it.remove();
+                }
+                i++;
+            }
+            fireContentsChanged(this, 0, data.size());
+        }
+
+        public List<StyleSourceInfo> getSelected() {
+            ArrayList<StyleSourceInfo> ret = new ArrayList<StyleSourceInfo>();
+            for(int i=0; i<data.size();i++) {
+                if (selectionModel.isSelectedIndex(i)) {
+                    ret.add(data.get(i));
+                }
+            }
+            return ret;
+        }
+    }
+
+
+    class ActiveStylesModel extends AbstractTableModel {
+        private ArrayList<String> data;
+        private DefaultListSelectionModel selectionModel;
+
+        public ActiveStylesModel(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) {
+            updateStyle(rowIndex, (String)aValue);
+        }
+
+        public void setActiveStyles(Collection<String> styles) {
+            data.clear();
+            if (styles !=null) {
+                data.addAll(styles);
+            }
+            sort();
+            fireTableDataChanged();
+        }
+
+        public void addStyle(String style) {
+            if (style == null) return;
+            data.add(style);
+            sort();
+            fireTableDataChanged();
+            int idx = data.indexOf(style);
+            if (idx >= 0) {
+                selectionModel.setSelectionInterval(idx, idx);
+            }
+        }
+
+        public void updateStyle(int pos, String style) {
+            if (style == null) return;
+            if (pos < 0 || pos >= getRowCount()) return;
+            data.set(pos, style);
+            sort();
+            fireTableDataChanged();
+            int idx = data.indexOf(style);
+            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();
+        }
+
+        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 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 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("download"));
+            this.url = url;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            MirroredInputStream.cleanup(url);
+            reloadAvailableStyles(url);
+        }
+    }
+
+    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);
+        }
+    }
+
+    class NewIconPathAction extends AbstractAction {
+        public NewIconPathAction() {
+            putValue(NAME, tr("New"));
+            putValue(SHORT_DESCRIPTION, tr("Add a new icon path"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            iconPathsModel.addPath("");
+            tblIconPaths.editCellAt(iconPathsModel.getRowCount() -1,0);
+        }
+    }
+
+    class RemoveIconPathAction extends AbstractAction implements ListSelectionListener {
+        public RemoveIconPathAction() {
+            putValue(NAME, tr("Remove"));
+            putValue(SHORT_DESCRIPTION, tr("Remove the selected icon paths"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
+            updateEnabledState();
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(tblIconPaths.getSelectedRowCount() > 0);
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            iconPathsModel.removeSelected();
+        }
+    }
+
+    class EditIconPathAction extends AbstractAction implements ListSelectionListener {
+        public EditIconPathAction() {
+            putValue(NAME, tr("Edit"));
+            putValue(SHORT_DESCRIPTION, tr("Edit the selected icon path"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
+            updateEnabledState();
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(tblIconPaths.getSelectedRowCount() == 1);
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            int row = tblIconPaths.getSelectedRow();
+            tblIconPaths.editCellAt(row, 0);
+        }
+    }
+
+    class StyleSourceCellRenderer extends JLabel implements ListCellRenderer {
+        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+                boolean cellHasFocus) {
+            String s = value.toString();
+            setText(s);
+            if (isSelected) {
+                setBackground(list.getSelectionBackground());
+                setForeground(list.getSelectionForeground());
+            } else {
+                setBackground(list.getBackground());
+                setForeground(list.getForeground());
+            }
+            setEnabled(list.isEnabled());
+            setFont(list.getFont());
+            setOpaque(true);
+            setToolTipText(((StyleSourceInfo) value).getTooltip());
+            return this;
+        }
+    }
+
+    class StyleSourceLoader extends PleaseWaitRunnable {
+        private String url;
+        private BufferedReader reader;
+        private boolean canceled;
+
+        public StyleSourceLoader(String url) {
+            super(tr("Loading style sources from ''{0}''", url));
+            this.url = url;
+        }
+
+        @Override
+        protected void cancel() {
+            canceled = true;
+            if (reader!= null) {
+                try {
+                    reader.close();
+                } catch(IOException e) {
+                    // ignore
+                }
+            }
+        }
+
+        @Override
+        protected void finish() {}
+
+        protected void warn(Exception e) {
+            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
+            );
+
+            HelpAwareOptionPane.showOptionDialog(
+                    Main.parent,
+                    msg,
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE,
+                    ht("Preferences/Styles#FailedToLoadStyleSources")
+            );
+        }
+
+        @Override
+        protected void realRun() throws SAXException, IOException, OsmTransferException {
+            LinkedList<StyleSourceInfo> styles = new LinkedList<StyleSourceInfo>();
+            String lang = LanguageInfo.getLanguageCodeXML();
+            try {
+                MirroredInputStream stream = new MirroredInputStream(url);
+                InputStreamReader r;
+                try {
+                    r = new InputStreamReader(stream, "UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    r = new InputStreamReader(stream);
+                }
+                BufferedReader reader = new BufferedReader(r);
+
+                String line;
+                StyleSourceInfo last = null;
+
+                while ((line = reader.readLine()) != null && !canceled) {
+                    if (line.trim().equals("")) {
+                        continue; // skip empty lines
+                    }
+                    if (line.startsWith("\t")) {
+                        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));
+                            continue;
+                        }
+                        if (last != null) {
+                            String key = m.group(1);
+                            String value = m.group(2);
+                            if ("author".equals(key) && last.author == null) {
+                                last.author = value;
+                            } else if ("version".equals(key)) {
+                                last.version = value;
+                            } else if ("link".equals(key) && last.link == null) {
+                                last.link = value;
+                            } else if ("description".equals(key) && last.description == null) {
+                                last.description = value;
+                            } else if ("shortdescription".equals(key) && last.shortdescription == null) {
+                                last.shortdescription = value;
+                            } else if ((lang + "author").equals(key)) {
+                                last.author = value;
+                            } else if ((lang + "link").equals(key)) {
+                                last.link = value;
+                            } else if ((lang + "description").equals(key)) {
+                                last.description = value;
+                            } else if ((lang + "shortdescription").equals(key)) {
+                                last.shortdescription = value;
+                            }
+                        }
+                    } else {
+                        last = null;
+                        Matcher m = Pattern.compile("^(.+);(.+)$").matcher(line);
+                        if (m.matches()) {
+                            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));
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                if (canceled)
+                    // ignore the exception and return
+                    return;
+                warn(e);
+                return;
+            }
+            availableStylesModel.setStyleSources(styles);
+        }
+    }
+
+    class FileOrUrlCellEditor extends JPanel implements TableCellEditor {
+        private JTextField tfFileName;
+        private CopyOnWriteArrayList<CellEditorListener> listeners;
+        private String value;
+        private JFileChooser fileChooser;
+
+        protected JFileChooser getFileChooser() {
+            if (fileChooser == null) {
+                this.fileChooser = new JFileChooser();
+            }
+            return fileChooser;
+        }
+
+        /**
+         * build the GUI
+         */
+        protected void build() {
+            setLayout(new GridBagLayout());
+            GridBagConstraints gc = new GridBagConstraints();
+            gc.gridx = 0;
+            gc.gridy = 0;
+            gc.fill = GridBagConstraints.BOTH;
+            gc.weightx = 1.0;
+            gc.weighty = 1.0;
+            add(tfFileName = new JTextField(), gc);
+
+
+            gc.gridx = 1;
+            gc.gridy = 0;
+            gc.fill = GridBagConstraints.BOTH;
+            gc.weightx = 0.0;
+            gc.weighty = 1.0;
+            add(new JButton(new LaunchFileChooserAction()));
+
+            tfFileName.addFocusListener(
+                    new FocusAdapter() {
+                        @Override
+                        public void focusGained(FocusEvent e) {
+                            tfFileName.selectAll();
+                        }
+                    }
+            );
+        }
+
+        public FileOrUrlCellEditor() {
+            listeners = new CopyOnWriteArrayList<CellEditorListener>();
+            build();
+        }
+
+
+        public void addCellEditorListener(CellEditorListener l) {
+            if (!listeners.contains(l)) {
+                listeners.add(l);
+            }
+        }
+
+        protected void fireEditingCanceled() {
+            for (CellEditorListener l: listeners) {
+                l.editingCanceled(new ChangeEvent(this));
+            }
+        }
+
+        protected void fireEditingStopped() {
+            for (CellEditorListener l: listeners) {
+                l.editingStopped(new ChangeEvent(this));
+            }
+        }
+
+        public void cancelCellEditing() {
+            fireEditingCanceled();
+        }
+
+        public Object getCellEditorValue() {
+            return value;
+        }
+
+        public boolean isCellEditable(EventObject anEvent) {
+            if (anEvent instanceof MouseEvent)
+                return ((MouseEvent)anEvent).getClickCount() >= 2;
+                return true;
+        }
+
+        public void removeCellEditorListener(CellEditorListener l) {
+            if (listeners.contains(l)) {
+                listeners.remove(l);
+            }
+        }
+
+        public boolean shouldSelectCell(EventObject anEvent) {
+            return true;
+        }
+
+        public boolean stopCellEditing() {
+            value = tfFileName.getText();
+            fireEditingStopped();
+            return true;
+        }
+
+        public void setInitialValue(String initialValue) {
+            this.value = initialValue;
+            if (initialValue == null) {
+                this.tfFileName.setText("");
+            } else {
+                this.tfFileName.setText(initialValue);
+            }
+        }
+
+        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+            setInitialValue((String)value);
+            tfFileName.selectAll();
+            return this;
+        }
+
+
+        class LaunchFileChooserAction extends AbstractAction {
+            public LaunchFileChooserAction() {
+                putValue(NAME, "...");
+                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 = getFileChooser();
+                prepareFileChooser(tfFileName.getText(), fc);
+                int ret = fc.showOpenDialog(JOptionPane.getFrameForComponent(StyleSourceEditor.this));
+                if (ret != JFileChooser.APPROVE_OPTION)
+                    return;
+                tfFileName.setText(fc.getSelectedFile().toString());
+            }
+        }
+    }
+}
Index: unk/src/org/openstreetmap/josm/gui/preferences/StyleSources.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/StyleSources.java	(revision 2399)
+++ 	(revision )
@@ -1,415 +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 java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.ListCellRenderer;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.io.MirroredInputStream;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.LanguageInfo;
-
-public class StyleSources extends JPanel {
-    private JList sourcesList;
-    private JList sourcesDefaults;
-    private JList iconsList = null;
-    private String pref;
-    private String iconpref;
-
-    public class SourceInfo {
-        String version;
-        String name;
-        String url;
-        String author;
-        String link;
-        String description;
-        String shortdescription;
-        public SourceInfo(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 MyCellRenderer extends JLabel implements ListCellRenderer {
-        public Component getListCellRendererComponent(JList list, Object value,
-                int index, boolean isSelected, boolean cellHasFocus)
-        {
-            String s = value.toString();
-            setText(s);
-            if (isSelected) {
-                setBackground(list.getSelectionBackground());
-                setForeground(list.getSelectionForeground());
-            }
-            else {
-                setBackground(list.getBackground());
-                setForeground(list.getForeground());
-            }
-            setEnabled(list.isEnabled());
-            setFont(list.getFont());
-            setOpaque(true);
-            setToolTipText(((SourceInfo)value).getTooltip());
-            return this;
-        }
-    }
-
-    public StyleSources(String pref, String iconpref, final String url, boolean named, final String name)
-    {
-        sourcesList = new JList(new DefaultListModel());
-        sourcesDefaults = new JList(new DefaultListModel());
-        sourcesDefaults.setCellRenderer(new MyCellRenderer());
-        getDefaults(url);
-
-        this.pref = pref;
-        this.iconpref = iconpref;
-
-        Collection<String> sources = Main.pref.getCollection(pref, null);
-        if(sources != null) {
-            for(String s : sources) {
-                ((DefaultListModel)sourcesList.getModel()).addElement(s);
-            }
-        }
-
-        JButton iconadd = null;
-        JButton iconedit = null;
-        JButton icondelete = null;
-
-        if(iconpref != null)
-        {
-            iconsList = new JList(new DefaultListModel());
-            sources = Main.pref.getCollection(iconpref, null);
-            if(sources != null) {
-                for(String s : sources) {
-                    ((DefaultListModel)iconsList.getModel()).addElement(s);
-                }
-            }
-
-            iconadd = new JButton(tr("Add"));
-            iconadd.addActionListener(new ActionListener(){
-                public void actionPerformed(ActionEvent e) {
-                    String source = JOptionPane.showInputDialog(
-                            Main.parent,
-                            tr("Icon paths"),
-                            tr("Icon paths"),
-                            JOptionPane.QUESTION_MESSAGE
-                    );
-                    if (source != null) {
-                        ((DefaultListModel)iconsList.getModel()).addElement(source);
-                    }
-                }
-            });
-
-            iconedit = new JButton(tr("Edit"));
-            iconedit.addActionListener(new ActionListener(){
-                public void actionPerformed(ActionEvent e) {
-                    if (sourcesList.getSelectedIndex() == -1) {
-                        JOptionPane.showMessageDialog(
-                                Main.parent,
-                                tr("Please select the row to edit."),
-                                tr("Warning"),
-                                JOptionPane.WARNING_MESSAGE
-                        );
-                    } else {
-                        String source = (String)JOptionPane.showInputDialog(
-                                Main.parent,
-                                tr("Icon paths"),
-                                tr("Icon paths"),
-                                JOptionPane.QUESTION_MESSAGE,
-                                null,
-                                null,
-                                iconsList.getSelectedValue()
-                        );
-                        if (source != null) {
-                            ((DefaultListModel)iconsList.getModel()).setElementAt(source, iconsList.getSelectedIndex());
-                        }
-                    }
-                }
-            });
-
-            icondelete = new JButton(tr("Delete"));
-            icondelete.addActionListener(new ActionListener(){
-                public void actionPerformed(ActionEvent e) {
-                    if (iconsList.getSelectedIndex() == -1) {
-                        JOptionPane.showMessageDialog(
-                                Main.parent, tr("Please select the row to delete."),
-                                tr("Warning"),
-                                JOptionPane.WARNING_MESSAGE);
-                    } else {
-                        ((DefaultListModel)iconsList.getModel()).remove(iconsList.getSelectedIndex());
-                    }
-                }
-            });
-        }
-
-        JButton add = new JButton(tr("Add"));
-        add.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                String source = JOptionPane.showInputDialog(
-                        Main.parent,
-                        name,
-                        name,
-                        JOptionPane.QUESTION_MESSAGE);
-                if (source != null) {
-                    ((DefaultListModel)sourcesList.getModel()).addElement(source);
-                }
-            }
-        });
-
-        JButton edit = new JButton(tr("Edit"));
-        edit.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                if (sourcesList.getSelectedIndex() == -1) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent, tr("Please select the row to edit."),
-                            tr("Warning"), JOptionPane.WARNING_MESSAGE);
-                } else {
-                    String source = (String)JOptionPane.showInputDialog(
-                            Main.parent,
-                            name,
-                            name,
-                            JOptionPane.QUESTION_MESSAGE,
-                            null,
-                            null,
-                            sourcesList.getSelectedValue()
-                    );
-                    if (source != null) {
-                        ((DefaultListModel)sourcesList.getModel()).setElementAt(source, sourcesList.getSelectedIndex());
-                    }
-                }
-            }
-        });
-
-        JButton delete = new JButton(tr("Delete"));
-        delete.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                if (sourcesList.getSelectedIndex() == -1) {
-                    JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete."),
-                            tr("Warning"), JOptionPane.WARNING_MESSAGE);
-                } else {
-                    ((DefaultListModel)sourcesList.getModel()).remove(sourcesList.getSelectedIndex());
-                }
-            }
-        });
-
-        JButton copy = new JButton(tr("Copy defaults"));
-        copy.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                if (sourcesDefaults.getSelectedIndex() == -1) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent, tr("Please select the row to copy."),
-                            tr("Warning"), JOptionPane.WARNING_MESSAGE);
-                } else {
-                    ((DefaultListModel)sourcesList.getModel()).addElement(
-                            ((SourceInfo)sourcesDefaults.getSelectedValue()).url);
-                }
-            }
-        });
-
-        JButton update = new JButton(tr("Update"));
-        update.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                MirroredInputStream.cleanup(url);
-                getDefaults(url);
-                int num = sourcesList.getModel().getSize();
-                if (num > 0)
-                {
-                    ArrayList<String> l = new ArrayList<String>();
-                    for (int i = 0; i < num; ++i) {
-                        MirroredInputStream.cleanup((String)sourcesList.getModel().getElementAt(i));
-                    }
-                }
-            }
-        });
-
-        sourcesList.setToolTipText(tr("The XML source (URL or filename) for {0} definition files.", name));
-        add.setToolTipText(tr("Add a new XML source to the list."));
-        delete.setToolTipText(tr("Delete the selected source from the list."));
-
-        setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-        setLayout(new GridBagLayout());
-        add(new JLabel(name), GBC.eol().insets(5,5,5,0));
-        add(new JScrollPane(sourcesList), GBC.eol().insets(5,0,5,0).fill(GBC.BOTH));
-        add(new JLabel(tr("Defaults (See tooltip for detailed information)")), GBC.eol().insets(5,5,5,0));
-        add(new JScrollPane(sourcesDefaults), GBC.eol().insets(5,0,5,0).fill(GBC.BOTH));
-        JPanel buttonPanel = new JPanel(new GridBagLayout());
-        add(buttonPanel, GBC.eol().insets(5,0,5,5).fill(GBC.HORIZONTAL));
-        buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
-        buttonPanel.add(add, GBC.std().insets(0,5,0,0));
-        buttonPanel.add(edit, GBC.std().insets(5,5,5,0));
-        buttonPanel.add(delete, GBC.std().insets(0,5,5,0));
-        buttonPanel.add(copy, GBC.std().insets(0,5,5,0));
-        buttonPanel.add(update, GBC.std().insets(0,5,0,0));
-        if(iconsList != null)
-        {
-            add(new JLabel(tr("Icon paths")), GBC.eol().insets(5,-5,5,0));
-            add(new JScrollPane(iconsList), GBC.eol().insets(5,0,5,0).fill(GBC.BOTH));
-            buttonPanel = new JPanel(new GridBagLayout());
-            add(buttonPanel, GBC.eol().insets(5,0,5,5).fill(GBC.HORIZONTAL));
-            buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
-            buttonPanel.add(iconadd, GBC.std().insets(0,5,0,0));
-            buttonPanel.add(iconedit, GBC.std().insets(5,5,5,0));
-            buttonPanel.add(icondelete, GBC.std().insets(0,5,0,0));
-        }
-    }
-
-    public boolean finish() {
-        boolean changed = false;
-        int num = sourcesList.getModel().getSize();
-        if (num > 0)
-        {
-            ArrayList<String> l = new ArrayList<String>();
-            for (int i = 0; i < num; ++i) {
-                l.add((String)sourcesList.getModel().getElementAt(i));
-            }
-            if(Main.pref.putCollection(pref, l)) {
-                changed = true;
-            }
-        }
-        else if(Main.pref.putCollection(pref, null)) {
-            changed = true;
-        }
-        if(iconsList != null)
-        {
-            num = iconsList.getModel().getSize();
-            if (num > 0)
-            {
-                ArrayList<String> l = new ArrayList<String>();
-                for (int i = 0; i < num; ++i) {
-                    l.add((String)iconsList.getModel().getElementAt(i));
-                }
-                if(Main.pref.putCollection(iconpref, l)) {
-                    changed = true;
-                }
-            }
-            else if(Main.pref.putCollection(iconpref, null)) {
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    public void getDefaults(String name)
-    {
-        ((DefaultListModel)sourcesDefaults.getModel()).removeAllElements();
-        String lang = LanguageInfo.getLanguageCodeXML();
-        try
-        {
-            MirroredInputStream stream = new MirroredInputStream(name);
-            InputStreamReader r;
-            try
-            {
-                r = new InputStreamReader(stream, "UTF-8");
-            }
-            catch (UnsupportedEncodingException e)
-            {
-                r = new InputStreamReader(stream);
-            }
-            BufferedReader reader = new BufferedReader(r);
-
-            String line;
-            SourceInfo last = null;
-
-            while((line = reader.readLine()) != null)
-            {
-                if(line.startsWith("\t"))
-                {
-                    Matcher m = Pattern.compile("^\t([^:]+): *(.+)$").matcher(line);
-                    m.matches();
-                    try
-                    {
-                        if(last != null)
-                        {
-                            String key = m.group(1);
-                            String value = m.group(2);
-                            if("author".equals(key) && last.author == null) {
-                                last.author = value;
-                            } else if("version".equals(key)) {
-                                last.version = value;
-                            } else if("link".equals(key) && last.link == null) {
-                                last.link = value;
-                            } else if("description".equals(key) && last.description == null) {
-                                last.description = value;
-                            } else if("shortdescription".equals(key) && last.shortdescription == null) {
-                                last.shortdescription = value;
-                            } else if((lang+"author").equals(key)) {
-                                last.author = value;
-                            } else if((lang+"link").equals(key)) {
-                                last.link = value;
-                            } else if((lang+"description").equals(key)) {
-                                last.description = value;
-                            } else if((lang+"shortdescription").equals(key)) {
-                                last.shortdescription = value;
-                            }
-                        }
-                    }
-                    catch (IllegalStateException e)
-                    { e.printStackTrace(); }
-                }
-                else
-                {
-                    last = null;
-                    Matcher m = Pattern.compile("^(.+);(.+)$").matcher(line);
-                    m.matches();
-                    try
-                    {
-                        last = new SourceInfo(m.group(1),m.group(2));
-                        ((DefaultListModel)sourcesDefaults.getModel()).addElement(last);
-                    }
-                    catch (IllegalStateException e)
-                    { e.printStackTrace(); }
-                }
-            }
-        }
-        catch(Exception e)
-        { e.printStackTrace(); }
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 2399)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 2400)
@@ -13,6 +13,7 @@
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
 import javax.swing.JSeparator;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 
 import org.openstreetmap.josm.Main;
@@ -31,5 +32,5 @@
 
     public static Collection<TaggingPreset> taggingPresets;
-    private StyleSources sources;
+    private StyleSourceEditor sources;
     private JCheckBox sortMenu;
     private JCheckBox enableDefault;
@@ -41,22 +42,36 @@
                 Main.pref.getBoolean("taggingpreset.enable-defaults", true));
 
-        JPanel panel = new JPanel(new GridBagLayout());
-        JScrollPane scrollpane = new JScrollPane(panel);
+        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 StyleSources("taggingpreset.sources", "taggingpreset.icon.sources",
-        "http://josm.openstreetmap.de/presets", false, tr("Tagging Presets"));
+        sources = new StyleSourceEditor("taggingpreset.sources", "taggingpreset.icon.sources",
+        "http://josm.openstreetmap.de/presets");
         panel.add(sources, GBC.eol().fill(GBC.BOTH));
-        gui.mapcontent.addTab(tr("Tagging Presets"), scrollpane);
+        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.initiallyLoadAvailableStyles();
+                        }
+                    }
+                }
+        );
     }
 
     public boolean ok() {
         boolean restart = Main.pref.put("taggingpreset.enable-defaults",
-        enableDefault.getSelectedObjects() != null);
-        if(Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null))
+                enableDefault.getSelectedObjects() != null);
+        if(Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null)) {
             restart = true;
-        if(sources.finish())
+        }
+        if(sources.finish()) {
             restart = true;
+        }
         return restart;
     }
@@ -76,7 +91,7 @@
             {
                 JMenu m = p.group != null ? submenus.get(p.group) : Main.main.menu.presetsMenu;
-                if (p instanceof TaggingPresetSeparator)
+                if (p instanceof TaggingPresetSeparator) {
                     m.add(new JSeparator());
-                else if (p instanceof TaggingPresetMenu)
+                } else if (p instanceof TaggingPresetMenu)
                 {
                     JMenu submenu = new JMenu(p);
@@ -94,6 +109,7 @@
             }
         }
-        if(Main.pref.getBoolean("taggingpreset.sortmenu"))
+        if(Main.pref.getBoolean("taggingpreset.sortmenu")) {
             TaggingPresetMenu.sortMenu(Main.main.menu.presetsMenu);
+        }
     }
 }
