source: josm/trunk/src/org/openstreetmap/josm/actions/upload/FixDataHook.java

Last change on this file was 12846, checked in by bastiK, 2 months ago

see #15229 - use Config.getPref() wherever possible

  • Property svn:eol-style set to native
File size: 7.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.upload;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Collection;
7import java.util.Collections;
8import java.util.HashMap;
9import java.util.LinkedList;
10import java.util.List;
11import java.util.Map;
12import java.util.Map.Entry;
13
14import org.openstreetmap.josm.command.ChangePropertyCommand;
15import org.openstreetmap.josm.command.Command;
16import org.openstreetmap.josm.command.SequenceCommand;
17import org.openstreetmap.josm.data.APIDataSet;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.data.osm.Relation;
20import org.openstreetmap.josm.data.osm.Tag;
21import org.openstreetmap.josm.gui.MainApplication;
22import org.openstreetmap.josm.spi.preferences.Config;
23
24/**
25 * Fixes defective data entries for all modified objects before upload
26 * @since 5621
27 */
28public class FixDataHook implements UploadHook {
29
30    private static final String ONEWAY = "oneway";
31
32    /**
33     * List of checks to run on data
34     */
35    private final List<FixData> deprecated = new LinkedList<>();
36
37    /**
38     * Constructor for data initialization
39     */
40    public FixDataHook() {
41        // CHECKSTYLE.OFF: SingleSpaceSeparator
42        deprecated.add(new FixDataSpace());
43        deprecated.add(new FixDataKey("color",            "colour"));
44        deprecated.add(new FixDataTag("highway", "ford",  "ford",    "yes"));
45        deprecated.add(new FixDataTag(ONEWAY,    "false",  ONEWAY,   "no"));
46        deprecated.add(new FixDataTag(ONEWAY,    "0",      ONEWAY,   "no"));
47        deprecated.add(new FixDataTag(ONEWAY,    "true",   ONEWAY,   "yes"));
48        deprecated.add(new FixDataTag(ONEWAY,    "1",      ONEWAY,   "yes"));
49        deprecated.add(new FixDataTag("highway", "stile", "barrier", "stile"));
50        // CHECKSTYLE.ON: SingleSpaceSeparator
51        deprecated.add((keys, osm) -> {
52            if (osm instanceof Relation && "multipolygon".equals(keys.get("type")) && "administrative".equals(keys.get("boundary"))) {
53                keys.put("type", "boundary");
54                return true;
55            }
56            return false;
57        });
58    }
59
60    /**
61     * Common set of commands for data fixing
62     * @since 10600 (functional interface)
63     */
64    @FunctionalInterface
65    public interface FixData {
66        /**
67         * Checks if data needs to be fixed and change keys
68         *
69         * @param keys list of keys to be modified
70         * @param osm the object for type validation, don't use keys of it!
71         * @return <code>true</code> if keys have been modified
72         */
73        boolean fixKeys(Map<String, String> keys, OsmPrimitive osm);
74    }
75
76    /**
77     * Data fix to remove spaces at begin or end of tags
78     */
79    public static class FixDataSpace implements FixData {
80        @Override
81        public boolean fixKeys(Map<String, String> keys, OsmPrimitive osm) {
82            Map<String, String> newKeys = new HashMap<>(keys);
83            for (Entry<String, String> e : keys.entrySet()) {
84                String v = Tag.removeWhiteSpaces(e.getValue());
85                String k = Tag.removeWhiteSpaces(e.getKey());
86                boolean drop = k.isEmpty() || v.isEmpty();
87                if (!e.getKey().equals(k)) {
88                    if (drop || !keys.containsKey(k)) {
89                        newKeys.put(e.getKey(), null);
90                        if (!drop)
91                            newKeys.put(k, v);
92                    }
93                } else if (!e.getValue().equals(v)) {
94                    newKeys.put(k, v.isEmpty() ? null : v);
95                } else if (drop) {
96                    newKeys.put(e.getKey(), null);
97                }
98            }
99            boolean changed = !keys.equals(newKeys);
100            if (changed) {
101                keys.clear();
102                keys.putAll(newKeys);
103            }
104            return changed;
105        }
106    }
107
108    /**
109     * Data fix to cleanup wrong spelled keys
110     */
111    public static class FixDataKey implements FixData {
112        /** key of wrong data */
113        private final String oldKey;
114        /** key of correct data */
115        private final String newKey;
116
117        /**
118         * Setup key check for wrong spelled keys
119         *
120         * @param oldKey wrong spelled key
121         * @param newKey correct replacement
122         */
123        public FixDataKey(String oldKey, String newKey) {
124            this.oldKey = oldKey;
125            this.newKey = newKey;
126        }
127
128        @Override
129        public boolean fixKeys(Map<String, String> keys, OsmPrimitive osm) {
130            if (keys.containsKey(oldKey) && !keys.containsKey(newKey)) {
131                keys.put(newKey, keys.get(oldKey));
132                keys.put(oldKey, null);
133                return true;
134            } else if (keys.containsKey(oldKey) && keys.containsKey(newKey) && keys.get(oldKey).equals(keys.get(newKey))) {
135                keys.put(oldKey, null);
136                return true;
137            }
138            return false;
139        }
140    }
141
142    /**
143     * Data fix to cleanup wrong spelled tags
144     */
145    public static class FixDataTag implements FixData {
146        /** key of wrong data */
147        private final String oldKey;
148        /** value of wrong data */
149        private final String oldValue;
150        /** key of correct data */
151        private final String newKey;
152        /** value of correct data */
153        private final String newValue;
154
155        /**
156         * Setup key check for wrong spelled keys
157         *
158         * @param oldKey wrong or old key
159         * @param oldValue wrong or old value
160         * @param newKey correct key replacement
161         * @param newValue correct value replacement
162         */
163        public FixDataTag(String oldKey, String oldValue, String newKey, String newValue) {
164            this.oldKey = oldKey;
165            this.oldValue = oldValue;
166            this.newKey = newKey;
167            this.newValue = newValue;
168        }
169
170        @Override
171        public boolean fixKeys(Map<String, String> keys, OsmPrimitive osm) {
172            if (oldValue.equals(keys.get(oldKey)) && (newKey.equals(oldKey)
173            || !keys.containsKey(newKey) || keys.get(newKey).equals(newValue))) {
174                keys.put(newKey, newValue);
175                if (!newKey.equals(oldKey))
176                    keys.put(oldKey, null);
177                return true;
178            }
179            return false;
180        }
181    }
182
183    /**
184     * Checks the upload for deprecated or wrong tags.
185     * @param apiDataSet the data to upload
186     */
187    @Override
188    public boolean checkUpload(APIDataSet apiDataSet) {
189        if (Config.getPref().getBoolean("fix.data.on.upload", true)) {
190            Collection<Command> cmds = new LinkedList<>();
191
192            for (OsmPrimitive osm : apiDataSet.getPrimitives()) {
193                Map<String, String> keys = new HashMap<>(osm.getKeys());
194                if (!keys.isEmpty()) {
195                    boolean modified = false;
196                    for (FixData fix : deprecated) {
197                        if (fix.fixKeys(keys, osm))
198                            modified = true;
199                    }
200                    if (modified) {
201                        cmds.add(new ChangePropertyCommand(Collections.singleton(osm), keys));
202                    }
203                }
204            }
205
206            if (!cmds.isEmpty()) {
207                MainApplication.undoRedo.add(new SequenceCommand(tr("Fix deprecated tags"), cmds));
208            }
209        }
210        return true;
211    }
212}
Note: See TracBrowser for help on using the repository browser.