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

Last change on this file was 14134, checked in by Don-vip, 6 years ago

see #15229 - deprecate Main*.undoRedo - make UndoRedoHandler a singleton

  • 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.UndoRedoHandler;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Relation;
21import org.openstreetmap.josm.spi.preferences.Config;
22import org.openstreetmap.josm.tools.Utils;
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 = Utils.removeWhiteSpaces(e.getValue());
85 String k = Utils.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 UndoRedoHandler.getInstance().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.