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

Last change on this file since 2165 was 2044, checked in by Gubaer, 15 years ago

fixed #3383: changeset tags in history dialog

File size: 22.4 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;
10import java.util.logging.Logger;
11
12import javax.swing.table.DefaultTableModel;
13
14import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
15import org.openstreetmap.josm.data.osm.history.History;
16import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
17import org.openstreetmap.josm.data.osm.history.HistoryRelation;
18import org.openstreetmap.josm.data.osm.history.HistoryWay;
19
20/**
21 * This is the model used by the history browser.
22 *
23 * The state this model manages consists of the following elements:
24 * <ul>
25 * <li>the {@see History} of a specific {@see OsmPrimitive}</li>
26 * <li>a dedicated version in this {@see History} called the {@see PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
27 * <li>another version in this {@see History} called the {@see PointInTimeType#CURRENT_POINT_IN_TIME}</li>
28 * <ul>
29 * {@see HistoryBrowser} always compares the {@see PointInTimeType#REFERENCE_POINT_IN_TIME} with the
30 * {@see PointInTimeType#CURRENT_POINT_IN_TIME}.
31
32 * This model provides various {@see TableModel}s for {@see JTable}s used in {@see HistoryBrowser}, for
33 * instance:
34 * <ul>
35 * <li>{@see #getTagTableModel(PointInTimeType)} replies a {@see TableModel} for the tags of either of
36 * the two selected versions</li>
37 * <li>{@see #getNodeListTableModel(PointInTimeType)} replies a {@see TableModel} for the list of nodes of
38 * the two selected versions (if the current history provides information about a {@see Way}</li>
39 * <li> {@see #getRelationMemberTableModel(PointInTimeType)} replies a {@see TableModel} for the list of relation
40 * members of the two selected versions (if the current history provides information about a {@see Relation}</li>
41 * </ul>
42 *
43 * @see HistoryBrowser
44 */
45public class HistoryBrowserModel extends Observable {
46
47 private static Logger logger = Logger.getLogger(HistoryBrowserModel.class.getName());
48
49 /** the history of an OsmPrimitive */
50 private History history;
51 private HistoryOsmPrimitive reference;
52 private HistoryOsmPrimitive current;
53
54 private VersionTableModel versionTableModel;
55 private TagTableModel currentTagTableModel;
56 private TagTableModel referenceTagTableModel;
57 private NodeListTableModel currentNodeListTableModel;
58 private NodeListTableModel referenceNodeListTableModel;
59 private RelationMemberTableModel currentRelationMemberTableModel;
60 private RelationMemberTableModel referenceRelationMemberTableModel;
61
62 public HistoryBrowserModel() {
63 versionTableModel = new VersionTableModel();
64 currentTagTableModel = new TagTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
65 referenceTagTableModel = new TagTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
66 currentNodeListTableModel = new NodeListTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
67 referenceNodeListTableModel = new NodeListTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
68 currentRelationMemberTableModel = new RelationMemberTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
69 referenceRelationMemberTableModel = new RelationMemberTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
70 }
71
72 public HistoryBrowserModel(History history) {
73 this();
74 setHistory(history);
75 }
76
77 /**
78 * replies the history managed by this model
79 * @return the history
80 */
81 public History getHistory() {
82 return history;
83 }
84
85 /**
86 * sets the history to be managed by this model
87 *
88 * @param history the history
89 *
90 */
91 public void setHistory(History history) {
92 this.history = history;
93 if (history.getNumVersions() > 0) {
94 current = history.getEarliest();
95 reference = history.getEarliest();
96 }
97 initTagTableModels();
98 fireModelChange();
99 }
100
101
102 protected void fireModelChange() {
103 setChanged();
104 notifyObservers();
105 versionTableModel.fireTableDataChanged();
106 }
107
108 /**
109 * Replies the table model to be used in a {@see JTable} which
110 * shows the list of versions in this history.
111 *
112 * @return the table model
113 */
114 public VersionTableModel getVersionTableModel() {
115 return versionTableModel;
116 }
117
118 protected void initTagTableModels() {
119 currentTagTableModel.initKeyList();
120 referenceTagTableModel.initKeyList();
121 }
122
123 protected void initNodeListTabeModel() {
124 currentNodeListTableModel.fireTableDataChanged();
125 referenceNodeListTableModel.fireTableDataChanged();
126 }
127
128 protected void initMemberListTableModel() {
129 currentRelationMemberTableModel.fireTableDataChanged();
130 referenceRelationMemberTableModel.fireTableDataChanged();
131 }
132
133 /**
134 * replies the tag table model for the respective point in time
135 *
136 * @param pointInTimeType the type of the point in time (must not be null)
137 * @return the tag table model
138 * @exception IllegalArgumentException thrown, if pointInTimeType is null
139 */
140 public TagTableModel getTagTableModel(PointInTimeType pointInTimeType) throws IllegalArgumentException {
141 if (pointInTimeType == null)
142 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "pointInTimeType"));
143 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
144 return currentTagTableModel;
145 else if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
146 return referenceTagTableModel;
147
148 // should not happen
149 return null;
150 }
151
152 public NodeListTableModel getNodeListTableModel(PointInTimeType pointInTimeType) throws IllegalArgumentException {
153 if (pointInTimeType == null)
154 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "pointInTimeType"));
155 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
156 return currentNodeListTableModel;
157 else if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
158 return referenceNodeListTableModel;
159
160 // should not happen
161 return null;
162 }
163
164 public RelationMemberTableModel getRelationMemberTableModel(PointInTimeType pointInTimeType) throws IllegalArgumentException {
165 if (pointInTimeType == null)
166 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "pointInTimeType"));
167 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
168 return currentRelationMemberTableModel;
169 else if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
170 return referenceRelationMemberTableModel;
171
172 // should not happen
173 return null;
174 }
175
176 public void setReferencePointInTime(HistoryOsmPrimitive reference) throws IllegalArgumentException, IllegalStateException{
177 if (reference == null)
178 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "reference"));
179 if (history == null)
180 throw new IllegalStateException(tr("history not initialized yet. Failed to set reference primitive."));
181 if (reference.getId() != history.getId())
182 throw new IllegalArgumentException(tr("failed to set reference. reference id {0} doesn't match history id {1}", reference.getId(), history.getId()));
183 HistoryOsmPrimitive primitive = history.getByVersion(reference.getVersion());
184 if (primitive == null)
185 throw new IllegalArgumentException(tr("failed to set reference. reference version {0} not available in history", reference.getVersion()));
186
187 this.reference = reference;
188 initTagTableModels();
189 initNodeListTabeModel();
190 initMemberListTableModel();
191 setChanged();
192 notifyObservers();
193 }
194
195 public void setCurrentPointInTime(HistoryOsmPrimitive current) throws IllegalArgumentException, IllegalStateException{
196 if (current == null)
197 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "current"));
198 if (history == null)
199 throw new IllegalStateException(tr("history not initialized yet. Failed to set current primitive."));
200 if (current.getId() != history.getId())
201 throw new IllegalArgumentException(tr("failed to set reference. reference id {0} doesn't match history id {1}", current.getId(), history.getId()));
202 HistoryOsmPrimitive primitive = history.getByVersion(current.getVersion());
203 if (primitive == null)
204 throw new IllegalArgumentException(tr("failed to set current. current version {0} not available in history", current.getVersion()));
205 this.current = current;
206 initTagTableModels();
207 initNodeListTabeModel();
208 initMemberListTableModel();
209 setChanged();
210 notifyObservers();
211 }
212
213 /**
214 * Replies the history OSM primitive for the {@see PointInTimeType#CURRENT_POINT_IN_TIME}
215 *
216 * @return the history OSM primitive for the {@see PointInTimeType#CURRENT_POINT_IN_TIME} (may be null)
217 */
218 public HistoryOsmPrimitive getCurrentPointInTime() {
219 return getPointInTime(PointInTimeType.CURRENT_POINT_IN_TIME);
220 }
221
222 /**
223 * Replies the history OSM primitive for the {@see PointInTimeType#REFERENCE_POINT_IN_TIME}
224 *
225 * @return the history OSM primitive for the {@see PointInTimeType#REFERENCE_POINT_IN_TIME} (may be null)
226 */
227 public HistoryOsmPrimitive getReferencePointInTime() {
228 return getPointInTime(PointInTimeType.REFERENCE_POINT_IN_TIME);
229 }
230
231 /**
232 * replies the history OSM primitive for a given point in time
233 *
234 * @param type the type of the point in time (must not be null)
235 * @return the respective primitive. Can be null.
236 * @exception IllegalArgumentException thrown, if type is null
237 */
238 public HistoryOsmPrimitive getPointInTime(PointInTimeType type) throws IllegalArgumentException {
239 if (type == null)
240 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "type"));
241 if (type.equals(PointInTimeType.CURRENT_POINT_IN_TIME))
242 return current;
243 else if (type.equals(PointInTimeType.REFERENCE_POINT_IN_TIME))
244 return reference;
245
246 // should not happen
247 return null;
248 }
249
250 /**
251 * The table model for the list of versions in the current history
252 *
253 */
254 public class VersionTableModel extends DefaultTableModel {
255
256 private VersionTableModel() {
257 }
258
259 @Override
260 public int getRowCount() {
261 if (history == null)
262 return 0;
263 return history.getNumVersions();
264 }
265
266 @Override
267 public Object getValueAt(int row, int column) {
268 if(history == null)
269 return null;
270 return history.get(row);
271 }
272
273 @Override
274 public boolean isCellEditable(int row, int column) {
275 return false;
276 }
277
278 public void setReferencePointInTime(int row) {
279 if (history == null) return;
280 if (row < 0 || row > history.getNumVersions()) return;
281 HistoryOsmPrimitive reference = history.get(row);
282 HistoryBrowserModel.this.setReferencePointInTime(reference);
283 }
284
285 public void setCurrentPointInTime(int row) {
286 if (history == null) return;
287 if (row < 0 || row > history.getNumVersions()) return;
288 HistoryOsmPrimitive current = history.get(row);
289 HistoryBrowserModel.this.setCurrentPointInTime(current);
290 }
291
292 public boolean isReferencePointInTime(int row) {
293 if (history == null) return false;
294 if (row < 0 || row > history.getNumVersions()) return false;
295 HistoryOsmPrimitive p = history.get(row);
296 return p.equals(reference);
297 }
298
299 public HistoryOsmPrimitive getPrimitive(int row) {
300 return history.get(row);
301 }
302 }
303
304
305 /**
306 * The table model for the tags of the version at {@see PointInTimeType#REFERENCE_POINT_IN_TIME}
307 * or {@see PointInTimeType#CURRENT_POINT_IN_TIME}
308 *
309 */
310 public class TagTableModel extends DefaultTableModel {
311
312 private ArrayList<String> keys;
313 private PointInTimeType pointInTimeType;
314
315 protected void initKeyList() {
316 HashSet<String> keySet = new HashSet<String>();
317 if (current != null) {
318 keySet.addAll(current.getTags().keySet());
319 }
320 if (reference != null) {
321 keySet.addAll(reference.getTags().keySet());
322 }
323 keys = new ArrayList<String>(keySet);
324 Collections.sort(keys);
325 fireTableDataChanged();
326 }
327
328 protected TagTableModel(PointInTimeType type) {
329 pointInTimeType = type;
330 initKeyList();
331 }
332
333 @Override
334 public int getRowCount() {
335 if (keys == null) return 0;
336 return keys.size();
337 }
338
339 @Override
340 public Object getValueAt(int row, int column) {
341 return keys.get(row);
342 }
343
344 @Override
345 public boolean isCellEditable(int row, int column) {
346 return false;
347 }
348
349 public boolean hasTag(String key) {
350 HistoryOsmPrimitive primitive = getPointInTime(pointInTimeType);
351 if (primitive == null)
352 return false;
353 return primitive.hasTag(key);
354 }
355
356 public String getValue(String key) {
357 HistoryOsmPrimitive primitive = getPointInTime(pointInTimeType);
358 if (primitive == null)
359 return null;
360 return primitive.get(key);
361 }
362
363 public boolean oppositeHasTag(String key) {
364 PointInTimeType opposite = pointInTimeType.opposite();
365 HistoryOsmPrimitive primitive = getPointInTime(opposite);
366 if (primitive == null)
367 return false;
368 return primitive.hasTag(key);
369 }
370
371 public String getOppositeValue(String key) {
372 PointInTimeType opposite = pointInTimeType.opposite();
373 HistoryOsmPrimitive primitive = getPointInTime(opposite);
374 if (primitive == null)
375 return null;
376 return primitive.get(key);
377 }
378
379 public boolean hasSameValueAsOpposite(String key) {
380 String value = getValue(key);
381 String oppositeValue = getOppositeValue(key);
382 if (value == null || oppositeValue == null)
383 return false;
384 return value.equals(oppositeValue);
385 }
386
387 public PointInTimeType getPointInTimeType() {
388 return pointInTimeType;
389 }
390
391 public boolean isCurrentPointInTime() {
392 return pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME);
393 }
394
395 public boolean isReferencePointInTime() {
396 return pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME);
397 }
398 }
399
400 /**
401 * The table model for the nodes of the version at {@see PointInTimeType#REFERENCE_POINT_IN_TIME}
402 * or {@see PointInTimeType#CURRENT_POINT_IN_TIME}
403 *
404 */
405 public class NodeListTableModel extends DefaultTableModel {
406
407 private PointInTimeType pointInTimeType;
408
409 private NodeListTableModel(PointInTimeType pointInTimeType) {
410 this.pointInTimeType = pointInTimeType;
411 }
412
413 @Override
414 public int getRowCount() {
415 int n = 0;
416 if (current != null && current.getType().equals(OsmPrimitiveType.WAY)) {
417 n = ((HistoryWay)current).getNumNodes();
418 }
419 if (reference != null && reference.getType().equals(OsmPrimitiveType.WAY)) {
420 n = Math.max(n,((HistoryWay)reference).getNumNodes());
421 }
422 return n;
423 }
424
425 protected HistoryWay getWay() {
426 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME)) {
427 if (! current.getType().equals(OsmPrimitiveType.WAY))
428 return null;
429 return (HistoryWay)current;
430 }
431 if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME)) {
432 if (! reference.getType().equals(OsmPrimitiveType.WAY))
433 return null;
434 return (HistoryWay)reference;
435 }
436
437 // should not happen
438 return null;
439 }
440
441 protected HistoryWay getOppositeWay() {
442 PointInTimeType opposite = pointInTimeType.opposite();
443 if (opposite.equals(PointInTimeType.CURRENT_POINT_IN_TIME)) {
444 if (! current.getType().equals(OsmPrimitiveType.WAY))
445 return null;
446 return (HistoryWay)current;
447 }
448 if (opposite.equals(PointInTimeType.REFERENCE_POINT_IN_TIME)) {
449 if (! reference.getType().equals(OsmPrimitiveType.WAY))
450 return null;
451 return (HistoryWay)reference;
452 }
453
454 // should not happen
455 return null;
456 }
457
458 @Override
459 public Object getValueAt(int row, int column) {
460 HistoryWay way = getWay();
461 if (way == null)
462 return null;
463 if (row >= way.getNumNodes())
464 return null;
465 return way.getNodes().get(row);
466 }
467
468 @Override
469 public boolean isCellEditable(int row, int column) {
470 return false;
471 }
472
473 public boolean isSameInOppositeWay(int row) {
474 HistoryWay thisWay = getWay();
475 HistoryWay oppositeWay = getOppositeWay();
476 if (thisWay == null || oppositeWay == null)
477 return false;
478 if (row >= oppositeWay.getNumNodes())
479 return false;
480 return thisWay.getNodeId(row) == oppositeWay.getNodeId(row);
481 }
482
483 public boolean isInOppositeWay(int row) {
484 HistoryWay thisWay = getWay();
485 HistoryWay oppositeWay = getOppositeWay();
486 if (thisWay == null || oppositeWay == null)
487 return false;
488 return oppositeWay.getNodes().contains(thisWay.getNodeId(row));
489 }
490 }
491
492 /**
493 * The table model for the relation members of the version at {@see PointInTimeType#REFERENCE_POINT_IN_TIME}
494 * or {@see PointInTimeType#CURRENT_POINT_IN_TIME}
495 *
496 */
497
498 public class RelationMemberTableModel extends DefaultTableModel {
499
500 private PointInTimeType pointInTimeType;
501
502 private RelationMemberTableModel(PointInTimeType pointInTimeType) {
503 this.pointInTimeType = pointInTimeType;
504 }
505
506 @Override
507 public int getRowCount() {
508 int n = 0;
509 if (current != null && current.getType().equals(OsmPrimitiveType.RELATION)) {
510 n = ((HistoryRelation)current).getNumMembers();
511 }
512 if (reference != null && reference.getType().equals(OsmPrimitiveType.RELATION)) {
513 n = Math.max(n,((HistoryRelation)reference).getNumMembers());
514 }
515 return n;
516 }
517
518 protected HistoryRelation getRelation() {
519 if (pointInTimeType.equals(PointInTimeType.CURRENT_POINT_IN_TIME)) {
520 if (! current.getType().equals(OsmPrimitiveType.RELATION))
521 return null;
522 return (HistoryRelation)current;
523 }
524 if (pointInTimeType.equals(PointInTimeType.REFERENCE_POINT_IN_TIME)) {
525 if (! reference.getType().equals(OsmPrimitiveType.RELATION))
526 return null;
527 return (HistoryRelation)reference;
528 }
529
530 // should not happen
531 return null;
532 }
533
534 protected HistoryRelation getOppositeRelation() {
535 PointInTimeType opposite = pointInTimeType.opposite();
536 if (opposite.equals(PointInTimeType.CURRENT_POINT_IN_TIME)) {
537 if (! current.getType().equals(OsmPrimitiveType.RELATION))
538 return null;
539 return (HistoryRelation)current;
540 }
541 if (opposite.equals(PointInTimeType.REFERENCE_POINT_IN_TIME)) {
542 if (! reference.getType().equals(OsmPrimitiveType.RELATION))
543 return null;
544 return (HistoryRelation)reference;
545 }
546
547 // should not happen
548 return null;
549 }
550
551 @Override
552 public Object getValueAt(int row, int column) {
553 HistoryRelation relation = getRelation();
554 if (relation == null)
555 return null;
556 if (row >= relation.getNumMembers())
557 return null;
558 return relation.getMembers().get(row);
559 }
560
561 @Override
562 public boolean isCellEditable(int row, int column) {
563 return false;
564 }
565
566 public boolean isSameInOppositeWay(int row) {
567 HistoryRelation thisRelation = getRelation();
568 HistoryRelation oppositeRelation = getOppositeRelation();
569 if (thisRelation == null || oppositeRelation == null)
570 return false;
571 if (row >= oppositeRelation.getNumMembers())
572 return false;
573 return
574 thisRelation.getMembers().get(row).getPrimitiveId() == oppositeRelation.getMembers().get(row).getPrimitiveId()
575 && thisRelation.getMembers().get(row).getRole().equals(oppositeRelation.getMembers().get(row).getRole());
576 }
577
578 public boolean isInOppositeWay(int row) {
579 HistoryRelation thisRelation = getRelation();
580 HistoryRelation oppositeRelation = getOppositeRelation();
581 if (thisRelation == null || oppositeRelation == null)
582 return false;
583 return oppositeRelation.getMembers().contains(thisRelation.getMembers().get(row));
584 }
585 }
586}
Note: See TracBrowser for help on using the repository browser.