001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.history; 003 004import java.awt.Color; 005import java.util.ArrayList; 006import java.util.Collections; 007import java.util.List; 008 009import javax.swing.table.AbstractTableModel; 010 011import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive; 012 013/** 014 * The table model for the tags of the version 015 * at {@link PointInTimeType#REFERENCE_POINT_IN_TIME} 016 * or {@link PointInTimeType#CURRENT_POINT_IN_TIME} 017 * @since 11647 (extracted from HistoryBrowserModel) 018 */ 019public final class TagTableModel extends AbstractTableModel { 020 021 private List<String> keys; 022 private final PointInTimeType pointInTimeType; 023 private final HistoryBrowserModel model; 024 025 /** 026 * Constructs a new {@code TagTableModel}. 027 * @param historyModel parent {@code HistoryBrowserModel} 028 * @param type type of point in time 029 */ 030 public TagTableModel(HistoryBrowserModel historyModel, PointInTimeType type) { 031 model = historyModel; 032 pointInTimeType = type; 033 initKeyList(); 034 } 035 036 void initKeyList() { 037 keys = new ArrayList<>(model.getKeySet()); 038 Collections.sort(keys); 039 fireTableDataChanged(); 040 } 041 042 @Override 043 public int getRowCount() { 044 if (keys == null) 045 return 0; 046 return keys.size(); 047 } 048 049 @Override 050 public Object getValueAt(int row, int column) { 051 return getKeyAt(row); 052 } 053 054 /** 055 * Get the key for the given row. 056 * @param row The row 057 * @return The key in that row. 058 * @since 10637 059 */ 060 public String getKeyAt(int row) { 061 return keys.get(row); 062 } 063 064 /** 065 * Determines if a tag exists for the given key. 066 * @param key tag key 067 * @return {@code true} if a tag exists for the given key 068 */ 069 public boolean hasTag(String key) { 070 HistoryOsmPrimitive primitive = model.getPointInTime(pointInTimeType); 071 return primitive != null && primitive.hasKey(key); 072 } 073 074 /** 075 * Returns the tag value for the given key. 076 * @param key tag key 077 * @return tag value, or null 078 */ 079 public String getValue(String key) { 080 HistoryOsmPrimitive primitive = model.getPointInTime(pointInTimeType); 081 if (primitive == null) 082 return null; 083 return primitive.get(key); 084 } 085 086 /** 087 * Returns the history primitive which changed the given key. 088 * @param key the OSM key 089 * @return the history primitive which changed the given key 090 */ 091 public HistoryOsmPrimitive getWhichChangedTag(String key) { 092 HistoryOsmPrimitive primitive = model.getPointInTime(pointInTimeType); 093 if (primitive == null) 094 return null; 095 return model.getHistory().getWhichChangedTag(primitive, key, model.isLatest(primitive)); 096 } 097 098 /** 099 * Returns a version string for the given primitive, {@code "*"} if it is {@linkplain HistoryBrowserModel#isLatest is latest}. 100 * @param primitive the history primitive 101 * @return a version string for the given primitive 102 */ 103 public String getVersionString(HistoryOsmPrimitive primitive) { 104 return model.isLatest(primitive) ? "*" : "v" + primitive.getVersion(); 105 } 106 107 /** 108 * Returns the color for the given primitive timestamp 109 * @param primitive the history primitive 110 * @return the color for the given primitive timestamp 111 */ 112 public Color getVersionColor(HistoryOsmPrimitive primitive) { 113 return model.getVersionColor(primitive); 114 } 115 116 /** 117 * Determines if a tag exists in the opposite point in time for the given key. 118 * @param key tag key 119 * @return {@code true} if a tag exists for the given key 120 */ 121 public boolean oppositeHasTag(String key) { 122 HistoryOsmPrimitive primitive = model.getPointInTime(pointInTimeType.opposite()); 123 return primitive != null && primitive.hasKey(key); 124 } 125 126 /** 127 * Returns the tag value in the opposite point in time for the given key. 128 * @param key tag key 129 * @return tag value, or null 130 */ 131 public String getOppositeValue(String key) { 132 HistoryOsmPrimitive primitive = model.getPointInTime(pointInTimeType.opposite()); 133 if (primitive == null) 134 return null; 135 return primitive.get(key); 136 } 137 138 /** 139 * Determines if the tag value is the same in the opposite point in time for the given key. 140 * @param key tag key 141 * @return {@code true} if the tag value is the same in the opposite point in time for the given key 142 */ 143 public boolean hasSameValueAsOpposite(String key) { 144 String value = getValue(key); 145 String oppositeValue = getOppositeValue(key); 146 return value != null && value.equals(oppositeValue); 147 } 148 149 /** 150 * Returns the type of point in time. 151 * @return the type of point in time 152 */ 153 public PointInTimeType getPointInTimeType() { 154 return pointInTimeType; 155 } 156 157 /** 158 * Determines if this is the current point in time. 159 * @return {@code true} if this is the current point in time 160 */ 161 public boolean isCurrentPointInTime() { 162 return pointInTimeType == PointInTimeType.CURRENT_POINT_IN_TIME; 163 } 164 165 /** 166 * Determines if this is the reference point in time. 167 * @return {@code true} if this is the reference point in time 168 */ 169 public boolean isReferencePointInTime() { 170 return pointInTimeType == PointInTimeType.REFERENCE_POINT_IN_TIME; 171 } 172 173 @Override 174 public int getColumnCount() { 175 return 3; 176 } 177 178 TwoColumnDiff.Item.DiffItemType getDiffItemType(String key, boolean isValue) { 179 if ((!hasTag(key) && isCurrentPointInTime()) || (!oppositeHasTag(key) && isReferencePointInTime())) { 180 return TwoColumnDiff.Item.DiffItemType.DELETED; 181 } else if ((!oppositeHasTag(key) && isCurrentPointInTime()) || (!hasTag(key) && isReferencePointInTime())) { 182 return TwoColumnDiff.Item.DiffItemType.INSERTED; 183 } else if (isValue && hasTag(key) && oppositeHasTag(key) && !hasSameValueAsOpposite(key)) { 184 return TwoColumnDiff.Item.DiffItemType.CHANGED; 185 } else { 186 return TwoColumnDiff.Item.DiffItemType.EMPTY; 187 } 188 } 189}