Index: src/org/openstreetmap/josm/data/CustomConfigurator.java
===================================================================
--- src/org/openstreetmap/josm/data/CustomConfigurator.java	(revision 0)
+++ src/org/openstreetmap/josm/data/CustomConfigurator.java	(working copy)
@@ -0,0 +1,456 @@
+package org.openstreetmap.josm.data;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.openstreetmap.josm.data.Preferences.Setting;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.BufferedInputStream;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.swing.JOptionPane;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import org.openstreetmap.josm.Main;
+
+
+/**
+ * Class to process configuration changes stored in XML
+ * can be used to modify preferences, store/delete files in .josm folders etc
+ */
+public class CustomConfigurator {
+
+    public CustomConfigurator() {
+    }
+
+    public void readXML(String dir, String fileName) {
+        readXML(new File(dir, fileName));
+    }
+
+    public void readXML(File file) {
+        System.out.println("-- Reading custom preferences from " + file.getAbsolutePath() + " --");
+
+        InputStream is = null;
+        try {
+            is = new BufferedInputStream(new FileInputStream(file));
+            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+            builderFactory.setValidating(false);
+            builderFactory.setNamespaceAware(true);
+            DocumentBuilder builder = builderFactory.newDocumentBuilder();
+            Document document = builder.parse(is);
+            processXML(document);
+            Main.pref.save();
+        } catch (SAXException ex) {
+            System.out.println("Can not parse XML parser:");   ex.printStackTrace();
+        } catch (ParserConfigurationException ex) {
+            System.out.println("Can not configure XML parser:");   ex.printStackTrace();
+        } catch (FileNotFoundException ex) {
+            System.out.println("File not found:");   ex.printStackTrace();
+        } catch (IOException ex) {
+            System.out.println("Error reading file:");    ex.printStackTrace();
+        } finally {
+            try {
+                if (is != null) is.close();
+            } catch (IOException ex) { }
+        }
+        System.out.println("-- Reading complete --");
+
+    }
+
+    private void processXML(Document document) {
+        Element root = document.getDocumentElement();
+        NodeList childNodes = root.getChildNodes();
+        int nops = childNodes.getLength();
+        for (int i = 0; i < nops; i++) {
+            Node item = childNodes.item(i);
+            if (item.getNodeType() == Node.ELEMENT_NODE) {
+                String elementName = item.getNodeName();
+                if ("preferences".equals(elementName)) {
+                    processPreferencesOperation((Element) item);
+                } else if ("download".equals(elementName)) {
+                    processDownloadOperation((Element) item);
+                } else if ("delete".equals(elementName)) {
+                    processFileDelete((Element) item);
+                } else {
+                    System.out.println("Unknown element " + elementName);
+                }
+                
+            }
+        }
+    }
+
+    private void processPreferencesOperation(Element item) {
+        String oper = item.getAttribute("operation");
+        System.out.println("PREFERENCES[" + oper + "]");
+        Preferences tmpPref;
+        if ("replace".equals(oper)) {
+            tmpPref = readPreferencesFromDOMElement(item);
+            showPrefs(tmpPref);
+
+            replacePreferences(tmpPref, Main.pref);
+        } else if ("append".equals(oper)) {
+            tmpPref = readPreferencesFromDOMElement(item);
+            showPrefs(tmpPref);
+
+            appendPreferences(tmpPref, Main.pref);
+        } else if ("delete-keys".equals(oper)) {
+            String pattern = item.getAttribute("pattern");
+            String key = item.getAttribute("key");
+            
+            if (key!=null) deletePreferenceKey(key, Main.pref);
+            if (pattern!=null) deletePreferenceKeyByPattern(pattern, Main.pref);
+        } else if ("delete-values".equals(oper)) {
+            tmpPref = readPreferencesFromDOMElement(item);
+            showPrefs(tmpPref);
+
+            deletePreferenceValues(tmpPref, Main.pref);
+        }
+    }
+
+    private Preferences readPreferencesFromDOMElement(Element item) {
+        Preferences tmpPref = new Preferences();
+        try {
+            Transformer xformer = TransformerFactory.newInstance().newTransformer();
+            CharArrayWriter outputWriter = new CharArrayWriter(5000);
+            StreamResult out = new StreamResult(outputWriter);
+
+            xformer.transform(new DOMSource(item), out);
+
+            CharArrayReader reader = new CharArrayReader(outputWriter.toCharArray());
+            tmpPref.fromXML(reader);
+        } catch (XMLStreamException ex) {
+            System.out.println("Error reading XML stream " + ex.getMessage());
+        } catch (TransformerException ex) {
+            System.out.println("Error transforming DOM node to character array" + ex.getMessage());
+        }
+
+        return tmpPref;
+    }
+
+    private void replacePreferences(Preferences fragment, Preferences mainpref) {
+        // normal prefs
+        for (Entry<String, String> entry : fragment.properties.entrySet()) {
+            mainpref.put(entry.getKey(), entry.getValue());
+        }
+        // "list"
+        for (Entry<String, List<String>> entry : fragment.collectionProperties.entrySet()) {
+            mainpref.putCollection(entry.getKey(), entry.getValue());
+        }
+        // "lists"
+        for (Entry<String, List<List<String>>> entry : fragment.arrayProperties.entrySet()) {
+            ArrayList<Collection<String>> array = new ArrayList<Collection<String>>();
+            array.addAll(entry.getValue());
+            mainpref.putArray(entry.getKey(), array);
+        }
+        /// "maps"
+        for (Entry<String, List<Map<String, String>>> entry : fragment.listOfStructsProperties.entrySet()) {
+            mainpref.putListOfStructs(entry.getKey(), entry.getValue());
+        }
+
+    }
+
+    private void appendPreferences(Preferences fragment, Preferences mainpref) {
+        // normal prefs
+        for (Entry<String, String> entry : fragment.properties.entrySet()) {
+            mainpref.put(entry.getKey(), entry.getValue());
+        }
+        
+        // "list"
+        for (Entry<String, List<String>> entry : fragment.collectionProperties.entrySet()) {
+            String key = entry.getKey();
+            
+            Collection<String> existing = mainpref.collectionProperties.get(key);
+            Collection<String> defaults = mainpref.collectionDefaults.get(key);
+
+            if (existing==null && defaults==null) {
+                defaultUnknownWarning(key);
+                continue;
+            } 
+            
+            Collection<String> newItems = (existing!=null) ? 
+                    new ArrayList<String>(existing) : new ArrayList<String>(defaults);
+            
+            for (String item : entry.getValue()) {
+                // add nonexisting elements to then list
+                if (!newItems.contains(item)) {
+                    newItems.add(item);
+                }
+            }
+            mainpref.putCollection(entry.getKey(), newItems);
+        }
+        
+        // "lists"
+        for (Entry<String, List<List<String>>> entry : fragment.arrayProperties.entrySet()) {
+            String key = entry.getKey();
+            
+            Collection<List<String>> existing = mainpref.arrayProperties.get(key);
+            Collection<List<String>> defaults = mainpref.arrayDefaults.get(key);
+            
+            if (existing==null && defaults==null) {
+                defaultUnknownWarning(key);
+                continue;
+            } 
+            
+            ArrayList<Collection<String>> newLists = (existing!=null) ? 
+                    new ArrayList<Collection<String>>(existing) : new ArrayList<Collection<String>>(defaults) ;
+            
+            for (Collection<String> list : entry.getValue()) {
+                // add nonexisting list (equals comparison for lists is used implicitly)
+                if (!newLists.contains(list)) {
+                    newLists.add(list);
+                }
+            }
+            mainpref.putArray(entry.getKey(), newLists);
+        }
+        
+        /// "maps" 
+        for (Entry<String, List<Map<String, String>>> entry : fragment.listOfStructsProperties.entrySet()) {
+            String key = entry.getKey();
+            
+            Collection<Map<String, String>> existing = mainpref.listOfStructsProperties.get(key);
+            Collection<Map<String, String>> defaults = mainpref.listOfStructsDefaults.get(key);
+            
+            if (existing==null && defaults==null) {
+                defaultUnknownWarning(key);
+                continue;
+            } 
+            
+            List<Map<String, String>> newMaps;
+            newMaps = (existing != null) ? 
+                    new ArrayList<Map<String, String>>(existing) : new ArrayList<Map<String, String>>(defaults);
+            // get existing properties as list of maps 
+
+            for (Map<String, String> map : entry.getValue()) {
+                // add nonexisting map (equals comparison for maps is used implicitly)
+                if (!newMaps.contains(map)) {
+                    newMaps.add(map);
+                }
+            }
+            mainpref.putListOfStructs(entry.getKey(), newMaps);
+        }
+    }
+
+
+    private void deletePreferenceKeyByPattern(String pattern, Preferences pref) {
+        Map<String, Setting> allSettings = pref.getAllSettings();
+        for (String key: allSettings.keySet()) {
+            if (key.matches(pattern)) {
+                System.out.println("!!!  deleting key from preferences: "+key);
+                pref.putSetting(key, allSettings.get(key).getNullInstance());
+            }
+        }
+    }
+
+    private void deletePreferenceKey(String key, Preferences pref) {
+        Map<String, Setting> allSettings = pref.getAllSettings();
+        if (allSettings.containsKey(key)) {
+            System.out.println("!!!  deleting key from preferences: "+key);
+            pref.putSetting(key, allSettings.get(key).getNullInstance());
+        }
+    }
+
+    /**
+     * Delete items from @param mainpref collections that match items from @param fragment collections
+     */
+    private void deletePreferenceValues(Preferences fragment, Preferences mainpref) {
+        
+        Map<String, Setting> allSettings = mainpref.getAllSettings();
+        
+        // normal prefs
+        for (Entry<String, String> entry : fragment.properties.entrySet()) {
+            // if mentioned value found, delete it
+            if (entry.getValue().equals( mainpref.properties.get(entry.getKey()) ))
+                    mainpref.put(entry.getKey(), null);
+        }
+        
+        // "list"
+        for (Entry<String, List<String>> entry : fragment.collectionProperties.entrySet()) {
+            String key = entry.getKey();
+            
+            Collection<String> existing = mainpref.collectionProperties.get(key);
+            Collection<String> defaults = mainpref.collectionDefaults.get(key);
+
+            if (existing==null && defaults==null) {
+                defaultUnknownWarning(key);
+                continue;
+            } 
+            
+            Collection<String> newItems = (existing!=null) ? 
+                    new ArrayList<String>(existing) : new ArrayList<String>(defaults);
+            
+            // remove mentioned items from collection
+            for (String item : entry.getValue()) {
+                System.out.printf("!!!  deleting from list %s: %s\n", key, item);
+                newItems.remove(item);
+            }
+            mainpref.putCollection(entry.getKey(), newItems);
+        }
+        
+        // "lists"
+        for (Entry<String, List<List<String>>> entry : fragment.arrayProperties.entrySet()) {
+            String key = entry.getKey();
+            
+            Collection<List<String>> existing = mainpref.arrayProperties.get(key);
+            Collection<List<String>> defaults = mainpref.arrayDefaults.get(key);
+            
+            if (existing==null && defaults==null) {
+                defaultUnknownWarning(key);
+                continue;
+            } 
+            
+            ArrayList<Collection<String>> newLists = (existing!=null) ? 
+                    new ArrayList<Collection<String>>(existing) : new ArrayList<Collection<String>>(defaults) ;
+            
+            // if items are found in one of lists, remove that list!
+            Iterator<Collection<String>> listIterator = newLists.iterator();
+            while (listIterator.hasNext()) {
+                Collection<String> list = listIterator.next();
+                for (Collection<String> removeList : entry.getValue()) {
+                    if (list.containsAll(removeList)) {
+                        // remove current list, because it matches search criteria
+                        System.out.printf("!!!  deleting list from lists %s: %s\n", key, list);
+                        listIterator.remove();
+                    }
+                }
+            }
+            
+            mainpref.putArray(entry.getKey(), newLists);
+        }
+        
+        /// "maps" 
+        for (Entry<String, List<Map<String, String>>> entry : fragment.listOfStructsProperties.entrySet()) {
+            String key = entry.getKey();
+            
+            Collection<Map<String, String>> existing = mainpref.listOfStructsProperties.get(key);
+            Collection<Map<String, String>> defaults = mainpref.listOfStructsDefaults.get(key);
+            
+            if (existing==null && defaults==null) {
+                defaultUnknownWarning(key);
+                continue;
+            } 
+            
+            List<Map<String, String>> newMaps;
+            newMaps = (existing != null) ? 
+                    new ArrayList<Map<String, String>>(existing) : new ArrayList<Map<String, String>>(defaults);
+            Iterator<Map<String, String>> mapIterator = newMaps.iterator();
+            while (mapIterator.hasNext()) {
+                Map<String, String> map = mapIterator.next();
+                for (Map<String, String> removeMap : entry.getValue()) {
+                    if (map.entrySet().containsAll( removeMap.entrySet() )) {
+                        // the map contain all mentioned key-value pair, so it should be deleted from "maps"
+                        System.out.printf("!!!  deleting map from maps %s: %s\n", key, map);
+                        mapIterator.remove();                                                                     
+                    }
+                }
+            }
+            mainpref.putListOfStructs(entry.getKey(), newMaps);
+        }
+    }
+
+    private void defaultUnknownWarning(String key) {
+        JOptionPane.showMessageDialog(
+                Main.parent,
+                tr("<html>Settings file asks to append preferences to <b>{0}</b>,<br/> but it's default value is unknown at this moment.<br/> Please activate corresponding function manually and retry importing.", key),
+                tr("Warning"),
+                JOptionPane.WARNING_MESSAGE);
+    }
+
+    private void showPrefs(Preferences tmpPref) {
+        System.out.println("properties: " + tmpPref.properties);
+        System.out.println("collections: " + tmpPref.collectionProperties);
+        System.out.println("arrays: " + tmpPref.arrayProperties);
+        System.out.println("maps: " + tmpPref.listOfStructsProperties);
+    }
+
+    private void processDownloadOperation(Element item) {
+        String address= item.getAttribute("url");
+        String path= item.getAttribute("path");
+        String dir= Main.pref.getPreferencesDir();
+        if (path.contains("..") || path.startsWith("/") || path.contains(":")) return; // some basic protection
+        File fOut = new File(dir,path);
+        
+        OutputStream out = null;
+        InputStream in = null;
+        HttpURLConnection downloadConnection;
+        try {
+            String mkdir=item.getAttribute("mkdir");
+            if (mkdir!=null) {
+                File newDir = new File(dir,mkdir);
+                newDir.mkdirs();
+            }
+        
+            URL url = new URL(address);
+            System.out.printf("Downloading %s from %s\n", path, url.toString());
+            
+            downloadConnection = (HttpURLConnection)url.openConnection();
+            downloadConnection.setRequestProperty("Cache-Control", "no-cache");
+            downloadConnection.setRequestProperty("User-Agent",Version.getInstance().getAgentString());
+            downloadConnection.setRequestProperty("Host", url.getHost());
+            downloadConnection.connect();
+            in = downloadConnection.getInputStream();
+            out = new FileOutputStream(fOut);
+            byte[] buffer = new byte[8192];
+            for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
+                out.write(buffer, 0, read);
+            }
+        } catch (IOException ex) {
+            System.out.printf("Error downloading file %s from %s\n",path,address);
+        } finally {
+            try {
+                if (out!=null) out.close();
+                if (in!=null) in.close();
+            } catch (IOException ex) {   }
+        }
+        
+    }
+
+    private void processFileDelete(Element item) {
+        String path= item.getAttribute("path");
+        String dir= Main.pref.getPreferencesDir();
+        if (path.contains("..") || path.startsWith("/") ||  path.contains(":")) return; // some basic protection
+        
+        System.out.printf("!!!  deleting file %s in %s\n", path, dir);
+        
+        File fOut = new File(dir,path);
+        if (fOut.exists()) {
+            if ( !fOut.delete() ) {
+                JOptionPane.showMessageDialog(
+                Main.parent,
+                tr("Can not delete file {0} in {1}", path, dir),
+                tr("Warning"),
+                JOptionPane.WARNING_MESSAGE);
+            }
+        }
+    }
+}
Index: src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java	(revision 5026)
+++ src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java	(working copy)
@@ -1,6 +1,7 @@
 // License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm.gui.preferences.advanced;
 
+import javax.swing.JFileChooser;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Component;
@@ -35,6 +36,8 @@
 import javax.swing.table.DefaultTableModel;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.DiskAccessAction;
+import org.openstreetmap.josm.data.CustomConfigurator;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.Preferences.ListListSetting;
 import org.openstreetmap.josm.data.Preferences.ListSetting;
@@ -191,6 +194,20 @@
             }
         });
 
+        JButton read = new JButton(tr("Read from file"));
+        p.add(read, GBC.std().insets(0,5,0,0));
+        read.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser ch = DiskAccessAction.createAndOpenFileChooser(true, false, tr("Open JOSM customization file"), "xml");
+                if (ch!=null) {
+                    CustomConfigurator cc = new CustomConfigurator();
+                    cc.readXML(ch.getSelectedFile());
+                    ((AllSettingsTableModel) list.getModel()).fireTableDataChanged();
+                }
+                
+            }
+        });
+
         list.addMouseListener(new MouseAdapter(){
             @Override public void mouseClicked(MouseEvent e) {
                 if (e.getClickCount() == 2) {
