Ticket #24482: autofilter_05_none.patch

File autofilter_05_none.patch, 8.2 KB (added by tordanik, 7 months ago)
  • src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java

    diff --git a/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java b/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java
    index ba5514dc03..1c40d8a82c 100644
    a b import java.util.ArrayList;  
    88import java.util.Arrays;
    99import java.util.Collection;
    1010import java.util.Collections;
     11import java.util.HashMap;
    1112import java.util.List;
    1213import java.util.Map;
    1314import java.util.NavigableSet;
    1415import java.util.Objects;
    15 import java.util.TreeMap;
     16import java.util.OptionalInt;
    1617import java.util.TreeSet;
    1718import java.util.stream.Collectors;
     19import java.util.stream.IntStream;
    1820
    1921import org.openstreetmap.josm.actions.mapmode.MapMode;
    2022import org.openstreetmap.josm.data.osm.BBox;
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    8789    /**
    8890     * The buttons currently displayed in map view.
    8991     */
    90     private final Map<Integer, AutoFilterButton> buttons = new TreeMap<>();
     92    private final Map<OptionalInt, AutoFilterButton> buttons = new HashMap<>();
    9193
    9294    /**
    9395     * The list of registered auto filter rules.
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    143145            NavigableSet<Integer> values = getNumericValues();
    144146            // Make sure current auto filter buttons remain visible even if no data is found, to allow user to disable them
    145147            for (var currentAutoFilter : currentAutoFilters) {
    146                 values.add(currentAutoFilter.getFilter().value);
     148                if (currentAutoFilter.getFilter().value != null) {
     149                    values.add(currentAutoFilter.getFilter().value);
     150                }
    147151            }
    148             if (!values.equals(buttons.keySet())) {
     152            if (!values.equals(buttons.keySet().stream()
     153                    .filter(it -> it.isPresent() && it.getAsInt() != Integer.MIN_VALUE)
     154                    .map(OptionalInt::getAsInt).collect(Collectors.toSet()))) {
    149155                removeAllButtons();
    150156                addNewButtons(values);
    151157            }
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    154160
    155161    static class CompiledFilter extends Filter implements MatchSupplier {
    156162        final AutoFilterRule rule;
    157         final int value;
     163        final Integer value;
    158164
    159         CompiledFilter(AutoFilterRule rule, int value, boolean hiding) {
     165        CompiledFilter(AutoFilterRule rule, Integer value, boolean hiding) {
    160166            this.rule = rule;
    161167            this.value = value;
    162168            this.hiding = hiding;
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    182188            if (!super.equals(obj) || getClass() != obj.getClass())
    183189                return false;
    184190            CompiledFilter other = (CompiledFilter) obj;
    185             return Objects.equals(rule, other.rule) && value == other.value;
     191            return Objects.equals(rule, other.rule) && Objects.equals(value, other.value);
    186192        }
    187193    }
    188194
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    242248
    243249    static class Match extends SearchCompiler.Match {
    244250        final AutoFilterRule rule;
    245         final int value;
     251        final Integer value;
    246252
    247         Match(AutoFilterRule rule, int value) {
     253        Match(AutoFilterRule rule, Integer value) {
    248254            this.rule = rule;
    249255            this.value = value;
    250256        }
    251257
    252258        @Override
    253259        public boolean match(OsmPrimitive osm) {
    254             return rule.getTagValuesForPrimitive(osm, false).anyMatch(v -> v == value);
     260            IntStream values = rule.getTagValuesForPrimitive(osm, false);
     261            if (value != null) {
     262                return values.anyMatch(v -> v == value);
     263            } else {
     264                return values.findAny().isEmpty();
     265            }
    255266        }
    256267
    257268        @Override
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    259270            if (this == o) return true;
    260271            if (o == null || getClass() != o.getClass()) return false;
    261272            Match match = (Match) o;
    262             return value == match.value &&
     273            return Objects.equals(value, match.value) &&
    263274                    Objects.equals(rule, match.rule);
    264275        }
    265276
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    277288        int maxWidth = 16;
    278289        final AutoFilterButton keyButton = AutoFilterButton.forOsmKey(enabledRule.getKey());
    279290        addButton(keyButton, Integer.MIN_VALUE, i++);
    280         for (final Integer value : values.descendingSet()) {
     291        var valueList = new ArrayList<>(values.descendingSet());
     292        if (enabledRule.getNoValueFilter()) {
     293            valueList.add(null);
     294        }
     295        for (final Integer value : valueList) {
    281296            CompiledFilter filter = new CompiledFilter(enabledRule, value, PROP_AUTO_FILTER_HIDING.get());
    282297            String label = enabledRule.formatValue(value);
    283298            AutoFilter autoFilter = new AutoFilter(label, filter.text, filter);
    implements ZoomChangeListener, MapModeChangeListener, DataSetListener, Preferenc  
    294309        MainApplication.getMap().mapView.validate();
    295310    }
    296311
    297     private void addButton(AutoFilterButton button, int value, int i) {
     312    private void addButton(AutoFilterButton button, Integer value, int i) {
    298313        MapView mapView = MainApplication.getMap().mapView;
    299         buttons.put(value, button);
     314        buttons.put(value == null ? OptionalInt.empty() : OptionalInt.of(value), button);
    300315        mapView.add(button).setLocation(3, 60 + 22*i);
    301316    }
    302317
  • src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java

    diff --git a/src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java b/src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java
    index e78c42d156..ec1f98d145 100644
    a b public class AutoFilterRule {  
    4242
    4343    private IntFunction<String> valueFormatter = Integer::toString;
    4444
     45    private boolean noValueFilter = false;
     46
    4547    /** The union of {@link #key} and the keys provided by {@link #setExtraKeys(List)}. */
    4648    private List<String> allKeys;
    4749
    public class AutoFilterRule {  
    7274        return minZoomLevel;
    7375    }
    7476
     77    /**
     78     * Returns true if there should be a filter button for OSM primitives which have no value for the key.
     79     */
     80    public boolean getNoValueFilter() {
     81        return noValueFilter;
     82    }
     83
    7584    /**
    7685     * Formats the numeric value
    7786     * @param value the numeric value to format
    7887     * @return the formatted value
    7988     */
    80     public String formatValue(int value) {
    81         return valueFormatter.apply(value);
     89    public String formatValue(Integer value) {
     90        return value == null ? "∅" : valueFormatter.apply(value);
    8291    }
    8392
    8493    /**
    public class AutoFilterRule {  
    115124        return this;
    116125    }
    117126
     127    /**
     128     * Adds a filter button for OSM primitives which have no value for the key.
     129     */
     130    public AutoFilterRule enableNoValueFilter() {
     131        this.noValueFilter = true;
     132        return this;
     133    }
     134
    118135    /**
    119136     * Sets extra OSM keys on which the rule applies in addition to the primary key ({@link #getKey()}).
    120137     * This allows a filter to look at the values of more than one key at the same time.
    public class AutoFilterRule {  
    195212                    .setDefaultValueSupplier(AutoFilterRule::defaultLayer),
    196213            new AutoFilterRule("level", 17)
    197214                .setExtraKeys(List.of("repeat_on"))
     215                .enableNoValueFilter()
    198216                // #17109, support values like 0.5 or 1.5 - level values are multiplied by 2 when parsing, values are divided by 2 for formatting
    199217                .setValueExtractor(s -> (int) (Double.parseDouble(s) * 2.))
    200218                .setValueFormatter(v -> DecimalFormat.getInstance(Locale.ROOT).format(v / 2.)),