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

Last change on this file since 5018 was 5018, checked in by akks, 12 years ago

fix "Shortcut redefinition" warnings after MapFrame reinitialization - see #7424 (core part)

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