source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/StyleElement.java@ 12378

Last change on this file since 12378 was 12303, checked in by michael2402, 7 years ago

Javadoc for package org.openstreetmap.josm.gui.mappaint.styleelement

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.styleelement;
3
4import java.awt.Font;
5import java.util.HashMap;
6import java.util.Map;
7import java.util.Objects;
8
9import org.openstreetmap.josm.Main;
10import org.openstreetmap.josm.data.osm.OsmPrimitive;
11import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
12import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
13import org.openstreetmap.josm.gui.mappaint.Cascade;
14import org.openstreetmap.josm.gui.mappaint.Keyword;
15import org.openstreetmap.josm.gui.mappaint.StyleKeys;
16import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction.RelativeFloat;
17
18/**
19 * Class that defines how objects ({@link OsmPrimitive}) should be drawn on the map.
20 *
21 * Several subclasses of this abstract class implement different drawing features,
22 * like icons for a node or area fill. This class and all its subclasses are immutable
23 * and tend to get shared when multiple objects have the same style (in order to
24 * save memory, see {@link org.openstreetmap.josm.gui.mappaint.StyleCache#intern()}).
25 */
26public abstract class StyleElement implements StyleKeys {
27
28 protected static final int ICON_IMAGE_IDX = 0;
29 protected static final int ICON_WIDTH_IDX = 1;
30 protected static final int ICON_HEIGHT_IDX = 2;
31 protected static final int ICON_OPACITY_IDX = 3;
32 protected static final int ICON_OFFSET_X_IDX = 4;
33 protected static final int ICON_OFFSET_Y_IDX = 5;
34
35 /**
36 * The major z index of this style element
37 */
38 public float majorZIndex;
39 /**
40 * The z index as set by the user
41 */
42 public float zIndex;
43 /**
44 * The object z index
45 */
46 public float objectZIndex;
47 /**
48 * false, if style can serve as main style for the primitive;
49 * true, if it is a highlight or modifier
50 */
51 public boolean isModifier;
52 /**
53 * A flag indicating that the selection color handling should be done automatically
54 */
55 public boolean defaultSelectedHandling;
56
57 /**
58 * Construct a new StyleElement
59 * @param majorZindex like z-index, but higher priority
60 * @param zIndex order the objects are drawn
61 * @param objectZindex like z-index, but lower priority
62 * @param isModifier if false, a default line or node symbol is generated
63 * @param defaultSelectedHandling true if default behavior for selected objects
64 * is enabled, false if a style for selected state is given explicitly
65 */
66 public StyleElement(float majorZindex, float zIndex, float objectZindex, boolean isModifier, boolean defaultSelectedHandling) {
67 this.majorZIndex = majorZindex;
68 this.zIndex = zIndex;
69 this.objectZIndex = objectZindex;
70 this.isModifier = isModifier;
71 this.defaultSelectedHandling = defaultSelectedHandling;
72 }
73
74 protected StyleElement(Cascade c, float defaultMajorZindex) {
75 majorZIndex = c.get(MAJOR_Z_INDEX, defaultMajorZindex, Float.class);
76 zIndex = c.get(Z_INDEX, 0f, Float.class);
77 objectZIndex = c.get(OBJECT_Z_INDEX, 0f, Float.class);
78 isModifier = c.get(MODIFIER, Boolean.FALSE, Boolean.class);
79 defaultSelectedHandling = c.isDefaultSelectedHandling();
80 }
81
82 /**
83 * draws a primitive
84 * @param primitive primitive to draw
85 * @param paintSettings paint settings
86 * @param painter painter
87 * @param selected true, if primitive is selected
88 * @param outermember true, if primitive is not selected and outer member of a selected multipolygon relation
89 * @param member true, if primitive is not selected and member of a selected relation
90 */
91 public abstract void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter,
92 boolean selected, boolean outermember, boolean member);
93
94 /**
95 * Check if this is a style that makes the line visible to the user
96 * @return <code>true</code> for line styles
97 */
98 public boolean isProperLineStyle() {
99 return false;
100 }
101
102 /**
103 * Get a property value of type Width
104 * @param c the cascade
105 * @param key property key for the width value
106 * @param relativeTo reference width. Only needed, when relative width syntax is used, e.g. "+4".
107 * @return width
108 */
109 protected static Float getWidth(Cascade c, String key, Float relativeTo) {
110 Float width = c.get(key, null, Float.class, true);
111 if (width != null) {
112 if (width > 0)
113 return width;
114 } else {
115 Keyword widthKW = c.get(key, null, Keyword.class, true);
116 if (Keyword.THINNEST.equals(widthKW))
117 return 0f;
118 if (Keyword.DEFAULT.equals(widthKW))
119 return (float) MapPaintSettings.INSTANCE.getDefaultSegmentWidth();
120 if (relativeTo != null) {
121 RelativeFloat widthRel = c.get(key, null, RelativeFloat.class, true);
122 if (widthRel != null)
123 return relativeTo + widthRel.val;
124 }
125 }
126 return null;
127 }
128
129 /* ------------------------------------------------------------------------------- */
130 /* cached values */
131 /* ------------------------------------------------------------------------------- */
132 /*
133 * Two preference values and the set of created fonts are cached in order to avoid
134 * expensive lookups and to avoid too many font objects
135 *
136 * FIXME: cached preference values are not updated if the user changes them during
137 * a JOSM session. Should have a listener listening to preference changes.
138 */
139 private static volatile String DEFAULT_FONT_NAME;
140 private static volatile Float DEFAULT_FONT_SIZE;
141 private static final Object lock = new Object();
142
143 // thread save access (double-checked locking)
144 private static Float getDefaultFontSize() {
145 Float s = DEFAULT_FONT_SIZE;
146 if (s == null) {
147 synchronized (lock) {
148 s = DEFAULT_FONT_SIZE;
149 if (s == null) {
150 DEFAULT_FONT_SIZE = s = (float) Main.pref.getInteger("mappaint.fontsize", 8);
151 }
152 }
153 }
154 return s;
155 }
156
157 private static String getDefaultFontName() {
158 String n = DEFAULT_FONT_NAME;
159 if (n == null) {
160 synchronized (lock) {
161 n = DEFAULT_FONT_NAME;
162 if (n == null) {
163 DEFAULT_FONT_NAME = n = Main.pref.get("mappaint.font", "Droid Sans");
164 }
165 }
166 }
167 return n;
168 }
169
170 private static class FontDescriptor {
171 public String name;
172 public int style;
173 public int size;
174
175 FontDescriptor(String name, int style, int size) {
176 this.name = name;
177 this.style = style;
178 this.size = size;
179 }
180
181 @Override
182 public int hashCode() {
183 return Objects.hash(name, style, size);
184 }
185
186 @Override
187 public boolean equals(Object obj) {
188 if (this == obj) return true;
189 if (obj == null || getClass() != obj.getClass()) return false;
190 FontDescriptor that = (FontDescriptor) obj;
191 return style == that.style &&
192 size == that.size &&
193 Objects.equals(name, that.name);
194 }
195 }
196
197 private static final Map<FontDescriptor, Font> FONT_MAP = new HashMap<>();
198
199 private static Font getCachedFont(FontDescriptor fd) {
200 Font f = FONT_MAP.get(fd);
201 if (f != null) return f;
202 f = new Font(fd.name, fd.style, fd.size);
203 FONT_MAP.put(fd, f);
204 return f;
205 }
206
207 private static Font getCachedFont(String name, int style, int size) {
208 return getCachedFont(new FontDescriptor(name, style, size));
209 }
210
211 protected static Font getFont(Cascade c, String s) {
212 String name = c.get(FONT_FAMILY, getDefaultFontName(), String.class);
213 float size = c.get(FONT_SIZE, getDefaultFontSize(), Float.class);
214 int weight = Font.PLAIN;
215 if ("bold".equalsIgnoreCase(c.get(FONT_WEIGHT, null, String.class))) {
216 weight = Font.BOLD;
217 }
218 int style = Font.PLAIN;
219 if ("italic".equalsIgnoreCase(c.get(FONT_STYLE, null, String.class))) {
220 style = Font.ITALIC;
221 }
222 Font f = getCachedFont(name, style | weight, Math.round(size));
223 if (f.canDisplayUpTo(s) == -1)
224 return f;
225 else {
226 // fallback if the string contains characters that cannot be
227 // rendered by the selected font
228 return getCachedFont("SansSerif", style | weight, Math.round(size));
229 }
230 }
231
232 @Override
233 public boolean equals(Object o) {
234 if (this == o) return true;
235 if (o == null || getClass() != o.getClass()) return false;
236 StyleElement that = (StyleElement) o;
237 return isModifier == that.isModifier &&
238 Float.compare(that.majorZIndex, majorZIndex) == 0 &&
239 Float.compare(that.zIndex, zIndex) == 0 &&
240 Float.compare(that.objectZIndex, objectZIndex) == 0;
241 }
242
243 @Override
244 public int hashCode() {
245 return Objects.hash(majorZIndex, zIndex, objectZIndex, isModifier);
246 }
247
248 @Override
249 public String toString() {
250 return String.format("z_idx=[%s/%s/%s] ", majorZIndex, zIndex, objectZIndex) + (isModifier ? "modifier " : "");
251 }
252}
Note: See TracBrowser for help on using the repository browser.