001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint;
003
004import java.awt.event.ActionEvent;
005import java.util.Arrays;
006
007import javax.swing.AbstractAction;
008import javax.swing.Action;
009import javax.swing.JCheckBoxMenuItem;
010import javax.swing.JMenu;
011
012import org.openstreetmap.josm.Main;
013
014/**
015 * Setting to customize a MapPaint style.
016 *
017 * Can be changed by the user in the right click menu of the mappaint style
018 * dialog.
019 *
020 * Defined in the MapCSS style, e.g.
021 * <pre>
022 * setting::highway_casing {
023 *   type: boolean;
024 *   label: tr("Draw highway casing");
025 *   default: true;
026 * }
027 *
028 * way[highway][setting("highway_casing")] {
029 *   casing-width: 2;
030 *   casing-color: white;
031 * }
032 * </pre>
033 */
034public interface StyleSetting {
035
036    void addMenuEntry(JMenu menu);
037
038    Object getValue();
039
040    /**
041     * A style setting for boolean value (yes / no).
042     */
043    class BooleanStyleSetting implements StyleSetting {
044        public final StyleSource parentStyle;
045        public final String prefKey;
046        public final String label;
047        public final boolean def;
048
049        public BooleanStyleSetting(StyleSource parentStyle, String prefKey, String label, boolean def) {
050            this.parentStyle = parentStyle;
051            this.prefKey = prefKey;
052            this.label = label;
053            this.def = def;
054        }
055
056        @Override
057        public void addMenuEntry(JMenu menu) {
058            final JCheckBoxMenuItem item = new JCheckBoxMenuItem();
059            Action a = new AbstractAction(label) {
060                @Override
061                public void actionPerformed(ActionEvent e) {
062                    setValue(item.isSelected());
063                    Main.worker.submit(new MapPaintStyles.MapPaintStyleLoader(Arrays.asList(parentStyle)));
064                }
065            };
066            item.setAction(a);
067            item.setSelected((boolean) getValue());
068            menu.add(item);
069        }
070
071        public static BooleanStyleSetting create(Cascade c, StyleSource parentStyle, String key) {
072            String label = c.get("label", null, String.class);
073            if (label == null) {
074                Main.warn("property 'label' required for boolean style setting");
075                return null;
076            }
077            Boolean def = c.get("default", null, Boolean.class);
078            if (def == null) {
079                Main.warn("property 'default' required for boolean style setting");
080                return null;
081            }
082            String prefKey = parentStyle.url + ":boolean:" + key;
083            return new BooleanStyleSetting(parentStyle, prefKey, label, def);
084        }
085
086        @Override
087        public Object getValue() {
088            String val = Main.pref.get(prefKey, null);
089            if (val == null) return def;
090            return Boolean.valueOf(val);
091        }
092
093        public void setValue(Object o) {
094            if (!(o instanceof Boolean)) {
095                throw new IllegalArgumentException();
096            }
097            boolean b = (Boolean) o;
098            if (b == def) {
099                Main.pref.put(prefKey, null);
100            } else {
101                Main.pref.put(prefKey, b);
102            }
103        }
104    }
105}