// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.data.validation.tests; import static org.openstreetmap.josm.tools.I18n.marktr; import static org.openstreetmap.josm.tools.I18n.tr; import java.util.Locale; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.data.osm.AbstractPrimitive; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.validation.Severity; import org.openstreetmap.josm.data.validation.Test; import org.openstreetmap.josm.data.validation.TestError; /** * Checks for nodes with uninteresting tags that are in no way * * @author frsantos */ public class UntaggedNode extends Test implements AbstractPrimitive.KeyValueVisitor { protected static final int UNTAGGED_NODE_BLANK = 201; protected static final int UNTAGGED_NODE_FIXME = 202; protected static final int UNTAGGED_NODE_NOTE = 203; protected static final int UNTAGGED_NODE_CREATED_BY = 204; protected static final int UNTAGGED_NODE_WATCH = 205; protected static final int UNTAGGED_NODE_SOURCE = 206; protected static final int UNTAGGED_NODE_OTHER = 207; protected static final String ERROR_MESSAGE = tr("Unconnected nodes without physical tags"); /** * Constructor */ public UntaggedNode() { super(tr("Untagged and unconnected nodes"), tr("This test checks for untagged nodes that are not part of any way.")); } @Override public void visit(Node n) { if (n.isUsable() && !n.isTagged() && n.getReferrers().isEmpty()) { if (!n.hasKeys() && IN_DOWNLOADED_AREA.test(n)) { errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_BLANK) .message(ERROR_MESSAGE, marktr("No tags")) .primitives(n) .build()); return; } n.visitKeys(this); } } private static OsmPrimitive[] castPrim(AbstractPrimitive n) { return n instanceof OsmPrimitive ? (new OsmPrimitive[]{(OsmPrimitive) n}) : (new OsmPrimitive[0]); } @Override public void visitKeyValue(AbstractPrimitive n, String key, String value) { if (key.toLowerCase(Locale.ENGLISH).contains("fixme") || value.toLowerCase(Locale.ENGLISH).contains("fixme")) { /* translation note: don't translate quoted words */ errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_FIXME) .message(ERROR_MESSAGE, marktr("Has tag containing ''fixme'' or ''FIXME''")) .primitives(castPrim(n)) .build()); return; } String msg = null; int code = 0; if (key.startsWith("note") || key.startsWith("comment") || key.startsWith("description")) { /* translation note: don't translate quoted words */ msg = marktr("Has key ''note'' or ''comment'' or ''description''"); code = UNTAGGED_NODE_NOTE; } else if (key.startsWith("created_by") || key.startsWith("converted_by")) { /* translation note: don't translate quoted words */ msg = marktr("Has key ''created_by'' or ''converted_by''"); code = UNTAGGED_NODE_CREATED_BY; } else if (key.startsWith("watch")) { /* translation note: don't translate quoted words */ msg = marktr("Has key ''watch''"); code = UNTAGGED_NODE_WATCH; } else if (key.startsWith("source")) { /* translation note: don't translate quoted words */ msg = marktr("Has key ''source''"); code = UNTAGGED_NODE_SOURCE; } if (msg != null) { errors.add(TestError.builder(this, Severity.WARNING, code) .message(ERROR_MESSAGE, msg) .primitives(castPrim(n)) .build()); return; } // Does not happen, but just to be sure. Maybe definition of uninteresting tags changes in future. errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_OTHER) .message(ERROR_MESSAGE, marktr("Other")) .primitives(castPrim(n)) .build()); } @Override public Command fixError(TestError testError) { return deletePrimitivesIfNeeded(testError.getPrimitives()); } @Override public boolean isFixable(TestError testError) { if (testError.getTester() instanceof UntaggedNode) { int code = testError.getCode(); switch (code) { case UNTAGGED_NODE_BLANK: case UNTAGGED_NODE_CREATED_BY: case UNTAGGED_NODE_WATCH: case UNTAGGED_NODE_SOURCE: return true; } } return false; } }