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

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

sonar - squid:S1126 - Return of boolean expressions should not be wrapped into an "if-then-else" statement

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