001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint; 003 004import java.awt.geom.Area; 005import java.util.LinkedHashSet; 006import java.util.List; 007import java.util.Map; 008import java.util.Set; 009 010import org.openstreetmap.josm.data.osm.IPrimitive; 011import org.openstreetmap.josm.data.osm.Relation; 012import org.openstreetmap.josm.data.osm.Way; 013import org.openstreetmap.josm.data.osm.WaySegment; 014import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context; 015import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector; 016import org.openstreetmap.josm.tools.CheckParameterUtil; 017 018/** 019 * Environment is a data object to provide access to various "global" parameters. 020 * It is used during processing of MapCSS rules and for the generation of 021 * style elements. 022 */ 023public class Environment { 024 025 /** 026 * The primitive that is currently evaluated 027 */ 028 public IPrimitive osm; 029 030 /** 031 * The cascades that are currently evaluated 032 */ 033 public MultiCascade mc; 034 /** 035 * The current MapCSS layer 036 */ 037 public String layer; 038 /** 039 * The style source that is evaluated 040 */ 041 public StyleSource source; 042 private Context context = Context.PRIMITIVE; 043 044 /** 045 * The name of the default layer. It is used if no layer is specified in the MapCSS rule 046 */ 047 public static final String DEFAULT_LAYER = "default"; 048 049 /** 050 * If not null, this is the matching parent object if a condition or an expression 051 * is evaluated in a {@link LinkSelector} (within a child selector) 052 */ 053 public IPrimitive parent; 054 055 /** 056 * The same for parent selector. Only one of the 2 fields (parent or child) is not null in any environment. 057 */ 058 public IPrimitive child; 059 060 /** 061 * index of node in parent way or member in parent relation. Must be != null in LINK context. 062 */ 063 public Integer index; 064 065 /** 066 * count of nodes in parent way or members in parent relation. Must be != null in LINK context. 067 */ 068 public Integer count; 069 070 /** 071 * Set of matched children filled by ContainsFinder and CrossingFinder, null if nothing matched 072 */ 073 public Set<IPrimitive> children; 074 075 /** 076 * Crossing ways result from CrossingFinder, filled for incomplete ways/relations 077 */ 078 public Map<IPrimitive, Map<List<Way>, List<WaySegment>>> crossingWaysMap; 079 080 /** 081 * Intersection areas (only filled with CrossingFinder if children is not null) 082 */ 083 public Map<IPrimitive, Area> intersections; 084 085 /** 086 * Cache for multipolygon areas, can be null, used with CrossingFinder 087 */ 088 public Map<IPrimitive, Area> mpAreaCache; 089 090 /** 091 * Can be null, may contain primitives when surrounding objects of the primitives are tested 092 */ 093 public Set<IPrimitive> toMatchForSurrounding; 094 095 /** 096 * Creates a new uninitialized environment. 097 */ 098 public Environment() { 099 // environment can be initialized later through with* methods 100 } 101 102 /** 103 * Creates a new environment. 104 * @param osm OSM primitive 105 * @since 8415 106 * @since 13810 (signature) 107 */ 108 public Environment(IPrimitive osm) { 109 this.osm = osm; 110 } 111 112 /** 113 * Creates a new environment. 114 * @param osm OSM primitive 115 * @param mc multi cascade 116 * @param layer layer 117 * @param source style source 118 * @since 13810 (signature) 119 */ 120 public Environment(IPrimitive osm, MultiCascade mc, String layer, StyleSource source) { 121 this.osm = osm; 122 this.mc = mc; 123 this.layer = layer; 124 this.source = source; 125 } 126 127 /** 128 * Creates a clone of the environment {@code other}. 129 * 130 * @param other the other environment. Must not be null. 131 * @throws IllegalArgumentException if {@code param} is {@code null} 132 */ 133 public Environment(Environment other) { 134 CheckParameterUtil.ensureParameterNotNull(other); 135 this.osm = other.osm; 136 this.mc = other.mc; 137 this.layer = other.layer; 138 this.parent = other.parent; 139 this.child = other.child; 140 this.source = other.source; 141 this.index = other.index; 142 this.count = other.count; 143 this.context = other.getContext(); 144 this.children = other.children == null ? null : new LinkedHashSet<>(other.children); 145 this.intersections = other.intersections; 146 this.crossingWaysMap = other.crossingWaysMap; 147 this.mpAreaCache = other.mpAreaCache; 148 this.toMatchForSurrounding = other.toMatchForSurrounding; 149 } 150 151 /** 152 * Creates a clone of this environment, with the specified primitive. 153 * @param osm OSM primitive 154 * @return A clone of this environment, with the specified primitive 155 * @see #osm 156 * @since 13810 (signature) 157 */ 158 public Environment withPrimitive(IPrimitive osm) { 159 Environment e = new Environment(this); 160 e.osm = osm; 161 return e; 162 } 163 164 /** 165 * Creates a clone of this environment, with the specified parent. 166 * @param parent the matching parent object 167 * @return A clone of this environment, with the specified parent 168 * @see #parent 169 * @since 13810 (signature) 170 */ 171 public Environment withParent(IPrimitive parent) { 172 Environment e = new Environment(this); 173 e.parent = parent; 174 return e; 175 } 176 177 /** 178 * Creates a clone of this environment, with the specified parent, index, and context set to {@link Context#LINK}. 179 * @param parent the matching parent object 180 * @param index index of node in parent way or member in parent relation 181 * @param count count of nodes in parent way or members in parent relation 182 * @return A clone of this environment, with the specified parent, index, and context set to {@link Context#LINK} 183 * @see #parent 184 * @see #index 185 * @since 6175 186 * @since 13810 (signature) 187 */ 188 public Environment withParentAndIndexAndLinkContext(IPrimitive parent, int index, int count) { 189 Environment e = new Environment(this); 190 e.parent = parent; 191 e.index = index; 192 e.count = count; 193 e.context = Context.LINK; 194 return e; 195 } 196 197 /** 198 * Creates a clone of this environment, with the specified child. 199 * @param child the matching child object 200 * @return A clone of this environment, with the specified child 201 * @see #child 202 * @since 13810 (signature) 203 */ 204 public Environment withChild(IPrimitive child) { 205 Environment e = new Environment(this); 206 e.child = child; 207 return e; 208 } 209 210 /** 211 * Creates a clone of this environment, with the specified child, index, and context set to {@link Context#LINK}. 212 * @param child the matching child object 213 * @param index index of node in parent way or member in parent relation 214 * @param count count of nodes in parent way or members in parent relation 215 * @return A clone of this environment, with the specified child, index, and context set to {@code Context#LINK} 216 * @see #child 217 * @see #index 218 * @since 6175 219 * @since 13810 (signature) 220 */ 221 public Environment withChildAndIndexAndLinkContext(IPrimitive child, int index, int count) { 222 Environment e = new Environment(this); 223 e.child = child; 224 e.index = index; 225 e.count = count; 226 e.context = Context.LINK; 227 return e; 228 } 229 230 /** 231 * Creates a clone of this environment, with the specified index. 232 * @param index index of node in parent way or member in parent relation 233 * @param count count of nodes in parent way or members in parent relation 234 * @return A clone of this environment, with the specified index 235 * @see #index 236 */ 237 public Environment withIndex(int index, int count) { 238 Environment e = new Environment(this); 239 e.index = index; 240 e.count = count; 241 return e; 242 } 243 244 /** 245 * Creates a clone of this environment, with the specified {@link Context}. 246 * @param context context 247 * @return A clone of this environment, with the specified {@code Context} 248 */ 249 public Environment withContext(Context context) { 250 Environment e = new Environment(this); 251 e.context = context == null ? Context.PRIMITIVE : context; 252 return e; 253 } 254 255 /** 256 * Creates a clone of this environment, with context set to {@link Context#LINK}. 257 * @return A clone of this environment, with context set to {@code Context#LINK} 258 */ 259 public Environment withLinkContext() { 260 Environment e = new Environment(this); 261 e.context = Context.LINK; 262 return e; 263 } 264 265 /** 266 * Determines if the context of this environment is {@link Context#LINK}. 267 * @return {@code true} if the context of this environment is {@code Context#LINK}, {@code false} otherwise 268 */ 269 public boolean isLinkContext() { 270 return Context.LINK == context; 271 } 272 273 /** 274 * Determines if this environment has a relation as parent. 275 * @return {@code true} if this environment has a relation as parent, {@code false} otherwise 276 * @see #parent 277 */ 278 public boolean hasParentRelation() { 279 return parent instanceof Relation; 280 } 281 282 /** 283 * Replies the current context. 284 * 285 * @return the current context 286 */ 287 public Context getContext() { 288 return context == null ? Context.PRIMITIVE : context; 289 } 290 291 /** 292 * Gets the role of the matching primitive in the relation 293 * @return The role 294 */ 295 public String getRole() { 296 if (getContext() == Context.PRIMITIVE) 297 return null; 298 299 if (parent instanceof Relation) 300 return ((Relation) parent).getMember(index).getRole(); 301 if (child != null && osm instanceof Relation) 302 return ((Relation) osm).getMember(index).getRole(); 303 return null; 304 } 305 306 /** 307 * Clears all matching context information 308 * @return this 309 */ 310 public Environment clearSelectorMatchingInformation() { 311 parent = null; 312 child = null; 313 index = null; 314 count = null; 315 children = null; 316 intersections = null; 317 crossingWaysMap = null; 318 return this; 319 } 320 321 /** 322 * Gets the current cascade for the current layer of this environment 323 * @return The cascade 324 */ 325 public Cascade getCascade() { 326 return getCascade(null); 327 } 328 329 /** 330 * Gets the current cascade for a given layer 331 * @param layer The layer to use, <code>null</code> to use the layer of the {@link Environment} 332 * @return The cascade 333 */ 334 public Cascade getCascade(String layer) { 335 return mc == null ? null : mc.getCascade(layer == null ? this.layer : layer); 336 } 337}