source: josm/trunk/src/org/openstreetmap/josm/data/osm/Changeset.java@ 11587

Last change on this file since 11587 was 11332, checked in by Don-vip, 7 years ago

javadoc

  • Property svn:eol-style set to native
File size: 13.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm;
3
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.Date;
8import java.util.HashMap;
9import java.util.List;
10import java.util.Map;
11import java.util.Objects;
12
13import org.openstreetmap.josm.data.Bounds;
14import org.openstreetmap.josm.data.coor.LatLon;
15import org.openstreetmap.josm.data.osm.visitor.Visitor;
16import org.openstreetmap.josm.tools.CheckParameterUtil;
17
18/**
19 * Represents a single changeset in JOSM. For now its only used during
20 * upload but in the future we may do more.
21 * @since 625
22 */
23public final class Changeset implements Tagged {
24
25 /** The maximum changeset tag length allowed by API 0.6 **/
26 public static final int MAX_CHANGESET_TAG_LENGTH = 255;
27
28 /** the changeset id */
29 private int id;
30 /** the user who owns the changeset */
31 private User user;
32 /** date this changeset was created at */
33 private Date createdAt;
34 /** the date this changeset was closed at*/
35 private Date closedAt;
36 /** indicates whether this changeset is still open or not */
37 private boolean open;
38 /** the min. coordinates of the bounding box of this changeset */
39 private LatLon min;
40 /** the max. coordinates of the bounding box of this changeset */
41 private LatLon max;
42 /** the number of comments for this changeset */
43 private int commentsCount;
44 /** the map of tags */
45 private Map<String, String> tags;
46 /** indicates whether this changeset is incomplete. For an incomplete changeset we only know its id */
47 private boolean incomplete;
48 /** the changeset content */
49 private ChangesetDataSet content;
50 /** the changeset discussion */
51 private List<ChangesetDiscussionComment> discussion;
52
53 /**
54 * Creates a new changeset with id 0.
55 */
56 public Changeset() {
57 this(0);
58 }
59
60 /**
61 * Creates a changeset with id <code>id</code>. If id &gt; 0, sets incomplete to true.
62 *
63 * @param id the id
64 */
65 public Changeset(int id) {
66 this.id = id;
67 this.incomplete = id > 0;
68 this.tags = new HashMap<>();
69 }
70
71 /**
72 * Creates a clone of <code>other</code>
73 *
74 * @param other the other changeset. If null, creates a new changeset with id 0.
75 */
76 public Changeset(Changeset other) {
77 if (other == null) {
78 this.id = 0;
79 this.tags = new HashMap<>();
80 } else if (other.isIncomplete()) {
81 setId(other.getId());
82 this.incomplete = true;
83 this.tags = new HashMap<>();
84 } else {
85 this.id = other.id;
86 mergeFrom(other);
87 this.incomplete = false;
88 }
89 }
90
91 /**
92 * Creates a changeset with the data obtained from the given preset, i.e.,
93 * the {@link AbstractPrimitive#getChangesetId() changeset id}, {@link AbstractPrimitive#getUser() user}, and
94 * {@link AbstractPrimitive#getTimestamp() timestamp}.
95 * @param primitive the primitive to use
96 * @return the created changeset
97 */
98 public static Changeset fromPrimitive(final OsmPrimitive primitive) {
99 final Changeset changeset = new Changeset(primitive.getChangesetId());
100 changeset.setUser(primitive.getUser());
101 changeset.setCreatedAt(primitive.getTimestamp()); // not accurate in all cases
102 return changeset;
103 }
104
105 /**
106 * Visitor pattern.
107 * @param v visitor
108 */
109 public void visit(Visitor v) {
110 v.visit(this);
111 }
112
113 /**
114 * Compares this changeset to another, based on their identifier.
115 * @param other other changeset
116 * @return the value {@code 0} if {@code getId() == other.getId()};
117 * a value less than {@code 0} if {@code getId() < other.getId()}; and
118 * a value greater than {@code 0} if {@code getId() > other.getId()}
119 */
120 public int compareTo(Changeset other) {
121 return Integer.compare(getId(), other.getId());
122 }
123
124 /**
125 * Returns the changeset name.
126 * @return the changeset name (untranslated: "changeset &lt;identifier&gt;")
127 */
128 public String getName() {
129 // no translation
130 return "changeset " + getId();
131 }
132
133 /**
134 * Returns the changeset display name, as per given name formatter.
135 * @param formatter name formatter
136 * @return the changeset display name, as per given name formatter
137 */
138 public String getDisplayName(NameFormatter formatter) {
139 return formatter.format(this);
140 }
141
142 /**
143 * Returns the changeset identifier.
144 * @return the changeset identifier
145 */
146 public int getId() {
147 return id;
148 }
149
150 /**
151 * Sets the changeset identifier.
152 * @param id changeset identifier
153 */
154 public void setId(int id) {
155 this.id = id;
156 }
157
158 /**
159 * Returns the changeset user.
160 * @return the changeset user
161 */
162 public User getUser() {
163 return user;
164 }
165
166 /**
167 * Sets the changeset user.
168 * @param user changeset user
169 */
170 public void setUser(User user) {
171 this.user = user;
172 }
173
174 /**
175 * Returns the changeset creation date.
176 * @return the changeset creation date
177 */
178 public Date getCreatedAt() {
179 return createdAt;
180 }
181
182 /**
183 * Sets the changeset creation date.
184 * @param createdAt changeset creation date
185 */
186 public void setCreatedAt(Date createdAt) {
187 this.createdAt = createdAt;
188 }
189
190 /**
191 * Returns the changeset closure date.
192 * @return the changeset closure date
193 */
194 public Date getClosedAt() {
195 return closedAt;
196 }
197
198 /**
199 * Sets the changeset closure date.
200 * @param closedAt changeset closure date
201 */
202 public void setClosedAt(Date closedAt) {
203 this.closedAt = closedAt;
204 }
205
206 /**
207 * Determines if this changeset is open.
208 * @return {@code true} if this changeset is open
209 */
210 public boolean isOpen() {
211 return open;
212 }
213
214 /**
215 * Sets whether this changeset is open.
216 * @param open {@code true} if this changeset is open
217 */
218 public void setOpen(boolean open) {
219 this.open = open;
220 }
221
222 /**
223 * Returns the min lat/lon of the changeset bounding box.
224 * @return the min lat/lon of the changeset bounding box
225 */
226 public LatLon getMin() {
227 return min;
228 }
229
230 /**
231 * Sets the min lat/lon of the changeset bounding box.
232 * @param min min lat/lon of the changeset bounding box
233 */
234 public void setMin(LatLon min) {
235 this.min = min;
236 }
237
238 /**
239 * Returns the max lat/lon of the changeset bounding box.
240 * @return the max lat/lon of the changeset bounding box
241 */
242 public LatLon getMax() {
243 return max;
244 }
245
246 /**
247 * Sets the max lat/lon of the changeset bounding box.
248 * @param max min lat/lon of the changeset bounding box
249 */
250 public void setMax(LatLon max) {
251 this.max = max;
252 }
253
254 /**
255 * Returns the changeset bounding box.
256 * @return the changeset bounding box
257 */
258 public Bounds getBounds() {
259 if (min != null && max != null)
260 return new Bounds(min, max);
261 return null;
262 }
263
264 /**
265 * Replies the number of comments for this changeset.
266 * @return the number of comments for this changeset
267 * @since 7700
268 */
269 public int getCommentsCount() {
270 return commentsCount;
271 }
272
273 /**
274 * Sets the number of comments for this changeset.
275 * @param commentsCount the number of comments for this changeset
276 * @since 7700
277 */
278 public void setCommentsCount(int commentsCount) {
279 this.commentsCount = commentsCount;
280 }
281
282 @Override
283 public Map<String, String> getKeys() {
284 return tags;
285 }
286
287 @Override
288 public void setKeys(Map<String, String> keys) {
289 CheckParameterUtil.ensureParameterNotNull(keys, "keys");
290 keys.values().stream()
291 .filter(value -> value != null && value.length() > MAX_CHANGESET_TAG_LENGTH)
292 .findFirst()
293 .ifPresent(value -> {
294 throw new IllegalArgumentException("Changeset tag value is too long: "+value);
295 });
296 this.tags = keys;
297 }
298
299 /**
300 * Determines if this changeset is incomplete.
301 * @return {@code true} if this changeset is incomplete
302 */
303 public boolean isIncomplete() {
304 return incomplete;
305 }
306
307 /**
308 * Sets whether this changeset is incomplete
309 * @param incomplete {@code true} if this changeset is incomplete
310 */
311 public void setIncomplete(boolean incomplete) {
312 this.incomplete = incomplete;
313 }
314
315 @Override
316 public void put(String key, String value) {
317 CheckParameterUtil.ensureParameterNotNull(key, "key");
318 if (value != null && value.length() > MAX_CHANGESET_TAG_LENGTH) {
319 throw new IllegalArgumentException("Changeset tag value is too long: "+value);
320 }
321 this.tags.put(key, value);
322 }
323
324 @Override
325 public String get(String key) {
326 return this.tags.get(key);
327 }
328
329 @Override
330 public void remove(String key) {
331 this.tags.remove(key);
332 }
333
334 @Override
335 public void removeAll() {
336 this.tags.clear();
337 }
338
339 /**
340 * Determines if this changeset has equals semantic attributes with another one.
341 * @param other other changeset
342 * @return {@code true} if this changeset has equals semantic attributes with other changeset
343 */
344 public boolean hasEqualSemanticAttributes(Changeset other) {
345 if (other == null)
346 return false;
347 if (closedAt == null) {
348 if (other.closedAt != null)
349 return false;
350 } else if (!closedAt.equals(other.closedAt))
351 return false;
352 if (createdAt == null) {
353 if (other.createdAt != null)
354 return false;
355 } else if (!createdAt.equals(other.createdAt))
356 return false;
357 if (id != other.id)
358 return false;
359 if (max == null) {
360 if (other.max != null)
361 return false;
362 } else if (!max.equals(other.max))
363 return false;
364 if (min == null) {
365 if (other.min != null)
366 return false;
367 } else if (!min.equals(other.min))
368 return false;
369 if (open != other.open)
370 return false;
371 if (tags == null) {
372 if (other.tags != null)
373 return false;
374 } else if (!tags.equals(other.tags))
375 return false;
376 if (user == null) {
377 if (other.user != null)
378 return false;
379 } else if (!user.equals(other.user))
380 return false;
381 if (commentsCount != other.commentsCount) {
382 return false;
383 }
384 return true;
385 }
386
387 @Override
388 public int hashCode() {
389 return Objects.hash(id);
390 }
391
392 @Override
393 public boolean equals(Object obj) {
394 if (this == obj) return true;
395 if (obj == null || getClass() != obj.getClass()) return false;
396 Changeset changeset = (Changeset) obj;
397 return id == changeset.id;
398 }
399
400 @Override
401 public boolean hasKeys() {
402 return !tags.keySet().isEmpty();
403 }
404
405 @Override
406 public Collection<String> keySet() {
407 return tags.keySet();
408 }
409
410 /**
411 * Determines if this changeset is new.
412 * @return {@code true} if this changeset is new ({@code id <= 0})
413 */
414 public boolean isNew() {
415 return id <= 0;
416 }
417
418 /**
419 * Merges changeset metadata from another changeset.
420 * @param other other changeset
421 */
422 public void mergeFrom(Changeset other) {
423 if (other == null)
424 return;
425 if (id != other.id)
426 return;
427 this.user = other.user;
428 this.createdAt = other.createdAt;
429 this.closedAt = other.closedAt;
430 this.open = other.open;
431 this.min = other.min;
432 this.max = other.max;
433 this.commentsCount = other.commentsCount;
434 this.tags = new HashMap<>(other.tags);
435 this.incomplete = other.incomplete;
436 this.discussion = other.discussion != null ? new ArrayList<>(other.discussion) : null;
437
438 // FIXME: merging of content required?
439 this.content = other.content;
440 }
441
442 /**
443 * Determines if this changeset has contents.
444 * @return {@code true} if this changeset has contents
445 */
446 public boolean hasContent() {
447 return content != null;
448 }
449
450 /**
451 * Returns the changeset contents.
452 * @return the changeset contents, can be null
453 */
454 public ChangesetDataSet getContent() {
455 return content;
456 }
457
458 /**
459 * Sets the changeset contents.
460 * @param content changeset contents, can be null
461 */
462 public void setContent(ChangesetDataSet content) {
463 this.content = content;
464 }
465
466 /**
467 * Replies the list of comments in the changeset discussion, if any.
468 * @return the list of comments in the changeset discussion. May be empty but never null
469 * @since 7704
470 */
471 public synchronized List<ChangesetDiscussionComment> getDiscussion() {
472 if (discussion == null) {
473 return Collections.emptyList();
474 }
475 return new ArrayList<>(discussion);
476 }
477
478 /**
479 * Adds a comment to the changeset discussion.
480 * @param comment the comment to add. Ignored if null
481 * @since 7704
482 */
483 public synchronized void addDiscussionComment(ChangesetDiscussionComment comment) {
484 if (comment == null) {
485 return;
486 }
487 if (discussion == null) {
488 discussion = new ArrayList<>();
489 }
490 discussion.add(comment);
491 }
492}
Note: See TracBrowser for help on using the repository browser.