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

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