Index: src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java =================================================================== --- src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java (revision 3980) +++ src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java (working copy) @@ -38,12 +38,11 @@ import org.openstreetmap.josm.gui.NavigatableComponent; import org.openstreetmap.josm.gui.mappaint.NodeElemStyle; import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.HorizontalTextAlignment; -import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol; import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement; +import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol; import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.VerticalTextAlignment; import org.openstreetmap.josm.gui.mappaint.TextElement; import org.openstreetmap.josm.tools.ImageProvider; -import org.openstreetmap.josm.tools.LanguageInfo; import org.openstreetmap.josm.tools.Pair; public class MapPainter { @@ -73,8 +72,6 @@ private final boolean leftHandTraffic; - private final Collection regionalNameOrder; - private static final double PHI = Math.toRadians(20); private static final double cosPHI = Math.cos(PHI); private static final double sinPHI = Math.sin(PHI); @@ -103,8 +100,6 @@ this.virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70); this.segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40); - String[] names = {"name:" + LanguageInfo.getJOSMLocaleCode(), "name", "int_name", "ref", "operator", "brand", "addr:housenumber"}; - this.regionalNameOrder = Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(names)); this.circum = circum; this.leftHandTraffic = leftHandTraffic; } @@ -117,7 +112,7 @@ * e.g. oneway street or waterway * @param onewayReversed for oneway=-1 and similar */ - public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, + public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, TextElement text, boolean showOrientation, boolean showHeadArrowOnly, boolean showOneway, boolean onewayReversed) { @@ -252,7 +247,7 @@ private void drawTextOnPath(Way way, TextElement text) { if (text == null) return; - String name = text.getString(way, this); + String name = text.getString(way); if (name == null || name.equals("")) return; @@ -291,8 +286,8 @@ double tStart; if (p1[0] < p2[0] && - p1[2] < Math.PI/2 && - p1[2] > -Math.PI/2) { + p1[2] < Math.PI/2 && + p1[2] > -Math.PI/2) { angleOffset = 0; offsetSign = 1; tStart = t1; @@ -346,8 +341,8 @@ continue; } return new double[] {poly.xpoints[i-1]+(totalLen - curLen)/segLen*dx, - poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy, - Math.atan2(dy, dx)}; + poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy, + Math.atan2(dy, dx)}; } return null; } @@ -494,9 +489,12 @@ if (!isShowNames() || text == null) return; - String s = text.textKey == null ? getNodeName(n) : n.get(text.textKey); - if (s == null) - return; + /* + * abort if we can't compose the label to be rendered + */ + if (text.labelCompositionStrategy == null) return; + String s = text.labelCompositionStrategy.compose(n); + if (s == null) return; Font defaultFont = g.getFont(); g.setFont(text.font); @@ -597,9 +595,12 @@ } if (text != null && isShowNames()) { - String name = text.textKey == null ? getAreaName(osm) : osm.get(text.textKey); - if (name == null) - return; + /* + * abort if we can't compose the label to be rendered + */ + if (text.labelCompositionStrategy == null) return; + String name = text.labelCompositionStrategy.compose(osm); + if (name == null) return; Rectangle pb = polygon.getBounds(); FontMetrics fontMetrics = g.getFontMetrics(orderFont); // if slow, use cache @@ -930,34 +931,6 @@ } } - //TODO Not a good place for this method - public String getNodeName(Node n) { - String name = null; - if (n.hasKeys()) { - for (String rn : regionalNameOrder) { - name = n.get(rn); - if (name != null) { - break; - } - } - } - return name; - } - - //TODO Not a good place for this method - public String getAreaName(OsmPrimitive w) { - String name = null; - if (w.hasKeys()) { - for (String rn : regionalNameOrder) { - name = w.get(rn); - if (name != null) { - break; - } - } - } - return name; - } - public boolean isInactive() { return inactive; } Index: src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java =================================================================== --- src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java (revision 3980) +++ src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java (working copy) @@ -16,7 +16,7 @@ public float z_index; public float object_z_index; public boolean isModifier; // false, if style can serve as main style for the - // primitive; true, if it is a highlight or modifier + // primitive; true, if it is a highlight or modifier public ElemStyle(float z_index, float object_z_index, boolean isModifier) { this.z_index = z_index; @@ -63,7 +63,7 @@ String name = c.get("font-family", Main.pref.get("mappaint.font", "Helvetica"), String.class); float size = c.get("font-size", (float) Main.pref.getInteger("mappaint.fontsize", 8), Float.class); int weight = Font.PLAIN; - Keyword weightKW = c.get("font-wheight", null, Keyword.class); + Keyword weightKW = c.get("font-weight", null, Keyword.class); if (weightKW != null && equal(weightKW, "bold")) { weight = Font.BOLD; } Index: src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java =================================================================== --- src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java (revision 0) +++ src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java (revision 0) @@ -0,0 +1,244 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.gui.mappaint; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.openstreetmap.josm.Main; +import org.openstreetmap.josm.data.osm.OsmPrimitive; +import org.openstreetmap.josm.tools.LanguageInfo; + +/** + *

Provides an abstract parent class and three concrete sub classes for various + * strategies on how to compose the text label which can be rendered close to a node + * or within an area in an OSM map.

+ * + *

The three strategies below support three rules for composing a label: + *

+ *

+ * + */ +public abstract class LabelCompositionStrategy { + + static public class StaticLabelCompositionStrategy extends LabelCompositionStrategy { + private String defaultLabel; + public StaticLabelCompositionStrategy(String defaultLabel){ + this.defaultLabel = defaultLabel; + } + + @Override + public String compose(OsmPrimitive primitive) { + return defaultLabel; + } + + public String getDefaultLabel() { + return defaultLabel; + } + + @Override + public String toString() { + return "{" + getClass().getSimpleName() + " defaultLabel=" + defaultLabel + "}"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((defaultLabel == null) ? 0 : defaultLabel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + StaticLabelCompositionStrategy other = (StaticLabelCompositionStrategy) obj; + if (defaultLabel == null) { + if (other.defaultLabel != null) + return false; + } else if (!defaultLabel.equals(other.defaultLabel)) + return false; + return true; + } + } + + static public class TagLookupCompositionStrategy extends LabelCompositionStrategy { + + private String defaultLabelTag; + public TagLookupCompositionStrategy(String defaultLabelTag){ + if (defaultLabelTag != null) { + defaultLabelTag = defaultLabelTag.trim(); + if (defaultLabelTag.isEmpty()) { + defaultLabelTag = null; + } + } + this.defaultLabelTag = defaultLabelTag; + } + + @Override + public String compose(OsmPrimitive primitive) { + if (defaultLabelTag == null) return null; + if (primitive == null) return null; + return primitive.get(defaultLabelTag); + } + + public String getDefaultLabelTag() { + return defaultLabelTag; + } + + @Override + public String toString() { + return "{" + getClass().getSimpleName() + " defaultLabelTag=" + defaultLabelTag + "}"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((defaultLabelTag == null) ? 0 : defaultLabelTag.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TagLookupCompositionStrategy other = (TagLookupCompositionStrategy) obj; + if (defaultLabelTag == null) { + if (other.defaultLabelTag != null) + return false; + } else if (!defaultLabelTag.equals(other.defaultLabelTag)) + return false; + return true; + } + } + + static public class DeriveLabelFromNameTagsCompositionStrategy extends LabelCompositionStrategy { + + /** + * The list of default name tags from which a label candidate is derived. + */ + static public final String[] DEFAULT_NAME_TAGS = { + "name:" + LanguageInfo.getJOSMLocaleCode(), + "name", + "int_name", + "ref", + "operator", + "brand", + "addr:housenumber" + }; + + private List nameTags = new ArrayList(); + + /** + *

Creates the strategy and initializes its name tags from the preferences.

+ * + *

Note: If the list of name tags in the preferences changes, strategy instances + * are not notified. It's up to the client to listen to preference changes and + * invoke {@link #initNameTagsFromPreferences()} accordingly.

+ * + */ + public DeriveLabelFromNameTagsCompositionStrategy() { + initNameTagsFromPreferences(); + } + + /** + * Sets the name tags to be looked up in order to build up the label + * + * @param nameTags the name tags. null values are ignore. + */ + public void setNameTags(List nameTags){ + if (nameTags == null) { + nameTags = Collections.emptyList(); + } + this.nameTags = new ArrayList(); + for(String tag: nameTags) { + if (tag == null) { + continue; + } + tag = tag.trim(); + if (tag.isEmpty()) { + continue; + } + this.nameTags.add(tag); + } + } + + /** + * Replies an unmodifiable list of the name tags used to compose the label. + * + * @return the list of name tags + */ + public List getNameTags() { + return Collections.unmodifiableList(nameTags); + } + + /** + * Initializes the name tags to use from a list of default name tags (see + * {@link #DEFAULT_NAME_TAGS}) and from name tags configured in the preferences + * using the preference key mappaint.nameOrder. + */ + public void initNameTagsFromPreferences() { + if (Main.pref == null){ + this.nameTags = new ArrayList(Arrays.asList(DEFAULT_NAME_TAGS)); + } else { + this.nameTags = new ArrayList( + Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(DEFAULT_NAME_TAGS)) + ); + } + } + + private String getPrimitiveName(OsmPrimitive n) { + String name = null; + if (!n.hasKeys()) return null; + for (String rn : nameTags) { + name = n.get(rn); + if (name != null) return name; + } + return null; + } + + @Override + public String compose(OsmPrimitive primitive) { + if (primitive == null) return null; + return getPrimitiveName(primitive); + } + + @Override + public String toString() { + return "{" + getClass().getSimpleName() +"}"; + } + } + + /** + * Replies the text value to be rendered as label for the primitive {@code primitive}. + * + * @param primitive the primitive + * + * @return the text value to be rendered or null, if primitive is null or + * if no suitable value could be composed + */ + abstract public String compose(OsmPrimitive primitive); +} Index: src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java =================================================================== --- src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java (revision 3980) +++ src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java (working copy) @@ -6,13 +6,15 @@ import java.util.Map; import java.util.Map.Entry; +import org.openstreetmap.josm.tools.CheckParameterUtil; + /** * Several layers / cascades, e.g. one for the main Line and one for each overlay. * The range is (0,Infinity) at first and it shrinks in the process when * StyleSources apply zoom level dependent properties. */ public class MultiCascade { - + private Map layers; public Range range; @@ -27,8 +29,7 @@ * a clone of the "*" layer, if it exists. */ public Cascade getOrCreateCascade(String layer) { - if (layer == null) - throw new IllegalArgumentException(); + CheckParameterUtil.ensureParameterNotNull(layer); Cascade c = layers.get(layer); if (c == null) { if (layers.containsKey("*")) { Index: src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java =================================================================== --- src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java (revision 3980) +++ src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java (working copy) @@ -25,6 +25,7 @@ * applies for Nodes and turn restriction relations */ public class NodeElemStyle extends ElemStyle { + //static private final Logger logger = Logger.getLogger(NodeElemStyle.class.getName()); public ImageIcon icon; public int iconAlpha; @@ -62,10 +63,10 @@ return false; final Symbol other = (Symbol) obj; return symbol == other.symbol && - size == other.size && - equal(stroke, other.stroke) && - equal(strokeColor, other.strokeColor) && - equal(fillColor, other.fillColor); + size == other.size && + equal(stroke, other.stroke) && + equal(strokeColor, other.strokeColor) && + equal(fillColor, other.fillColor); } @Override @@ -82,8 +83,8 @@ @Override public String toString() { return "symbol=" + symbol + " size=" + size + - (stroke != null ? (" stroke=" + stroke + " strokeColor=" + strokeColor) : "") + - (fillColor != null ? (" fillColor=" + fillColor) : ""); + (stroke != null ? (" stroke=" + stroke + " strokeColor=" + strokeColor) : "") + + (fillColor != null ? (" fillColor=" + fillColor) : ""); } } @@ -107,7 +108,7 @@ return false; final NodeTextElement other = (NodeTextElement) obj; return hAlign == other.hAlign && - vAlign == other.vAlign; + vAlign == other.vAlign; } @Override @@ -162,9 +163,6 @@ symbol = createSymbol(env); } - if (icon == null && symbol == null && !allowOnlyText) - return null; - NodeTextElement text = null; TextElement te = TextElement.create(c, PaintColors.TEXT.get()); if (te != null) { @@ -192,7 +190,7 @@ } text = new NodeTextElement(te, hAlign, vAlign); } - + return new NodeElemStyle(c, icon, iconAlpha, symbol, text); } @@ -224,7 +222,7 @@ shape = SymbolShape.DECAGON; } else return null; - + Float sizeOnDefault = c_def.get("symbol-size", null, Float.class); if (sizeOnDefault != null && sizeOnDefault <= 0) { sizeOnDefault = null; @@ -258,8 +256,9 @@ } Color fillColor = c.get("symbol-fill-color", null, Color.class); - if (stroke == null && fillColor == null) + if (stroke == null && fillColor == null) { fillColor = Color.BLUE; + } if (fillColor != null) { float fillAlpha = c.get("symbol-fill-opacity", 1f, Float.class); @@ -335,14 +334,14 @@ } final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0), - (n.isTagged() ? settings.getTaggedNodeSize() : 0), - (isConnection ? settings.getConnectionNodeSize() : 0), - settings.getUnselectedNodeSize()); + (n.isTagged() ? settings.getTaggedNodeSize() : 0), + (isConnection ? settings.getConnectionNodeSize() : 0), + settings.getUnselectedNodeSize()); final boolean fill = (selected && settings.isFillSelectedNode()) || - (n.isTagged() && settings.isFillTaggedNode()) || - (isConnection && settings.isFillConnectionNode()) || - settings.isFillUnselectedNode(); + (n.isTagged() && settings.isFillTaggedNode()) || + (isConnection && settings.isFillConnectionNode()) || + settings.isFillUnselectedNode(); painter.drawNode(n, color, size, fill, text); } @@ -394,8 +393,8 @@ @Override public String toString() { return "NodeElemStyle{" + super.toString() + - (icon != null ? ("icon=" + icon + " iconAlpha=" + iconAlpha) : "") + - (symbol != null ? (" symbol=[" + symbol + "]") : "") + '}'; + (icon != null ? ("icon=" + icon + " iconAlpha=" + iconAlpha) : "") + + (symbol != null ? (" symbol=[" + symbol + "]") : "") + '}'; } } Index: src/org/openstreetmap/josm/gui/mappaint/TextElement.java =================================================================== --- src/org/openstreetmap/josm/gui/mappaint/TextElement.java (revision 3980) +++ src/org/openstreetmap/josm/gui/mappaint/TextElement.java (working copy) @@ -1,31 +1,53 @@ // License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.mappaint; -import static org.openstreetmap.josm.tools.Utils.equal; - import java.awt.Color; import java.awt.Font; + import org.openstreetmap.josm.data.osm.OsmPrimitive; -import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter; - +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy; +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.StaticLabelCompositionStrategy; +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy; import org.openstreetmap.josm.tools.CheckParameterUtil; import org.openstreetmap.josm.tools.Utils; +/** + * Represents the rendering style for a textual label placed somewhere on the map. + * + */ public class TextElement { - // textKey == null means automatic generation of text string, otherwise - // the corresponding tag value is used - public String textKey; + //static private final Logger logger = Logger.getLogger(TextElement.class.getName()); + + static private final LabelCompositionStrategy AUTO_LABEL_COMPOSITION_STRATEGY = new DeriveLabelFromNameTagsCompositionStrategy(); + + /** the font to be used when rendering*/ public Font font; public int xOffset; public int yOffset; public Color color; public Float haloRadius; public Color haloColor; + /** the strategy for building the actual label value for a given a {@link OsmPrimitive}. + * Check for null before accessing. + */ + public LabelCompositionStrategy labelCompositionStrategy; - public TextElement(String textKey, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) { + /** + * Creates a new text element + * + * @param strategy the strategy indicating how the text is composed for a specific {@link OsmPrimitive} to be rendered. + * If null, no label is rendered. + * @param font the font to be used. Must not be null. + * @param xOffset + * @param yOffset + * @param color the color to be used. Must not be null + * @param haloRadius + * @param haloColor + */ + public TextElement(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) { CheckParameterUtil.ensureParameterNotNull(font); CheckParameterUtil.ensureParameterNotNull(color); - this.textKey = textKey; + labelCompositionStrategy = strategy; this.font = font; this.xOffset = xOffset; this.yOffset = yOffset; @@ -34,8 +56,13 @@ this.haloColor = haloColor; } + /** + * Copy constructor + * + * @param other the other element. + */ public TextElement(TextElement other) { - this.textKey = other.textKey; + this.labelCompositionStrategy = other.labelCompositionStrategy; this.font = other.font; this.xOffset = other.xOffset; this.yOffset = other.yOffset; @@ -44,17 +71,47 @@ this.haloRadius = other.haloRadius; } - public static TextElement create(Cascade c, Color defTextColor) { - - String textKey = null; + /** + * Derives a suitable label composition strategy from the style properties in + * {@code c}. + * + * @param c the style properties + * @return the label composition strategy + */ + protected static LabelCompositionStrategy buildLabelCompositionStrategy(Cascade c){ + LabelCompositionStrategy strategy; Keyword textKW = c.get("text", null, Keyword.class, true); if (textKW == null) { - textKey = c.get("text", null, String.class); - if (textKey == null) - return null; + String textKey = c.get("text", null, String.class); + if (textKey == null) return null; + strategy = new StaticLabelCompositionStrategy(textKey); } else if (!textKW.val.equals("auto")) return null; + else { + String defaultLabelTag = c.get("text-from-tag", null, String.class); + if (defaultLabelTag == null){ + strategy = AUTO_LABEL_COMPOSITION_STRATEGY; + } else { + strategy = new TagLookupCompositionStrategy(defaultLabelTag); + } + } + return strategy; + } + /** + * Builds a text element from style properties in {@code c} and the + * default text color {@code defaultTextColor} + * + * @param c the style properties + * @param defaultTextColor the default text color. Must not be null. + * @return the text element or null, if the style properties don't include + * properties for text rendering + * @throws IllegalArgumentException thrown if {@code defaultTextColor} is null + */ + public static TextElement create(Cascade c, Color defaultTextColor) throws IllegalArgumentException{ + CheckParameterUtil.ensureParameterNotNull(defaultTextColor, "defaultTextColor"); + + LabelCompositionStrategy strategy = buildLabelCompositionStrategy(c); Font font = ElemStyle.getFont(c); float xOffset = 0; @@ -70,8 +127,8 @@ } xOffset = c.get("text-offset-x", xOffset, Float.class); yOffset = c.get("text-offset-y", yOffset, Float.class); - - Color color = c.get("text-color", defTextColor, Color.class); + + Color color = c.get("text-color", defaultTextColor, Color.class); float alpha = c.get("text-opacity", 1f, Float.class); color = new Color(color.getRed(), color.getGreen(), color.getBlue(), Utils.color_float2int(alpha)); @@ -88,42 +145,86 @@ haloColor.getBlue(), Utils.color_float2int(haloAlpha)); } - return new TextElement(textKey, font, (int) xOffset, - (int) yOffset, color, haloRadius, haloColor); + return new TextElement(strategy, font, (int) xOffset, - (int) yOffset, color, haloRadius, haloColor); } + /** + * Replies the label to be rendered for the primitive {@code osm}. + * + * @param osm the the OSM object + * @return the label, or null, if {@code osm} is null or if no label can be + * derived for {@code osm} + */ + public String getString(OsmPrimitive osm) { + if (labelCompositionStrategy == null) return null; + return labelCompositionStrategy.compose(osm); + } + @Override - public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) - return false; - final TextElement other = (TextElement) obj; - return equal(textKey, other.textKey) && - equal(font, other.font) && - xOffset == other.xOffset && - yOffset == other.yOffset && - equal(color, other.color) && - equal(haloRadius, other.haloRadius) && - equal(haloColor, other.haloColor); + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{TextElement "); + sb.append("strategy="); + sb.append(labelCompositionStrategy == null ? "null" : labelCompositionStrategy.toString()); + sb.append("}"); + return sb.toString(); } + /* -------------------------------------------------------------------------------- */ + /* equals and hashCode (generated by Eclipse, regenerate if necessary) */ + /* -------------------------------------------------------------------------------- */ @Override public int hashCode() { - int hash = 3; - hash = 79 * hash + (textKey != null ? textKey.hashCode() : 0); - hash = 79 * hash + font.hashCode(); - hash = 79 * hash + xOffset; - hash = 79 * hash + yOffset; - hash = 79 * hash + color.hashCode(); - hash = 79 * hash + (haloRadius != null ? Float.floatToIntBits(haloRadius) : 0); - hash = 79 * hash + (haloColor != null ? haloColor.hashCode() : 0); - return hash; + final int prime = 31; + int result = 1; + result = prime * result + ((color == null) ? 0 : color.hashCode()); + result = prime * result + ((font == null) ? 0 : font.hashCode()); + result = prime * result + ((haloColor == null) ? 0 : haloColor.hashCode()); + result = prime * result + ((haloRadius == null) ? 0 : haloRadius.hashCode()); + result = prime * result + ((labelCompositionStrategy == null) ? 0 : labelCompositionStrategy.hashCode()); + result = prime * result + xOffset; + result = prime * result + yOffset; + return result; } - public String getString(OsmPrimitive osm, MapPainter painter) { - if (textKey == null) - return painter.getAreaName(osm); - else - return osm.get(textKey); + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TextElement other = (TextElement) obj; + if (color == null) { + if (other.color != null) + return false; + } else if (!color.equals(other.color)) + return false; + if (font == null) { + if (other.font != null) + return false; + } else if (!font.equals(other.font)) + return false; + if (haloColor == null) { + if (other.haloColor != null) + return false; + } else if (!haloColor.equals(other.haloColor)) + return false; + if (haloRadius == null) { + if (other.haloRadius != null) + return false; + } else if (!haloRadius.equals(other.haloRadius)) + return false; + if (labelCompositionStrategy == null) { + if (other.labelCompositionStrategy != null) + return false; + } else if (!labelCompositionStrategy.equals(other.labelCompositionStrategy)) + return false; + if (xOffset != other.xOffset) + return false; + if (yOffset != other.yOffset) + return false; + return true; } - - } Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java =================================================================== --- src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java (revision 3980) +++ src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java (working copy) @@ -27,7 +27,8 @@ import org.openstreetmap.josm.tools.Utils; public class MapCSSStyleSource extends StyleSource { - + //static private final Logger logger = Logger.getLogger(MapCSSStyleSource.class.getName()); + final public List rules; private Color backgroundColorOverride; @@ -65,6 +66,7 @@ } } + @Override public InputStream getSourceInputStream() throws IOException { MirroredInputStream in = new MirroredInputStream(url); InputStream zip = in.getZipEntry("mapcss", "style"); @@ -107,26 +109,28 @@ Environment env = new Environment(n, mc, "default", this); NEXT_RULE: - for (MapCSSRule r : rules) { - for (Selector s : r.selectors) { - if ((s instanceof GeneralSelector)) { - GeneralSelector gs = (GeneralSelector) s; - if (gs.base.equals(type)) - { - for (Condition cnd : gs.conds) { - if (!cnd.applies(env)) - continue NEXT_RULE; + for (MapCSSRule r : rules) { + for (Selector s : r.selectors) { + if ((s instanceof GeneralSelector)) { + GeneralSelector gs = (GeneralSelector) s; + if (gs.base.equals(type)) + { + for (Condition cnd : gs.conds) { + if (!cnd.applies(env)) { + continue NEXT_RULE; + } + } + for (Instruction i : r.declaration) { + i.execute(env); + } } - for (Instruction i : r.declaration) { - i.execute(env); - } } } } - } return mc.getCascade("default"); } + @Override public Color getBackgroundColorOverride() { return backgroundColorOverride; } @@ -159,7 +163,7 @@ i.execute(env); } } - } + } env.layer = sub; for (Instruction i : r.declaration) { i.execute(env); Index: test/data/styles/label-from-tag.mapcss =================================================================== --- test/data/styles/label-from-tag.mapcss (revision 0) +++ test/data/styles/label-from-tag.mapcss (revision 0) @@ -0,0 +1,21 @@ +/* + * Simple test style sheet. Includes a style with the new style declaration 'text-from-tag'. + * + */ + +meta { + title: "Test style - Deriving labels from tags"; +} + +canvas { + background-color: #000000; +} + +node { + text: auto; + text-color: white; + font-size: 12; + /* the value of the tag 'my_label_tag' will be rendered as text */ + text-from-tag: my_label_tag; +} + Index: test/functional/org/openstreetmap/josm/fixtures/JOSMFixture.java =================================================================== --- test/functional/org/openstreetmap/josm/fixtures/JOSMFixture.java (revision 3980) +++ test/functional/org/openstreetmap/josm/fixtures/JOSMFixture.java (working copy) @@ -10,7 +10,7 @@ import java.util.logging.Logger; import org.openstreetmap.josm.Main; -import org.openstreetmap.josm.data.osm.DataSetMergerTest; +import org.openstreetmap.josm.data.Preferences; import org.openstreetmap.josm.data.projection.Mercator; import org.openstreetmap.josm.io.OsmApi; import org.openstreetmap.josm.tools.I18n; @@ -39,7 +39,7 @@ // load properties // try { - testProperties.load(DataSetMergerTest.class.getResourceAsStream(testPropertiesResourceName)); + testProperties.load(JOSMFixture.class.getResourceAsStream(testPropertiesResourceName)); } catch(Exception e){ logger.log(Level.SEVERE, MessageFormat.format("failed to load property file ''{0}''", testPropertiesResourceName)); fail(MessageFormat.format("failed to load property file ''{0}''. \nMake sure the path ''$project_root/test/config'' is on the classpath.", testPropertiesResourceName)); @@ -57,6 +57,7 @@ } } System.setProperty("josm.home", josmHome); + Main.pref = new Preferences(); I18n.init(); // initialize the plaform hook, and Main.determinePlatformHook(); Index: test/unit/org/openstreetmap/josm/gui/mappaint/AllMappaintTests.groovy =================================================================== --- test/unit/org/openstreetmap/josm/gui/mappaint/AllMappaintTests.groovy (revision 0) +++ test/unit/org/openstreetmap/josm/gui/mappaint/AllMappaintTests.groovy (revision 0) @@ -0,0 +1,15 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.gui.mappaint + +import junit.framework.TestCase; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses([ + LabelCompositionStrategyTest.class, + MapCSSWithExtendedTextDirectivesTest.class +]) +public class AllMappaintTests extends TestCase{} + Index: test/unit/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategyTest.groovy =================================================================== --- test/unit/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategyTest.groovy (revision 0) +++ test/unit/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategyTest.groovy (revision 0) @@ -0,0 +1,66 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.gui.mappaint + +import org.junit.* +import org.openstreetmap.josm.fixtures.JOSMFixture; +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.StaticLabelCompositionStrategy; +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy +import org.openstreetmap.josm.data.osm.Node; + +class LabelCompositionStrategyTest { + + @BeforeClass + public static void createJOSMFixture(){ + JOSMFixture.createUnitTestFixture().init() + } + + @Test + public void createStaticLabelCompositionStrategy() { + def n = new Node() + + def strat = new StaticLabelCompositionStrategy(null) + assert strat.compose(n) == null + + strat = new StaticLabelCompositionStrategy("a label") + assert strat.compose(n) == "a label" + } + + @Test + public void createTagLookupCompositionStrategy() { + def n = new Node() + n.put("my-tag", "my-value") + + def strat = new TagLookupCompositionStrategy(null) + assert strat.compose(n) == null + + strat = new TagLookupCompositionStrategy("name") + assert strat.compose(n) == null + + strat = new TagLookupCompositionStrategy("my-tag") + assert strat.compose(n) == "my-value" + } + + @Test + public void createDeriveLabelFromNameTagsCompositionStrategy() { + def n + def strat + + strat = new DeriveLabelFromNameTagsCompositionStrategy() + strat.setNameTags(null) + assert strat.getNameTags() == [] + + strat = new DeriveLabelFromNameTagsCompositionStrategy() + strat.setNameTags(["name", "brand"]) + assert strat.getNameTags() == ["name", "brand"] + + n = new Node() + n.put("brand", "my brand") + assert strat.compose(n) == "my brand" + + n = new Node() + n.put("name", "my name") + n.put("brand", "my brand") + assert strat.compose(n) == "my name" + } +} Index: test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy =================================================================== --- test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy (revision 0) +++ test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy (revision 0) @@ -0,0 +1,58 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.gui.mappaint + +import java.awt.Color; + +import org.junit.*; +import org.openstreetmap.josm.fixtures.JOSMFixture +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.StaticLabelCompositionStrategy +import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy +class MapCSSWithExtendedTextDirectivesTest { + + + @BeforeClass + public static void createJOSMFixture(){ + JOSMFixture.createUnitTestFixture().init() + } + + @Test + public void createAutoTextElement() { + Cascade c = new Cascade() + c.put("text", new Keyword("auto")) + + TextElement te = TextElement.create(c, Color.WHITE) + assert te.labelCompositionStrategy != null + assert te.labelCompositionStrategy instanceof DeriveLabelFromNameTagsCompositionStrategy + } + + @Test + public void createTextElementComposingTextFromTag() { + Cascade c = new Cascade() + c.put("text", new Keyword("auto")) + c.put("text-from-tag", "my_name") + + TextElement te = TextElement.create(c, Color.WHITE) + assert te.labelCompositionStrategy != null + assert te.labelCompositionStrategy instanceof TagLookupCompositionStrategy + assert te.labelCompositionStrategy.getDefaultLabelTag() == "my_name" + } + + @Test + public void createTextElementWithStaticText() { + Cascade c = new Cascade() + c.put("text","my static label") + + TextElement te = TextElement.create(c, Color.WHITE) + assert te.labelCompositionStrategy != null + assert te.labelCompositionStrategy instanceof StaticLabelCompositionStrategy + } + + @Test + public void createNullStrategy() { + Cascade c = new Cascade() + + TextElement te = TextElement.create(c, Color.WHITE) + assert te.labelCompositionStrategy == null + } +}