Changeset 10824 in josm for trunk


Ignore:
Timestamp:
2016-08-17T09:18:31+02:00 (8 years ago)
Author:
Don-vip
Message:

see #13309 - Caching and notifying preferences (patch by michael2402) - gsoc-core

Location:
trunk
Files:
4 added
27 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/Preferences.java

    r10788 r10824  
    3737import java.util.SortedMap;
    3838import java.util.TreeMap;
    39 import java.util.concurrent.CopyOnWriteArrayList;
    4039import java.util.function.Predicate;
    4140import java.util.regex.Matcher;
    4241import java.util.regex.Pattern;
     42import java.util.stream.Stream;
    4343
    4444import javax.json.Json;
     
    5555
    5656import org.openstreetmap.josm.Main;
     57import org.openstreetmap.josm.data.preferences.BooleanProperty;
    5758import org.openstreetmap.josm.data.preferences.ColorProperty;
     59import org.openstreetmap.josm.data.preferences.DoubleProperty;
     60import org.openstreetmap.josm.data.preferences.IntegerProperty;
    5861import org.openstreetmap.josm.data.preferences.ListListSetting;
    5962import org.openstreetmap.josm.data.preferences.ListSetting;
     63import org.openstreetmap.josm.data.preferences.LongProperty;
    6064import org.openstreetmap.josm.data.preferences.MapListSetting;
    6165import org.openstreetmap.josm.data.preferences.PreferencesReader;
     
    6872import org.openstreetmap.josm.tools.ColorHelper;
    6973import org.openstreetmap.josm.tools.I18n;
     74import org.openstreetmap.josm.tools.ListenerList;
    7075import org.openstreetmap.josm.tools.MultiMap;
    71 import org.openstreetmap.josm.tools.SubclassFilteredCollection;
    7276import org.openstreetmap.josm.tools.Utils;
    7377import org.xml.sax.SAXException;
     
    215219    }
    216220
     221    /**
     222     * Old color interface
     223     * <p>
     224     * To be removed: end of 2016
     225     * @deprecated Use a {@link ColorProperty} instead.
     226     */
     227    @Deprecated
    217228    public interface ColorKey {
    218229        String getColorName();
     
    223234    }
    224235
    225     private final CopyOnWriteArrayList<PreferenceChangedListener> listeners = new CopyOnWriteArrayList<>();
     236    private final ListenerList<PreferenceChangedListener> listeners = ListenerList.create();
     237
     238    private final HashMap<String, ListenerList<PreferenceChangedListener>> keyListeners = new HashMap<>();
    226239
    227240    /**
     
    231244    public void addPreferenceChangeListener(PreferenceChangedListener listener) {
    232245        if (listener != null) {
    233             listeners.addIfAbsent(listener);
     246            listeners.addListener(listener);
    234247        }
    235248    }
     
    240253     */
    241254    public void removePreferenceChangeListener(PreferenceChangedListener listener) {
    242         listeners.remove(listener);
     255        listeners.removeListener(listener);
     256    }
     257
     258    /**
     259     * Adds a listener that only listens to changes in one preference
     260     * @param key The preference key to listen to
     261     * @param listener The listener to add.
     262     * @since 10824
     263     */
     264    public void addKeyPreferenceChangeListener(String key, PreferenceChangedListener listener) {
     265        listenersForKey(key).addListener(listener);
     266    }
     267
     268    /**
     269     * Adds a weak listener that only listens to changes in one preference
     270     * @param key The preference key to listen to
     271     * @param listener The listener to add.
     272     * @since 10824
     273     */
     274    public void addWeakKeyPreferenceChangeListener(String key, PreferenceChangedListener listener) {
     275        listenersForKey(key).addWeakListener(listener);
     276    }
     277
     278    private ListenerList<PreferenceChangedListener> listenersForKey(String key) {
     279        ListenerList<PreferenceChangedListener> keyListener = keyListeners.get(key);
     280        if (keyListener == null) {
     281            keyListener = ListenerList.create();
     282            keyListeners.put(key, keyListener);
     283        }
     284        return keyListener;
     285    }
     286
     287    /**
     288     * Removes a listener that only listens to changes in one preference
     289     * @param key The preference key to listen to
     290     * @param listener The listener to add.
     291     */
     292    public void removeKeyPreferenceChangeListener(String key, PreferenceChangedListener listener) {
     293        ListenerList<PreferenceChangedListener> keyListener = keyListeners.get(key);
     294        if (keyListener == null) {
     295            throw new IllegalArgumentException("There are no listeners registered for " + key);
     296        }
     297        keyListener.removeListener(listener);
    243298    }
    244299
    245300    protected void firePreferenceChanged(String key, Setting<?> oldValue, Setting<?> newValue) {
    246         PreferenceChangeEvent evt = new DefaultPreferenceChangeEvent(key, oldValue, newValue);
    247         for (PreferenceChangedListener l : listeners) {
    248             l.preferenceChanged(evt);
     301        final PreferenceChangeEvent evt = new DefaultPreferenceChangeEvent(key, oldValue, newValue);
     302        listeners.fireEvent(listener -> listener.preferenceChanged(evt));
     303
     304        ListenerList<PreferenceChangedListener> forKey = keyListeners.get(key);
     305        if (forKey != null) {
     306            forKey.fireEvent(listener -> listener.preferenceChanged(evt));
    249307        }
    250308    }
     
    479537     */
    480538    public boolean put(final String key, String value) {
    481         if (value != null && value.isEmpty()) {
    482             value = null;
    483         }
    484         return putSetting(key, value == null ? null : new StringSetting(value));
    485     }
    486 
     539        return putSetting(key, value == null || value.isEmpty() ? null : new StringSetting(value));
     540    }
     541
     542    /**
     543     * Set a boolean value for a certain setting.
     544     * @param key the unique identifier for the setting
     545     * @param value The new value
     546     * @return {@code true}, if something has changed (i.e. value is different than before)
     547     * @see BooleanProperty
     548     */
    487549    public boolean put(final String key, final boolean value) {
    488550        return put(key, Boolean.toString(value));
    489551    }
    490552
     553    /**
     554     * Set a boolean value for a certain setting.
     555     * @param key the unique identifier for the setting
     556     * @param value The new value
     557     * @return {@code true}, if something has changed (i.e. value is different than before)
     558     * @see IntegerProperty
     559     */
    491560    public boolean putInteger(final String key, final Integer value) {
    492561        return put(key, Integer.toString(value));
    493562    }
    494563
     564    /**
     565     * Set a boolean value for a certain setting.
     566     * @param key the unique identifier for the setting
     567     * @param value The new value
     568     * @return {@code true}, if something has changed (i.e. value is different than before)
     569     * @see DoubleProperty
     570     */
    495571    public boolean putDouble(final String key, final Double value) {
    496572        return put(key, Double.toString(value));
    497573    }
    498574
     575    /**
     576     * Set a boolean value for a certain setting.
     577     * @param key the unique identifier for the setting
     578     * @param value The new value
     579     * @return {@code true}, if something has changed (i.e. value is different than before)
     580     * @see LongProperty
     581     */
    499582    public boolean putLong(final String key, final Long value) {
    500583        return put(key, Long.toString(value));
     
    506589     */
    507590    public synchronized void save() throws IOException {
    508         save(getPreferenceFile(),
    509                 new SubclassFilteredCollection<>(settingsMap.entrySet(), NO_DEFAULT_SETTINGS_ENTRY), false);
     591        save(getPreferenceFile(), settingsMap.entrySet().stream().filter(NO_DEFAULT_SETTINGS_ENTRY), false);
    510592    }
    511593
    512594    public synchronized void saveDefaults() throws IOException {
    513         save(getDefaultsCacheFile(), defaultsMap.entrySet(), true);
    514     }
    515 
    516     protected void save(File prefFile, Collection<Entry<String, Setting<?>>> settings, boolean defaults) throws IOException {
    517 
     595        save(getDefaultsCacheFile(), defaultsMap.entrySet().stream(), true);
     596    }
     597
     598    protected void save(File prefFile, Stream<Entry<String, Setting<?>>> settings, boolean defaults) throws IOException {
    518599        if (!defaults) {
    519600            /* currently unused, but may help to fix configuration issues in future */
     
    719800    /**
    720801     * Convenience method for accessing colour preferences.
     802     * <p>
     803     * To be removed: end of 2016
    721804     *
    722805     * @param colName name of the colour
    723806     * @param def default value
    724807     * @return a Color object for the configured colour, or the default value if none configured.
    725      */
     808     * @deprecated Use a {@link ColorProperty} instead.
     809     */
     810    @Deprecated
    726811    public synchronized Color getColor(String colName, Color def) {
    727812        return getColor(colName, null, def);
     
    743828    /**
    744829     * Returns the color for the given key.
     830     * <p>
     831     * To be removed: end of 2016
    745832     * @param key The color key
    746833     * @return the color
    747      */
     834     * @deprecated Use a {@link ColorProperty} instead.
     835     */
     836    @Deprecated
    748837    public Color getColor(ColorKey key) {
    749838        return getColor(key.getColorName(), key.getSpecialName(), key.getDefaultValue());
     
    752841    /**
    753842     * Convenience method for accessing colour preferences.
    754      *
     843     * <p>
     844     * To be removed: end of 2016
    755845     * @param colName name of the colour
    756846     * @param specName name of the special colour settings
    757847     * @param def default value
    758848     * @return a Color object for the configured colour, or the default value if none configured.
    759      */
     849     * @deprecated Use a {@link ColorProperty} instead.
     850     * You can replace this by: <code>new ColorProperty(colName, def).getChildColor(specName)</code>
     851     */
     852    @Deprecated
    760853    public synchronized Color getColor(String colName, String specName, Color def) {
    761854        String colKey = ColorProperty.getColorKey(colName);
    762         if (!colKey.equals(colName)) {
    763             colornames.put(colKey, colName);
    764         }
     855        registerColor(colKey, colName);
    765856        String colStr = specName != null ? get("color."+specName) : "";
    766857        if (colStr.isEmpty()) {
     
    771862        } else {
    772863            return def;
     864        }
     865    }
     866
     867    /**
     868     * Registers a color name conversion for the global color registry.
     869     * @param colKey The key
     870     * @param colName The name of the color.
     871     * @since 10824
     872     */
     873    public void registerColor(String colKey, String colName) {
     874        if (!colKey.equals(colName)) {
     875            colornames.put(colKey, colName);
    773876        }
    774877    }
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/PaintColors.java

    r10378 r10824  
    77import java.util.List;
    88
    9 import org.openstreetmap.josm.Main;
    10 import org.openstreetmap.josm.data.Preferences.ColorKey;
     9import org.openstreetmap.josm.data.preferences.CachingProperty;
     10import org.openstreetmap.josm.data.preferences.ColorProperty;
    1111import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    1212import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.MapPaintSylesUpdateListener;
    1313import org.openstreetmap.josm.gui.mappaint.StyleSource;
    1414
    15 public enum PaintColors implements ColorKey {
     15public enum PaintColors {
    1616
    1717    INACTIVE(marktr("inactive"), Color.darkGray),
     
    3434    private final String name;
    3535    private final Color defaultColor;
     36    private final CachingProperty<Color> property;
    3637
    3738    private static volatile Color backgroundColorCache;
    3839
    3940    private static final MapPaintSylesUpdateListener styleOverrideListener = new MapPaintSylesUpdateListener() {
    40 
     41        //TODO: Listen to wireframe map mode changes.
    4142        @Override
    4243        public void mapPaintStylesUpdated() {
     
    5556
    5657    PaintColors(String name, Color defaultColor) {
     58        property = new ColorProperty(name, defaultColor).cached();
    5759        this.name = name;
    5860        this.defaultColor = defaultColor;
    5961    }
    6062
    61     @Override
    62     public String getColorName() {
    63         return name;
    64     }
    65 
    66     @Override
    6763    public Color getDefaultValue() {
    68         return defaultColor;
    69     }
    70 
    71     @Override
    72     public String getSpecialName() {
    73         return null;
     64        return property.getDefaultValue();
    7465    }
    7566
    7667    public Color get() {
    77         return Main.pref.getColor(this);
    78     }
    79 
    80     public static void getColors() {
    81         for (PaintColors c:values()) {
    82             c.get();
    83         }
     68        return property.get();
    8469    }
    8570
     
    9883        }
    9984        if (backgroundColorCache == null) {
    100             backgroundColorCache = BACKGROUND.get();
     85            return BACKGROUND.get();
     86        } else {
     87            return backgroundColorCache;
    10188        }
    102         return backgroundColorCache;
    10389    }
    10490}
  • trunk/src/org/openstreetmap/josm/data/preferences/AbstractProperty.java

    r6069 r10824  
    33
    44import org.openstreetmap.josm.Main;
     5import org.openstreetmap.josm.data.Preferences;
     6import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
     7import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
    58
    69/**
     
    912 */
    1013public abstract class AbstractProperty<T> {
     14
     15    private final class PreferenceChangedListenerAdapter implements PreferenceChangedListener {
     16        private 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)
     41                return false;
     42            if (getClass() != obj.getClass())
     43                return false;
     44            @SuppressWarnings("unchecked")
     45            PreferenceChangedListenerAdapter other = (PreferenceChangedListenerAdapter) obj;
     46            if (!getOuterType().equals(other.getOuterType()))
     47                return false;
     48            if (listener == null) {
     49                if (other.listener != null)
     50                    return false;
     51            } else if (!listener.equals(other.listener))
     52                return false;
     53            return true;
     54        }
     55
     56        private AbstractProperty<T> getOuterType() {
     57            return AbstractProperty.this;
     58        }
     59
     60        @Override
     61        public String toString() {
     62            return "PreferenceChangedListenerAdapter [listener=" + listener + ']';
     63        }
     64    }
     65
     66    /**
     67     * A listener that listens to changes in the properties value.
     68     * @author michael
     69     * @param <T> property type
     70     * @since 10824
     71     */
     72    public interface ValueChangeListener<T> {
     73        /**
     74         * Method called when a property value has changed.
     75         * @param e property change event
     76         */
     77        void valueChanged(ValueChangeEvent<? extends T> e);
     78    }
     79
     80    /**
     81     * An event that is triggered if the value of a property changes.
     82     * @author Michael Zangl
     83     * @param <T> property type
     84     * @since 10824
     85     */
     86    public static class ValueChangeEvent<T> {
     87        private final PreferenceChangeEvent base;
     88
     89        private final AbstractProperty<T> source;
     90
     91        ValueChangeEvent(PreferenceChangeEvent base, AbstractProperty<T> source) {
     92            this.base = base;
     93            this.source = source;
     94        }
     95
     96        /**
     97         * Get the property that was changed
     98         * @return The property.
     99         */
     100        public AbstractProperty<T> getProperty() {
     101            return source;
     102        }
     103    }
     104
     105    /**
     106     * An exception that is thrown if a preference value is invalid.
     107     * @author Michael Zangl
     108     * @since 10824
     109     */
     110    public static class InvalidPreferenceValueException extends RuntimeException {
     111
     112        /**
     113         * Constructs a new {@code InvalidPreferenceValueException} with the specified detail message and cause.
     114         * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method).
     115         * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
     116         */
     117        public InvalidPreferenceValueException(String message, Throwable cause) {
     118            super(message, cause);
     119        }
     120
     121        /**
     122         * Constructs a new {@code InvalidPreferenceValueException} with the specified detail message.
     123         * The cause is not initialized, and may subsequently be initialized by a call to {@link #initCause}.
     124         *
     125         * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
     126         */
     127        public InvalidPreferenceValueException(String message) {
     128            super(message);
     129        }
     130
     131        /**
     132         * Constructs a new {@code InvalidPreferenceValueException} with the specified cause and a detail message of
     133         * <tt>(cause==null ? null : cause.toString())</tt> (which typically contains the class and detail message of <tt>cause</tt>).
     134         *
     135         * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
     136         */
     137        public InvalidPreferenceValueException(Throwable cause) {
     138            super(cause);
     139        }
     140    }
     141
     142    /**
     143     * The preferences object this property is for.
     144     */
     145    protected final Preferences preferences;
    11146    protected final String key;
    12147    protected final T defaultValue;
     
    19154     */
    20155    public AbstractProperty(String key, T defaultValue) {
     156        // Main.pref should not change in production but may change during tests.
     157        preferences = Main.pref;
    21158        this.key = key;
    22159        this.defaultValue = defaultValue;
     
    24161
    25162    /**
     163     * Store the default value to {@link Preferences}.
     164     */
     165    protected void storeDefaultValue() {
     166        if (getPreferences() != null) {
     167            get();
     168        }
     169    }
     170
     171    /**
    26172     * Replies the property key.
    27173     * @return The property key
     
    36182     */
    37183    public boolean isSet() {
    38         return !Main.pref.get(key).isEmpty();
     184        return !getPreferences().get(key).isEmpty();
    39185    }
    40186
     
    51197     */
    52198    public void remove() {
    53         Main.pref.put(getKey(), String.valueOf(getDefaultValue()));
     199        put(getDefaultValue());
    54200    }
    55201
     
    68214     */
    69215    public abstract boolean put(T value);
     216
     217    /**
     218     * Gets the preferences used for this property.
     219     * @return The preferences for this property.
     220     * @since 10824
     221     */
     222    protected Preferences getPreferences() {
     223        return preferences;
     224    }
     225
     226    /**
     227     * Adds a listener that listens only for changes to this preference key.
     228     * @param listener The listener to add.
     229     * @since 10824
     230     */
     231    public void addListener(ValueChangeListener<? super T> listener) {
     232        addListenerImpl(new PreferenceChangedListenerAdapter(listener));
     233    }
     234
     235    protected void addListenerImpl(PreferenceChangedListener adapter) {
     236        getPreferences().addKeyPreferenceChangeListener(getKey(), adapter);
     237    }
     238
     239    /**
     240     * Adds a weak listener that listens only for changes to this preference key.
     241     * @param listener The listener to add.
     242     * @since 10824
     243     */
     244    public void addWeakListener(ValueChangeListener<? super T> listener) {
     245        addWeakListenerImpl(new PreferenceChangedListenerAdapter(listener));
     246    }
     247
     248    protected void addWeakListenerImpl(PreferenceChangedListener adapter) {
     249        getPreferences().addWeakKeyPreferenceChangeListener(getKey(), adapter);
     250    }
     251
     252    /**
     253     * Removes a listener that listens only for changes to this preference key.
     254     * @param listener The listener to add.
     255     * @since 10824
     256     */
     257    public void removeListener(ValueChangeListener<? super T> listener) {
     258        removeListenerImpl(new PreferenceChangedListenerAdapter(listener));
     259    }
     260
     261    protected void removeListenerImpl(PreferenceChangedListener adapter) {
     262        getPreferences().removeKeyPreferenceChangeListener(getKey(), adapter);
     263    }
     264
     265    @Override
     266    public int hashCode() {
     267        final int prime = 31;
     268        int result = 1;
     269        result = prime * result + ((key == null) ? 0 : key.hashCode());
     270        result = prime * result + ((preferences == null) ? 0 : preferences.hashCode());
     271        return result;
     272    }
     273
     274    @Override
     275    public boolean equals(Object obj) {
     276        if (this == obj)
     277            return true;
     278        if (obj == null)
     279            return false;
     280        if (getClass() != obj.getClass())
     281            return false;
     282        AbstractProperty<?> other = (AbstractProperty<?>) obj;
     283        if (key == null) {
     284            if (other.key != null)
     285                return false;
     286        } else if (!key.equals(other.key))
     287            return false;
     288        if (preferences == null) {
     289            if (other.preferences != null)
     290                return false;
     291        } else if (!preferences.equals(other.preferences))
     292            return false;
     293        return true;
     294    }
    70295}
  • trunk/src/org/openstreetmap/josm/data/preferences/BooleanProperty.java

    r9689 r10824  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.data.preferences;
    3 
    4 import org.openstreetmap.josm.Main;
    53
    64/**
    75 * A property containing a {@code Boolean} value.
    86 */
    9 public class BooleanProperty extends AbstractProperty<Boolean> {
     7public class BooleanProperty extends AbstractToStringProperty<Boolean> {
    108
    119    /**
     
    1614    public BooleanProperty(String key, boolean defaultValue) {
    1715        super(key, defaultValue);
    18         if (Main.pref != null) {
    19             get();
    20         }
    2116    }
    2217
    2318    @Override
    2419    public Boolean get() {
    25         return Main.pref.getBoolean(getKey(), defaultValue);
     20        // Removing this implementation breaks binary compatibility
     21        return super.get();
    2622    }
    2723
    2824    @Override
    2925    public boolean put(Boolean value) {
    30         return Main.pref.put(getKey(), value);
     26        // Removing this implementation breaks binary compatibility
     27        return super.put(value);
     28    }
     29
     30    @Override
     31    protected Boolean fromString(String string) {
     32        return Boolean.valueOf(string);
     33    }
     34
     35    @Override
     36    protected String toString(Boolean t) {
     37        return t.toString();
    3138    }
    3239}
  • trunk/src/org/openstreetmap/josm/data/preferences/CachedProperty.java

    r7937 r10824  
    1414    protected CachedProperty(String key, String defaultValueAsString) {
    1515        super(key, null);
    16         Main.pref.addPreferenceChangeListener(this);
     16        Main.pref.addKeyPreferenceChangeListener(key, this);
    1717        this.defaultValueAsString = defaultValueAsString;
    1818        updateValue();
     
    6161
    6262    public String getAsString() {
    63         return Main.pref.get(getKey(), getDefaultValueAsString());
     63        return getPreferences().get(getKey(), getDefaultValueAsString());
    6464    }
    6565
  • trunk/src/org/openstreetmap/josm/data/preferences/CollectionProperty.java

    r9689 r10824  
    2525    @Override
    2626    public Collection<String> get() {
    27         return Main.pref.getCollection(getKey(), getDefaultValue());
     27        return getPreferences().getCollection(getKey(), getDefaultValue());
    2828    }
    2929
    3030    @Override
    3131    public boolean put(Collection<String> value) {
    32         return Main.pref.putCollection(getKey(), value);
     32        return getPreferences().putCollection(getKey(), value);
    3333    }
    3434}
  • trunk/src/org/openstreetmap/josm/data/preferences/ColorProperty.java

    r9689 r10824  
    55import java.util.Locale;
    66
    7 import org.openstreetmap.josm.Main;
    8 import org.openstreetmap.josm.data.Preferences.ColorKey;
     7import org.openstreetmap.josm.tools.ColorHelper;
    98
    109/**
     
    1211 * @since 5464
    1312 */
    14 public class ColorProperty extends AbstractProperty<Color> implements ColorKey {
     13public class ColorProperty extends AbstractToStringProperty<Color> {
    1514
    1615    private final String name;
     16
     17    /**
     18     * Constructs a new {@code ColorProperty}.
     19     * @param colName The color name
     20     * @param defaultValue The default value as HTML string
     21     */
     22    public ColorProperty(String colName, String defaultValue) {
     23        this(colName, ColorHelper.html2color(defaultValue));
     24    }
    1725
    1826    /**
     
    2432        super(getColorKey(colName), defaultValue);
    2533        this.name = colName;
    26         if (Main.pref != null) {
    27             get();
    28         }
     34        getPreferences().registerColor(getColorKey(colName), colName);
    2935    }
    3036
    3137    @Override
    3238    public Color get() {
    33         return Main.pref.getColor(this);
     39        // Removing this implementation breaks binary compatibility due to the way generics work
     40        return super.get();
    3441    }
    3542
    3643    @Override
    3744    public boolean put(Color value) {
    38         return Main.pref.putColor(getColorKey(name), value);
     45        // Removing this implementation breaks binary compatibility due to the way generics work
     46        return super.put(value);
     47    }
     48
     49    @Override
     50    protected Color fromString(String string) {
     51        return ColorHelper.html2color(string);
     52    }
     53
     54    @Override
     55    protected String toString(Color t) {
     56        return ColorHelper.color2html(t, true);
     57    }
     58
     59    /**
     60     * Gets a color of which the value can be set.
     61     * @param colorName the name of the color.
     62     * @return The child property that inherits this value if it is not set.
     63     */
     64    public AbstractToStringProperty<Color> getChildColor(String colorName) {
     65        return getChildProperty(getColorKey(colorName));
     66    }
     67
     68    /**
     69     * Gets the name this color was registered with.
     70     * @return The name.
     71     */
     72    public String getName() {
     73        return name;
    3974    }
    4075
     
    4580     */
    4681    public static String getColorKey(String colName) {
    47         return colName == null ? null : colName.toLowerCase(Locale.ENGLISH).replaceAll("[^a-z0-9]+", ".");
     82        return colName == null ? null : "color." + colName.toLowerCase(Locale.ENGLISH).replaceAll("[^a-z0-9]+", ".");
    4883    }
    4984
    5085    @Override
    51     public String getColorName() {
    52         return name;
    53     }
    54 
    55     @Override
    56     public String getSpecialName() {
    57         return null;
     86    public String toString() {
     87        return "ColorProperty [name=" + name + ", defaultValue=" + getDefaultValue() + "]";
    5888    }
    5989}
  • trunk/src/org/openstreetmap/josm/data/preferences/DoubleProperty.java

    r9818 r10824  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.data.preferences;
    3 
    4 import org.openstreetmap.josm.Main;
    53
    64/**
     
    86 * @since 3246
    97 */
    10 public class DoubleProperty extends AbstractProperty<Double> {
     8public class DoubleProperty extends AbstractToStringProperty<Double> {
    119
    1210    /**
     
    2119    @Override
    2220    public Double get() {
    23         return Main.pref.getDouble(getKey(), getDefaultValue());
     21        // Removing this implementation breaks binary compatibility
     22        return super.get();
    2423    }
    2524
    2625    @Override
    2726    public boolean put(Double value) {
    28         return Main.pref.putDouble(getKey(), value);
     27        // Removing this implementation breaks binary compatibility
     28        return super.put(value);
     29    }
     30
     31    @Override
     32    protected Double fromString(String string) {
     33        try {
     34            return Double.valueOf(string);
     35        } catch (NumberFormatException e) {
     36            throw new InvalidPreferenceValueException(e);
     37        }
     38    }
     39
     40    @Override
     41    protected String toString(Double t) {
     42        return t.toString();
    2943    }
    3044
  • trunk/src/org/openstreetmap/josm/data/preferences/IntegerProperty.java

    r9689 r10824  
    88 * @since 3246
    99 */
    10 public class IntegerProperty extends AbstractProperty<Integer> {
     10public class IntegerProperty extends AbstractToStringProperty<Integer> {
    1111
    1212    /**
     
    2424    @Override
    2525    public Integer get() {
    26         return Main.pref.getInteger(getKey(), getDefaultValue());
     26        // Removing this implementation breaks binary compatibility
     27        return super.get();
    2728    }
    2829
    2930    @Override
    3031    public boolean put(Integer value) {
    31         return Main.pref.putInteger(getKey(), value);
     32        // Removing this implementation breaks binary compatibility
     33        return super.put(value);
     34    }
     35
     36    @Override
     37    protected Integer fromString(String string) {
     38        try {
     39            return Integer.valueOf(string);
     40        } catch (NumberFormatException e) {
     41            throw new InvalidPreferenceValueException(e);
     42        }
     43    }
     44
     45    @Override
     46    protected String toString(Integer t) {
     47        return t.toString();
    3248    }
    3349
  • trunk/src/org/openstreetmap/josm/data/preferences/LongProperty.java

    r10087 r10824  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.data.preferences;
    3 
    4 import org.openstreetmap.josm.Main;
    53
    64/**
     
    97 *
    108 */
    11 public class LongProperty extends AbstractProperty<Long> {
     9public class LongProperty extends AbstractToStringProperty<Long> {
    1210
    1311    /**
     
    1816    public LongProperty(String key, long defaultValue) {
    1917        super(key, defaultValue);
    20         if (Main.pref != null) {
    21             get();
     18    }
     19
     20    @Override
     21    public Long get() {
     22        // Removing this implementation breaks binary compatibility
     23        return super.get();
     24    }
     25
     26    @Override
     27    public boolean put(Long value) {
     28        // Removing this implementation breaks binary compatibility
     29        return super.put(value);
     30    }
     31
     32    @Override
     33    protected Long fromString(String string) {
     34        try {
     35            return Long.valueOf(string);
     36        } catch (NumberFormatException e) {
     37            throw new InvalidPreferenceValueException(e);
    2238        }
    2339    }
    2440
    2541    @Override
    26     public Long get() {
    27         return Main.pref.getLong(getKey(), getDefaultValue());
     42    protected String toString(Long t) {
     43        return t.toString();
    2844    }
    29 
    30     @Override
    31     public boolean put(Long value) {
    32         return Main.pref.putLong(getKey(), value);
    33     }
    34 
    3545}
  • trunk/src/org/openstreetmap/josm/data/preferences/PreferencesWriter.java

    r9828 r10824  
    66import java.util.List;
    77import java.util.Map;
     8import java.util.stream.Stream;
    89
    910import org.openstreetmap.josm.Main;
     
    3839     */
    3940    public void write(Collection<Map.Entry<String, Setting<?>>> settings) {
     41        write(settings.stream());
     42    }
     43
     44    /**
     45     * Write preferences.
     46     *
     47     * @param settings preferences settings to write as stream.
     48     */
     49    public void write(Stream<Map.Entry<String, Setting<?>>> settings) {
    4050        out.write(String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n"));
    4151        String rootElement = defaults ? "preferences-defaults" : "preferences";
     
    4555        }
    4656        out.write(String.format(" version='%d'>%n", Version.getInstance().getVersion()));
    47         for (Map.Entry<String, Setting<?>> e : settings) {
     57        settings.forEachOrdered(e -> {
    4858            setKey(e.getKey());
    4959            e.getValue().visit(this);
    50         }
     60        });
    5161        out.write(String.format("</%s>%n", rootElement));
    5262    }
  • trunk/src/org/openstreetmap/josm/data/preferences/StringProperty.java

    r9689 r10824  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.data.preferences;
    3 
    4 import org.openstreetmap.josm.Main;
    53
    64/**
    75 * A property containing an {@code String} value.
    86 */
    9 public class StringProperty extends AbstractProperty<String> {
     7public class StringProperty extends AbstractToStringProperty<String> {
    108
    119    /**
     
    1614    public StringProperty(String key, String defaultValue) {
    1715        super(key, defaultValue);
    18         if (Main.pref != null) {
    19             get();
    20         }
    2116    }
    2217
    2318    @Override
    2419    public String get() {
    25         return Main.pref.get(getKey(), getDefaultValue());
     20        // Removing this implementation breaks binary compatibility
     21        return super.get();
    2622    }
    2723
    2824    @Override
    2925    public boolean put(String value) {
    30         return Main.pref.put(getKey(), value);
     26        // Removing this implementation breaks binary compatibility
     27        return super.put(value);
     28    }
     29
     30    @Override
     31    protected String fromString(String string) {
     32        return string;
     33    }
     34
     35    @Override
     36    protected String toString(String string) {
     37        return string;
    3138    }
    3239}
  • trunk/src/org/openstreetmap/josm/gui/MainApplication.java

    r10786 r10824  
    314314        }
    315315
    316         initApplicationPreferences();
    317 
    318         Policy.setPolicy(new Policy() {
    319             // Permissions for plug-ins loaded when josm is started via webstart
    320             private PermissionCollection pc;
    321 
    322             {
    323                 pc = new Permissions();
    324                 pc.add(new AllPermission());
    325             }
    326 
    327             @Override
    328             public PermissionCollection getPermissions(CodeSource codesource) {
    329                 return pc;
    330             }
    331         });
    332 
    333         Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
    334 
    335         // initialize the platform hook, and
    336         Main.determinePlatformHook();
    337         // call the really early hook before we do anything else
    338         Main.platform.preStartupHook();
    339 
    340         Main.COMMAND_LINE_ARGS.addAll(Arrays.asList(argArray));
    341 
    342         if (args.containsKey(Option.VERSION)) {
    343             System.out.println(Version.getInstance().getAgentString());
    344             System.exit(0);
    345         }
    346 
    347         if (args.containsKey(Option.DEBUG) || args.containsKey(Option.TRACE)) {
    348             // Enable JOSM debug level
    349             logLevel = 4;
    350             Main.info(tr("Printing debugging messages to console"));
    351         }
    352 
    353         boolean skipLoadingPlugins = false;
    354         if (args.containsKey(Option.SKIP_PLUGINS)) {
    355             skipLoadingPlugins = true;
    356             Main.info(tr("Plugin loading skipped"));
    357         }
    358 
    359316        if (args.containsKey(Option.TRACE)) {
    360317            // Enable JOSM debug level
     
    363320            Utils.updateSystemProperty("debug", "true");
    364321            Main.info(tr("Enabled detailed debug level (trace)"));
     322        } else if (args.containsKey(Option.DEBUG)) {
     323            // Enable JOSM debug level
     324            logLevel = 4;
     325            Main.info(tr("Printing debugging messages to console"));
     326        }
     327
     328        initApplicationPreferences();
     329
     330        Policy.setPolicy(new Policy() {
     331            // Permissions for plug-ins loaded when josm is started via webstart
     332            private PermissionCollection pc;
     333
     334            {
     335                pc = new Permissions();
     336                pc.add(new AllPermission());
     337            }
     338
     339            @Override
     340            public PermissionCollection getPermissions(CodeSource codesource) {
     341                return pc;
     342            }
     343        });
     344
     345        Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
     346
     347        // initialize the platform hook, and
     348        Main.determinePlatformHook();
     349        // call the really early hook before we do anything else
     350        Main.platform.preStartupHook();
     351
     352        Main.COMMAND_LINE_ARGS.addAll(Arrays.asList(argArray));
     353
     354        if (args.containsKey(Option.VERSION)) {
     355            System.out.println(Version.getInstance().getAgentString());
     356            System.exit(0);
     357        }
     358
     359        boolean skipLoadingPlugins = false;
     360        if (args.containsKey(Option.SKIP_PLUGINS)) {
     361            skipLoadingPlugins = true;
     362            Main.info(tr("Plugin loading skipped"));
    365363        }
    366364
  • trunk/src/org/openstreetmap/josm/gui/MapFrame.java

    r10611 r10824  
    760760            } else if (mapMode != null) {
    761761                mapMode.exitMode(); // if new mode is null - simply exit from previous mode
     762                mapMode = null;
    762763            }
    763764        }
  • trunk/src/org/openstreetmap/josm/gui/MapStatus.java

    r10716 r10824  
    6565import org.openstreetmap.josm.data.osm.OsmPrimitive;
    6666import org.openstreetmap.josm.data.osm.Way;
     67import org.openstreetmap.josm.data.preferences.AbstractProperty;
     68import org.openstreetmap.josm.data.preferences.BooleanProperty;
    6769import org.openstreetmap.josm.data.preferences.ColorProperty;
     70import org.openstreetmap.josm.data.preferences.DoubleProperty;
    6871import org.openstreetmap.josm.gui.help.Helpful;
    6972import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
     
    9396
    9497    private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat(Main.pref.get("statusbar.decimal-format", "0.0"));
    95     private final double DISTANCE_THRESHOLD = Main.pref.getDouble("statusbar.distance-threshold", 0.01);
     98    private static final AbstractProperty<Double> DISTANCE_THRESHOLD = new DoubleProperty("statusbar.distance-threshold", 0.01).cached();
     99
     100    private static final AbstractProperty<Boolean> SHOW_ID = new BooleanProperty("osm-primitives.showid", false);
    96101
    97102    /**
     
    100105     */
    101106    public static final ColorProperty PROP_BACKGROUND_COLOR = new ColorProperty(
    102             marktr("Status bar background"), Color.decode("#b8cfe5"));
     107            marktr("Status bar background"), "#b8cfe5");
    103108
    104109    /**
     
    107112     */
    108113    public static final ColorProperty PROP_ACTIVE_BACKGROUND_COLOR = new ColorProperty(
    109             marktr("Status bar background: active"), Color.decode("#aaff5e"));
     114            marktr("Status bar background: active"), "#aaff5e");
    110115
    111116    /**
     
    568573            text.append(name);
    569574
    570             boolean idShown = Main.pref.getBoolean("osm-primitives.showid");
     575            boolean idShown = SHOW_ID.get();
    571576            // fix #7557 - do not show ID twice
    572577
     
    10211026    public void setDist(double dist) {
    10221027        distValue = dist;
    1023         distText.setText(dist < 0 ? "--" : NavigatableComponent.getDistText(dist, DECIMAL_FORMAT, DISTANCE_THRESHOLD));
     1028        distText.setText(dist < 0 ? "--" : NavigatableComponent.getDistText(dist, DECIMAL_FORMAT, DISTANCE_THRESHOLD.get()));
    10241029    }
    10251030
  • trunk/src/org/openstreetmap/josm/gui/conflict/ConflictColors.java

    r10134 r10824  
    66import java.awt.Color;
    77
    8 import org.openstreetmap.josm.Main;
    9 import org.openstreetmap.josm.data.Preferences.ColorKey;
     8import org.openstreetmap.josm.data.preferences.ColorProperty;
    109
    1110/**
     
    1312 * @since 4162
    1413 */
    15 public enum ConflictColors implements ColorKey {
     14public enum ConflictColors {
    1615
    1716    /** Conflict background: no conflict */
     
    8382    FGCOLOR_MEMBER_REMOVE(marktr("Conflict foreground: remove member"), Color.black);
    8483
    85     private final String name;
    86     private final Color defaultColor;
     84    private final ColorProperty property;
    8785
    8886    ConflictColors(String name, Color defaultColor) {
    89         this.name = name;
    90         this.defaultColor = defaultColor;
    91     }
    92 
    93     @Override
    94     public String getColorName() {
    95         return name;
    96     }
    97 
    98     @Override
    99     public Color getDefaultValue() {
    100         return defaultColor;
    101     }
    102 
    103     @Override
    104     public String getSpecialName() {
    105         return null;
     87        property = new ColorProperty(name, defaultColor);
    10688    }
    10789
     
    11193     */
    11294    public Color get() {
    113         return Main.pref.getColor(this);
     95        return property.get();
    11496    }
    11597
  • trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java

    r10763 r10824  
    2121import java.util.Collections;
    2222import java.util.List;
     23import java.util.Objects;
    2324import java.util.concurrent.CopyOnWriteArrayList;
    2425
     
    4546import org.openstreetmap.josm.Main;
    4647import org.openstreetmap.josm.actions.MergeLayerAction;
     48import org.openstreetmap.josm.data.preferences.AbstractProperty;
    4749import org.openstreetmap.josm.gui.MapFrame;
    4850import org.openstreetmap.josm.gui.MapView;
     
    546548            }
    547549            if (Main.pref.getBoolean("dialog.layer.colorname", true)) {
    548                 Color c = layer.getColor(false);
    549                 if (c != null) {
    550                     Color oc = null;
    551                     for (Layer l : model.getLayers()) {
    552                         oc = l.getColor(false);
    553                         if (oc != null) {
    554                             if (oc.equals(c)) {
    555                                 oc = null;
    556                             } else {
    557                                 break;
    558                             }
    559                         }
    560                     }
     550                AbstractProperty<Color> prop = layer.getColorProperty();
     551                Color c = prop == null ? null : prop.get();
     552                if (c == null || !model.getLayers().stream()
     553                        .map(Layer::getColorProperty)
     554                        .filter(Objects::nonNull)
     555                        .map(AbstractProperty::get)
     556                        .anyMatch(oc -> oc != null && !oc.equals(c))) {
    561557                    /* not more than one color, don't use coloring */
    562                     if (oc == null) {
    563                         c = null;
    564                     }
     558                    label.setForeground(UIManager.getColor(isSelected ? "Table.selectionForeground" : "Table.foreground"));
     559                } else {
     560                    label.setForeground(c);
    565561                }
    566                 if (c == null) {
    567                     c = UIManager.getColor(isSelected ? "Table.selectionForeground" : "Table.foreground");
    568                 }
    569                 label.setForeground(c);
    570562            }
    571563            label.setIcon(layer.getIcon());
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java

    r10790 r10824  
    6464import org.openstreetmap.josm.command.ChangePropertyCommand;
    6565import org.openstreetmap.josm.command.Command;
    66 import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
     66import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
    6767import org.openstreetmap.josm.data.SelectionChangedListener;
    6868import org.openstreetmap.josm.data.osm.IRelation;
     
    226226            + tr("Select objects for which to change tags.") + "</p></html>");
    227227
     228    private final PreferenceChangedListener preferenceListener = e -> {
     229                if (Main.getLayerManager().getEditDataSet() != null) {
     230                    // Re-load data when display preference change
     231                    updateSelection();
     232                }};
     233
    228234    private final transient TaggingPresetHandler presetHandler = new TaggingPresetHandler() {
    229235        @Override
     
    298304        editHelper.loadTagsIfNeeded();
    299305
    300         Main.pref.addPreferenceChangeListener(this);
     306        Main.pref.addKeyPreferenceChangeListener("display.discardable-keys", preferenceListener);
    301307    }
    302308
     
    602608    public void destroy() {
    603609        super.destroy();
    604         Main.pref.removePreferenceChangeListener(this);
     610        Main.pref.removeKeyPreferenceChangeListener("display.discardable-keys", preferenceListener);
    605611        Container parent = pluginHook.getParent();
    606612        if (parent != null) {
     
    13901396    }
    13911397
    1392     @Override
    1393     public void preferenceChanged(PreferenceChangeEvent e) {
    1394         super.preferenceChanged(e);
    1395         if ("display.discardable-keys".equals(e.getKey()) && Main.getLayerManager().getEditDataSet() != null) {
    1396             // Re-load data when display preference change
    1397             updateSelection();
    1398         }
    1399     }
    1400 
    14011398    /**
    14021399     * Clears the row selection when it is filtered away by the row sorter.
  • trunk/src/org/openstreetmap/josm/gui/layer/CustomizeColor.java

    r9949 r10824  
    88import java.awt.Component;
    99import java.awt.event.ActionEvent;
    10 import java.util.LinkedList;
     10import java.util.Collections;
    1111import java.util.List;
     12import java.util.Objects;
     13import java.util.stream.Collectors;
    1214
    1315import javax.swing.AbstractAction;
     
    1820
    1921import org.openstreetmap.josm.Main;
     22import org.openstreetmap.josm.data.preferences.AbstractProperty;
     23import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    2024import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
    2125import org.openstreetmap.josm.gui.layer.Layer.MultiLayerAction;
     26import org.openstreetmap.josm.tools.CheckParameterUtil;
    2227import org.openstreetmap.josm.tools.ImageProvider;
    2328
    2429public class CustomizeColor extends AbstractAction implements LayerAction, MultiLayerAction {
    25     private final transient List<Layer> layers;
     30    private final transient List<AbstractProperty<Color>> colors;
    2631
    2732    /**
     
    3136    public CustomizeColor(List<Layer> l) {
    3237        super(tr("Customize Color"), ImageProvider.get("colorchooser"));
     38        colors = l.stream().map(Layer::getColorProperty).collect(Collectors.toList());
     39        CheckParameterUtil.ensureThat(colors.stream().allMatch(Objects::nonNull), "All layers must have colors.");
    3340        putValue("help", ht("/Action/LayerCustomizeColor"));
    34         layers = l;
    3541    }
    3642
     
    4046     */
    4147    public CustomizeColor(Layer l) {
    42         this(new LinkedList<Layer>());
    43         layers.add(l);
     48        this(Collections.singletonList(l));
    4449    }
    4550
    4651    @Override
    4752    public boolean supportLayers(List<Layer> layers) {
    48         for (Layer layer: layers) {
    49             if (layer.getColor(false) == null)
    50                 return false;
    51         }
    52         return true;
     53        return layers.stream().allMatch(l -> l.getColorProperty() != null);
    5354    }
    5455
     
    6566    @Override
    6667    public void actionPerformed(ActionEvent e) {
    67         Color cl = layers.get(0).getColor(false);
    68         if (cl == null)
    69             cl = Color.gray;
     68        Color cl = colors.stream().map(c -> c.get()).filter(Objects::nonNull).findAny().orElse(Color.GRAY);
    7069        JColorChooser c = new JColorChooser(cl);
    7170        Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
     
    8281        switch (answer) {
    8382        case 0:
    84             for (Layer layer : layers) {
    85                 Main.pref.putColor("layer "+layer.getName(), c.getColor());
    86             }
     83            colors.stream().forEach(prop -> prop.put(c.getColor()));
    8784            break;
    8885        case 1:
    8986            return;
    9087        case 2:
    91             for (Layer layer : layers) {
    92                 Main.pref.putColor("layer "+layer.getName(), null);
    93             }
     88            colors.stream().forEach(prop -> prop.put(null));
    9489            break;
    9590        }
    96         Main.map.repaint();
     91        // TODO: Make the layer dialog listen to property change events so that this is not needed any more.
     92        LayerListDialog.getInstance().repaint();
    9793    }
    9894}
  • trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    r10755 r10824  
    55import static org.openstreetmap.josm.tools.I18n.trn;
    66
    7 import java.awt.Color;
    87import java.awt.Dimension;
    98import java.awt.Graphics2D;
     
    3231import org.openstreetmap.josm.data.gpx.WayPoint;
    3332import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     33import org.openstreetmap.josm.data.preferences.ColorProperty;
    3434import org.openstreetmap.josm.data.projection.Projection;
    3535import org.openstreetmap.josm.gui.MapView;
     
    8989        super(d.getString(GpxConstants.META_NAME));
    9090        data = d;
    91         drawHelper = new GpxDrawHelper(data);
     91        drawHelper = new GpxDrawHelper(data, getColorProperty());
    9292        SystemOfMeasurement.addSoMChangeListener(drawHelper);
    9393        ensureTrackVisibilityLength();
     
    9797
    9898    @Override
    99     public Color getColor(boolean ignoreCustom) {
    100         return drawHelper.getColor(getName(), ignoreCustom);
     99    protected ColorProperty getBaseColorProperty() {
     100        return GpxDrawHelper.DEFAULT_COLOR;
    101101    }
    102102
  • trunk/src/org/openstreetmap/josm/gui/layer/Layer.java

    r10809 r10824  
    2626import org.openstreetmap.josm.data.ProjectionBounds;
    2727import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     28import org.openstreetmap.josm.data.preferences.AbstractProperty;
     29import org.openstreetmap.josm.data.preferences.AbstractProperty.ValueChangeListener;
     30import org.openstreetmap.josm.data.preferences.ColorProperty;
    2831import org.openstreetmap.josm.data.projection.Projection;
    2932import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
     
    146149    private File associatedFile;
    147150
     151    private final ValueChangeListener<Object> invalidateListener = change -> invalidate();
     152
    148153    /**
    149154     * Create the layer and fill in the necessary components.
     
    182187     *      color is returned - mainly for layer internal use.
    183188     * @return layer color
    184      */
     189     * @deprecated Use the new {@link #getColorProperty()}. To be removed end of 2016.
     190     */
     191    @Deprecated
    185192    public Color getColor(boolean ignoreCustom) {
    186193        return null;
     194    }
     195
     196    /**
     197     * Gets the color property to use for this layer.
     198     * @return The color property.
     199     * @since 10824
     200     */
     201    public AbstractProperty<Color> getColorProperty() {
     202        ColorProperty base = getBaseColorProperty();
     203        if (base != null) {
     204            // cannot cache this - name may change.
     205            return base.getChildColor("layer " + getName());
     206        } else {
     207            return null;
     208        }
     209    }
     210
     211    /**
     212     * Gets the color property that stores the default color for this layer.
     213     * @return The property or <code>null</code> if this layer is not colored.
     214     * @since 10824
     215     */
     216    protected ColorProperty getBaseColorProperty() {
     217        return null;
     218    }
     219
     220    private void addColorPropertyListener() {
     221        AbstractProperty<Color> colorProperty = getColorProperty();
     222        if (colorProperty != null) {
     223            colorProperty.addWeakListener(invalidateListener);
     224        }
     225    }
     226
     227    private void removeColorPropertyListener() {
     228        AbstractProperty<Color> colorProperty = getColorProperty();
     229        if (colorProperty != null) {
     230            colorProperty.removeListener(invalidateListener);
     231        }
    187232    }
    188233
     
    265310     */
    266311    public final void setName(String name) {
     312        if (this.name != null) {
     313            removeColorPropertyListener();
     314        }
    267315        if (name == null) {
    268316            name = "";
    269317        }
     318
    270319        String oldValue = this.name;
    271320        this.name = name;
     
    273322            propertyChangeSupport.firePropertyChange(NAME_PROP, oldValue, this.name);
    274323        }
     324
     325        // re-add listener
     326        addColorPropertyListener();
     327        invalidate();
    275328    }
    276329
  • trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java

    r10659 r10824  
    2525import org.openstreetmap.josm.data.gpx.GpxData;
    2626import org.openstreetmap.josm.data.gpx.WayPoint;
     27import org.openstreetmap.josm.data.preferences.AbstractProperty;
     28import org.openstreetmap.josm.data.preferences.ColorProperty;
    2729import org.openstreetmap.josm.gui.MapView;
    2830import org.openstreetmap.josm.tools.ColorScale;
     
    3335 */
    3436public class GpxDrawHelper implements SoMChangeListener {
     37
     38    /**
     39     * The color that is used for drawing GPX points.
     40     * @since 10824
     41     */
     42    public static final ColorProperty DEFAULT_COLOR = new ColorProperty(marktr("gps point"), Color.magenta);
     43
    3544    private final GpxData data;
    3645
     
    8493    private int hdopAlpha;
    8594
    86     private static final Color DEFAULT_COLOR = Color.magenta;
    87 
    8895    // lookup array to draw arrows without doing any math
    8996    private static final int ll0 = 9;
     
    134141     * Constructs a new {@code GpxDrawHelper}.
    135142     * @param gpxData GPX data
     143     * @param abstractProperty The color to draw with
     144     * @since 10824
    136145     */
    137     public GpxDrawHelper(GpxData gpxData) {
     146    public GpxDrawHelper(GpxData gpxData, AbstractProperty<Color> abstractProperty) {
    138147        data = gpxData;
    139148        setupColors();
     
    151160     */
    152161    public Color getColor(String layerName, boolean ignoreCustom) {
    153         Color c = Main.pref.getColor(marktr("gps point"), specName(layerName), DEFAULT_COLOR);
    154         return ignoreCustom || getColorMode(layerName) == ColorMode.NONE ? c : null;
     162        if (ignoreCustom || getColorMode(layerName) == ColorMode.NONE) {
     163            return DEFAULT_COLOR.getChildColor(specName(layerName)).get();
     164        } else {
     165            return null;
     166        }
    155167    }
    156168
     
    174186     **/
    175187    public static Color getGenericColor() {
    176         return Main.pref.getColor(marktr("gps point"), DEFAULT_COLOR);
     188        return DEFAULT_COLOR.get();
    177189    }
    178190
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java

    r10647 r10824  
    3838import org.openstreetmap.josm.data.gpx.WayPoint;
    3939import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     40import org.openstreetmap.josm.data.preferences.ColorProperty;
    4041import org.openstreetmap.josm.gui.MapView;
    4142import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
     
    7475
    7576    private static final Color DEFAULT_COLOR = Color.magenta;
     77    private static final ColorProperty COLOR_PROPERTY = new ColorProperty(marktr("gps marker"), DEFAULT_COLOR);
    7678
    7779    /**
     
    195197
    196198    @Override
    197     public Color getColor(boolean ignoreCustom) {
    198         return Main.pref.getColor(marktr("gps marker"), "layer "+getName(), DEFAULT_COLOR);
     199    protected ColorProperty getBaseColorProperty() {
     200        return COLOR_PROPERTY;
    199201    }
    200202
    201203    /* for preferences */
    202204    public static Color getGenericColor() {
    203         return Main.pref.getColor(marktr("gps marker"), DEFAULT_COLOR);
     205        return COLOR_PROPERTY.get();
    204206    }
    205207
     
    207209    public void paint(Graphics2D g, MapView mv, Bounds box) {
    208210        boolean showTextOrIcon = isTextOrIconShown();
    209         g.setColor(getColor(true));
     211        g.setColor(getColorProperty().get());
    210212
    211213        if (mousePressed) {
  • trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java

    r10611 r10824  
    257257     */
    258258    private static void fixColorPrefixes() {
    259         PaintColors.getColors();
     259        PaintColors.values();
    260260        ConflictColors.getColors();
    261261        Severity.getColors();
  • trunk/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java

    r10467 r10824  
    7474        assertEquals("foo", layer.getName());
    7575        assertFalse(layer.isLocalFile());
    76         assertEquals(Color.MAGENTA, layer.getColor(false));
     76        assertEquals(Color.MAGENTA, layer.getColorProperty().get());
    7777        assertEquals("<html>0 tracks, 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer.getToolTipText());
    7878
     
    8080        assertEquals("bar", layer2.getName());
    8181        assertTrue(layer2.isLocalFile());
    82         assertEquals(Color.MAGENTA, layer2.getColor(true));
     82        assertEquals(Color.MAGENTA, layer2.getColorProperty().get());
    8383        assertEquals("<html>0 tracks, 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer2.getToolTipText());
    8484
  • trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java

    r9809 r10824  
    44import static org.junit.Assert.assertEquals;
    55
     6import java.awt.Color;
    67import java.io.FileNotFoundException;
    78import java.io.IOException;
     
    1718import org.openstreetmap.josm.data.gpx.GpxData;
    1819import org.openstreetmap.josm.data.gpx.WayPoint;
     20import org.openstreetmap.josm.data.preferences.ColorProperty;
    1921import org.openstreetmap.josm.io.GpxReaderTest;
    2022import org.openstreetmap.josm.tools.ColorHelper;
     
    125127    static List<String> calculateColors(String fileName, String layerName, int n) throws IOException, SAXException {
    126128        final GpxData data = GpxReaderTest.parseGpxData(fileName);
    127         final GpxDrawHelper gdh = new GpxDrawHelper(data);
     129        final GpxDrawHelper gdh = new GpxDrawHelper(data, new ColorProperty("x", Color.MAGENTA));
    128130        gdh.readPreferences(layerName);
    129131        gdh.calculateColors();
  • trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java

    r10378 r10824  
    4242
    4343        assertEquals("foo", layer.getName());
    44         assertEquals(Color.magenta, layer.getColor(false));
     44        assertEquals(Color.magenta, layer.getColorProperty().get());
    4545        assertNotNull(layer.getIcon());
    4646        assertEquals("0 markers", layer.getToolTipText());
     
    5959
    6060        assertEquals("bar", layer.getName());
    61         assertEquals(Color.magenta, layer.getColor(false));
     61        assertEquals(Color.magenta, layer.getColorProperty().get());
    6262        assertNotNull(layer.getIcon());
    6363        assertEquals("3 markers", layer.getToolTipText());
Note: See TracChangeset for help on using the changeset viewer.