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

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

fix #12983 - replace calls to Main.main.get[Active|Edit]Layer() by Main.getLayerManager().get[Active|Edit]Layer() - gsoc-core

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