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 }