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

Last change on this file since 2497 was 2497, checked in by jttt, 14 years ago

Added Dataset.beginUpdate and Dataset.endUpdate that can be used to temporarily stop dataset events in case of big changes

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