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

Last change on this file since 12298 was 12298, checked in by michael2402, 7 years ago

Rename one character variables in filter dialog, add javadoc.

  • Property svn:eol-style set to native
File size: 14.5 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;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.Color;
9import java.awt.Font;
10import java.awt.Graphics;
11import java.awt.Graphics2D;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.HashSet;
15import java.util.LinkedList;
16import java.util.List;
17
18import javax.swing.BorderFactory;
19import javax.swing.JLabel;
20import javax.swing.JOptionPane;
21import javax.swing.table.AbstractTableModel;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
25import org.openstreetmap.josm.data.osm.DataSet;
26import org.openstreetmap.josm.data.osm.Filter;
27import org.openstreetmap.josm.data.osm.Filter.FilterPreferenceEntry;
28import org.openstreetmap.josm.data.osm.FilterMatcher;
29import org.openstreetmap.josm.data.osm.FilterWorker;
30import org.openstreetmap.josm.data.osm.Node;
31import org.openstreetmap.josm.data.osm.OsmPrimitive;
32import org.openstreetmap.josm.tools.Utils;
33
34/**
35 * The model that is used for the table in the {@link FilterDialog}.
36 *
37 * @author Petr_Dlouhý
38 */
39public class FilterTableModel extends AbstractTableModel {
40
41 /**
42 * The filter enabled column
43 */
44 public static final int COL_ENABLED = 0;
45 /**
46 * The column indicating if the filter is hiding.
47 */
48 public static final int COL_HIDING = 1;
49 /**
50 * The column that displays the filter text
51 */
52 public static final int COL_TEXT = 2;
53 /**
54 * The column to invert the filter
55 */
56 public static final int COL_INVERTED = 3;
57
58 /**
59 * number of primitives that are disabled but not hidden
60 */
61 public int disabledCount;
62 /**
63 * number of primitives that are disabled and hidden
64 */
65 public int disabledAndHiddenCount;
66
67 /**
68 * Constructs a new {@code FilterTableModel}.
69 */
70 public FilterTableModel() {
71 loadPrefs();
72 }
73
74 private final transient List<Filter> filters = new LinkedList<>();
75 private final transient FilterMatcher filterMatcher = new FilterMatcher();
76
77 private void updateFilters() {
78 filterMatcher.reset();
79 for (Filter filter : filters) {
80 try {
81 filterMatcher.add(filter);
82 } catch (ParseError e) {
83 Main.error(e);
84 JOptionPane.showMessageDialog(
85 Main.parent,
86 tr("<html>Error in filter <code>{0}</code>:<br>{1}",
87 Utils.escapeReservedCharactersHTML(Utils.shortenString(filter.text, 80)),
88 Utils.escapeReservedCharactersHTML(e.getMessage())),
89 tr("Error in filter"),
90 JOptionPane.ERROR_MESSAGE);
91 filter.enable = false;
92 savePrefs();
93 }
94 }
95 executeFilters();
96 }
97
98 /**
99 * Runs the filters on the current edit data set.
100 */
101 public void executeFilters() {
102 DataSet ds = Main.getLayerManager().getEditDataSet();
103 boolean changed = false;
104 if (ds == null) {
105 disabledAndHiddenCount = 0;
106 disabledCount = 0;
107 changed = true;
108 } else {
109 final Collection<OsmPrimitive> deselect = new HashSet<>();
110
111 ds.beginUpdate();
112 try {
113
114 final Collection<OsmPrimitive> all = ds.allNonDeletedCompletePrimitives();
115
116 changed = FilterWorker.executeFilters(all, filterMatcher);
117
118 disabledCount = 0;
119 disabledAndHiddenCount = 0;
120 // collect disabled and selected the primitives
121 for (OsmPrimitive osm : all) {
122 if (osm.isDisabled()) {
123 disabledCount++;
124 if (osm.isSelected()) {
125 deselect.add(osm);
126 }
127 if (osm.isDisabledAndHidden()) {
128 disabledAndHiddenCount++;
129 }
130 }
131 }
132 disabledCount -= disabledAndHiddenCount;
133 } finally {
134 ds.endUpdate();
135 }
136
137 if (!deselect.isEmpty()) {
138 ds.clearSelection(deselect);
139 }
140 }
141
142 if (changed && Main.isDisplayingMapView()) {
143 Main.map.mapView.repaint();
144 Main.map.filterDialog.updateDialogHeader();
145 }
146 }
147
148 /**
149 * Runs the filter on a list of primitives that are part of the edit data set.
150 * @param primitives The primitives
151 */
152 public void executeFilters(Collection<? extends OsmPrimitive> primitives) {
153 DataSet ds = Main.getLayerManager().getEditDataSet();
154 if (ds == null)
155 return;
156
157 boolean changed = false;
158 List<OsmPrimitive> deselect = new ArrayList<>();
159
160 ds.beginUpdate();
161 try {
162 for (int i = 0; i < 2; i++) {
163 for (OsmPrimitive primitive: primitives) {
164
165 if (i == 0 && primitive instanceof Node) {
166 continue;
167 }
168
169 if (i == 1 && !(primitive instanceof Node)) {
170 continue;
171 }
172
173 if (primitive.isDisabled()) {
174 disabledCount--;
175 }
176 if (primitive.isDisabledAndHidden()) {
177 disabledAndHiddenCount--;
178 }
179 changed |= FilterWorker.executeFilters(primitive, filterMatcher);
180 if (primitive.isDisabled()) {
181 disabledCount++;
182 }
183 if (primitive.isDisabledAndHidden()) {
184 disabledAndHiddenCount++;
185 }
186
187 if (primitive.isSelected() && primitive.isDisabled()) {
188 deselect.add(primitive);
189 }
190
191 }
192 }
193 } finally {
194 ds.endUpdate();
195 }
196
197 if (changed) {
198 Main.map.mapView.repaint();
199 Main.map.filterDialog.updateDialogHeader();
200 ds.clearSelection(deselect);
201 }
202
203 }
204
205 /**
206 * Clears all filtered flags from all primitives in the dataset
207 */
208 public void clearFilterFlags() {
209 DataSet ds = Main.getLayerManager().getEditDataSet();
210 if (ds != null) {
211 FilterWorker.clearFilterFlags(ds.allPrimitives());
212 }
213 disabledCount = 0;
214 disabledAndHiddenCount = 0;
215 }
216
217 private void loadPrefs() {
218 List<FilterPreferenceEntry> entries = Main.pref.getListOfStructs("filters.entries", null, FilterPreferenceEntry.class);
219 if (entries != null) {
220 for (FilterPreferenceEntry e : entries) {
221 filters.add(new Filter(e));
222 }
223 updateFilters();
224 }
225 }
226
227 private void savePrefs() {
228 Collection<FilterPreferenceEntry> entries = new ArrayList<>();
229 for (Filter flt : filters) {
230 entries.add(flt.getPreferenceEntry());
231 }
232 Main.pref.putListOfStructs("filters.entries", entries, FilterPreferenceEntry.class);
233 }
234
235 /**
236 * Adds a new filter to the filter list.
237 * @param filter The new filter
238 */
239 public void addFilter(Filter filter) {
240 filters.add(filter);
241 savePrefs();
242 updateFilters();
243 fireTableRowsInserted(filters.size() - 1, filters.size() - 1);
244 }
245
246 /**
247 * Moves down the filter in the given row.
248 * @param rowIndex The filter row
249 */
250 public void moveDownFilter(int rowIndex) {
251 if (rowIndex >= filters.size() - 1)
252 return;
253 filters.add(rowIndex + 1, filters.remove(rowIndex));
254 savePrefs();
255 updateFilters();
256 fireTableRowsUpdated(rowIndex, rowIndex + 1);
257 }
258
259 /**
260 * Moves up the filter in the given row
261 * @param rowIndex The filter row
262 */
263 public void moveUpFilter(int rowIndex) {
264 if (rowIndex == 0)
265 return;
266 filters.add(rowIndex - 1, filters.remove(rowIndex));
267 savePrefs();
268 updateFilters();
269 fireTableRowsUpdated(rowIndex - 1, rowIndex);
270 }
271
272 /**
273 * Removes the filter that is displayed in the given row
274 * @param rowIndex
275 */
276 public void removeFilter(int rowIndex) {
277 filters.remove(rowIndex);
278 savePrefs();
279 updateFilters();
280 fireTableRowsDeleted(rowIndex, rowIndex);
281 }
282
283 /**
284 * Sets/replaces the filter for a given row.
285 * @param rowIndex The row index
286 * @param filter The filter that should be placed in that row
287 */
288 public void setFilter(int rowIndex, Filter filter) {
289 filters.set(rowIndex, filter);
290 savePrefs();
291 updateFilters();
292 fireTableRowsUpdated(rowIndex, rowIndex);
293 }
294
295 /**
296 * Gets the filter by row index
297 * @param rowIndex The row index
298 * @return The filter in that row
299 */
300 public Filter getFilter(int rowIndex) {
301 return filters.get(rowIndex);
302 }
303
304 @Override
305 public int getRowCount() {
306 return filters.size();
307 }
308
309 @Override
310 public int getColumnCount() {
311 return 5;
312 }
313
314 @Override
315 public String getColumnName(int column) {
316 String[] names = {/* translators notes must be in front */
317 /* column header: enable filter */trc("filter", "E"),
318 /* column header: hide filter */trc("filter", "H"),
319 /* column header: filter text */trc("filter", "Text"),
320 /* column header: inverted filter */trc("filter", "I"),
321 /* column header: filter mode */trc("filter", "M")};
322 return names[column];
323 }
324
325 @Override
326 public Class<?> getColumnClass(int column) {
327 Class<?>[] classes = {Boolean.class, Boolean.class, String.class, Boolean.class, String.class};
328 return classes[column];
329 }
330
331 /**
332 * Determines if a cell is enabled.
333 * @param row row index
334 * @param column column index
335 * @return {@code true} if the cell at (row, column) is enabled
336 */
337 public boolean isCellEnabled(int row, int column) {
338 return filters.get(row).enable || column == 0;
339 }
340
341 @Override
342 public boolean isCellEditable(int row, int column) {
343 return column < 4 && isCellEnabled(row, column);
344 }
345
346 @Override
347 public void setValueAt(Object aValue, int row, int column) {
348 if (row >= filters.size()) {
349 return;
350 }
351 Filter f = filters.get(row);
352 switch (column) {
353 case COL_ENABLED:
354 f.enable = (Boolean) aValue;
355 savePrefs();
356 updateFilters();
357 fireTableRowsUpdated(row, row);
358 break;
359 case COL_HIDING:
360 f.hiding = (Boolean) aValue;
361 savePrefs();
362 updateFilters();
363 break;
364 case COL_TEXT:
365 f.text = (String) aValue;
366 savePrefs();
367 break;
368 case COL_INVERTED:
369 f.inverted = (Boolean) aValue;
370 savePrefs();
371 updateFilters();
372 break;
373 default: // Do nothing
374 }
375 if (column != 0) {
376 fireTableCellUpdated(row, column);
377 }
378 }
379
380 @Override
381 public Object getValueAt(int row, int column) {
382 if (row >= filters.size()) {
383 return null;
384 }
385 Filter f = filters.get(row);
386 switch (column) {
387 case COL_ENABLED:
388 return f.enable;
389 case COL_HIDING:
390 return f.hiding;
391 case COL_TEXT:
392 return f.text;
393 case COL_INVERTED:
394 return f.inverted;
395 case 4:
396 switch (f.mode) { /* translators notes must be in front */
397 case replace: /* filter mode: replace */
398 return trc("filter", "R");
399 case add: /* filter mode: add */
400 return trc("filter", "A");
401 case remove: /* filter mode: remove */
402 return trc("filter", "D");
403 case in_selection: /* filter mode: in selection */
404 return trc("filter", "F");
405 default:
406 Main.warn("Unknown filter mode: " + f.mode);
407 }
408 break;
409 default: // Do nothing
410 }
411 return null;
412 }
413
414 /**
415 * On screen display label
416 */
417 private static class OSDLabel extends JLabel {
418 OSDLabel(String text) {
419 super(text);
420 setOpaque(true);
421 setForeground(Color.black);
422 setBackground(new Color(0, 0, 0, 0));
423 setFont(getFont().deriveFont(Font.PLAIN));
424 setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
425 }
426
427 @Override
428 public void paintComponent(Graphics g) {
429 g.setColor(new Color(255, 255, 255, 140));
430 g.fillRoundRect(getX(), getY(), getWidth(), getHeight(), 10, 10);
431 super.paintComponent(g);
432 }
433 }
434
435 private final OSDLabel lblOSD = new OSDLabel("");
436
437 /**
438 * Draws a text on the map display that indicates that filters are active.
439 * @param g The graphics to draw that text on.
440 */
441 public void drawOSDText(Graphics2D g) {
442 String message = "<html>" + tr("<h2>Filter active</h2>");
443
444 if (disabledCount == 0 && disabledAndHiddenCount == 0)
445 return;
446
447 if (disabledAndHiddenCount != 0) {
448 /* for correct i18n of plural forms - see #9110 */
449 message += trn("<p><b>{0}</b> object hidden", "<p><b>{0}</b> objects hidden", disabledAndHiddenCount, disabledAndHiddenCount);
450 }
451
452 if (disabledAndHiddenCount != 0 && disabledCount != 0) {
453 message += "<br>";
454 }
455
456 if (disabledCount != 0) {
457 /* for correct i18n of plural forms - see #9110 */
458 message += trn("<b>{0}</b> object disabled", "<b>{0}</b> objects disabled", disabledCount, disabledCount);
459 }
460
461 message += tr("</p><p>Close the filter dialog to see all objects.<p></html>");
462
463 lblOSD.setText(message);
464 lblOSD.setSize(lblOSD.getPreferredSize());
465
466 int dx = Main.map.mapView.getWidth() - lblOSD.getPreferredSize().width - 15;
467 int dy = 15;
468 g.translate(dx, dy);
469 lblOSD.paintComponent(g);
470 g.translate(-dx, -dy);
471 }
472
473 /**
474 * Returns the list of filters.
475 * @return the list of filters
476 */
477 public List<Filter> getFilters() {
478 return filters;
479 }
480}
Note: See TracBrowser for help on using the repository browser.