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

Last change on this file since 8345 was 8338, checked in by Don-vip, 9 years ago

fix squid:S1319 - Declarations should use Java collection interfaces rather than specific implementation classes

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