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

Last change on this file since 6084 was 6084, checked in by bastiK, 11 years ago

see #8902 - add missing @Override annotations (patch by shinigami)

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