Changeset 15764 in josm


Ignore:
Timestamp:
2020-01-26T00:18:32+01:00 (2 months ago)
Author:
simon04
Message:

fix #17496 - AutoFilter: infer sensible default values for layer

Location:
trunk
Files:
3 edited

Legend:

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

    r15440 r15764  
    1919import java.util.Optional;
    2020import java.util.function.Predicate;
     21import java.util.function.Supplier;
    2122import java.util.regex.Matcher;
    2223import java.util.regex.Pattern;
     
    264265
    265266    /**
     267     * Classes implementing this interface can provide Match instances themselves and do not rely on {@link #compile(String)}.
     268     *
     269     * @since 15764
     270     */
     271    @FunctionalInterface
     272    public interface MatchSupplier extends Supplier<Match> {
     273        @Override
     274        Match get();
     275    }
     276
     277    /**
    266278     * Base class for all search criteria. If the criterion only depends on an object's tags,
    267279     * inherit from {@link org.openstreetmap.josm.data.osm.search.SearchCompiler.TaggedMatch}.
     
    19441956     */
    19451957    public static Match compile(SearchSetting setting) throws SearchParseError {
     1958        if (setting instanceof MatchSupplier) {
     1959            return ((MatchSupplier) setting).get();
     1960        }
    19461961        if (setting.mapCSSSearch) {
    19471962            return compileMapCSS(setting.text);
  • trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java

    r14206 r15764  
    2020import java.util.regex.Matcher;
    2121import java.util.regex.Pattern;
     22import java.util.stream.IntStream;
     23import java.util.stream.Stream;
    2224
    2325import org.openstreetmap.josm.actions.mapmode.MapMode;
     
    2729import org.openstreetmap.josm.data.osm.FilterModel;
    2830import org.openstreetmap.josm.data.osm.OsmPrimitive;
     31import org.openstreetmap.josm.data.osm.OsmUtils;
    2932import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
    3033import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
     
    3841import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
    3942import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
     43import org.openstreetmap.josm.data.osm.search.SearchCompiler;
     44import org.openstreetmap.josm.data.osm.search.SearchCompiler.MatchSupplier;
    4045import org.openstreetmap.josm.data.preferences.BooleanProperty;
    4146import org.openstreetmap.josm.data.preferences.StringProperty;
     
    7782
    7883    /**
     84     * Property to determine if the auto filter should assume sensible defaults for values (such as layer=1 for bridge=yes).
     85     */
     86    private static final BooleanProperty PROP_AUTO_FILTER_DEFAULTS = new BooleanProperty("auto.filter.defaults", true);
     87
     88    /**
    7989     * The unique instance.
    8090     */
     
    148158    }
    149159
     160    static class CompiledFilter extends Filter implements MatchSupplier {
     161        final String key;
     162        final String value;
     163
     164        CompiledFilter(String key, String value) {
     165            this.key = key;
     166            this.value = value;
     167            this.enable = true;
     168            this.inverted = true;
     169            this.text = key + "=" + value;
     170        }
     171
     172        @Override
     173        public SearchCompiler.Match get() {
     174            return new SearchCompiler.Match() {
     175                @Override
     176                public boolean match(OsmPrimitive osm) {
     177                    return getTagValuesForPrimitive(key, osm).anyMatch(value::equals);
     178                }
     179            };
     180        }
     181    }
     182
    150183    private synchronized void addNewButtons(NavigableSet<String> values) {
    151184        int i = 0;
     
    153186        MapView mapView = MainApplication.getMap().mapView;
    154187        for (final String value : values.descendingSet()) {
    155             Filter filter = new Filter();
    156             filter.enable = true;
    157             filter.inverted = true;
    158             filter.text = enabledRule.getKey() + "=" + value;
     188            Filter filter = new CompiledFilter(enabledRule.getKey(), value);
    159189            String label = enabledRule.getValueFormatter().apply(value);
    160190            AutoFilter autoFilter = new AutoFilter(label, filter.text, filter);
     
    198228        if (ds != null) {
    199229            BBox bbox = MainApplication.getMap().mapView.getState().getViewArea().getLatLonBoundsBox().toBBox();
    200             Consumer<OsmPrimitive> consumer = getTagValuesConsumer(key, values);
     230            Consumer<OsmPrimitive> consumer = o -> getTagValuesForPrimitive(key, o).forEach(values::add);
    201231            ds.searchNodes(bbox).forEach(consumer);
    202232            ds.searchWays(bbox).forEach(consumer);
     
    206236    }
    207237
    208     static Consumer<OsmPrimitive> getTagValuesConsumer(String key, Set<String> values) {
    209         return o -> {
    210             String value = o.get(key);
    211             if (value != null) {
    212                 Pattern p = Pattern.compile("(-?[0-9]+)-(-?[0-9]+)");
    213                 for (String v : value.split(";")) {
    214                     Matcher m = p.matcher(v);
    215                     if (m.matches()) {
    216                         int a = Integer.parseInt(m.group(1));
    217                         int b = Integer.parseInt(m.group(2));
    218                         for (int i = Math.min(a, b); i <= Math.max(a, b); i++) {
    219                             values.add(Integer.toString(i));
    220                         }
    221                     } else {
    222                         values.add(v);
    223                     }
     238    static Stream<String> getTagValuesForPrimitive(String key, OsmPrimitive osm) {
     239        String value = osm.get(key);
     240        if (value != null) {
     241            Pattern p = Pattern.compile("(-?[0-9]+)-(-?[0-9]+)");
     242            return OsmUtils.splitMultipleValues(value).flatMap(v -> {
     243                Matcher m = p.matcher(v);
     244                if (m.matches()) {
     245                    int a = Integer.parseInt(m.group(1));
     246                    int b = Integer.parseInt(m.group(2));
     247                    return IntStream.rangeClosed(Math.min(a, b), Math.max(a, b))
     248                            .mapToObj(Integer::toString);
     249                } else {
     250                    return Stream.of(v);
    224251                }
    225             }
    226         };
     252            });
     253        } else if (PROP_AUTO_FILTER_DEFAULTS.get() && "layer".equals(key)) {
     254            // assume sensible defaults, see #17496
     255            if (osm.hasTag("bridge") || osm.hasTag("power", "line") || osm.hasTag("location", "overhead")) {
     256                return Stream.of("1");
     257            } else if (osm.isKeyTrue("tunnel") || osm.hasTag("tunnel", "culvert") || osm.hasTag("location", "underground")) {
     258                return Stream.of("-1");
     259            } else if (osm.hasTag("tunnel", "building_passage") || osm.hasKey("highway", "railway", "waterway")) {
     260                return Stream.of("0");
     261            }
     262        }
     263        return Stream.empty();
    227264    }
    228265
  • trunk/test/unit/org/openstreetmap/josm/gui/autofilter/AutoFilterManagerTest.java

    r12407 r15764  
    33
    44import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertNull;
    56
    67import java.util.Arrays;
    7 import java.util.Set;
    88import java.util.TreeSet;
    9 import java.util.function.Consumer;
     9import java.util.stream.Collectors;
     10import java.util.stream.Stream;
    1011
    1112import org.junit.Rule;
    1213import org.junit.Test;
    13 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1414import org.openstreetmap.josm.data.osm.OsmUtils;
    1515import org.openstreetmap.josm.testutils.JOSMTestRules;
     
    3030
    3131    /**
    32      * Unit test of {@link AutoFilterManager#getTagValuesConsumer}.
     32     * Unit test of {@link AutoFilterManager#getTagValuesForPrimitive}.
    3333     */
    3434    @Test
    35     public void testTagValuesConsumer() {
    36         Set<String> values = new TreeSet<>();
    37         Consumer<OsmPrimitive> consumer = AutoFilterManager.getTagValuesConsumer("level", values);
    38         Arrays.asList(
     35    public void testTagValuesForPrimitive() {
     36        final TreeSet<String> values = Stream.of(
    3937                OsmUtils.createPrimitive("way level=-4--5"),
    4038                OsmUtils.createPrimitive("way level=-2"),
     
    4341                OsmUtils.createPrimitive("way level=2;3"),
    4442                OsmUtils.createPrimitive("way level=6-9"),
    45                 OsmUtils.createPrimitive("way level=10;12-13")
    46                 ).forEach(consumer);
     43                OsmUtils.createPrimitive("way level=10;12-13"))
     44                .flatMap(o -> AutoFilterManager.getTagValuesForPrimitive("level", o))
     45                .collect(Collectors.toCollection(TreeSet::new));
    4746        assertEquals(new TreeSet<>(Arrays.asList("-5", "-4", "-2", "0", "1", "2", "3", "6", "7", "8", "9", "10", "12", "13")), values);
     47
     48    }
     49
     50    /**
     51     * Unit test of {@link AutoFilterManager#getTagValuesForPrimitive} provides sensible defaults, see #17496.
     52     */
     53    @Test
     54    public void testTagValuesForPrimitivesDefaults() {
     55        assertNull(getLayer("way foo=bar"));
     56        assertEquals("1", getLayer("way bridge=yes"));
     57        assertEquals("1", getLayer("way power=line"));
     58        assertEquals("-1", getLayer("way tunnel=yes"));
     59        assertEquals("0", getLayer("way tunnel=building_passage"));
     60        assertEquals("0", getLayer("way highway=residential"));
     61        assertEquals("0", getLayer("way railway=rail"));
     62        assertEquals("0", getLayer("way waterway=canal"));
     63    }
     64
     65    private String getLayer(final String assertion) {
     66        return AutoFilterManager.getTagValuesForPrimitive("layer", OsmUtils.createPrimitive(assertion))
     67                .findFirst()
     68                .orElse(null);
    4869    }
    4970}
Note: See TracChangeset for help on using the changeset viewer.