source: josm/trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java@ 13014

Last change on this file since 13014 was 12809, checked in by bastiK, 7 years ago

replace abstract class AbstractVisitor by interface OsmPrimitiveVisitor; deprecate Visitor

  • data.osm.visitor.Visitor awkwardly mixes OsmPrimitive types and Changeset class; this may have been used in the past, but is no longer needed; AbstractVisitor should have been a super-interface of Visitor in the first place
  • hopefully, this is binary compatible and plugins can be updated gracefully
  • Property svn:eol-style set to native
File size: 26.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.history;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.HashSet;
7import java.util.Set;
8
9import javax.swing.JTable;
10import javax.swing.table.TableModel;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.data.UserIdentityManager;
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
17import org.openstreetmap.josm.data.osm.Relation;
18import org.openstreetmap.josm.data.osm.RelationMember;
19import org.openstreetmap.josm.data.osm.RelationMemberData;
20import org.openstreetmap.josm.data.osm.User;
21import org.openstreetmap.josm.data.osm.UserInfo;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
24import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
25import org.openstreetmap.josm.data.osm.event.DataSetListener;
26import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
27import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
28import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
29import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
30import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
31import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
32import org.openstreetmap.josm.data.osm.history.History;
33import org.openstreetmap.josm.data.osm.history.HistoryNode;
34import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
35import org.openstreetmap.josm.data.osm.history.HistoryRelation;
36import org.openstreetmap.josm.data.osm.history.HistoryWay;
37import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
38import org.openstreetmap.josm.gui.MainApplication;
39import org.openstreetmap.josm.gui.layer.Layer;
40import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
41import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
42import org.openstreetmap.josm.gui.layer.OsmDataLayer;
43import org.openstreetmap.josm.gui.util.ChangeNotifier;
44import org.openstreetmap.josm.tools.CheckParameterUtil;
45import org.openstreetmap.josm.tools.Logging;
46
47/**
48 * This is the model used by the history browser.
49 *
50 * The model state consists of the following elements:
51 * <ul>
52 * <li>the {@link History} of a specific {@link OsmPrimitive}</li>
53 * <li>a dedicated version in this {@link History} called the {@link PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
54 * <li>another version in this {@link History} called the {@link PointInTimeType#CURRENT_POINT_IN_TIME}</li>
55 * </ul>
56 * {@link HistoryBrowser} always compares the {@link PointInTimeType#REFERENCE_POINT_IN_TIME} with the
57 * {@link PointInTimeType#CURRENT_POINT_IN_TIME}.
58
59 * This model provides various {@link TableModel}s for {@link JTable}s used in {@link HistoryBrowser}, for
60 * instance:
61 * <ul>
62 * <li>{@link #getTagTableModel(PointInTimeType)} replies a {@link TableModel} for the tags of either of
63 * the two selected versions</li>
64 * <li>{@link #getNodeListTableModel(PointInTimeType)} replies a {@link TableModel} for the list of nodes of
65 * the two selected versions (if the current history provides information about a {@link Way}</li>
66 * <li> {@link #getRelationMemberTableModel(PointInTimeType)} replies a {@link TableModel} for the list of relation
67 * members of the two selected versions (if the current history provides information about a {@link Relation}</li>
68 * </ul>
69 *
70 * @see HistoryBrowser
71 */
72public class HistoryBrowserModel extends ChangeNotifier implements ActiveLayerChangeListener, DataSetListener {
73 /** the history of an OsmPrimitive */
74 private History history;
75 private HistoryOsmPrimitive reference;
76 private HistoryOsmPrimitive current;
77 /**
78 * latest isn't a reference of history. It's a clone of the currently edited
79 * {@link OsmPrimitive} in the current edit layer.
80 */
81 private HistoryOsmPrimitive latest;
82
83 private final VersionTableModel versionTableModel;
84 private final TagTableModel currentTagTableModel;
85 private final TagTableModel referenceTagTableModel;
86 private final DiffTableModel currentRelationMemberTableModel;
87 private final DiffTableModel referenceRelationMemberTableModel;
88 private final DiffTableModel referenceNodeListTableModel;
89 private final DiffTableModel currentNodeListTableModel;
90
91 /**
92 * constructor
93 */
94 public HistoryBrowserModel() {
95 versionTableModel = new VersionTableModel(this);
96 currentTagTableModel = new TagTableModel(this, PointInTimeType.CURRENT_POINT_IN_TIME);
97 referenceTagTableModel = new TagTableModel(this, PointInTimeType.REFERENCE_POINT_IN_TIME);
98 referenceNodeListTableModel = new DiffTableModel();
99 currentNodeListTableModel = new DiffTableModel();
100 currentRelationMemberTableModel = new DiffTableModel();
101 referenceRelationMemberTableModel = new DiffTableModel();
102
103 if (Main.main != null) {
104 OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer();
105 if (editLayer != null) {
106 editLayer.data.addDataSetListener(this);
107 }
108 }
109 MainApplication.getLayerManager().addActiveLayerChangeListener(this);
110 }
111
112 /**
113 * Creates a new history browser model for a given history.
114 *
115 * @param history the history. Must not be null.
116 * @throws IllegalArgumentException if history is null
117 */
118 public HistoryBrowserModel(History history) {
119 this();
120 CheckParameterUtil.ensureParameterNotNull(history, "history");
121 setHistory(history);
122 }
123
124 /**
125 * replies the history managed by this model
126 * @return the history
127 */
128 public History getHistory() {
129 return history;
130 }
131
132 private boolean canShowAsLatest(OsmPrimitive primitive) {
133 if (primitive == null)
134 return false;
135 if (primitive.isNew() || !primitive.isUsable())
136 return false;
137
138 //try creating a history primitive. if that fails, the primitive cannot be used.
139 try {
140 HistoryOsmPrimitive.forOsmPrimitive(primitive);
141 } catch (IllegalArgumentException ign) {
142 Logging.trace(ign);
143 return false;
144 }
145
146 if (history == null)
147 return false;
148 // only show latest of the same version if it is modified
149 if (history.getByVersion(primitive.getVersion()) != null)
150 return primitive.isModified();
151
152 // if latest version from history is higher than a non existing primitive version,
153 // that means this version has been redacted and the primitive cannot be used.
154 if (history.getLatest().getVersion() > primitive.getVersion())
155 return false;
156
157 // latest has a higher version than one of the primitives
158 // in the history (probably because the history got out of sync
159 // with uploaded data) -> show the primitive as latest
160 return true;
161 }
162
163 /**
164 * sets the history to be managed by this model
165 *
166 * @param history the history
167 *
168 */
169 public void setHistory(History history) {
170 this.history = history;
171 if (history.getNumVersions() > 0) {
172 HistoryOsmPrimitive newLatest = null;
173 OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer();
174 if (editLayer != null) {
175 OsmPrimitive p = editLayer.data.getPrimitiveById(history.getId(), history.getType());
176 if (canShowAsLatest(p)) {
177 newLatest = new HistoryPrimitiveBuilder().build(p);
178 }
179 }
180 if (newLatest == null) {
181 current = history.getLatest();
182 int prevIndex = history.getNumVersions() - 2;
183 reference = prevIndex < 0 ? history.getEarliest() : history.get(prevIndex);
184 } else {
185 reference = history.getLatest();
186 current = newLatest;
187 }
188 setLatest(newLatest);
189 }
190 initTagTableModels();
191 fireModelChange();
192 }
193
194 private void fireModelChange() {
195 initNodeListTableModels();
196 initMemberListTableModels();
197 fireStateChanged();
198 versionTableModel.fireTableDataChanged();
199 }
200
201 /**
202 * Replies the table model to be used in a {@link JTable} which
203 * shows the list of versions in this history.
204 *
205 * @return the table model
206 */
207 public VersionTableModel getVersionTableModel() {
208 return versionTableModel;
209 }
210
211 private void initTagTableModels() {
212 currentTagTableModel.initKeyList();
213 referenceTagTableModel.initKeyList();
214 }
215
216 /**
217 * Should be called everytime either reference of current changes to update the diff.
218 * TODO: Maybe rename to reflect this? eg. updateNodeListTableModels
219 */
220 private void initNodeListTableModels() {
221 if (current == null || current.getType() != OsmPrimitiveType.WAY
222 || reference == null || reference.getType() != OsmPrimitiveType.WAY)
223 return;
224 TwoColumnDiff diff = new TwoColumnDiff(
225 ((HistoryWay) reference).getNodes().toArray(),
226 ((HistoryWay) current).getNodes().toArray());
227 referenceNodeListTableModel.setRows(diff.referenceDiff, diff.referenceReversed);
228 currentNodeListTableModel.setRows(diff.currentDiff, false);
229 }
230
231 private void initMemberListTableModels() {
232 if (current == null || current.getType() != OsmPrimitiveType.RELATION
233 || reference == null || reference.getType() != OsmPrimitiveType.RELATION)
234 return;
235 TwoColumnDiff diff = new TwoColumnDiff(
236 ((HistoryRelation) reference).getMembers().toArray(),
237 ((HistoryRelation) current).getMembers().toArray());
238 referenceRelationMemberTableModel.setRows(diff.referenceDiff, diff.referenceReversed);
239 currentRelationMemberTableModel.setRows(diff.currentDiff, false);
240 }
241
242 /**
243 * Replies the tag table model for the respective point in time.
244 *
245 * @param pointInTimeType the type of the point in time (must not be null)
246 * @return the tag table model
247 * @throws IllegalArgumentException if pointInTimeType is null
248 */
249 public TagTableModel getTagTableModel(PointInTimeType pointInTimeType) {
250 CheckParameterUtil.ensureParameterNotNull(pointInTimeType, "pointInTimeType");
251 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
252 return currentTagTableModel;
253 else // REFERENCE_POINT_IN_TIME
254 return referenceTagTableModel;
255 }
256
257 /**
258 * Replies the node list table model for the respective point in time.
259 *
260 * @param pointInTimeType the type of the point in time (must not be null)
261 * @return the node list table model
262 * @throws IllegalArgumentException if pointInTimeType is null
263 */
264 public DiffTableModel getNodeListTableModel(PointInTimeType pointInTimeType) {
265 CheckParameterUtil.ensureParameterNotNull(pointInTimeType, "pointInTimeType");
266 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
267 return currentNodeListTableModel;
268 else // REFERENCE_POINT_IN_TIME
269 return referenceNodeListTableModel;
270 }
271
272 /**
273 * Replies the relation member table model for the respective point in time.
274 *
275 * @param pointInTimeType the type of the point in time (must not be null)
276 * @return the relation member table model
277 * @throws IllegalArgumentException if pointInTimeType is null
278 */
279 public DiffTableModel getRelationMemberTableModel(PointInTimeType pointInTimeType) {
280 CheckParameterUtil.ensureParameterNotNull(pointInTimeType, "pointInTimeType");
281 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
282 return currentRelationMemberTableModel;
283 else // REFERENCE_POINT_IN_TIME
284 return referenceRelationMemberTableModel;
285 }
286
287 /**
288 * Sets the {@link HistoryOsmPrimitive} which plays the role of a reference point
289 * in time (see {@link PointInTimeType}).
290 *
291 * @param reference the reference history primitive. Must not be null.
292 * @throws IllegalArgumentException if reference is null
293 * @throws IllegalStateException if this model isn't a assigned a history yet
294 * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
295 *
296 * @see #setHistory(History)
297 * @see PointInTimeType
298 */
299 public void setReferencePointInTime(HistoryOsmPrimitive reference) {
300 CheckParameterUtil.ensureParameterNotNull(reference, "reference");
301 if (history == null)
302 throw new IllegalStateException(tr("History not initialized yet. Failed to set reference primitive."));
303 if (reference.getId() != history.getId())
304 throw new IllegalArgumentException(
305 tr("Failed to set reference. Reference ID {0} does not match history ID {1}.", reference.getId(), history.getId()));
306 if (history.getByVersion(reference.getVersion()) == null)
307 throw new IllegalArgumentException(
308 tr("Failed to set reference. Reference version {0} not available in history.", reference.getVersion()));
309
310 this.reference = reference;
311 initTagTableModels();
312 initNodeListTableModels();
313 initMemberListTableModels();
314 fireStateChanged();
315 }
316
317 /**
318 * Sets the {@link HistoryOsmPrimitive} which plays the role of the current point
319 * in time (see {@link PointInTimeType}).
320 *
321 * @param current the reference history primitive. Must not be {@code null}.
322 * @throws IllegalArgumentException if reference is {@code null}
323 * @throws IllegalStateException if this model isn't a assigned a history yet
324 * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
325 *
326 * @see #setHistory(History)
327 * @see PointInTimeType
328 */
329 public void setCurrentPointInTime(HistoryOsmPrimitive current) {
330 CheckParameterUtil.ensureParameterNotNull(current, "current");
331 if (history == null)
332 throw new IllegalStateException(tr("History not initialized yet. Failed to set current primitive."));
333 if (current.getId() != history.getId())
334 throw new IllegalArgumentException(
335 tr("Failed to set reference. Reference ID {0} does not match history ID {1}.", current.getId(), history.getId()));
336 if (history.getByVersion(current.getVersion()) == null)
337 throw new IllegalArgumentException(
338 tr("Failed to set current primitive. Current version {0} not available in history.", current.getVersion()));
339 this.current = current;
340 initTagTableModels();
341 initNodeListTableModels();
342 initMemberListTableModels();
343 fireStateChanged();
344 }
345
346 /**
347 * Replies the history OSM primitive for the {@link PointInTimeType#CURRENT_POINT_IN_TIME}
348 *
349 * @return the history OSM primitive for the {@link PointInTimeType#CURRENT_POINT_IN_TIME} (may be null)
350 */
351 public HistoryOsmPrimitive getCurrentPointInTime() {
352 return getPointInTime(PointInTimeType.CURRENT_POINT_IN_TIME);
353 }
354
355 /**
356 * Replies the history OSM primitive for the {@link PointInTimeType#REFERENCE_POINT_IN_TIME}
357 *
358 * @return the history OSM primitive for the {@link PointInTimeType#REFERENCE_POINT_IN_TIME} (may be null)
359 */
360 public HistoryOsmPrimitive getReferencePointInTime() {
361 return getPointInTime(PointInTimeType.REFERENCE_POINT_IN_TIME);
362 }
363
364 /**
365 * replies the history OSM primitive for a given point in time
366 *
367 * @param type the type of the point in time (must not be null)
368 * @return the respective primitive. Can be null.
369 * @throws IllegalArgumentException if type is null
370 */
371 public HistoryOsmPrimitive getPointInTime(PointInTimeType type) {
372 CheckParameterUtil.ensureParameterNotNull(type, "type");
373 if (type.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
374 return current;
375 else if (type.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
376 return reference;
377
378 // should not happen
379 return null;
380 }
381
382 /**
383 * Returns true if <code>primitive</code> is the latest primitive
384 * representing the version currently edited in the current data layer.
385 *
386 * @param primitive the primitive to check
387 * @return true if <code>primitive</code> is the latest primitive
388 */
389 public boolean isLatest(HistoryOsmPrimitive primitive) {
390 return primitive != null && primitive == latest;
391 }
392
393 /**
394 * Sets the reference point in time to the given row.
395 * @param row row number
396 */
397 public void setReferencePointInTime(int row) {
398 if (history == null)
399 return;
400 if (row == history.getNumVersions()) {
401 if (latest != null) {
402 setReferencePointInTime(latest);
403 }
404 return;
405 }
406 if (row < 0 || row > history.getNumVersions())
407 return;
408 setReferencePointInTime(history.get(row));
409 }
410
411 /**
412 * Sets the current point in time to the given row.
413 * @param row row number
414 */
415 public void setCurrentPointInTime(int row) {
416 if (history == null)
417 return;
418 if (row == history.getNumVersions()) {
419 if (latest != null) {
420 setCurrentPointInTime(latest);
421 }
422 return;
423 }
424 if (row < 0 || row > history.getNumVersions())
425 return;
426 setCurrentPointInTime(history.get(row));
427 }
428
429 /**
430 * Determines if the given row is the reference point in time.
431 * @param row row number
432 * @return {@code true} if the given row is the reference point in time
433 */
434 public boolean isReferencePointInTime(int row) {
435 if (history == null)
436 return false;
437 if (row == history.getNumVersions())
438 return latest == reference;
439 if (row < 0 || row > history.getNumVersions())
440 return false;
441 return history.get(row) == reference;
442 }
443
444 /**
445 * Determines if the given row is the current point in time.
446 * @param row row number
447 * @return {@code true} if the given row is the current point in time
448 */
449 public boolean isCurrentPointInTime(int row) {
450 if (history == null)
451 return false;
452 if (row == history.getNumVersions())
453 return latest == current;
454 if (row < 0 || row > history.getNumVersions())
455 return false;
456 return history.get(row) == current;
457 }
458
459 /**
460 * Returns the {@code HistoryPrimitive} at the given row.
461 * @param row row number
462 * @return the {@code HistoryPrimitive} at the given row
463 */
464 public HistoryOsmPrimitive getPrimitive(int row) {
465 if (history == null)
466 return null;
467 return isLatest(row) ? latest : history.get(row);
468 }
469
470 /**
471 * Determines if the given row is the latest.
472 * @param row row number
473 * @return {@code true} if the given row is the latest
474 */
475 public boolean isLatest(int row) {
476 return row >= history.getNumVersions();
477 }
478
479 /**
480 * Returns the latest {@code HistoryOsmPrimitive}.
481 * @return the latest {@code HistoryOsmPrimitive}
482 * @since 11646
483 */
484 public HistoryOsmPrimitive getLatest() {
485 return latest;
486 }
487
488 /**
489 * Returns the key set (union of current and reference point in type key sets).
490 * @return the key set (union of current and reference point in type key sets)
491 * @since 11647
492 */
493 public Set<String> getKeySet() {
494 Set<String> keySet = new HashSet<>();
495 if (current != null) {
496 keySet.addAll(current.getTags().keySet());
497 }
498 if (reference != null) {
499 keySet.addAll(reference.getTags().keySet());
500 }
501 return keySet;
502 }
503
504 /**
505 * Sets the latest {@code HistoryOsmPrimitive}.
506 * @param latest the latest {@code HistoryOsmPrimitive}
507 */
508 protected void setLatest(HistoryOsmPrimitive latest) {
509 if (latest == null) {
510 if (this.current == this.latest) {
511 this.current = history != null ? history.getLatest() : null;
512 }
513 if (this.reference == this.latest) {
514 this.reference = history != null ? history.getLatest() : null;
515 }
516 this.latest = null;
517 } else {
518 if (this.current == this.latest) {
519 this.current = latest;
520 }
521 if (this.reference == this.latest) {
522 this.reference = latest;
523 }
524 this.latest = latest;
525 }
526 fireModelChange();
527 }
528
529 /**
530 * Removes this model as listener for data change and layer change events.
531 *
532 */
533 public void unlinkAsListener() {
534 OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer();
535 if (editLayer != null) {
536 editLayer.data.removeDataSetListener(this);
537 }
538 MainApplication.getLayerManager().removeActiveLayerChangeListener(this);
539 }
540
541 /* ---------------------------------------------------------------------- */
542 /* DataSetListener */
543 /* ---------------------------------------------------------------------- */
544 @Override
545 public void nodeMoved(NodeMovedEvent event) {
546 Node node = event.getNode();
547 if (!node.isNew() && node.getId() == history.getId()) {
548 setLatest(new HistoryPrimitiveBuilder().build(node));
549 }
550 }
551
552 @Override
553 public void primitivesAdded(PrimitivesAddedEvent event) {
554 for (OsmPrimitive p: event.getPrimitives()) {
555 if (canShowAsLatest(p)) {
556 setLatest(new HistoryPrimitiveBuilder().build(p));
557 }
558 }
559 }
560
561 @Override
562 public void primitivesRemoved(PrimitivesRemovedEvent event) {
563 for (OsmPrimitive p: event.getPrimitives()) {
564 if (!p.isNew() && p.getId() == history.getId()) {
565 setLatest(null);
566 }
567 }
568 }
569
570 @Override
571 public void relationMembersChanged(RelationMembersChangedEvent event) {
572 Relation r = event.getRelation();
573 if (!r.isNew() && r.getId() == history.getId()) {
574 setLatest(new HistoryPrimitiveBuilder().build(r));
575 }
576 }
577
578 @Override
579 public void tagsChanged(TagsChangedEvent event) {
580 OsmPrimitive prim = event.getPrimitive();
581 if (!prim.isNew() && prim.getId() == history.getId()) {
582 setLatest(new HistoryPrimitiveBuilder().build(prim));
583 }
584 }
585
586 @Override
587 public void wayNodesChanged(WayNodesChangedEvent event) {
588 Way way = event.getChangedWay();
589 if (!way.isNew() && way.getId() == history.getId()) {
590 setLatest(new HistoryPrimitiveBuilder().build(way));
591 }
592 }
593
594 @Override
595 public void dataChanged(DataChangedEvent event) {
596 if (history == null)
597 return;
598 OsmPrimitive primitive = event.getDataset().getPrimitiveById(history.getId(), history.getType());
599 HistoryOsmPrimitive newLatest;
600 if (canShowAsLatest(primitive)) {
601 newLatest = new HistoryPrimitiveBuilder().build(primitive);
602 } else {
603 newLatest = null;
604 }
605 setLatest(newLatest);
606 fireModelChange();
607 }
608
609 @Override
610 public void otherDatasetChange(AbstractDatasetChangedEvent event) {
611 // Irrelevant
612 }
613
614 /* ---------------------------------------------------------------------- */
615 /* ActiveLayerChangeListener */
616 /* ---------------------------------------------------------------------- */
617 @Override
618 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
619 Layer oldLayer = e.getPreviousActiveLayer();
620 if (oldLayer instanceof OsmDataLayer) {
621 OsmDataLayer l = (OsmDataLayer) oldLayer;
622 l.data.removeDataSetListener(this);
623 }
624 Layer newLayer = e.getSource().getActiveLayer();
625 if (!(newLayer instanceof OsmDataLayer)) {
626 latest = null;
627 fireModelChange();
628 return;
629 }
630 OsmDataLayer l = (OsmDataLayer) newLayer;
631 l.data.addDataSetListener(this);
632 OsmPrimitive primitive = history != null ? l.data.getPrimitiveById(history.getId(), history.getType()) : null;
633 HistoryOsmPrimitive newLatest;
634 if (canShowAsLatest(primitive)) {
635 newLatest = new HistoryPrimitiveBuilder().build(primitive);
636 } else {
637 newLatest = null;
638 }
639 setLatest(newLatest);
640 fireModelChange();
641 }
642
643 /**
644 * Creates a {@link HistoryOsmPrimitive} from a {@link OsmPrimitive}
645 *
646 */
647 static class HistoryPrimitiveBuilder implements OsmPrimitiveVisitor {
648 private HistoryOsmPrimitive clone;
649
650 @Override
651 public void visit(Node n) {
652 clone = new HistoryNode(n.getId(), n.getVersion(), n.isVisible(), getCurrentUser(), 0, null, n.getCoor(), false);
653 clone.setTags(n.getKeys());
654 }
655
656 @Override
657 public void visit(Relation r) {
658 clone = new HistoryRelation(r.getId(), r.getVersion(), r.isVisible(), getCurrentUser(), 0, null, false);
659 clone.setTags(r.getKeys());
660 HistoryRelation hr = (HistoryRelation) clone;
661 for (RelationMember rm : r.getMembers()) {
662 hr.addMember(new RelationMemberData(rm.getRole(), rm.getType(), rm.getUniqueId()));
663 }
664 }
665
666 @Override
667 public void visit(Way w) {
668 clone = new HistoryWay(w.getId(), w.getVersion(), w.isVisible(), getCurrentUser(), 0, null, false);
669 clone.setTags(w.getKeys());
670 for (Node n: w.getNodes()) {
671 ((HistoryWay) clone).addNode(n.getUniqueId());
672 }
673 }
674
675 private static User getCurrentUser() {
676 UserInfo info = UserIdentityManager.getInstance().getUserInfo();
677 return info == null ? User.getAnonymous() : User.createOsmUser(info.getId(), info.getDisplayName());
678 }
679
680 HistoryOsmPrimitive build(OsmPrimitive primitive) {
681 primitive.accept(this);
682 return clone;
683 }
684 }
685
686}
Note: See TracBrowser for help on using the repository browser.