source: josm/trunk/src/org/openstreetmap/josm/data/osm/Relation.java@ 2970

Last change on this file since 2970 was 2970, checked in by jttt, 14 years ago

Throw DataIntergrityException also when Way/Relation with broken member references is added to the dataset

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1package org.openstreetmap.josm.data.osm;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
8
9import org.openstreetmap.josm.data.osm.visitor.Visitor;
10import org.openstreetmap.josm.tools.CopyList;
11
12/**
13 * An relation, having a set of tags and any number (0...n) of members.
14 *
15 * @author Frederik Ramm <frederik@remote.org>
16 */
17public final class Relation extends OsmPrimitive {
18
19 /**
20 * All members of this relation. Note that after changing this,
21 * makeBackReferences and/or removeBackReferences should be called.
22 *
23 */
24 private final List<RelationMember> members = new ArrayList<RelationMember>();
25
26 /**
27 * @return Members of the relation. Changes made in returned list are not mapped
28 * back to the primitive, use setMembers() to modify the members
29 * @since 1925
30 */
31 public List<RelationMember> getMembers() {
32 return new CopyList<RelationMember>(members.toArray(new RelationMember[members.size()]));
33 }
34
35 /**
36 *
37 * @param members Can be null, in that case all members are removed
38 * @since 1925
39 */
40 public void setMembers(List<RelationMember> members) {
41 for (RelationMember rm:this.members) {
42 rm.getMember().removeReferrer(this);
43 }
44
45 this.members.clear();
46 if (members != null) {
47 this.members.addAll(members);
48 }
49 for (RelationMember rm:this.members) {
50 rm.getMember().addReferrer(this);
51 }
52
53 fireMembersChanged();
54 }
55
56 /**
57 *
58 * @since 1926
59 */
60 public int getMembersCount() {
61 return members.size();
62 }
63
64 /**
65 *
66 * @param index
67 * @return
68 * @since 1926
69 */
70 public RelationMember getMember(int index) {
71 return members.get(index);
72 }
73
74 /**
75 *
76 * @param member
77 * @since 1951
78 */
79 public void addMember(RelationMember member) {
80 members.add(member);
81 member.getMember().addReferrer(this);
82 fireMembersChanged();
83 }
84
85 /**
86 *
87 * @param index
88 * @param member
89 * @since 1951
90 */
91 public void addMember(int index, RelationMember member) {
92 members.add(index, member);
93 member.getMember().addReferrer(this);
94 fireMembersChanged();
95 }
96
97 /**
98 * Replace member at position specified by index.
99 * @param index
100 * @param member
101 * @return Member that was at the position
102 * @since 1951
103 */
104 public RelationMember setMember(int index, RelationMember member) {
105 RelationMember result = members.set(index, member);
106 if (result.getMember() != member.getMember()) {
107 member.getMember().addReferrer(this);
108 result.getMember().removeReferrer(this);
109 fireMembersChanged();
110 }
111 return result;
112 }
113
114 /**
115 * Removes member at specified position.
116 * @param index
117 * @return Member that was at the position
118 * @since 1951
119 */
120 public RelationMember removeMember(int index) {
121 RelationMember result = members.remove(index);
122 for (RelationMember rm:members) {
123 // Do not remove referrer if this primitive is used in relation twice
124 if (rm.getMember() == result.getMember())
125 return result;
126 }
127 result.getMember().removeReferrer(this);
128 fireMembersChanged();
129 return result;
130 }
131
132 @Override public void visit(Visitor visitor) {
133 visitor.visit(this);
134 }
135
136 protected Relation(long id, boolean allowNegative) {
137 super(id, allowNegative);
138 }
139
140 /**
141 * Create a new relation with id 0
142 */
143 public Relation() {
144 super(0, false);
145 }
146
147 public Relation(Relation clone, boolean clearId) {
148 super(clone.getUniqueId(), true);
149 cloneFrom(clone);
150 if (clearId) {
151 clearOsmId();
152 }
153 }
154
155 /**
156 * Create an identical clone of the argument (including the id)
157 */
158 public Relation(Relation clone) {
159 this(clone, false);
160 }
161
162 /**
163 * Creates a new relation for the given id. If the id > 0, the way is marked
164 * as incomplete.
165 *
166 * @param id the id. > 0 required
167 * @throws IllegalArgumentException thrown if id < 0
168 */
169 public Relation(long id) throws IllegalArgumentException {
170 super(id, false);
171 }
172
173 /**
174 * Creates new relation
175 * @param id
176 * @param version
177 */
178 public Relation(long id, int version) {
179 super(id, version, false);
180 }
181
182 @Override public void cloneFrom(OsmPrimitive osm) {
183 super.cloneFrom(osm);
184 // It's not necessary to clone members as RelationMember class is immutable
185 setMembers(((Relation)osm).getMembers());
186 }
187
188 @Override public void load(PrimitiveData data) {
189 super.load(data);
190
191 RelationData relationData = (RelationData) data;
192
193 List<RelationMember> newMembers = new ArrayList<RelationMember>();
194 for (RelationMemberData member : relationData.getMembers()) {
195 OsmPrimitive primitive = getDataSet().getPrimitiveById(member);
196 if (primitive == null)
197 throw new AssertionError("Data consistency problem - relation with missing member detected");
198 newMembers.add(new RelationMember(member.getRole(), primitive));
199 }
200 setMembers(newMembers);
201 }
202
203 @Override public RelationData save() {
204 RelationData data = new RelationData();
205 saveCommonAttributes(data);
206 for (RelationMember member:getMembers()) {
207 data.getMembers().add(new RelationMemberData(member.getRole(), member.getMember()));
208 }
209 return data;
210 }
211
212 @Override public String toString() {
213 StringBuilder result = new StringBuilder();
214 result.append("{Relation id=");
215 result.append(getUniqueId());
216 result.append(" version=");
217 result.append(getVersion());
218 result.append(" ");
219 result.append(getFlagsAsString());
220 result.append(" [");
221 for (RelationMember rm:getMembers()) {
222 result.append(OsmPrimitiveType.from(rm.getMember()));
223 result.append(" ");
224 result.append(rm.getMember().getUniqueId());
225 result.append(", ");
226 }
227 result.delete(result.length()-2, result.length());
228 result.append("]");
229 result.append("}");
230 return result.toString();
231 }
232
233 @Override
234 public boolean hasEqualSemanticAttributes(OsmPrimitive other) {
235 if (other == null || ! (other instanceof Relation) )
236 return false;
237 if (! super.hasEqualSemanticAttributes(other))
238 return false;
239 Relation r = (Relation)other;
240 return members.equals(r.members);
241 }
242
243 public int compareTo(OsmPrimitive o) {
244 return o instanceof Relation ? Long.valueOf(getUniqueId()).compareTo(o.getUniqueId()) : -1;
245 }
246
247 public RelationMember firstMember() {
248 if (isIncomplete()) return null;
249 return (members.size() == 0) ? null : members.get(0);
250 }
251 public RelationMember lastMember() {
252 if (isIncomplete()) return null;
253 return (members.size() == 0) ? null : members.get(members.size() -1);
254 }
255
256 /**
257 * removes all members with member.member == primitive
258 *
259 * @param primitive the primitive to check for
260 */
261 public void removeMembersFor(OsmPrimitive primitive) {
262 if (primitive == null)
263 return;
264
265 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>();
266 for (RelationMember member: members) {
267 if (member.getMember() == primitive) {
268 todelete.add(member);
269 }
270 }
271 primitive.removeReferrer(this);
272 members.removeAll(todelete);
273 fireMembersChanged();
274 }
275
276 @Override
277 public void setDeleted(boolean deleted) {
278 for (RelationMember rm:members) {
279 if (deleted) {
280 rm.getMember().removeReferrer(this);
281 } else {
282 rm.getMember().addReferrer(this);
283 }
284 }
285 super.setDeleted(deleted);
286 }
287
288 /**
289 * removes all members with member.member == primitive
290 *
291 * @param primitives the primitives to check for
292 */
293 public void removeMembersFor(Collection<OsmPrimitive> primitives) {
294 if (primitives == null || primitives.isEmpty())
295 return;
296
297 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>();
298 for (RelationMember member: members) {
299 if (primitives.contains(member.getMember())) {
300 todelete.add(member);
301 }
302 }
303 members.removeAll(todelete);
304 for (OsmPrimitive primitive:primitives) {
305 primitive.removeReferrer(this);
306 }
307 fireMembersChanged();
308 }
309
310 @Override
311 public String getDisplayName(NameFormatter formatter) {
312 return formatter.format(this);
313 }
314
315 /**
316 * Replies the set of {@see OsmPrimitive}s referred to by at least one
317 * member of this relation
318 *
319 * @return the set of {@see OsmPrimitive}s referred to by at least one
320 * member of this relation
321 */
322 public Set<OsmPrimitive> getMemberPrimitives() {
323 HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
324 for (RelationMember m: members) {
325 if (m.getMember() != null) {
326 ret.add(m.getMember());
327 }
328 }
329 return ret;
330 }
331
332 public OsmPrimitiveType getType() {
333 return OsmPrimitiveType.RELATION;
334 }
335
336 @Override
337 public BBox getBBox() {
338 return new BBox(0, 0, 0, 0);
339 }
340
341 @Override
342 public void updatePosition() {
343 // Do nothing for now
344 }
345
346 @Override
347 public void setDataset(DataSet dataSet) {
348 super.setDataset(dataSet);
349 checkMembers();
350 }
351
352 private void checkMembers() {
353 DataSet dataSet = getDataSet();
354 if (dataSet != null) {
355 for (RelationMember rm: members) {
356 if (rm.getMember().getDataSet() != dataSet)
357 throw new DataIntegrityProblemException("Relation member must be part of the same dataset as relation");
358 }
359 }
360 }
361
362 private void fireMembersChanged() {
363 checkMembers();
364 if (getDataSet() != null) {
365 getDataSet().fireRelationMembersChanged(this);
366 }
367 }
368}
Note: See TracBrowser for help on using the repository browser.