001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.history; 003 import static org.openstreetmap.josm.tools.I18n.tr; 004 005 import java.awt.Color; 006 import java.awt.GridBagConstraints; 007 import java.awt.GridBagLayout; 008 import java.awt.Insets; 009 import java.util.Observable; 010 import java.util.Observer; 011 012 import javax.swing.BorderFactory; 013 import javax.swing.JLabel; 014 import javax.swing.JPanel; 015 016 import org.openstreetmap.josm.data.coor.CoordinateFormat; 017 import org.openstreetmap.josm.data.coor.LatLon; 018 import org.openstreetmap.josm.data.osm.history.HistoryNode; 019 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive; 020 import org.openstreetmap.josm.gui.NavigatableComponent; 021 import org.openstreetmap.josm.tools.CheckParameterUtil; 022 023 /** 024 * An UI widget for displaying differences in the coordinates of two 025 * {@link HistoryNode}s. 026 * 027 */ 028 public class CoordinateInfoViewer extends JPanel { 029 030 /** background color used when the coordinates are different */ 031 public final static Color BGCOLOR_DIFFERENCE = new Color(255,197,197); 032 033 /** the model */ 034 private HistoryBrowserModel model; 035 /** the common info panel for the history node in role REFERENCE_POINT_IN_TIME */ 036 private VersionInfoPanel referenceInfoPanel; 037 /** the common info panel for the history node in role CURRENT_POINT_IN_TIME */ 038 private VersionInfoPanel currentInfoPanel; 039 /** the info panel for coordinates for the node in role REFERENCE_POINT_IN_TIME */ 040 private LatLonViewer referenceLatLonViewer; 041 /** the info panel for coordinates for the node in role CURRENT_POINT_IN_TIME */ 042 private LatLonViewer currentLatLonViewer; 043 /** the info panel for distance between the two coordinates */ 044 private DistanceViewer distanceViewer; 045 046 protected void build() { 047 setLayout(new GridBagLayout()); 048 GridBagConstraints gc = new GridBagConstraints(); 049 050 // --------------------------- 051 gc.gridx = 0; 052 gc.gridy = 0; 053 gc.gridwidth = 1; 054 gc.gridheight = 1; 055 gc.weightx = 0.5; 056 gc.weighty = 0.0; 057 gc.insets = new Insets(5,5,5,0); 058 gc.fill = GridBagConstraints.HORIZONTAL; 059 gc.anchor = GridBagConstraints.FIRST_LINE_START; 060 referenceInfoPanel = new VersionInfoPanel(model, PointInTimeType.REFERENCE_POINT_IN_TIME); 061 add(referenceInfoPanel,gc); 062 063 gc.gridx = 1; 064 gc.gridy = 0; 065 gc.fill = GridBagConstraints.HORIZONTAL; 066 gc.weightx = 0.5; 067 gc.weighty = 0.0; 068 gc.anchor = GridBagConstraints.FIRST_LINE_START; 069 currentInfoPanel = new VersionInfoPanel(model, PointInTimeType.CURRENT_POINT_IN_TIME); 070 add(currentInfoPanel,gc); 071 072 // --------------------------- 073 // the two coordinate panels 074 gc.gridx = 0; 075 gc.gridy = 1; 076 gc.weightx = 0.5; 077 gc.weighty = 1.0; 078 gc.fill = GridBagConstraints.BOTH; 079 gc.anchor = GridBagConstraints.NORTHWEST; 080 add(referenceLatLonViewer = new LatLonViewer(model, PointInTimeType.REFERENCE_POINT_IN_TIME), gc); 081 082 gc.gridx = 1; 083 gc.gridy = 1; 084 gc.weightx = 0.5; 085 gc.weighty = 1.0; 086 gc.fill = GridBagConstraints.BOTH; 087 gc.anchor = GridBagConstraints.NORTHWEST; 088 add(currentLatLonViewer = new LatLonViewer(model, PointInTimeType.CURRENT_POINT_IN_TIME), gc); 089 090 // -------------------- 091 // the distance panel 092 gc.gridx = 0; 093 gc.gridy = 2; 094 gc.gridwidth = 2; 095 gc.fill = GridBagConstraints.HORIZONTAL; 096 gc.weightx = 1.0; 097 gc.weighty = 0.0; 098 add(distanceViewer = new DistanceViewer(model), gc); 099 } 100 101 /** 102 * 103 * @param model the model. Must not be null. 104 * @throws IllegalArgumentException thrown if model is null 105 */ 106 public CoordinateInfoViewer(HistoryBrowserModel model) throws IllegalArgumentException{ 107 CheckParameterUtil.ensureParameterNotNull(model, "model"); 108 setModel(model); 109 build(); 110 registerAsObserver(model); 111 } 112 113 protected void unregisterAsObserver(HistoryBrowserModel model) { 114 if (currentInfoPanel != null) { 115 model.deleteObserver(currentInfoPanel); 116 } 117 if (referenceInfoPanel != null) { 118 model.deleteObserver(referenceInfoPanel); 119 } 120 if (currentLatLonViewer != null) { 121 model.deleteObserver(currentLatLonViewer); 122 } 123 if (referenceLatLonViewer != null) { 124 model.deleteObserver(referenceLatLonViewer); 125 } 126 if (distanceViewer != null) { 127 model.deleteObserver(distanceViewer); 128 } 129 } 130 131 protected void registerAsObserver(HistoryBrowserModel model) { 132 if (currentInfoPanel != null) { 133 model.addObserver(currentInfoPanel); 134 } 135 if (referenceInfoPanel != null) { 136 model.addObserver(referenceInfoPanel); 137 } 138 if (currentLatLonViewer != null) { 139 model.addObserver(currentLatLonViewer); 140 } 141 if (referenceLatLonViewer != null) { 142 model.addObserver(referenceLatLonViewer); 143 } 144 if (distanceViewer != null) { 145 model.addObserver(distanceViewer); 146 } 147 } 148 149 /** 150 * Sets the model for this viewer 151 * 152 * @param model the model. 153 */ 154 public void setModel(HistoryBrowserModel model) { 155 if (this.model != null) { 156 unregisterAsObserver(model); 157 } 158 this.model = model; 159 if (this.model != null) { 160 registerAsObserver(model); 161 } 162 } 163 164 /** 165 * A UI widgets which displays the Lan/Lon-coordinates of a 166 * {@link HistoryNode}. 167 * 168 */ 169 private static class LatLonViewer extends JPanel implements Observer{ 170 171 private JLabel lblLat; 172 private JLabel lblLon; 173 private HistoryBrowserModel model; 174 private PointInTimeType role; 175 176 protected HistoryOsmPrimitive getPrimitive() { 177 if (model == null || role == null) 178 return null; 179 return model.getPointInTime(role); 180 } 181 182 protected HistoryOsmPrimitive getOppositePrimitive() { 183 if (model == null || role == null) 184 return null; 185 return model.getPointInTime(role.opposite()); 186 } 187 188 protected void build() { 189 setLayout(new GridBagLayout()); 190 setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY)); 191 GridBagConstraints gc = new GridBagConstraints(); 192 193 // -------- 194 gc.gridx = 0; 195 gc.gridy = 0; 196 gc.fill = GridBagConstraints.NONE; 197 gc.weightx = 0.0; 198 gc.insets = new Insets(5,5,5,5); 199 gc.anchor = GridBagConstraints.NORTHWEST; 200 add(new JLabel(tr("Latitude: ")), gc); 201 202 // -------- 203 gc.gridx = 1; 204 gc.gridy = 0; 205 gc.fill = GridBagConstraints.HORIZONTAL; 206 gc.weightx = 1.0; 207 add(lblLat = new JLabel(), gc); 208 lblLat.setBackground(Color.WHITE); 209 lblLat.setOpaque(true); 210 lblLat.setBorder(BorderFactory.createEmptyBorder(2,2,2,2)); 211 212 // -------- 213 gc.gridx = 0; 214 gc.gridy = 1; 215 gc.fill = GridBagConstraints.NONE; 216 gc.weightx = 0.0; 217 gc.anchor = GridBagConstraints.NORTHWEST; 218 add(new JLabel(tr("Longitude: ")), gc); 219 220 // -------- 221 gc.gridx = 1; 222 gc.gridy = 1; 223 gc.fill = GridBagConstraints.HORIZONTAL; 224 gc.weightx = 1.0; 225 add(lblLon = new JLabel(), gc); 226 lblLon.setBackground(Color.WHITE); 227 lblLon.setOpaque(true); 228 lblLon.setBorder(BorderFactory.createEmptyBorder(2,2,2,2)); 229 230 // fill the remaining space 231 gc.gridx = 0; 232 gc.gridy = 2; 233 gc.gridwidth = 2; 234 gc.fill = GridBagConstraints.BOTH; 235 gc.weightx = 1.0; 236 gc.weighty = 1.0; 237 add(new JPanel(), gc); 238 } 239 240 /** 241 * 242 * @param model a model 243 * @param role the role for this viewer. 244 */ 245 public LatLonViewer(HistoryBrowserModel model, PointInTimeType role) { 246 build(); 247 this.model = model; 248 this.role = role; 249 } 250 251 protected void refresh() { 252 HistoryOsmPrimitive p = getPrimitive(); 253 HistoryOsmPrimitive opposite = getOppositePrimitive(); 254 if (p == null || ! ( p instanceof HistoryNode)) return; 255 if (opposite == null || ! (opposite instanceof HistoryNode)) return; 256 HistoryNode node = (HistoryNode)p; 257 HistoryNode oppositeNode = (HistoryNode) opposite; 258 259 LatLon coord = node.getCoords(); 260 LatLon oppositeCoord = oppositeNode.getCoords(); 261 262 // display the coordinates 263 // 264 lblLat.setText(coord != null ? coord.latToString(CoordinateFormat.DECIMAL_DEGREES) : tr("(none)")); 265 lblLon.setText(coord != null ? coord.lonToString(CoordinateFormat.DECIMAL_DEGREES) : tr("(none)")); 266 267 // update background color to reflect differences in the coordinates 268 // 269 if (coord == oppositeCoord || 270 (coord != null && oppositeCoord != null && coord.lat() == oppositeCoord.lat())) { 271 lblLat.setBackground(Color.WHITE); 272 } else { 273 lblLat.setBackground(BGCOLOR_DIFFERENCE); 274 } 275 if (coord == oppositeCoord || 276 (coord != null && oppositeCoord != null && coord.lon() == oppositeCoord.lon())) { 277 lblLon.setBackground(Color.WHITE); 278 } else { 279 lblLon.setBackground(BGCOLOR_DIFFERENCE); 280 } 281 } 282 283 public void update(Observable o, Object arg) { 284 refresh(); 285 } 286 } 287 288 private static class DistanceViewer extends LatLonViewer { 289 290 private JLabel lblDistance; 291 292 public DistanceViewer(HistoryBrowserModel model) { 293 super(model, PointInTimeType.REFERENCE_POINT_IN_TIME); 294 } 295 296 protected void build() { 297 setLayout(new GridBagLayout()); 298 setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY)); 299 GridBagConstraints gc = new GridBagConstraints(); 300 301 // -------- 302 gc.gridx = 0; 303 gc.gridy = 0; 304 gc.fill = GridBagConstraints.NONE; 305 gc.weightx = 0.0; 306 gc.insets = new Insets(5,5,5,5); 307 gc.anchor = GridBagConstraints.NORTHWEST; 308 add(new JLabel(tr("Distance: ")), gc); 309 310 // -------- 311 gc.gridx = 1; 312 gc.gridy = 0; 313 gc.fill = GridBagConstraints.HORIZONTAL; 314 gc.weightx = 1.0; 315 add(lblDistance = new JLabel(), gc); 316 lblDistance.setBackground(Color.WHITE); 317 lblDistance.setOpaque(true); 318 lblDistance.setBorder(BorderFactory.createEmptyBorder(2,2,2,2)); 319 } 320 321 protected void refresh() { 322 HistoryOsmPrimitive p = getPrimitive(); 323 HistoryOsmPrimitive opposite = getOppositePrimitive(); 324 if (p == null || ! ( p instanceof HistoryNode)) return; 325 if (opposite == null || ! (opposite instanceof HistoryNode)) return; 326 HistoryNode node = (HistoryNode) p; 327 HistoryNode oppositeNode = (HistoryNode) opposite; 328 329 LatLon coord = node.getCoords(); 330 LatLon oppositeCoord = oppositeNode.getCoords(); 331 332 // update distance 333 // 334 if (coord != null && oppositeCoord != null) { 335 double distance = coord.greatCircleDistance(oppositeCoord); 336 if (distance > 0) { 337 lblDistance.setBackground(BGCOLOR_DIFFERENCE); 338 } else { 339 lblDistance.setBackground(Color.WHITE); 340 } 341 lblDistance.setText(NavigatableComponent.getDistText(distance)); 342 } else { 343 lblDistance.setBackground(coord != oppositeCoord ? BGCOLOR_DIFFERENCE : Color.WHITE); 344 lblDistance.setText(tr("(none)")); 345 } 346 } 347 } 348 }