Changeset 4546 in josm


Ignore:
Timestamp:
Oct 29, 2011 9:01:30 AM (20 months ago)
Author:
jttt
Message:

Extend name templates with context switch - possibility to use tags of referenced primitive when constructing primitive name

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java

    r4377 r4546  
    6969        protected boolean existsMatch(Collection<? extends OsmPrimitive> primitives) { 
    7070            for (OsmPrimitive p : primitives) { 
    71                 if (match(p)) { 
     71                if (match(p)) 
    7272                    return true; 
    73                 } 
    7473            } 
    7574            return false; 
     
    8180        protected boolean forallMatch(Collection<? extends OsmPrimitive> primitives) { 
    8281            for (OsmPrimitive p : primitives) { 
    83                 if (!match(p)) { 
     82                if (!match(p)) 
    8483                    return false; 
    85                 } 
    8684            } 
    8785            return true; 
     
    110108        } 
    111109        @Override public String toString() {return "!"+match;} 
     110        public Match getMatch() { 
     111            return match; 
     112        } 
    112113    } 
    113114 
     
    130131    } 
    131132 
    132     private static class And extends Match { 
    133         private Match lhs; 
    134         private Match rhs; 
     133    public static class And extends Match { 
     134        private final Match lhs; 
     135        private final Match rhs; 
    135136        public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;} 
    136137        @Override public boolean match(OsmPrimitive osm) { 
     
    138139        } 
    139140        @Override public String toString() {return lhs+" && "+rhs;} 
    140     } 
    141  
    142     private static class Or extends Match { 
    143         private Match lhs; 
    144         private Match rhs; 
     141        public Match getLhs() { 
     142            return lhs; 
     143        } 
     144        public Match getRhs() { 
     145            return rhs; 
     146        } 
     147    } 
     148 
     149    public static class Or extends Match { 
     150        private final Match lhs; 
     151        private final Match rhs; 
    145152        public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;} 
    146153        @Override public boolean match(OsmPrimitive osm) { 
     
    148155        } 
    149156        @Override public String toString() {return lhs+" || "+rhs;} 
     157        public Match getLhs() { 
     158            return lhs; 
     159        } 
     160        public Match getRhs() { 
     161            return rhs; 
     162        } 
    150163    } 
    151164 
     
    552565        public boolean match(OsmPrimitive osm) { 
    553566            Integer count = getCount(osm); 
    554             if (count == null) { 
     567            if (count == null) 
    555568                return false; 
    556             } else { 
     569            else 
    557570                return (count >= minCount) && (count <= maxCount); 
    558             } 
    559571        } 
    560572 
     
    575587        @Override 
    576588        protected Integer getCount(OsmPrimitive osm) { 
    577             if (!(osm instanceof Way)) { 
     589            if (!(osm instanceof Way)) 
    578590                return null; 
    579             } else { 
     591            else 
    580592                return ((Way) osm).getNodesCount(); 
    581             } 
    582593        } 
    583594 
     
    649660    } 
    650661 
    651     private static class Parent extends Match { 
    652         private Match child; 
    653         public Parent(Match m) { child = m; } 
     662    public static class Parent extends Match { 
     663        private final Match child; 
     664        public Parent(Match m) { 
     665            if (m == null) { 
     666                // "parent" (null) should mean the same as "parent()" 
     667                // (Always). I.e. match everything 
     668                child = new Always(); 
     669            } else { 
     670                child = m; 
     671            } 
     672        } 
    654673        @Override public boolean match(OsmPrimitive osm) { 
    655674            boolean isParent = false; 
    656  
    657             // "parent" (null) should mean the same as "parent()" 
    658             // (Always). I.e. match everything 
    659             if (child == null) { 
    660                 child = new Always(); 
    661             } 
    662675 
    663676            if (osm instanceof Way) { 
     
    673686        } 
    674687        @Override public String toString() {return "parent(" + child + ")";} 
    675     } 
    676  
    677     private static class Child extends Match { 
     688        public Match getChild() { 
     689            return child; 
     690        } 
     691    } 
     692 
     693    public static class Child extends Match { 
    678694        private final Match parent; 
    679695 
     
    696712        } 
    697713        @Override public String toString() {return "child(" + parent + ")";} 
    698     } 
    699      
     714 
     715        public Match getParent() { 
     716            return parent; 
     717        } 
     718    } 
     719 
    700720    /** 
    701721     * Matches on the area of a closed way. 
    702      *  
     722     * 
    703723     * @author Ole Jørgen Brønner 
    704724     */ 
     
    711731        @Override 
    712732        protected Integer getCount(OsmPrimitive osm) { 
    713             if (!(osm instanceof Way && ((Way) osm).isClosed())) { 
     733            if (!(osm instanceof Way && ((Way) osm).isClosed())) 
    714734                return null; 
    715             } 
    716735            Way way = (Way) osm; 
    717736            return (int) Geometry.closedWayArea(way); 
     
    743762        @Override 
    744763        public boolean match(OsmPrimitive osm) { 
    745             if (!osm.isUsable()) { 
     764            if (!osm.isUsable()) 
    746765                return false; 
    747             } else if (osm instanceof Node) { 
     766            else if (osm instanceof Node) 
    748767                return bounds.contains(((Node) osm).getCoor()); 
    749             } else if (osm instanceof Way) { 
     768            else if (osm instanceof Way) { 
    750769                Collection<Node> nodes = ((Way) osm).getNodes(); 
    751770                return all ? forallMatch(nodes) : existsMatch(nodes); 
     
    753772                Collection<OsmPrimitive> primitives = ((Relation) osm).getMemberPrimitives(); 
    754773                return all ? forallMatch(primitives) : existsMatch(primitives); 
    755             } else { 
     774            } else 
    756775                return false; 
    757             } 
    758776        } 
    759777    } 
     
    799817 
    800818    public static Match compile(String searchStr, boolean caseSensitive, boolean regexSearch) 
    801     throws ParseError { 
     819            throws ParseError { 
    802820        return new SearchCompiler(caseSensitive, regexSearch, 
    803821                new PushbackTokenizer( 
  • trunk/src/org/openstreetmap/josm/tools/template_engine/ParseError.java

    r4282 r4546  
    2121    } 
    2222 
    23     public ParseError(org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) { 
    24         super(tr("Error while parsing search expression"), e); 
     23    public ParseError(int position, org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) { 
     24        super(tr("Error while parsing search expression on position {0}", position), e); 
     25        unexpectedToken = null; 
     26    } 
     27 
     28    public ParseError(String message) { 
     29        super(message); 
    2530        unexpectedToken = null; 
    2631    } 
     
    2934        return unexpectedToken; 
    3035    } 
     36 
     37    public static ParseError unexpectedChar(char expected, char found, int position) { 
     38        return new ParseError(tr("Unexpected char on {0}. Expected {1} found {2}", position, expected, found)); 
     39    } 
    3140} 
  • trunk/src/org/openstreetmap/josm/tools/template_engine/TemplateParser.java

    r4282 r4546  
    22package org.openstreetmap.josm.tools.template_engine; 
    33 
     4 
     5import static org.openstreetmap.josm.tools.I18n.tr; 
    46 
    57import java.util.ArrayList; 
     
    911 
    1012import org.openstreetmap.josm.actions.search.SearchCompiler; 
     13import org.openstreetmap.josm.actions.search.SearchCompiler.Match; 
    1114import org.openstreetmap.josm.tools.template_engine.Tokenizer.Token; 
    1215import org.openstreetmap.josm.tools.template_engine.Tokenizer.TokenType; 
     
    4245            if (token.getType() == TokenType.CONDITION_START) { 
    4346                templateEntry = parseCondition(); 
     47            } else if (token.getType() == TokenType.CONTEXT_SWITCH_START) { 
     48                templateEntry = parseContextSwitch(); 
    4449            } else if (token.getType() == TokenType.VARIABLE_START) { 
    4550                templateEntry = parseVariable(); 
     
    6368    } 
    6469 
    65     private void skipWhitespace() { 
     70    private void skipWhitespace() throws ParseError { 
    6671        Token token = tokenizer.lookAhead(); 
    6772        if (token.getType() == TokenType.TEXT && token.getText().trim().isEmpty()) { 
     
    7681 
    7782            TemplateEntry condition; 
    78             String searchExpression = tokenizer.skip('\''); 
     83            Token searchExpression = tokenizer.skip('\''); 
    7984            check(TokenType.APOSTROPHE); 
    8085            condition = parseExpression(CONDITION_WITH_APOSTROPHES_END_TOKENS); 
    8186            check(TokenType.APOSTROPHE); 
    82             if (searchExpression.trim().isEmpty()) { 
     87            if (searchExpression.getText().trim().isEmpty()) { 
    8388                result.getEntries().add(condition); 
    8489            } else { 
    8590                try { 
    86                     result.getEntries().add(new SearchExpressionCondition(SearchCompiler.compile(searchExpression, false, false), condition)); 
     91                    result.getEntries().add(new SearchExpressionCondition(SearchCompiler.compile(searchExpression.getText(), false, false), condition)); 
    8792                } catch (org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) { 
    88                     throw new ParseError(e); 
     93                    throw new ParseError(searchExpression.getPosition(), e); 
    8994                } 
    9095            } 
     
    101106    } 
    102107 
     108    private TemplateEntry parseContextSwitch() throws ParseError { 
     109 
     110        check(TokenType.CONTEXT_SWITCH_START); 
     111        Token searchExpression = tokenizer.skip('\''); 
     112        check(TokenType.APOSTROPHE); 
     113        TemplateEntry template = parseExpression(CONDITION_WITH_APOSTROPHES_END_TOKENS); 
     114        check(TokenType.APOSTROPHE); 
     115        ContextSwitchTemplate result; 
     116        if (searchExpression.getText().trim().isEmpty()) 
     117            throw new ParseError(tr("Expected search expression")); 
     118        else { 
     119            try { 
     120                Match match = SearchCompiler.compile(searchExpression.getText(), false, false); 
     121                result = new ContextSwitchTemplate(match, template, searchExpression.getPosition()); 
     122            } catch (org.openstreetmap.josm.actions.search.SearchCompiler.ParseError e) { 
     123                throw new ParseError(searchExpression.getPosition(), e); 
     124            } 
     125        } 
     126        skipWhitespace(); 
     127        check(TokenType.END); 
     128        return result; 
     129    } 
     130 
    103131} 
  • trunk/src/org/openstreetmap/josm/tools/template_engine/Tokenizer.java

    r4282 r4546  
    4040    } 
    4141 
    42     public enum TokenType { CONDITION_START, VARIABLE_START, END, PIPE, APOSTROPHE, TEXT, EOF } 
     42    public enum TokenType { CONDITION_START, VARIABLE_START, CONTEXT_SWITCH_START, END, PIPE, APOSTROPHE, TEXT, EOF } 
    4343 
    4444    private final List<Character> specialCharaters = Arrays.asList(new Character[] {'$', '?', '{', '}', '|', '\''}); 
     
    6464    } 
    6565 
    66     public Token nextToken() { 
     66    public Token nextToken() throws ParseError { 
    6767        if (currentToken != null) { 
    6868            Token result = currentToken; 
     
    7979            getChar(); 
    8080            return new Token(TokenType.VARIABLE_START, position); 
    81  
    8281        case '?': 
    8382            getChar(); 
     
    8685                return new Token(TokenType.CONDITION_START, position); 
    8786            } else 
    88                 throw new AssertionError(); 
     87                throw ParseError.unexpectedChar('{', (char)c, position); 
     88        case '!': 
     89            getChar(); 
     90            if (c == '{') { 
     91                getChar(); 
     92                return new Token(TokenType.CONTEXT_SWITCH_START, position); 
     93            } else 
     94                throw ParseError.unexpectedChar('{', (char)c, position); 
    8995        case '}': 
    9096            getChar(); 
     
    111117    } 
    112118 
    113     public Token lookAhead() { 
     119    public Token lookAhead() throws ParseError { 
    114120        if (currentToken == null) { 
    115121            currentToken = nextToken(); 
     
    118124    } 
    119125 
    120     public String skip(char lastChar) { 
     126    public Token skip(char lastChar) { 
    121127        currentToken = null; 
     128        int position = index; 
    122129        StringBuilder result = new StringBuilder(); 
    123130        while (c != lastChar && c != -1) { 
     
    128135            getChar(); 
    129136        } 
    130         return result.toString(); 
     137        return new Token(TokenType.TEXT, position, result.toString()); 
    131138    } 
    132139 
  • trunk/test/unit/org/openstreetmap/josm/tools/template_engine/TemplateEngineTest.java

    r4431 r4546  
    1313import org.openstreetmap.josm.actions.search.SearchCompiler.Match; 
    1414import org.openstreetmap.josm.data.Preferences; 
     15import org.openstreetmap.josm.data.osm.DatasetFactory; 
     16import org.openstreetmap.josm.data.osm.Node; 
    1517import org.openstreetmap.josm.data.osm.Relation; 
     18import org.openstreetmap.josm.data.osm.RelationMember; 
    1619import org.unitils.reflectionassert.ReflectionAssert; 
    1720 
     
    150153        templateEntry.appendText(sb, dataProvider); 
    151154        Assert.assertEquals("waypointNameulocalNameuspecialKey", sb.toString()); 
    152  
    153     } 
    154  
     155    } 
     156 
     157    @Test 
     158    public void testSearchExpression() throws Exception { 
     159        Match match = compile("(parent type=type1 type=parent1) | (parent type=type2 type=parent2)"); 
     160        //"parent(type=type1,type=parent1) | (parent(type=type2,type=parent2)" 
     161        //TODO 
     162    } 
     163 
     164    @Test 
     165    public void testSwitchContext() throws Exception { 
     166        TemplateParser parser = new TemplateParser("!{parent() type=parent2 '{name}'}"); 
     167        DatasetFactory ds = new DatasetFactory(); 
     168        Relation parent1 = ds.addRelation(1); 
     169        parent1.put("type", "parent1"); 
     170        parent1.put("name", "name_parent1"); 
     171        Relation parent2 = ds.addRelation(2); 
     172        parent2.put("type", "parent2"); 
     173        parent2.put("name", "name_parent2"); 
     174        Node child = ds.addNode(1); 
     175        parent1.addMember(new RelationMember("", child)); 
     176        parent2.addMember(new RelationMember("", child)); 
     177 
     178        StringBuilder sb = new StringBuilder(); 
     179        TemplateEntry entry = parser.parse(); 
     180        entry.appendText(sb, child); 
     181 
     182        Assert.assertEquals("name_parent2", sb.toString()); 
     183    } 
     184 
     185    @Test 
     186    public void testSetOr() throws ParseError { 
     187        TemplateParser parser = new TemplateParser("!{(parent(type=type1) type=parent1) | (parent type=type2 type=parent2) '{name}'}"); 
     188        DatasetFactory ds = new DatasetFactory(); 
     189        Relation parent1 = ds.addRelation(1); 
     190        parent1.put("type", "parent1"); 
     191        parent1.put("name", "name_parent1"); 
     192        Relation parent2 = ds.addRelation(2); 
     193        parent2.put("type", "parent2"); 
     194        parent2.put("name", "name_parent2"); 
     195        Node child1 = ds.addNode(1); 
     196        child1.put("type", "type1"); 
     197        parent1.addMember(new RelationMember("", child1)); 
     198        parent2.addMember(new RelationMember("", child1)); 
     199        Node child2 = ds.addNode(2); 
     200        child2.put("type", "type2"); 
     201        parent1.addMember(new RelationMember("", child2)); 
     202        parent2.addMember(new RelationMember("", child2)); 
     203 
     204 
     205        StringBuilder sb = new StringBuilder(); 
     206        TemplateEntry entry = parser.parse(); 
     207        entry.appendText(sb, child1); 
     208        entry.appendText(sb, child2); 
     209 
     210        Assert.assertEquals("name_parent1name_parent2", sb.toString()); 
     211    } 
     212 
     213    @Test 
     214    public void testMultilevel() throws ParseError { 
     215        TemplateParser parser = new TemplateParser("!{(parent(parent(type=type1)) type=grandparent) | (parent type=type2 type=parent2) '{name}'}"); 
     216        DatasetFactory ds = new DatasetFactory(); 
     217        Relation parent1 = ds.addRelation(1); 
     218        parent1.put("type", "parent1"); 
     219        parent1.put("name", "name_parent1"); 
     220        Relation parent2 = ds.addRelation(2); 
     221        parent2.put("type", "parent2"); 
     222        parent2.put("name", "name_parent2"); 
     223        Node child1 = ds.addNode(1); 
     224        child1.put("type", "type1"); 
     225        parent1.addMember(new RelationMember("", child1)); 
     226        parent2.addMember(new RelationMember("", child1)); 
     227        Node child2 = ds.addNode(2); 
     228        child2.put("type", "type2"); 
     229        parent1.addMember(new RelationMember("", child2)); 
     230        parent2.addMember(new RelationMember("", child2)); 
     231        Relation grandParent = ds.addRelation(3); 
     232        grandParent.put("type", "grandparent"); 
     233        grandParent.put("name", "grandparent_name"); 
     234        grandParent.addMember(new RelationMember("", parent1)); 
     235 
     236 
     237        StringBuilder sb = new StringBuilder(); 
     238        TemplateEntry entry = parser.parse(); 
     239        entry.appendText(sb, child1); 
     240        entry.appendText(sb, child2); 
     241 
     242        Assert.assertEquals("grandparent_namename_parent2", sb.toString()); 
     243    } 
     244 
     245    @Test(expected=ParseError.class) 
     246    public void testErrorsNot() throws ParseError { 
     247        TemplateParser parser = new TemplateParser("!{-parent() '{name}'}"); 
     248        parser.parse(); 
     249    } 
     250 
     251    @Test(expected=ParseError.class) 
     252    public void testErrorOr() throws ParseError { 
     253        TemplateParser parser = new TemplateParser("!{parent() | type=type1 '{name}'}"); 
     254        parser.parse(); 
     255    } 
     256 
     257    @Test 
     258    public void testChild() throws ParseError { 
     259        TemplateParser parser = new TemplateParser("!{((child(type=type1) type=child1) | (child type=type2 type=child2)) type=child2 '{name}'}"); 
     260        DatasetFactory ds = new DatasetFactory(); 
     261        Relation parent1 = ds.addRelation(1); 
     262        parent1.put("type", "type1"); 
     263        Relation parent2 = ds.addRelation(2); 
     264        parent2.put("type", "type2"); 
     265        Node child1 = ds.addNode(1); 
     266        child1.put("type", "child1"); 
     267        child1.put("name", "child1"); 
     268        parent1.addMember(new RelationMember("", child1)); 
     269        parent2.addMember(new RelationMember("", child1)); 
     270        Node child2 = ds.addNode(2); 
     271        child2.put("type", "child2"); 
     272        child2.put("name", "child2"); 
     273        parent1.addMember(new RelationMember("", child2)); 
     274        parent2.addMember(new RelationMember("", child2)); 
     275 
     276 
     277        StringBuilder sb = new StringBuilder(); 
     278        TemplateEntry entry = parser.parse(); 
     279        entry.appendText(sb, parent2); 
     280 
     281        Assert.assertEquals("child2", sb.toString()); 
     282    } 
    155283 
    156284} 
Note: See TracChangeset for help on using the changeset viewer.