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