001    // License: GPL. See LICENSE file for details.
002    package org.openstreetmap.josm.data.validation.tests;
003    
004    import static org.openstreetmap.josm.tools.I18n.marktr;
005    import static org.openstreetmap.josm.tools.I18n.tr;
006    
007    import java.util.Collection;
008    import java.util.Map;
009    
010    import org.openstreetmap.josm.command.Command;
011    import org.openstreetmap.josm.data.osm.Node;
012    import org.openstreetmap.josm.data.osm.OsmPrimitive;
013    import org.openstreetmap.josm.data.validation.Severity;
014    import org.openstreetmap.josm.data.validation.Test;
015    import org.openstreetmap.josm.data.validation.TestError;
016    import org.openstreetmap.josm.gui.progress.ProgressMonitor;
017    
018    /**
019     * Checks for nodes with uninteresting tags that are in no way
020     *
021     * @author frsantos
022     */
023    public class UntaggedNode extends Test {
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    
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 startTest(ProgressMonitor monitor) {
043            super.startTest(monitor);
044        }
045    
046        @Override
047        public void visit(Collection<OsmPrimitive> selection) {
048            for (OsmPrimitive p : selection) {
049                if (p.isUsable() && p instanceof Node) {
050                    p.visit(this);
051                }
052            }
053        }
054    
055        @Override
056        public void visit(Node n) {
057            if(n.isUsable() && !n.isTagged() && n.getReferrers().isEmpty()) {
058                if (!n.hasKeys()) {
059                    String msg = marktr("No tags");
060                    errors.add(new TestError(this, Severity.WARNING, tr("Unconnected nodes without physical tags"), tr(msg), msg, UNTAGGED_NODE_BLANK, n));
061                    return;
062                }
063                for (Map.Entry<String, String> tag : n.getKeys().entrySet()) {
064                    String key = tag.getKey();
065                    if (contains(tag, "fixme") || contains(tag, "FIXME")) {
066                        /* translation note: don't translate quoted words */
067                        String msg = marktr("Has tag containing ''fixme'' or ''FIXME''");
068                        errors.add(new TestError(this, Severity.WARNING, tr("Unconnected nodes without physical tags"),
069                                tr(msg), msg, UNTAGGED_NODE_FIXME, n));
070                        return;
071                    }
072    
073                    String msg = null;
074                    int code = 0;
075                    if (key.startsWith("note") || key.startsWith("comment") || key.startsWith("description")) {
076                        /* translation note: don't translate quoted words */
077                        msg = marktr("Has key ''note'' or ''comment'' or ''description''");
078                        code = UNTAGGED_NODE_NOTE;
079                    } else if (key.startsWith("created_by") || key.startsWith("converted_by")) {
080                        /* translation note: don't translate quoted words */
081                        msg = marktr("Has key ''created_by'' or ''converted_by''");
082                        code = UNTAGGED_NODE_CREATED_BY;
083                    } else if (key.startsWith("watch")) {
084                        /* translation note: don't translate quoted words */
085                        msg = marktr("Has key ''watch''");
086                        code = UNTAGGED_NODE_WATCH;
087                    } else if (key.startsWith("source")) {
088                        /* translation note: don't translate quoted words */
089                        msg = marktr("Has key ''source''");
090                        code = UNTAGGED_NODE_SOURCE;
091                    }
092                    if (msg != null) {
093                        errors.add(new TestError(this, Severity.WARNING, tr("Unconnected nodes without physical tags"),
094                                tr(msg), msg, code, n));
095                        return;
096                    }
097                }
098                // Does not happen, but just to be sure. Maybe definition of uninteresting tags changes in future.
099                errors.add(new TestError(this, Severity.WARNING, tr("Unconnected nodes without physical tags"),
100                        tr("Other"), "Other", UNTAGGED_NODE_OTHER, n));
101            }
102        }
103    
104        private boolean contains(Map.Entry<String, String> tag, String s) {
105            return tag.getKey().indexOf(s) != -1 || tag.getValue().indexOf(s) != -1;
106        }
107    
108        @Override
109        public Command fixError(TestError testError) {
110            return deletePrimitivesIfNeeded(testError.getPrimitives());
111        }
112    
113        @Override
114        public boolean isFixable(TestError testError) {
115            if (testError.getTester() instanceof UntaggedNode) {
116                int code = testError.getCode();
117                switch (code) {
118                case UNTAGGED_NODE_BLANK:
119                case UNTAGGED_NODE_CREATED_BY:
120                case UNTAGGED_NODE_WATCH:
121                case UNTAGGED_NODE_SOURCE:
122                    return true;
123                }
124            }
125            return false;
126        }
127    }