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

Last change on this file since 9438 was 9348, checked in by simon04, 8 years ago

see #12083 - When activating an erroneous filter, name the filter with the error

  • Property svn:eol-style set to native
File size: 12.4 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 *
36 * @author Petr_Dlouhý
37 */
38public class FilterTableModel extends AbstractTableModel {
39
40 public static final int COL_ENABLED = 0;
41 public static final int COL_HIDING = 1;
42 public static final int COL_TEXT = 2;
43 public static final int COL_INVERTED = 3;
44
45 // number of primitives that are disabled but not hidden
46 public int disabledCount;
47 // number of primitives that are disabled and hidden
48 public int disabledAndHiddenCount;
49
50 /**
51 * Constructs a new {@code FilterTableModel}.
52 */
53 public FilterTableModel() {
54 loadPrefs();
55 }
56
57 private final transient List<Filter> filters = new LinkedList<>();
58 private final transient FilterMatcher filterMatcher = new FilterMatcher();
59
60 private void updateFilters() {
61 filterMatcher.reset();
62 for (Filter filter : filters) {
63 try {
64 filterMatcher.add(filter);
65 } catch (ParseError e) {
66 JOptionPane.showMessageDialog(
67 Main.parent,
68 tr("<html>Error in filter <code>{0}</code>:<br>{1}", Utils.shortenString(filter.text, 80), e.getMessage()),
69 tr("Error in filter"),
70 JOptionPane.ERROR_MESSAGE);
71 filter.enable = false;
72 savePrefs();
73 }
74 }
75 executeFilters();
76 }
77
78 public void executeFilters() {
79 DataSet ds = Main.main.getCurrentDataSet();
80 boolean changed = false;
81 if (ds == null) {
82 disabledAndHiddenCount = 0;
83 disabledCount = 0;
84 changed = true;
85 } else {
86 final Collection<OsmPrimitive> deselect = new HashSet<>();
87
88 ds.beginUpdate();
89 try {
90
91 final Collection<OsmPrimitive> all = ds.allNonDeletedCompletePrimitives();
92
93 changed = FilterWorker.executeFilters(all, filterMatcher);
94
95 disabledCount = 0;
96 disabledAndHiddenCount = 0;
97 // collect disabled and selected the primitives
98 for (OsmPrimitive osm : all) {
99 if (osm.isDisabled()) {
100 disabledCount++;
101 if (osm.isSelected()) {
102 deselect.add(osm);
103 }
104 if (osm.isDisabledAndHidden()) {
105 disabledAndHiddenCount++;
106 }
107 }
108 }
109 disabledCount -= disabledAndHiddenCount;
110 } finally {
111 ds.endUpdate();
112 }
113
114 if (!deselect.isEmpty()) {
115 ds.clearSelection(deselect);
116 }
117 }
118
119 if (Main.isDisplayingMapView() && changed) {
120 Main.map.mapView.repaint();
121 Main.map.filterDialog.updateDialogHeader();
122 }
123 }
124
125 public void executeFilters(Collection<? extends OsmPrimitive> primitives) {
126 DataSet ds = Main.main.getCurrentDataSet();
127 if (ds == null)
128 return;
129
130 boolean changed = false;
131 List<OsmPrimitive> deselect = new ArrayList<>();
132
133 ds.beginUpdate();
134 try {
135 for (int i = 0; i < 2; i++) {
136 for (OsmPrimitive primitive: primitives) {
137
138 if (i == 0 && primitive instanceof Node) {
139 continue;
140 }
141
142 if (i == 1 && !(primitive instanceof Node)) {
143 continue;
144 }
145
146 if (primitive.isDisabled()) {
147 disabledCount--;
148 }
149 if (primitive.isDisabledAndHidden()) {
150 disabledAndHiddenCount--;
151 }
152 changed = changed | FilterWorker.executeFilters(primitive, filterMatcher);
153 if (primitive.isDisabled()) {
154 disabledCount++;
155 }
156 if (primitive.isDisabledAndHidden()) {
157 disabledAndHiddenCount++;
158 }
159
160 if (primitive.isSelected() && primitive.isDisabled()) {
161 deselect.add(primitive);
162 }
163
164 }
165 }
166 } finally {
167 ds.endUpdate();
168 }
169
170 if (changed) {
171 Main.map.mapView.repaint();
172 Main.map.filterDialog.updateDialogHeader();
173 ds.clearSelection(deselect);
174 }
175
176 }
177
178 public void clearFilterFlags() {
179 DataSet ds = Main.main.getCurrentDataSet();
180 if (ds != null) {
181 FilterWorker.clearFilterFlags(ds.allPrimitives());
182 }
183 disabledCount = 0;
184 disabledAndHiddenCount = 0;
185 }
186
187 private void loadPrefs() {
188 List<FilterPreferenceEntry> entries = Main.pref.getListOfStructs("filters.entries", null, FilterPreferenceEntry.class);
189 if (entries != null) {
190 for (FilterPreferenceEntry e : entries) {
191 filters.add(new Filter(e));
192 }
193 updateFilters();
194 }
195 }
196
197 private void savePrefs() {
198 Collection<FilterPreferenceEntry> entries = new ArrayList<>();
199 for (Filter flt : filters) {
200 entries.add(flt.getPreferenceEntry());
201 }
202 Main.pref.putListOfStructs("filters.entries", entries, FilterPreferenceEntry.class);
203 }
204
205 public void addFilter(Filter f) {
206 filters.add(f);
207 savePrefs();
208 updateFilters();
209 fireTableRowsInserted(filters.size() - 1, filters.size() - 1);
210 }
211
212 public void moveDownFilter(int i) {
213 if (i >= filters.size() - 1)
214 return;
215 filters.add(i + 1, filters.remove(i));
216 savePrefs();
217 updateFilters();
218 fireTableRowsUpdated(i, i + 1);
219 }
220
221 public void moveUpFilter(int i) {
222 if (i == 0)
223 return;
224 filters.add(i - 1, filters.remove(i));
225 savePrefs();
226 updateFilters();
227 fireTableRowsUpdated(i - 1, i);
228 }
229
230 public void removeFilter(int i) {
231 filters.remove(i);
232 savePrefs();
233 updateFilters();
234 fireTableRowsDeleted(i, i);
235 }
236
237 public void setFilter(int i, Filter f) {
238 filters.set(i, f);
239 savePrefs();
240 updateFilters();
241 fireTableRowsUpdated(i, i);
242 }
243
244 public Filter getFilter(int i) {
245 return filters.get(i);
246 }
247
248 @Override
249 public int getRowCount() {
250 return filters.size();
251 }
252
253 @Override
254 public int getColumnCount() {
255 return 5;
256 }
257
258 @Override
259 public String getColumnName(int column) {
260 String[] names = {/* translators notes must be in front */
261 /* column header: enable filter */trc("filter", "E"),
262 /* column header: hide filter */trc("filter", "H"),
263 /* column header: filter text */trc("filter", "Text"),
264 /* column header: inverted filter */trc("filter", "I"),
265 /* column header: filter mode */trc("filter", "M")};
266 return names[column];
267 }
268
269 @Override
270 public Class<?> getColumnClass(int column) {
271 Class<?>[] classes = {Boolean.class, Boolean.class, String.class, Boolean.class, String.class};
272 return classes[column];
273 }
274
275 public boolean isCellEnabled(int row, int column) {
276 if (!filters.get(row).enable && column != 0)
277 return false;
278 return true;
279 }
280
281 @Override
282 public boolean isCellEditable(int row, int column) {
283 if (!filters.get(row).enable && column != 0)
284 return false;
285 if (column < 4)
286 return true;
287 return false;
288 }
289
290 @Override
291 public void setValueAt(Object aValue, int row, int column) {
292 if (row >= filters.size()) {
293 return;
294 }
295 Filter f = filters.get(row);
296 switch (column) {
297 case COL_ENABLED:
298 f.enable = (Boolean) aValue;
299 savePrefs();
300 updateFilters();
301 fireTableRowsUpdated(row, row);
302 break;
303 case COL_HIDING:
304 f.hiding = (Boolean) aValue;
305 savePrefs();
306 updateFilters();
307 break;
308 case COL_TEXT:
309 f.text = (String) aValue;
310 savePrefs();
311 break;
312 case COL_INVERTED:
313 f.inverted = (Boolean) aValue;
314 savePrefs();
315 updateFilters();
316 break;
317 }
318 if (column != 0) {
319 fireTableCellUpdated(row, column);
320 }
321 }
322
323 @Override
324 public Object getValueAt(int row, int column) {
325 if (row >= filters.size()) {
326 return null;
327 }
328 Filter f = filters.get(row);
329 switch (column) {
330 case COL_ENABLED:
331 return f.enable;
332 case COL_HIDING:
333 return f.hiding;
334 case COL_TEXT:
335 return f.text;
336 case COL_INVERTED:
337 return f.inverted;
338 case 4:
339 switch (f.mode) { /* translators notes must be in front */
340 case replace: /* filter mode: replace */
341 return trc("filter", "R");
342 case add: /* filter mode: add */
343 return trc("filter", "A");
344 case remove: /* filter mode: remove */
345 return trc("filter", "D");
346 case in_selection: /* filter mode: in selection */
347 return trc("filter", "F");
348 }
349 }
350 return null;
351 }
352
353 /**
354 * On screen display label
355 */
356 private static class OSDLabel extends JLabel {
357 OSDLabel(String text) {
358 super(text);
359 setOpaque(true);
360 setForeground(Color.black);
361 setBackground(new Color(0, 0, 0, 0));
362 setFont(getFont().deriveFont(Font.PLAIN));
363 setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
364 }
365
366 @Override
367 public void paintComponent(Graphics g) {
368 g.setColor(new Color(255, 255, 255, 140));
369 g.fillRoundRect(getX(), getY(), getWidth(), getHeight(), 10, 10);
370 super.paintComponent(g);
371 }
372 }
373
374 private final OSDLabel lblOSD = new OSDLabel("");
375
376 public void drawOSDText(Graphics2D g) {
377 String message = "<html>" + tr("<h2>Filter active</h2>");
378
379 if (disabledCount == 0 && disabledAndHiddenCount == 0)
380 return;
381
382 if (disabledAndHiddenCount != 0) {
383 /* for correct i18n of plural forms - see #9110 */
384 message += trn("<p><b>{0}</b> object hidden", "<p><b>{0}</b> objects hidden", disabledAndHiddenCount, disabledAndHiddenCount);
385 }
386
387 if (disabledAndHiddenCount != 0 && disabledCount != 0) {
388 message += "<br>";
389 }
390
391 if (disabledCount != 0) {
392 /* for correct i18n of plural forms - see #9110 */
393 message += trn("<b>{0}</b> object disabled", "<b>{0}</b> objects disabled", disabledCount, disabledCount);
394 }
395
396 message += tr("</p><p>Close the filter dialog to see all objects.<p></html>");
397
398 lblOSD.setText(message);
399 lblOSD.setSize(lblOSD.getPreferredSize());
400
401 int dx = Main.map.mapView.getWidth() - lblOSD.getPreferredSize().width - 15;
402 int dy = 15;
403 g.translate(dx, dy);
404 lblOSD.paintComponent(g);
405 g.translate(-dx, -dy);
406 }
407
408 public List<Filter> getFilters() {
409 return filters;
410 }
411}
Note: See TracBrowser for help on using the repository browser.