001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint; 003 004import org.openstreetmap.josm.data.osm.OsmPrimitive; 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 public OsmPrimitive osm; 018 019 public MultiCascade mc; 020 public String layer; 021 public StyleSource source; 022 private Context context = Context.PRIMITIVE; 023 public static final String DEFAULT_LAYER = "default"; 024 025 /** 026 * If not null, this is the matching parent object if a condition or an expression 027 * is evaluated in a {@link LinkSelector} (within a child selector) 028 */ 029 public OsmPrimitive parent; 030 031 /** 032 * The same for parent selector. Only one of the 2 fields (parent or child) is not null in any environment. 033 */ 034 public OsmPrimitive child; 035 036 /** 037 * index of node in parent way or member in parent relation. Must be != null in LINK context. 038 */ 039 public Integer index = null; 040 041 /** 042 * Creates a new uninitialized environment. 043 */ 044 public Environment() {} 045 046 /** 047 * Creates a new environment. 048 */ 049 public Environment(OsmPrimitive osm, MultiCascade mc, String layer, StyleSource source) { 050 this.osm = osm; 051 this.mc = mc; 052 this.layer = layer; 053 this.source = source; 054 } 055 056 /** 057 * Creates a clone of the environment {@code other}. 058 * 059 * @param other the other environment. Must not be null. 060 * @throws IllegalArgumentException if {@code param} is {@code null} 061 */ 062 public Environment(Environment other) throws IllegalArgumentException { 063 CheckParameterUtil.ensureParameterNotNull(other); 064 this.osm = other.osm; 065 this.mc = other.mc; 066 this.layer = other.layer; 067 this.parent = other.parent; 068 this.child = other.child; 069 this.source = other.source; 070 this.index = other.index; 071 this.context = other.getContext(); 072 } 073 074 /** 075 * Creates a clone of this environment, with the specified primitive. 076 * @return A clone of this environment, with the specified primitive 077 * @see #osm 078 */ 079 public Environment withPrimitive(OsmPrimitive osm) { 080 Environment e = new Environment(this); 081 e.osm = osm; 082 return e; 083 } 084 085 /** 086 * Creates a clone of this environment, with the specified parent. 087 * @param parent the matching parent object 088 * @return A clone of this environment, with the specified parent 089 * @see #parent 090 */ 091 public Environment withParent(OsmPrimitive parent) { 092 Environment e = new Environment(this); 093 e.parent = parent; 094 return e; 095 } 096 097 /** 098 * Creates a clone of this environment, with the specified parent, index, and context set to {@link Context#LINK}. 099 * @param parent the matching parent object 100 * @param index index of node in parent way or member in parent relation 101 * @return A clone of this environment, with the specified parent, index, and context set to {@link Context#LINK} 102 * @since 6175 103 * @see #parent 104 * @see #index 105 */ 106 public Environment withParentAndIndexAndLinkContext(OsmPrimitive parent, int index) { 107 Environment e = new Environment(this); 108 e.parent = parent; 109 e.index = index; 110 e.context = Context.LINK; 111 return e; 112 } 113 114 /** 115 * Creates a clone of this environment, with the specified child. 116 * @param child the matching child object 117 * @return A clone of this environment, with the specified child 118 * @see #child 119 */ 120 public Environment withChild(OsmPrimitive child) { 121 Environment e = new Environment(this); 122 e.child = child; 123 return e; 124 } 125 126 /** 127 * Creates a clone of this environment, with the specified child, index, and context set to {@link Context#LINK}. 128 * @param child the matching child object 129 * @param index index of node in parent way or member in parent relation 130 * @return A clone of this environment, with the specified child, index, and context set to {@code Context#LINK} 131 * @since 6175 132 * @see #child 133 * @see #index 134 */ 135 public Environment withChildAndIndexAndLinkContext(OsmPrimitive child, int index) { 136 Environment e = new Environment(this); 137 e.child = child; 138 e.index = index; 139 e.context = Context.LINK; 140 return e; 141 } 142 143 /** 144 * Creates a clone of this environment, with the specified index. 145 * @param index index of node in parent way or member in parent relation 146 * @return A clone of this environment, with the specified index 147 * @see #index 148 */ 149 public Environment withIndex(int index) { 150 Environment e = new Environment(this); 151 e.index = index; 152 return e; 153 } 154 155 /** 156 * Creates a clone of this environment, with the specified {@link Context}. 157 * @return A clone of this environment, with the specified {@code Context} 158 */ 159 public Environment withContext(Context context) { 160 Environment e = new Environment(this); 161 e.context = context == null ? Context.PRIMITIVE : context; 162 return e; 163 } 164 165 /** 166 * Creates a clone of this environment, with context set to {@link Context#LINK}. 167 * @return A clone of this environment, with context set to {@code Context#LINK} 168 */ 169 public Environment withLinkContext() { 170 Environment e = new Environment(this); 171 e.context = Context.LINK; 172 return e; 173 } 174 175 /** 176 * Determines if the context of this environment is {@link Context#LINK}. 177 * @return {@code true} if the context of this environment is {@code Context#LINK}, {@code false} otherwise 178 */ 179 public boolean isLinkContext() { 180 return Context.LINK.equals(context); 181 } 182 183 /** 184 * Determines if this environment has a relation as parent. 185 * @return {@code true} if this environment has a relation as parent, {@code false} otherwise 186 * @see #parent 187 */ 188 public boolean hasParentRelation() { 189 return parent instanceof Relation; 190 } 191 192 /** 193 * Replies the current context. 194 * 195 * @return the current context 196 */ 197 public Context getContext() { 198 return context == null ? Context.PRIMITIVE : context; 199 } 200 201 public String getRole() { 202 if (getContext().equals(Context.PRIMITIVE)) 203 return null; 204 205 if (parent instanceof Relation) 206 return ((Relation) parent).getMember(index).getRole(); 207 if (child != null && osm instanceof Relation) 208 return ((Relation) osm).getMember(index).getRole(); 209 return null; 210 } 211 212 public void clearSelectorMatchingInformation() { 213 parent = null; 214 child = null; 215 index = null; 216 } 217 218 public Cascade getCascade(String layer) { 219 return mc == null ? null : mc.getCascade(layer == null ? this.layer : layer); 220 } 221}