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