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

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

Added support for referrers

  • Property svn:eol-style set to native
File size: 9.1 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 }
54
55 /**
56 *
57 * @since 1926
58 */
59 public int getMembersCount() {
60 return members.size();
61 }
62
63 /**
64 *
65 * @param index
66 * @return
67 * @since 1926
68 */
69 public RelationMember getMember(int index) {
70 return members.get(index);
71 }
72
73 /**
74 *
75 * @param member
76 * @since 1951
77 */
78 public void addMember(RelationMember member) {
79 members.add(member);
80 member.getMember().addReferrer(this);
81 }
82
83 /**
84 *
85 * @param index
86 * @param member
87 * @since 1951
88 */
89 public void addMember(int index, RelationMember member) {
90 members.add(index, member);
91 member.getMember().addReferrer(this);
92 }
93
94 /**
95 * Replace member at position specified by index.
96 * @param index
97 * @param member
98 * @return Member that was at the position
99 * @since 1951
100 */
101 public RelationMember setMember(int index, RelationMember member) {
102 RelationMember result = members.set(index, member);
103 if (result.getMember() != member.getMember()) {
104 member.getMember().addReferrer(this);
105 result.getMember().removeReferrer(this);
106 }
107 return result;
108 }
109
110 /**
111 * Removes member at specified position.
112 * @param index
113 * @return Member that was at the position
114 * @since 1951
115 */
116 public RelationMember removeMember(int index) {
117 RelationMember result = members.remove(index);
118 for (RelationMember rm:members) {
119 // Do not remove referrer if this primitive is used in relation twice
120 if (rm.getMember() == result.getMember())
121 return result;
122 }
123 result.getMember().removeReferrer(this);
124 return result;
125 }
126
127 @Override public void visit(Visitor visitor) {
128 visitor.visit(this);
129 }
130
131 protected Relation(long id, boolean allowNegative) {
132 super(id, allowNegative);
133 }
134
135 /**
136 * Create a new relation with id 0
137 */
138 public Relation() {
139 super(0, false);
140 }
141
142 /**
143 * Create an identical clone of the argument (including the id)
144 */
145 public Relation(Relation clone) {
146 super(clone.getUniqueId(), true);
147 cloneFrom(clone);
148 }
149
150 /**
151 * Creates a new relation for the given id. If the id > 0, the way is marked
152 * as incomplete.
153 *
154 * @param id the id. > 0 required
155 * @throws IllegalArgumentException thrown if id < 0
156 */
157 public Relation(long id) throws IllegalArgumentException {
158 super(id, false);
159 }
160
161 @Override public void cloneFrom(OsmPrimitive osm) {
162 super.cloneFrom(osm);
163 // It's not necessary to clone members as RelationMember class is immutable
164 setMembers(((Relation)osm).getMembers());
165 }
166
167 @Override public void load(PrimitiveData data) {
168 super.load(data);
169
170 RelationData relationData = (RelationData) data;
171
172 List<RelationMember> newMembers = new ArrayList<RelationMember>();
173 for (RelationMemberData member : relationData.getMembers()) {
174 OsmPrimitive primitive = getDataSet().getPrimitiveById(member);
175 if (primitive == null)
176 throw new AssertionError("Data consistency problem - relation with missing member detected");
177 newMembers.add(new RelationMember(member.getRole(), primitive));
178 }
179 setMembers(newMembers);
180 }
181
182 @Override public RelationData save() {
183 RelationData data = new RelationData();
184 saveCommonAttributes(data);
185 for (RelationMember member:getMembers()) {
186 data.getMembers().add(new RelationMemberData(member.getRole(), member.getMember()));
187 }
188 return data;
189 }
190
191 @Override public String toString() {
192 StringBuilder result = new StringBuilder();
193 result.append("{Relation id=");
194 result.append(getUniqueId());
195 result.append(" version=");
196 result.append(getVersion());
197 result.append(" [");
198 for (RelationMember rm:getMembers()) {
199 result.append(OsmPrimitiveType.from(rm.getMember()));
200 result.append(" ");
201 result.append(rm.getMember().getUniqueId());
202 result.append(", ");
203 }
204 result.delete(result.length()-2, result.length());
205 result.append("]");
206 result.append("}");
207 return result.toString();
208 }
209
210 @Override
211 public boolean hasEqualSemanticAttributes(OsmPrimitive other) {
212 if (other == null || ! (other instanceof Relation) )
213 return false;
214 if (! super.hasEqualSemanticAttributes(other))
215 return false;
216 Relation r = (Relation)other;
217 return members.equals(r.members);
218 }
219
220 public int compareTo(OsmPrimitive o) {
221 return o instanceof Relation ? Long.valueOf(getId()).compareTo(o.getId()) : -1;
222 }
223
224 // seems to be different from member "incomplete" - FIXME
225 public boolean isIncomplete() {
226 for (RelationMember m : members)
227 if (m.getMember() == null)
228 return true;
229 return false;
230 }
231
232 public RelationMember firstMember() {
233 if (incomplete) return null;
234 return (members.size() == 0) ? null : members.get(0);
235 }
236 public RelationMember lastMember() {
237 if (incomplete) return null;
238 return (members.size() == 0) ? null : members.get(members.size() -1);
239 }
240
241 /**
242 * removes all members with member.member == primitive
243 *
244 * @param primitive the primitive to check for
245 */
246 public void removeMembersFor(OsmPrimitive primitive) {
247 if (primitive == null)
248 return;
249
250 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>();
251 for (RelationMember member: members) {
252 if (member.getMember() == primitive) {
253 todelete.add(member);
254 }
255 }
256 primitive.removeReferrer(this);
257 members.removeAll(todelete);
258 }
259
260 @Override
261 public void setDeleted(boolean deleted) {
262 for (RelationMember rm:members) {
263 if (deleted) {
264 rm.getMember().removeReferrer(this);
265 } else {
266 rm.getMember().addReferrer(this);
267 }
268 }
269 super.setDeleted(deleted);
270 }
271
272
273 /**
274 * removes all members with member.member == primitive
275 *
276 * @param primitives the primitives to check for
277 */
278 public void removeMembersFor(Collection<OsmPrimitive> primitives) {
279 if (primitives == null || primitives.isEmpty())
280 return;
281
282 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>();
283 for (RelationMember member: members) {
284 if (primitives.contains(member.getMember())) {
285 todelete.add(member);
286 }
287 }
288 members.removeAll(todelete);
289 for (OsmPrimitive primitive:primitives) {
290 primitive.removeReferrer(this);
291 }
292 }
293
294 @Override
295 public String getDisplayName(NameFormatter formatter) {
296 return formatter.format(this);
297 }
298
299 /**
300 * Replies the set of {@see OsmPrimitive}s referred to by at least one
301 * member of this relation
302 *
303 * @return the set of {@see OsmPrimitive}s referred to by at least one
304 * member of this relation
305 */
306 public Set<OsmPrimitive> getMemberPrimitives() {
307 HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
308 for (RelationMember m: members) {
309 if (m.getMember() != null) {
310 ret.add(m.getMember());
311 }
312 }
313 return ret;
314 }
315
316 public OsmPrimitiveType getType() {
317 return OsmPrimitiveType.RELATION;
318 }
319}
Note: See TracBrowser for help on using the repository browser.