source: josm/src/org/openstreetmap/josm/gui/MapStatus.java@ 17

Last change on this file since 17 was 17, checked in by imi, 19 years ago
  • added Layer support
  • added support for raw GPS data
  • fixed tooltips
  • added options for loading gpx files
File size: 6.2 KB
Line 
1package org.openstreetmap.josm.gui;
2
3import java.awt.AWTEvent;
4import java.awt.Point;
5import java.awt.Toolkit;
6import java.awt.event.AWTEventListener;
7import java.awt.event.InputEvent;
8import java.awt.event.MouseEvent;
9import java.awt.event.MouseMotionListener;
10import java.beans.PropertyChangeEvent;
11import java.beans.PropertyChangeListener;
12import java.util.Map.Entry;
13
14import javax.swing.BorderFactory;
15import javax.swing.BoxLayout;
16import javax.swing.JLabel;
17import javax.swing.JPanel;
18import javax.swing.JTextField;
19import javax.swing.Popup;
20import javax.swing.PopupFactory;
21
22import org.openstreetmap.josm.data.GeoPoint;
23import org.openstreetmap.josm.data.osm.Key;
24import org.openstreetmap.josm.data.osm.OsmPrimitive;
25import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
26
27/**
28 * A component that manages some status information display about the map.
29 * It keeps a status line below the map up to date and displays some tooltip
30 * information if the user hold the mouse long enough at some point.
31 *
32 * All this is done in background to not disturb other processes.
33 *
34 * The background thread does not alter any data of the map (read only thread).
35 * Also it is rather fail safe. In case of some error in the data, it just do
36 * nothing instead of whining and complaining.
37 *
38 * @author imi
39 */
40public class MapStatus extends JPanel {
41
42 /**
43 * The MapView this status belongs.
44 */
45 final MapView mv;
46 /**
47 * The position of the mouse cursor.
48 */
49 private JTextField positionText = new JTextField("-000.00000000000000 -000.00000000000000".length());
50 /**
51 * The field holding the name of the object under the mouse.
52 */
53 private JTextField nameText = new JTextField(30);
54
55 /**
56 * The collector class that waits for notification and then update
57 * the display objects.
58 *
59 * @author imi
60 */
61 private final class Collector implements Runnable {
62 /**
63 * The last object displayed in status line.
64 */
65 OsmPrimitive osmStatus;
66 /**
67 * A visitor to retrieve name information about the osm primitive
68 */
69 private SelectionComponentVisitor visitor = new SelectionComponentVisitor();
70 /**
71 * The old modifiers, that was pressed the last time this collector ran.
72 */
73 private int oldModifiers;
74 /**
75 * The popup displayed to show additional information
76 */
77 private Popup popup;
78 /**
79 * Signals the collector to shut down on next event.
80 */
81 boolean exitCollector = false;
82
83 /**
84 * Execution function for the Collector.
85 */
86 public void run() {
87 for (;;) {
88 MouseState ms = new MouseState();
89 synchronized (this) {
90 try {wait();} catch (InterruptedException e) {}
91 ms.modifiers = mouseState.modifiers;
92 ms.mousePos = mouseState.mousePos;
93 }
94 if (exitCollector)
95 return;
96 if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null)
97 continue; // freeze display when holding down ctrl
98 OsmPrimitive osm = mv.getNearest(ms.mousePos, (ms.modifiers & MouseEvent.ALT_DOWN_MASK) != 0);
99 if (osm == osmStatus && ms.modifiers == oldModifiers)
100 continue;
101 osmStatus = osm;
102 oldModifiers = ms.modifiers;
103 if (osm != null) {
104 osm.visit(visitor);
105 nameText.setText(visitor.name);
106 } else
107 nameText.setText("");
108
109 // Popup Information
110 if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 && osm != null) {
111 if (popup != null)
112 popup.hide();
113
114 StringBuilder text = new StringBuilder("<html>");
115 text.append(visitor.name);
116 if (osm.keys != null) {
117 for (Entry<Key, String> e : osm.keys.entrySet()) {
118 text.append("<br>");
119 text.append(e.getKey().name);
120 text.append("=");
121 text.append(e.getValue());
122 }
123 }
124 JLabel l = new JLabel(text.toString(), visitor.icon, JLabel.HORIZONTAL);
125 l.setVerticalTextPosition(JLabel.TOP);
126
127 Point p = mv.getLocationOnScreen();
128 popup = PopupFactory.getSharedInstance().getPopup(mv, l, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16);
129 popup.show();
130 } else if (popup != null) {
131 popup.hide();
132 popup = null;
133 }
134 }
135 }
136 }
137
138 /**
139 * Everything, the collector is interested of. Access must be synchronized.
140 * @author imi
141 */
142 class MouseState {
143 Point mousePos;
144 int modifiers;
145 }
146 /**
147 * The last sent mouse movement event.
148 */
149 private MouseState mouseState = new MouseState();
150
151 /**
152 * Construct a new MapStatus and attach it to the map view.
153 * @param mv The MapView the status line is part of.
154 */
155 public MapStatus(final MapFrame mapFrame) {
156 this.mv = mapFrame.mapView;
157
158 // Listen for mouse movements and set the position text field
159 mv.addMouseMotionListener(new MouseMotionListener(){
160 public void mouseDragged(MouseEvent e) {
161 mouseMoved(e);
162 }
163 public void mouseMoved(MouseEvent e) {
164 // Do not update the view, if ctrl is pressed.
165 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
166 GeoPoint p = mv.getPoint(e.getX(),e.getY(),true);
167 positionText.setText(p.lat+" "+p.lon);
168 }
169 }
170 });
171
172 positionText.setEditable(false);
173 nameText.setEditable(false);
174 setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
175 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
176 add(new JLabel("Lat/Lon "));
177 add(positionText);
178 add(new JLabel(" Object "));
179 add(nameText);
180
181 // The background thread
182 final Collector collector = new Collector();
183 new Thread(collector).start();
184
185 // Listen to keyboard/mouse events for pressing/releasing alt key and
186 // inform the collector.
187 Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
188 public void eventDispatched(AWTEvent event) {
189 synchronized (collector) {
190 mouseState.modifiers = ((InputEvent)event).getModifiersEx();
191 if (event instanceof MouseEvent)
192 mouseState.mousePos = ((MouseEvent)event).getPoint();
193 collector.notify();
194 }
195 }
196 }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
197
198 // listen for shutdowns to cancel the background thread
199 mapFrame.addPropertyChangeListener("visible", new PropertyChangeListener(){
200 public void propertyChange(PropertyChangeEvent evt) {
201 if (evt.getNewValue() == Boolean.FALSE) {
202 collector.exitCollector = true;
203 synchronized (collector) {
204 collector.notify();
205 }
206 }
207 }
208 });
209 }
210}
Note: See TracBrowser for help on using the repository browser.