001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.marktr; 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.util.Locale; 008 009import org.openstreetmap.josm.command.Command; 010import org.openstreetmap.josm.data.osm.AbstractPrimitive; 011import org.openstreetmap.josm.data.osm.Node; 012import org.openstreetmap.josm.data.osm.OsmPrimitive; 013import org.openstreetmap.josm.data.validation.Severity; 014import org.openstreetmap.josm.data.validation.Test; 015import org.openstreetmap.josm.data.validation.TestError; 016 017/** 018 * Checks for nodes with uninteresting tags that are in no way 019 * 020 * @author frsantos 021 */ 022public class UntaggedNode extends Test implements AbstractPrimitive.KeyValueVisitor { 023 024 protected static final int UNTAGGED_NODE_BLANK = 201; 025 protected static final int UNTAGGED_NODE_FIXME = 202; 026 protected static final int UNTAGGED_NODE_NOTE = 203; 027 protected static final int UNTAGGED_NODE_CREATED_BY = 204; 028 protected static final int UNTAGGED_NODE_WATCH = 205; 029 protected static final int UNTAGGED_NODE_SOURCE = 206; 030 protected static final int UNTAGGED_NODE_OTHER = 207; 031 protected static final String ERROR_MESSAGE = tr("Unconnected nodes without physical tags"); 032 033 /** 034 * Constructor 035 */ 036 public UntaggedNode() { 037 super(tr("Untagged and unconnected nodes"), 038 tr("This test checks for untagged nodes that are not part of any way.")); 039 } 040 041 @Override 042 public void visit(Node n) { 043 if (n.isUsable() && !n.isTagged() && n.getReferrers().isEmpty()) { 044 045 if (!n.hasKeys() && IN_DOWNLOADED_AREA.evaluate(n)) { 046 String msg = marktr("No tags"); 047 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr(msg), msg, UNTAGGED_NODE_BLANK, n)); 048 return; 049 } 050 n.visitKeys(this); 051 } 052 } 053 054 @Override 055 public void visitKeyValue(AbstractPrimitive n, String key, String value) { 056 if (key.toLowerCase(Locale.ENGLISH).contains("fixme") || value.toLowerCase(Locale.ENGLISH).contains("fixme")) { 057 /* translation note: don't translate quoted words */ 058 String msg = marktr("Has tag containing ''fixme'' or ''FIXME''"); 059 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr(msg), msg, UNTAGGED_NODE_FIXME, (OsmPrimitive) n)); 060 return; 061 } 062 063 String msg = null; 064 int code = 0; 065 if (key.startsWith("note") || key.startsWith("comment") || key.startsWith("description")) { 066 /* translation note: don't translate quoted words */ 067 msg = marktr("Has key ''note'' or ''comment'' or ''description''"); 068 code = UNTAGGED_NODE_NOTE; 069 } else if (key.startsWith("created_by") || key.startsWith("converted_by")) { 070 /* translation note: don't translate quoted words */ 071 msg = marktr("Has key ''created_by'' or ''converted_by''"); 072 code = UNTAGGED_NODE_CREATED_BY; 073 } else if (key.startsWith("watch")) { 074 /* translation note: don't translate quoted words */ 075 msg = marktr("Has key ''watch''"); 076 code = UNTAGGED_NODE_WATCH; 077 } else if (key.startsWith("source")) { 078 /* translation note: don't translate quoted words */ 079 msg = marktr("Has key ''source''"); 080 code = UNTAGGED_NODE_SOURCE; 081 } 082 if (msg != null) { 083 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr(msg), msg, code, (OsmPrimitive) n)); 084 return; 085 } 086 // Does not happen, but just to be sure. Maybe definition of uninteresting tags changes in future. 087 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr("Other"), "Other", UNTAGGED_NODE_OTHER, (OsmPrimitive) n)); 088 } 089 090 @Override 091 public Command fixError(TestError testError) { 092 return deletePrimitivesIfNeeded(testError.getPrimitives()); 093 } 094 095 @Override 096 public boolean isFixable(TestError testError) { 097 if (testError.getTester() instanceof UntaggedNode) { 098 int code = testError.getCode(); 099 switch (code) { 100 case UNTAGGED_NODE_BLANK: 101 case UNTAGGED_NODE_CREATED_BY: 102 case UNTAGGED_NODE_WATCH: 103 case UNTAGGED_NODE_SOURCE: 104 return true; 105 } 106 } 107 return false; 108 } 109}