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 }