Ticket #14923: preset-search-v3.patch
File preset-search-v3.patch, 10.0 KB (added by , 7 years ago) |
---|
-
src/org/openstreetmap/josm/actions/search/SearchAction.java
454 454 .addKeyword("type:node", "type:node ", tr("all nodes")) 455 455 .addKeyword("type:way", "type:way ", tr("all ways")) 456 456 .addKeyword("type:relation", "type:relation ", tr("all relations")) 457 .addKeyword("preset:water", "preset:water", tr("all objects that use the water preset")) 458 .addKeyword("preset:\"fast food\"", "preset:\"fast food\"", tr("all objects that use the fast food preset")) 457 459 .addKeyword("closed", "closed ", tr("all closed ways")) 458 460 .addKeyword("untagged", "untagged ", tr("object without useful tags")), 459 461 GBC.eol()); … … 888 890 public List<ActionParameter<?>> getActionParameters() { 889 891 return Collections.<ActionParameter<?>>singletonList(new SearchSettingsActionParameter(SEARCH_EXPRESSION)); 890 892 } 891 } 893 } 894 No newline at end of file -
src/org/openstreetmap/josm/actions/search/SearchCompiler.java
20 20 import java.util.regex.Matcher; 21 21 import java.util.regex.Pattern; 22 22 import java.util.regex.PatternSyntaxException; 23 import java.util.stream.Collectors; 23 24 24 25 import org.openstreetmap.josm.Main; 25 26 import org.openstreetmap.josm.actions.search.PushbackTokenizer.Range; … … 38 39 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; 39 40 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser; 40 41 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException; 42 import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset; 43 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets; 41 44 import org.openstreetmap.josm.tools.AlphanumComparator; 42 45 import org.openstreetmap.josm.tools.Geometry; 43 46 import org.openstreetmap.josm.tools.UncheckedParseException; … … 115 118 private final Collection<String> keywords = Arrays.asList("id", "version", "type", "user", "role", 116 119 "changeset", "nodes", "ways", "tags", "areasize", "waylength", "modified", "deleted", "selected", 117 120 "incomplete", "untagged", "closed", "new", "indownloadedarea", 118 "allindownloadedarea", "inview", "allinview", "timestamp", "nth", "nth%", "hasRole" );121 "allindownloadedarea", "inview", "allinview", "timestamp", "nth", "nth%", "hasRole", "preset"); 119 122 120 123 @Override 121 124 public Match get(String keyword, PushbackTokenizer tokenizer) throws ParseError { … … 151 154 return new Version(tokenizer); 152 155 case "type": 153 156 return new ExactType(tokenizer.readTextOrNumber()); 157 case "preset": 158 return new Preset(tokenizer.readTextOrNumber()); 154 159 case "user": 155 160 return new UserMatch(tokenizer.readTextOrNumber()); 156 161 case "role": … … 1554 1559 } 1555 1560 } 1556 1561 1562 /** 1563 * Matches presets. 1564 */ 1565 private static class Preset extends Match { 1566 private List<TaggingPreset> presets; 1567 1568 Preset(String presetName) throws ParseError { 1569 1570 if (presetName == null) { 1571 throw new ParseError("The name of the preset is required"); 1572 } 1573 1574 this.presets = TaggingPresets.getTaggingPresets() 1575 .stream() 1576 .filter(preset -> presetName.equalsIgnoreCase(preset.getSimpleName())) 1577 .collect(Collectors.toList()); 1578 1579 if (this.presets.isEmpty()) { 1580 throw new ParseError(tr("Unknown preset name: ") + presetName); 1581 } 1582 } 1583 1584 /** 1585 * Since presets can have common names, the primitive is considered to 1586 * belong to a certain preset if it matches at least one of them. 1587 */ 1588 @Override 1589 public boolean match(OsmPrimitive osm) { 1590 for (TaggingPreset p : this.presets) { 1591 if (p.test(osm)) { 1592 return true; 1593 } 1594 } 1595 1596 return false; 1597 } 1598 } 1599 1557 1600 public static class ParseError extends Exception { 1558 1601 public ParseError(String msg) { 1559 1602 super(msg); … … 1803 1846 return forKey + '"' + escapeStringForSearch(value) + '"'; 1804 1847 } 1805 1848 } 1806 } 1849 } 1850 No newline at end of file -
src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java
173 173 } 174 174 175 175 /** 176 * Returns the non translated name without any prefixes. 177 * @return returns the non translated name without any prefixes. 178 */ 179 public String getSimpleName() { 180 return this.name; 181 } 182 183 /** 176 184 * Returns the preset icon (16px). 177 185 * @return The preset icon, or {@code null} if none defined 178 186 * @since 6403 … … 634 642 ToolbarPreferences.ActionParser actionParser = new ToolbarPreferences.ActionParser(null); 635 643 return actionParser.saveAction(new ToolbarPreferences.ActionDefinition(this)); 636 644 } 637 } 645 } 646 No newline at end of file -
test/unit/org/openstreetmap/josm/actions/search/SearchCompilerTest.java
10 10 import java.nio.charset.StandardCharsets; 11 11 import java.nio.file.Files; 12 12 import java.nio.file.Paths; 13 import java.util.Collections; 13 14 14 15 import org.junit.Rule; 15 16 import org.junit.Test; … … 30 31 import org.openstreetmap.josm.data.osm.User; 31 32 import org.openstreetmap.josm.data.osm.Way; 32 33 import org.openstreetmap.josm.data.osm.WayData; 34 import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset; 35 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType; 36 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets; 37 import org.openstreetmap.josm.gui.tagging.presets.items.Key; 33 38 import org.openstreetmap.josm.testutils.JOSMTestRules; 34 39 import org.openstreetmap.josm.tools.date.DateUtils; 35 40 … … 490 495 public void testEnumExactKeyValueMode() { 491 496 TestUtils.superficialEnumCodeCoverage(ExactKeyValue.Mode.class); 492 497 } 493 } 498 499 /** 500 * Robustness test for preset searching. Ensures that the query 'preset:' is not accepted. 501 * @throws ParseError always 502 */ 503 @Test(expected = ParseError.class) 504 public void testPresetSearchMissingValue() throws ParseError { 505 SearchSetting settings = new SearchSetting(); 506 settings.text = "preset:"; 507 settings.mapCSSSearch = false; 508 509 SearchCompiler.compile(settings); 510 } 511 512 /** 513 * Robustness test for preset searching. Validates that it is not possible to search for 514 * non existing presets. 515 * @throws ParseError always 516 */ 517 @Test(expected = ParseError.class) 518 public void testPresetNotExist() throws ParseError { 519 String testPresetName = "namethatshouldnotexist"; 520 SearchSetting settings = new SearchSetting(); 521 settings.text = "preset:" + testPresetName; 522 settings.mapCSSSearch = false; 523 524 // load presets 525 TaggingPresets.readFromPreferences(); 526 527 SearchCompiler.compile(settings); 528 } 529 530 /** 531 * Robustness tests for preset searching. Ensures that combined presed names (having more than 532 * 1 words) must be enclosed in " . 533 * @throws ParseError always 534 */ 535 @Test(expected = ParseError.class) 536 public void testPresetMultipleWords() throws ParseError{ 537 String combinedPresetname = "Fast Food"; 538 SearchSetting settings = new SearchSetting(); 539 settings.text = "preset:" + combinedPresetname; 540 settings.mapCSSSearch = false; 541 542 SearchCompiler.compile(settings); 543 } 544 545 /** 546 * Ensures that correct primitives are matched against the specified preset. 547 * @throws ParseError if an error has been encountered while compiling 548 */ 549 @Test 550 public void testPreset() throws ParseError { 551 final String presetName = "testPresetName"; 552 final String key = "test_key1"; 553 final String val = "test_val1"; 554 555 Key key1 = new Key(); 556 key1.key = key; 557 key1.value = val; 558 559 TaggingPreset testPreset = new TaggingPreset(); 560 testPreset.name = presetName; 561 testPreset.types = Collections.singleton(TaggingPresetType.NODE); 562 testPreset.data.add(key1); 563 564 TaggingPresets.readFromPreferences(); 565 TaggingPresets.addTaggingPresets(Collections.singleton(testPreset)); 566 567 String[] queries = { 568 "preset:" + presetName, 569 "preset: " + presetName, 570 "preset:" + "\"" + presetName + "\"" 571 }; 572 573 for (int i = 0; i < queries.length; i++) { 574 SearchContext ctx = new SearchContext(queries[i]); 575 ctx.n1.put(key, val); 576 ctx.n2.put(key, val); 577 578 for (OsmPrimitive osm : new OsmPrimitive[] { ctx.n1, ctx.n2 }) { 579 ctx.match(osm, true); 580 } 581 582 for (OsmPrimitive osm : new OsmPrimitive[] { ctx.r1, ctx.r2, ctx.w1, ctx.w2 }) { 583 ctx.match(osm, false); 584 } 585 } 586 } 587 } 588 No newline at end of file