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

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

new: history feature implemented

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