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

Last change on this file since 6479 was 6362, checked in by Don-vip, 10 years ago

Checkstyle:

  • private constructors for util classes
  • final classes
  • missing "else" statements
  • import cleanup
  • Property svn:eol-style set to native
File size: 30.3 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;
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.MapView;
44import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
45import org.openstreetmap.josm.gui.layer.Layer;
46import org.openstreetmap.josm.gui.layer.OsmDataLayer;
47import org.openstreetmap.josm.io.XmlWriter;
48import org.openstreetmap.josm.tools.CheckParameterUtil;
49
50/**
51 * This is the model used by the history browser.
52 *
53 * The model state consists of the following elements:
54 * <ul>
55 * <li>the {@link History} of a specific {@link OsmPrimitive}</li>
56 * <li>a dedicated version in this {@link History} called the {@link PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
57 * <li>another version in this {@link History} called the {@link PointInTimeType#CURRENT_POINT_IN_TIME}</li>
58 * <ul>
59 * {@link HistoryBrowser} always compares the {@link PointInTimeType#REFERENCE_POINT_IN_TIME} with the
60 * {@link PointInTimeType#CURRENT_POINT_IN_TIME}.
61
62 * This model provides various {@link TableModel}s for {@link JTable}s used in {@link HistoryBrowser}, for
63 * instance:
64 * <ul>
65 * <li>{@link #getTagTableModel(PointInTimeType)} replies a {@link TableModel} for the tags of either of
66 * the two selected versions</li>
67 * <li>{@link #getNodeListTableModel(PointInTimeType)} replies a {@link TableModel} for the list of nodes of
68 * the two selected versions (if the current history provides information about a {@link Way}</li>
69 * <li> {@link #getRelationMemberTableModel(PointInTimeType)} replies a {@link TableModel} for the list of relation
70 * members of the two selected versions (if the current history provides information about a {@link Relation}</li>
71 * </ul>
72 *
73 * @see HistoryBrowser
74 */
75public class HistoryBrowserModel extends Observable implements LayerChangeListener, DataSetListener {
76 /** the history of an OsmPrimitive */
77 private History history;
78 private HistoryOsmPrimitive reference;
79 private HistoryOsmPrimitive current;
80 /**
81 * latest isn't a reference of history. It's a clone of the currently edited
82 * {@link OsmPrimitive} in the current edit layer.
83 */
84 private HistoryOsmPrimitive latest;
85
86 private VersionTableModel versionTableModel;
87 private TagTableModel currentTagTableModel;
88 private TagTableModel referenceTagTableModel;
89 private DiffTableModel currentRelationMemberTableModel;
90 private DiffTableModel referenceRelationMemberTableModel;
91 private DiffTableModel referenceNodeListTableModel;
92 private DiffTableModel currentNodeListTableModel;
93
94 /**
95 * constructor
96 */
97 public HistoryBrowserModel() {
98 versionTableModel = new VersionTableModel();
99 currentTagTableModel = new TagTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
100 referenceTagTableModel = new TagTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
101 referenceNodeListTableModel = new DiffTableModel();
102 currentNodeListTableModel = new DiffTableModel();
103 currentRelationMemberTableModel = new DiffTableModel();
104 referenceRelationMemberTableModel = new DiffTableModel();
105
106 OsmDataLayer editLayer = Main.main.getEditLayer();
107 if (editLayer != null) {
108 editLayer.data.addDataSetListener(this);
109 }
110 MapView.addLayerChangeListener(this);
111 }
112
113 /**
114 * Creates a new history browser model for a given history.
115 *
116 * @param history the history. Must not be null.
117 * @throws IllegalArgumentException thrown if history is null
118 */
119 public HistoryBrowserModel(History history) {
120 this();
121 CheckParameterUtil.ensureParameterNotNull(history, "history");
122 setHistory(history);
123 }
124
125 /**
126 * replies the history managed by this model
127 * @return the history
128 */
129 public History getHistory() {
130 return history;
131 }
132
133 protected boolean hasNewNodes(Way way) {
134 for (Node n: way.getNodes()) {
135 if (n.isNew()) return true;
136 }
137 return false;
138 }
139 protected boolean canShowAsLatest(OsmPrimitive primitive) {
140 if (primitive == null) return false;
141 if (primitive.isNew() || !primitive.isUsable()) return false;
142
143 //try creating a history primitive. if that fails, the primitive cannot be used.
144 try {
145 HistoryOsmPrimitive.forOsmPrimitive(primitive);
146 } catch (Exception ign) {
147 return false;
148 }
149
150 if (history == null) 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.main.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 setChanged();
201 notifyObservers();
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
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);
232 currentNodeListTableModel.setRows(diff.currentDiff);
233
234 referenceNodeListTableModel.fireTableDataChanged();
235 currentNodeListTableModel.fireTableDataChanged();
236 }
237
238 protected void initMemberListTableModels() {
239 if(current.getType() != OsmPrimitiveType.RELATION || reference.getType() != OsmPrimitiveType.RELATION)
240 return;
241
242 TwoColumnDiff diff = new TwoColumnDiff(
243 ((HistoryRelation)reference).getMembers().toArray(),
244 ((HistoryRelation)current).getMembers().toArray());
245
246 referenceRelationMemberTableModel.setRows(diff.referenceDiff);
247 currentRelationMemberTableModel.setRows(diff.currentDiff);
248
249 currentRelationMemberTableModel.fireTableDataChanged();
250 referenceRelationMemberTableModel.fireTableDataChanged();
251 }
252
253 /**
254 * replies the tag table model for the respective point in time
255 *
256 * @param pointInTimeType the type of the point in time (must not be null)
257 * @return the tag table model
258 * @exception IllegalArgumentException thrown, if pointInTimeType is null
259 */
260 public TagTableModel getTagTableModel(PointInTimeType pointInTimeType) throws IllegalArgumentException {
261 CheckParameterUtil.ensureParameterNotNull(pointInTimeType, "pointInTimeType");
262 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
263 return currentTagTableModel;
264 else if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
265 return referenceTagTableModel;
266
267 // should not happen
268 return null;
269 }
270
271 public DiffTableModel getNodeListTableModel(PointInTimeType pointInTimeType) throws IllegalArgumentException {
272 CheckParameterUtil.ensureParameterNotNull(pointInTimeType, "pointInTimeType");
273 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
274 return currentNodeListTableModel;
275 else if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
276 return referenceNodeListTableModel;
277
278 // should not happen
279 return null;
280 }
281
282 public DiffTableModel getRelationMemberTableModel(PointInTimeType pointInTimeType) throws IllegalArgumentException {
283 CheckParameterUtil.ensureParameterNotNull(pointInTimeType, "pointInTimeType");
284 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
285 return currentRelationMemberTableModel;
286 else if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
287 return referenceRelationMemberTableModel;
288
289 // should not happen
290 return null;
291 }
292
293 /**
294 * Sets the {@link HistoryOsmPrimitive} which plays the role of a reference point
295 * in time (see {@link PointInTimeType}).
296 *
297 * @param reference the reference history primitive. Must not be null.
298 * @throws IllegalArgumentException thrown if reference is null
299 * @throws IllegalStateException thrown if this model isn't a assigned a history yet
300 * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
301 *
302 * @see #setHistory(History)
303 * @see PointInTimeType
304 */
305 public void setReferencePointInTime(HistoryOsmPrimitive reference) throws IllegalArgumentException, IllegalStateException{
306 CheckParameterUtil.ensureParameterNotNull(reference, "reference");
307 if (history == null)
308 throw new IllegalStateException(tr("History not initialized yet. Failed to set reference primitive."));
309 if (reference.getId() != history.getId())
310 throw new IllegalArgumentException(tr("Failed to set reference. Reference ID {0} does not match history ID {1}.", reference.getId(), history.getId()));
311 HistoryOsmPrimitive primitive = history.getByVersion(reference.getVersion());
312 if (primitive == null)
313 throw new IllegalArgumentException(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 setChanged();
320 notifyObservers();
321 }
322
323 /**
324 * Sets the {@link HistoryOsmPrimitive} which plays the role of the current point
325 * in time (see {@link PointInTimeType}).
326 *
327 * @param current the reference history primitive. Must not be {@code null}.
328 * @throws IllegalArgumentException thrown if reference is {@code null}
329 * @throws IllegalStateException thrown if this model isn't a assigned a history yet
330 * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
331 *
332 * @see #setHistory(History)
333 * @see PointInTimeType
334 */
335 public void setCurrentPointInTime(HistoryOsmPrimitive current) throws IllegalArgumentException, IllegalStateException{
336 CheckParameterUtil.ensureParameterNotNull(current, "current");
337 if (history == null)
338 throw new IllegalStateException(tr("History not initialized yet. Failed to set current primitive."));
339 if (current.getId() != history.getId())
340 throw new IllegalArgumentException(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(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 setChanged();
349 notifyObservers();
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 * @exception IllegalArgumentException thrown, if type is null
376 */
377 public HistoryOsmPrimitive getPointInTime(PointInTimeType type) throws IllegalArgumentException {
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) 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 p = getPrimitive(row);
432 if (p != null && p.getTimestamp() != null)
433 return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(p.getTimestamp());
434 return null;
435 }
436 case 4: {
437 HistoryOsmPrimitive p = getPrimitive(row);
438 if (p != null) {
439 User user = p.getUser();
440 if (user != null)
441 return "<html>" + XmlWriter.encode(user.getName(), true) + " <font color=gray>(" + user.getId() + ")</font></html>";
442 }
443 return null;
444 }
445 }
446 return null;
447 }
448
449 @Override
450 public void setValueAt(Object aValue, int row, int column) {
451 if (!((Boolean) aValue)) 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) 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()) return;
479 HistoryOsmPrimitive reference = history.get(row);
480 HistoryBrowserModel.this.setReferencePointInTime(reference);
481 }
482
483 public void setCurrentPointInTime(int row) {
484 if (history == null) return;
485 if (row == history.getNumVersions()) {
486 if (latest != null) {
487 HistoryBrowserModel.this.setCurrentPointInTime(latest);
488 }
489 return;
490 }
491 if (row < 0 || row > history.getNumVersions()) return;
492 HistoryOsmPrimitive current = history.get(row);
493 HistoryBrowserModel.this.setCurrentPointInTime(current);
494 }
495
496 public boolean isReferencePointInTime(int row) {
497 if (history == null) return false;
498 if (row == history.getNumVersions())
499 return latest == reference;
500 if (row < 0 || row > history.getNumVersions()) return false;
501 HistoryOsmPrimitive p = history.get(row);
502 return p == reference;
503 }
504
505 public boolean isCurrentPointInTime(int row) {
506 if (history == null) return false;
507 if (row == history.getNumVersions())
508 return latest == current;
509 if (row < 0 || row > history.getNumVersions()) return false;
510 HistoryOsmPrimitive p = history.get(row);
511 return p == current;
512 }
513
514 public HistoryOsmPrimitive getPrimitive(int row) {
515 if (history == null)
516 return null;
517 return isLatest(row) ? latest : history.get(row);
518 }
519
520 public boolean isLatest(int row) {
521 return row >= history.getNumVersions();
522 }
523
524 public OsmPrimitive getLatest() {
525 if (latest == null) return null;
526 OsmDataLayer editLayer = Main.main.getEditLayer();
527 if (editLayer == null) return null;
528 OsmPrimitive p = editLayer.data.getPrimitiveById(latest.getId(), latest.getType());
529 return p;
530 }
531
532 @Override
533 public int getColumnCount() {
534 return 6;
535 }
536 }
537
538 /**
539 * The table model for the tags of the version at {@link PointInTimeType#REFERENCE_POINT_IN_TIME}
540 * or {@link PointInTimeType#CURRENT_POINT_IN_TIME}
541 *
542 */
543 public class TagTableModel extends AbstractTableModel {
544
545 private List<String> keys;
546 private PointInTimeType pointInTimeType;
547
548 protected void initKeyList() {
549 HashSet<String> keySet = new HashSet<String>();
550 if (current != null) {
551 keySet.addAll(current.getTags().keySet());
552 }
553 if (reference != null) {
554 keySet.addAll(reference.getTags().keySet());
555 }
556 keys = new ArrayList<String>(keySet);
557 Collections.sort(keys);
558 fireTableDataChanged();
559 }
560
561 protected TagTableModel(PointInTimeType type) {
562 pointInTimeType = type;
563 initKeyList();
564 }
565
566 @Override
567 public int getRowCount() {
568 if (keys == null) return 0;
569 return keys.size();
570 }
571
572 @Override
573 public Object getValueAt(int row, int column) {
574 return keys.get(row);
575 }
576
577 @Override
578 public boolean isCellEditable(int row, int column) {
579 return false;
580 }
581
582 public boolean hasTag(String key) {
583 HistoryOsmPrimitive primitive = getPointInTime(pointInTimeType);
584 if (primitive == null)
585 return false;
586 return primitive.hasTag(key);
587 }
588
589 public String getValue(String key) {
590 HistoryOsmPrimitive primitive = getPointInTime(pointInTimeType);
591 if (primitive == null)
592 return null;
593 return primitive.get(key);
594 }
595
596 public boolean oppositeHasTag(String key) {
597 PointInTimeType opposite = pointInTimeType.opposite();
598 HistoryOsmPrimitive primitive = getPointInTime(opposite);
599 if (primitive == null)
600 return false;
601 return primitive.hasTag(key);
602 }
603
604 public String getOppositeValue(String key) {
605 PointInTimeType opposite = pointInTimeType.opposite();
606 HistoryOsmPrimitive primitive = getPointInTime(opposite);
607 if (primitive == null)
608 return null;
609 return primitive.get(key);
610 }
611
612 public boolean hasSameValueAsOpposite(String key) {
613 String value = getValue(key);
614 String oppositeValue = getOppositeValue(key);
615 if (value == null || oppositeValue == null)
616 return false;
617 return value.equals(oppositeValue);
618 }
619
620 public PointInTimeType getPointInTimeType() {
621 return pointInTimeType;
622 }
623
624 public boolean isCurrentPointInTime() {
625 return pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME);
626 }
627
628 public boolean isReferencePointInTime() {
629 return pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME);
630 }
631
632 @Override
633 public int getColumnCount() {
634 return 1;
635 }
636 }
637
638 protected void setLatest(HistoryOsmPrimitive latest) {
639 if (latest == null) {
640 if (this.current == this.latest) {
641 this.current = history.getLatest();
642 }
643 if (this.reference == this.latest) {
644 this.current = history.getLatest();
645 }
646 this.latest = null;
647 } else {
648 if (this.current == this.latest) {
649 this.current = latest;
650 }
651 if (this.reference == this.latest) {
652 this.reference = latest;
653 }
654 this.latest = latest;
655 }
656 fireModelChange();
657 }
658
659 /**
660 * Removes this model as listener for data change and layer change
661 * events.
662 *
663 */
664 public void unlinkAsListener() {
665 OsmDataLayer editLayer = Main.main.getEditLayer();
666 if (editLayer != null) {
667 editLayer.data.removeDataSetListener(this);
668 }
669 MapView.removeLayerChangeListener(this);
670 }
671
672 /* ---------------------------------------------------------------------- */
673 /* DataSetListener */
674 /* ---------------------------------------------------------------------- */
675 @Override
676 public void nodeMoved(NodeMovedEvent event) {
677 Node node = event.getNode();
678 if (!node.isNew() && node.getId() == history.getId()) {
679 setLatest(new HistoryPrimitiveBuilder().build(node));
680 }
681 }
682
683 @Override
684 public void primitivesAdded(PrimitivesAddedEvent event) {
685 for (OsmPrimitive p: event.getPrimitives()) {
686 if (canShowAsLatest(p)) {
687 setLatest(new HistoryPrimitiveBuilder().build(p));
688 }
689 }
690 }
691
692 @Override
693 public void primitivesRemoved(PrimitivesRemovedEvent event) {
694 for (OsmPrimitive p: event.getPrimitives()) {
695 if (!p.isNew() && p.getId() == history.getId()) {
696 setLatest(null);
697 }
698 }
699 }
700
701 @Override
702 public void relationMembersChanged(RelationMembersChangedEvent event) {
703 Relation r = event.getRelation();
704 if (!r.isNew() && r.getId() == history.getId()) {
705 setLatest(new HistoryPrimitiveBuilder().build(r));
706 }
707 }
708
709 @Override
710 public void tagsChanged(TagsChangedEvent event) {
711 OsmPrimitive prim = event.getPrimitive();
712 if (!prim.isNew() && prim.getId() == history.getId()) {
713 setLatest(new HistoryPrimitiveBuilder().build(prim));
714 }
715 }
716
717 @Override
718 public void wayNodesChanged(WayNodesChangedEvent event) {
719 Way way = event.getChangedWay();
720 if (!way.isNew() && way.getId() == history.getId()) {
721 setLatest(new HistoryPrimitiveBuilder().build(way));
722 }
723 }
724
725 @Override
726 public void dataChanged(DataChangedEvent event) {
727 OsmPrimitive primitive = event.getDataset().getPrimitiveById(history.getId(), history.getType());
728 HistoryOsmPrimitive latest;
729 if (canShowAsLatest(primitive)) {
730 latest = new HistoryPrimitiveBuilder().build(primitive);
731 } else {
732 latest = null;
733 }
734 setLatest(latest);
735 fireModelChange();
736 }
737
738 @Override
739 public void otherDatasetChange(AbstractDatasetChangedEvent event) {
740 // Irrelevant
741 }
742
743 /* ---------------------------------------------------------------------- */
744 /* LayerChangeListener */
745 /* ---------------------------------------------------------------------- */
746 @Override
747 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
748 if (oldLayer instanceof OsmDataLayer) {
749 OsmDataLayer l = (OsmDataLayer)oldLayer;
750 l.data.removeDataSetListener(this);
751 }
752 if (!(newLayer instanceof OsmDataLayer)) {
753 latest = null;
754 fireModelChange();
755 return;
756 }
757 OsmDataLayer l = (OsmDataLayer)newLayer;
758 l.data.addDataSetListener(this);
759 OsmPrimitive primitive = l.data.getPrimitiveById(history.getId(), history.getType());
760 HistoryOsmPrimitive latest;
761 if (canShowAsLatest(primitive)) {
762 latest = new HistoryPrimitiveBuilder().build(primitive);
763 } else {
764 latest = null;
765 }
766 setLatest(latest);
767 fireModelChange();
768 }
769
770 @Override
771 public void layerAdded(Layer newLayer) {}
772 @Override
773 public void layerRemoved(Layer oldLayer) {}
774
775 /**
776 * Creates a {@link HistoryOsmPrimitive} from a {@link OsmPrimitive}
777 *
778 */
779 static class HistoryPrimitiveBuilder extends AbstractVisitor {
780 private HistoryOsmPrimitive clone;
781
782 @Override
783 public void visit(Node n) {
784 clone = new HistoryNode(n.getId(), n.getVersion(), n.isVisible(), getCurrentUser(), 0, null, n.getCoor(), false);
785 clone.setTags(n.getKeys());
786 }
787
788 @Override
789 public void visit(Relation r) {
790 clone = new HistoryRelation(r.getId(), r.getVersion(), r.isVisible(), getCurrentUser(), 0, null, false);
791 clone.setTags(r.getKeys());
792 HistoryRelation hr = (HistoryRelation)clone;
793 for (RelationMember rm : r.getMembers()) {
794 hr.addMember(new RelationMemberData(rm.getRole(), rm.getType(), rm.getUniqueId()));
795 }
796 }
797
798 @Override
799 public void visit(Way w) {
800 clone = new HistoryWay(w.getId(), w.getVersion(), w.isVisible(), getCurrentUser(), 0, null, false);
801 clone.setTags(w.getKeys());
802 for (Node n: w.getNodes()) {
803 ((HistoryWay)clone).addNode(n.getUniqueId());
804 }
805 }
806
807 private User getCurrentUser() {
808 UserInfo info = JosmUserIdentityManager.getInstance().getUserInfo();
809 return info == null ? User.getAnonymous() : User.createOsmUser(info.getId(), info.getDisplayName());
810 }
811
812 public HistoryOsmPrimitive build(OsmPrimitive primitive) {
813 primitive.accept(this);
814 return clone;
815 }
816 }
817}
Note: See TracBrowser for help on using the repository browser.