Ticket #2673: keyvaluesearch.patch

File keyvaluesearch.patch, 8.6 KB (added by jttt, 17 years ago)
  • src/org/openstreetmap/josm/actions/search/SearchCompiler.java

     
    153153        }
    154154        @Override public String toString() {return key+"="+value;}
    155155    }
     156   
     157    private static class ExactKeyValue extends Match {
     158       
     159        private enum Mode {
     160            ANY, ANY_KEY, ANY_VALUE, EXACT, NONE, MISSING_KEY,
     161            ANY_KEY_REGEXP, ANY_VALUE_REGEXP, EXACT_REGEXP, MISSING_KEY_REGEXP;
     162        }
     163       
     164        private final String key;
     165        private final String value;
     166        private final Pattern keyPattern;
     167        private final Pattern valuePattern;
     168        private final Mode mode;
     169       
     170        public ExactKeyValue(boolean regexp, String key, String value) throws ParseError {
     171            if (key == "") {
     172                throw new ParseError("Key cannot be empty when tag operator is used. Sample use: key=value");
     173            }           
     174            this.key = key;
     175            this.value = value;
     176            if ("".equals(value) && "*".equals(key)) {
     177                mode = Mode.NONE;
     178            } else if ("".equals(value)) {
     179                if (regexp) {
     180                    mode = Mode.MISSING_KEY_REGEXP;
     181                } else {
     182                    mode = Mode.MISSING_KEY;
     183                }
     184            } else if ("*".equals(key) && "*".equals(value)) {
     185                mode = Mode.ANY;
     186            } else if ("*".equals(key)) {
     187                if (regexp) {
     188                    mode = Mode.ANY_KEY_REGEXP;
     189                } else {
     190                    mode = Mode.ANY_KEY;
     191                }
     192            } else if ("*".equals(value)) {
     193                if (regexp) {
     194                    mode = Mode.ANY_VALUE_REGEXP;
     195                } else {
     196                    mode = Mode.ANY_VALUE;
     197                }
     198            } else {
     199                if (regexp) {
     200                    mode = Mode.EXACT_REGEXP;
     201                } else {
     202                    mode = Mode.EXACT;
     203                }
     204            }
     205           
     206            if (regexp && key.length() > 0 && !key.equals("*")) {
     207                keyPattern = Pattern.compile(key);
     208            } else {
     209                keyPattern = null;
     210            }
     211            if (regexp && value.length() > 0 && !value.equals("*")) {
     212                valuePattern = Pattern.compile(value);
     213            } else {
     214                valuePattern = null;
     215            }
     216        }
    156217
     218        @Override
     219        public boolean match(OsmPrimitive osm) throws ParseError {
     220           
     221            if (osm.keys == null || osm.keys.isEmpty()) {
     222                return mode == Mode.NONE;
     223            }
     224           
     225            switch (mode) {
     226            case NONE:
     227                return false;
     228            case MISSING_KEY:
     229                return osm.get(key) == null;
     230            case ANY:
     231                return true;
     232            case ANY_VALUE:
     233                return osm.get(key) != null;
     234            case ANY_KEY:
     235                for (String v:osm.keys.values()) {
     236                    if (v.equals(value)) {
     237                        return true;
     238                    }
     239                }
     240                return false;
     241            case EXACT:
     242                return value.equals(osm.get(key));
     243            case ANY_KEY_REGEXP:
     244                for (String v:osm.keys.values()) {
     245                    if (valuePattern.matcher(v).matches()) {
     246                        return true;
     247                    }
     248                }
     249                return false;
     250            case ANY_VALUE_REGEXP:
     251            case EXACT_REGEXP:
     252                for (Entry<String, String> entry:osm.keys.entrySet()) {
     253                    if (keyPattern.matcher(entry.getKey()).matches()) {
     254                        if (mode == Mode.ANY_VALUE_REGEXP
     255                                || valuePattern.matcher(entry.getValue()).matches()) {
     256                            return true;
     257                        }
     258                    }
     259                }
     260                return false;
     261            case MISSING_KEY_REGEXP:
     262                for (String k:osm.keys.keySet()) {
     263                    if (keyPattern.matcher(k).matches()) {
     264                        return false;
     265                    }
     266                }
     267                return true;
     268            } 
     269            throw new AssertionError("Missed state");
     270        }
     271       
     272        @Override
     273        public String toString() {
     274            return key + '=' + value;
     275        }
     276       
     277    }
     278
    157279    private class Any extends Match {
    158280        private String s;
    159281        public Any(String s) {this.s = s;}
     
    427549            if (tok2 == null) tok2 = "";
    428550            return parseKV(tok, tok2);
    429551        }
     552       
     553        if (tokenizer.readIfEqual("=")) {
     554            String tok2 = tokenizer.readText();
     555            if (tok == null) tok = "";
     556            if (tok2 == null) tok2 = "";
     557            return new ExactKeyValue(regexSearch, tok, tok2);
     558        }
    430559
    431560        if (tok == null) {
    432561            return null;
     
    476605            return new KeyValue(key, value);
    477606        }
    478607    }
    479 
     608   
    480609    private int regexFlags() {
    481610        int searchFlags = 0;
    482611
  • src/org/openstreetmap/josm/actions/search/SearchAction.java

     
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
     6import java.awt.Font;
    67import java.awt.GridBagLayout;
    78import java.awt.event.ActionEvent;
    89import java.awt.event.KeyEvent;
     
    7879        left.add(regexSearch, GBC.eol());
    7980
    8081        JPanel right = new JPanel();
    81         right.add(new JLabel("<html><ul>"
     82        JLabel description =
     83        new JLabel("<html><ul>"
    8284                + "<li>"+tr("<b>Baker Street</b> - 'Baker' and 'Street' in any key or name.")+"</li>"
    8385                + "<li>"+tr("<b>\"Baker Street\"</b> - 'Baker Street' in any key or name.")+"</li>"
    8486                + "<li>"+tr("<b>name:Bak</b> - 'Bak' anywhere in the name.")+"</li>"
     87                + "<li>"+tr("<b>type=route</b> - key 'type' with value exactly 'route'.") + "</li>"
     88                + "<li>"+tr("<b>type=*</b> - key 'type' with any value. Try also <b>*=value</b>, <b>type=</b>, <b>*=*</b>, <b>*=</b>") + "</li>"
    8589                + "<li>"+tr("<b>-name:Bak</b> - not 'Bak' in the name.")+"</li>"
    8690                + "<li>"+tr("<b>foot:</b> - key=foot set to any value.")+"</li>"
    8791                + "<li>"+tr("<u>Special targets:</u>")+"</li>"
     
    98102                + "<li>"+tr("Use <b>|</b> or <b>OR</b> to combine with logical or")+"</li>"
    99103                + "<li>"+tr("Use <b>\"</b> to quote operators (e.g. if key contains :)")+"</li>"
    100104                + "<li>"+tr("Use <b>(</b> and <b>)</b> to group expressions")+"</li>"
    101                 + "</ul></html>"));
     105                + "</ul></html>");
     106        description.setFont(description.getFont().deriveFont(Font.PLAIN));
     107        right.add(description);
    102108
    103109        final JPanel p = new JPanel();
    104110        p.add(left);
  • src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java

     
    3939            StringBuilder s;
    4040            switch (c) {
    4141            case ':':
     42            case '=':
    4243                next = search.read();
    43                 c = (char) next;
    44                 if (next == -1 || c == ' ' || c == '\t') {
     44                if (next == -1 || next == ' ' || next == '\t') {
    4545                    pushBack(" ");
    4646                } else {
    4747                    search.unread(next);
    4848                }
    49                 return ":";
     49                return String.valueOf(c);
    5050            case '-':
    5151                return "-";
    5252            case '(':
     
    7171                    return " "+s.toString();
    7272                }
    7373                c = (char)next;
    74                 if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') {
     74                if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|' || c == '=') {
    7575                    search.unread(next);
    7676                    if (s.toString().equals("OR"))
    7777                        return "|";