001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint;
003
004import java.util.function.BiFunction;
005
006import org.openstreetmap.josm.data.preferences.BooleanProperty;
007import org.openstreetmap.josm.data.preferences.DoubleProperty;
008import org.openstreetmap.josm.data.preferences.StringProperty;
009import org.openstreetmap.josm.tools.Logging;
010
011/**
012 * Factory to create matching {@link StyleSetting} instances.
013 * @since 15731
014 */
015public final class StyleSettingFactory {
016
017    private StyleSettingFactory() {
018        // private constructor for factory classes
019    }
020
021    /**
022     * Creates a new {@code StyleSetting} based on the specified type by {@code c}.
023     * The type must be supported by {@link Cascade#convertTo} as well as {@link org.openstreetmap.josm.data.preferences.AbstractProperty}.
024     * @param c cascade
025     * @param parentStyle parent style source
026     * @param key setting identifier
027     * @return newly created {@code StyleSetting}
028     */
029    public static StyleSetting create(Cascade c, StyleSource parentStyle, String key) {
030        final String type = c.get("type", null, String.class);
031        final String qualifiedKey = String.join(":", parentStyle.url, type, key);
032        switch (type) {
033            case "boolean":
034                return forLabelAndDefault(c, Boolean.class, (label, defaultValue) -> {
035                    final BooleanProperty property = new BooleanProperty(qualifiedKey, defaultValue);
036                    return new StyleSetting.BooleanStyleSetting(parentStyle, label, property);
037                });
038            case "double":
039                return forLabelAndDefault(c, Double.class, (label, defaultValue) -> {
040                    final DoubleProperty property = new DoubleProperty(qualifiedKey, defaultValue);
041                    return new StyleSetting.PropertyStyleSetting<>(parentStyle, label, Double.class, property);
042                });
043            case "string":
044                return forLabelAndDefault(c, String.class, (label, defaultValue) -> {
045                    final StringProperty property = new StringProperty(qualifiedKey, defaultValue);
046                    return new StyleSetting.PropertyStyleSetting<>(parentStyle, label, String.class, property);
047                });
048            default:
049                Logging.warn("Unknown setting type {0} for style {1}", type, parentStyle.url);
050                return null;
051        }
052    }
053
054    private static <T> StyleSetting forLabelAndDefault(Cascade c, final Class<T> type, BiFunction<String, T, StyleSetting> function) {
055        String label = c.get("label", null, String.class);
056        if (label == null) {
057            Logging.warn("property 'label' required for style setting of type " + type);
058            return null;
059        }
060        T defaultValue = c.get("default", null, type);
061        if (defaultValue == null) {
062            Logging.warn("property 'default' required for style setting of type " + type);
063            return null;
064        }
065        return function.apply(label, defaultValue);
066    }
067}