source: josm/trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java@ 9468

Last change on this file since 9468 was 9454, checked in by Don-vip, 8 years ago

checkstyle + add basic unit test

  • Property svn:eol-style set to native
File size: 14.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.history;
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.Color;
6import java.awt.GridBagConstraints;
7import java.awt.GridBagLayout;
8import java.awt.Insets;
9import java.util.Observable;
10import java.util.Observer;
11
12import javax.swing.BorderFactory;
13import javax.swing.JLabel;
14import javax.swing.JPanel;
15
16import org.openstreetmap.gui.jmapviewer.JMapViewer;
17import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
18import org.openstreetmap.josm.data.coor.CoordinateFormat;
19import org.openstreetmap.josm.data.coor.LatLon;
20import org.openstreetmap.josm.data.osm.history.HistoryNode;
21import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
22import org.openstreetmap.josm.gui.NavigatableComponent;
23import org.openstreetmap.josm.gui.util.GuiHelper;
24import org.openstreetmap.josm.tools.CheckParameterUtil;
25import org.openstreetmap.josm.tools.Pair;
26
27/**
28 * An UI widget for displaying differences in the coordinates of two
29 * {@link HistoryNode}s.
30 * @since 2243
31 */
32public class CoordinateInfoViewer extends JPanel {
33
34 /** the model */
35 private transient HistoryBrowserModel model;
36 /** the common info panel for the history node in role REFERENCE_POINT_IN_TIME */
37 private VersionInfoPanel referenceInfoPanel;
38 /** the common info panel for the history node in role CURRENT_POINT_IN_TIME */
39 private VersionInfoPanel currentInfoPanel;
40 /** the info panel for coordinates for the node in role REFERENCE_POINT_IN_TIME */
41 private LatLonViewer referenceLatLonViewer;
42 /** the info panel for coordinates for the node in role CURRENT_POINT_IN_TIME */
43 private LatLonViewer currentLatLonViewer;
44 /** the info panel for distance between the two coordinates */
45 private DistanceViewer distanceViewer;
46 /** the map panel showing the old+new coordinate */
47 private MapViewer mapViewer;
48
49 protected void build() {
50 setLayout(new GridBagLayout());
51 GridBagConstraints gc = new GridBagConstraints();
52
53 // ---------------------------
54 gc.gridx = 0;
55 gc.gridy = 0;
56 gc.gridwidth = 1;
57 gc.gridheight = 1;
58 gc.weightx = 0.5;
59 gc.weighty = 0.0;
60 gc.insets = new Insets(5, 5, 5, 0);
61 gc.fill = GridBagConstraints.HORIZONTAL;
62 gc.anchor = GridBagConstraints.FIRST_LINE_START;
63 referenceInfoPanel = new VersionInfoPanel(model, PointInTimeType.REFERENCE_POINT_IN_TIME);
64 add(referenceInfoPanel, gc);
65
66 gc.gridx = 1;
67 gc.gridy = 0;
68 gc.fill = GridBagConstraints.HORIZONTAL;
69 gc.weightx = 0.5;
70 gc.weighty = 0.0;
71 gc.anchor = GridBagConstraints.FIRST_LINE_START;
72 currentInfoPanel = new VersionInfoPanel(model, PointInTimeType.CURRENT_POINT_IN_TIME);
73 add(currentInfoPanel, gc);
74
75 // ---------------------------
76 // the two coordinate panels
77 gc.gridx = 0;
78 gc.gridy = 1;
79 gc.weightx = 0.5;
80 gc.weighty = 0.0;
81 gc.fill = GridBagConstraints.HORIZONTAL;
82 gc.anchor = GridBagConstraints.NORTHWEST;
83 add(referenceLatLonViewer = new LatLonViewer(model, PointInTimeType.REFERENCE_POINT_IN_TIME), gc);
84
85 gc.gridx = 1;
86 gc.gridy = 1;
87 gc.weightx = 0.5;
88 gc.weighty = 0.0;
89 gc.fill = GridBagConstraints.HORIZONTAL;
90 gc.anchor = GridBagConstraints.NORTHWEST;
91 add(currentLatLonViewer = new LatLonViewer(model, PointInTimeType.CURRENT_POINT_IN_TIME), gc);
92
93 // --------------------
94 // the distance panel
95 gc.gridx = 0;
96 gc.gridy = 2;
97 gc.gridwidth = 2;
98 gc.fill = GridBagConstraints.HORIZONTAL;
99 gc.weightx = 1.0;
100 gc.weighty = 0.0;
101 add(distanceViewer = new DistanceViewer(model), gc);
102
103 // the map panel
104 gc.gridx = 0;
105 gc.gridy = 3;
106 gc.gridwidth = 2;
107 gc.fill = GridBagConstraints.BOTH;
108 gc.weightx = 1.0;
109 gc.weighty = 1.0;
110 gc.insets = new Insets(5, 5, 5, 5);
111 add(mapViewer = new MapViewer(model), gc);
112 mapViewer.setZoomContolsVisible(false);
113 }
114
115 /**
116 * Constructs a new {@code CoordinateInfoViewer}.
117 * @param model the model. Must not be null.
118 * @throws IllegalArgumentException if model is null
119 */
120 public CoordinateInfoViewer(HistoryBrowserModel model) {
121 CheckParameterUtil.ensureParameterNotNull(model, "model");
122 setModel(model);
123 build();
124 registerAsObserver(model);
125 }
126
127 protected void unregisterAsObserver(HistoryBrowserModel model) {
128 if (currentInfoPanel != null) {
129 model.deleteObserver(currentInfoPanel);
130 }
131 if (referenceInfoPanel != null) {
132 model.deleteObserver(referenceInfoPanel);
133 }
134 if (currentLatLonViewer != null) {
135 model.deleteObserver(currentLatLonViewer);
136 }
137 if (referenceLatLonViewer != null) {
138 model.deleteObserver(referenceLatLonViewer);
139 }
140 if (distanceViewer != null) {
141 model.deleteObserver(distanceViewer);
142 }
143 if (mapViewer != null) {
144 model.deleteObserver(mapViewer);
145 }
146 }
147
148 protected void registerAsObserver(HistoryBrowserModel model) {
149 if (currentInfoPanel != null) {
150 model.addObserver(currentInfoPanel);
151 }
152 if (referenceInfoPanel != null) {
153 model.addObserver(referenceInfoPanel);
154 }
155 if (currentLatLonViewer != null) {
156 model.addObserver(currentLatLonViewer);
157 }
158 if (referenceLatLonViewer != null) {
159 model.addObserver(referenceLatLonViewer);
160 }
161 if (distanceViewer != null) {
162 model.addObserver(distanceViewer);
163 }
164 if (mapViewer != null) {
165 model.addObserver(mapViewer);
166 }
167 }
168
169 /**
170 * Sets the model for this viewer
171 *
172 * @param model the model.
173 */
174 public void setModel(HistoryBrowserModel model) {
175 if (this.model != null) {
176 unregisterAsObserver(model);
177 }
178 this.model = model;
179 if (this.model != null) {
180 registerAsObserver(model);
181 }
182 }
183
184 /**
185 * Pans the map to the old+new coordinate
186 * @see JMapViewer#setDisplayToFitMapMarkers()
187 */
188 public void setDisplayToFitMapMarkers() {
189 mapViewer.setDisplayToFitMapMarkers();
190 }
191
192 private static class Updater {
193 private final transient HistoryBrowserModel model;
194 private final PointInTimeType role;
195
196 protected Updater(HistoryBrowserModel model, PointInTimeType role) {
197 this.model = model;
198 this.role = role;
199 }
200
201 protected HistoryOsmPrimitive getPrimitive() {
202 if (model == null || role == null)
203 return null;
204 return model.getPointInTime(role);
205 }
206
207 protected HistoryOsmPrimitive getOppositePrimitive() {
208 if (model == null || role == null)
209 return null;
210 return model.getPointInTime(role.opposite());
211 }
212
213 protected final Pair<LatLon, LatLon> getCoordinates() {
214 HistoryOsmPrimitive p = getPrimitive();
215 HistoryOsmPrimitive opposite = getOppositePrimitive();
216 if (!(p instanceof HistoryNode)) return null;
217 if (!(opposite instanceof HistoryNode)) return null;
218 HistoryNode node = (HistoryNode) p;
219 HistoryNode oppositeNode = (HistoryNode) opposite;
220
221 return Pair.create(node.getCoords(), oppositeNode.getCoords());
222 }
223
224 }
225
226 /**
227 * A UI widgets which displays the Lan/Lon-coordinates of a
228 * {@link HistoryNode}.
229 *
230 */
231 private static class LatLonViewer extends JPanel implements Observer {
232
233 private JLabel lblLat;
234 private JLabel lblLon;
235 private final Updater updater;
236 private final Color modifiedColor;
237
238 protected void build() {
239 setLayout(new GridBagLayout());
240 setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
241 GridBagConstraints gc = new GridBagConstraints();
242
243 // --------
244 gc.gridx = 0;
245 gc.gridy = 0;
246 gc.fill = GridBagConstraints.NONE;
247 gc.weightx = 0.0;
248 gc.insets = new Insets(5, 5, 5, 5);
249 gc.anchor = GridBagConstraints.NORTHWEST;
250 add(new JLabel(tr("Latitude: ")), gc);
251
252 // --------
253 gc.gridx = 1;
254 gc.gridy = 0;
255 gc.fill = GridBagConstraints.HORIZONTAL;
256 gc.weightx = 1.0;
257 add(lblLat = new JLabel(), gc);
258 GuiHelper.setBackgroundReadable(lblLat, Color.WHITE);
259 lblLat.setOpaque(true);
260 lblLat.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
261
262 // --------
263 gc.gridx = 0;
264 gc.gridy = 1;
265 gc.fill = GridBagConstraints.NONE;
266 gc.weightx = 0.0;
267 gc.anchor = GridBagConstraints.NORTHWEST;
268 add(new JLabel(tr("Longitude: ")), gc);
269
270 // --------
271 gc.gridx = 1;
272 gc.gridy = 1;
273 gc.fill = GridBagConstraints.HORIZONTAL;
274 gc.weightx = 1.0;
275 add(lblLon = new JLabel(), gc);
276 GuiHelper.setBackgroundReadable(lblLon, Color.WHITE);
277 lblLon.setOpaque(true);
278 lblLon.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
279 }
280
281 /**
282 *
283 * @param model a model
284 * @param role the role for this viewer.
285 */
286 LatLonViewer(HistoryBrowserModel model, PointInTimeType role) {
287 this.updater = new Updater(model, role);
288 this.modifiedColor = PointInTimeType.CURRENT_POINT_IN_TIME.equals(role)
289 ? TwoColumnDiff.Item.DiffItemType.INSERTED.getColor()
290 : TwoColumnDiff.Item.DiffItemType.DELETED.getColor();
291 build();
292 }
293
294 protected void refresh() {
295 final Pair<LatLon, LatLon> coordinates = updater.getCoordinates();
296 if (coordinates == null) return;
297 final LatLon coord = coordinates.a;
298 final LatLon oppositeCoord = coordinates.b;
299
300 // display the coordinates
301 lblLat.setText(coord != null ? coord.latToString(CoordinateFormat.DECIMAL_DEGREES) : tr("(none)"));
302 lblLon.setText(coord != null ? coord.lonToString(CoordinateFormat.DECIMAL_DEGREES) : tr("(none)"));
303
304 // update background color to reflect differences in the coordinates
305 if (coord == oppositeCoord ||
306 (coord != null && oppositeCoord != null && coord.lat() == oppositeCoord.lat())) {
307 GuiHelper.setBackgroundReadable(lblLat, Color.WHITE);
308 } else {
309 GuiHelper.setBackgroundReadable(lblLat, modifiedColor);
310 }
311 if (coord == oppositeCoord ||
312 (coord != null && oppositeCoord != null && coord.lon() == oppositeCoord.lon())) {
313 GuiHelper.setBackgroundReadable(lblLon, Color.WHITE);
314 } else {
315 GuiHelper.setBackgroundReadable(lblLon, modifiedColor);
316 }
317 }
318
319 @Override
320 public void update(Observable o, Object arg) {
321 refresh();
322 }
323 }
324
325 private static class MapViewer extends JMapViewer implements Observer {
326
327 private final Updater updater;
328
329 MapViewer(HistoryBrowserModel model) {
330 this.updater = new Updater(model, PointInTimeType.REFERENCE_POINT_IN_TIME);
331 setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
332 }
333
334 @Override
335 public void update(Observable o, Object arg) {
336 final Pair<LatLon, LatLon> coordinates = updater.getCoordinates();
337 if (coordinates == null) {
338 return;
339 }
340
341 final MapMarkerDot oldMarker = new MapMarkerDot(coordinates.a.lat(), coordinates.a.lon());
342 final MapMarkerDot newMarker = new MapMarkerDot(coordinates.b.lat(), coordinates.b.lon());
343 oldMarker.setBackColor(TwoColumnDiff.Item.DiffItemType.DELETED.getColor());
344 newMarker.setBackColor(TwoColumnDiff.Item.DiffItemType.INSERTED.getColor());
345
346 removeAllMapMarkers();
347 addMapMarker(oldMarker);
348 addMapMarker(newMarker);
349 setDisplayToFitMapMarkers();
350 }
351 }
352
353 private static class DistanceViewer extends JPanel implements Observer {
354
355 private JLabel lblDistance;
356 private final Updater updater;
357
358 DistanceViewer(HistoryBrowserModel model) {
359 this.updater = new Updater(model, PointInTimeType.REFERENCE_POINT_IN_TIME);
360 build();
361 }
362
363 protected void build() {
364 setLayout(new GridBagLayout());
365 setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
366 GridBagConstraints gc = new GridBagConstraints();
367
368 // --------
369 gc.gridx = 0;
370 gc.gridy = 0;
371 gc.fill = GridBagConstraints.NONE;
372 gc.weightx = 0.0;
373 gc.insets = new Insets(5, 5, 5, 5);
374 gc.anchor = GridBagConstraints.NORTHWEST;
375 add(new JLabel(tr("Distance: ")), gc);
376
377 // --------
378 gc.gridx = 1;
379 gc.gridy = 0;
380 gc.fill = GridBagConstraints.HORIZONTAL;
381 gc.weightx = 1.0;
382 add(lblDistance = new JLabel(), gc);
383 GuiHelper.setBackgroundReadable(lblDistance, Color.WHITE);
384 lblDistance.setOpaque(true);
385 lblDistance.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
386 }
387
388 protected void refresh() {
389 final Pair<LatLon, LatLon> coordinates = updater.getCoordinates();
390 if (coordinates == null) return;
391 final LatLon coord = coordinates.a;
392 final LatLon oppositeCoord = coordinates.b;
393
394 // update distance
395 //
396 if (coord != null && oppositeCoord != null) {
397 double distance = coord.greatCircleDistance(oppositeCoord);
398 GuiHelper.setBackgroundReadable(lblDistance, distance > 0
399 ? TwoColumnDiff.Item.DiffItemType.CHANGED.getColor()
400 : Color.WHITE);
401 lblDistance.setText(NavigatableComponent.getDistText(distance));
402 } else {
403 GuiHelper.setBackgroundReadable(lblDistance, coord != oppositeCoord
404 ? TwoColumnDiff.Item.DiffItemType.CHANGED.getColor()
405 : Color.WHITE);
406 lblDistance.setText(tr("(none)"));
407 }
408 }
409
410 @Override
411 public void update(Observable o, Object arg) {
412 refresh();
413 }
414 }
415}
Note: See TracBrowser for help on using the repository browser.