Ticket #4421: CustomConfigurator.2.patch

File CustomConfigurator.2.patch, 21.0 KB (added by akks, 13 years ago)
  • src/org/openstreetmap/josm/data/CustomConfigurator.java

     
     1package org.openstreetmap.josm.data;
     2
     3import java.util.logging.Level;
     4import java.util.logging.Logger;
     5import org.openstreetmap.josm.data.Preferences.Setting;
     6import static org.openstreetmap.josm.tools.I18n.tr;
     7
     8import java.io.BufferedInputStream;
     9import java.io.CharArrayReader;
     10import java.io.CharArrayWriter;
     11import java.io.File;
     12import java.io.FileInputStream;
     13import java.io.FileNotFoundException;
     14import java.io.FileOutputStream;
     15import java.io.IOException;
     16import java.io.InputStream;
     17import java.io.OutputStream;
     18import java.net.HttpURLConnection;
     19import java.net.URL;
     20import java.util.ArrayList;
     21import java.util.Collection;
     22import java.util.Iterator;
     23import java.util.List;
     24import java.util.Map;
     25import java.util.Map.Entry;
     26import java.util.regex.Matcher;
     27import java.util.regex.Pattern;
     28import javax.swing.JOptionPane;
     29import javax.xml.parsers.DocumentBuilder;
     30import javax.xml.parsers.DocumentBuilderFactory;
     31import javax.xml.parsers.ParserConfigurationException;
     32import javax.xml.stream.XMLStreamException;
     33import javax.xml.transform.Transformer;
     34import javax.xml.transform.TransformerException;
     35import javax.xml.transform.TransformerFactory;
     36import javax.xml.transform.dom.DOMSource;
     37import javax.xml.transform.stream.StreamResult;
     38
     39import org.w3c.dom.Document;
     40import org.w3c.dom.Element;
     41import org.w3c.dom.Node;
     42import org.w3c.dom.NodeList;
     43import org.xml.sax.SAXException;
     44
     45import org.openstreetmap.josm.Main;
     46
     47
     48/**
     49 * Class to process configuration changes stored in XML
     50 * can be used to modify preferences, store/delete files in .josm folders etc
     51 */
     52public class CustomConfigurator {
     53
     54    public CustomConfigurator() {
     55    }
     56
     57    public void readXML(String dir, String fileName) {
     58        readXML(new File(dir, fileName));
     59    }
     60
     61    public void readXML(File file) {
     62        System.out.println("-- Reading custom preferences from " + file.getAbsolutePath() + " --");
     63
     64        InputStream is = null;
     65        try {
     66            is = new BufferedInputStream(new FileInputStream(file));
     67            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
     68            builderFactory.setValidating(false);
     69            builderFactory.setNamespaceAware(true);
     70            DocumentBuilder builder = builderFactory.newDocumentBuilder();
     71            Document document = builder.parse(is);
     72            processXML(document);
     73            Main.pref.save();
     74        } catch (SAXException ex) {
     75            System.out.println("Can not parse XML parser:");   ex.printStackTrace();
     76        } catch (ParserConfigurationException ex) {
     77            System.out.println("Can not configure XML parser:");   ex.printStackTrace();
     78        } catch (FileNotFoundException ex) {
     79            System.out.println("File not found:");   ex.printStackTrace();
     80        } catch (IOException ex) {
     81            System.out.println("Error reading file:");    ex.printStackTrace();
     82        } finally {
     83            try {
     84                if (is != null) is.close();
     85            } catch (IOException ex) { }
     86        }
     87        System.out.println("-- Reading complete --");
     88
     89    }
     90
     91    private void processXML(Document document) {
     92        Element root = document.getDocumentElement();
     93        NodeList childNodes = root.getChildNodes();
     94        int nops = childNodes.getLength();
     95        for (int i = 0; i < nops; i++) {
     96            Node item = childNodes.item(i);
     97            if (item.getNodeType() == Node.ELEMENT_NODE) {
     98                String elementName = item.getNodeName();
     99                if ("preferences".equals(elementName)) {
     100                    processPreferencesOperation((Element) item);
     101                } else if ("download".equals(elementName)) {
     102                    processDownloadOperation((Element) item);
     103                } else if ("delete".equals(elementName)) {
     104                    processFileDelete((Element) item);
     105                } else {
     106                    System.out.println("Unknown element " + elementName);
     107                }
     108               
     109            }
     110        }
     111    }
     112
     113    private void processPreferencesOperation(Element item) {
     114        String oper = item.getAttribute("operation");
     115        System.out.println("PREFERENCES[" + oper + "]");
     116        Preferences tmpPref;
     117        if ("replace".equals(oper)) {
     118            tmpPref = readPreferencesFromDOMElement(item);
     119            showPrefs(tmpPref);
     120
     121            replacePreferences(tmpPref, Main.pref);
     122        } else if ("append".equals(oper)) {
     123            tmpPref = readPreferencesFromDOMElement(item);
     124            showPrefs(tmpPref);
     125
     126            appendPreferences(tmpPref, Main.pref);
     127        } else if ("delete-keys".equals(oper)) {
     128            String pattern = item.getAttribute("pattern");
     129            String key = item.getAttribute("key");
     130           
     131            if (key!=null) deletePreferenceKey(key, Main.pref);
     132            if (pattern!=null) deletePreferenceKeyByPattern(pattern, Main.pref);
     133        } else if ("delete-values".equals(oper)) {
     134            tmpPref = readPreferencesFromDOMElement(item);
     135            showPrefs(tmpPref);
     136
     137            deletePreferenceValues(tmpPref, Main.pref);
     138        }
     139    }
     140
     141    private Preferences readPreferencesFromDOMElement(Element item) {
     142        Preferences tmpPref = new Preferences();
     143        try {
     144            Transformer xformer = TransformerFactory.newInstance().newTransformer();
     145            CharArrayWriter outputWriter = new CharArrayWriter(5000);
     146            StreamResult out = new StreamResult(outputWriter);
     147
     148            xformer.transform(new DOMSource(item), out);
     149
     150            CharArrayReader reader = new CharArrayReader(outputWriter.toCharArray());
     151            tmpPref.fromXML(reader);
     152        } catch (XMLStreamException ex) {
     153            System.out.println("Error reading XML stream " + ex.getMessage());
     154        } catch (TransformerException ex) {
     155            System.out.println("Error transforming DOM node to character array" + ex.getMessage());
     156        }
     157
     158        return tmpPref;
     159    }
     160
     161    private void replacePreferences(Preferences fragment, Preferences mainpref) {
     162        // normal prefs
     163        for (Entry<String, String> entry : fragment.properties.entrySet()) {
     164            mainpref.put(entry.getKey(), entry.getValue());
     165        }
     166        // "list"
     167        for (Entry<String, List<String>> entry : fragment.collectionProperties.entrySet()) {
     168            mainpref.putCollection(entry.getKey(), entry.getValue());
     169        }
     170        // "lists"
     171        for (Entry<String, List<List<String>>> entry : fragment.arrayProperties.entrySet()) {
     172            ArrayList<Collection<String>> array = new ArrayList<Collection<String>>();
     173            array.addAll(entry.getValue());
     174            mainpref.putArray(entry.getKey(), array);
     175        }
     176        /// "maps"
     177        for (Entry<String, List<Map<String, String>>> entry : fragment.listOfStructsProperties.entrySet()) {
     178            mainpref.putListOfStructs(entry.getKey(), entry.getValue());
     179        }
     180
     181    }
     182
     183    private void appendPreferences(Preferences fragment, Preferences mainpref) {
     184        // normal prefs
     185        for (Entry<String, String> entry : fragment.properties.entrySet()) {
     186            mainpref.put(entry.getKey(), entry.getValue());
     187        }
     188       
     189        // "list"
     190        for (Entry<String, List<String>> entry : fragment.collectionProperties.entrySet()) {
     191            String key = entry.getKey();
     192           
     193            Collection<String> existing = mainpref.collectionProperties.get(key);
     194            Collection<String> defaults = mainpref.collectionDefaults.get(key);
     195
     196            if (existing==null && defaults==null) {
     197                defaultUnknownWarning(key);
     198                continue;
     199            }
     200           
     201            Collection<String> newItems = (existing!=null) ?
     202                    new ArrayList<String>(existing) : new ArrayList<String>(defaults);
     203           
     204            for (String item : entry.getValue()) {
     205                // add nonexisting elements to then list
     206                if (!newItems.contains(item)) {
     207                    newItems.add(item);
     208                }
     209            }
     210            mainpref.putCollection(entry.getKey(), newItems);
     211        }
     212       
     213        // "lists"
     214        for (Entry<String, List<List<String>>> entry : fragment.arrayProperties.entrySet()) {
     215            String key = entry.getKey();
     216           
     217            Collection<List<String>> existing = mainpref.arrayProperties.get(key);
     218            Collection<List<String>> defaults = mainpref.arrayDefaults.get(key);
     219           
     220            if (existing==null && defaults==null) {
     221                defaultUnknownWarning(key);
     222                continue;
     223            }
     224           
     225            ArrayList<Collection<String>> newLists = (existing!=null) ?
     226                    new ArrayList<Collection<String>>(existing) : new ArrayList<Collection<String>>(defaults) ;
     227           
     228            for (Collection<String> list : entry.getValue()) {
     229                // add nonexisting list (equals comparison for lists is used implicitly)
     230                if (!newLists.contains(list)) {
     231                    newLists.add(list);
     232                }
     233            }
     234            mainpref.putArray(entry.getKey(), newLists);
     235        }
     236       
     237        /// "maps"
     238        for (Entry<String, List<Map<String, String>>> entry : fragment.listOfStructsProperties.entrySet()) {
     239            String key = entry.getKey();
     240           
     241            Collection<Map<String, String>> existing = mainpref.listOfStructsProperties.get(key);
     242            Collection<Map<String, String>> defaults = mainpref.listOfStructsDefaults.get(key);
     243           
     244            if (existing==null && defaults==null) {
     245                defaultUnknownWarning(key);
     246                continue;
     247            }
     248           
     249            List<Map<String, String>> newMaps;
     250            newMaps = (existing != null) ?
     251                    new ArrayList<Map<String, String>>(existing) : new ArrayList<Map<String, String>>(defaults);
     252            // get existing properties as list of maps
     253
     254            for (Map<String, String> map : entry.getValue()) {
     255                // add nonexisting map (equals comparison for maps is used implicitly)
     256                if (!newMaps.contains(map)) {
     257                    newMaps.add(map);
     258                }
     259            }
     260            mainpref.putListOfStructs(entry.getKey(), newMaps);
     261        }
     262    }
     263
     264
     265    private void deletePreferenceKeyByPattern(String pattern, Preferences pref) {
     266        Map<String, Setting> allSettings = pref.getAllSettings();
     267        for (String key: allSettings.keySet()) {
     268            if (key.matches(pattern)) {
     269                System.out.println("!!!  deleting key from preferences: "+key);
     270                pref.putSetting(key, allSettings.get(key).getNullInstance());
     271            }
     272        }
     273    }
     274
     275    private void deletePreferenceKey(String key, Preferences pref) {
     276        Map<String, Setting> allSettings = pref.getAllSettings();
     277        if (allSettings.containsKey(key)) {
     278            System.out.println("!!!  deleting key from preferences: "+key);
     279            pref.putSetting(key, allSettings.get(key).getNullInstance());
     280        }
     281    }
     282
     283    /**
     284     * Delete items from @param mainpref collections that match items from @param fragment collections
     285     */
     286    private void deletePreferenceValues(Preferences fragment, Preferences mainpref) {
     287       
     288        Map<String, Setting> allSettings = mainpref.getAllSettings();
     289       
     290        // normal prefs
     291        for (Entry<String, String> entry : fragment.properties.entrySet()) {
     292            // if mentioned value found, delete it
     293            if (entry.getValue().equals( mainpref.properties.get(entry.getKey()) ))
     294                    mainpref.put(entry.getKey(), null);
     295        }
     296       
     297        // "list"
     298        for (Entry<String, List<String>> entry : fragment.collectionProperties.entrySet()) {
     299            String key = entry.getKey();
     300           
     301            Collection<String> existing = mainpref.collectionProperties.get(key);
     302            Collection<String> defaults = mainpref.collectionDefaults.get(key);
     303
     304            if (existing==null && defaults==null) {
     305                defaultUnknownWarning(key);
     306                continue;
     307            }
     308           
     309            Collection<String> newItems = (existing!=null) ?
     310                    new ArrayList<String>(existing) : new ArrayList<String>(defaults);
     311           
     312            // remove mentioned items from collection
     313            for (String item : entry.getValue()) {
     314                System.out.printf("!!!  deleting from list %s: %s\n", key, item);
     315                newItems.remove(item);
     316            }
     317            mainpref.putCollection(entry.getKey(), newItems);
     318        }
     319       
     320        // "lists"
     321        for (Entry<String, List<List<String>>> entry : fragment.arrayProperties.entrySet()) {
     322            String key = entry.getKey();
     323           
     324            Collection<List<String>> existing = mainpref.arrayProperties.get(key);
     325            Collection<List<String>> defaults = mainpref.arrayDefaults.get(key);
     326           
     327            if (existing==null && defaults==null) {
     328                defaultUnknownWarning(key);
     329                continue;
     330            }
     331           
     332            ArrayList<Collection<String>> newLists = (existing!=null) ?
     333                    new ArrayList<Collection<String>>(existing) : new ArrayList<Collection<String>>(defaults) ;
     334           
     335            // if items are found in one of lists, remove that list!
     336            Iterator<Collection<String>> listIterator = newLists.iterator();
     337            while (listIterator.hasNext()) {
     338                Collection<String> list = listIterator.next();
     339                for (Collection<String> removeList : entry.getValue()) {
     340                    if (list.containsAll(removeList)) {
     341                        // remove current list, because it matches search criteria
     342                        System.out.printf("!!!  deleting list from lists %s: %s\n", key, list);
     343                        listIterator.remove();
     344                    }
     345                }
     346            }
     347           
     348            mainpref.putArray(entry.getKey(), newLists);
     349        }
     350       
     351        /// "maps"
     352        for (Entry<String, List<Map<String, String>>> entry : fragment.listOfStructsProperties.entrySet()) {
     353            String key = entry.getKey();
     354           
     355            Collection<Map<String, String>> existing = mainpref.listOfStructsProperties.get(key);
     356            Collection<Map<String, String>> defaults = mainpref.listOfStructsDefaults.get(key);
     357           
     358            if (existing==null && defaults==null) {
     359                defaultUnknownWarning(key);
     360                continue;
     361            }
     362           
     363            List<Map<String, String>> newMaps;
     364            newMaps = (existing != null) ?
     365                    new ArrayList<Map<String, String>>(existing) : new ArrayList<Map<String, String>>(defaults);
     366            Iterator<Map<String, String>> mapIterator = newMaps.iterator();
     367            while (mapIterator.hasNext()) {
     368                Map<String, String> map = mapIterator.next();
     369                for (Map<String, String> removeMap : entry.getValue()) {
     370                    if (map.entrySet().containsAll( removeMap.entrySet() )) {
     371                        // the map contain all mentioned key-value pair, so it should be deleted from "maps"
     372                        System.out.printf("!!!  deleting map from maps %s: %s\n", key, map);
     373                        mapIterator.remove();                                                                     
     374                    }
     375                }
     376            }
     377            mainpref.putListOfStructs(entry.getKey(), newMaps);
     378        }
     379    }
     380
     381    private void defaultUnknownWarning(String key) {
     382        JOptionPane.showMessageDialog(
     383                Main.parent,
     384                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),
     385                tr("Warning"),
     386                JOptionPane.WARNING_MESSAGE);
     387    }
     388
     389    private void showPrefs(Preferences tmpPref) {
     390        System.out.println("properties: " + tmpPref.properties);
     391        System.out.println("collections: " + tmpPref.collectionProperties);
     392        System.out.println("arrays: " + tmpPref.arrayProperties);
     393        System.out.println("maps: " + tmpPref.listOfStructsProperties);
     394    }
     395
     396    private void processDownloadOperation(Element item) {
     397        String address= item.getAttribute("url");
     398        String path= item.getAttribute("path");
     399        String dir= Main.pref.getPreferencesDir();
     400        if (path.contains("..") || path.startsWith("/") || path.contains(":")) return; // some basic protection
     401        File fOut = new File(dir,path);
     402       
     403        OutputStream out = null;
     404        InputStream in = null;
     405        HttpURLConnection downloadConnection;
     406        try {
     407            String mkdir=item.getAttribute("mkdir");
     408            if (mkdir!=null) {
     409                File newDir = new File(dir,mkdir);
     410                newDir.mkdirs();
     411            }
     412       
     413            URL url = new URL(address);
     414            System.out.printf("Downloading %s from %s\n", path, url.toString());
     415           
     416            downloadConnection = (HttpURLConnection)url.openConnection();
     417            downloadConnection.setRequestProperty("Cache-Control", "no-cache");
     418            downloadConnection.setRequestProperty("User-Agent",Version.getInstance().getAgentString());
     419            downloadConnection.setRequestProperty("Host", url.getHost());
     420            downloadConnection.connect();
     421            in = downloadConnection.getInputStream();
     422            out = new FileOutputStream(fOut);
     423            byte[] buffer = new byte[8192];
     424            for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
     425                out.write(buffer, 0, read);
     426            }
     427        } catch (IOException ex) {
     428            System.out.printf("Error downloading file %s from %s\n",path,address);
     429        } finally {
     430            try {
     431                if (out!=null) out.close();
     432                if (in!=null) in.close();
     433            } catch (IOException ex) {   }
     434        }
     435       
     436    }
     437
     438    private void processFileDelete(Element item) {
     439        String path= item.getAttribute("path");
     440        String dir= Main.pref.getPreferencesDir();
     441        if (path.contains("..") || path.startsWith("/") ||  path.contains(":")) return; // some basic protection
     442       
     443        System.out.printf("!!!  deleting file %s in %s\n", path, dir);
     444       
     445        File fOut = new File(dir,path);
     446        if (fOut.exists()) {
     447            if ( !fOut.delete() ) {
     448                JOptionPane.showMessageDialog(
     449                Main.parent,
     450                tr("Can not delete file {0} in {1}", path, dir),
     451                tr("Warning"),
     452                JOptionPane.WARNING_MESSAGE);
     453            }
     454        }
     455    }
     456}
  • src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java

     
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    22package org.openstreetmap.josm.gui.preferences.advanced;
    33
     4import javax.swing.JFileChooser;
    45import static org.openstreetmap.josm.tools.I18n.tr;
    56
    67import java.awt.Component;
     
    3536import javax.swing.table.DefaultTableModel;
    3637
    3738import org.openstreetmap.josm.Main;
     39import org.openstreetmap.josm.actions.DiskAccessAction;
     40import org.openstreetmap.josm.data.CustomConfigurator;
    3841import org.openstreetmap.josm.data.Preferences;
    3942import org.openstreetmap.josm.data.Preferences.ListListSetting;
    4043import org.openstreetmap.josm.data.Preferences.ListSetting;
     
    191194            }
    192195        });
    193196
     197        JButton read = new JButton(tr("Read from file"));
     198        p.add(read, GBC.std().insets(0,5,0,0));
     199        read.addActionListener(new ActionListener(){
     200            public void actionPerformed(ActionEvent e) {
     201                JFileChooser ch = DiskAccessAction.createAndOpenFileChooser(true, false, tr("Open JOSM customization file"), "xml");
     202                if (ch!=null) {
     203                    CustomConfigurator cc = new CustomConfigurator();
     204                    cc.readXML(ch.getSelectedFile());
     205                    ((AllSettingsTableModel) list.getModel()).fireTableDataChanged();
     206                }
     207               
     208            }
     209        });
     210
    194211        list.addMouseListener(new MouseAdapter(){
    195212            @Override public void mouseClicked(MouseEvent e) {
    196213                if (e.getClickCount() == 2) {