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

Last change on this file since 4191 was 4191, checked in by stoecker, 13 years ago

remove old debug stuff

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