source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/BoxTextElemStyle.java@ 8256

Last change on this file since 8256 was 8126, checked in by Don-vip, 9 years ago

fix Sonar issue squid:S2444 - Lazy initialization of "static" fields should be "synchronized"

  • Property svn:eol-style set to native
File size: 8.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.awt.Color;
5import java.awt.Rectangle;
6
7import org.openstreetmap.josm.data.osm.Node;
8import org.openstreetmap.josm.data.osm.OsmPrimitive;
9import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
10import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
11import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
12import org.openstreetmap.josm.tools.CheckParameterUtil;
13
14/**
15 * Text style attached to a style with a bounding box, like an icon or a symbol.
16 */
17public class BoxTextElemStyle extends ElemStyle {
18
19 public enum HorizontalTextAlignment { LEFT, CENTER, RIGHT }
20 public enum VerticalTextAlignment { ABOVE, TOP, CENTER, BOTTOM, BELOW }
21
22 public static interface BoxProvider {
23 BoxProviderResult get();
24 }
25
26 public static class BoxProviderResult {
27 private Rectangle box;
28 private boolean temporary;
29
30 public BoxProviderResult(Rectangle box, boolean temporary) {
31 this.box = box;
32 this.temporary = temporary;
33 }
34
35 /**
36 * The box
37 */
38 public Rectangle getBox() {
39 return box;
40 }
41
42 /**
43 * True, if the box can change in future calls of the BoxProvider get() method
44 */
45 public boolean isTemporary() {
46 return temporary;
47 }
48 }
49
50 public static class SimpleBoxProvider implements BoxProvider {
51 private Rectangle box;
52
53 public SimpleBoxProvider(Rectangle box) {
54 this.box = box;
55 }
56
57 @Override
58 public BoxProviderResult get() {
59 return new BoxProviderResult(box, false);
60 }
61
62 @Override
63 public int hashCode() {
64 return box.hashCode();
65 }
66
67 @Override
68 public boolean equals(Object obj) {
69 if (!(obj instanceof BoxProvider))
70 return false;
71 final BoxProvider other = (BoxProvider) obj;
72 BoxProviderResult resultOther = other.get();
73 if (resultOther.isTemporary()) return false;
74 return box.equals(resultOther.getBox());
75 }
76 }
77
78 public static final Rectangle ZERO_BOX = new Rectangle(0, 0, 0, 0);
79
80 public TextElement text;
81 // Either boxProvider or box is not null. If boxProvider is different from
82 // null, this means, that the box can still change in future, otherwise
83 // it is fixed.
84 protected BoxProvider boxProvider;
85 protected Rectangle box;
86 public HorizontalTextAlignment hAlign;
87 public VerticalTextAlignment vAlign;
88
89 public BoxTextElemStyle(Cascade c, TextElement text, BoxProvider boxProvider, Rectangle box, HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
90 super(c, 5f);
91 CheckParameterUtil.ensureParameterNotNull(text);
92 CheckParameterUtil.ensureParameterNotNull(hAlign);
93 CheckParameterUtil.ensureParameterNotNull(vAlign);
94 this.text = text;
95 this.boxProvider = boxProvider;
96 this.box = box == null ? ZERO_BOX : box;
97 this.hAlign = hAlign;
98 this.vAlign = vAlign;
99 }
100
101 public static BoxTextElemStyle create(Environment env, BoxProvider boxProvider) {
102 return create(env, boxProvider, null);
103 }
104
105 public static BoxTextElemStyle create(Environment env, Rectangle box) {
106 return create(env, null, box);
107 }
108
109 public static BoxTextElemStyle create(Environment env, BoxProvider boxProvider, Rectangle box) {
110 initDefaultParameters();
111 Cascade c = env.mc.getCascade(env.layer);
112
113 TextElement text = TextElement.create(env, DEFAULT_TEXT_COLOR, false);
114 if (text == null) return null;
115 // Skip any primitives that don't have text to draw. (Styles are recreated for any tag change.)
116 // The concrete text to render is not cached in this object, but computed for each
117 // repaint. This way, one BoxTextElemStyle object can be used by multiple primitives (to save memory).
118 if (text.labelCompositionStrategy.compose(env.osm) == null) return null;
119
120 HorizontalTextAlignment hAlign = HorizontalTextAlignment.RIGHT;
121 Keyword hAlignKW = c.get(TEXT_ANCHOR_HORIZONTAL, Keyword.RIGHT, Keyword.class);
122 if ("left".equals(hAlignKW.val)) {
123 hAlign = HorizontalTextAlignment.LEFT;
124 } else if ("center".equals(hAlignKW.val)) {
125 hAlign = HorizontalTextAlignment.CENTER;
126 } else if ("right".equals(hAlignKW.val)) {
127 hAlign = HorizontalTextAlignment.RIGHT;
128 }
129 VerticalTextAlignment vAlign = VerticalTextAlignment.BOTTOM;
130 String vAlignStr = c.get(TEXT_ANCHOR_VERTICAL, Keyword.BOTTOM, Keyword.class).val;
131 if ("above".equals(vAlignStr)) {
132 vAlign = VerticalTextAlignment.ABOVE;
133 } else if ("top".equals(vAlignStr)) {
134 vAlign = VerticalTextAlignment.TOP;
135 } else if ("center".equals(vAlignStr)) {
136 vAlign = VerticalTextAlignment.CENTER;
137 } else if ("bottom".equals(vAlignStr)) {
138 vAlign = VerticalTextAlignment.BOTTOM;
139 } else if ("below".equals(vAlignStr)) {
140 vAlign = VerticalTextAlignment.BELOW;
141 }
142
143 return new BoxTextElemStyle(c, text, boxProvider, box, hAlign, vAlign);
144 }
145
146 public Rectangle getBox() {
147 if (boxProvider != null) {
148 BoxProviderResult result = boxProvider.get();
149 if (!result.isTemporary()) {
150 box = result.getBox();
151 boxProvider = null;
152 }
153 return result.getBox();
154 }
155 return box;
156 }
157
158 public static final BoxTextElemStyle SIMPLE_NODE_TEXT_ELEMSTYLE;
159 static {
160 MultiCascade mc = new MultiCascade();
161 Cascade c = mc.getOrCreateCascade("default");
162 c.put(TEXT, Keyword.AUTO);
163 Node n = new Node();
164 n.put("name", "dummy");
165 SIMPLE_NODE_TEXT_ELEMSTYLE = create(new Environment(n, mc, "default", null), NodeElemStyle.SIMPLE_NODE_ELEMSTYLE.getBoxProvider());
166 if (SIMPLE_NODE_TEXT_ELEMSTYLE == null) throw new AssertionError();
167 }
168 /*
169 * Caches the default text color from the preferences.
170 *
171 * FIXME: the cache isn't updated if the user changes the preference during a JOSM
172 * session. There should be preference listener updating this cache.
173 */
174 private static volatile Color DEFAULT_TEXT_COLOR = null;
175 private static void initDefaultParameters() {
176 if (DEFAULT_TEXT_COLOR != null) return;
177 DEFAULT_TEXT_COLOR = PaintColors.TEXT.get();
178 }
179
180 @Override
181 public void paintPrimitive(OsmPrimitive osm, MapPaintSettings settings, StyledMapRenderer painter,
182 boolean selected, boolean outermember, boolean member) {
183 if (osm instanceof Node) {
184 painter.drawBoxText((Node) osm, this);
185 }
186 }
187
188 @Override
189 public boolean equals(Object obj) {
190 if (!super.equals(obj))
191 return false;
192 if (obj == null || getClass() != obj.getClass())
193 return false;
194 final BoxTextElemStyle other = (BoxTextElemStyle) obj;
195 if (!text.equals(other.text)) return false;
196 if (boxProvider != null) {
197 if (!boxProvider.equals(other.boxProvider)) return false;
198 } else if (other.boxProvider != null)
199 return false;
200 else {
201 if (!box.equals(other.box)) return false;
202 }
203 if (hAlign != other.hAlign) return false;
204 if (vAlign != other.vAlign) return false;
205 return true;
206 }
207
208 @Override
209 public int hashCode() {
210 int hash = super.hashCode();
211 hash = 97 * hash + text.hashCode();
212 if (boxProvider != null) {
213 hash = 97 * hash + boxProvider.hashCode();
214 } else {
215 hash = 97 * hash + box.hashCode();
216 }
217 hash = 97 * hash + hAlign.hashCode();
218 hash = 97 * hash + vAlign.hashCode();
219 return hash;
220 }
221
222 @Override
223 public String toString() {
224 return "BoxTextElemStyle{" + super.toString() + " " + text.toStringImpl() + " box=" + box + " hAlign=" + hAlign + " vAlign=" + vAlign + '}';
225 }
226
227}
Note: See TracBrowser for help on using the repository browser.