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

Last change on this file since 5627 was 5627, checked in by jttt, 11 years ago

use diff to show relation members in history dialog, jump to first change when different version is selected

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