[8378] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
[3669] | 2 | package org.openstreetmap.josm.gui.layer;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
| 5 |
|
---|
| 6 | import java.awt.Graphics2D;
|
---|
[12667] | 7 | import java.io.File;
|
---|
[10507] | 8 | import java.util.Collections;
|
---|
[3669] | 9 | import java.util.Enumeration;
|
---|
| 10 | import java.util.List;
|
---|
| 11 |
|
---|
| 12 | import javax.swing.Action;
|
---|
| 13 | import javax.swing.Icon;
|
---|
| 14 | import javax.swing.tree.DefaultMutableTreeNode;
|
---|
[8633] | 15 | import javax.swing.tree.TreeNode;
|
---|
[3669] | 16 |
|
---|
| 17 | import org.openstreetmap.josm.actions.RenameLayerAction;
|
---|
[12667] | 18 | import org.openstreetmap.josm.actions.SaveActionBase;
|
---|
[3669] | 19 | import org.openstreetmap.josm.data.Bounds;
|
---|
| 20 | import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
|
---|
| 21 | import org.openstreetmap.josm.data.validation.OsmValidator;
|
---|
[5671] | 22 | import org.openstreetmap.josm.data.validation.PaintVisitor;
|
---|
[3669] | 23 | import org.openstreetmap.josm.data.validation.Severity;
|
---|
| 24 | import org.openstreetmap.josm.data.validation.TestError;
|
---|
[12630] | 25 | import org.openstreetmap.josm.gui.MainApplication;
|
---|
[3669] | 26 | import org.openstreetmap.josm.gui.MapView;
|
---|
| 27 | import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
|
---|
| 28 | import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
|
---|
[12671] | 29 | import org.openstreetmap.josm.gui.io.importexport.ValidatorErrorExporter;
|
---|
[10386] | 30 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
|
---|
| 31 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
|
---|
| 32 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
|
---|
| 33 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
|
---|
[3669] | 34 | import org.openstreetmap.josm.tools.ImageProvider;
|
---|
[3674] | 35 | import org.openstreetmap.josm.tools.MultiMap;
|
---|
[3669] | 36 |
|
---|
| 37 | /**
|
---|
| 38 | * A layer showing error messages.
|
---|
| 39 | *
|
---|
| 40 | * @author frsantos
|
---|
[10386] | 41 | *
|
---|
| 42 | * @since 3669 (creation)
|
---|
| 43 | * @since 10386 (new LayerChangeListener interface)
|
---|
[3669] | 44 | */
|
---|
| 45 | public class ValidatorLayer extends Layer implements LayerChangeListener {
|
---|
[10880] | 46 | private final Runnable invalidator = this::invalidate;
|
---|
[3669] | 47 |
|
---|
[5671] | 48 | /**
|
---|
| 49 | * Constructs a new Validator layer
|
---|
| 50 | */
|
---|
[3669] | 51 | public ValidatorLayer() {
|
---|
| 52 | super(tr("Validation errors"));
|
---|
[12636] | 53 | MainApplication.getLayerManager().addLayerChangeListener(this);
|
---|
[12630] | 54 | MainApplication.getMap().validatorDialog.tree.addInvalidationListener(invalidator);
|
---|
[3669] | 55 | }
|
---|
| 56 |
|
---|
| 57 | /**
|
---|
| 58 | * Return a static icon.
|
---|
| 59 | */
|
---|
| 60 | @Override
|
---|
| 61 | public Icon getIcon() {
|
---|
| 62 | return ImageProvider.get("layer", "validator_small");
|
---|
| 63 | }
|
---|
| 64 |
|
---|
| 65 | /**
|
---|
| 66 | * Draw all primitives in this layer but do not draw modified ones (they
|
---|
| 67 | * are drawn by the edit layer).
|
---|
| 68 | * Draw nodes last to overlap the ways they belong to.
|
---|
| 69 | */
|
---|
| 70 | @SuppressWarnings("unchecked")
|
---|
| 71 | @Override
|
---|
| 72 | public void paint(final Graphics2D g, final MapView mv, Bounds bounds) {
|
---|
[12630] | 73 | DefaultMutableTreeNode root = MainApplication.getMap().validatorDialog.tree.getRoot();
|
---|
[3669] | 74 | if (root == null || root.getChildCount() == 0)
|
---|
| 75 | return;
|
---|
[6070] | 76 |
|
---|
[5671] | 77 | PaintVisitor paintVisitor = new PaintVisitor(g, mv);
|
---|
[3669] | 78 |
|
---|
| 79 | DefaultMutableTreeNode severity = (DefaultMutableTreeNode) root.getLastChild();
|
---|
| 80 | while (severity != null) {
|
---|
[8633] | 81 | Enumeration<TreeNode> errorMessages = severity.breadthFirstEnumeration();
|
---|
[3669] | 82 | while (errorMessages.hasMoreElements()) {
|
---|
[8633] | 83 | Object tn = ((DefaultMutableTreeNode) errorMessages.nextElement()).getUserObject();
|
---|
[3671] | 84 | if (tn instanceof TestError) {
|
---|
[8345] | 85 | paintVisitor.visit((TestError) tn);
|
---|
[3671] | 86 | }
|
---|
[3669] | 87 | }
|
---|
| 88 |
|
---|
| 89 | // Severities in inverse order
|
---|
| 90 | severity = severity.getPreviousSibling();
|
---|
| 91 | }
|
---|
[6070] | 92 |
|
---|
[5671] | 93 | paintVisitor.clearPaintedObjects();
|
---|
[3669] | 94 | }
|
---|
| 95 |
|
---|
| 96 | @Override
|
---|
| 97 | public String getToolTipText() {
|
---|
[7005] | 98 | MultiMap<Severity, TestError> errorTree = new MultiMap<>();
|
---|
[12630] | 99 | List<TestError> errors = MainApplication.getMap().validatorDialog.tree.getErrors();
|
---|
[3669] | 100 | for (TestError e : errors) {
|
---|
[3674] | 101 | errorTree.put(e.getSeverity(), e);
|
---|
[3669] | 102 | }
|
---|
| 103 |
|
---|
| 104 | StringBuilder b = new StringBuilder();
|
---|
| 105 | for (Severity s : Severity.values()) {
|
---|
[3671] | 106 | if (errorTree.containsKey(s)) {
|
---|
[3669] | 107 | b.append(tr(s.toString())).append(": ").append(errorTree.get(s).size()).append("<br>");
|
---|
[3671] | 108 | }
|
---|
[3669] | 109 | }
|
---|
| 110 |
|
---|
| 111 | if (b.length() == 0)
|
---|
| 112 | return "<html>" + tr("No validation errors") + "</html>";
|
---|
| 113 | else
|
---|
| 114 | return "<html>" + tr("Validation errors") + ":<br>" + b + "</html>";
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | @Override
|
---|
| 118 | public void mergeFrom(Layer from) {
|
---|
[10173] | 119 | // Do nothing
|
---|
[3669] | 120 | }
|
---|
| 121 |
|
---|
| 122 | @Override
|
---|
| 123 | public boolean isMergable(Layer other) {
|
---|
| 124 | return false;
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | @Override
|
---|
| 128 | public void visitBoundingBox(BoundingXYVisitor v) {
|
---|
[10173] | 129 | // Do nothing
|
---|
[3669] | 130 | }
|
---|
| 131 |
|
---|
| 132 | @Override
|
---|
| 133 | public Object getInfoComponent() {
|
---|
| 134 | return getToolTipText();
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | @Override
|
---|
| 138 | public Action[] getMenuEntries() {
|
---|
| 139 | return new Action[] {
|
---|
| 140 | LayerListDialog.getInstance().createShowHideLayerAction(),
|
---|
| 141 | LayerListDialog.getInstance().createDeleteLayerAction(),
|
---|
| 142 | SeparatorLayerAction.INSTANCE,
|
---|
| 143 | new RenameLayerAction(null, this),
|
---|
| 144 | SeparatorLayerAction.INSTANCE,
|
---|
[12667] | 145 | new LayerListPopup.InfoAction(this),
|
---|
| 146 | new LayerSaveAsAction(this)
|
---|
| 147 | };
|
---|
[3669] | 148 | }
|
---|
| 149 |
|
---|
| 150 | @Override
|
---|
[12667] | 151 | public File createAndOpenSaveFileChooser() {
|
---|
| 152 | return SaveActionBase.createAndOpenSaveFileChooser(tr("Save Validation errors file"), ValidatorErrorExporter.FILE_FILTER);
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | @Override
|
---|
[10386] | 156 | public void layerOrderChanged(LayerOrderChangeEvent e) {
|
---|
[10173] | 157 | // Do nothing
|
---|
[3669] | 158 | }
|
---|
| 159 |
|
---|
[3671] | 160 | @Override
|
---|
[10386] | 161 | public void layerAdded(LayerAddEvent e) {
|
---|
[10173] | 162 | // Do nothing
|
---|
[3669] | 163 | }
|
---|
| 164 |
|
---|
| 165 | /**
|
---|
| 166 | * If layer is the OSM Data layer, remove all errors
|
---|
| 167 | */
|
---|
[3671] | 168 | @Override
|
---|
[10386] | 169 | public void layerRemoving(LayerRemoveEvent e) {
|
---|
[10453] | 170 | // Removed layer is still in that list.
|
---|
| 171 | if (e.getRemovedLayer() instanceof OsmDataLayer && e.getSource().getLayersOfType(OsmDataLayer.class).size() <= 1) {
|
---|
[10507] | 172 | e.scheduleRemoval(Collections.singleton(this));
|
---|
[10386] | 173 | } else if (e.getRemovedLayer() == this) {
|
---|
[11852] | 174 | OsmValidator.resetErrorLayer();
|
---|
[3669] | 175 | }
|
---|
| 176 | }
|
---|
[10008] | 177 |
|
---|
| 178 | @Override
|
---|
| 179 | public LayerPositionStrategy getDefaultLayerPosition() {
|
---|
| 180 | return LayerPositionStrategy.IN_FRONT;
|
---|
| 181 | }
|
---|
[10880] | 182 |
|
---|
| 183 | @Override
|
---|
[12028] | 184 | public synchronized void destroy() {
|
---|
[12630] | 185 | MainApplication.getMap().validatorDialog.tree.removeInvalidationListener(invalidator);
|
---|
[12636] | 186 | MainApplication.getLayerManager().removeLayerChangeListener(this);
|
---|
[10880] | 187 | super.destroy();
|
---|
| 188 | }
|
---|
[3669] | 189 | }
|
---|