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

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

see #15229 - see #15182 - remove GUI references from PreferencesUtils

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