source: josm/trunk/src/org/openstreetmap/josm/tools/template_engine/ContextSwitchTemplate.java@ 12796

Last change on this file since 12796 was 12656, checked in by Don-vip, 7 years ago

see #15182 - move SearchCompiler from actions.search to data.osm.search

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools.template_engine;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.List;
10
11import org.openstreetmap.josm.data.osm.Node;
12import org.openstreetmap.josm.data.osm.OsmPrimitive;
13import org.openstreetmap.josm.data.osm.Relation;
14import org.openstreetmap.josm.data.osm.RelationMember;
15import org.openstreetmap.josm.data.osm.Way;
16import org.openstreetmap.josm.data.osm.search.SearchCompiler.And;
17import org.openstreetmap.josm.data.osm.search.SearchCompiler.Child;
18import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
19import org.openstreetmap.josm.data.osm.search.SearchCompiler.Not;
20import org.openstreetmap.josm.data.osm.search.SearchCompiler.Or;
21import org.openstreetmap.josm.data.osm.search.SearchCompiler.Parent;
22
23/**
24 * The context switch offers possibility to use tags of referenced primitive when constructing primitive name.
25 * @author jttt
26 * @since 4546
27 */
28public class ContextSwitchTemplate implements TemplateEntry {
29
30 private static final TemplateEngineDataProvider EMPTY_PROVIDER = new TemplateEngineDataProvider() {
31 @Override
32 public Object getTemplateValue(String name, boolean special) {
33 return null;
34 }
35
36 @Override
37 public Collection<String> getTemplateKeys() {
38 return Collections.emptyList();
39 }
40
41 @Override
42 public boolean evaluateCondition(Match condition) {
43 return false;
44 }
45 };
46
47 private abstract static class ContextProvider extends Match {
48 protected Match condition;
49
50 abstract List<OsmPrimitive> getPrimitives(OsmPrimitive root);
51 }
52
53 private static class ParentSet extends ContextProvider {
54 private final Match childCondition;
55
56 ParentSet(Match child) {
57 this.childCondition = child;
58 }
59
60 @Override
61 public boolean match(OsmPrimitive osm) {
62 throw new UnsupportedOperationException();
63 }
64
65 @Override
66 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
67 List<OsmPrimitive> children;
68 if (childCondition instanceof ContextProvider) {
69 children = ((ContextProvider) childCondition).getPrimitives(root);
70 } else if (childCondition.match(root)) {
71 children = Collections.singletonList(root);
72 } else {
73 children = Collections.emptyList();
74 }
75
76 List<OsmPrimitive> result = new ArrayList<>();
77 for (OsmPrimitive child: children) {
78 for (OsmPrimitive parent: child.getReferrers(true)) {
79 if (condition == null || condition.match(parent)) {
80 result.add(parent);
81 }
82 }
83 }
84 return result;
85 }
86 }
87
88 private static class ChildSet extends ContextProvider {
89 private final Match parentCondition;
90
91 ChildSet(Match parentCondition) {
92 this.parentCondition = parentCondition;
93 }
94
95 @Override
96 public boolean match(OsmPrimitive osm) {
97 throw new UnsupportedOperationException();
98 }
99
100 @Override
101 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
102 List<OsmPrimitive> parents;
103 if (parentCondition instanceof ContextProvider) {
104 parents = ((ContextProvider) parentCondition).getPrimitives(root);
105 } else if (parentCondition.match(root)) {
106 parents = Collections.singletonList(root);
107 } else {
108 parents = Collections.emptyList();
109 }
110 List<OsmPrimitive> result = new ArrayList<>();
111 for (OsmPrimitive p: parents) {
112 if (p instanceof Way) {
113 for (Node n: ((Way) p).getNodes()) {
114 if (condition != null && condition.match(n)) {
115 result.add(n);
116 }
117 result.add(n);
118 }
119 } else if (p instanceof Relation) {
120 for (RelationMember rm: ((Relation) p).getMembers()) {
121 if (condition != null && condition.match(rm.getMember())) {
122 result.add(rm.getMember());
123 }
124 }
125 }
126 }
127 return result;
128 }
129 }
130
131 private static class OrSet extends ContextProvider {
132 private final ContextProvider lhs;
133 private final ContextProvider rhs;
134
135 OrSet(ContextProvider lhs, ContextProvider rhs) {
136 this.lhs = lhs;
137 this.rhs = rhs;
138 }
139
140 @Override
141 public boolean match(OsmPrimitive osm) {
142 throw new UnsupportedOperationException();
143 }
144
145 @Override
146 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
147 List<OsmPrimitive> result = new ArrayList<>();
148 for (OsmPrimitive o: lhs.getPrimitives(root)) {
149 if (condition == null || condition.match(o)) {
150 result.add(o);
151 }
152 }
153 for (OsmPrimitive o: rhs.getPrimitives(root)) {
154 if (condition == null || (condition.match(o) && !result.contains(o))) {
155 result.add(o);
156 }
157 }
158 return result;
159 }
160 }
161
162 private static class AndSet extends ContextProvider {
163 private final ContextProvider lhs;
164 private final ContextProvider rhs;
165
166 AndSet(ContextProvider lhs, ContextProvider rhs) {
167 this.lhs = lhs;
168 this.rhs = rhs;
169 }
170
171 @Override
172 public boolean match(OsmPrimitive osm) {
173 throw new UnsupportedOperationException();
174 }
175
176 @Override
177 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
178 List<OsmPrimitive> result = new ArrayList<>();
179 List<OsmPrimitive> lhsList = lhs.getPrimitives(root);
180 for (OsmPrimitive o: rhs.getPrimitives(root)) {
181 if (lhsList.contains(o) && (condition == null || condition.match(o))) {
182 result.add(o);
183 }
184 }
185 return result;
186 }
187 }
188
189 private final ContextProvider context;
190 private final TemplateEntry template;
191
192 private static Match transform(Match m, int searchExpressionPosition) throws ParseError {
193 if (m instanceof Parent) {
194 Match child = transform(((Parent) m).getOperand(), searchExpressionPosition);
195 return new ParentSet(child);
196 } else if (m instanceof Child) {
197 Match parent = transform(((Child) m).getOperand(), searchExpressionPosition);
198 return new ChildSet(parent);
199 } else if (m instanceof And) {
200 Match lhs = transform(((And) m).getLhs(), searchExpressionPosition);
201 Match rhs = transform(((And) m).getRhs(), searchExpressionPosition);
202
203 if (lhs instanceof ContextProvider && rhs instanceof ContextProvider)
204 return new AndSet((ContextProvider) lhs, (ContextProvider) rhs);
205 else if (lhs instanceof ContextProvider) {
206 ContextProvider cp = (ContextProvider) lhs;
207 if (cp.condition == null) {
208 cp.condition = rhs;
209 } else {
210 cp.condition = new And(cp.condition, rhs);
211 }
212 return cp;
213 } else if (rhs instanceof ContextProvider) {
214 ContextProvider cp = (ContextProvider) rhs;
215 if (cp.condition == null) {
216 cp.condition = lhs;
217 } else {
218 cp.condition = new And(lhs, cp.condition);
219 }
220 return cp;
221 } else
222 return m;
223 } else if (m instanceof Or) {
224 Match lhs = transform(((Or) m).getLhs(), searchExpressionPosition);
225 Match rhs = transform(((Or) m).getRhs(), searchExpressionPosition);
226
227 if (lhs instanceof ContextProvider && rhs instanceof ContextProvider)
228 return new OrSet((ContextProvider) lhs, (ContextProvider) rhs);
229 else if (lhs instanceof ContextProvider)
230 throw new ParseError(
231 tr("Error in search expression on position {0} - right side of or(|) expression must return set of primitives",
232 searchExpressionPosition));
233 else if (rhs instanceof ContextProvider)
234 throw new ParseError(
235 tr("Error in search expression on position {0} - left side of or(|) expression must return set of primitives",
236 searchExpressionPosition));
237 else
238 return m;
239 } else if (m instanceof Not) {
240 Match match = transform(((Not) m).getMatch(), searchExpressionPosition);
241 if (match instanceof ContextProvider)
242 throw new ParseError(
243 tr("Error in search expression on position {0} - not(-) cannot be used in this context",
244 searchExpressionPosition));
245 else
246 return m;
247 } else
248 return m;
249 }
250
251 /**
252 * Constructs a new {@code ContextSwitchTemplate}.
253 * @param match match
254 * @param template template
255 * @param searchExpressionPosition search expression position
256 * @throws ParseError if a parse error occurs, or if the match transformation returns the same primitive
257 */
258 public ContextSwitchTemplate(Match match, TemplateEntry template, int searchExpressionPosition) throws ParseError {
259 Match m = transform(match, searchExpressionPosition);
260 if (!(m instanceof ContextProvider))
261 throw new ParseError(
262 tr("Error in search expression on position {0} - expression must return different then current primitive",
263 searchExpressionPosition));
264 else {
265 context = (ContextProvider) m;
266 }
267 this.template = template;
268 }
269
270 @Override
271 public void appendText(StringBuilder result, TemplateEngineDataProvider dataProvider) {
272 if (dataProvider instanceof OsmPrimitive) {
273 List<OsmPrimitive> primitives = context.getPrimitives((OsmPrimitive) dataProvider);
274 if (primitives != null && !primitives.isEmpty()) {
275 template.appendText(result, primitives.get(0));
276 }
277 }
278 template.appendText(result, EMPTY_PROVIDER);
279 }
280
281 @Override
282 public boolean isValid(TemplateEngineDataProvider dataProvider) {
283 if (dataProvider instanceof OsmPrimitive) {
284 List<OsmPrimitive> primitives = context.getPrimitives((OsmPrimitive) dataProvider);
285 if (primitives != null && !primitives.isEmpty()) {
286 return template.isValid(primitives.get(0));
287 }
288 }
289 return false;
290 }
291}
Note: See TracBrowser for help on using the repository browser.