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

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

Sonar/FindBugs - Replace singular fields by local variables

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