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

Last change on this file since 3083 was 3083, checked in by bastiK, 14 years ago

added svn:eol-style=native to source files

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