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

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

sonar - squid:S2325 - "private" methods that don't access instance data should be "static"

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