Index: src/org/openstreetmap/josm/actions/search/SearchCompiler.java =================================================================== --- src/org/openstreetmap/josm/actions/search/SearchCompiler.java (revision 775) +++ src/org/openstreetmap/josm/actions/search/SearchCompiler.java (working copy) @@ -19,10 +19,12 @@ private boolean caseSensitive = false; private PushbackTokenizer tokenizer; + private boolean alternateTokenizing = false; - public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) { + public SearchCompiler(boolean caseSensitive, boolean alternateTokenizing, PushbackTokenizer tokenizer) { this.caseSensitive = caseSensitive; this.tokenizer = tokenizer; + this.alternateTokenizing = alternateTokenizing; } abstract public static class Match { @@ -177,11 +179,11 @@ } } - public static Match compile(String searchStr, boolean caseSensitive) + public static Match compile(String searchStr, boolean caseSensitive, boolean alternateTokenizing) throws ParseError { - return new SearchCompiler(caseSensitive, + return new SearchCompiler(caseSensitive, alternateTokenizing, new PushbackTokenizer( - new PushbackReader(new StringReader(searchStr)))) + new PushbackReader(new StringReader(searchStr)), alternateTokenizing)) .parse(); } @@ -240,8 +242,9 @@ private Match parsePat() { String tok = tokenizer.readText(); + String token = alternateTokenizing ? "=" : ":"; - if (tokenizer.readIfEqual(":")) { + if (tokenizer.readIfEqual(token)) { String tok2 = tokenizer.readText(); if (tok == null) tok = ""; if (tok2 == null) tok2 = ""; Index: src/org/openstreetmap/josm/actions/search/SearchAction.java =================================================================== --- src/org/openstreetmap/josm/actions/search/SearchAction.java (revision 775) +++ src/org/openstreetmap/josm/actions/search/SearchAction.java (working copy) @@ -54,6 +54,7 @@ bg.add(remove); JCheckBox caseSensitive = new JCheckBox(tr("case sensitive"), false); + JCheckBox alternateTokenizing = new JCheckBox(tr("use = instead of : for key/value separation"), false); JPanel p = new JPanel(new GridBagLayout()); p.add(label, GBC.eop()); @@ -62,6 +63,7 @@ p.add(add, GBC.eol()); p.add(remove, GBC.eop()); p.add(caseSensitive, GBC.eol()); + p.add(alternateTokenizing, GBC.eol()); JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null){ @Override public void selectInitialValue() { input.requestFocusInWindow(); @@ -73,10 +75,26 @@ return; lastSearch = input.getText(); SearchAction.SearchMode mode = replace.isSelected() ? SearchAction.SearchMode.replace : (add.isSelected() ? SearchAction.SearchMode.add : SearchAction.SearchMode.remove); - search(lastSearch, mode, caseSensitive.isSelected()); + search(lastSearch, mode, caseSensitive.isSelected(), alternateTokenizing.isSelected()); } - public static void search(String search, SearchMode mode, boolean caseSensitive) { + /** + * To stay compatible, the old call + * @param search Text to search for + * @param mode what to do with the search result + * @param caseSensitive switch case sensitivity + */ + public static void search(String search, SearchMode mode, boolean caseSensitive) { + search (search, mode, caseSensitive, false); + } + + /** + * @param search Text to search for + * @param mode what to do with the search result + * @param caseSensitive switch case sensitivity + * @param alternateTokenizing if set, a = separates key and value, else it stays a :. + */ + public static void search(String search, SearchMode mode, boolean caseSensitive, boolean alternateTokenizing) { if (search.startsWith("http://") || search.startsWith("ftp://") || search.startsWith("https://") || search.startsWith("file:/")) { SelectionWebsiteLoader loader = new SelectionWebsiteLoader(search, mode); if (loader.url != null) { @@ -86,7 +104,7 @@ } try { Collection sel = Main.ds.getSelected(); - SearchCompiler.Match matcher = SearchCompiler.compile(search, caseSensitive); + SearchCompiler.Match matcher = SearchCompiler.compile(search, caseSensitive, alternateTokenizing); for (OsmPrimitive osm : Main.ds.allNonDeletedCompletePrimitives()) { if (mode == SearchMode.replace) { if (matcher.match(osm)) Index: src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java =================================================================== --- src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java (revision 775) +++ src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java (working copy) @@ -7,17 +7,33 @@ public class PushbackTokenizer { private PushbackReader search; + private boolean alternateTokenizing; private LinkedList pushBackBuf = new LinkedList(); + /** + * The 'classic' interface, a : separates key and value + * @param search datasource to sift through + */ public PushbackTokenizer(PushbackReader search) { this.search = search; + this.alternateTokenizing = false; } /** + * The new interface, key/value separation is switchable + * @param search datasource to sift through + * @param alternateTokenizing switches between : (false) and = (true) as key/value token + */ + public PushbackTokenizer(PushbackReader search, boolean alternateTokenizing) { + this.search = search; + this.alternateTokenizing = alternateTokenizing; + } + + /** * The token returned is null or starts with an identifier character: * - for an '-'. This will be the only character - * : for an key. The value is the next token + * : or = for an key (depending on alternateTokenizing in the constructor. The value is the next token * | for "OR" * ' ' for anything else. * @return The next token in the stream. @@ -38,15 +54,32 @@ } StringBuilder s; switch (c) { - case ':': - next = search.read(); - c = (char) next; - if (next == -1 || c == ' ' || c == '\t') { - pushBack(" "); - } else { - search.unread(next); + case ':' : + if(!alternateTokenizing) { + next = search.read(); + c = (char) next; + if (next == -1 || c == ' ' || c == '\t') { + pushBack(" "); + } else { + search.unread(next); + } + return ":"; } - return ":"; + s = new StringBuilder (); + break; + case '=' : + if(alternateTokenizing) { + next = search.read(); + c = (char) next; + if (next == -1 || c == ' ' || c == '\t') { + pushBack(" "); + } else { + search.unread(next); + } + return "="; + } + s = new StringBuilder (); + break; case '-': return "-"; case '(': @@ -60,6 +93,8 @@ return s.toString(); default: s = new StringBuilder(); + break; + } for (;;) { s.append(c); next = search.read(); @@ -69,14 +104,14 @@ return " "+s.toString(); } c = (char)next; - if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')') { + if (c == ' ' || c == '\t' || c == '"' || c == (alternateTokenizing ? '=' : ':') || c == '(' || c == ')') { search.unread(next); if (s.toString().equals("OR")) return "|"; return " "+s.toString(); } } - } + } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); }