001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005import static org.openstreetmap.josm.tools.I18n.trn;
006
007import java.util.List;
008
009import org.openstreetmap.josm.Main;
010import org.openstreetmap.josm.data.conflict.Conflict;
011import org.openstreetmap.josm.data.coor.EastNorth;
012import org.openstreetmap.josm.data.osm.BBox;
013import org.openstreetmap.josm.data.osm.Node;
014import org.openstreetmap.josm.data.osm.OsmPrimitive;
015import org.openstreetmap.josm.data.osm.Relation;
016import org.openstreetmap.josm.data.osm.RelationMember;
017import org.openstreetmap.josm.data.osm.Way;
018import org.openstreetmap.josm.gui.layer.OsmDataLayer;
019import org.openstreetmap.josm.tools.Geometry;
020import org.openstreetmap.josm.tools.date.DateUtils;
021
022/**
023 * Textual representation of primitive contents, used in {@code InspectPrimitiveDialog}.
024 * @since 10198
025 */
026public class InspectPrimitiveDataText {
027    private static final String INDENT = "  ";
028    private static final char NL = '\n';
029
030    private final StringBuilder s = new StringBuilder();
031    private final OsmDataLayer layer;
032
033    InspectPrimitiveDataText(OsmDataLayer layer) {
034        this.layer = layer;
035    }
036
037    private InspectPrimitiveDataText add(String title, String... values) {
038        s.append(INDENT).append(title);
039        for (String v : values) {
040            s.append(v);
041        }
042        s.append(NL);
043        return this;
044    }
045
046    private static String getNameAndId(String name, long id) {
047        if (name != null) {
048            return name + tr(" ({0})", /* sic to avoid thousand seperators */ Long.toString(id));
049        } else {
050            return Long.toString(id);
051        }
052    }
053
054    /**
055     * Adds a new OSM primitive.
056     * @param o primitive to add
057     */
058    public void addPrimitive(OsmPrimitive o) {
059
060        addHeadline(o);
061
062        if (!(o.getDataSet() != null && o.getDataSet().getPrimitiveById(o) != null)) {
063            s.append(NL).append(INDENT).append(tr("not in data set")).append(NL);
064            return;
065        }
066        if (o.isIncomplete()) {
067            s.append(NL).append(INDENT).append(tr("incomplete")).append(NL);
068            return;
069        }
070        s.append(NL);
071
072        addState(o);
073        addCommon(o);
074        addAttributes(o);
075        addSpecial(o);
076        addReferrers(s, o);
077        addConflicts(o);
078        s.append(NL);
079    }
080
081    void addHeadline(OsmPrimitive o) {
082        addType(o);
083        addNameAndId(o);
084    }
085
086    void addType(OsmPrimitive o) {
087        if (o instanceof Node) {
088            s.append(tr("Node: "));
089        } else if (o instanceof Way) {
090            s.append(tr("Way: "));
091        } else if (o instanceof Relation) {
092            s.append(tr("Relation: "));
093        }
094    }
095
096    void addNameAndId(OsmPrimitive o) {
097        String name = o.get("name");
098        if (name == null) {
099            s.append(o.getUniqueId());
100        } else {
101            s.append(getNameAndId(name, o.getUniqueId()));
102        }
103    }
104
105    void addState(OsmPrimitive o) {
106        StringBuilder sb = new StringBuilder(INDENT);
107        /* selected state is left out: not interesting as it is always selected */
108        if (o.isDeleted()) {
109            sb.append(tr("deleted")).append(INDENT);
110        }
111        if (!o.isVisible()) {
112            sb.append(tr("deleted-on-server")).append(INDENT);
113        }
114        if (o.isModified()) {
115            sb.append(tr("modified")).append(INDENT);
116        }
117        if (o.isDisabledAndHidden()) {
118            sb.append(tr("filtered/hidden")).append(INDENT);
119        }
120        if (o.isDisabled()) {
121            sb.append(tr("filtered/disabled")).append(INDENT);
122        }
123        if (o.hasDirectionKeys()) {
124            if (o.reversedDirection()) {
125                sb.append(tr("has direction keys (reversed)")).append(INDENT);
126            } else {
127                sb.append(tr("has direction keys")).append(INDENT);
128            }
129        }
130        String state = sb.toString().trim();
131        if (!state.isEmpty()) {
132            add(tr("State: "), sb.toString().trim());
133        }
134    }
135
136    void addCommon(OsmPrimitive o) {
137        add(tr("Data Set: "), Integer.toHexString(o.getDataSet().hashCode()));
138        add(tr("Edited at: "), o.isTimestampEmpty() ? tr("<new object>")
139                : DateUtils.fromTimestamp(o.getRawTimestamp()));
140        add(tr("Edited by: "), o.getUser() == null ? tr("<new object>")
141                : getNameAndId(o.getUser().getName(), o.getUser().getId()));
142        add(tr("Version: "), Integer.toString(o.getVersion()));
143        add(tr("In changeset: "), Integer.toString(o.getChangesetId()));
144    }
145
146    void addAttributes(OsmPrimitive o) {
147        if (o.hasKeys()) {
148            add(tr("Tags: "));
149            for (String key : o.keySet()) {
150                s.append(INDENT).append(INDENT);
151                s.append(String.format("\"%s\"=\"%s\"%n", key, o.get(key)));
152            }
153        }
154    }
155
156    void addSpecial(OsmPrimitive o) {
157        if (o instanceof Node) {
158            addCoordinates((Node) o);
159        } else if (o instanceof Way) {
160            addBbox(o);
161            add(tr("Centroid: "), Main.getProjection().eastNorth2latlon(
162                    Geometry.getCentroid(((Way) o).getNodes())).toStringCSV(", "));
163            addWayNodes((Way) o);
164        } else if (o instanceof Relation) {
165            addBbox(o);
166            addRelationMembers((Relation) o);
167        }
168    }
169
170    void addRelationMembers(Relation r) {
171        add(trn("{0} Member: ", "{0} Members: ", r.getMembersCount(), r.getMembersCount()));
172        for (RelationMember m : r.getMembers()) {
173            s.append(INDENT).append(INDENT);
174            addHeadline(m.getMember());
175            s.append(tr(" as \"{0}\"", m.getRole()));
176            s.append(NL);
177        }
178    }
179
180    void addWayNodes(Way w) {
181        add(tr("{0} Nodes: ", w.getNodesCount()));
182        for (Node n : w.getNodes()) {
183            s.append(INDENT).append(INDENT);
184            addNameAndId(n);
185            s.append(NL);
186        }
187    }
188
189    void addBbox(OsmPrimitive o) {
190        BBox bbox = o.getBBox();
191        if (bbox != null) {
192            add(tr("Bounding box: "), bbox.toStringCSV(", "));
193            EastNorth bottomRigth = Main.getProjection().latlon2eastNorth(bbox.getBottomRight());
194            EastNorth topLeft = Main.getProjection().latlon2eastNorth(bbox.getTopLeft());
195            add(tr("Bounding box (projected): "),
196                    Double.toString(topLeft.east()), ", ",
197                    Double.toString(bottomRigth.north()), ", ",
198                    Double.toString(bottomRigth.east()), ", ",
199                    Double.toString(topLeft.north()));
200            add(tr("Center of bounding box: "), bbox.getCenter().toStringCSV(", "));
201        }
202    }
203
204    void addCoordinates(Node n) {
205        if (n.getCoor() != null) {
206            add(tr("Coordinates: "),
207                    Double.toString(n.getCoor().lat()), ", ",
208                    Double.toString(n.getCoor().lon()));
209            add(tr("Coordinates (projected): "),
210                    Double.toString(n.getEastNorth().east()), ", ",
211                    Double.toString(n.getEastNorth().north()));
212        }
213    }
214
215    void addReferrers(StringBuilder s, OsmPrimitive o) {
216        List<OsmPrimitive> refs = o.getReferrers();
217        if (!refs.isEmpty()) {
218            add(tr("Part of: "));
219            for (OsmPrimitive p : refs) {
220                s.append(INDENT).append(INDENT);
221                addHeadline(p);
222                s.append(NL);
223            }
224        }
225    }
226
227    void addConflicts(OsmPrimitive o) {
228        Conflict<?> c = layer.getConflicts().getConflictForMy(o);
229        if (c != null) {
230            add(tr("In conflict with: "));
231            addNameAndId(c.getTheir());
232        }
233    }
234
235    @Override
236    public String toString() {
237        return s.toString();
238    }
239}