001 // License: GPL. Copyright 2007 by Martijn van Oosterhout and others
002 package org.openstreetmap.josm.data.osm;
003
004 import java.util.Collection;
005 import java.util.Date;
006 import java.util.HashMap;
007 import java.util.Map;
008
009 import org.openstreetmap.josm.data.Bounds;
010 import org.openstreetmap.josm.data.coor.LatLon;
011 import org.openstreetmap.josm.data.osm.visitor.Visitor;
012
013 /**
014 * Represents a single changeset in JOSM. For now its only used during
015 * upload but in the future we may do more.
016 *
017 */
018 public final class Changeset implements Tagged {
019
020 /** The maximum changeset comment text length allowed by API 0.6 **/
021 public static final int MAX_COMMENT_LENGTH = 255;
022
023 /** the changeset id */
024 private int id;
025 /** the user who owns the changeset */
026 private User user;
027 /** date this changeset was created at */
028 private Date createdAt;
029 /** the date this changeset was closed at*/
030 private Date closedAt;
031 /** indicates whether this changeset is still open or not */
032 private boolean open;
033 /** the min. coordinates of the bounding box of this changeset */
034 private LatLon min;
035 /** the max. coordinates of the bounding box of this changeset */
036 private LatLon max;
037 /** the map of tags */
038 private Map<String,String> tags;
039 /** indicates whether this changeset is incomplete. For an
040 * incomplete changeset we only know its id
041 */
042 private boolean incomplete;
043 /** the changeset content */
044 private ChangesetDataSet content = null;
045
046 /**
047 * Creates a new changeset with id 0.
048 */
049 public Changeset() {
050 this.id = 0;
051 this.tags = new HashMap<String, String>();
052 }
053
054 /**
055 * Creates a changeset with id <code>id</code>. If id > 0, sets incomplete to true.
056 *
057 * @param id the id
058 */
059 public Changeset(int id) {
060 this.id = id;
061 this.incomplete = id > 0;
062 this.tags = new HashMap<String, String>();
063 }
064
065 /**
066 * Creates a clone of <code>other</code>
067 *
068 * @param other the other changeset. If null, creates a new changeset with id 0.
069 */
070 public Changeset(Changeset other) {
071 if (other == null) {
072 this.id = 0;
073 this.tags = new HashMap<String, String>();
074 } else if (other.isIncomplete()) {
075 setId(other.getId());
076 this.incomplete = true;
077 this.tags = new HashMap<String, String>();
078 } else {
079 this.id = other.id;
080 mergeFrom(other);
081 this.incomplete = false;
082 }
083 }
084
085 public void visit(Visitor v) {
086 v.visit(this);
087 }
088
089 public int compareTo(Changeset other) {
090 return Integer.valueOf(getId()).compareTo(other.getId());
091 }
092
093 public String getName() {
094 // no translation
095 return "changeset " + getId();
096 }
097
098 public String getDisplayName(NameFormatter formatter) {
099 return formatter.format(this);
100 }
101
102 public int getId() {
103 return id;
104 }
105
106 public void setId(int id) {
107 this.id = id;
108 }
109
110 public User getUser() {
111 return user;
112 }
113
114 public void setUser(User user) {
115 this.user = user;
116 }
117
118 public Date getCreatedAt() {
119 return createdAt;
120 }
121
122 public void setCreatedAt(Date createdAt) {
123 this.createdAt = createdAt;
124 }
125
126 public Date getClosedAt() {
127 return closedAt;
128 }
129
130 public void setClosedAt(Date closedAt) {
131 this.closedAt = closedAt;
132 }
133
134 public boolean isOpen() {
135 return open;
136 }
137
138 public void setOpen(boolean open) {
139 this.open = open;
140 }
141
142 public LatLon getMin() {
143 return min;
144 }
145
146 public void setMin(LatLon min) {
147 this.min = min;
148 }
149
150 public LatLon getMax() {
151 return max;
152 }
153
154 public Bounds getBounds() {
155 if (min != null && max != null)
156 return new Bounds(min,max);
157 return null;
158 }
159
160 public void setMax(LatLon max) {
161 this.max = max;
162 }
163
164 public Map<String, String> getKeys() {
165 return tags;
166 }
167
168 public void setKeys(Map<String, String> keys) {
169 this.tags = keys;
170 }
171
172 public boolean isIncomplete() {
173 return incomplete;
174 }
175
176 public void setIncomplete(boolean incomplete) {
177 this.incomplete = incomplete;
178 }
179
180 public void put(String key, String value) {
181 this.tags.put(key, value);
182 }
183
184 public String get(String key) {
185 return this.tags.get(key);
186 }
187
188 public void remove(String key) {
189 this.tags.remove(key);
190 }
191
192 public void removeAll() {
193 this.tags.clear();
194 }
195
196 public boolean hasEqualSemanticAttributes(Changeset other) {
197 if (other == null)
198 return false;
199 if (closedAt == null) {
200 if (other.closedAt != null)
201 return false;
202 } else if (!closedAt.equals(other.closedAt))
203 return false;
204 if (createdAt == null) {
205 if (other.createdAt != null)
206 return false;
207 } else if (!createdAt.equals(other.createdAt))
208 return false;
209 if (id != other.id)
210 return false;
211 if (max == null) {
212 if (other.max != null)
213 return false;
214 } else if (!max.equals(other.max))
215 return false;
216 if (min == null) {
217 if (other.min != null)
218 return false;
219 } else if (!min.equals(other.min))
220 return false;
221 if (open != other.open)
222 return false;
223 if (tags == null) {
224 if (other.tags != null)
225 return false;
226 } else if (!tags.equals(other.tags))
227 return false;
228 if (user == null) {
229 if (other.user != null)
230 return false;
231 } else if (!user.equals(other.user))
232 return false;
233 return true;
234 }
235
236 @Override
237 public int hashCode() {
238 if (id > 0)
239 return id;
240 else
241 return super.hashCode();
242 }
243
244 @Override
245 public boolean equals(Object obj) {
246 if (this == obj)
247 return true;
248 if (obj == null)
249 return false;
250 if (getClass() != obj.getClass())
251 return false;
252 Changeset other = (Changeset) obj;
253 if (this.id > 0 && other.id == this.id)
254 return true;
255 return this == obj;
256 }
257
258 public boolean hasKeys() {
259 return !tags.keySet().isEmpty();
260 }
261
262 public Collection<String> keySet() {
263 return tags.keySet();
264 }
265
266 public boolean isNew() {
267 return id <= 0;
268 }
269
270 public void mergeFrom(Changeset other) {
271 if (other == null)
272 return;
273 if (id != other.id)
274 return;
275 this.user = other.user;
276 this.createdAt = other.createdAt;
277 this.closedAt = other.closedAt;
278 this.open = other.open;
279 this.min = other.min;
280 this.max = other.max;
281 this.tags = new HashMap<String, String>(other.tags);
282 this.incomplete = other.incomplete;
283
284 // FIXME: merging of content required?
285 this.content = other.content;
286 }
287
288 public boolean hasContent() {
289 return content != null;
290 }
291
292 public ChangesetDataSet getContent() {
293 return content;
294 }
295
296 public void setContent(ChangesetDataSet content) {
297 this.content = content;
298 }
299 }