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