001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.gui.mappaint;
003
004 import java.util.ArrayList;
005 import java.util.Arrays;
006 import java.util.Collections;
007 import java.util.List;
008
009 import org.openstreetmap.josm.Main;
010 import org.openstreetmap.josm.data.osm.OsmPrimitive;
011 import org.openstreetmap.josm.tools.LanguageInfo;
012
013 /**
014 * <p>Provides an abstract parent class and three concrete sub classes for various
015 * strategies on how to compose the text label which can be rendered close to a node
016 * or within an area in an OSM map.</p>
017 *
018 * <p>The three strategies below support three rules for composing a label:
019 * <ul>
020 * <li>{@link StaticLabelCompositionStrategy} - the label is given by a static text
021 * specified in the MapCSS style file</li>
022 *
023 * <li>{@link TagLookupCompositionStrategy} - the label is given by the content of a
024 * tag whose name specified in the MapCSS style file</li>
025 *
026 * <li>{@link DeriveLabelFromNameTagsCompositionStrategy} - the label is given by the value
027 * of one
028 * of the configured "name tags". The list of relevant name tags can be configured
029 * in the JOSM preferences
030 * content of a tag whose name specified in the MapCSS style file, see the preference
031 * option <tt>mappaint.nameOrder</tt>.</li>
032 * </ul>
033 * </p>
034 *
035 */
036 public abstract class LabelCompositionStrategy {
037
038 /**
039 * Replies the text value to be rendered as label for the primitive {@code primitive}.
040 *
041 * @param primitive the primitive
042 *
043 * @return the text value to be rendered or null, if primitive is null or
044 * if no suitable value could be composed
045 */
046 abstract public String compose(OsmPrimitive primitive);
047
048 static public class StaticLabelCompositionStrategy extends LabelCompositionStrategy {
049 private String defaultLabel;
050
051 public StaticLabelCompositionStrategy(String defaultLabel){
052 this.defaultLabel = defaultLabel;
053 }
054
055 @Override
056 public String compose(OsmPrimitive primitive) {
057 return defaultLabel;
058 }
059
060 public String getDefaultLabel() {
061 return defaultLabel;
062 }
063
064 @Override
065 public String toString() {
066 return "{" + getClass().getSimpleName() + " defaultLabel=" + defaultLabel + "}";
067 }
068
069 @Override
070 public int hashCode() {
071 final int prime = 31;
072 int result = 1;
073 result = prime * result + ((defaultLabel == null) ? 0 : defaultLabel.hashCode());
074 return result;
075 }
076
077 @Override
078 public boolean equals(Object obj) {
079 if (this == obj)
080 return true;
081 if (obj == null)
082 return false;
083 if (getClass() != obj.getClass())
084 return false;
085 StaticLabelCompositionStrategy other = (StaticLabelCompositionStrategy) obj;
086 if (defaultLabel == null) {
087 if (other.defaultLabel != null)
088 return false;
089 } else if (!defaultLabel.equals(other.defaultLabel))
090 return false;
091 return true;
092 }
093 }
094
095 static public class TagLookupCompositionStrategy extends LabelCompositionStrategy {
096
097 private String defaultLabelTag;
098 public TagLookupCompositionStrategy(String defaultLabelTag){
099 if (defaultLabelTag != null) {
100 defaultLabelTag = defaultLabelTag.trim();
101 if (defaultLabelTag.isEmpty()) {
102 defaultLabelTag = null;
103 }
104 }
105 this.defaultLabelTag = defaultLabelTag;
106 }
107
108 @Override
109 public String compose(OsmPrimitive primitive) {
110 if (defaultLabelTag == null) return null;
111 if (primitive == null) return null;
112 return primitive.get(defaultLabelTag);
113 }
114
115 public String getDefaultLabelTag() {
116 return defaultLabelTag;
117 }
118
119 @Override
120 public String toString() {
121 return "{" + getClass().getSimpleName() + " defaultLabelTag=" + defaultLabelTag + "}";
122 }
123
124 @Override
125 public int hashCode() {
126 final int prime = 31;
127 int result = 1;
128 result = prime * result + ((defaultLabelTag == null) ? 0 : defaultLabelTag.hashCode());
129 return result;
130 }
131
132 @Override
133 public boolean equals(Object obj) {
134 if (this == obj)
135 return true;
136 if (obj == null)
137 return false;
138 if (getClass() != obj.getClass())
139 return false;
140 TagLookupCompositionStrategy other = (TagLookupCompositionStrategy) obj;
141 if (defaultLabelTag == null) {
142 if (other.defaultLabelTag != null)
143 return false;
144 } else if (!defaultLabelTag.equals(other.defaultLabelTag))
145 return false;
146 return true;
147 }
148 }
149
150 static public class DeriveLabelFromNameTagsCompositionStrategy extends LabelCompositionStrategy {
151
152 /**
153 * The list of default name tags from which a label candidate is derived.
154 */
155 static public final String[] DEFAULT_NAME_TAGS = {
156 "name:" + LanguageInfo.getJOSMLocaleCode(),
157 "name",
158 "int_name",
159 "ref",
160 "operator",
161 "brand",
162 "addr:housenumber"
163 };
164
165 private List<String> nameTags = new ArrayList<String>();
166
167 /**
168 * <p>Creates the strategy and initializes its name tags from the preferences.</p>
169 *
170 * <p><strong>Note:</strong> If the list of name tags in the preferences changes, strategy instances
171 * are not notified. It's up to the client to listen to preference changes and
172 * invoke {@link #initNameTagsFromPreferences()} accordingly.</p>
173 *
174 */
175 public DeriveLabelFromNameTagsCompositionStrategy() {
176 initNameTagsFromPreferences();
177 }
178
179 /**
180 * Sets the name tags to be looked up in order to build up the label
181 *
182 * @param nameTags the name tags. null values are ignore.
183 */
184 public void setNameTags(List<String> nameTags){
185 if (nameTags == null) {
186 nameTags = Collections.emptyList();
187 }
188 this.nameTags = new ArrayList<String>();
189 for(String tag: nameTags) {
190 if (tag == null) {
191 continue;
192 }
193 tag = tag.trim();
194 if (tag.isEmpty()) {
195 continue;
196 }
197 this.nameTags.add(tag);
198 }
199 }
200
201 /**
202 * Replies an unmodifiable list of the name tags used to compose the label.
203 *
204 * @return the list of name tags
205 */
206 public List<String> getNameTags() {
207 return Collections.unmodifiableList(nameTags);
208 }
209
210 /**
211 * Initializes the name tags to use from a list of default name tags (see
212 * {@link #DEFAULT_NAME_TAGS}) and from name tags configured in the preferences
213 * using the preference key <tt>mappaint.nameOrder</tt>.
214 */
215 public void initNameTagsFromPreferences() {
216 if (Main.pref == null){
217 this.nameTags = new ArrayList<String>(Arrays.asList(DEFAULT_NAME_TAGS));
218 } else {
219 this.nameTags = new ArrayList<String>(
220 Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(DEFAULT_NAME_TAGS))
221 );
222 }
223 }
224
225 private String getPrimitiveName(OsmPrimitive n) {
226 String name = null;
227 if (!n.hasKeys()) return null;
228 for (String rn : nameTags) {
229 name = n.get(rn);
230 if (name != null) return name;
231 }
232 return null;
233 }
234
235 @Override
236 public String compose(OsmPrimitive primitive) {
237 if (primitive == null) return null;
238 return getPrimitiveName(primitive);
239 }
240
241 @Override
242 public String toString() {
243 return "{" + getClass().getSimpleName() +"}";
244 }
245 }
246 }