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

Last change on this file since 10670 was 10637, checked in by Don-vip, 8 years ago

fix #13050 - cannot copy from the object history view (patch by michael2402, modified) - gsoc-core

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