- Timestamp:
- 2009-12-16T21:27:28+01:00 (15 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java
r1641 r2645 3 3 4 4 import java.io.IOException; 5 import java.io.PushbackReader; 6 import java.util.LinkedList; 5 import java.io.Reader; 6 7 import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError; 7 8 8 9 public class PushbackTokenizer { 9 private PushbackReader search;10 private final Reader search; 10 11 11 private LinkedList<String> pushBackBuf = new LinkedList<String>(); 12 private Token currentToken; 13 private String currentText; 14 private int c; 12 15 13 public PushbackTokenizer( PushbackReader search) {16 public PushbackTokenizer(Reader search) { 14 17 this.search = search; 18 getChar(); 19 } 20 21 public enum Token {NOT, OR, LEFT_PARENT, RIGHT_PARENT, COLON, EQUALS, KEY, EOF} 22 23 private void getChar() { 24 try { 25 c = search.read(); 26 } catch (IOException e) { 27 throw new RuntimeException(e.getMessage(), e); 28 } 15 29 } 16 30 … … 23 37 * @return The next token in the stream. 24 38 */ 25 public String nextToken() { 26 if (!pushBackBuf.isEmpty()) { 27 return pushBackBuf.removeLast(); 39 public Token nextToken() { 40 if (currentToken != null) { 41 Token result = currentToken; 42 currentToken = null; 43 return result; 28 44 } 29 45 30 try { 31 int next; 32 char c = ' '; 33 while (c == ' ' || c == '\t' || c == '\n') { 34 next = search.read(); 35 if (next == -1) 36 return null; 37 c = (char)next; 46 while (Character.isWhitespace(c)) { 47 getChar(); 48 } 49 switch (c) { 50 case -1: 51 getChar(); 52 return Token.EOF; 53 case ':': 54 getChar(); 55 return Token.COLON; 56 case '=': 57 getChar(); 58 return Token.EQUALS; 59 case '-': 60 getChar(); 61 return Token.NOT; 62 case '(': 63 getChar(); 64 return Token.LEFT_PARENT; 65 case ')': 66 getChar(); 67 return Token.RIGHT_PARENT; 68 case '|': 69 getChar(); 70 return Token.OR; 71 case '"': 72 { 73 StringBuilder s = new StringBuilder(); 74 while (c != -1 && c != '"') { 75 s.append((char)c); 76 getChar(); 38 77 } 39 StringBuilder s; 40 switch (c) { 41 case ':': 42 case '=': 43 next = search.read(); 44 if (next == -1 || next == ' ' || next == '\t') { 45 pushBack(" "); 46 } else { 47 search.unread(next); 48 } 49 return String.valueOf(c); 50 case '-': 51 return "-"; 52 case '(': 53 return "("; 54 case ')': 55 return ")"; 56 case '|': 57 return "|"; 58 case '"': 59 s = new StringBuilder(" "); 60 for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read()) 61 s.append((char)nc); 62 return s.toString(); 63 default: 64 s = new StringBuilder(); 65 for (;;) { 66 s.append(c); 67 next = search.read(); 68 if (next == -1) { 69 if (s.toString().equals("OR")) 70 return "|"; 71 return " "+s.toString(); 72 } 73 c = (char)next; 74 if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|' || c == '=') { 75 search.unread(next); 76 if (s.toString().equals("OR")) 77 return "|"; 78 return " "+s.toString(); 79 } 78 getChar(); 79 currentText = s.toString(); 80 return Token.KEY; 81 } 82 default: 83 { 84 StringBuilder s = new StringBuilder(); 85 while (!(c == -1 || Character.isWhitespace(c) || c == '"'|| c == ':' || c == '(' || c == ')' || c == '|' || c == '=')) { 86 s.append((char)c); 87 getChar(); 80 88 } 81 } 82 } catch (IOException e) { 83 throw new RuntimeException(e.getMessage(), e); 89 currentText = s.toString(); 90 if ("or".equals(currentText)) 91 return Token.OR; 92 else 93 return Token.KEY; 94 } 84 95 } 85 96 } 86 97 87 public boolean readIfEqual( String tok) {88 StringnextTok = nextToken();89 if (nextTok == null ? tok == null : nextTok .equals(tok))98 public boolean readIfEqual(Token token) { 99 Token nextTok = nextToken(); 100 if (nextTok == null ? token == null : nextTok == token) 90 101 return true; 91 pushBack(nextTok);102 currentToken = nextTok; 92 103 return false; 93 104 } 94 105 95 106 public String readText() { 96 StringnextTok = nextToken();97 if (nextTok != null && nextTok.startsWith(" "))98 return nextTok.substring(1);99 pushBack(nextTok);107 Token nextTok = nextToken(); 108 if (nextTok == Token.KEY) 109 return currentText; 110 currentToken = nextTok; 100 111 return null; 101 112 } 102 113 103 public void pushBack(String tok) { 104 pushBackBuf.addLast(tok); 114 public String readText(String errorMessage) throws ParseError { 115 String text = readText(); 116 if (text == null) 117 throw new ParseError(errorMessage); 118 else 119 return text; 120 } 121 122 public String getText() { 123 return currentText; 105 124 } 106 125 } -
trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
r2636 r2645 14 14 15 15 import org.openstreetmap.josm.Main; 16 import org.openstreetmap.josm.actions.search.PushbackTokenizer.Token; 16 17 import org.openstreetmap.josm.data.osm.Node; 17 18 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 23 24 24 25 /** 25 * Implements a google-like search. 26 * @author Imi 26 Implements a google-like search. 27 <br> 28 Grammar: 29 <pre> 30 expression = 31 fact | expression 32 fact expression 33 fact 34 35 fact = 36 ( expression ) 37 -fact 38 term=term 39 term:term 40 term 41 </pre> 42 43 @author Imi 27 44 */ 28 45 public class SearchCompiler { … … 184 201 } 185 202 186 p rivatestatic class ExactKeyValue extends Match {203 public static class ExactKeyValue extends Match { 187 204 188 205 private enum Mode { … … 201 218 throw new ParseError(tr("Key cannot be empty when tag operator is used. Sample use: key=value")); 202 219 this.key = key; 203 this.value = value; 220 this.value = value == null?"":value; 204 221 if ("".equals(value) && "*".equals(key)) { 205 222 mode = Mode.NONE; … … 527 544 } else if (osm instanceof Relation) { 528 545 for (RelationMember member : ((Relation)osm).getMembers()) { 529 if (member.getMember() != null) { 530 // TODO Nullable member will not be allowed 531 isParent |= child.match(member.getMember()); 532 } 546 isParent |= child.match(member.getMember()); 533 547 } 534 548 } … … 576 590 577 591 public Match parse() throws ParseError { 578 Match m = parse Juxta();579 if (!tokenizer.readIfEqual( null))592 Match m = parseExpression(); 593 if (!tokenizer.readIfEqual(Token.EOF)) 580 594 throw new ParseError(tr("Unexpected token: {0}", tokenizer.nextToken())); 581 595 return m; 582 596 } 583 597 584 private Match parseJuxta() throws ParseError { 585 Match juxta = new Always(); 586 587 Match m; 588 while ((m = parseOr()) != null) { 589 juxta = new And(m, juxta); 590 } 591 592 return juxta; 593 } 594 595 private Match parseOr() throws ParseError { 596 Match a = parseNot(); 597 if (tokenizer.readIfEqual("|")) { 598 Match b = parseNot(); 599 if (a == null || b == null) 600 throw new ParseError(tr("Missing arguments for or.")); 601 return new Or(a, b); 602 } 603 return a; 604 } 605 606 private Match parseNot() throws ParseError { 607 if (tokenizer.readIfEqual("-")) { 608 Match m = parseParens(); 609 if (m == null) 610 throw new ParseError(tr("Missing argument for not.")); 611 return new Not(m); 612 } 613 return parseParens(); 614 } 615 616 private Match parseParens() throws ParseError { 617 if (tokenizer.readIfEqual("(")) { 618 Match m = parseJuxta(); 619 if (!tokenizer.readIfEqual(")")) 620 throw new ParseError(tr("Expected closing parenthesis.")); 621 return m; 622 } 623 return parsePat(); 624 } 625 626 private Match parsePat() throws ParseError { 627 String tok = tokenizer.readText(); 628 629 if (tokenizer.readIfEqual(":")) { 630 String tok2 = tokenizer.readText(); 631 if (tok == null) { 632 tok = ""; 633 } 634 if (tok2 == null) { 635 tok2 = ""; 636 } 637 return parseKV(tok, tok2); 638 } 639 640 if (tokenizer.readIfEqual("=")) { 641 String tok2 = tokenizer.readText(); 642 if (tok == null) { 643 tok = ""; 644 } 645 if (tok2 == null) { 646 tok2 = ""; 647 } 648 return new ExactKeyValue(regexSearch, tok, tok2); 649 } 650 651 if (tok == null) 598 private Match parseExpression() throws ParseError { 599 Match factor = parseFactor(); 600 if (factor == null) 652 601 return null; 653 else if (tok.equals("modified")) 654 return new Modified(); 655 else if (tok.equals("incomplete")) 656 return new Incomplete(); 657 else if (tok.equals("untagged")) 658 return new Untagged(); 659 else if (tok.equals("selected")) 660 return new Selected(); 661 else if (tok.equals("child")) 662 return new Child(parseParens()); 663 else if (tok.equals("parent")) 664 return new Parent(parseParens()); 602 if (tokenizer.readIfEqual(Token.OR)) 603 return new Or(factor, parseExpression(tr("Missing parameter for OR"))); 604 else { 605 Match expression = parseExpression(); 606 if (expression == null) 607 return factor; 608 else 609 return new And(factor, expression); 610 } 611 } 612 613 private Match parseExpression(String errorMessage) throws ParseError { 614 Match expression = parseExpression(); 615 if (expression == null) 616 throw new ParseError(errorMessage); 665 617 else 666 return new Any(tok, regexSearch, caseSensitive); 667 } 618 return expression; 619 } 620 621 private Match parseFactor() throws ParseError { 622 if (tokenizer.readIfEqual(Token.LEFT_PARENT)) { 623 Match expression = parseExpression(); 624 if (!tokenizer.readIfEqual(Token.RIGHT_PARENT)) 625 throw new ParseError(tr("Missing right parent")); 626 return expression; 627 } else if (tokenizer.readIfEqual(Token.NOT)) 628 return new Not(parseFactor(tr("Missing operator for NOT"))); 629 else if (tokenizer.readIfEqual(Token.KEY)) { 630 String key = tokenizer.getText(); 631 if (tokenizer.readIfEqual(Token.EQUALS)) 632 return new ExactKeyValue(regexSearch, key, tokenizer.readText()); 633 else if (tokenizer.readIfEqual(Token.COLON)) 634 return parseKV(key, tokenizer.readText()); 635 else if ("modified".equals(key)) 636 return new Modified(); 637 else if ("incomplete".equals(key)) 638 return new Incomplete(); 639 else if ("untagged".equals(key)) 640 return new Untagged(); 641 else if ("selected".equals(key)) 642 return new Selected(); 643 else if ("child".equals(key)) 644 return new Child(parseFactor()); 645 else if ("parent".equals(key)) 646 return new Parent(parseFactor()); 647 else 648 return new Any(key, regexSearch, caseSensitive); 649 } else 650 return null; 651 } 652 653 private Match parseFactor(String errorMessage) throws ParseError { 654 Match fact = parseFactor(); 655 if (fact == null) 656 throw new ParseError(errorMessage); 657 else 658 return fact; 659 } 660 661 668 662 669 663 private Match parseKV(String key, String value) throws ParseError { 664 if (value == null) { 665 value = ""; 666 } 670 667 if (key.equals("type")) 671 668 return new ExactType(value); -
trunk/src/org/openstreetmap/josm/data/Preferences.java
r2641 r2645 670 670 } 671 671 672 public boolean isCollection(String key, boolean def) { 673 String s = get(key); 674 if (s != null && s.length() != 0) 675 return s.indexOf("\u001e") >= 0 || s.indexOf("§§§") >= 0; 676 else 677 return def; 678 } 679 672 680 synchronized public Collection<String> getCollection(String key, Collection<String> def) { 673 681 String s = get(key); -
trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
r2623 r2645 21 21 22 22 import org.openstreetmap.josm.Main; 23 import org.openstreetmap.josm.actions.search.SearchCompiler; 24 import org.openstreetmap.josm.actions.search.SearchCompiler.Match; 25 import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError; 23 26 import org.openstreetmap.josm.data.osm.visitor.Visitor; 24 27 import org.openstreetmap.josm.gui.mappaint.ElemStyle; … … 512 515 private int timestamp; 513 516 514 private static Collection<String> uninteresting = null; 517 private static volatile Collection<String> uninteresting = null; 515 518 /** 516 519 * Contains a list of "uninteresting" keys that do not make an object … … 526 529 } 527 530 528 private static Collection<String>directionKeys = null;531 private static volatile Match directionKeys = null; 529 532 530 533 /** … … 533 536 * Initialized by checkDirectionTagged() 534 537 */ 535 public static Collection<String> getDirectionKeys() {538 public static void initDirectionKeys() { 536 539 if(directionKeys == null) { 537 directionKeys = Main.pref.getCollection("tags.direction", 538 Arrays.asList("oneway","incline","incline_steep","aerialway")); 539 } 540 return directionKeys; 540 541 // Legacy support - convert list of keys to search pattern 542 if (Main.pref.isCollection("tags.direction", false)) { 543 System.out.println("Collection of keys in tags.direction is no longer supported, value will converted to search pattern"); 544 Collection<String> keys = Main.pref.getCollection("tags.direction", null); 545 StringBuilder builder = new StringBuilder(); 546 for (String key:keys) { 547 builder.append(key); 548 builder.append("=* | "); 549 } 550 builder.delete(builder.length() - 3, builder.length()); 551 Main.pref.put("tags.direction", builder.toString()); 552 } 553 554 String defaultValue = "oneway=* | incline=* | incline_steep=* | aerialway=*"; 555 try { 556 directionKeys = SearchCompiler.compile(Main.pref.get("tags.direction", defaultValue), false, false); 557 } catch (ParseError e) { 558 System.err.println("Unable to compile pattern for tags.direction, trying default pattern: " + e.getMessage()); 559 560 try { 561 directionKeys = SearchCompiler.compile(defaultValue, false, false); 562 } catch (ParseError e2) { 563 throw new AssertionError("Unable to compile default pattern for direction keys: " + e2.getMessage()); 564 } 565 } 566 } 541 567 } 542 568 … … 1071 1097 1072 1098 private void updateHasDirectionKeys() { 1073 getDirectionKeys(); 1074 if (keys != null) { 1075 for (Entry<String,String> e : getKeys().entrySet()) { 1076 if (directionKeys.contains(e.getKey())) { 1077 flags |= FLAG_HAS_DIRECTIONS; 1078 return; 1079 } 1080 } 1081 } 1082 flags &= ~FLAG_HAS_DIRECTIONS; 1099 initDirectionKeys(); 1100 if (directionKeys.match(this)) { 1101 flags |= FLAG_HAS_DIRECTIONS; 1102 } else { 1103 flags &= ~FLAG_HAS_DIRECTIONS; 1104 } 1083 1105 } 1084 1106 /** -
trunk/src/org/openstreetmap/josm/data/osm/event/AbstractDatasetChangedEvent.java
r2622 r2645 10 10 public abstract class AbstractDatasetChangedEvent { 11 11 12 public enum DatasetEventType {DATA_CHANGED, NODE_MOVED, PRIMITIVES_ADDED, PRIMITIVES_REMOVED, 13 RELATION_MEMBERS_CHANGED, TAGS_CHANGED, WAY_NODES_CHANGED} 14 12 15 protected final DataSet dataSet; 13 16 … … 17 20 18 21 public abstract void fire(DataSetListener listener); 22 23 /** 24 * Returns list of primitives modified by this event. 25 * <br/> 26 * <strong>WARNING</strong> This value might be incorrect in case 27 * of {@link DataChangedEvent}. It returns all primitives in the dataset 28 * when this method is called (live list), not list of primitives when 29 * the event was created 30 * @return List of modified primitives 31 */ 19 32 public abstract List<? extends OsmPrimitive> getPrimitives(); 20 33 … … 23 36 } 24 37 38 public abstract DatasetEventType getType(); 39 40 @Override 41 public String toString() { 42 return getType().toString(); 43 } 44 25 45 } -
trunk/src/org/openstreetmap/josm/data/osm/event/DataChangedEvent.java
r2622 r2645 24 24 } 25 25 26 @Override 27 public DatasetEventType getType() { 28 return DatasetEventType.DATA_CHANGED; 29 } 30 26 31 } -
trunk/src/org/openstreetmap/josm/data/osm/event/DataSetListenerAdapter.java
r2622 r2645 2 2 package org.openstreetmap.josm.data.osm.event; 3 3 4 /** 5 * Classes that do not wish to implement all methods of DataSetListener 6 * may use this class. Implement DatasetListenerAdapter.Listener and 7 * pass this adapter instead of class itself. 8 * 9 */ 4 10 public class DataSetListenerAdapter implements DataSetListener { 5 11 -
trunk/src/org/openstreetmap/josm/data/osm/event/NodeMovedEvent.java
r2622 r2645 32 32 } 33 33 34 @Override 35 public DatasetEventType getType() { 36 return DatasetEventType.NODE_MOVED; 37 } 38 34 39 } -
trunk/src/org/openstreetmap/josm/data/osm/event/PrimitivesAddedEvent.java
r2623 r2645 39 39 } 40 40 41 @Override 42 public DatasetEventType getType() { 43 return DatasetEventType.PRIMITIVES_ADDED; 44 } 45 41 46 } -
trunk/src/org/openstreetmap/josm/data/osm/event/PrimitivesRemovedEvent.java
r2623 r2645 39 39 } 40 40 41 @Override 42 public DatasetEventType getType() { 43 return DatasetEventType.PRIMITIVES_REMOVED; 44 } 45 41 46 } -
trunk/src/org/openstreetmap/josm/data/osm/event/RelationMembersChangedEvent.java
r2622 r2645 32 32 } 33 33 34 @Override 35 public DatasetEventType getType() { 36 return DatasetEventType.RELATION_MEMBERS_CHANGED; 37 } 38 34 39 } -
trunk/src/org/openstreetmap/josm/data/osm/event/TagsChangedEvent.java
r2622 r2645 31 31 } 32 32 33 @Override 34 public DatasetEventType getType() { 35 return DatasetEventType.TAGS_CHANGED; 36 } 37 33 38 } -
trunk/src/org/openstreetmap/josm/data/osm/event/WayNodesChangedEvent.java
r2622 r2645 32 32 } 33 33 34 @Override 35 public DatasetEventType getType() { 36 return DatasetEventType.WAY_NODES_CHANGED; 37 } 38 34 39 }
Note:
See TracChangeset
for help on using the changeset viewer.