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

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

fix #14613 - Special HTML characters not escaped in GUI error messages

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