source: josm/trunk/src/org/openstreetmap/josm/data/PreferencesUtils.java@ 12823

Last change on this file since 12823 was 12634, checked in by Don-vip, 7 years ago

see #15182 - deprecate Main.worker, replace it by gui.MainApplication.worker + code refactoring to make sure only editor packages use it

File size: 20.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashMap;
9import java.util.Iterator;
10import java.util.List;
11import java.util.Map;
12import java.util.Map.Entry;
13import java.util.TreeMap;
14
15import javax.script.ScriptEngine;
16import javax.script.ScriptException;
17import javax.swing.JOptionPane;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.data.preferences.ListListSetting;
21import org.openstreetmap.josm.data.preferences.ListSetting;
22import org.openstreetmap.josm.data.preferences.MapListSetting;
23import org.openstreetmap.josm.data.preferences.Setting;
24import org.openstreetmap.josm.data.preferences.StringSetting;
25import org.openstreetmap.josm.gui.io.CustomConfigurator;
26import org.openstreetmap.josm.tools.Logging;
27import org.openstreetmap.josm.tools.Utils;
28
29/**
30 * Helper class to do specific Preferences operation - appending, replacing, deletion by key and by value
31 * Also contains functions that convert preferences object to JavaScript object and back
32 * @since 12634 (extracted from {@code CustomConfigurator})
33 */
34public final class PreferencesUtils {
35
36 private PreferencesUtils() {
37 // Hide implicit public constructor for utility class
38 }
39
40 public static void replacePreferences(Preferences fragment, Preferences mainpref) {
41 for (Entry<String, Setting<?>> entry: fragment.settingsMap.entrySet()) {
42 mainpref.putSetting(entry.getKey(), entry.getValue());
43 }
44 }
45
46 public static void appendPreferences(Preferences fragment, Preferences mainpref) {
47 for (Entry<String, Setting<?>> entry: fragment.settingsMap.entrySet()) {
48 String key = entry.getKey();
49 if (entry.getValue() instanceof StringSetting) {
50 mainpref.putSetting(key, entry.getValue());
51 } else if (entry.getValue() instanceof ListSetting) {
52 ListSetting lSetting = (ListSetting) entry.getValue();
53 Collection<String> newItems = getCollection(mainpref, key, true);
54 if (newItems == null) continue;
55 for (String item : lSetting.getValue()) {
56 // add nonexisting elements to then list
57 if (!newItems.contains(item)) {
58 newItems.add(item);
59 }
60 }
61 mainpref.putCollection(key, newItems);
62 } else if (entry.getValue() instanceof ListListSetting) {
63 ListListSetting llSetting = (ListListSetting) entry.getValue();
64 Collection<Collection<String>> newLists = getArray(mainpref, key, true);
65 if (newLists == null) continue;
66
67 for (Collection<String> list : llSetting.getValue()) {
68 // add nonexisting list (equals comparison for lists is used implicitly)
69 if (!newLists.contains(list)) {
70 newLists.add(list);
71 }
72 }
73 mainpref.putArray(key, newLists);
74 } else if (entry.getValue() instanceof MapListSetting) {
75 MapListSetting mlSetting = (MapListSetting) entry.getValue();
76 List<Map<String, String>> newMaps = getListOfStructs(mainpref, key, true);
77 if (newMaps == null) continue;
78
79 // get existing properties as list of maps
80
81 for (Map<String, String> map : mlSetting.getValue()) {
82 // add nonexisting map (equals comparison for maps is used implicitly)
83 if (!newMaps.contains(map)) {
84 newMaps.add(map);
85 }
86 }
87 mainpref.putListOfStructs(entry.getKey(), newMaps);
88 }
89 }
90 }
91
92 /**
93 * Delete items from {@code mainpref} collections that match items from {@code fragment} collections.
94 * @param fragment preferences
95 * @param mainpref main preferences
96 */
97 public static void deletePreferenceValues(Preferences fragment, Preferences mainpref) {
98
99 for (Entry<String, Setting<?>> entry : fragment.settingsMap.entrySet()) {
100 String key = entry.getKey();
101 if (entry.getValue() instanceof StringSetting) {
102 StringSetting sSetting = (StringSetting) entry.getValue();
103 // if mentioned value found, delete it
104 if (sSetting.equals(mainpref.settingsMap.get(key))) {
105 mainpref.put(key, null);
106 }
107 } else if (entry.getValue() instanceof ListSetting) {
108 ListSetting lSetting = (ListSetting) entry.getValue();
109 Collection<String> newItems = getCollection(mainpref, key, true);
110 if (newItems == null) continue;
111
112 // remove mentioned items from collection
113 for (String item : lSetting.getValue()) {
114 CustomConfigurator.log("Deleting preferences: from list %s: %s\n", key, item);
115 newItems.remove(item);
116 }
117 mainpref.putCollection(entry.getKey(), newItems);
118 } else if (entry.getValue() instanceof ListListSetting) {
119 ListListSetting llSetting = (ListListSetting) entry.getValue();
120 Collection<Collection<String>> newLists = getArray(mainpref, key, true);
121 if (newLists == null) continue;
122
123 // if items are found in one of lists, remove that list!
124 Iterator<Collection<String>> listIterator = newLists.iterator();
125 while (listIterator.hasNext()) {
126 Collection<String> list = listIterator.next();
127 for (Collection<String> removeList : llSetting.getValue()) {
128 if (list.containsAll(removeList)) {
129 // remove current list, because it matches search criteria
130 CustomConfigurator.log("Deleting preferences: list from lists %s: %s\n", key, list);
131 listIterator.remove();
132 }
133 }
134 }
135
136 mainpref.putArray(key, newLists);
137 } else if (entry.getValue() instanceof MapListSetting) {
138 MapListSetting mlSetting = (MapListSetting) entry.getValue();
139 List<Map<String, String>> newMaps = getListOfStructs(mainpref, key, true);
140 if (newMaps == null) continue;
141
142 Iterator<Map<String, String>> mapIterator = newMaps.iterator();
143 while (mapIterator.hasNext()) {
144 Map<String, String> map = mapIterator.next();
145 for (Map<String, String> removeMap : mlSetting.getValue()) {
146 if (map.entrySet().containsAll(removeMap.entrySet())) {
147 // the map contain all mentioned key-value pair, so it should be deleted from "maps"
148 CustomConfigurator.log("Deleting preferences: deleting map from maps %s: %s\n", key, map);
149 mapIterator.remove();
150 }
151 }
152 }
153 mainpref.putListOfStructs(entry.getKey(), newMaps);
154 }
155 }
156 }
157
158 public static void deletePreferenceKeyByPattern(String pattern, Preferences pref) {
159 Map<String, Setting<?>> allSettings = pref.getAllSettings();
160 for (Entry<String, Setting<?>> entry : allSettings.entrySet()) {
161 String key = entry.getKey();
162 if (key.matches(pattern)) {
163 CustomConfigurator.log("Deleting preferences: deleting key from preferences: " + key);
164 pref.putSetting(key, null);
165 }
166 }
167 }
168
169 public static void deletePreferenceKey(String key, Preferences pref) {
170 Map<String, Setting<?>> allSettings = pref.getAllSettings();
171 if (allSettings.containsKey(key)) {
172 CustomConfigurator.log("Deleting preferences: deleting key from preferences: " + key);
173 pref.putSetting(key, null);
174 }
175 }
176
177 private static Collection<String> getCollection(Preferences mainpref, String key, boolean warnUnknownDefault) {
178 ListSetting existing = Utils.cast(mainpref.settingsMap.get(key), ListSetting.class);
179 ListSetting defaults = Utils.cast(mainpref.defaultsMap.get(key), ListSetting.class);
180 if (existing == null && defaults == null) {
181 if (warnUnknownDefault) defaultUnknownWarning(key);
182 return null;
183 }
184 if (existing != null)
185 return new ArrayList<>(existing.getValue());
186 else
187 return defaults.getValue() == null ? null : new ArrayList<>(defaults.getValue());
188 }
189
190 private static Collection<Collection<String>> getArray(Preferences mainpref, String key, boolean warnUnknownDefault) {
191 ListListSetting existing = Utils.cast(mainpref.settingsMap.get(key), ListListSetting.class);
192 ListListSetting defaults = Utils.cast(mainpref.defaultsMap.get(key), ListListSetting.class);
193
194 if (existing == null && defaults == null) {
195 if (warnUnknownDefault) defaultUnknownWarning(key);
196 return null;
197 }
198 if (existing != null)
199 return new ArrayList<>(existing.getValue());
200 else
201 return defaults.getValue() == null ? null : new ArrayList<>(defaults.getValue());
202 }
203
204 private static List<Map<String, String>> getListOfStructs(Preferences mainpref, String key, boolean warnUnknownDefault) {
205 MapListSetting existing = Utils.cast(mainpref.settingsMap.get(key), MapListSetting.class);
206 MapListSetting defaults = Utils.cast(mainpref.settingsMap.get(key), MapListSetting.class);
207
208 if (existing == null && defaults == null) {
209 if (warnUnknownDefault) defaultUnknownWarning(key);
210 return null;
211 }
212
213 if (existing != null)
214 return new ArrayList<>(existing.getValue());
215 else
216 return defaults.getValue() == null ? null : new ArrayList<>(defaults.getValue());
217 }
218
219 private static void defaultUnknownWarning(String key) {
220 CustomConfigurator.log("Warning: Unknown default value of %s , skipped\n", key);
221 JOptionPane.showMessageDialog(
222 Main.parent,
223 tr("<html>Settings file asks to append preferences to <b>{0}</b>,<br/> "+
224 "but its default value is unknown at this moment.<br/> " +
225 "Please activate corresponding function manually and retry importing.", key),
226 tr("Warning"),
227 JOptionPane.WARNING_MESSAGE);
228 }
229
230 public static void showPrefs(Preferences tmpPref) {
231 Logging.info("properties: " + tmpPref.settingsMap);
232 }
233
234 public static void modifyPreferencesByScript(ScriptEngine engine, Preferences tmpPref, String js) throws ScriptException {
235 loadPrefsToJS(engine, tmpPref, "API.pref", true);
236 engine.eval(js);
237 readPrefsFromJS(engine, tmpPref, "API.pref");
238 }
239
240 /**
241 * Convert JavaScript preferences object to preferences data structures
242 * @param engine - JS engine to put object
243 * @param tmpPref - preferences to fill from JS
244 * @param varInJS - JS variable name, where preferences are stored
245 * @throws ScriptException if the evaluation fails
246 */
247 public static void readPrefsFromJS(ScriptEngine engine, Preferences tmpPref, String varInJS) throws ScriptException {
248 String finish =
249 "stringMap = new java.util.TreeMap ;"+
250 "listMap = new java.util.TreeMap ;"+
251 "listlistMap = new java.util.TreeMap ;"+
252 "listmapMap = new java.util.TreeMap ;"+
253 "for (key in "+varInJS+") {"+
254 " val = "+varInJS+"[key];"+
255 " type = typeof val == 'string' ? 'string' : val.type;"+
256 " if (type == 'string') {"+
257 " stringMap.put(key, val);"+
258 " } else if (type == 'list') {"+
259 " l = new java.util.ArrayList;"+
260 " for (i=0; i<val.length; i++) {"+
261 " l.add(java.lang.String.valueOf(val[i]));"+
262 " }"+
263 " listMap.put(key, l);"+
264 " } else if (type == 'listlist') {"+
265 " l = new java.util.ArrayList;"+
266 " for (i=0; i<val.length; i++) {"+
267 " list=val[i];"+
268 " jlist=new java.util.ArrayList;"+
269 " for (j=0; j<list.length; j++) {"+
270 " jlist.add(java.lang.String.valueOf(list[j]));"+
271 " }"+
272 " l.add(jlist);"+
273 " }"+
274 " listlistMap.put(key, l);"+
275 " } else if (type == 'listmap') {"+
276 " l = new java.util.ArrayList;"+
277 " for (i=0; i<val.length; i++) {"+
278 " map=val[i];"+
279 " jmap=new java.util.TreeMap;"+
280 " for (var key2 in map) {"+
281 " jmap.put(key2,java.lang.String.valueOf(map[key2]));"+
282 " }"+
283 " l.add(jmap);"+
284 " }"+
285 " listmapMap.put(key, l);"+
286 " } else {" +
287 " " + CustomConfigurator.class.getName() + ".log('Unknown type:'+val.type+ '- use list, listlist or listmap'); }"+
288 " }";
289 engine.eval(finish);
290
291 @SuppressWarnings("unchecked")
292 Map<String, String> stringMap = (Map<String, String>) engine.get("stringMap");
293 @SuppressWarnings("unchecked")
294 Map<String, List<String>> listMap = (Map<String, List<String>>) engine.get("listMap");
295 @SuppressWarnings("unchecked")
296 Map<String, List<Collection<String>>> listlistMap = (Map<String, List<Collection<String>>>) engine.get("listlistMap");
297 @SuppressWarnings("unchecked")
298 Map<String, List<Map<String, String>>> listmapMap = (Map<String, List<Map<String, String>>>) engine.get("listmapMap");
299
300 tmpPref.settingsMap.clear();
301
302 Map<String, Setting<?>> tmp = new HashMap<>();
303 for (Entry<String, String> e : stringMap.entrySet()) {
304 tmp.put(e.getKey(), new StringSetting(e.getValue()));
305 }
306 for (Entry<String, List<String>> e : listMap.entrySet()) {
307 tmp.put(e.getKey(), new ListSetting(e.getValue()));
308 }
309
310 for (Entry<String, List<Collection<String>>> e : listlistMap.entrySet()) {
311 @SuppressWarnings({ "unchecked", "rawtypes" })
312 List<List<String>> value = (List) e.getValue();
313 tmp.put(e.getKey(), new ListListSetting(value));
314 }
315 for (Entry<String, List<Map<String, String>>> e : listmapMap.entrySet()) {
316 tmp.put(e.getKey(), new MapListSetting(e.getValue()));
317 }
318 for (Entry<String, Setting<?>> e : tmp.entrySet()) {
319 if (e.getValue().equals(tmpPref.defaultsMap.get(e.getKey()))) continue;
320 tmpPref.settingsMap.put(e.getKey(), e.getValue());
321 }
322 }
323
324 /**
325 * Convert preferences data structures to JavaScript object
326 * @param engine - JS engine to put object
327 * @param tmpPref - preferences to convert
328 * @param whereToPutInJS - variable name to store preferences in JS
329 * @param includeDefaults - include known default values to JS objects
330 * @throws ScriptException if the evaluation fails
331 */
332 public static void loadPrefsToJS(ScriptEngine engine, Preferences tmpPref, String whereToPutInJS, boolean includeDefaults)
333 throws ScriptException {
334 Map<String, String> stringMap = new TreeMap<>();
335 Map<String, List<String>> listMap = new TreeMap<>();
336 Map<String, List<List<String>>> listlistMap = new TreeMap<>();
337 Map<String, List<Map<String, String>>> listmapMap = new TreeMap<>();
338
339 if (includeDefaults) {
340 for (Map.Entry<String, Setting<?>> e: tmpPref.defaultsMap.entrySet()) {
341 Setting<?> setting = e.getValue();
342 if (setting instanceof StringSetting) {
343 stringMap.put(e.getKey(), ((StringSetting) setting).getValue());
344 } else if (setting instanceof ListSetting) {
345 listMap.put(e.getKey(), ((ListSetting) setting).getValue());
346 } else if (setting instanceof ListListSetting) {
347 listlistMap.put(e.getKey(), ((ListListSetting) setting).getValue());
348 } else if (setting instanceof MapListSetting) {
349 listmapMap.put(e.getKey(), ((MapListSetting) setting).getValue());
350 }
351 }
352 }
353 tmpPref.settingsMap.entrySet().removeIf(e -> e.getValue().getValue() == null);
354
355 for (Map.Entry<String, Setting<?>> e: tmpPref.settingsMap.entrySet()) {
356 Setting<?> setting = e.getValue();
357 if (setting instanceof StringSetting) {
358 stringMap.put(e.getKey(), ((StringSetting) setting).getValue());
359 } else if (setting instanceof ListSetting) {
360 listMap.put(e.getKey(), ((ListSetting) setting).getValue());
361 } else if (setting instanceof ListListSetting) {
362 listlistMap.put(e.getKey(), ((ListListSetting) setting).getValue());
363 } else if (setting instanceof MapListSetting) {
364 listmapMap.put(e.getKey(), ((MapListSetting) setting).getValue());
365 }
366 }
367
368 engine.put("stringMap", stringMap);
369 engine.put("listMap", listMap);
370 engine.put("listlistMap", listlistMap);
371 engine.put("listmapMap", listmapMap);
372
373 String init =
374 "function getJSList( javaList ) {"+
375 " var jsList; var i; "+
376 " if (javaList == null) return null;"+
377 "jsList = [];"+
378 " for (i = 0; i < javaList.size(); i++) {"+
379 " jsList.push(String(list.get(i)));"+
380 " }"+
381 "return jsList;"+
382 "}"+
383 "function getJSMap( javaMap ) {"+
384 " var jsMap; var it; var e; "+
385 " if (javaMap == null) return null;"+
386 " jsMap = {};"+
387 " for (it = javaMap.entrySet().iterator(); it.hasNext();) {"+
388 " e = it.next();"+
389 " jsMap[ String(e.getKey()) ] = String(e.getValue()); "+
390 " }"+
391 " return jsMap;"+
392 "}"+
393 "for (it = stringMap.entrySet().iterator(); it.hasNext();) {"+
394 " e = it.next();"+
395 whereToPutInJS+"[String(e.getKey())] = String(e.getValue());"+
396 "}\n"+
397 "for (it = listMap.entrySet().iterator(); it.hasNext();) {"+
398 " e = it.next();"+
399 " list = e.getValue();"+
400 " jslist = getJSList(list);"+
401 " jslist.type = 'list';"+
402 whereToPutInJS+"[String(e.getKey())] = jslist;"+
403 "}\n"+
404 "for (it = listlistMap.entrySet().iterator(); it.hasNext(); ) {"+
405 " e = it.next();"+
406 " listlist = e.getValue();"+
407 " jslistlist = [];"+
408 " for (it2 = listlist.iterator(); it2.hasNext(); ) {"+
409 " list = it2.next(); "+
410 " jslistlist.push(getJSList(list));"+
411 " }"+
412 " jslistlist.type = 'listlist';"+
413 whereToPutInJS+"[String(e.getKey())] = jslistlist;"+
414 "}\n"+
415 "for (it = listmapMap.entrySet().iterator(); it.hasNext();) {"+
416 " e = it.next();"+
417 " listmap = e.getValue();"+
418 " jslistmap = [];"+
419 " for (it2 = listmap.iterator(); it2.hasNext();) {"+
420 " map = it2.next();"+
421 " jslistmap.push(getJSMap(map));"+
422 " }"+
423 " jslistmap.type = 'listmap';"+
424 whereToPutInJS+"[String(e.getKey())] = jslistmap;"+
425 "}\n";
426
427 // Execute conversion script
428 engine.eval(init);
429 }
430}
Note: See TracBrowser for help on using the repository browser.