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

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

Added DatasetListener, Dataset now fire events everytime one of its primitives is changed. Used new Dataset listener in RelationListDialog

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