Ticket #3475: diff3

File diff3, 50.3 KB (added by petr.dlouhy (at) email.cz, 3 years ago)

filters.patch

Line 
1Index: src/org/openstreetmap/josm/actions/SplitWayAction.java
2===================================================================
3--- src/org/openstreetmap/josm/actions/SplitWayAction.java      (revision 2114)
4+++ src/org/openstreetmap/josm/actions/SplitWayAction.java      (working copy)
5@@ -101,7 +101,7 @@
6             HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();
7             for (Node n : selectedNodes) {
8                 for (Way w : getCurrentDataSet().ways) {
9-                    if (w.isDeleted() || w.incomplete) {
10+                    if (w.isDeleted() || w.isDisabled() || w.incomplete) {
11                         continue;
12                     }
13                     int last = w.getNodesCount()-1;
14@@ -292,7 +292,7 @@
15         // now copy all relations to new way also
16 
17         for (Relation r : getCurrentDataSet().relations) {
18-            if (r.isDeleted() || r.incomplete) {
19+            if (r.isDeleted() || r.isDisabled() || r.incomplete) {
20                 continue;
21             }
22             Relation c = null;
23Index: src/org/openstreetmap/josm/actions/search/SearchAction.java
24===================================================================
25--- src/org/openstreetmap/josm/actions/search/SearchAction.java (revision 2114)
26+++ src/org/openstreetmap/josm/actions/search/SearchAction.java (working copy)
27@@ -24,13 +24,14 @@
28 import org.openstreetmap.josm.gui.ExtendedDialog;
29 import org.openstreetmap.josm.tools.GBC;
30 import org.openstreetmap.josm.tools.Shortcut;
31+import org.openstreetmap.josm.data.osm.Filter;
32 
33 public class SearchAction extends JosmAction{
34 
35     public static final int SEARCH_HISTORY_SIZE = 10;
36 
37     public static enum SearchMode {
38-        replace, add, remove
39+        replace, add, remove, in_selection
40     }
41 
42     public static final LinkedList<SearchSetting> searchHistory = new LinkedList<SearchSetting>();
43@@ -56,33 +57,46 @@
44         }
45         SearchSetting s = lastSearch;
46         if (s == null) {
47-            s = new SearchSetting("", false, false, SearchMode.replace);
48+            s = new SearchSetting("", SearchMode.replace, false, false);
49         }
50-        showSearchDialog(s);
51+        SearchSetting se = showSearchDialog(s);
52+        if(se != null) searchWithHistory(se);
53     }
54 
55-    public void showSearchDialog(SearchSetting initialValues) {
56-        JLabel label = new JLabel(tr("Please enter a search string."));
57+    public static SearchSetting showSearchDialog(SearchSetting initialValues) {
58+        JLabel label = new JLabel( initialValues instanceof Filter ? tr("Please enter a filter string.") : tr("Please enter a search string."));
59         final JTextField input = new JTextField(initialValues.text);
60         input.selectAll();
61         input.requestFocusInWindow();
62         JRadioButton replace = new JRadioButton(tr("replace selection"), initialValues.mode == SearchMode.replace);
63         JRadioButton add = new JRadioButton(tr("add to selection"), initialValues.mode == SearchMode.add);
64         JRadioButton remove = new JRadioButton(tr("remove from selection"), initialValues.mode == SearchMode.remove);
65+        JRadioButton in_selection = new JRadioButton(tr("find in selection"), initialValues.mode == SearchMode.in_selection);
66         ButtonGroup bg = new ButtonGroup();
67         bg.add(replace);
68         bg.add(add);
69         bg.add(remove);
70+        bg.add(in_selection);
71 
72         JCheckBox caseSensitive = new JCheckBox(tr("case sensitive"), initialValues.caseSensitive);
73         JCheckBox regexSearch   = new JCheckBox(tr("regular expression"), initialValues.regexSearch);
74 
75         JPanel left = new JPanel(new GridBagLayout());
76+
77+        JTextField finput = null;
78+        if(initialValues instanceof Filter){
79+           JLabel fLabel = new JLabel(tr("Please enter a filter name."));
80+           finput = new JTextField(((Filter)initialValues).filterName);
81+           left.add(fLabel, GBC.eop());
82+           left.add(finput, GBC.eop().fill(GBC.HORIZONTAL));
83+        }
84+
85         left.add(label, GBC.eop());
86         left.add(input, GBC.eop().fill(GBC.HORIZONTAL));
87         left.add(replace, GBC.eol());
88         left.add(add, GBC.eol());
89-        left.add(remove, GBC.eop());
90+        left.add(remove, GBC.eol());
91+        left.add(in_selection, GBC.eop());
92         left.add(caseSensitive, GBC.eol());
93         left.add(regexSearch, GBC.eol());
94 
95@@ -119,21 +133,27 @@
96         p.add(right);
97         ExtendedDialog dialog = new ExtendedDialog(
98                 Main.parent,
99-                tr("Search"),
100-                new String[] {tr("Start Search"), tr("Cancel")}
101+                initialValues instanceof Filter ? tr("Filter") : tr("Search"),
102+                new String[] {
103+                   initialValues instanceof Filter ? tr("Make filter") : tr("Start Search"),
104+                tr("Cancel")}
105         );
106         dialog.setButtonIcons(new String[] {"dialogs/search.png", "cancel.png"});
107         dialog.setContent(p);
108         dialog.showDialog();
109         int result = dialog.getValue();
110 
111-        if(result != 1) return;
112+        if(result != 1) return null;
113 
114         // User pressed OK - let's perform the search
115         SearchMode mode = replace.isSelected() ? SearchAction.SearchMode.replace
116-                : (add.isSelected() ? SearchAction.SearchMode.add : SearchAction.SearchMode.remove);
117-        SearchSetting setting = new SearchSetting(input.getText(), caseSensitive.isSelected(), regexSearch.isSelected(), mode);
118-        searchWithHistory(setting);
119+                : (add.isSelected() ? SearchAction.SearchMode.add
120+                : (remove.isSelected() ? SearchAction.SearchMode.remove : SearchAction.SearchMode.in_selection));
121+        if(initialValues instanceof Filter){
122+           return new Filter(input.getText(), mode, caseSensitive.isSelected(), regexSearch.isSelected(), finput.getText());
123+        } else {
124+           return new SearchSetting(input.getText(), mode, caseSensitive.isSelected(), regexSearch.isSelected());
125+        }
126     }
127 
128     /**
129@@ -150,67 +170,48 @@
130             searchHistory.removeLast();
131         }
132         lastSearch = s;
133-        search(s.text, s.mode, s.caseSensitive, s.regexSearch);
134+        search(s);
135     }
136 
137     public static void searchWithoutHistory(SearchSetting s) {
138         lastSearch = s;
139-        search(s.text, s.mode, s.caseSensitive, s.regexSearch);
140+        search(s);
141     }
142 
143-    public static void search(String search, SearchMode mode, boolean caseSensitive, boolean regexSearch) {
144-        // FIXME: This is confusing. The GUI says nothing about loading primitives from an URL. We'd like to *search*
145-        // for URLs in the current data set.
146-        // Disabling until a better solution is in place
147-        //
148-        //        if (search.startsWith("http://") || search.startsWith("ftp://") || search.startsWith("https://")
149-        //                || search.startsWith("file:/")) {
150-        //            SelectionWebsiteLoader loader = new SelectionWebsiteLoader(search, mode);
151-        //            if (loader.url != null && loader.url.getHost() != null) {
152-        //                Main.worker.execute(loader);
153-        //                return;
154-        //            }
155-        //        }
156+    public interface Function{
157+       public Boolean isSomething(OsmPrimitive o);
158+    }
159+
160+    public static Integer getSelection(SearchSetting s, Collection<OsmPrimitive> sel, Function f) {
161+        Integer foundMatches = 0;
162         try {
163-            Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
164-            SearchCompiler.Match matcher = SearchCompiler.compile(search, caseSensitive, regexSearch);
165-            int foundMatches = 0;
166+            String searchText = s.text;
167+            if(s instanceof Filter){
168+               searchText = ((Filter)s).inverted ? "-" : "";
169+               searchText = searchText + "(" + ((Filter)s).text + ")" + (((Filter)s).applyForChildren ? ("| child (" + ((Filter)s).text + ")"): "");
170+            }
171+            /*System.out.println(searchText);  */
172+            SearchCompiler.Match matcher = SearchCompiler.compile(searchText, s.caseSensitive, s.regexSearch);
173+            foundMatches = 0;
174             for (OsmPrimitive osm : Main.main.getCurrentDataSet().allNonDeletedCompletePrimitives()) {
175-                if (mode == SearchMode.replace) {
176+                if (s.mode == SearchMode.replace) {
177                     if (matcher.match(osm)) {
178                         sel.add(osm);
179                         ++foundMatches;
180                     } else {
181                         sel.remove(osm);
182                     }
183-                } else if (mode == SearchMode.add && !osm.isSelected() && matcher.match(osm)) {
184+                } else if (s.mode == SearchMode.add && !f.isSomething(osm) && matcher.match(osm)) {
185                     sel.add(osm);
186                     ++foundMatches;
187-                } else if (mode == SearchMode.remove && osm.isSelected() && matcher.match(osm)) {
188+                } else if (s.mode == SearchMode.remove && f.isSomething(osm) && matcher.match(osm)) {
189                     sel.remove(osm);
190                     ++foundMatches;
191+                } else if (s.mode == SearchMode.in_selection &&  f.isSomething(osm)&& !matcher.match(osm)) {
192+                    sel.remove(osm);
193+                    ++foundMatches;
194                 }
195             }
196-            Main.main.getCurrentDataSet().setSelected(sel);
197-            if (foundMatches == 0) {
198-                String msg = null;
199-                if (mode == SearchMode.replace) {
200-                    msg = tr("No match found for ''{0}''", search);
201-                } else if (mode == SearchMode.add) {
202-                    msg = tr("Nothing added to selection by searching for ''{0}''", search);
203-                } else if (mode == SearchMode.remove) {
204-                    msg = tr("Nothing removed from selection by searching for ''{0}''", search);
205-                }
206-                Main.map.statusLine.setHelpText(msg);
207-                JOptionPane.showMessageDialog(
208-                        Main.parent,
209-                        msg,
210-                        tr("Warning"),
211-                        JOptionPane.WARNING_MESSAGE
212-                );
213-            } else {
214-                Main.map.statusLine.setHelpText(tr("Found {0} matches", foundMatches));
215-            }
216         } catch (SearchCompiler.ParseError e) {
217             JOptionPane.showMessageDialog(
218                     Main.parent,
219@@ -220,15 +221,64 @@
220 
221             );
222         }
223+        return foundMatches;
224     }
225+
226+    public static void search(String search, SearchMode mode, boolean caseSensitive, boolean regexSearch) {
227+       search(new SearchSetting(search, mode, caseSensitive, regexSearch));
228+    }
229 
230+    public static void search(SearchSetting s) {
231+        // FIXME: This is confusing. The GUI says nothing about loading primitives from an URL. We'd like to *search*
232+        // for URLs in the current data set.
233+        // Disabling until a better solution is in place
234+        //
235+        //        if (search.startsWith("http://") || search.startsWith("ftp://") || search.startsWith("https://")
236+        //                || search.startsWith("file:/")) {
237+        //            SelectionWebsiteLoader loader = new SelectionWebsiteLoader(search, mode);
238+        //            if (loader.url != null && loader.url.getHost() != null) {
239+        //                Main.worker.execute(loader);
240+        //                return;
241+        //            }
242+        //        }
243+         
244+       Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
245+       int foundMatches = getSelection(s, sel, new Function(){
246+          public Boolean isSomething(OsmPrimitive o){
247+             return o.isSelected();
248+          }
249+       });
250+       Main.main.getCurrentDataSet().setSelected(sel);
251+       if (foundMatches == 0) {
252+           String msg = null;
253+           if (s.mode == SearchMode.replace) {
254+               msg = tr("No match found for ''{0}''", s.text);
255+           } else if (s.mode == SearchMode.add) {
256+               msg = tr("Nothing added to selection by searching for ''{0}''", s.text);
257+           } else if (s.mode == SearchMode.remove) {
258+               msg = tr("Nothing removed from selection by searching for ''{0}''", s.text);
259+           } else if (s.mode == SearchMode.in_selection) {
260+               msg = tr("Nothing find in selection by searching for ''{0}''", s.text);
261+           }
262+           Main.map.statusLine.setHelpText(msg);
263+           JOptionPane.showMessageDialog(
264+                   Main.parent,
265+                   msg,
266+                   tr("Warning"),
267+                   JOptionPane.WARNING_MESSAGE
268+           );
269+       } else {
270+           Main.map.statusLine.setHelpText(tr("Found {0} matches", foundMatches));
271+       }
272+    }
273+
274     public static class SearchSetting {
275-        String text;
276-        SearchMode mode;
277-        boolean caseSensitive;
278-        boolean regexSearch;
279+        public String text;
280+        public SearchMode mode;
281+        public boolean caseSensitive;
282+        public boolean regexSearch;
283 
284-        public SearchSetting(String text, boolean caseSensitive, boolean regexSearch, SearchMode mode) {
285+        public SearchSetting(String text, SearchMode mode, boolean caseSensitive, boolean regexSearch) {
286             super();
287             this.caseSensitive = caseSensitive;
288             this.regexSearch = regexSearch;
289Index: src/org/openstreetmap/josm/actions/UnGlueAction.java
290===================================================================
291--- src/org/openstreetmap/josm/actions/UnGlueAction.java        (revision 2114)
292+++ src/org/openstreetmap/josm/actions/UnGlueAction.java        (working copy)
293@@ -65,7 +65,7 @@
294         if (checkSelection(selection)) {
295             int count = 0;
296             for (Way w : getCurrentDataSet().ways) {
297-                if (w.isDeleted() || w.incomplete || w.getNodesCount() < 1) {
298+                if (w.isDeleted() || w.isDisabled() || w.incomplete || w.getNodesCount() < 1) {
299                     continue;
300                 }
301                 if (!w.containsNode(selectedNode)) {
302Index: src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
303===================================================================
304--- src/org/openstreetmap/josm/actions/mapmode/DrawAction.java  (revision 2114)
305+++ src/org/openstreetmap/josm/actions/mapmode/DrawAction.java  (working copy)
306@@ -766,7 +766,7 @@
307     public Way getWayForNode(Node n) {
308         Way way = null;
309         for (Way w : getCurrentDataSet().ways) {
310-            if (w.isDeleted() || w.incomplete || w.getNodesCount() < 1) {
311+            if (w.isDeleted() || w.isDisabled() || w.incomplete || w.getNodesCount() < 1) {
312                 continue;
313             }
314             Node firstNode = w.getNode(0);
315Index: src/org/openstreetmap/josm/actions/CombineWayAction.java
316===================================================================
317--- src/org/openstreetmap/josm/actions/CombineWayAction.java    (revision 2114)
318+++ src/org/openstreetmap/josm/actions/CombineWayAction.java    (working copy)
319@@ -285,7 +285,7 @@
320          */
321         public void build(DataSet ds) {
322             for (Relation r: ds.relations) {
323-                if (r.isDeleted() || r.incomplete) {
324+                if (r.isDeleted() || r.isDisabled() || r.incomplete) {
325                     continue;
326                 }
327                 Set<Way> referringWays = OsmPrimitive.getFilteredSet(r.getMemberPrimitives(), Way.class);
328Index: src/org/openstreetmap/josm/gui/SelectionManager.java
329===================================================================
330--- src/org/openstreetmap/josm/gui/SelectionManager.java        (revision 2114)
331+++ src/org/openstreetmap/josm/gui/SelectionManager.java        (working copy)
332@@ -285,14 +285,14 @@
333         } else {
334             // nodes
335             for (Node n : nc.getCurrentDataSet().nodes) {
336-                if (!n.isDeleted() && !n.incomplete && r.contains(nc.getPoint(n))) {
337+                if (!n.isDeleted() && !n.incomplete && !n.isDisabled() && r.contains(nc.getPoint(n))) {
338                     selection.add(n);
339                 }
340             }
341 
342             // ways
343             for (Way w : nc.getCurrentDataSet().ways) {
344-                if (w.isDeleted() || w.getNodesCount() == 0 || w.incomplete) {
345+                if (w.isDeleted() || w.getNodesCount() == 0 || w.incomplete || w.isDisabled()) {
346                     continue;
347                 }
348                 if (alt) {
349Index: src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
350===================================================================
351--- src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java      (revision 2114)
352+++ src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java      (working copy)
353@@ -317,7 +317,7 @@
354 
355     @Override public void visitBoundingBox(final BoundingXYVisitor v) {
356         for (final Node n : data.nodes)
357-            if (!n.isDeleted() && !n.incomplete) {
358+            if (!n.isDeleted() && !n.isFiltered() && !n.incomplete) {
359                 v.visit(n);
360             }
361     }
362@@ -440,7 +440,7 @@
363         gpxData.storageFile = file;
364         HashSet<Node> doneNodes = new HashSet<Node>();
365         for (Way w : data.ways) {
366-            if (w.incomplete || w.isDeleted()) {
367+            if (w.incomplete || w.isDeleted() || w.isFiltered()) {
368                 continue;
369             }
370             GpxTrack trk = new GpxTrack();
371@@ -452,7 +452,7 @@
372 
373             ArrayList<WayPoint> trkseg = null;
374             for (Node n : w.getNodes()) {
375-                if (n.incomplete || n.isDeleted()) {
376+                if (n.incomplete || w.isFiltered()) {
377                     trkseg = null;
378                     continue;
379                 }
380Index: src/org/openstreetmap/josm/gui/NavigatableComponent.java
381===================================================================
382--- src/org/openstreetmap/josm/gui/NavigatableComponent.java    (revision 2114)
383+++ src/org/openstreetmap/josm/gui/NavigatableComponent.java    (working copy)
384@@ -306,7 +306,7 @@
385         if(ds == null)
386             return null;
387         for (Node n : ds.nodes) {
388-            if (n.isDeleted() || n.incomplete) {
389+            if (n.isDeleted() || n.incomplete || n.isDisabled()) {
390                 continue;
391             }
392             Point sp = getPoint(n);
393@@ -337,7 +337,7 @@
394         if(ds == null)
395             return null;
396         for (Way w : ds.ways) {
397-            if (w.isDeleted() || w.incomplete) {
398+            if (w.isDeleted() || w.incomplete || w.isDisabled()) {
399                 continue;
400             }
401             Node lastN = null;
402@@ -461,12 +461,12 @@
403         if(ds == null)
404             return null;
405         for (Way w : ds.ways) {
406-            if (w.isDeleted() || w.incomplete) {
407+            if (w.isDeleted() || w.incomplete || w.isDisabled()) {
408                 continue;
409             }
410             Node lastN = null;
411             for (Node n : w.getNodes()) {
412-                if (n.isDeleted() || n.incomplete) {
413+                if (n.isDeleted() || n.incomplete || n.isDisabled()) {
414                     continue;
415                 }
416                 if (lastN == null) {
417@@ -487,7 +487,7 @@
418             }
419         }
420         for (Node n : ds.nodes) {
421-            if (!n.isDeleted() && !n.incomplete
422+            if (!n.isDeleted() && !n.incomplete && !n.isDisabled()
423                     && getPoint(n).distanceSq(p) < snapDistance) {
424                 nearest.add(n);
425             }
426@@ -509,7 +509,7 @@
427         if(ds == null)
428             return null;
429         for (Node n : ds.nodes) {
430-            if (!n.isDeleted() && !n.incomplete
431+            if (!n.isDeleted() && !n.incomplete && !n.isDisabled()
432                     && getPoint(n).distanceSq(p) < snapDistance) {
433                 nearest.add(n);
434             }
435Index: src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java
436===================================================================
437--- src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java    (revision 0)
438+++ src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java    (revision 0)
439@@ -0,0 +1,189 @@
440+// License: GPL. Copyright 2007 by Immanuel Scholz and others
441+package org.openstreetmap.josm.gui.dialogs;
442+
443+import static org.openstreetmap.josm.tools.I18n.marktr;
444+import static org.openstreetmap.josm.tools.I18n.tr;
445+import static org.openstreetmap.josm.tools.I18n.trn;
446+
447+import javax.swing.JPanel;
448+import javax.swing.JTable;
449+import javax.swing.table.JTableHeader;
450+import javax.swing.ListSelectionModel;
451+import javax.swing.JPopupMenu;
452+import javax.swing.table.AbstractTableModel;
453+import javax.swing.JScrollPane;
454+
455+import java.awt.FlowLayout;
456+import java.awt.BorderLayout;
457+import java.awt.GridLayout;
458+import java.awt.event.KeyEvent;
459+import java.awt.event.ActionListener;
460+import java.awt.event.ActionEvent;
461+import java.awt.event.MouseEvent;
462+
463+import org.openstreetmap.josm.Main;
464+import org.openstreetmap.josm.gui.SideButton;
465+import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
466+import org.openstreetmap.josm.gui.layer.DataChangeListener;
467+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
468+import org.openstreetmap.josm.gui.layer.Layer;
469+import org.openstreetmap.josm.data.osm.Filters;
470+import org.openstreetmap.josm.data.osm.Filter;
471+import org.openstreetmap.josm.tools.Shortcut;
472+import org.openstreetmap.josm.data.osm.DataSet;
473+import org.openstreetmap.josm.actions.search.SearchAction;
474+
475+/**
476+ *
477+ * @author Petr_DlouhÜ
478+ */
479+public class FilterDialog extends ToggleDialog implements DataChangeListener, LayerChangeListener {
480+    private JTable userTable;
481+    private Filters filters = new Filters();
482+    private SideButton addButton;
483+    private SideButton editButton;
484+    private SideButton deleteButton;
485+    private SideButton upButton;
486+    private SideButton downButton;
487+    private JPopupMenu popupMenu;
488+
489+    public FilterDialog(){
490+       super(tr("Filter"), "filter", tr("Filter objects and hide/disable them."),
491+               Shortcut.registerShortcut("subwindow:filter", tr("Toggle: {0}", tr("Filter")), KeyEvent.VK_F, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 162);
492+
493+       Layer.listeners.add(this);
494+       build();
495+    }
496+
497+    protected JPanel buildButtonRow() {
498+        JPanel pnl = new JPanel(new GridLayout(1, 4));
499+
500+        addButton = new SideButton(marktr("Add"), "add", "SelectionList", tr("Add filter."),
501+              new ActionListener(){
502+                 public void actionPerformed(ActionEvent evt){
503+                    Filter filter = (Filter)SearchAction.showSearchDialog(new Filter());
504+                    if(filter != null){
505+                       filters.addFilter(filter);
506+                       filters.filter();
507+                    }
508+                 }
509+              });
510+        pnl.add(addButton);
511+
512+        editButton = new SideButton(marktr("Edit"), "edit", "SelectionList", tr("Edit filter."),
513+              new ActionListener(){
514+                 public void actionPerformed(ActionEvent evt){
515+                    int index = userTable.getSelectionModel().getMinSelectionIndex();
516+                    if(index < 0) return;
517+                    Filter f = filters.getFilter(index);
518+                    Filter filter = (Filter)SearchAction.showSearchDialog(f);
519+                    if(filter != null){
520+                       filters.setFilter(index, filter);
521+                       filters.filter();
522+                    }
523+                 }
524+              });
525+        pnl.add(editButton);
526+
527+        deleteButton = new SideButton(marktr("Delete"), "delete", "SelectionList", tr("Delete filter."),
528+              new ActionListener(){
529+                 public void actionPerformed(ActionEvent evt){
530+                    int index = userTable.getSelectionModel().getMinSelectionIndex();
531+                    if(index < 0) return;
532+                    filters.removeFilter(index);
533+                 }
534+              });
535+        pnl.add(deleteButton);
536+
537+        upButton = new SideButton(marktr("Up"), "up", "SelectionList", tr("Move filter up."),
538+              new ActionListener(){
539+                 public void actionPerformed(ActionEvent evt){
540+                    int index = userTable.getSelectionModel().getMinSelectionIndex();
541+                    if(index < 0) return;
542+                    filters.moveUpFilter(index);
543+                    userTable.getSelectionModel().setSelectionInterval(index-1, index-1);
544+                 }
545+              });
546+        pnl.add(upButton);
547+       
548+        downButton = new SideButton(marktr("Down"), "down", "SelectionList", tr("Move filter down."),
549+              new ActionListener(){
550+                 public void actionPerformed(ActionEvent evt){
551+                    int index = userTable.getSelectionModel().getMinSelectionIndex();
552+                    if(index < 0) return;
553+                    filters.moveDownFilter(index);
554+                    userTable.getSelectionModel().setSelectionInterval(index+1, index+1);
555+                 }
556+              });
557+        pnl.add(downButton);
558+        return pnl;
559+    }
560+
561+    protected String[] columnToolTips = {
562+        tr("Filter elements"),
563+        tr("Disable elements"),
564+        tr("Apply also for children"),
565+        tr("Inverse filter"),
566+        null,
567+        tr("Filter mode")
568+    };
569+
570+    protected void build() {
571+        JPanel pnl = new JPanel();
572+        pnl.setLayout(new BorderLayout());
573+        userTable = new JTable(filters){
574+            protected JTableHeader createDefaultTableHeader() {
575+                return new JTableHeader(columnModel) {
576+                   public String getToolTipText(MouseEvent e) {
577+                       String tip = null;
578+                       java.awt.Point p = e.getPoint();
579+                       int index = columnModel.getColumnIndexAtX(p.x);
580+                       int realIndex = columnModel.getColumn(index).getModelIndex();
581+                       return columnToolTips[realIndex];
582+                   }
583+               };
584+           }
585+        };   
586
587+        userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
588+
589+        userTable.getColumnModel().getColumn(0).setMaxWidth(1);
590+        userTable.getColumnModel().getColumn(1).setMaxWidth(1);
591+        userTable.getColumnModel().getColumn(3).setMaxWidth(1);
592+        userTable.getColumnModel().getColumn(4).setMaxWidth(1);
593+        userTable.getColumnModel().getColumn(5).setMaxWidth(1);
594+
595+        userTable.getColumnModel().getColumn(0).setResizable(false);
596+        userTable.getColumnModel().getColumn(1).setResizable(false);
597+        userTable.getColumnModel().getColumn(3).setResizable(false);
598+        userTable.getColumnModel().getColumn(4).setResizable(false);
599+        userTable.getColumnModel().getColumn(5).setResizable(false);
600+
601+        pnl.add(new JScrollPane(userTable), BorderLayout.CENTER);
602+
603+        // -- the button row
604+        pnl.add(buildButtonRow(), BorderLayout.SOUTH);
605+        /*userTable.addMouseListener(new DoubleClickAdapter());*/
606+        add(pnl, BorderLayout.CENTER);
607+    }
608+
609+    public void layerRemoved(Layer a) {
610+        if (a instanceof OsmDataLayer) {
611+            ((OsmDataLayer)a).listenerDataChanged.remove(this);
612+        }
613+    }
614+
615+    public void layerAdded(Layer a) {
616+        if (a instanceof OsmDataLayer) {
617+            ((OsmDataLayer)a).listenerDataChanged.add(this);
618+        }
619+    }
620+
621+   public void activeLayerChange(Layer oldLayer, Layer newLayer) {
622+      filters.filter();
623+   }
624+
625+   public void dataChanged(OsmDataLayer l){
626+      filters.filter();
627+   }
628+}
629Index: src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
630===================================================================
631--- src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java      (revision 2114)
632+++ src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java      (working copy)
633@@ -134,7 +134,7 @@
634         if (getNumRelations() > 0 ) {
635             int i = 0;
636             for (OsmPrimitive e : DataSet.sort(Main.main.getCurrentDataSet().relations)) {
637-                if (!e.isDeleted() && !e.incomplete) {
638+                if (!e.isDeleted() && !e.isFiltered() && !e.incomplete) {
639                     list.setElementAt(e, i++);
640                 }
641             }
642Index: src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
643===================================================================
644--- src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java        (revision 2114)
645+++ src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java        (working copy)
646@@ -749,7 +749,7 @@
647         Map<Relation, Collection<RelationMember>> roles = new HashMap<Relation, Collection<RelationMember>>();
648         if (Main.main.getCurrentDataSet() != null) {
649             for (Relation r : Main.main.getCurrentDataSet().relations) {
650-                if (!r.isDeleted() && !r.incomplete) {
651+                if (!r.isDeleted() && !r.isFiltered() && !r.isDisabled() && !r.incomplete) {
652                     for (RelationMember m : r.getMembers()) {
653                         if (newSelection.contains(m.getMember())) {
654                             Collection<RelationMember> value = roles.get(r);
655Index: src/org/openstreetmap/josm/gui/MapFrame.java
656===================================================================
657--- src/org/openstreetmap/josm/gui/MapFrame.java        (revision 2114)
658+++ src/org/openstreetmap/josm/gui/MapFrame.java        (working copy)
659@@ -28,6 +28,7 @@
660 import org.openstreetmap.josm.gui.dialogs.PropertiesDialog;
661 import org.openstreetmap.josm.gui.dialogs.RelationListDialog;
662 import org.openstreetmap.josm.gui.dialogs.SelectionListDialog;
663+import org.openstreetmap.josm.gui.dialogs.FilterDialog;
664 import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
665 import org.openstreetmap.josm.gui.dialogs.UserListDialog;
666 import org.openstreetmap.josm.tools.Destroyable;
667@@ -103,6 +104,7 @@
668         addToggleDialog(new PropertiesDialog(this));
669         addToggleDialog(new HistoryDialog());
670         addToggleDialog(new SelectionListDialog());
671+        addToggleDialog(new FilterDialog());
672         addToggleDialog(new UserListDialog());
673         addToggleDialog(conflictDialog = new ConflictDialog());
674         addToggleDialog(new CommandStackDialog(this));
675Index: src/org/openstreetmap/josm/data/osm/Filters.java
676===================================================================
677--- src/org/openstreetmap/josm/data/osm/Filters.java    (revision 0)
678+++ src/org/openstreetmap/josm/data/osm/Filters.java    (revision 0)
679@@ -0,0 +1,197 @@
680+package org.openstreetmap.josm.data.osm;
681+
682+import static org.openstreetmap.josm.tools.I18n.tr;
683+
684+import javax.swing.table.AbstractTableModel;
685+
686+import java.util.LinkedList;
687+import java.util.List;
688+import java.util.Collection;
689+import java.util.Map;
690+
691+import org.openstreetmap.josm.data.osm.Filter;
692+import org.openstreetmap.josm.Main;
693+import org.openstreetmap.josm.actions.search.SearchAction.Function;
694+import org.openstreetmap.josm.actions.search.SearchAction;
695+
696+public class Filters extends AbstractTableModel{
697+
698+   public Filters(){
699+      loadPrefs();
700+   }
701+
702+   private List<Filter> filters = new LinkedList<Filter>();
703+   public void filter(){
704+      Collection<OsmPrimitive> seld = new LinkedList<OsmPrimitive> ();
705+      Collection<OsmPrimitive> self = new LinkedList<OsmPrimitive> ();
706+      Main.main.getCurrentDataSet().setFiltered();
707+      Main.main.getCurrentDataSet().setDisabled();
708+      for (Filter flt : filters){
709+            if(flt.filtered){
710+               SearchAction.getSelection(flt, self, new Function(){
711+                  public Boolean isSomething(OsmPrimitive o){
712+                     return o.isFiltered();
713+                  }
714+               });
715+            }
716+            if(flt.disabled) {
717+               SearchAction.getSelection(flt, seld, new Function(){
718+                  public Boolean isSomething(OsmPrimitive o){
719+                     return o.isDisabled();
720+                  }
721+               });
722+            }
723+      }
724+      Main.main.getCurrentDataSet().setFiltered(self);
725+      Main.main.getCurrentDataSet().setDisabled(seld);
726+      Main.map.mapView.repaint();
727+   }
728+
729+   private void loadPrefs(){
730+      Map<String,String> prefs = Main.pref.getAllPrefix("filters.filter");
731+      for (String value : prefs.values()) {
732+         Filter filter = new Filter(value);
733+         if(filter!=null)
734+            filters.add(filter);
735+      }
736+   }
737+
738+   private void savePrefs(){
739+      Map<String,String> prefs = Main.pref.getAllPrefix("filters.filter");
740+      for (String key : prefs.keySet()) {
741+         String[] sts = key.split("\\.");
742+         if (sts.length != 3)throw new Error("Incompatible filter preferences");
743+         Main.pref.put("filters.filter." + sts[2], null);
744+      }
745+
746+      int i = 0;
747+      for (Filter flt : filters){
748+         Main.pref.put("filters.filter." + i++, flt.getPrefString());
749+      }
750+   }
751+
752+   private void savePref(int i){
753+      if(i >= filters.size())
754+         Main.pref.put("filters.filter." + i, null);
755+      else
756+         Main.pref.put("filters.filter." + i, filters.get(i).getPrefString());
757+   }
758+
759+   public void addFilter(Filter f){
760+      filters.add(f);
761+      savePref(filters.size()-1);
762+      filter();
763+      fireTableRowsInserted(filters.size()-1, filters.size()-1);
764+   }
765+
766+   public void moveDownFilter(int i){
767+      if(i >= filters.size()-1) return;
768+      filters.add(i+1, filters.remove(i));
769+      savePref(i);
770+      savePref(i+1);
771+      filter();
772+      fireTableRowsUpdated(i, i+1);
773+   }
774+
775+   public void moveUpFilter(int i){
776+      if(i == 0) return;
777+      filters.add(i-1, filters.remove(i));
778+      savePref(i);
779+      savePref(i-1);
780+      filter();
781+      fireTableRowsUpdated(i-1, i);
782+   }
783+
784+   public void removeFilter(int i){
785+      filters.remove(i);
786+      savePrefs();
787+      filter();
788+      fireTableRowsDeleted(i, i);
789+   }
790+
791+   public void setFilter(int i, Filter f){
792+      filters.set(i, f);
793+      savePref(i);
794+      filter();
795+      fireTableRowsUpdated(i, i);
796+   }
797+
798+   public Filter getFilter(int i){
799+      return filters.get(i);
800+   }
801+
802+
803+
804+   @Override
805+   public int getRowCount(){
806+      return filters.size();
807+   }
808+
809+   @Override
810+   public int getColumnCount(){
811+      return 6;
812+   }
813+
814+   @Override
815+   public String getColumnName(int column){
816+      String[] names = { tr("F"), tr("D"), tr("Name"), tr("C"), tr("I"), tr("M") };
817+      return names[column];
818+   }
819+
820+   @Override
821+   public Class getColumnClass(int column){
822+      Class[] classes = { Boolean.class, Boolean.class, String.class, Boolean.class, Boolean.class, String.class };
823+      return classes[column];
824+   }
825+
826+   @Override
827+   public boolean isCellEditable(int row, int column){
828+      if(column < 5)return true;
829+      return false;
830+   }
831+   @Override
832+   public void setValueAt(Object aValue, int row, int column){
833+      Filter f = filters.get(row);
834+      switch(column){
835+         case 0: f.filtered = (Boolean)aValue;
836+                 savePref(row);
837+                 filter();
838+                 return;
839+         case 1: f.disabled = (Boolean)aValue;
840+                 savePref(row);
841+                 filter();
842+                 return;
843+         case 2: f.filterName = (String)aValue;
844+                 savePref(row);
845+                 return;
846+         case 3: f.applyForChildren = (Boolean)aValue;
847+                 savePref(row);
848+                 filter();
849+                 return;
850+         case 4: f.inverted = (Boolean)aValue;
851+                 savePref(row);
852+                 filter();
853+                 return;
854+      }
855+   }
856+
857+   @Override
858+   public Object getValueAt(int row, int column){
859+      Filter f = filters.get(row);
860+      switch(column){
861+         case 0: return f.filtered;
862+         case 1: return f.disabled;
863+         case 2: return f.filterName;
864+         case 3: return f.applyForChildren;
865+         case 4: return f.inverted;
866+         case 5:
867+                 switch(f.mode){
868+                    case replace: return "∅";
869+                    case add: return "∪";
870+                    case remove: return "∖";
871+                    case in_selection: return "∩";
872+                 }
873+      }
874+      return null;
875+   }
876+}
877Index: src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
878===================================================================
879--- src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java (revision 2114)
880+++ src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java (working copy)
881@@ -148,7 +148,7 @@
882            require changing the colour while painting... */
883         //profilerN = 0;
884         for (final OsmPrimitive osm : data.relations)
885-            if (!osm.isDeleted() && !osm.isSelected())
886+            if (!osm.isDeleted() && !osm.isSelected() && !osm.isFiltered())
887             {
888                 osm.visit(this);
889                 //        profilerN++;
890@@ -162,7 +162,7 @@
891 
892         //profilerN = 0;
893         for (final OsmPrimitive osm : data.ways)
894-            if (!osm.isDeleted() && !osm.isSelected() && osm.isTagged())
895+            if (!osm.isDeleted() && !osm.isSelected() && !osm.isFiltered() && osm.isTagged())
896             {
897                 osm.visit(this);
898                 //        profilerN++;
899@@ -170,7 +170,7 @@
900         displaySegments();
901 
902         for (final OsmPrimitive osm : data.ways)
903-            if (!osm.isDeleted() && !osm.isSelected() && !osm.isTagged())
904+            if (!osm.isDeleted() && !osm.isSelected() && !osm.isFiltered() && !osm.isTagged())
905             {
906                 osm.visit(this);
907                 //        profilerN++;
908@@ -201,7 +201,7 @@
909 
910         //profilerN = 0;
911         for (final OsmPrimitive osm : data.nodes)
912-            if (!osm.isDeleted() && !osm.isSelected())
913+            if (!osm.isDeleted() && !osm.isSelected() && !osm.isFiltered())
914             {
915                 osm.visit(this);
916                 //        profilerN++;
917@@ -219,7 +219,7 @@
918             //    profilerN = 0;
919             currentColor = nodeColor;
920             for (final OsmPrimitive osm : data.ways)
921-                if (!osm.isDeleted())
922+                if (!osm.isDeleted() && !osm.isDisabled() && !osm.isFiltered())
923                 {
924                     visitVirtual((Way)osm);
925                     //                profilerN++;
926@@ -248,7 +248,7 @@
927     public void visit(Node n) {
928         if (n.incomplete) return;
929 
930-        if (inactive) {
931+        if (inactive || n.isDisabled()) {
932             drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
933         } else if (n.highlighted) {
934             drawNode(n, highlightColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
935@@ -311,7 +311,7 @@
936         boolean showOnlyHeadArrowOnly = showThisDirectionArrow && !w.isSelected() && showHeadArrowOnly;
937         Color wayColor;
938 
939-        if (inactive) {
940+        if (inactive || w.isDisabled()) {
941             wayColor = inactiveColor;
942         } else if(w.highlighted) {
943             wayColor = highlightColor;
944@@ -344,7 +344,7 @@
945         if (r.incomplete) return;
946 
947         Color col;
948-        if (inactive) {
949+        if (inactive || r.isDisabled()) {
950             col = inactiveColor;
951         } else if (r.isSelected()) {
952             col = selectedColor;
953Index: src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java
954===================================================================
955--- src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java    (revision 2114)
956+++ src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java    (working copy)
957@@ -158,6 +158,8 @@
958             drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
959         } else if (n.isTagged()) {
960             drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
961+        } else if (n.isDisabled()) {
962+            drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
963         } else {
964             drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
965         }
966@@ -306,6 +308,8 @@
967             color = highlightColor;
968         } else if(w.isSelected()) {
969             color = selectedColor;
970+        } else if(w.isDisabled()) {
971+            color = inactiveColor;
972         }
973 
974         /* draw overlays under the way */
975@@ -529,7 +533,7 @@
976         {
977             for (RelationMember m : r.getMembers())
978             {
979-                if (m.isNode() && !m.getMember().incomplete && !m.getMember().isDeleted())
980+                if (m.isNode() && !m.getMember().incomplete && !m.getMember().isDeleted() && !m.getMember().isFiltered())
981                 {
982                     drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember()) : null, true, true);
983                 }
984@@ -550,7 +554,7 @@
985         {
986             for (RelationMember m : r.getMembers())
987             {
988-                if (m.isWay() && !m.getMember().incomplete && !m.getMember().isDeleted()) /* nodes drawn on second call */
989+                if (m.isWay() && !m.getMember().incomplete && !m.getMember().isDeleted() && !m.getMember().isFiltered()) /* nodes drawn on second call */
990                 {
991                     drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember())
992                             : null, true, true);
993@@ -1394,7 +1398,7 @@
994             //    profilerN = 0;
995             for (final Relation osm : data.relations)
996             {
997-                if(!osm.isDeleted() && !osm.incomplete && osm.mappaintVisibleCode != viewid)
998+                if(!osm.isDeleted() && !osm.isFiltered() && !osm.incomplete && osm.mappaintVisibleCode != viewid)
999                 {
1000                     osm.visit(this);
1001                     //            profilerN++;
1002@@ -1411,7 +1415,7 @@
1003             //    profilerN = 0;
1004             for (final Way osm : data.ways)
1005             {
1006-                if (!osm.incomplete && !osm.isDeleted()
1007+                if (!osm.incomplete && !osm.isDeleted() && !osm.isFiltered()
1008                         && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid)
1009                 {
1010                     if(isPrimitiveArea(osm) && osm.mappaintDrawnAreaCode != paintid)
1011@@ -1452,7 +1456,7 @@
1012             /*** WAYS (filling disabled)  ***/
1013             //    profilerN = 0;
1014             for (final OsmPrimitive osm : data.ways)
1015-                if (!osm.incomplete && !osm.isDeleted() && !osm.isSelected()
1016+                if (!osm.incomplete && !osm.isDeleted() && !osm.isFiltered() && !osm.isSelected()
1017                         && osm.mappaintVisibleCode != viewid )
1018                 {
1019                     osm.visit(this);
1020@@ -1471,7 +1475,7 @@
1021         selectedCall = true;
1022         //profilerN = 0;
1023         for (final OsmPrimitive osm : data.getSelected()) {
1024-            if (!osm.incomplete && !osm.isDeleted() && !(osm instanceof Node)
1025+            if (!osm.incomplete && !osm.isDeleted() && !osm.isFiltered() && !(osm instanceof Node)
1026                     && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid)
1027             {
1028                 osm.visit(this);
1029@@ -1491,7 +1495,7 @@
1030         /*** NODES ***/
1031         //profilerN = 0;
1032         for (final OsmPrimitive osm : data.nodes)
1033-            if (!osm.incomplete && !osm.isDeleted()
1034+            if (!osm.incomplete && !osm.isDeleted() && !osm.isFiltered()
1035                     && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid)
1036             {
1037                 osm.visit(this);
1038@@ -1511,7 +1515,7 @@
1039             //    profilerN = 0;
1040             currentColor = nodeColor;
1041             for (final OsmPrimitive osm : data.ways)
1042-                if (!osm.incomplete && !osm.isDeleted()
1043+                if (!osm.incomplete && !osm.isDeleted() && !osm.isDisabled() && !osm.isFiltered()
1044                         && osm.mappaintVisibleCode != viewid )
1045                 {
1046                     /* TODO: move this into the SimplePaint code? */
1047Index: src/org/openstreetmap/josm/data/osm/Filter.java
1048===================================================================
1049--- src/org/openstreetmap/josm/data/osm/Filter.java     (revision 0)
1050+++ src/org/openstreetmap/josm/data/osm/Filter.java     (revision 0)
1051@@ -0,0 +1,48 @@
1052+package org.openstreetmap.josm.data.osm;
1053+
1054+import org.openstreetmap.josm.actions.search.SearchAction;
1055+import org.openstreetmap.josm.actions.search.SearchAction.SearchSetting;
1056+import org.openstreetmap.josm.actions.search.SearchAction.SearchMode;
1057+
1058+public class Filter extends SearchSetting {
1059+   private final String version = "1";
1060+   public String filterName = "";
1061+   public Boolean filtered = false;
1062+   public Boolean disabled = true;
1063+   public Boolean inverted = false;
1064+   public Boolean applyForChildren = true;
1065+   public Filter() {
1066+       super("", SearchMode.add, false, false);
1067+   }
1068+   public Filter(String text, SearchMode mode, boolean caseSensitive, boolean regexSearch, String filterName) {
1069+       super(text, mode, caseSensitive, regexSearch);
1070+       this.filterName = filterName;
1071+   }
1072+
1073+   public Filter(String prefText){
1074+      super("", SearchMode.add, false, false);
1075+      String[] prfs = prefText.split(";");
1076+      if(prfs.length != 10 && !prfs[0].equals(version))
1077+         throw new Error("Incompatible filter preferences");
1078+      text = prfs[1];
1079+      if(prfs[2].equals("replace")) mode = SearchMode.replace;
1080+      if(prfs[2].equals("add")) mode = SearchMode.add;
1081+      if(prfs[2].equals("remove")) mode = SearchMode.remove;
1082+      if(prfs[2].equals("in_selection")) mode = SearchMode.in_selection;
1083+      caseSensitive = Boolean.parseBoolean(prfs[3]);
1084+      regexSearch = Boolean.parseBoolean(prfs[4]);
1085+      filterName = prfs[5];
1086+      filtered = Boolean.parseBoolean(prfs[6]);
1087+      disabled = Boolean.parseBoolean(prfs[7]);
1088+      inverted = Boolean.parseBoolean(prfs[8]);
1089+      applyForChildren = Boolean.parseBoolean(prfs[9]);
1090+
1091+   } 
1092+
1093+   public String getPrefString(){
1094+      return (String) version + ";" +
1095+          text + ";" + mode + ";" + caseSensitive + ";" + regexSearch + ";" +
1096+          filterName + ";" + filtered + ";" + disabled + ";" +
1097+          inverted + ";" + applyForChildren;
1098+   }
1099+}
1100Index: src/org/openstreetmap/josm/data/osm/DataSet.java
1101===================================================================
1102--- src/org/openstreetmap/josm/data/osm/DataSet.java    (revision 2114)
1103+++ src/org/openstreetmap/josm/data/osm/DataSet.java    (working copy)
1104@@ -183,6 +183,52 @@
1105         return getSelected(relations);
1106     }
1107 
1108+    public void setFiltered(Collection<? extends OsmPrimitive> selection) {
1109+        clearFiltered(nodes);
1110+        clearFiltered(ways);
1111+        clearFiltered(relations);
1112+        for (OsmPrimitive osm : selection) {
1113+            osm.setFiltered(true);
1114+        }
1115+    }
1116+
1117+    public void setFiltered(OsmPrimitive... osm) {
1118+        if (osm.length == 1 && osm[0] == null) {
1119+            setFiltered();
1120+            return;
1121+        }
1122+        clearFiltered(nodes);
1123+        clearFiltered(ways);
1124+        clearFiltered(relations);
1125+        for (OsmPrimitive o : osm)
1126+            if (o != null) {
1127+                o.setFiltered(true);
1128+            }
1129+    }
1130+
1131+    public void setDisabled(Collection<? extends OsmPrimitive> selection) {
1132+        clearDisabled(nodes);
1133+        clearDisabled(ways);
1134+        clearDisabled(relations);
1135+        for (OsmPrimitive osm : selection) {
1136+            osm.setDisabled(true);
1137+        }
1138+    }
1139+
1140+    public void setDisabled(OsmPrimitive... osm) {
1141+        if (osm.length == 1 && osm[0] == null) {
1142+            setDisabled();
1143+            return;
1144+        }
1145+        clearDisabled(nodes);
1146+        clearDisabled(ways);
1147+        clearDisabled(relations);
1148+        for (OsmPrimitive o : osm)
1149+            if (o != null) {
1150+                o.setDisabled(true);
1151+            }
1152+    }
1153+
1154     public void setSelected(Collection<? extends OsmPrimitive> selection) {
1155         clearSelection(nodes);
1156         clearSelection(ways);
1157@@ -209,6 +255,29 @@
1158     }
1159 
1160     /**
1161+     * Remove the filtered parameter from every value in the collection.
1162+     * @param list The collection to remove the filtered parameter from.
1163+     */
1164+    private void clearFiltered(Collection<? extends OsmPrimitive> list) {
1165+        if (list == null)
1166+            return;
1167+        for (OsmPrimitive osm : list) {
1168+            osm.setFiltered(false);
1169+        }
1170+    }
1171+    /**
1172+     * Remove the disabled parameter from every value in the collection.
1173+     * @param list The collection to remove the disabled parameter from.
1174+     */
1175+    private void clearDisabled(Collection<? extends OsmPrimitive> list) {
1176+        if (list == null)
1177+            return;
1178+        for (OsmPrimitive osm : list) {
1179+            osm.setDisabled(false);
1180+        }
1181+    }
1182+
1183+    /**
1184      * Remove the selection from every value in the collection.
1185      * @param list The collection to remove the selection from.
1186      */
1187Index: src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
1188===================================================================
1189--- src/org/openstreetmap/josm/data/osm/OsmPrimitive.java       (revision 2114)
1190+++ src/org/openstreetmap/josm/data/osm/OsmPrimitive.java       (working copy)
1191@@ -123,6 +123,18 @@
1192     private boolean visible = true;
1193 
1194     /**
1195+     * <code>true</code>, if the object has been set inactive
1196+     *
1197+     */
1198+    public boolean disabled = false;
1199+
1200+    /**
1201+     * <code>true</code>, if the object has been filtered out
1202+     *
1203+     */
1204+    public boolean filtered = false;
1205+
1206+    /**
1207      * User that last modified this primitive, as specified by the server.
1208      * Never changed by JOSM.
1209      */
1210@@ -174,6 +186,40 @@
1211     /* ------------------------------------------------------------------------------------ */
1212 
1213     /**
1214+     * Sets whether this primitive is disabled or not.
1215+     *
1216+     * @param selected  true, if this primitive is disabled; false, otherwise
1217+     */
1218+    public void setDisabled(boolean disabled) {
1219+        this.disabled = disabled;
1220+    }
1221+
1222+    /**
1223+     * Replies true, if this primitive is disabled.
1224+     *
1225+     * @return true, if this primitive is disabled
1226+     */
1227+    public boolean isDisabled() {
1228+        return disabled;
1229+    }
1230+    /**
1231+     * Sets whether this primitive is filtered out or not.
1232+     *
1233+     * @param selected  true, if this primitive is filtered out; false, otherwise
1234+     */
1235+    public void setFiltered(boolean filtered) {
1236+        this.filtered = filtered;
1237+    }
1238+    /**
1239+     * Replies true, if this primitive is filtered out.
1240+     *
1241+     * @return true, if this primitive is filtered out
1242+     */
1243+    public boolean isFiltered() {
1244+        return filtered;
1245+    }
1246+
1247+    /**
1248      * Sets whether this primitive is selected or not.
1249      *
1250      * @param selected  true, if this primitive is selected; false, otherwise
1251Index: images/dialogs/filter.png
1252===================================================================
1253Cannot display: file marked as a binary type.
1254svn:mime-type = application/octet-stream
1255
1256Property changes on: images/dialogs/filter.png
1257___________________________________________________________________
1258Added: svn:mime-type
1259   + application/octet-stream
1260