001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.preferences;
003
004import java.awt.Color;
005import java.util.Arrays;
006import java.util.List;
007
008import javax.swing.UIManager;
009
010import org.openstreetmap.josm.tools.CheckParameterUtil;
011import org.openstreetmap.josm.tools.ColorHelper;
012import org.openstreetmap.josm.tools.Utils;
013
014/**
015 * A property containing a {@link Color} value with additional information associated to it.
016 *
017 * The additional information is used to describe the color in the
018 * {@link org.openstreetmap.josm.gui.preferences.display.ColorPreference}, so it can be recognized
019 * and customized by the user.
020 * @since 12987
021 */
022public class NamedColorProperty extends AbstractToStringProperty<Color> {
023
024    public static final String NAMED_COLOR_PREFIX = "clr.";
025
026    public static final String COLOR_CATEGORY_GENERAL = "general";
027    public static final String COLOR_CATEGORY_MAPPAINT = "mappaint";
028
029    private final String category;
030    private final String source;
031    private final String name;
032
033    /**
034     * Construct a new {@code NamedColorProperty}.
035     *
036     * The priority for getting the color is: 1. a set property, 2. {@link UIManager#getColor}, 3. the given {@code defaultValue}
037     * @param category a category, can be any identifier, but the following values are recognized by
038     * the GUI preferences: {@link #COLOR_CATEGORY_GENERAL} and {@link #COLOR_CATEGORY_MAPPAINT}
039     * @param source a filename or similar associated with the color, can be null if not applicable
040     * @param name a short description of the color
041     * @param defaultValue the default value, can be null
042     */
043    public NamedColorProperty(String category, String source, String name, Color defaultValue) {
044        super(getKey(category, source, name), getUIColor("JOSM." + getKey(category, source, name), defaultValue));
045        CheckParameterUtil.ensureParameterNotNull(category, "category");
046        CheckParameterUtil.ensureParameterNotNull(name, "name");
047        this.category = category;
048        this.source = source;
049        this.name = name;
050    }
051
052    /**
053     * Construct a new {@code NamedColorProperty}.
054     * @param name a short description of the color
055     * @param defaultValue the default value, can be null
056     */
057    public NamedColorProperty(String name, Color defaultValue) {
058        this(COLOR_CATEGORY_GENERAL, null, name, defaultValue);
059    }
060
061    private static String getKey(String category, String source, String name) {
062        CheckParameterUtil.ensureParameterNotNull(category, "category");
063        CheckParameterUtil.ensureParameterNotNull(name, "name");
064        return NAMED_COLOR_PREFIX + category + "." + (source == null ? "" : source + ".") + name;
065    }
066
067    private static Color getUIColor(String uiKey, Color defaultValue) {
068        Color color = UIManager.getColor(uiKey);
069        return color != null ? color : defaultValue;
070    }
071
072    private List<String> getDefaultValuePref() {
073        return defaultValue == null ? null : getValuePref(defaultValue, category, source, name);
074    }
075
076    @Override
077    protected void storeDefaultValue() {
078        // This is required due to the super() initializer calling this method.
079        if (category != null) {
080            super.storeDefaultValue();
081        }
082    }
083
084    @Override
085    public Color get() {
086        List<String> data = getPreferences().getList(getKey(), getDefaultValuePref()); // store default value
087        if (super.isSet() && !Utils.isEmpty(data)) {
088            return ColorHelper.html2color(data.get(0));
089        }
090        return defaultValue;
091    }
092
093    @Override
094    public boolean isSet() {
095        get(); // trigger migration
096        return super.isSet();
097    }
098
099    /**
100     * Get the category for this color.
101     * @return the category
102     */
103    public String getCategory() {
104        return category;
105    }
106
107    /**
108     * Get the source, i.e.&nbsp;a filename or layer name associated with the color.
109     * May return null if not applicable.
110     * @return the source
111     */
112    public String getSource() {
113        return source;
114    }
115
116    /**
117     * Get the color name (a short description of the color).
118     * @return the color name
119     */
120    public String getName() {
121        return name;
122    }
123
124    private static List<String> getValuePref(Color color, String category, String source, String name) {
125        CheckParameterUtil.ensureParameterNotNull(color, "color");
126        CheckParameterUtil.ensureParameterNotNull(category, "category");
127        CheckParameterUtil.ensureParameterNotNull(name, "name");
128        return Arrays.asList(ColorHelper.color2html(color, true), category, source == null ? "" : source, name);
129    }
130
131    @Override
132    public boolean put(Color value) {
133        return getPreferences().putList(getKey(), value == null ? null : getValuePref(value, category, source, name));
134    }
135
136    /**
137     * Return a more specialized color, that will fall back to this color, if not set explicitly.
138     * @param category the category of the specialized color
139     * @param source the source of the specialized color
140     * @param name the name of the specialized color
141     * @return a {@link FallbackProperty} that will the return the specialized color, if set, but
142     * fall back to this property as default value
143     */
144    public FallbackProperty<Color> getChildColor(String category, String source, String name) {
145        return new FallbackProperty<>(new NamedColorProperty(category, source, name, defaultValue), this);
146    }
147
148    /**
149     * Return a more specialized color, that will fall back to this color, if not set explicitly.
150     * @param name the name of the specialized color
151     * @return a {@link FallbackProperty} that will the return the specialized color, if set, but
152     * fall back to this property as default value
153     */
154    public FallbackProperty<Color> getChildColor(String name) {
155        return getChildColor(category, source, name);
156    }
157
158    @Override
159    protected Color fromString(String string) {
160        return ColorHelper.html2color(string);
161    }
162
163    @Override
164    protected String toString(Color color) {
165        return ColorHelper.color2html(color);
166    }
167}