source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java@ 14206

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

fix #16698, see #15670 - make sure filters are executed (costly operation) only when necessary:

  • data changes imply execution of filters only when at least a filter is enabled
  • filter changes imply execution of filters even is no filter is enabled
  • filter dataset change events should not trigger a new filter execution!
  • Property svn:eol-style set to native
File size: 9.2 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;
5import static org.openstreetmap.josm.tools.I18n.trc;
6
7import java.awt.Graphics2D;
8import java.util.Collection;
9import java.util.List;
10
11import javax.swing.table.AbstractTableModel;
12
13import org.openstreetmap.josm.data.osm.Filter;
14import org.openstreetmap.josm.data.osm.FilterModel;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.gui.MainApplication;
17import org.openstreetmap.josm.gui.MapFrame;
18import org.openstreetmap.josm.gui.autofilter.AutoFilterManager;
19import org.openstreetmap.josm.gui.widgets.OSDLabel;
20import org.openstreetmap.josm.tools.Logging;
21
22/**
23 * The model that is used for the table in the {@link FilterDialog}.
24 *
25 * @author Petr_Dlouhý
26 */
27public class FilterTableModel extends AbstractTableModel {
28
29 /**
30 * The filter enabled column
31 */
32 public static final int COL_ENABLED = 0;
33 /**
34 * The column indicating if the filter is hiding.
35 */
36 public static final int COL_HIDING = 1;
37 /**
38 * The column that displays the filter text
39 */
40 public static final int COL_TEXT = 2;
41 /**
42 * The column to invert the filter
43 */
44 public static final int COL_INVERTED = 3;
45
46 /**
47 * The filter model
48 */
49 final FilterModel model = new FilterModel();
50
51 /**
52 * A helper for {@link #drawOSDText(Graphics2D)}.
53 */
54 private final OSDLabel lblOSD = new OSDLabel("");
55
56 /**
57 * Constructs a new {@code FilterTableModel}.
58 */
59 public FilterTableModel() {
60 loadPrefs();
61 }
62
63 private void updateFilters() {
64 AutoFilterManager.getInstance().setCurrentAutoFilter(null);
65 executeFilters(true);
66 }
67
68 /**
69 * Runs the filters on the current edit data set, if any. Does nothing if no filter is enabled.
70 */
71 public void executeFilters() {
72 executeFilters(false);
73 }
74
75 /**
76 * Runs the filter on a list of primitives that are part of the edit data set, if any. Does nothing if no filter is enabled.
77 * @param primitives The primitives
78 */
79 public void executeFilters(Collection<? extends OsmPrimitive> primitives) {
80 executeFilters(primitives, false);
81 }
82
83 /**
84 * Runs the filters on the current edit data set, if any.
85 * @param force force execution of filters even if no filter is enabled. Useful to reset state after change of filters
86 * @since 14206
87 */
88 public void executeFilters(boolean force) {
89 if (AutoFilterManager.getInstance().getCurrentAutoFilter() == null && (force || model.hasFilters())) {
90 model.executeFilters();
91 updateMap();
92 }
93 }
94
95 /**
96 * Runs the filter on a list of primitives that are part of the edit data set, if any.
97 * @param force force execution of filters even if no filter is enabled. Useful to reset state after change of filters
98 * @param primitives The primitives
99 * @since 14206
100 */
101 public void executeFilters(Collection<? extends OsmPrimitive> primitives, boolean force) {
102 if (AutoFilterManager.getInstance().getCurrentAutoFilter() == null && (force || model.hasFilters())) {
103 model.executeFilters(primitives);
104 updateMap();
105 }
106 }
107
108 private void updateMap() {
109 MapFrame map = MainApplication.getMap();
110 if (map != null && model.isChanged()) {
111 map.filterDialog.updateDialogHeader();
112 }
113 }
114
115 private void loadPrefs() {
116 model.loadPrefs("filters.entries");
117 }
118
119 private void savePrefs() {
120 model.savePrefs("filters.entries");
121 }
122
123 /**
124 * Adds a new filter to the filter list.
125 * @param filter The new filter
126 */
127 public void addFilter(Filter filter) {
128 if (model.addFilter(filter)) {
129 savePrefs();
130 updateFilters();
131 int size = model.getFiltersCount();
132 fireTableRowsInserted(size - 1, size - 1);
133 }
134 }
135
136 /**
137 * Moves down the filter in the given row.
138 * @param rowIndex The filter row
139 */
140 public void moveDownFilter(int rowIndex) {
141 if (model.moveDownFilter(rowIndex)) {
142 savePrefs();
143 updateFilters();
144 fireTableRowsUpdated(rowIndex, rowIndex + 1);
145 }
146 }
147
148 /**
149 * Moves up the filter in the given row
150 * @param rowIndex The filter row
151 */
152 public void moveUpFilter(int rowIndex) {
153 if (model.moveUpFilter(rowIndex)) {
154 savePrefs();
155 updateFilters();
156 fireTableRowsUpdated(rowIndex - 1, rowIndex);
157 }
158 }
159
160 /**
161 * Removes the filter that is displayed in the given row
162 * @param rowIndex The index of the filter to remove
163 */
164 public void removeFilter(int rowIndex) {
165 if (model.removeFilter(rowIndex) != null) {
166 savePrefs();
167 updateFilters();
168 fireTableRowsDeleted(rowIndex, rowIndex);
169 }
170 }
171
172 /**
173 * Sets/replaces the filter for a given row.
174 * @param rowIndex The row index
175 * @param filter The filter that should be placed in that row
176 */
177 public void setFilter(int rowIndex, Filter filter) {
178 model.setFilter(rowIndex, filter);
179 savePrefs();
180 updateFilters();
181 fireTableRowsUpdated(rowIndex, rowIndex);
182 }
183
184 /**
185 * Gets the filter by row index
186 * @param rowIndex The row index
187 * @return The filter in that row
188 */
189 public Filter getFilter(int rowIndex) {
190 return model.getFilter(rowIndex);
191 }
192
193 @Override
194 public int getRowCount() {
195 return model.getFiltersCount();
196 }
197
198 @Override
199 public int getColumnCount() {
200 return 5;
201 }
202
203 @Override
204 public String getColumnName(int column) {
205 String[] names = {/* translators notes must be in front */
206 /* column header: enable filter */trc("filter", "E"),
207 /* column header: hide filter */trc("filter", "H"),
208 /* column header: filter text */trc("filter", "Text"),
209 /* column header: inverted filter */trc("filter", "I"),
210 /* column header: filter mode */trc("filter", "M")};
211 return names[column];
212 }
213
214 @Override
215 public Class<?> getColumnClass(int column) {
216 Class<?>[] classes = {Boolean.class, Boolean.class, String.class, Boolean.class, String.class};
217 return classes[column];
218 }
219
220 /**
221 * Determines if a cell is enabled.
222 * @param row row index
223 * @param column column index
224 * @return {@code true} if the cell at (row, column) is enabled
225 */
226 public boolean isCellEnabled(int row, int column) {
227 return model.getFilter(row).enable || column == 0;
228 }
229
230 @Override
231 public boolean isCellEditable(int row, int column) {
232 return column < 4 && isCellEnabled(row, column);
233 }
234
235 @Override
236 public void setValueAt(Object aValue, int row, int column) {
237 if (row >= model.getFiltersCount()) {
238 return;
239 }
240 Filter f = model.getFilter(row);
241 switch (column) {
242 case COL_ENABLED:
243 f.enable = (Boolean) aValue;
244 setFilter(row, f);
245 break;
246 case COL_HIDING:
247 f.hiding = (Boolean) aValue;
248 setFilter(row, f);
249 break;
250 case COL_TEXT:
251 f.text = (String) aValue;
252 savePrefs();
253 break;
254 case COL_INVERTED:
255 f.inverted = (Boolean) aValue;
256 setFilter(row, f);
257 break;
258 default: // Do nothing
259 }
260 if (column != 0) {
261 fireTableCellUpdated(row, column);
262 }
263 }
264
265 @Override
266 public Object getValueAt(int row, int column) {
267 if (row >= model.getFiltersCount()) {
268 return null;
269 }
270 Filter f = model.getFilter(row);
271 switch (column) {
272 case COL_ENABLED:
273 return f.enable;
274 case COL_HIDING:
275 return f.hiding;
276 case COL_TEXT:
277 return f.text;
278 case COL_INVERTED:
279 return f.inverted;
280 case 4:
281 switch (f.mode) { /* translators notes must be in front */
282 case replace: /* filter mode: replace */
283 return trc("filter", "R");
284 case add: /* filter mode: add */
285 return trc("filter", "A");
286 case remove: /* filter mode: remove */
287 return trc("filter", "D");
288 case in_selection: /* filter mode: in selection */
289 return trc("filter", "F");
290 default:
291 Logging.warn("Unknown filter mode: " + f.mode);
292 }
293 break;
294 default: // Do nothing
295 }
296 return null;
297 }
298
299 /**
300 * Draws a text on the map display that indicates that filters are active.
301 * @param g The graphics to draw that text on.
302 */
303 public void drawOSDText(Graphics2D g) {
304 model.drawOSDText(g, lblOSD,
305 tr("<h2>Filter active</h2>"),
306 tr("</p><p>Close the filter dialog to see all objects.<p></html>"));
307 }
308
309 /**
310 * Returns the list of filters.
311 * @return the list of filters
312 */
313 public List<Filter> getFilters() {
314 return model.getFilters();
315 }
316}
Note: See TracBrowser for help on using the repository browser.