source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/Cascade.java@ 7246

Last change on this file since 7246 was 7246, checked in by bastiK, 10 years ago

fixed #10142 - Regression: MapCSS changes did break lane attribute style

  • Property svn:eol-style set to native
File size: 6.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.awt.Color;
5import java.util.Arrays;
6import java.util.HashMap;
7import java.util.List;
8import java.util.Map;
9import java.util.regex.Pattern;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.gui.mappaint.mapcss.CSSColors;
13import org.openstreetmap.josm.tools.ColorHelper;
14import org.openstreetmap.josm.tools.Utils;
15
16/**
17 * Simple map of properties with dynamic typing.
18 */
19public final class Cascade implements Cloneable {
20
21 public static final Cascade EMPTY_CASCADE = new Cascade();
22
23 protected Map<String, Object> prop = new HashMap<>();
24
25 private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})");
26
27 public <T> T get(String key, T def, Class<T> klass) {
28 return get(key, def, klass, false);
29 }
30
31 /**
32 * Get value for the given key
33 * @param <T> the expected type
34 * @param key the key
35 * @param def default value, can be null
36 * @param klass the same as T
37 * @param suppressWarnings show or don't show a warning when some value is
38 * found, but cannot be converted to the requested type
39 * @return if a value with class klass has been mapped to key, returns this
40 * value, def otherwise
41 */
42 public <T> T get(String key, T def, Class<T> klass, boolean suppressWarnings) {
43 if (def != null && !klass.isInstance(def))
44 throw new IllegalArgumentException();
45 Object o = prop.get(key);
46 if (o == null)
47 return def;
48 T res = convertTo(o, klass);
49 if (res == null) {
50 if (!suppressWarnings) {
51 Main.warn(String.format("Unable to convert property %s to type %s: found %s of type %s!", key, klass, o, o.getClass()));
52 }
53 return def;
54 } else
55 return res;
56 }
57
58 public Object get(String key) {
59 return prop.get(key);
60 }
61
62 public void put(String key, Object val) {
63 prop.put(key, val);
64 }
65
66 public void putOrClear(String key, Object val) {
67 if (val != null) {
68 prop.put(key, val);
69 } else {
70 prop.remove(key);
71 }
72 }
73
74 public void remove(String key) {
75 prop.remove(key);
76 }
77
78 @SuppressWarnings("unchecked")
79 public static <T> T convertTo(Object o, Class<T> klass) {
80 if (o == null)
81 return null;
82 if (klass.isInstance(o))
83 return (T) o;
84
85 if (klass == float.class || klass == Float.class)
86 return (T) toFloat(o);
87
88 if (klass == double.class || klass == Double.class) {
89 o = toFloat(o);
90 if (o != null) {
91 o = new Double((Float) o);
92 }
93 return (T) o;
94 }
95
96 if (klass == boolean.class || klass == Boolean.class)
97 return (T) toBool(o);
98
99 if (klass == float[].class)
100 return (T) toFloatArray(o);
101
102 if (klass == Color.class)
103 return (T) toColor(o);
104
105 if (klass == String.class) {
106 if (o instanceof Keyword)
107 return (T) ((Keyword) o).val;
108 if (o instanceof Color) {
109 Color c = (Color) o;
110 int alpha = c.getAlpha();
111 if (alpha != 255)
112 return (T) String.format("#%06x%02x", ((Color) o).getRGB() & 0x00ffffff, alpha);
113 return (T) String.format("#%06x", ((Color) o).getRGB() & 0x00ffffff);
114
115 }
116
117 return (T) o.toString();
118 }
119
120 return null;
121 }
122
123 private static Float toFloat(Object o) {
124 if (o instanceof Number)
125 return ((Number) o).floatValue();
126 if (o instanceof String && !((String) o).isEmpty()) {
127 try {
128 return Float.parseFloat((String) o);
129 } catch (NumberFormatException e) {
130 Main.debug("'"+o+"' cannot be converted to float");
131 }
132 }
133 return null;
134 }
135
136 private static Boolean toBool(Object o) {
137 if (o instanceof Boolean)
138 return (Boolean) o;
139 String s = null;
140 if (o instanceof Keyword) {
141 s = ((Keyword) o).val;
142 } else if (o instanceof String) {
143 s = (String) o;
144 }
145 if (s != null)
146 return !(s.isEmpty() || "false".equals(s) || "no".equals(s) || "0".equals(s) || "0.0".equals(s));
147 if (o instanceof Number)
148 return ((Number) o).floatValue() != 0.0f;
149 if (o instanceof List)
150 return !((List) o).isEmpty();
151 if (o instanceof float[])
152 return ((float[]) o).length != 0;
153
154 return null;
155 }
156
157 private static float[] toFloatArray(Object o) {
158 if (o instanceof float[])
159 return (float[]) o;
160 if (o instanceof List) {
161 List<?> l = (List<?>) o;
162 float[] a = new float[l.size()];
163 for (int i=0; i<l.size(); ++i) {
164 Float f = toFloat(l.get(i));
165 if (f == null)
166 return null;
167 else
168 a[i] = f;
169 }
170 return a;
171 }
172 Float f = toFloat(o);
173 if (f != null)
174 return new float[] { f };
175 return null;
176 }
177
178 private static Color toColor(Object o) {
179 if (o instanceof Color)
180 return (Color) o;
181 if (o instanceof Keyword)
182 return CSSColors.get(((Keyword) o).val);
183 if (o instanceof String) {
184 Color c = CSSColors.get((String) o);
185 if (c != null)
186 return c;
187 if (HEX_COLOR_PATTERN.matcher((String) o).matches()) {
188 return ColorHelper.html2color((String) o);
189 }
190 }
191 return null;
192 }
193
194 @Override
195 public Cascade clone() {
196 @SuppressWarnings("unchecked")
197 HashMap<String, Object> clonedProp = (HashMap<String, Object>) ((HashMap) this.prop).clone();
198 Cascade c = new Cascade();
199 c.prop = clonedProp;
200 return c;
201 }
202
203 @Override
204 public String toString() {
205 StringBuilder res = new StringBuilder("Cascade{ ");
206 for (String key : prop.keySet()) {
207 res.append(key+":");
208 Object val = prop.get(key);
209 if (val instanceof float[]) {
210 res.append(Arrays.toString((float[]) val));
211 } else if (val instanceof Color) {
212 res.append(Utils.toString((Color)val));
213 } else if (val != null) {
214 res.append(val.toString());
215 }
216 res.append("; ");
217 }
218 return res.append("}").toString();
219 }
220
221 public boolean containsKey(String key) {
222 return prop.containsKey(key);
223 }
224}
Note: See TracBrowser for help on using the repository browser.