source: josm/trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java@ 1924

Last change on this file since 1924 was 1924, checked in by jttt, 15 years ago

Made OsmPrimitive.keys deprecated, removed remaining references in JOSM

  • Property svn:eol-style set to native
File size: 12.6 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data.osm;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.Date;
11import java.util.HashMap;
12import java.util.Map;
13import java.util.Map.Entry;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.data.osm.visitor.Visitor;
17import org.openstreetmap.josm.gui.mappaint.ElemStyle;
18
19
20/**
21 * An OSM primitive can be associated with a key/value pair. It can be created, deleted
22 * and updated within the OSM-Server.
23 *
24 * Although OsmPrimitive is designed as a base class, it is not to be meant to subclass
25 * it by any other than from the package {@link org.openstreetmap.josm.data.osm}. The available primitives are a fixed set that are given
26 * by the server environment and not an extendible data stuff.
27 *
28 * @author imi
29 */
30abstract public class OsmPrimitive implements Comparable<OsmPrimitive> {
31
32 /* mappaint data */
33 public ElemStyle mappaintStyle = null;
34 public Integer mappaintVisibleCode = 0;
35 public Integer mappaintDrawnCode = 0;
36 public Collection<String> errors;
37
38 public void putError(String text, Boolean isError)
39 {
40 if(errors == null) {
41 errors = new ArrayList<String>();
42 }
43 String s = isError ? tr("Error: {0}", text) : tr("Warning: {0}", text);
44 errors.add(s);
45 }
46 public void clearErrors()
47 {
48 errors = null;
49 }
50 /* This should not be called from outside. Fixing the UI to add relevant
51 get/set functions calling this implicitely is preferred, so we can have
52 transparent cache handling in the future. */
53 protected void clearCached()
54 {
55 mappaintVisibleCode = 0;
56 mappaintDrawnCode = 0;
57 mappaintStyle = null;
58 }
59 /* end of mappaint data */
60
61 /**
62 * Unique identifier in OSM. This is used to identify objects on the server.
63 * An id of 0 means an unknown id. The object has not been uploaded yet to
64 * know what id it will get.
65 *
66 * Do not write to this attribute except you know exactly what you are doing.
67 * More specific, it is not good to set this to 0 and think the object is now
68 * new to the server! To create a new object, call the default constructor of
69 * the respective class.
70 */
71 public long id = 0;
72
73 /**
74 * <code>true</code> if the object has been modified since it was loaded from
75 * the server. In this case, on next upload, this object will be updated.
76 * Deleted objects are deleted from the server. If the objects are added (id=0),
77 * the modified is ignored and the object is added to the server.
78 */
79 public boolean modified = false;
80
81 /**
82 * <code>true</code>, if the object has been deleted.
83 */
84 public boolean deleted = false;
85
86 /**
87 * Visibility status as specified by the server. The visible attribute was
88 * introduced with the 0.4 API to be able to communicate deleted objects
89 * (they will have visible=false).
90 */
91 public boolean visible = true;
92
93 /**
94 * User that last modified this primitive, as specified by the server.
95 * Never changed by JOSM.
96 */
97 public User user = null;
98
99 /**
100 * If set to true, this object is currently selected.
101 */
102 @Deprecated
103 public volatile boolean selected = false;
104
105 /**
106 *
107 * @since 1899
108 */
109 public void setSelected(boolean selected) {
110 this.selected = selected;
111 }
112 /**
113 *
114 * @since 1899
115 */
116 public boolean isSelected() {
117 return selected;
118 }
119
120 /**
121 * If set to true, this object is highlighted. Currently this is only used to
122 * show which ways/nodes will connect
123 */
124 public volatile boolean highlighted = false;
125
126 private int timestamp;
127
128 public void setTimestamp(Date timestamp) {
129 this.timestamp = (int)(timestamp.getTime() / 1000);
130 }
131
132 /**
133 * Time of last modification to this object. This is not set by JOSM but
134 * read from the server and delivered back to the server unmodified. It is
135 * used to check against edit conflicts.
136 *
137 */
138 public Date getTimestamp() {
139 return new Date(timestamp * 1000l);
140 }
141
142 public boolean isTimestampEmpty() {
143 return timestamp == 0;
144 }
145
146 /**
147 * If set to true, this object is incomplete, which means only the id
148 * and type is known (type is the objects instance class)
149 */
150 public boolean incomplete = false;
151
152 /**
153 * Contains the version number as returned by the API. Needed to
154 * ensure update consistency
155 */
156 public int version = -1;
157
158 private static Collection<String> uninteresting = null;
159 /**
160 * Contains a list of "uninteresting" keys that do not make an object
161 * "tagged".
162 * Initialized by checkTagged()
163 */
164 public static Collection<String> getUninterestingKeys() {
165 if (uninteresting == null) {
166 uninteresting = Main.pref.getCollection("tags.uninteresting",
167 Arrays.asList(new String[]{"source","note","comment","converted_by","created_by"}));
168 }
169 return uninteresting;
170 }
171
172
173 private static Collection<String> directionKeys = null;
174
175 /**
176 * Contains a list of direction-dependent keys that make an object
177 * direction dependent.
178 * Initialized by checkDirectionTagged()
179 */
180 public static Collection<String> getDirectionKeys() {
181 if(directionKeys == null) {
182 directionKeys = Main.pref.getCollection("tags.direction",
183 Arrays.asList(new String[]{"oneway","incline","incline_steep","aerialway"}));
184 }
185 return directionKeys;
186 }
187
188 /**
189 * Implementation of the visitor scheme. Subclasses have to call the correct
190 * visitor function.
191 * @param visitor The visitor from which the visit() function must be called.
192 */
193 abstract public void visit(Visitor visitor);
194
195 public final void delete(boolean deleted) {
196 this.deleted = deleted;
197 setSelected(false);
198 modified = true;
199 }
200
201 /**
202 * Equal, if the id (and class) is equal.
203 *
204 * An primitive is equal to its incomplete counter part.
205 */
206 @Override public boolean equals(Object obj) {
207 if (id == 0) return obj == this;
208 if (obj instanceof OsmPrimitive)
209 return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass();
210 return false;
211 }
212
213 /**
214 * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0.
215 *
216 * An primitive has the same hashcode as its incomplete counterpart.
217 */
218 @Override public final int hashCode() {
219 if (id == 0)
220 return super.hashCode();
221 final int[] ret = new int[1];
222 Visitor v = new Visitor(){
223 public void visit(Node n) { ret[0] = 0; }
224 public void visit(Way w) { ret[0] = 1; }
225 public void visit(Relation e) { ret[0] = 2; }
226 public void visit(Changeset cs) { ret[0] = 3; }
227 };
228 visit(v);
229 return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0];
230 }
231
232 /*------------
233 * Keys handling
234 ------------*/
235
236 /**
237 * The key/value list for this primitive.
238 * @deprecated This field will became private or protected in future, use api instead
239 */
240 @Deprecated
241 public Map<String, String> keys;
242
243 /**
244 *
245 * @return Keys of this primitive. Changes made in returned map are not mapped
246 * back to the primitive, use setKeys() to modify the keys
247 * @since 1924
248 */
249 public Map<String, String> getKeys() {
250 // TODO More effective map
251 return new HashMap<String, String>(keys);
252 }
253
254 /**
255 *
256 * @since 1924
257 */
258 public void setKeys(Map<String, String> keys) {
259 if (keys == null) {
260 this.keys = null;
261 } else {
262 this.keys = new HashMap<String, String>(keys);
263 }
264 }
265
266 /**
267 * Set the given value to the given key
268 * @param key The key, for which the value is to be set.
269 * @param value The value for the key.
270 */
271 public final void put(String key, String value) {
272 if (value == null) {
273 remove(key);
274 } else {
275 if (keys == null) {
276 keys = new HashMap<String, String>();
277 }
278 keys.put(key, value);
279 }
280 mappaintStyle = null;
281 }
282 /**
283 * Remove the given key from the list.
284 */
285 public final void remove(String key) {
286 if (keys != null) {
287 keys.remove(key);
288 if (keys.isEmpty()) {
289 keys = null;
290 }
291 }
292 mappaintStyle = null;
293 }
294
295 /**
296 *
297 * @since 1843
298 */
299 public final void removeAll() {
300 keys = null;
301 mappaintStyle = null;
302 }
303
304 public final String get(String key) {
305 return keys == null ? null : keys.get(key);
306 }
307
308 public final Collection<Entry<String, String>> entrySet() {
309 if (keys == null)
310 return Collections.emptyList();
311 return keys.entrySet();
312 }
313
314 public final Collection<String> keySet() {
315 if (keys == null)
316 return Collections.emptyList();
317 return keys.keySet();
318 }
319
320 /**
321 *
322 * @since 1843
323 */
324 public final boolean hasKeys() {
325 return keys != null && !keys.isEmpty();
326 }
327
328
329
330
331
332
333 public String getName() {
334 return null;
335 }
336
337 /**
338 * Get and write all attributes from the parameter. Does not fire any listener, so
339 * use this only in the data initializing phase
340 */
341 public void cloneFrom(OsmPrimitive osm) {
342 keys = osm.keys == null ? null : new HashMap<String, String>(osm.keys);
343 id = osm.id;
344 modified = osm.modified;
345 deleted = osm.deleted;
346 setSelected(osm.isSelected());
347 timestamp = osm.timestamp;
348 version = osm.version;
349 incomplete = osm.incomplete;
350 visible = osm.visible;
351 clearCached();
352 clearErrors();
353 }
354
355 /**
356 * Replies true if this primitive and other are equal with respect to their
357 * semantic attributes.
358 * <ol>
359 * <li>equal id</ol>
360 * <li>both are complete or both are incomplete</li>
361 * <li>both have the same tags</li>
362 * </ol>
363 * @param other
364 * @return true if this primitive and other are equal with respect to their
365 * semantic attributes.
366 */
367 public boolean hasEqualSemanticAttributes(OsmPrimitive other) {
368 if (id != other.id)
369 return false;
370 if (incomplete && ! other.incomplete || !incomplete && other.incomplete)
371 return false;
372 return (keys == null ? other.keys==null : keys.equals(other.keys));
373 }
374
375 /**
376 * Replies true if this primitive and other are equal with respect to their
377 * technical attributes. The attributes:
378 * <ol>
379 * <li>deleted</ol>
380 * <li>modified</ol>
381 * <li>timestamp</ol>
382 * <li>version</ol>
383 * <li>visible</ol>
384 * <li>user</ol>
385 * </ol>
386 * have to be equal
387 * @param other the other primitive
388 * @return true if this primitive and other are equal with respect to their
389 * technical attributes
390 */
391 public boolean hasEqualTechnicalAttributes(OsmPrimitive other) {
392 if (other == null) return false;
393
394 return
395 deleted == other.deleted
396 && modified == other.modified
397 && timestamp == other.timestamp
398 && version == other.version
399 && visible == other.visible
400 && (user == null ? other.user==null : user==other.user);
401 }
402
403 /**
404 * true if this object is considered "tagged". To be "tagged", an object
405 * must have one or more "interesting" tags. "created_by" and "source"
406 * are typically considered "uninteresting" and do not make an object
407 * "tagged".
408 */
409 public boolean isTagged() {
410 // TODO Cache value after keys are made private
411 getUninterestingKeys();
412 if (keys != null) {
413 for (Entry<String,String> e : keys.entrySet()) {
414 if (!uninteresting.contains(e.getKey()))
415 return true;
416 }
417 }
418 return false;
419 }
420 /**
421 * true if this object has direction dependent tags (e.g. oneway)
422 */
423 public boolean hasDirectionKeys() {
424 // TODO Cache value after keys are made private
425 getDirectionKeys();
426 if (keys != null) {
427 for (Entry<String,String> e : keys.entrySet()) {
428 if (directionKeys.contains(e.getKey()))
429 return true;
430 }
431 }
432 return false;
433 }
434}
Note: See TracBrowser for help on using the repository browser.