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