001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.spi.preferences; 003 004import java.util.LinkedList; 005import java.util.List; 006import java.util.Map; 007import java.util.Map.Entry; 008import java.util.TreeMap; 009import java.util.stream.Collectors; 010 011import org.openstreetmap.josm.tools.Logging; 012import org.openstreetmap.josm.tools.Utils; 013 014/** 015 * Abstract implementation of the {@link IPreferences} interface. 016 * @since 12847 017 */ 018public abstract class AbstractPreferences implements IPreferences { 019 020 @Override 021 public synchronized String get(final String key, final String def) { 022 return getSetting(key, new StringSetting(def), StringSetting.class).getValue(); 023 } 024 025 @Override 026 public boolean put(final String key, String value) { 027 return putSetting(key, Utils.isEmpty(value) ? null : new StringSetting(value)); 028 } 029 030 @Override 031 public boolean getBoolean(final String key, final boolean def) { 032 return Boolean.parseBoolean(get(key, Boolean.toString(def))); 033 } 034 035 @Override 036 public boolean putBoolean(final String key, final boolean value) { 037 return put(key, Boolean.toString(value)); 038 } 039 040 @Override 041 public synchronized int getInt(String key, int def) { 042 String v = get(key, Integer.toString(def)); 043 if (v.isEmpty()) 044 return def; 045 046 try { 047 return Integer.parseInt(v); 048 } catch (NumberFormatException e) { 049 // fall out 050 Logging.trace(e); 051 } 052 return def; 053 } 054 055 @Override 056 public boolean putInt(String key, int value) { 057 return put(key, Integer.toString(value)); 058 } 059 060 @Override 061 public long getLong(String key, long def) { 062 String v = get(key, Long.toString(def)); 063 if (null == v) 064 return def; 065 066 try { 067 return Long.parseLong(v); 068 } catch (NumberFormatException e) { 069 // fall out 070 Logging.trace(e); 071 } 072 return def; 073 } 074 075 @Override 076 public boolean putLong(final String key, final long value) { 077 return put(key, Long.toString(value)); 078 } 079 080 @Override 081 public synchronized double getDouble(String key, double def) { 082 String v = get(key, Double.toString(def)); 083 if (null == v) 084 return def; 085 086 try { 087 return Double.parseDouble(v); 088 } catch (NumberFormatException e) { 089 // fall out 090 Logging.trace(e); 091 } 092 return def; 093 } 094 095 @Override 096 public boolean putDouble(final String key, final double value) { 097 return put(key, Double.toString(value)); 098 } 099 100 @Override 101 public List<String> getList(String key, List<String> def) { 102 return getSetting(key, new ListSetting(def), ListSetting.class).getValue(); 103 } 104 105 @Override 106 public boolean putList(String key, List<String> value) { 107 return putSetting(key, value == null ? null : new ListSetting(value)); 108 } 109 110 @Override 111 public List<List<String>> getListOfLists(String key, List<List<String>> def) { 112 return getSetting(key, new ListListSetting(def), ListListSetting.class).getValue(); 113 } 114 115 @Override 116 public boolean putListOfLists(String key, List<List<String>> value) { 117 return putSetting(key, value == null ? null : new ListListSetting(value)); 118 } 119 120 @Override 121 public List<Map<String, String>> getListOfMaps(String key, List<Map<String, String>> def) { 122 return getSetting(key, new MapListSetting(def), MapListSetting.class).getValue(); 123 } 124 125 @Override 126 public boolean putListOfMaps(String key, List<Map<String, String>> value) { 127 return putSetting(key, value == null ? null : new MapListSetting(value)); 128 } 129 130 /** 131 * Gets a map of all settings that are currently stored 132 * @return The settings 133 */ 134 public abstract Map<String, Setting<?>> getAllSettings(); 135 136 /** 137 * Set a value for a certain setting. The changed setting is saved to the preference file immediately. 138 * Due to caching mechanisms on modern operating systems and hardware, this shouldn't be a performance problem. 139 * @param key the unique identifier for the setting 140 * @param setting the value of the setting. In case it is null, the key-value entry will be removed. 141 * @return {@code true}, if something has changed (i.e. value is different than before) 142 */ 143 public abstract boolean putSetting(String key, Setting<?> setting); 144 145 /** 146 * Get settings value for a certain key and provide default a value. 147 * @param <T> the setting type 148 * @param key the identifier for the setting 149 * @param def the default value. For each call of getSetting() with a given key, the default value must be the same. 150 * <code>def</code> must not be null, but the value of <code>def</code> can be null. 151 * @param klass the setting type (same as T) 152 * @return the corresponding value if the property has been set before, {@code def} otherwise 153 */ 154 public abstract <T extends Setting<?>> T getSetting(String key, T def, Class<T> klass); 155 156 /** 157 * Gets all normal (string) settings that have a key starting with the prefix 158 * @param prefix The start of the key 159 * @return The key names of the settings 160 */ 161 public Map<String, String> getAllPrefix(String prefix) { 162 return getAllSettings().entrySet().stream() 163 .filter(e -> e.getKey().startsWith(prefix) && (e.getValue() instanceof StringSetting)) 164 .collect(Collectors.toMap(Entry::getKey, e -> ((StringSetting) e.getValue()).getValue(), (a, b) -> b, TreeMap::new)); 165 } 166 167 /** 168 * Gets all list settings that have a key starting with the prefix 169 * @param prefix The start of the key 170 * @return The key names of the list settings 171 */ 172 public List<String> getAllPrefixCollectionKeys(String prefix) { 173 return getAllSettings().entrySet().stream() 174 .filter(entry -> entry.getKey().startsWith(prefix) && entry.getValue() instanceof ListSetting) 175 .map(Entry::getKey) 176 .collect(Collectors.toCollection(LinkedList::new)); 177 } 178}