Index: trunk/src/org/openstreetmap/josm/data/osm/FilterMatcher.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/FilterMatcher.java	(revision 3366)
+++ trunk/src/org/openstreetmap/josm/data/osm/FilterMatcher.java	(revision 3367)
@@ -17,4 +17,5 @@
         final Match match;
         final boolean isDelete;
+        final boolean isInverted;
 
         FilterInfo(Filter filter) throws ParseError {
@@ -27,4 +28,5 @@
             Match compiled = SearchCompiler.compile(filter.text, filter.caseSensitive, filter.regexSearch);
             this.match = filter.inverted?new Not(compiled):compiled;
+            this.isInverted = filter.inverted;
         }
     }
@@ -43,33 +45,87 @@
             }
 
-            List<FilterInfo> list = filter.hiding?hiddenFilters:disabledFilters;
+            FilterInfo fi = new FilterInfo(filter);
+            if (fi.isDelete) {
+                if (filter.hiding) {
+                    // Remove only hide flag
+                    hiddenFilters.add(fi);
+                } else {
+                    // Remove both flags
+                    disabledFilters.add(fi);
+                    hiddenFilters.add(fi);
+                }
+            } else {
+                if (filter.mode == SearchMode.replace) {
+                    if (filter.hiding) {
+                        hiddenFilters.clear();
+                        disabledFilters.clear();
+                    }
+                }
 
-            if (filter.mode == SearchMode.replace) {
-                // No point in evalutaing filter when value will get replaced anyway (and yes, there is no point in using replace mode with filters)
-                list.clear();
+                disabledFilters.add(fi);
+                if (filter.hiding) {
+                    hiddenFilters.add(fi);
+                }
             }
-
-            list.add(new FilterInfo(filter));
         }
     }
 
-    private boolean test(List<FilterInfo> filters, OsmPrimitive primitive) {
+    private boolean getState(OsmPrimitive primitive, boolean hidden) {
+        return hidden?primitive.isDisabledAndHidden():primitive.isDisabled();
+    }
+
+    private boolean allParentWaysFiltered(OsmPrimitive primitive, boolean hidden) {
+        List<OsmPrimitive> refs = primitive.getReferrers();
+        if (refs.isEmpty())
+            return false;
+
+        for (OsmPrimitive p: refs) {
+            if (p instanceof Way && !getState(p, hidden))
+                return false;
+        }
+
+        return true;
+    }
+
+    private boolean oneParentWayNotFiltered(OsmPrimitive primitive, boolean hidden) {
+        List<OsmPrimitive> refs = primitive.getReferrers();
+        for (OsmPrimitive p: refs) {
+            if (p instanceof Way && !getState(p, hidden))
+                return true;
+        }
+
+        return false;
+    }
+
+    private boolean test(List<FilterInfo> filters, OsmPrimitive primitive, boolean hidden) {
         boolean selected = false;
+        boolean onlyInvertedFilters = true;
+
         for (FilterInfo fi: filters) {
             if (fi.isDelete && selected && fi.match.match(primitive)) {
                 selected = false;
-            } else if (!fi.isDelete && !selected && fi.match.match(primitive)) {
+            } else if (!fi.isDelete && (!selected || (onlyInvertedFilters && !fi.isInverted)) && fi.match.match(primitive)) {
                 selected = true;
+                onlyInvertedFilters = onlyInvertedFilters && fi.isInverted;
             }
         }
-        return selected;
+
+        if (primitive instanceof Node) {
+            if (!selected)
+                return !primitive.isTagged() && allParentWaysFiltered(primitive, hidden);
+            if (onlyInvertedFilters)
+                return selected && !oneParentWayNotFiltered(primitive, hidden);
+            return true;
+        } else
+            return selected;
+
     }
 
     public boolean isHidden(OsmPrimitive primitive) {
-        return test(hiddenFilters, primitive);
+        return test(hiddenFilters, primitive, true);
     }
 
     public boolean isDisabled(OsmPrimitive primitive) {
-        return test(disabledFilters, primitive);
+        return test(disabledFilters, primitive, false);
     }
 
Index: trunk/src/org/openstreetmap/josm/data/osm/FilterWorker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/FilterWorker.java	(revision 3366)
+++ trunk/src/org/openstreetmap/josm/data/osm/FilterWorker.java	(revision 3367)
@@ -33,35 +33,27 @@
      */
     public static void executeFilters(Collection<OsmPrimitive> all, FilterMatcher filterMatcher) {
+
+        // First relation and ways
         for (OsmPrimitive primitive: all) {
-            if (filterMatcher.isHidden(primitive)) {
-                primitive.setDisabledState(true);
-            } else if (filterMatcher.isDisabled(primitive)) {
-                primitive.setDisabledState(false);
-            } else {
-                primitive.unsetDisabledState();
+            if (!(primitive instanceof Node)) {
+                if (filterMatcher.isHidden(primitive)) {
+                    primitive.setDisabledState(true);
+                } else if (filterMatcher.isDisabled(primitive)) {
+                    primitive.setDisabledState(false);
+                } else {
+                    primitive.unsetDisabledState();
+                }
             }
         }
 
+        // Then nodes (because they state may depend on parent ways)
         for (OsmPrimitive primitive: all) {
-            if (primitive instanceof Way && primitive.isDisabled()) {
-                Way w = (Way)primitive;
-                for (Node n: w.getNodes()) {
-
-                    if (n.isTagged()) {
-                        continue;
-                    }
-
-                    boolean disabled = w.isDisabled();
-                    boolean hidden = w.isDisabledAndHidden();
-                    for (OsmPrimitive ref: n.getReferrers()) {
-                        if (ref instanceof Way) {
-                            disabled = disabled && ref.isDisabled();
-                            hidden = hidden && ref.isDisabledAndHidden();
-                        }
-                    }
-
-                    if (disabled) {
-                        n.setDisabledState(hidden);
-                    }
+            if (primitive instanceof Node) {
+                if (filterMatcher.isHidden(primitive)) {
+                    primitive.setDisabledState(true);
+                } else if (filterMatcher.isDisabled(primitive)) {
+                    primitive.setDisabledState(false);
+                } else {
+                    primitive.unsetDisabledState();
                 }
             }
