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

Last change on this file since 12279 was 12279, checked in by Don-vip, 7 years ago

sonar - squid:S3878 - Arrays should not be created for varargs parameters

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