Index: /trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 19591)
+++ /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 19592)
@@ -621,5 +621,5 @@
 
         MapFrame map = MainApplication.getMap();
-        if (AutoFilterManager.getInstance().getCurrentAutoFilter() != null) {
+        if (AutoFilterManager.getInstance().getCurrentCombinedFilter() != null) {
             AutoFilterManager.getInstance().drawOSDText(tempG);
         } else if (MainApplication.isDisplayingMapView() && map.filterDialog != null) {
Index: /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterButton.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterButton.java	(revision 19591)
+++ /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterButton.java	(revision 19592)
@@ -15,5 +15,4 @@
 import org.openstreetmap.josm.actions.PreferencesAction;
 import org.openstreetmap.josm.data.preferences.NamedColorProperty;
-import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.preferences.display.DrawingPreference;
 
@@ -36,11 +35,26 @@
             @Override
             public synchronized void actionPerformed(ActionEvent e) {
+
                 AutoFilterManager afm = AutoFilterManager.getInstance();
-                if (filter.equals(afm.getCurrentAutoFilter())) {
-                    afm.setCurrentAutoFilter(null);
-                    MainApplication.getMap().filterDialog.getFilterModel().executeFilters(true);
+
+                if (afm.getCurrentAutoFilters().isEmpty()) {
+                    afm.setCurrentAutoFilter(filter);
                 } else {
-                    afm.setCurrentAutoFilter(filter);
+                    if ((e.getModifiers() & ActionEvent.CTRL_MASK) != 0
+                            || (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0) {
+                        if (afm.getCurrentAutoFilters().contains(filter)) {
+                            afm.removeCurrentAutoFilter(filter);
+                        } else {
+                            afm.addCurrentAutoFilter(filter);
+                        }
+                    } else {
+                        if (afm.getCurrentAutoFilters().size() == 1 && afm.getCurrentAutoFilters().contains(filter)) {
+                            afm.setCurrentAutoFilter(null);
+                        } else {
+                            afm.setCurrentAutoFilter(filter);
+                        }
+                    }
                 }
+
             }
         });
@@ -55,5 +69,5 @@
         if (getModel().isPressed()) {
             g.setColor(PROP_COLOR.get().darker().darker());
-        } else if (getModel().isRollover() || AutoFilterManager.getInstance().getCurrentAutoFilter() == filter) {
+        } else if (getModel().isRollover() || AutoFilterManager.getInstance().getCurrentAutoFilters().contains(filter)) {
             g.setColor(PROP_COLOR.get().darker());
         } else {
Index: /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java	(revision 19591)
+++ /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java	(revision 19592)
@@ -9,11 +9,13 @@
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NavigableSet;
 import java.util.Objects;
-import java.util.TreeMap;
+import java.util.OptionalInt;
 import java.util.TreeSet;
-import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 import org.openstreetmap.josm.actions.mapmode.MapMode;
@@ -64,9 +66,16 @@
 
     /**
-     * Property to determines if the auto filter feature is enabled.
+     * Property to determine if the auto filter feature is enabled.
      */
     public static final BooleanProperty PROP_AUTO_FILTER_ENABLED = new BooleanProperty("auto.filter.enabled", true);
 
     /**
+     * Property to determine if the auto filter feature completely hides elements instead of just disabling them.
+     * Equivalent to {@link Filter#hiding}
+     */
+    public static final BooleanProperty PROP_AUTO_FILTER_HIDING = new BooleanProperty("auto.filter.hiding", false);
+
+
+    /**
      * Property to determine the current auto filter rule.
      */
@@ -81,5 +90,5 @@
      * The buttons currently displayed in map view.
      */
-    private final Map<Integer, AutoFilterButton> buttons = new TreeMap<>();
+    private final Map<OptionalInt, AutoFilterButton> buttons = new HashMap<>();
 
     /**
@@ -104,7 +113,8 @@
 
     /**
-     * The currently selected auto filter, if any.
-     */
-    private AutoFilter currentAutoFilter;
+     * The currently selected auto filters, if any.
+     * If more than one auto filter is active, elements will match if they match at least one of them.
+     */
+    private final List<AutoFilter> currentAutoFilters = new ArrayList<>();
 
     /**
@@ -134,9 +144,13 @@
             // Retrieve the values from current rule visible on screen
             NavigableSet<Integer> values = getNumericValues();
-            // Make sure current auto filter button remains visible even if no data is found, to allow user to disable it
-            if (currentAutoFilter != null) {
-                values.add(currentAutoFilter.getFilter().value);
-            }
-            if (!values.equals(buttons.keySet())) {
+            // Make sure current auto filter buttons remain visible even if no data is found, to allow user to disable them
+            for (var currentAutoFilter : currentAutoFilters) {
+                if (currentAutoFilter.getFilter().value != null) {
+                    values.add(currentAutoFilter.getFilter().value);
+                }
+            }
+            if (!values.equals(buttons.keySet().stream()
+                    .filter(it -> it.isPresent() && it.getAsInt() != Integer.MIN_VALUE)
+                    .map(OptionalInt::getAsInt).collect(Collectors.toSet()))) {
                 removeAllButtons();
                 addNewButtons(values);
@@ -147,9 +161,10 @@
     static class CompiledFilter extends Filter implements MatchSupplier {
         final AutoFilterRule rule;
-        final int value;
-
-        CompiledFilter(AutoFilterRule rule, int value) {
+        final Integer value;
+
+        CompiledFilter(AutoFilterRule rule, Integer value, boolean hiding) {
             this.rule = rule;
             this.value = value;
+            this.hiding = hiding;
             this.enable = true;
             this.inverted = true;
@@ -174,5 +189,59 @@
                 return false;
             CompiledFilter other = (CompiledFilter) obj;
-            return Objects.equals(rule, other.rule) && value == other.value;
+            return Objects.equals(rule, other.rule) && Objects.equals(value, other.value);
+        }
+    }
+
+    /** The combination of multiple {@link CompiledFilter}s */
+    static class CombinedFilter extends Filter implements MatchSupplier {
+
+        private final List<CompiledFilter> filters;
+
+        CombinedFilter(List<CompiledFilter> filters) {
+
+            if (filters == null || filters.isEmpty()) throw new IllegalArgumentException("no filters provided");
+
+            this.filters = filters;
+
+            boolean hiding = filters.get(0).hiding;
+            String key = filters.get(0).rule.getKey();
+            List<String> values = new ArrayList<>();
+
+            for (CompiledFilter filter : filters) {
+                if (hiding != filter.hiding) throw new IllegalArgumentException("non-matching hiding properties");
+                if (!Objects.equals(key, filter.rule.getKey())) throw new IllegalArgumentException("non-matching keys");
+                values.add(filter.rule.formatValue(filter.value));
+            }
+
+            this.hiding = hiding;
+            this.enable = true;
+            this.inverted = true;
+            this.text = key + "~" + String.join("|", values);
+
+        }
+
+        @Override
+        public SearchCompiler.Match get() {
+            return new SearchCompiler.Match() {
+                @Override
+                public boolean match(OsmPrimitive osm) {
+                    return filters.stream().anyMatch(filter -> filter.get().match(osm));
+                }
+            };
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * super.hashCode() + Objects.hash(filters);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (!super.equals(obj) || getClass() != obj.getClass())
+                return false;
+            CombinedFilter other = (CombinedFilter) obj;
+            return Objects.equals(filters, other.filters);
         }
     }
@@ -180,7 +249,7 @@
     static class Match extends SearchCompiler.Match {
         final AutoFilterRule rule;
-        final int value;
-
-        Match(AutoFilterRule rule, int value) {
+        final Integer value;
+
+        Match(AutoFilterRule rule, Integer value) {
             this.rule = rule;
             this.value = value;
@@ -189,5 +258,10 @@
         @Override
         public boolean match(OsmPrimitive osm) {
-            return rule.getTagValuesForPrimitive(osm).anyMatch(v -> v == value);
+            IntStream values = rule.getTagValuesForPrimitive(osm, false);
+            if (value != null) {
+                return values.anyMatch(v -> v == value);
+            } else {
+                return values.findAny().isEmpty();
+            }
         }
 
@@ -197,5 +271,5 @@
             if (o == null || getClass() != o.getClass()) return false;
             Match match = (Match) o;
-            return value == match.value &&
+            return Objects.equals(value, match.value) &&
                     Objects.equals(rule, match.rule);
         }
@@ -215,14 +289,18 @@
         final AutoFilterButton keyButton = AutoFilterButton.forOsmKey(enabledRule.getKey());
         addButton(keyButton, Integer.MIN_VALUE, i++);
-        for (final Integer value : values.descendingSet()) {
-            CompiledFilter filter = new CompiledFilter(enabledRule, value);
+        var valueList = new ArrayList<>(values.descendingSet());
+        if (enabledRule.getNoValueFilter()) {
+            valueList.add(null);
+        }
+        for (final Integer value : valueList) {
+            CompiledFilter filter = new CompiledFilter(enabledRule, value, PROP_AUTO_FILTER_HIDING.get());
             String label = enabledRule.formatValue(value);
             AutoFilter autoFilter = new AutoFilter(label, filter.text, filter);
             AutoFilterButton button = new AutoFilterButton(autoFilter);
-            if (autoFilter.equals(currentAutoFilter)) {
+            if (currentAutoFilters.contains(autoFilter)) {
                 button.getModel().setPressed(true);
             }
+            addButton(button, value, i++);
             maxWidth = Math.max(maxWidth, button.getPreferredSize().width);
-            addButton(button, value, i++);
         }
         for (AutoFilterButton b : buttons.values()) {
@@ -232,7 +310,7 @@
     }
 
-    private void addButton(AutoFilterButton button, int value, int i) {
+    private void addButton(AutoFilterButton button, Integer value, int i) {
         MapView mapView = MainApplication.getMap().mapView;
-        buttons.put(value, button);
+        buttons.put(value == null ? OptionalInt.empty() : OptionalInt.of(value), button);
         mapView.add(button).setLocation(3, 60 + 22*i);
     }
@@ -253,8 +331,13 @@
         BBox bbox = MainApplication.getMap().mapView.getState().getViewArea().getLatLonBoundsBox().toBBox();
         NavigableSet<Integer> values = new TreeSet<>();
-        Consumer<OsmPrimitive> consumer = o -> enabledRule.getTagValuesForPrimitive(o).forEach(values::add);
-        ds.searchNodes(bbox).forEach(consumer);
-        ds.searchWays(bbox).forEach(consumer);
-        ds.searchRelations(bbox).forEach(consumer);
+        for (var primitiveList : List.of(ds.searchNodes(bbox), ds.searchWays(bbox), ds.searchRelations(bbox))) {
+            // add all values that are directly mentioned
+            primitiveList.forEach(o -> enabledRule.getTagValuesForPrimitive(o, true).forEach(values::add));
+            // only add integer values from value ranges, not fractional values
+            primitiveList.forEach(o -> enabledRule.getTagValuesForPrimitive(o, false)
+                    .filter(v -> !enabledRule.formatValue(v).contains("."))
+                    .forEach(values::add));
+
+        }
         return values;
     }
@@ -268,4 +351,5 @@
     public void dataChanged(DataChangedEvent event) {
         updateFiltersFull();
+        updateButtons();
     }
 
@@ -314,5 +398,5 @@
 
     private synchronized void updateFiltersFull() {
-        if (currentAutoFilter != null) {
+        if (!currentAutoFilters.isEmpty()) {
             model.executeFilters();
         }
@@ -320,5 +404,5 @@
 
     private synchronized void updateFiltersEvent(AbstractDatasetChangedEvent event, boolean affectedOnly) {
-        if (currentAutoFilter != null) {
+        if (!currentAutoFilters.isEmpty()) {
             Collection<? extends OsmPrimitive> prims = event.getPrimitives();
             model.executeFilters(affectedOnly ? FilterModel.getAffectedPrimitives(prims) : prims);
@@ -383,9 +467,23 @@
 
     /**
-     * Returns the currently selected auto filter, if any.
-     * @return the currently selected auto filter, or null
-     */
-    public synchronized AutoFilter getCurrentAutoFilter() {
-        return currentAutoFilter;
+     * Returns the currently selected auto filters, if any.
+     * @return the currently selected auto filters. Can be empty.
+     */
+    public synchronized List<AutoFilter> getCurrentAutoFilters() {
+        return currentAutoFilters;
+    }
+
+    /**
+     * Returns a combination of all {@link #getCurrentAutoFilters()}, if any.
+     * @return a single combined filter, or null
+     */
+    public Filter getCurrentCombinedFilter() {
+        if (currentAutoFilters.isEmpty()) {
+            return null;
+        } else if (currentAutoFilters.size() == 1) {
+            return currentAutoFilters.get(0).getFilter();
+        } else {
+            return new CombinedFilter(currentAutoFilters.stream().map(AutoFilter::getFilter).collect(Collectors.toList()));
+        }
     }
 
@@ -395,14 +493,38 @@
      */
     public synchronized void setCurrentAutoFilter(AutoFilter autoFilter) {
+        currentAutoFilters.clear();
+        if (autoFilter != null) {
+            currentAutoFilters.add(autoFilter);
+        }
+        updateModelFilters();
+    }
+
+    public synchronized void addCurrentAutoFilter(AutoFilter autoFilter) {
+        if (!currentAutoFilters.contains(autoFilter)) {
+            currentAutoFilters.add(autoFilter);
+            updateModelFilters();
+        }
+    }
+
+    public synchronized void removeCurrentAutoFilter(AutoFilter autoFilter) {
+        if (currentAutoFilters.contains(autoFilter)) {
+            currentAutoFilters.removeIf(it -> Objects.equals(it, autoFilter));
+            updateModelFilters();
+        }
+    }
+
+    private synchronized void updateModelFilters() {
         model.clearFilters();
-        currentAutoFilter = autoFilter;
-        if (autoFilter != null) {
-            model.addFilter(autoFilter.getFilter());
+        if (currentAutoFilters.isEmpty()) {
+            if (MainApplication.getMap() != null) {
+                MainApplication.getMap().filterDialog.getFilterModel().executeFilters(true);
+            }
+        } else {
+            model.addFilter(getCurrentCombinedFilter());
             model.executeFilters();
-            if (model.isChanged()) {
-                OsmDataLayer dataLayer = MainApplication.getLayerManager().getActiveDataLayer();
-                if (dataLayer != null) {
-                    dataLayer.invalidate();
-                }
+            // update the data layer (necessary even if model.isChanged() == false to update the OSDText)
+            OsmDataLayer dataLayer = MainApplication.getLayerManager().getActiveDataLayer();
+            if (dataLayer != null) {
+                dataLayer.invalidate();
             }
         }
@@ -414,6 +536,8 @@
      */
     public synchronized void drawOSDText(Graphics2D g) {
+        String filterText = Objects.requireNonNull(getCurrentCombinedFilter()).text;
+        String lengthLimitedFilterText = filterText.length() > 18 ? filterText.substring(0, 18) + "…" : filterText;
         model.drawOSDText(g, lblOSD,
-            tr("<h2>Filter active: {0}</h2>", currentAutoFilter.getFilter().text),
+            tr("<h2>Filter active: {0}</h2>", lengthLimitedFilterText),
             tr("</p><p>Click again on filter button to see all objects.</p></html>"));
     }
@@ -438,5 +562,6 @@
                 resetCurrentAutoFilter();
             }
-        } else if (e.getKey().equals(PROP_AUTO_FILTER_RULE.getKey())) {
+        } else if (e.getKey().equals(PROP_AUTO_FILTER_RULE.getKey())
+                || e.getKey().equals(PROP_AUTO_FILTER_HIDING.getKey())) {
             enableAutoFilterRule(PROP_AUTO_FILTER_RULE.get());
             resetCurrentAutoFilter();
Index: /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java	(revision 19591)
+++ /trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java	(revision 19592)
@@ -4,7 +4,10 @@
 import java.text.DecimalFormat;
 import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.function.IntFunction;
@@ -13,4 +16,5 @@
 import java.util.regex.Pattern;
 import java.util.stream.IntStream;
+import java.util.stream.Stream;
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -18,4 +22,6 @@
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.tools.Logging;
+
+import static java.util.stream.Collectors.toList;
 
 /**
@@ -43,4 +49,9 @@
     private IntFunction<String> valueFormatter = Integer::toString;
 
+    private boolean noValueFilter = false;
+
+    /** The union of {@link #key} and the keys provided by {@link #setExtraKeys(List)}. */
+    private List<String> allKeys;
+
     /**
      * Constructs a new {@code AutoFilterRule}.
@@ -51,4 +62,5 @@
         this.key = key;
         this.minZoomLevel = minZoomLevel;
+        this.allKeys = List.of(key);
     }
 
@@ -67,4 +79,12 @@
     public int getMinZoomLevel() {
         return minZoomLevel;
+    }
+
+    /**
+     * Returns true if there should be a filter button for OSM primitives which have no value for the key.
+     * @since xxx
+     */
+    public boolean getNoValueFilter() {
+        return noValueFilter;
     }
 
@@ -73,7 +93,8 @@
      * @param value the numeric value to format
      * @return the formatted value
-     */
-    public String formatValue(int value) {
-        return valueFormatter.apply(value);
+     * @since xxx
+     */
+    public String formatValue(Integer value) {
+        return value == null ? "∅" : valueFormatter.apply(value);
     }
 
@@ -113,9 +134,52 @@
 
     /**
+     * Adds a filter button for OSM primitives which have no value for the key.
+     */
+    public AutoFilterRule enableNoValueFilter() {
+        this.noValueFilter = true;
+        return this;
+    }
+
+    /**
+     * Sets extra OSM keys on which the rule applies in addition to the primary key ({@link #getKey()}).
+     * This allows a filter to look at the values of more than one key at the same time.
+     * @param extraKeys the list of extra keys, may be empty
+     * @return {@code this}
+     * @throws NullPointerException if {@code extraKeys} is null
+     * @since xxx
+     */
+    public AutoFilterRule setExtraKeys(List<String> extraKeys) {
+        Objects.requireNonNull(extraKeys);
+        this.allKeys = Stream.concat(Stream.of(key), extraKeys.stream()).collect(toList());
+        return this;
+    }
+
+    /**
      * Returns the numeric values for the given OSM primitive
-     * @param osm the primitive
+     *
+     * @param osm              the primitive
+     * @param directValuesOnly whether "inner" values from ranges (such as 6 and 7 for 5-8) should be omitted
      * @return a stream of numeric values
-     */
-    public IntStream getTagValuesForPrimitive(OsmPrimitive osm) {
+     * @since xxx
+     */
+    public IntStream getTagValuesForPrimitive(OsmPrimitive osm, boolean directValuesOnly) {
+        if (osm.isDeleted()) return IntStream.empty();
+        if (allKeys.size() == 1) {
+            IntStream values = getTagValuesForPrimitive(osm, key, directValuesOnly);
+            if (values != null) return values;
+        } else {
+            Set<Integer> allValues = new HashSet<>();
+            for (String k : allKeys) {
+                IntStream values = getTagValuesForPrimitive(osm, k, directValuesOnly);
+                if (values != null) {
+                    values.forEach(allValues::add);
+                }
+            }
+            if (!allValues.isEmpty()) return allValues.stream().mapToInt(it -> it).sorted();
+        }
+        return Boolean.TRUE.equals(PROP_AUTO_FILTER_DEFAULTS.get()) ? defaultValueSupplier.apply(osm) : IntStream.empty();
+    }
+
+    private IntStream getTagValuesForPrimitive(OsmPrimitive osm, String key, boolean directValuesOnly) {
         String value = osm.get(key);
         if (value != null) {
@@ -126,5 +190,9 @@
                     int a = valueExtractor.applyAsInt(m.group(1));
                     int b = valueExtractor.applyAsInt(m.group(2));
-                    return IntStream.rangeClosed(Math.min(a, b), Math.max(a, b));
+                    if (directValuesOnly && a != b) {
+                        return IntStream.of(a, b).sorted();
+                    } else {
+                        return IntStream.rangeClosed(Math.min(a, b), Math.max(a, b));
+                    }
                 } else {
                     try {
@@ -137,5 +205,5 @@
             });
         }
-        return Boolean.TRUE.equals(PROP_AUTO_FILTER_DEFAULTS.get()) ? defaultValueSupplier.apply(osm) : IntStream.empty();
+        return null;
     }
 
@@ -157,4 +225,6 @@
                     .setDefaultValueSupplier(AutoFilterRule::defaultLayer),
             new AutoFilterRule("level", 17)
+                .setExtraKeys(List.of("repeat_on"))
+                .enableNoValueFilter()
                 // #17109, support values like 0.5 or 1.5 - level values are multiplied by 2 when parsing, values are divided by 2 for formatting
                 .setValueExtractor(s -> (int) (Double.parseDouble(s) * 2.))
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java	(revision 19591)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java	(revision 19592)
@@ -99,5 +99,5 @@
      */
     public void executeFilters(boolean force) {
-        if (AutoFilterManager.getInstance().getCurrentAutoFilter() == null && (force || model.hasFilters())) {
+        if (AutoFilterManager.getInstance().getCurrentCombinedFilter() == null && (force || model.hasFilters())) {
             model.executeFilters();
             updateMap();
@@ -112,5 +112,5 @@
      */
     public void executeFilters(Collection<? extends OsmPrimitive> primitives, boolean force) {
-        if (AutoFilterManager.getInstance().getCurrentAutoFilter() == null && (force || model.hasFilters())) {
+        if (AutoFilterManager.getInstance().getCurrentCombinedFilter() == null && (force || model.hasFilters())) {
             model.executeFilters(primitives);
             updateMap();
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/DrawingPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/DrawingPreference.java	(revision 19591)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/DrawingPreference.java	(revision 19592)
@@ -57,4 +57,6 @@
     private final JCheckBox discardableKeys = new JCheckBox(tr("Display discardable keys"));
     private final JCheckBox autoFilters = new JCheckBox(tr("Use auto filters"));
+    private final JCheckBox autoFiltersHiding = new JCheckBox(tr("Hide auto-filtered elements"));
+
     private final JLabel lblRule = new JLabel(tr("Rule"));
     private final JosmComboBox<AutoFilterRule> autoFilterRules = new JosmComboBox<>(
@@ -150,7 +152,11 @@
             lblRule.setEnabled(autoFilters.isSelected());
             autoFilterRules.setEnabled(autoFilters.isSelected());
+            autoFiltersHiding.setEnabled(autoFilters.isSelected());
         });
         autoFilterRules.setToolTipText("Rule defining which tag will provide automatic filters, below a certain zoom level");
         autoFilterRules.setSelectedItem(AutoFilterManager.getInstance().getAutoFilterRule(AutoFilterManager.PROP_AUTO_FILTER_RULE.get()));
+        autoFiltersHiding.setToolTipText(
+            tr("Completely hide elements which do not match the automatic filter instead of merely disabling them"));
+        autoFiltersHiding.setSelected(AutoFilterManager.PROP_AUTO_FILTER_HIDING.get());
 
         JLabel performanceLabel = new JLabel(tr("Options that affect drawing performance"));
@@ -184,4 +190,5 @@
         panel.add(lblRule, GBC.std().insets(40, 0, 0, 0));
         panel.add(autoFilterRules, GBC.eop().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
+        panel.add(autoFiltersHiding, GBC.eop().insets(40, 0, 0, 0));
 
         ExpertToggleAction.addVisibilitySwitcher(performanceLabel);
@@ -214,4 +221,5 @@
         Config.getPref().putBoolean("display.discardable-keys", discardableKeys.isSelected());
         AutoFilterManager.PROP_AUTO_FILTER_ENABLED.put(autoFilters.isSelected());
+        AutoFilterManager.PROP_AUTO_FILTER_HIDING.put(autoFiltersHiding.isSelected());
         AutoFilterManager.PROP_AUTO_FILTER_RULE.put(((AutoFilterRule) autoFilterRules.getSelectedItem()).getKey());
         int vn = Config.getPref().getInt("mappaint.node.virtual-size", 8);
Index: /trunk/test/unit/org/openstreetmap/josm/gui/autofilter/AutoFilterRuleTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/autofilter/AutoFilterRuleTest.java	(revision 19591)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/autofilter/AutoFilterRuleTest.java	(revision 19592)
@@ -23,5 +23,5 @@
 class AutoFilterRuleTest {
     /**
-     * Unit test of {@link AutoFilterRule#getTagValuesForPrimitive}.
+     * Unit test of {@link AutoFilterRule#getTagValuesForPrimitive(OsmPrimitive, boolean)}.
      */
     @Test
@@ -37,4 +37,6 @@
         assertTagValuesForPrimitive(level, "way level=10;12-13", 20, 24, 25, 26);
         assertTagValuesForPrimitive(level, "way level=0;0.5;1;1.5;2;2.5;3", 0, 1, 2, 3, 4, 5, 6);
+        assertTagValuesForPrimitive(level, "node level=0 repeat_on=1;2", 0, 2, 4);
+        assertTagValuesForPrimitive(level, "way level=4 repeat_on=4;5 layer=1", 8, 10);
         assertEquals("0 0.5 1 1.5 2 2.5 3",
                 IntStream.of(0, 1, 2, 3, 4, 5, 6).mapToObj(level::formatValue).collect(Collectors.joining(" ")));
@@ -42,5 +44,5 @@
 
     /**
-     * Unit test of {@link AutoFilterRule#getTagValuesForPrimitive} to deal with {@code %} of key {@code incline}.
+     * Unit test of {@link AutoFilterRule#getTagValuesForPrimitive(OsmPrimitive, boolean)} to deal with {@code %} of key {@code incline}.
      */
     @Test
@@ -53,5 +55,5 @@
 
     /**
-     * Unit test of {@link AutoFilterRule#getTagValuesForPrimitive} provides sensible defaults, see #17496.
+     * Unit test of {@link AutoFilterRule#getTagValuesForPrimitive(OsmPrimitive, boolean)} provides sensible defaults, see #17496.
      */
     @Test
@@ -70,5 +72,5 @@
     private void assertTagValuesForPrimitive(AutoFilterRule rule, String assertion, int... expected) {
         final OsmPrimitive primitive = OsmUtils.createPrimitive(assertion);
-        final int[] actual = rule.getTagValuesForPrimitive(primitive).toArray();
+        final int[] actual = rule.getTagValuesForPrimitive(primitive, false).toArray();
         assertArrayEquals(expected, actual);
     }
