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.test(n)) { 046 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_BLANK) 047 .message(ERROR_MESSAGE, marktr("No tags")) 048 .primitives(n) 049 .build()); 050 return; 051 } 052 n.visitKeys(this); 053 } 054 } 055 056 @Override 057 public void visitKeyValue(AbstractPrimitive n, String key, String value) { 058 if (key.toLowerCase(Locale.ENGLISH).contains("fixme") || value.toLowerCase(Locale.ENGLISH).contains("fixme")) { 059 /* translation note: don't translate quoted words */ 060 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_FIXME) 061 .message(ERROR_MESSAGE, marktr("Has tag containing ''fixme'' or ''FIXME''")) 062 .primitives((OsmPrimitive) n) 063 .build()); 064 return; 065 } 066 067 String msg = null; 068 int code = 0; 069 if (key.startsWith("note") || key.startsWith("comment") || key.startsWith("description")) { 070 /* translation note: don't translate quoted words */ 071 msg = marktr("Has key ''note'' or ''comment'' or ''description''"); 072 code = UNTAGGED_NODE_NOTE; 073 } else if (key.startsWith("created_by") || key.startsWith("converted_by")) { 074 /* translation note: don't translate quoted words */ 075 msg = marktr("Has key ''created_by'' or ''converted_by''"); 076 code = UNTAGGED_NODE_CREATED_BY; 077 } else if (key.startsWith("watch")) { 078 /* translation note: don't translate quoted words */ 079 msg = marktr("Has key ''watch''"); 080 code = UNTAGGED_NODE_WATCH; 081 } else if (key.startsWith("source")) { 082 /* translation note: don't translate quoted words */ 083 msg = marktr("Has key ''source''"); 084 code = UNTAGGED_NODE_SOURCE; 085 } 086 if (msg != null) { 087 errors.add(TestError.builder(this, Severity.WARNING, code) 088 .message(ERROR_MESSAGE, msg) 089 .primitives((OsmPrimitive) n) 090 .build()); 091 return; 092 } 093 // Does not happen, but just to be sure. Maybe definition of uninteresting tags changes in future. 094 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_OTHER) 095 .message(ERROR_MESSAGE, marktr("Other")) 096 .primitives((OsmPrimitive) n) 097 .build()); 098 } 099 100 @Override 101 public Command fixError(TestError testError) { 102 return deletePrimitivesIfNeeded(testError.getPrimitives()); 103 } 104 105 @Override 106 public boolean isFixable(TestError testError) { 107 if (testError.getTester() instanceof UntaggedNode) { 108 int code = testError.getCode(); 109 switch (code) { 110 case UNTAGGED_NODE_BLANK: 111 case UNTAGGED_NODE_CREATED_BY: 112 case UNTAGGED_NODE_WATCH: 113 case UNTAGGED_NODE_SOURCE: 114 return true; 115 } 116 } 117 return false; 118 } 119}