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