source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java@ 3745

Last change on this file since 3745 was 3745, checked in by bastiK, 13 years ago

fixed #5752 - validator: warning window on upload is broken (2)

  • Property svn:eol-style set to native
File size: 12.4 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.gui.dialogs.validator;
3
4import java.awt.event.MouseEvent;
5import java.util.ArrayList;
6import java.util.Collections;
7import java.util.Enumeration;
8import java.util.HashMap;
9import java.util.HashSet;
10import java.util.LinkedHashSet;
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14import java.util.Map.Entry;
15
16import javax.swing.JTree;
17import javax.swing.ToolTipManager;
18import javax.swing.tree.DefaultMutableTreeNode;
19import javax.swing.tree.DefaultTreeModel;
20import javax.swing.tree.TreePath;
21import javax.swing.tree.TreeSelectionModel;
22
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.validation.Severity;
25import org.openstreetmap.josm.data.validation.TestError;
26import org.openstreetmap.josm.data.validation.util.MultipleNameVisitor;
27import org.openstreetmap.josm.gui.preferences.ValidatorPreference;
28import org.openstreetmap.josm.tools.MultiMap;
29import org.openstreetmap.josm.Main;
30
31/**
32 * A panel that displays the error tree. The selection manager
33 * respects clicks into the selection list. Ctrl-click will remove entries from
34 * the list while single click will make the clicked entry the only selection.
35 *
36 * @author frsantos
37 */
38public class ValidatorTreePanel extends JTree {
39 /** Serializable ID */
40 private static final long serialVersionUID = 2952292777351992696L;
41
42 /**
43 * The validation data.
44 */
45 protected DefaultTreeModel valTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
46
47 /** The list of errors shown in the tree */
48 private List<TestError> errors = new ArrayList<TestError>();
49
50 /**
51 * If {@link #filter} is not <code>null</code> only errors are displayed
52 * that refer to one of the primitives in the filter.
53 */
54 private Set<OsmPrimitive> filter = null;
55
56 private int updateCount;
57
58 /**
59 * Constructor
60 * @param errors The list of errors
61 */
62 public ValidatorTreePanel(List<TestError> errors) {
63 ToolTipManager.sharedInstance().registerComponent(this);
64 this.setModel(valTreeModel);
65 this.setRootVisible(false);
66 this.setShowsRootHandles(true);
67 this.expandRow(0);
68 this.setVisibleRowCount(8);
69 this.setCellRenderer(new ValidatorTreeRenderer());
70 this.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
71 setErrorList(errors);
72 }
73
74 @Override
75 public String getToolTipText(MouseEvent e) {
76 String res = null;
77 TreePath path = getPathForLocation(e.getX(), e.getY());
78 if (path != null) {
79 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
80 Object nodeInfo = node.getUserObject();
81
82 if (nodeInfo instanceof TestError) {
83 TestError error = (TestError) nodeInfo;
84 MultipleNameVisitor v = new MultipleNameVisitor();
85 v.visit(error.getPrimitives());
86 res = "<html>" + v.getText() + "<br>" + error.getMessage();
87 String d = error.getDescription();
88 if (d != null)
89 res += "<br>" + d;
90 res += "</html>";
91 } else {
92 res = node.toString();
93 }
94 }
95 return res;
96 }
97
98 /** Constructor */
99 public ValidatorTreePanel() {
100 this(null);
101 }
102
103 @Override
104 public void setVisible(boolean v) {
105 if (v) {
106 buildTree();
107 } else {
108 valTreeModel.setRoot(new DefaultMutableTreeNode());
109 }
110 super.setVisible(v);
111 }
112
113 /**
114 * Builds the errors tree
115 */
116 public void buildTree() {
117 updateCount++;
118 DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
119
120 if (errors == null || errors.isEmpty()) {
121 valTreeModel.setRoot(rootNode);
122 return;
123 }
124
125 // Remember the currently expanded rows
126 Set<Object> oldSelectedRows = new HashSet<Object>();
127 Enumeration<TreePath> expanded = getExpandedDescendants(new TreePath(getRoot()));
128 if (expanded != null) {
129 while (expanded.hasMoreElements()) {
130 TreePath path = expanded.nextElement();
131 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
132 Object userObject = node.getUserObject();
133 if (userObject instanceof Severity) {
134 oldSelectedRows.add(userObject);
135 } else if (userObject instanceof String) {
136 String msg = (String) userObject;
137 msg = msg.substring(0, msg.lastIndexOf(" ("));
138 oldSelectedRows.add(msg);
139 }
140 }
141 }
142
143 Map<Severity, MultiMap<String, TestError>> errorTree = new HashMap<Severity, MultiMap<String, TestError>>();
144 Map<Severity, HashMap<String, MultiMap<String, TestError>>> errorTreeDeep = new HashMap<Severity, HashMap<String, MultiMap<String, TestError>>>();
145 for (Severity s : Severity.values()) {
146 errorTree.put(s, new MultiMap<String, TestError>(20));
147 errorTreeDeep.put(s, new HashMap<String, MultiMap<String, TestError>>());
148 }
149
150 boolean other = Main.pref.getBoolean(ValidatorPreference.PREF_OTHER, false);
151 for (TestError e : errors) {
152 if (e.getIgnored()) {
153 continue;
154 }
155 Severity s = e.getSeverity();
156 if(!other && s == Severity.OTHER) {
157 continue;
158 }
159 String d = e.getDescription();
160 String m = e.getMessage();
161 if (filter != null) {
162 boolean found = false;
163 for (OsmPrimitive p : e.getPrimitives()) {
164 if (filter.contains(p)) {
165 found = true;
166 break;
167 }
168 }
169 if (!found) {
170 continue;
171 }
172 }
173 if (d != null) {
174 MultiMap<String, TestError> b = errorTreeDeep.get(s).get(m);
175 if (b == null) {
176 b = new MultiMap<String, TestError>(20);
177 errorTreeDeep.get(s).put(m, b);
178 }
179 b.put(d, e);
180 } else {
181 errorTree.get(s).put(m, e);
182 }
183 }
184
185 List<TreePath> expandedPaths = new ArrayList<TreePath>();
186 for (Severity s : Severity.values()) {
187 MultiMap<String, TestError> severityErrors = errorTree.get(s);
188 Map<String, MultiMap<String, TestError>> severityErrorsDeep = errorTreeDeep.get(s);
189 if (severityErrors.isEmpty() && severityErrorsDeep.isEmpty()) {
190 continue;
191 }
192
193 // Severity node
194 DefaultMutableTreeNode severityNode = new DefaultMutableTreeNode(s);
195 rootNode.add(severityNode);
196
197 if (oldSelectedRows.contains(s)) {
198 expandedPaths.add(new TreePath(new Object[] { rootNode, severityNode }));
199 }
200
201 for (Entry<String, LinkedHashSet<TestError>> msgErrors : severityErrors.entrySet()) {
202 // Message node
203 Set<TestError> errs = msgErrors.getValue();
204 String msg = msgErrors.getKey() + " (" + errs.size() + ")";
205 DefaultMutableTreeNode messageNode = new DefaultMutableTreeNode(msg);
206 severityNode.add(messageNode);
207
208 if (oldSelectedRows.contains(msgErrors.getKey())) {
209 expandedPaths.add(new TreePath(new Object[] { rootNode, severityNode, messageNode }));
210 }
211
212 for (TestError error : errs) {
213 // Error node
214 DefaultMutableTreeNode errorNode = new DefaultMutableTreeNode(error);
215 messageNode.add(errorNode);
216 }
217 }
218 for (Entry<String, MultiMap<String, TestError>> bag : severityErrorsDeep.entrySet()) {
219 // Group node
220 MultiMap<String, TestError> errorlist = bag.getValue();
221 DefaultMutableTreeNode groupNode = null;
222 if (errorlist.size() > 1) {
223 String nmsg = bag.getKey() + " (" + errorlist.size() + ")";
224 groupNode = new DefaultMutableTreeNode(nmsg);
225 severityNode.add(groupNode);
226 if (oldSelectedRows.contains(bag.getKey())) {
227 expandedPaths.add(new TreePath(new Object[] { rootNode, severityNode, groupNode }));
228 }
229 }
230
231 for (Entry<String, LinkedHashSet<TestError>> msgErrors : errorlist.entrySet()) {
232 // Message node
233 Set<TestError> errs = msgErrors.getValue();
234 String msg;
235 if (groupNode != null) {
236 msg = msgErrors.getKey() + " (" + errs.size() + ")";
237 } else {
238 msg = bag.getKey() + " - " + msgErrors.getKey() + " (" + errs.size() + ")";
239 }
240 DefaultMutableTreeNode messageNode = new DefaultMutableTreeNode(msg);
241 if (groupNode != null) {
242 groupNode.add(messageNode);
243 } else {
244 severityNode.add(messageNode);
245 }
246
247 if (oldSelectedRows.contains(msgErrors.getKey())) {
248 if (groupNode != null) {
249 expandedPaths.add(new TreePath(new Object[] { rootNode, severityNode, groupNode,
250 messageNode }));
251 } else {
252 expandedPaths.add(new TreePath(new Object[] { rootNode, severityNode, messageNode }));
253 }
254 }
255
256 for (TestError error : errs) {
257 // Error node
258 DefaultMutableTreeNode errorNode = new DefaultMutableTreeNode(error);
259 messageNode.add(errorNode);
260 }
261 }
262 }
263 }
264
265 valTreeModel.setRoot(rootNode);
266 for (TreePath path : expandedPaths) {
267 this.expandPath(path);
268 }
269 }
270
271 /**
272 * Sets the errors list used by a data layer
273 * @param errors The error list that is used by a data layer
274 */
275 public void setErrorList(List<TestError> errors) {
276 this.errors = errors;
277 if (isVisible()) {
278 buildTree();
279 }
280 }
281
282 /**
283 * Clears the current error list and adds these errors to it
284 * @param errors The validation errors
285 */
286 public void setErrors(List<TestError> newerrors) {
287 if (errors == null)
288 return;
289 errors.clear();
290 for (TestError error : newerrors) {
291 if (!error.getIgnored()) {
292 errors.add(error);
293 }
294 }
295 if (isVisible()) {
296 buildTree();
297 }
298 }
299
300 /**
301 * Returns the errors of the tree
302 * @return the errors of the tree
303 */
304 public List<TestError> getErrors() {
305 return errors != null ? errors : Collections.<TestError> emptyList();
306 }
307
308 public Set<OsmPrimitive> getFilter() {
309 return filter;
310 }
311
312 public void setFilter(Set<OsmPrimitive> filter) {
313 if (filter != null && filter.isEmpty()) {
314 this.filter = null;
315 } else {
316 this.filter = filter;
317 }
318 if (isVisible()) {
319 buildTree();
320 }
321 }
322
323 /**
324 * Updates the current errors list
325 * @param errors The validation errors
326 */
327 public void resetErrors() {
328 List<TestError> e = new ArrayList<TestError>(errors);
329 setErrors(e);
330 }
331
332 /**
333 * Expands all tree
334 */
335 @SuppressWarnings("unchecked")
336 public void expandAll() {
337 DefaultMutableTreeNode root = getRoot();
338
339 int row = 0;
340 Enumeration<DefaultMutableTreeNode> children = root.breadthFirstEnumeration();
341 while (children.hasMoreElements()) {
342 children.nextElement();
343 expandRow(row++);
344 }
345 }
346
347 /**
348 * Returns the root node model.
349 * @return The root node model
350 */
351 public DefaultMutableTreeNode getRoot() {
352 return (DefaultMutableTreeNode) valTreeModel.getRoot();
353 }
354
355 public int getUpdateCount() {
356 return updateCount;
357 }
358}
Note: See TracBrowser for help on using the repository browser.