001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.osm; 003 004import java.util.Collection; 005import java.util.Date; 006import java.util.HashMap; 007import java.util.Map; 008 009import org.openstreetmap.josm.data.Bounds; 010import org.openstreetmap.josm.data.coor.LatLon; 011import 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 */ 018public 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(0); 051 } 052 053 /** 054 * Creates a changeset with id <code>id</code>. If id > 0, sets incomplete to true. 055 * 056 * @param id the id 057 */ 058 public Changeset(int id) { 059 this.id = id; 060 this.incomplete = id > 0; 061 this.tags = new HashMap<String, String>(); 062 } 063 064 /** 065 * Creates a clone of <code>other</code> 066 * 067 * @param other the other changeset. If null, creates a new changeset with id 0. 068 */ 069 public Changeset(Changeset other) { 070 if (other == null) { 071 this.id = 0; 072 this.tags = new HashMap<String, String>(); 073 } else if (other.isIncomplete()) { 074 setId(other.getId()); 075 this.incomplete = true; 076 this.tags = new HashMap<String, String>(); 077 } else { 078 this.id = other.id; 079 mergeFrom(other); 080 this.incomplete = false; 081 } 082 } 083 084 public void visit(Visitor v) { 085 v.visit(this); 086 } 087 088 public int compareTo(Changeset other) { 089 return Integer.valueOf(getId()).compareTo(other.getId()); 090 } 091 092 public String getName() { 093 // no translation 094 return "changeset " + getId(); 095 } 096 097 public String getDisplayName(NameFormatter formatter) { 098 return formatter.format(this); 099 } 100 101 public int getId() { 102 return id; 103 } 104 105 public void setId(int id) { 106 this.id = id; 107 } 108 109 public User getUser() { 110 return user; 111 } 112 113 public void setUser(User user) { 114 this.user = user; 115 } 116 117 public Date getCreatedAt() { 118 return createdAt; 119 } 120 121 public void setCreatedAt(Date createdAt) { 122 this.createdAt = createdAt; 123 } 124 125 public Date getClosedAt() { 126 return closedAt; 127 } 128 129 public void setClosedAt(Date closedAt) { 130 this.closedAt = closedAt; 131 } 132 133 public boolean isOpen() { 134 return open; 135 } 136 137 public void setOpen(boolean open) { 138 this.open = open; 139 } 140 141 public LatLon getMin() { 142 return min; 143 } 144 145 public void setMin(LatLon min) { 146 this.min = min; 147 } 148 149 public LatLon getMax() { 150 return max; 151 } 152 153 public Bounds getBounds() { 154 if (min != null && max != null) 155 return new Bounds(min,max); 156 return null; 157 } 158 159 public void setMax(LatLon max) { 160 this.max = max; 161 } 162 163 @Override 164 public Map<String, String> getKeys() { 165 return tags; 166 } 167 168 @Override 169 public void setKeys(Map<String, String> keys) { 170 this.tags = keys; 171 } 172 173 public boolean isIncomplete() { 174 return incomplete; 175 } 176 177 public void setIncomplete(boolean incomplete) { 178 this.incomplete = incomplete; 179 } 180 181 @Override 182 public void put(String key, String value) { 183 this.tags.put(key, value); 184 } 185 186 @Override 187 public String get(String key) { 188 return this.tags.get(key); 189 } 190 191 @Override 192 public void remove(String key) { 193 this.tags.remove(key); 194 } 195 196 @Override 197 public void removeAll() { 198 this.tags.clear(); 199 } 200 201 public boolean hasEqualSemanticAttributes(Changeset other) { 202 if (other == null) 203 return false; 204 if (closedAt == null) { 205 if (other.closedAt != null) 206 return false; 207 } else if (!closedAt.equals(other.closedAt)) 208 return false; 209 if (createdAt == null) { 210 if (other.createdAt != null) 211 return false; 212 } else if (!createdAt.equals(other.createdAt)) 213 return false; 214 if (id != other.id) 215 return false; 216 if (max == null) { 217 if (other.max != null) 218 return false; 219 } else if (!max.equals(other.max)) 220 return false; 221 if (min == null) { 222 if (other.min != null) 223 return false; 224 } else if (!min.equals(other.min)) 225 return false; 226 if (open != other.open) 227 return false; 228 if (tags == null) { 229 if (other.tags != null) 230 return false; 231 } else if (!tags.equals(other.tags)) 232 return false; 233 if (user == null) { 234 if (other.user != null) 235 return false; 236 } else if (!user.equals(other.user)) 237 return false; 238 return true; 239 } 240 241 @Override 242 public int hashCode() { 243 if (id > 0) 244 return id; 245 else 246 return super.hashCode(); 247 } 248 249 @Override 250 public boolean equals(Object obj) { 251 if (this == obj) 252 return true; 253 if (obj == null) 254 return false; 255 if (getClass() != obj.getClass()) 256 return false; 257 Changeset other = (Changeset) obj; 258 if (this.id > 0 && other.id == this.id) 259 return true; 260 return this == obj; 261 } 262 263 @Override 264 public boolean hasKeys() { 265 return !tags.keySet().isEmpty(); 266 } 267 268 @Override 269 public Collection<String> keySet() { 270 return tags.keySet(); 271 } 272 273 public boolean isNew() { 274 return id <= 0; 275 } 276 277 public void mergeFrom(Changeset other) { 278 if (other == null) 279 return; 280 if (id != other.id) 281 return; 282 this.user = other.user; 283 this.createdAt = other.createdAt; 284 this.closedAt = other.closedAt; 285 this.open = other.open; 286 this.min = other.min; 287 this.max = other.max; 288 this.tags = new HashMap<String, String>(other.tags); 289 this.incomplete = other.incomplete; 290 291 // FIXME: merging of content required? 292 this.content = other.content; 293 } 294 295 public boolean hasContent() { 296 return content != null; 297 } 298 299 public ChangesetDataSet getContent() { 300 return content; 301 } 302 303 public void setContent(ChangesetDataSet content) { 304 this.content = content; 305 } 306}