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

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

see #8902 - Small performance enhancements / coding style (patch by shinigami):

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