source: josm/trunk/src/org/openstreetmap/josm/data/preferences/AbstractProperty.java@ 11746

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

refactor handling of null values - use Java 8 Optional where possible

  • Property svn:eol-style set to native
File size: 9.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.preferences;
3
4import org.openstreetmap.josm.Main;
5import org.openstreetmap.josm.data.Preferences;
6import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
7import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
8
9/**
10 * Captures the common functionality of preference properties
11 * @param <T> The type of object accessed by this property
12 */
13public abstract class AbstractProperty<T> {
14
15 private final class PreferenceChangedListenerAdapter implements PreferenceChangedListener {
16 private final ValueChangeListener<? super T> listener;
17
18 PreferenceChangedListenerAdapter(ValueChangeListener<? super T> listener) {
19 this.listener = listener;
20 }
21
22 @Override
23 public void preferenceChanged(PreferenceChangeEvent e) {
24 listener.valueChanged(new ValueChangeEvent<>(e, AbstractProperty.this));
25 }
26
27 @Override
28 public int hashCode() {
29 final int prime = 31;
30 int result = 1;
31 result = prime * result + getOuterType().hashCode();
32 result = prime * result + ((listener == null) ? 0 : listener.hashCode());
33 return result;
34 }
35
36 @Override
37 public boolean equals(Object obj) {
38 if (this == obj)
39 return true;
40 if (obj == null || getClass() != obj.getClass())
41 return false;
42 @SuppressWarnings("unchecked")
43 PreferenceChangedListenerAdapter other = (PreferenceChangedListenerAdapter) obj;
44 if (!getOuterType().equals(other.getOuterType()))
45 return false;
46 if (listener == null) {
47 if (other.listener != null)
48 return false;
49 } else if (!listener.equals(other.listener))
50 return false;
51 return true;
52 }
53
54 private AbstractProperty<T> getOuterType() {
55 return AbstractProperty.this;
56 }
57
58 @Override
59 public String toString() {
60 return "PreferenceChangedListenerAdapter [listener=" + listener + ']';
61 }
62 }
63
64 /**
65 * A listener that listens to changes in the properties value.
66 * @author michael
67 * @param <T> property type
68 * @since 10824
69 */
70 @FunctionalInterface
71 public interface ValueChangeListener<T> {
72 /**
73 * Method called when a property value has changed.
74 * @param e property change event
75 */
76 void valueChanged(ValueChangeEvent<? extends T> e);
77 }
78
79 /**
80 * An event that is triggered if the value of a property changes.
81 * @author Michael Zangl
82 * @param <T> property type
83 * @since 10824
84 */
85 public static class ValueChangeEvent<T> {
86 private final PreferenceChangeEvent base;
87 private final AbstractProperty<T> source;
88
89 ValueChangeEvent(PreferenceChangeEvent base, AbstractProperty<T> source) {
90 this.base = base;
91 this.source = source;
92 }
93
94 /**
95 * Get the base event.
96 * @return the base event
97 * @since 11496
98 */
99 public final PreferenceChangeEvent getBaseEvent() {
100 return base;
101 }
102
103 /**
104 * Get the property that was changed
105 * @return The property.
106 */
107 public AbstractProperty<T> getProperty() {
108 return source;
109 }
110 }
111
112 /**
113 * An exception that is thrown if a preference value is invalid.
114 * @author Michael Zangl
115 * @since 10824
116 */
117 public static class InvalidPreferenceValueException extends RuntimeException {
118
119 /**
120 * Constructs a new {@code InvalidPreferenceValueException} with the specified detail message and cause.
121 * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method).
122 * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
123 */
124 public InvalidPreferenceValueException(String message, Throwable cause) {
125 super(message, cause);
126 }
127
128 /**
129 * Constructs a new {@code InvalidPreferenceValueException} with the specified detail message.
130 * The cause is not initialized, and may subsequently be initialized by a call to {@link #initCause}.
131 *
132 * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
133 */
134 public InvalidPreferenceValueException(String message) {
135 super(message);
136 }
137
138 /**
139 * Constructs a new {@code InvalidPreferenceValueException} with the specified cause and a detail message of
140 * <tt>(cause==null ? null : cause.toString())</tt> (which typically contains the class and detail message of <tt>cause</tt>).
141 *
142 * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
143 */
144 public InvalidPreferenceValueException(Throwable cause) {
145 super(cause);
146 }
147 }
148
149 /**
150 * The preferences object this property is for.
151 */
152 protected final Preferences preferences;
153 protected final String key;
154 protected final T defaultValue;
155
156 /**
157 * Constructs a new {@code AbstractProperty}.
158 * @param key The property key
159 * @param defaultValue The default value
160 * @since 5464
161 */
162 public AbstractProperty(String key, T defaultValue) {
163 // Main.pref should not change in production but may change during tests.
164 preferences = Main.pref;
165 this.key = key;
166 this.defaultValue = defaultValue;
167 }
168
169 /**
170 * Store the default value to {@link Preferences}.
171 */
172 protected void storeDefaultValue() {
173 if (getPreferences() != null) {
174 get();
175 }
176 }
177
178 /**
179 * Replies the property key.
180 * @return The property key
181 */
182 public String getKey() {
183 return key;
184 }
185
186 /**
187 * Determines if this property is currently set in JOSM preferences.
188 * @return true if {@code Main.pref} contains this property.
189 */
190 public boolean isSet() {
191 return !getPreferences().get(key).isEmpty();
192 }
193
194 /**
195 * Replies the default value of this property.
196 * @return The default value of this property
197 */
198 public T getDefaultValue() {
199 return defaultValue;
200 }
201
202 /**
203 * Removes this property from JOSM preferences (i.e replace it by its default value).
204 */
205 public void remove() {
206 put(getDefaultValue());
207 }
208
209 /**
210 * Replies the value of this property.
211 * @return the value of this property
212 * @since 5464
213 */
214 public abstract T get();
215
216 /**
217 * Sets this property to the specified value.
218 * @param value The new value of this property
219 * @return true if something has changed (i.e. value is different than before)
220 * @since 5464
221 */
222 public abstract boolean put(T value);
223
224 /**
225 * Gets the preferences used for this property.
226 * @return The preferences for this property.
227 * @since 10824
228 */
229 protected Preferences getPreferences() {
230 return preferences;
231 }
232
233 /**
234 * Adds a listener that listens only for changes to this preference key.
235 * @param listener The listener to add.
236 * @since 10824
237 */
238 public void addListener(ValueChangeListener<? super T> listener) {
239 addListenerImpl(new PreferenceChangedListenerAdapter(listener));
240 }
241
242 protected void addListenerImpl(PreferenceChangedListener adapter) {
243 getPreferences().addKeyPreferenceChangeListener(getKey(), adapter);
244 }
245
246 /**
247 * Adds a weak listener that listens only for changes to this preference key.
248 * @param listener The listener to add.
249 * @since 10824
250 */
251 public void addWeakListener(ValueChangeListener<? super T> listener) {
252 addWeakListenerImpl(new PreferenceChangedListenerAdapter(listener));
253 }
254
255 protected void addWeakListenerImpl(PreferenceChangedListener adapter) {
256 getPreferences().addWeakKeyPreferenceChangeListener(getKey(), adapter);
257 }
258
259 /**
260 * Removes a listener that listens only for changes to this preference key.
261 * @param listener The listener to add.
262 * @since 10824
263 */
264 public void removeListener(ValueChangeListener<? super T> listener) {
265 removeListenerImpl(new PreferenceChangedListenerAdapter(listener));
266 }
267
268 protected void removeListenerImpl(PreferenceChangedListener adapter) {
269 getPreferences().removeKeyPreferenceChangeListener(getKey(), adapter);
270 }
271
272 @Override
273 public int hashCode() {
274 final int prime = 31;
275 int result = 1;
276 result = prime * result + ((key == null) ? 0 : key.hashCode());
277 result = prime * result + ((preferences == null) ? 0 : preferences.hashCode());
278 return result;
279 }
280
281 @Override
282 public boolean equals(Object obj) {
283 if (this == obj)
284 return true;
285 if (obj == null || getClass() != obj.getClass())
286 return false;
287 AbstractProperty<?> other = (AbstractProperty<?>) obj;
288 if (key == null) {
289 if (other.key != null)
290 return false;
291 } else if (!key.equals(other.key))
292 return false;
293 if (preferences == null) {
294 if (other.preferences != null)
295 return false;
296 } else if (!preferences.equals(other.preferences))
297 return false;
298 return true;
299 }
300}
Note: See TracBrowser for help on using the repository browser.