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.data.preferences.AbstractToStringProperty; 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 * Create a matching {@link StyleSettingGui} instances for a given {@link StyleSetting} object. 044 * @return matching {@code StyleSettingGui} 045 * @throws UnsupportedOperationException when class of {@link StyleSetting} is not supported 046 */ 047 default StyleSettingGui getStyleSettingGui() { 048 throw new UnsupportedOperationException(getClass() + " not supported"); 049 } 050 051 /** 052 * Superclass of style settings and groups. 053 * @since 15289 054 */ 055 abstract class LabeledStyleSetting implements Comparable<LabeledStyleSetting> { 056 public final StyleSource parentStyle; 057 public final String label; 058 059 LabeledStyleSetting(StyleSource parentStyle, String label) { 060 this.parentStyle = Objects.requireNonNull(parentStyle); 061 this.label = Objects.requireNonNull(label); 062 } 063 064 @Override 065 public int hashCode() { 066 return Objects.hash(label, parentStyle); 067 } 068 069 @Override 070 public boolean equals(Object obj) { 071 if (this == obj) 072 return true; 073 if (obj == null || getClass() != obj.getClass()) 074 return false; 075 LabeledStyleSetting other = (LabeledStyleSetting) obj; 076 return Objects.equals(label, other.label) && Objects.equals(parentStyle, other.parentStyle); 077 } 078 079 @Override 080 public int compareTo(LabeledStyleSetting o) { 081 return label.compareTo(o.label); 082 } 083 } 084 085 /** 086 * A style setting group. 087 * @since 15289 088 */ 089 class StyleSettingGroup extends LabeledStyleSetting { 090 /** group identifier */ 091 public final String key; 092 /** group icon (optional) */ 093 public final Icon icon; 094 095 StyleSettingGroup(StyleSource parentStyle, String label, String key, Icon icon) { 096 super(parentStyle, label); 097 this.key = Objects.requireNonNull(key); 098 this.icon = icon; 099 } 100 101 /** 102 * Creates a new {@code StyleSettingGroup}. 103 * @param c cascade 104 * @param parentStyle parent style source 105 * @param key group identifier 106 * @return newly created {@code StyleSettingGroup} 107 */ 108 public static StyleSettingGroup create(Cascade c, StyleSource parentStyle, String key) { 109 String label = c.get("label", null, String.class); 110 if (label == null) { 111 Logging.warn("property 'label' required for StyleSettingGroup"); 112 return null; 113 } 114 Icon icon = Optional.ofNullable(c.get("icon", null, String.class)) 115 .map(s -> ImageProvider.get(s, ImageSizes.MENU)).orElse(null); 116 return new StyleSettingGroup(parentStyle, label, key, icon); 117 } 118 } 119 120 class PropertyStyleSetting<T> extends LabeledStyleSetting implements StyleSetting { 121 private final Class<T> type; 122 private final AbstractToStringProperty<T> property; 123 124 PropertyStyleSetting(StyleSource parentStyle, String label, Class<T> type, AbstractToStringProperty<T> property) { 125 super(parentStyle, label); 126 this.type = type; 127 this.property = property; 128 } 129 130 /** 131 * Replies the property key. 132 * @return The property key 133 */ 134 public String getKey() { 135 return property.getKey(); 136 } 137 138 @Override 139 public T getValue() { 140 return property.get(); 141 } 142 143 /** 144 * Sets this property to the specified value. 145 * @param value The new value of this property 146 */ 147 public void setValue(T value) { 148 property.put(value); 149 } 150 151 /** 152 * Sets this property to the specified string value. 153 * @param value The new string value of this property 154 */ 155 public void setStringValue(String value) { 156 setValue(Cascade.convertTo(value, type)); 157 } 158 159 @Override 160 public StyleSettingGui getStyleSettingGui() { 161 return new PropertyStyleSettingGui<>(this); 162 } 163 } 164 165 /** 166 * A style setting for boolean value (yes / no). 167 */ 168 class BooleanStyleSetting extends PropertyStyleSetting<Boolean> { 169 BooleanStyleSetting(StyleSource parentStyle, String label, AbstractToStringProperty<Boolean> property) { 170 super(parentStyle, label, Boolean.class, property); 171 } 172 173 @Override 174 public StyleSettingGui getStyleSettingGui() { 175 return new BooleanStyleSettingGui(this); 176 } 177 } 178}