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

Last change on this file since 11553 was 11553, checked in by Don-vip, 8 months 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.