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

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

fix #14778 - stroke not reset after drawing of large areas produced graphics artifacts when painting world bounds and selection rectangles, bug seen when filtering ways only, as way rendering reset the stroke

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