source: osm/applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelation.java

Last change on this file was 36213, checked in by GerdP, 22 months ago

fix #23515: IllegalArgumentException in Relation Toolbox after undo

  • add check if relation is still in dataset
  • fix some sonarlimt / checkstyle issues
  • Property svn:eol-style set to native
File size: 8.2 KB
RevLine 
[32395]1// License: GPL. For details, see LICENSE file.
[25649]2package relcontext;
3
[32395]4import java.awt.AlphaComposite;
5import java.awt.BasicStroke;
6import java.awt.Color;
7import java.awt.Composite;
8import java.awt.Graphics2D;
9import java.awt.Point;
10import java.awt.Stroke;
[25649]11import java.awt.geom.GeneralPath;
[32395]12import java.util.HashSet;
[36102]13import java.util.Objects;
[32395]14import java.util.Set;
15
[25649]16import org.openstreetmap.josm.data.Bounds;
[32395]17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.data.osm.Relation;
20import org.openstreetmap.josm.data.osm.Way;
21import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
22import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
23import org.openstreetmap.josm.data.osm.event.DataSetListener;
24import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
25import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
26import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
27import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
28import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
29import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
[33530]30import org.openstreetmap.josm.gui.MainApplication;
[25649]31import org.openstreetmap.josm.gui.MapView;
[32395]32import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
33import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
[25649]34import org.openstreetmap.josm.gui.layer.MapViewPaintable;
35import org.openstreetmap.josm.gui.layer.OsmDataLayer;
36
37/**
38 * Chosen relation; is used for all actions and is highlighted on the map.
39 *
40 * @author Zverik
41 */
[32395]42public class ChosenRelation implements ActiveLayerChangeListener, MapViewPaintable, DataSetListener {
[36213]43 protected Relation chosenRelation;
[36102]44 private final Set<ChosenRelationListener> chosenRelationListeners = new HashSet<>();
[25649]45
[32395]46 public void set(Relation rel) {
[36102]47 if (Objects.equals(rel, chosenRelation))
[25649]48 return; // new is the same as old
49 Relation oldRel = chosenRelation;
50 chosenRelation = rel;
51 analyse();
[33530]52 MainApplication.getMap().mapView.repaint();
[25669]53 fireRelationChanged(oldRel);
54 }
55
[32395]56 protected void fireRelationChanged(Relation oldRel) {
57 for (ChosenRelationListener listener : chosenRelationListeners) {
[25649]58 listener.chosenRelationChanged(oldRel, chosenRelation);
[32395]59 }
[25649]60 }
61
62 public Relation get() {
63 return chosenRelation;
64 }
65
66 public void clear() {
67 set(null);
68 }
[25748]69
[32395]70 public boolean isSame(Object r) {
[32398]71 if (r == null)
[25748]72 return chosenRelation == null;
[32398]73 else if (!(r instanceof Relation))
[25748]74 return false;
75 else
[36102]76 return r.equals(chosenRelation);
[25748]77 }
[32395]78
79 private static final String[] MULTIPOLYGON_TYPES = new String[] {
80 "multipolygon", "boundary"
[25671]81 };
[25649]82
[25671]83 /**
84 * Check if the relation type assumes all ways inside it form a multipolygon.
[34130]85 * @return true if the relation type assumes all ways inside it form a multipolygon
[25671]86 */
87 public boolean isMultipolygon() {
[25751]88 return isMultipolygon(chosenRelation);
89 }
90
[32395]91 public static boolean isMultipolygon(Relation r) {
[32398]92 if (r == null)
[25671]93 return false;
[25751]94 String type = r.get("type");
[32398]95 if (type == null)
[25671]96 return false;
[32398]97 for (String t : MULTIPOLYGON_TYPES) {
98 if (t.equals(type))
[25671]99 return true;
[32398]100 }
[25671]101 return false;
102 }
103
[25649]104 public int getSegmentsCount() {
105 return 0;
106 }
107
108 public int getCirclesCount() {
109 return 0;
110 }
111
[25711]112 protected void analyse() {
[25649]113 // todo
114 }
115
[32395]116 public void addChosenRelationListener(ChosenRelationListener listener) {
[25649]117 chosenRelationListeners.add(listener);
118 }
119
[32395]120 public void removeChosenRelationListener(ChosenRelationListener listener) {
[25649]121 chosenRelationListeners.remove(listener);
122 }
123
[32395]124 @Override
125 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
[25649]126 // todo: dim chosen relation when changing layer
127 // todo: check this WTF!
[33530]128 OsmDataLayer newLayer = MainApplication.getLayerManager().getEditLayer();
[25692]129 clear();
[34087]130 if (newLayer != null && e.getPreviousDataLayer() == null) {
[33530]131 MainApplication.getMap().mapView.addTemporaryLayer(this);
[32395]132 } else if (newLayer == null) {
[33530]133 MainApplication.getMap().mapView.removeTemporaryLayer(this);
[25649]134 }
135 }
136
[32395]137 @Override
138 public void paint(Graphics2D g, MapView mv, Bounds bbox) {
139 if (chosenRelation == null)
[25649]140 return;
141
[32398]142 OsmDataLayer dataLayer = mv.getLayerManager().getEditLayer();
143 float opacity = dataLayer == null ? 0.0f : !dataLayer.isVisible() ? 0.0f : (float) dataLayer.getOpacity();
144 if (opacity < 0.01)
[26290]145 return;
[32395]146
[28693]147 Composite oldComposite = g.getComposite();
[25669]148 Stroke oldStroke = g.getStroke();
[28693]149 g.setStroke(new BasicStroke(9, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
[25649]150 g.setColor(Color.yellow);
[26290]151 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f * opacity));
[32395]152
[36102]153 drawRelations(g, mv, bbox, chosenRelation, new HashSet<>());
[32395]154
[28693]155 g.setComposite(oldComposite);
156 g.setStroke(oldStroke);
157 }
[32395]158
[33265]159 private void drawRelations(Graphics2D g, MapView mv, Bounds bbox, Relation rel, Set<Relation> visitedRelations) {
160 if (!visitedRelations.contains(rel)) {
161 visitedRelations.add(rel);
162 for (OsmPrimitive element : rel.getMemberPrimitives()) {
[33530]163 if (null != element.getType()) {
[36213]164 switch (element.getType()) {
[33311]165 case NODE:
166 Node node = (Node) element;
167 Point center = mv.getPoint(node);
168 g.drawOval(center.x - 4, center.y - 4, 9, 9);
169 break;
170 case WAY:
171 Way way = (Way) element;
172 if (way.getNodesCount() >= 2) {
173 GeneralPath b = new GeneralPath();
174 Point p = mv.getPoint(way.getNode(0));
175 b.moveTo(p.x, p.y);
176 for (int i = 1; i < way.getNodesCount(); i++) {
177 p = mv.getPoint(way.getNode(i));
178 b.lineTo(p.x, p.y);
179 }
180 g.draw(b);
[36102]181 }
182 break;
[33311]183 case RELATION:
184 Color oldColor = g.getColor();
185 g.setColor(Color.magenta);
186 drawRelations(g, mv, bbox, (Relation) element, visitedRelations);
187 g.setColor(oldColor);
188 break;
189 default:
190 break;
[33530]191 }
[25649]192 }
193 }
194 }
195 }
[25669]196
[32395]197 @Override
198 public void relationMembersChanged(RelationMembersChangedEvent event) {
[36102]199 if (event.getRelation().equals(chosenRelation)) {
[25669]200 fireRelationChanged(chosenRelation);
[32395]201 }
[25669]202 }
[32395]203
204 @Override
205 public void tagsChanged(TagsChangedEvent event) {
[36102]206 if (event.getPrimitive().equals(chosenRelation)) {
[25669]207 fireRelationChanged(chosenRelation);
[32395]208 }
[25669]209 }
210
[32395]211 @Override
212 public void dataChanged(DataChangedEvent event) {
[32398]213 if (chosenRelation != null) {
[36213]214 if (chosenRelation.getDataSet() == null)
215 clear();
216 else
217 fireRelationChanged(chosenRelation);
[32395]218 }
[25669]219 }
220
[32395]221 @Override
222 public void primitivesRemoved(PrimitivesRemovedEvent event) {
[32398]223 if (chosenRelation != null && event.getPrimitives().contains(chosenRelation)) {
[25671]224 clear();
[32395]225 }
[25671]226 }
227
[32395]228 @Override
229 public void wayNodesChanged(WayNodesChangedEvent event) {
[32398]230 if (chosenRelation != null) {
[25673]231 fireRelationChanged(chosenRelation); // download incomplete primitives doesn't cause dataChanged event
[32395]232 }
[25673]233 }
234
[32395]235 @Override
236 public void primitivesAdded(PrimitivesAddedEvent event) {}
[32398]237
[32395]238 @Override
239 public void nodeMoved(NodeMovedEvent event) {}
[32398]240
[32395]241 @Override
242 public void otherDatasetChange(AbstractDatasetChangedEvent event) {}
[25649]243}
Note: See TracBrowser for help on using the repository browser.