001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint; 003 004import java.util.Objects; 005import java.util.Optional; 006 007import javax.swing.Icon; 008 009import org.openstreetmap.josm.spi.preferences.Config; 010import org.openstreetmap.josm.tools.ImageProvider; 011import org.openstreetmap.josm.tools.ImageProvider.ImageSizes; 012import org.openstreetmap.josm.tools.Logging; 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 /** 037 * gets the value for this setting 038 * @return The value the user selected 039 */ 040 Object getValue(); 041 042 /** 043 * Superclass of style settings and groups. 044 * @since 15289 045 */ 046 abstract class LabeledStyleSetting implements Comparable<LabeledStyleSetting> { 047 public final StyleSource parentStyle; 048 public final String label; 049 050 LabeledStyleSetting(StyleSource parentStyle, String label) { 051 this.parentStyle = Objects.requireNonNull(parentStyle); 052 this.label = Objects.requireNonNull(label); 053 } 054 055 @Override 056 public int hashCode() { 057 return Objects.hash(label, parentStyle); 058 } 059 060 @Override 061 public boolean equals(Object obj) { 062 if (this == obj) 063 return true; 064 if (obj == null || getClass() != obj.getClass()) 065 return false; 066 LabeledStyleSetting other = (LabeledStyleSetting) obj; 067 return Objects.equals(label, other.label) && Objects.equals(parentStyle, other.parentStyle); 068 } 069 070 @Override 071 public int compareTo(LabeledStyleSetting o) { 072 return label.compareTo(o.label); 073 } 074 } 075 076 /** 077 * A style setting group. 078 * @since 15289 079 */ 080 class StyleSettingGroup extends LabeledStyleSetting { 081 /** group identifier */ 082 public final String key; 083 /** group icon (optional) */ 084 public final Icon icon; 085 086 public StyleSettingGroup(StyleSource parentStyle, String label, String key, Icon icon) { 087 super(parentStyle, label); 088 this.key = Objects.requireNonNull(key); 089 this.icon = icon; 090 } 091 092 /** 093 * Creates a new {@code StyleSettingGroup}. 094 * @param c cascade 095 * @param parentStyle parent style source 096 * @param key group identifier 097 * @return newly created {@code StyleSettingGroup} 098 */ 099 public static StyleSettingGroup create(Cascade c, StyleSource parentStyle, String key) { 100 String label = c.get("label", null, String.class); 101 if (label == null) { 102 Logging.warn("property 'label' required for boolean style setting"); 103 return null; 104 } 105 Icon icon = Optional.ofNullable(c.get("icon", null, String.class)) 106 .map(s -> ImageProvider.get(s, ImageSizes.MENU)).orElse(null); 107 return new StyleSettingGroup(parentStyle, label, key, icon); 108 } 109 } 110 111 /** 112 * A style setting for boolean value (yes / no). 113 */ 114 class BooleanStyleSetting extends LabeledStyleSetting implements StyleSetting { 115 public final String prefKey; 116 public final boolean def; 117 118 public BooleanStyleSetting(StyleSource parentStyle, String prefKey, String label, boolean def) { 119 super(parentStyle, label); 120 this.prefKey = Objects.requireNonNull(prefKey); 121 this.def = def; 122 } 123 124 /** 125 * Creates a new {@code BooleanStyleSetting}. 126 * @param c cascade 127 * @param parentStyle parent style source 128 * @param key setting identifier 129 * @return newly created {@code BooleanStyleSetting} 130 */ 131 public static BooleanStyleSetting create(Cascade c, StyleSource parentStyle, String key) { 132 String label = c.get("label", null, String.class); 133 if (label == null) { 134 Logging.warn("property 'label' required for boolean style setting"); 135 return null; 136 } 137 Boolean def = c.get("default", null, Boolean.class); 138 if (def == null) { 139 Logging.warn("property 'default' required for boolean style setting"); 140 return null; 141 } 142 String prefKey = parentStyle.url + ":boolean:" + key; 143 return new BooleanStyleSetting(parentStyle, prefKey, label, def); 144 } 145 146 @Override 147 public Object getValue() { 148 String val = Config.getPref().get(prefKey, null); 149 if (val == null) return def; 150 return Boolean.valueOf(val); 151 } 152 153 public void setValue(Object o) { 154 if (!(o instanceof Boolean)) { 155 throw new IllegalArgumentException(); 156 } 157 boolean b = (Boolean) o; 158 if (b == def) { 159 Config.getPref().put(prefKey, null); 160 } else { 161 Config.getPref().putBoolean(prefKey, b); 162 } 163 } 164 } 165}