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

Last change on this file since 2850 was 2850, checked in by mjulius, 14 years ago

fix messages for gui

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