source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java @ 14138

Last change on this file since 14138 was 14138, checked in by Don-vip, 2 months ago

see #15229 - deprecate Main.platform and related methods - new class PlatformManager

  • Property svn:eol-style set to native
File size: 17.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Graphics2D;
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.awt.event.MouseEvent;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.List;
14
15import javax.swing.AbstractAction;
16import javax.swing.DefaultCellEditor;
17import javax.swing.JCheckBox;
18import javax.swing.JTable;
19import javax.swing.ListSelectionModel;
20import javax.swing.SwingUtilities;
21import javax.swing.table.DefaultTableCellRenderer;
22import javax.swing.table.JTableHeader;
23import javax.swing.table.TableCellRenderer;
24import javax.swing.table.TableColumnModel;
25import javax.swing.table.TableModel;
26
27import org.openstreetmap.josm.actions.mapmode.MapMode;
28import org.openstreetmap.josm.actions.search.SearchAction;
29import org.openstreetmap.josm.data.osm.Filter;
30import org.openstreetmap.josm.data.osm.FilterModel;
31import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
32import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
33import org.openstreetmap.josm.data.osm.event.DataSetListener;
34import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
35import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
36import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
37import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
38import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
39import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
40import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
41import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
42import org.openstreetmap.josm.gui.MainApplication;
43import org.openstreetmap.josm.gui.MapFrame;
44import org.openstreetmap.josm.gui.MapFrame.MapModeChangeListener;
45import org.openstreetmap.josm.gui.SideButton;
46import org.openstreetmap.josm.gui.util.MultikeyActionsHandler;
47import org.openstreetmap.josm.gui.util.MultikeyShortcutAction;
48import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField;
49import org.openstreetmap.josm.tools.ImageProvider;
50import org.openstreetmap.josm.tools.InputMapUtils;
51import org.openstreetmap.josm.tools.PlatformManager;
52import org.openstreetmap.josm.tools.Shortcut;
53
54/**
55 * The filter dialog displays a list of filters that are active on the current edit layer.
56 *
57 * @author Petr_Dlouhý
58 */
59public class FilterDialog extends ToggleDialog implements DataSetListener, MapModeChangeListener {
60
61    private JTable userTable;
62    private final FilterTableModel filterModel = new FilterTableModel();
63
64    private final EnableFilterAction enableFilterAction;
65    private final HidingFilterAction hidingFilterAction;
66
67    /**
68     * Constructs a new {@code FilterDialog}
69     */
70    public FilterDialog() {
71        super(tr("Filter"), "filter", tr("Filter objects and hide/disable them."),
72                Shortcut.registerShortcut("subwindow:filter", tr("Toggle: {0}", tr("Filter")),
73                        KeyEvent.VK_F, Shortcut.ALT_SHIFT), 162);
74        build();
75        enableFilterAction = new EnableFilterAction();
76        hidingFilterAction = new HidingFilterAction();
77        MultikeyActionsHandler.getInstance().addAction(enableFilterAction);
78        MultikeyActionsHandler.getInstance().addAction(hidingFilterAction);
79    }
80
81    @Override
82    public void showNotify() {
83        DatasetEventManager.getInstance().addDatasetListener(this, FireMode.IN_EDT_CONSOLIDATED);
84        MapFrame.addMapModeChangeListener(this);
85        filterModel.executeFilters();
86    }
87
88    @Override
89    public void hideNotify() {
90        DatasetEventManager.getInstance().removeDatasetListener(this);
91        MapFrame.removeMapModeChangeListener(this);
92        filterModel.model.clearFilterFlags();
93        MainApplication.getLayerManager().invalidateEditLayer();
94    }
95
96    private static final Shortcut ENABLE_FILTER_SHORTCUT
97    = Shortcut.registerShortcut("core_multikey:enableFilter", tr("Multikey: {0}", tr("Enable filter")),
98            KeyEvent.VK_E, Shortcut.ALT_CTRL);
99
100    private static final Shortcut HIDING_FILTER_SHORTCUT
101    = Shortcut.registerShortcut("core_multikey:hidingFilter", tr("Multikey: {0}", tr("Hide filter")),
102            KeyEvent.VK_H, Shortcut.ALT_CTRL);
103
104    private static final String[] COLUMN_TOOLTIPS = {
105            PlatformManager.getPlatform().makeTooltip(tr("Enable filter"), ENABLE_FILTER_SHORTCUT),
106            PlatformManager.getPlatform().makeTooltip(tr("Hiding filter"), HIDING_FILTER_SHORTCUT),
107            null,
108            tr("Inverse filter"),
109            tr("Filter mode")
110    };
111
112    /**
113     * Builds the GUI.
114     */
115    protected void build() {
116        userTable = new UserTable(filterModel);
117
118        userTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
119        userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
120
121        userTable.getColumnModel().getColumn(0).setMaxWidth(1);
122        userTable.getColumnModel().getColumn(1).setMaxWidth(1);
123        userTable.getColumnModel().getColumn(3).setMaxWidth(1);
124        userTable.getColumnModel().getColumn(4).setMaxWidth(1);
125
126        userTable.getColumnModel().getColumn(0).setResizable(false);
127        userTable.getColumnModel().getColumn(1).setResizable(false);
128        userTable.getColumnModel().getColumn(3).setResizable(false);
129        userTable.getColumnModel().getColumn(4).setResizable(false);
130
131        userTable.setDefaultRenderer(Boolean.class, new BooleanRenderer());
132        userTable.setDefaultRenderer(String.class, new StringRenderer());
133        userTable.setDefaultEditor(String.class, new DefaultCellEditor(new DisableShortcutsOnFocusGainedTextField()));
134
135        SideButton addButton = new SideButton(new AbstractAction() {
136            {
137                putValue(NAME, tr("Add"));
138                putValue(SHORT_DESCRIPTION, tr("Add filter."));
139                new ImageProvider("dialogs", "add").getResource().attachImageIcon(this, true);
140            }
141
142            @Override
143            public void actionPerformed(ActionEvent e) {
144                Filter filter = (Filter) SearchAction.showSearchDialog(new Filter());
145                if (filter != null) {
146                    filterModel.addFilter(filter);
147                }
148            }
149        });
150        SideButton editButton = new SideButton(new AbstractAction() {
151            {
152                putValue(NAME, tr("Edit"));
153                putValue(SHORT_DESCRIPTION, tr("Edit filter."));
154                new ImageProvider("dialogs", "edit").getResource().attachImageIcon(this, true);
155            }
156
157            @Override
158            public void actionPerformed(ActionEvent e) {
159                int index = userTable.getSelectionModel().getMinSelectionIndex();
160                if (index < 0) return;
161                Filter f = filterModel.getFilter(index);
162                Filter filter = (Filter) SearchAction.showSearchDialog(f);
163                if (filter != null) {
164                    filterModel.setFilter(index, filter);
165                }
166            }
167        });
168        SideButton deleteButton = new SideButton(new AbstractAction() {
169            {
170                putValue(NAME, tr("Delete"));
171                putValue(SHORT_DESCRIPTION, tr("Delete filter."));
172                new ImageProvider("dialogs", "delete").getResource().attachImageIcon(this, true);
173            }
174
175            @Override
176            public void actionPerformed(ActionEvent e) {
177                int index = userTable.getSelectionModel().getMinSelectionIndex();
178                if (index >= 0) {
179                    filterModel.removeFilter(index);
180                }
181            }
182        });
183        SideButton upButton = new SideButton(new AbstractAction() {
184            {
185                putValue(NAME, tr("Up"));
186                putValue(SHORT_DESCRIPTION, tr("Move filter up."));
187                new ImageProvider("dialogs", "up").getResource().attachImageIcon(this, true);
188            }
189
190            @Override
191            public void actionPerformed(ActionEvent e) {
192                int index = userTable.getSelectionModel().getMinSelectionIndex();
193                if (index >= 0) {
194                    filterModel.moveUpFilter(index);
195                    userTable.getSelectionModel().setSelectionInterval(index-1, index-1);
196                }
197            }
198        });
199        SideButton downButton = new SideButton(new AbstractAction() {
200            {
201                putValue(NAME, tr("Down"));
202                putValue(SHORT_DESCRIPTION, tr("Move filter down."));
203                new ImageProvider("dialogs", "down").getResource().attachImageIcon(this, true);
204            }
205
206            @Override
207            public void actionPerformed(ActionEvent e) {
208                int index = userTable.getSelectionModel().getMinSelectionIndex();
209                if (index >= 0) {
210                    filterModel.moveDownFilter(index);
211                    userTable.getSelectionModel().setSelectionInterval(index+1, index+1);
212                }
213            }
214        });
215
216        // Toggle filter "enabled" on Enter
217        InputMapUtils.addEnterAction(userTable, new AbstractAction() {
218            @Override
219            public void actionPerformed(ActionEvent e) {
220                int index = userTable.getSelectedRow();
221                if (index >= 0) {
222                    Filter filter = filterModel.getFilter(index);
223                    filterModel.setValueAt(!filter.enable, index, FilterTableModel.COL_ENABLED);
224                }
225            }
226        });
227
228        // Toggle filter "hiding" on Spacebar
229        InputMapUtils.addSpacebarAction(userTable, new AbstractAction() {
230            @Override
231            public void actionPerformed(ActionEvent e) {
232                int index = userTable.getSelectedRow();
233                if (index >= 0) {
234                    Filter filter = filterModel.getFilter(index);
235                    filterModel.setValueAt(!filter.hiding, index, FilterTableModel.COL_HIDING);
236                }
237            }
238        });
239
240        createLayout(userTable, true, Arrays.asList(
241                addButton, editButton, deleteButton, upButton, downButton
242        ));
243    }
244
245    @Override
246    public void destroy() {
247        MultikeyActionsHandler.getInstance().removeAction(enableFilterAction);
248        MultikeyActionsHandler.getInstance().removeAction(hidingFilterAction);
249        super.destroy();
250    }
251
252    static final class UserTable extends JTable {
253        static final class UserTableHeader extends JTableHeader {
254            UserTableHeader(TableColumnModel cm) {
255                super(cm);
256            }
257
258            @Override
259            public String getToolTipText(MouseEvent e) {
260                int index = columnModel.getColumnIndexAtX(e.getPoint().x);
261                int realIndex = columnModel.getColumn(index).getModelIndex();
262                return COLUMN_TOOLTIPS[realIndex];
263            }
264        }
265
266        UserTable(TableModel dm) {
267            super(dm);
268        }
269
270        @Override
271        protected JTableHeader createDefaultTableHeader() {
272            return new UserTableHeader(columnModel);
273        }
274    }
275
276    static class StringRenderer extends DefaultTableCellRenderer {
277        @Override
278        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
279            Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
280            TableModel model = table.getModel();
281            if (model instanceof FilterTableModel) {
282                cell.setEnabled(((FilterTableModel) model).isCellEnabled(row, column));
283            }
284            return cell;
285        }
286    }
287
288    static class BooleanRenderer extends JCheckBox implements TableCellRenderer {
289        @Override
290        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
291            FilterTableModel model = (FilterTableModel) table.getModel();
292            setSelected(value != null && (Boolean) value);
293            setEnabled(model.isCellEnabled(row, column));
294            setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
295            return this;
296        }
297    }
298
299    /**
300     * Updates the headline of this dialog to display the number of active filters.
301     */
302    public void updateDialogHeader() {
303        SwingUtilities.invokeLater(() -> setTitle(
304                tr("Filter Hidden:{0} Disabled:{1}",
305                        filterModel.model.getDisabledAndHiddenCount(), filterModel.model.getDisabledCount())));
306    }
307
308    /**
309     * Draws a text on the map display that indicates that filters are active.
310     * @param g The graphics to draw that text on.
311     */
312    public void drawOSDText(Graphics2D g) {
313        filterModel.drawOSDText(g);
314    }
315
316    @Override
317    public void dataChanged(DataChangedEvent event) {
318        filterModel.executeFilters();
319    }
320
321    @Override
322    public void nodeMoved(NodeMovedEvent event) {
323        filterModel.executeFilters();
324    }
325
326    @Override
327    public void otherDatasetChange(AbstractDatasetChangedEvent event) {
328        filterModel.executeFilters();
329    }
330
331    @Override
332    public void primitivesAdded(PrimitivesAddedEvent event) {
333        filterModel.executeFilters(event.getPrimitives());
334    }
335
336    @Override
337    public void primitivesRemoved(PrimitivesRemovedEvent event) {
338        filterModel.executeFilters();
339    }
340
341    @Override
342    public void relationMembersChanged(RelationMembersChangedEvent event) {
343        filterModel.executeFilters(FilterModel.getAffectedPrimitives(event.getPrimitives()));
344    }
345
346    @Override
347    public void tagsChanged(TagsChangedEvent event) {
348        filterModel.executeFilters(FilterModel.getAffectedPrimitives(event.getPrimitives()));
349    }
350
351    @Override
352    public void wayNodesChanged(WayNodesChangedEvent event) {
353        filterModel.executeFilters(FilterModel.getAffectedPrimitives(event.getPrimitives()));
354    }
355
356    @Override
357    public void mapModeChange(MapMode oldMapMode, MapMode newMapMode) {
358        filterModel.executeFilters();
359    }
360
361    /**
362     * This method is intended for Plugins getting the filtermodel and using .addFilter() to
363     * add a new filter.
364     * @return the filtermodel
365     */
366    public FilterTableModel getFilterModel() {
367        return filterModel;
368    }
369
370    abstract class AbstractFilterAction extends AbstractAction implements MultikeyShortcutAction {
371
372        protected transient Filter lastFilter;
373
374        @Override
375        public void actionPerformed(ActionEvent e) {
376            throw new UnsupportedOperationException();
377        }
378
379        @Override
380        public List<MultikeyInfo> getMultikeyCombinations() {
381            List<MultikeyInfo> result = new ArrayList<>();
382
383            for (int i = 0; i < filterModel.getRowCount(); i++) {
384                Filter filter = filterModel.getFilter(i);
385                MultikeyInfo info = new MultikeyInfo(i, filter.text);
386                result.add(info);
387            }
388
389            return result;
390        }
391
392        protected final boolean isLastFilterValid() {
393            return lastFilter != null && filterModel.getFilters().contains(lastFilter);
394        }
395
396        @Override
397        public MultikeyInfo getLastMultikeyAction() {
398            if (isLastFilterValid())
399                return new MultikeyInfo(-1, lastFilter.text);
400            else
401                return null;
402        }
403    }
404
405    private class EnableFilterAction extends AbstractFilterAction {
406
407        EnableFilterAction() {
408            putValue(SHORT_DESCRIPTION, tr("Enable filter"));
409            ENABLE_FILTER_SHORTCUT.setAccelerator(this);
410        }
411
412        @Override
413        public Shortcut getMultikeyShortcut() {
414            return ENABLE_FILTER_SHORTCUT;
415        }
416
417        @Override
418        public void executeMultikeyAction(int index, boolean repeatLastAction) {
419            if (index >= 0 && index < filterModel.getRowCount()) {
420                Filter filter = filterModel.getFilter(index);
421                filterModel.setValueAt(!filter.enable, index, FilterTableModel.COL_ENABLED);
422                lastFilter = filter;
423            } else if (repeatLastAction && isLastFilterValid()) {
424                filterModel.setValueAt(!lastFilter.enable, filterModel.getFilters().indexOf(lastFilter), FilterTableModel.COL_ENABLED);
425            }
426        }
427    }
428
429    private class HidingFilterAction extends AbstractFilterAction {
430
431        HidingFilterAction() {
432            putValue(SHORT_DESCRIPTION, tr("Hiding filter"));
433            HIDING_FILTER_SHORTCUT.setAccelerator(this);
434        }
435
436        @Override
437        public Shortcut getMultikeyShortcut() {
438            return HIDING_FILTER_SHORTCUT;
439        }
440
441        @Override
442        public void executeMultikeyAction(int index, boolean repeatLastAction) {
443            if (index >= 0 && index < filterModel.getRowCount()) {
444                Filter filter = filterModel.getFilter(index);
445                filterModel.setValueAt(!filter.hiding, index, FilterTableModel.COL_HIDING);
446                lastFilter = filter;
447            } else if (repeatLastAction && isLastFilterValid()) {
448                filterModel.setValueAt(!lastFilter.hiding, filterModel.getFilters().indexOf(lastFilter), FilterTableModel.COL_HIDING);
449            }
450        }
451    }
452}
Note: See TracBrowser for help on using the repository browser.