// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.graphview.plugin.data; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.RelationMember; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.plugins.graphview.core.data.DataSource; import org.openstreetmap.josm.plugins.graphview.core.data.DataSourceObserver; import org.openstreetmap.josm.plugins.graphview.core.data.MapBasedTagGroup; import org.openstreetmap.josm.plugins.graphview.core.data.TagGroup; /** * DataSource that gets data from JOSM; * this DataSource type does not send updates! */ public class JOSMDataSource implements DataSource<Node, Way, Relation, RelationMember> { @Override public double getLat(Node node) { return node.getCoor().lat(); } @Override public double getLon(Node node) { return node.getCoor().lon(); } @Override public Iterable<RelationMember> getMembers(Relation relation) { return relation.getMembers(); } @Override public Iterable<Node> getNodes(Way way) { return new FilteredOsmPrimitiveIterable<>(way.getNodes()); } @Override public Iterable<Node> getNodes() { return new FilteredOsmPrimitiveIterable<>(Main.getLayerManager().getEditDataSet().getNodes()); } @Override public Iterable<Relation> getRelations() { return new FilteredRelationIterable(Main.getLayerManager().getEditDataSet().getRelations()); } @Override public Iterable<Way> getWays() { return new FilteredOsmPrimitiveIterable<>(Main.getLayerManager().getEditDataSet().getWays()); } @Override public TagGroup getTagsN(Node node) { return getTags(node); } @Override public TagGroup getTagsW(Way way) { return getTags(way); } @Override public TagGroup getTagsR(Relation relation) { return getTags(relation); } private TagGroup getTags(OsmPrimitive primitive) { if (primitive.getKeys() == null) { return EMPTY_TAG_GROUP; } else { return new MapBasedTagGroup(primitive.getKeys()); } } @Override public Object getMember(RelationMember member) { return member.getMember(); } @Override public String getRole(RelationMember member) { return member.getRole(); } @Override public boolean isNMember(RelationMember member) { return member.getMember() instanceof Node; } @Override public boolean isWMember(RelationMember member) { return member.getMember() instanceof Way; } @Override public boolean isRMember(RelationMember member) { return member.getMember() instanceof Relation; } private static final TagGroup EMPTY_TAG_GROUP; static { Map<String, String> emptyMap = new HashMap<>(0); EMPTY_TAG_GROUP = new MapBasedTagGroup(emptyMap); } /** * Iterable of OsmPrimitive objects based on an existing Iterable, * will filter incomplete and deleted objects from the iterator. * * @param <P> OsmPrimitive subtype */ public static class FilteredOsmPrimitiveIterable<P extends OsmPrimitive> implements Iterable<P> { private final Iterable<P> originalIterable; public FilteredOsmPrimitiveIterable(Iterable<P> originalIterable) { this.originalIterable = originalIterable; } /** returns an iterator. The iterator does not support {@link Iterator#remove()}. */ @Override public Iterator<P> iterator() { return new FilteredIterator(originalIterable.iterator()); } private class FilteredIterator implements Iterator<P> { private final Iterator<P> originalIterator; private P next; FilteredIterator(Iterator<P> originalIterator) { this.originalIterator = originalIterator; updateNext(); } @Override public boolean hasNext() { return next != null; } @Override public P next() { if (next != null) { P result = next; updateNext(); return result; } else { throw new NoSuchElementException(); } } @Override public void remove() { throw new UnsupportedOperationException(); } private void updateNext() { next = null; while (originalIterator.hasNext()) { P originalNext = originalIterator.next(); if (accept(originalNext)) { next = originalNext; break; } } } } protected boolean accept(P primitive) { return !primitive.isDeleted() && !primitive.isIncomplete(); } } /** * Relation-specific variant of the FilteredOsmPrimitiveIterable, * also checks completeness of relation's members */ public static class FilteredRelationIterable extends FilteredOsmPrimitiveIterable<Relation> { public FilteredRelationIterable(Iterable<Relation> originalIterable) { super(originalIterable); } @Override protected boolean accept(Relation relation) { boolean complete = true; for (org.openstreetmap.josm.data.osm.RelationMember member : relation.getMembers()) { if (member.getMember() == null || member.getMember().isDeleted() || member.getMember().isIncomplete()) { complete = false; } } return complete && super.accept(relation); } } static class RelationMemberImpl { private final String role; private final Object member; RelationMemberImpl(org.openstreetmap.josm.data.osm.RelationMember originalMember) { this.role = originalMember.getRole(); this.member = originalMember.getMember(); } public String getRole() { return role; } public Object getMember() { return member; } } private final Set<DataSourceObserver> observers = new HashSet<>(); @Override public void addObserver(DataSourceObserver observer) { observers.add(observer); } @Override public void deleteObserver(DataSourceObserver observer) { observers.remove(observer); } }