001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.preferences; 003 004import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener; 005import org.openstreetmap.josm.tools.CheckParameterUtil; 006import org.openstreetmap.josm.tools.Logging; 007import org.openstreetmap.josm.tools.bugreport.BugReport; 008 009/** 010 * This class represents a property that can be represented as String. 011 * 012 * @author Michael Zangl 013 * 014 * @param <T> The property content type. 015 * @since 10824 016 */ 017public abstract class AbstractToStringProperty<T> extends AbstractProperty<T> { 018 019 /** 020 * This is a version of this property that attempts to get the property with a more specialized key and - if that fails - uses the property 021 * value as default. 022 * 023 * @author Michael Zangl 024 * @param <T> The content type 025 */ 026 public static class ChildProperty<T> extends AbstractToStringProperty<T> { 027 private final AbstractToStringProperty<T> parent; 028 029 ChildProperty(AbstractToStringProperty<T> parent, String key) { 030 super(key, null); 031 CheckParameterUtil.ensureParameterNotNull(parent, "parent"); 032 this.parent = parent; 033 } 034 035 @Override 036 protected void storeDefaultValue() { 037 // Default value hidden in preferences. 038 } 039 040 @Override 041 public T getDefaultValue() { 042 return parent.get(); 043 } 044 045 @Override 046 protected T fromString(String string) { 047 return parent.fromString(string); 048 } 049 050 @Override 051 protected String toString(T t) { 052 return parent.toString(t); 053 } 054 055 @Override 056 protected void addListenerImpl(PreferenceChangedListener adapter) { 057 super.addListenerImpl(adapter); 058 parent.addListenerImpl(adapter); 059 } 060 061 @Override 062 protected void removeListenerImpl(PreferenceChangedListener adapter) { 063 super.removeListenerImpl(adapter); 064 parent.removeListenerImpl(adapter); 065 } 066 067 @Override 068 public CachingProperty<T> cached() { 069 throw new UnsupportedOperationException("Not implemented yet."); 070 } 071 } 072 073 /** 074 * Create a new property and store the default value. 075 * @param key The key 076 * @param defaultValue The default value. 077 * @see AbstractProperty#AbstractProperty(String, Object) 078 */ 079 public AbstractToStringProperty(String key, T defaultValue) { 080 super(key, defaultValue); 081 storeDefaultValue(); 082 } 083 084 @Override 085 public T get() { 086 String string = getAsString(); 087 if (!string.isEmpty()) { 088 try { 089 return fromString(string); 090 } catch (InvalidPreferenceValueException e) { 091 Logging.warn(BugReport.intercept(e).put("key", key).put("value", string)); 092 } 093 } 094 return getDefaultValue(); 095 } 096 097 /** 098 * Converts the string to an object of the given type. 099 * @param string The string 100 * @return The object. 101 * @throws InvalidPreferenceValueException If the value could not be converted. 102 */ 103 protected abstract T fromString(String string); 104 105 @Override 106 public boolean put(T value) { 107 String string = value == null ? null : toString(value); 108 return getPreferences().put(getKey(), string); 109 } 110 111 /** 112 * Converts the string to an object of the given type. 113 * @param t The object. 114 * @return The string representing the object 115 * @throws InvalidPreferenceValueException If the value could not be converted. 116 */ 117 protected abstract String toString(T t); 118 119 /** 120 * Gets the preference value as String. 121 * @return The string preference value. 122 */ 123 protected String getAsString() { 124 T def = getDefaultValue(); 125 String sdef = def == null ? "" : toString(def); 126 return getPreferences() != null ? getPreferences().get(key, sdef) : sdef; 127 } 128 129 /** 130 * Gets a specialized setting value that has the current value as default 131 * <p> 132 * The key will be getKey().spec 133 * @param spec The key specialization 134 * @return The property 135 */ 136 public AbstractToStringProperty<T> getSpecialized(String spec) { 137 return getChildProperty(getKey() + "." + spec); 138 } 139 140 /** 141 * Gets a setting that defaults to this setting if the key is not set. 142 * @param key The more specialized key. 143 * @return The new setting. 144 */ 145 protected AbstractToStringProperty<T> getChildProperty(String key) { 146 return new ChildProperty<>(this, key); 147 } 148 149}