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

Last change on this file since 142 was 142, checked in by imi, 18 years ago
  • added External Tool support (no gui configuration yet)
  • applied patch for bug that Save action does not set filename (thanks Dean)
  • fixed case sensitiveness of search tool (now insensitive, like google)
File size: 7.7 KB
Line 
1package org.openstreetmap.josm.gui;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.AWTEvent;
6import java.awt.Cursor;
7import java.awt.Font;
8import java.awt.GridBagLayout;
9import java.awt.Point;
10import java.awt.Toolkit;
11import java.awt.event.AWTEventListener;
12import java.awt.event.InputEvent;
13import java.awt.event.MouseAdapter;
14import java.awt.event.MouseEvent;
15import java.awt.event.MouseMotionListener;
16import java.util.Collection;
17import java.util.ConcurrentModificationException;
18import java.util.Map.Entry;
19
20import javax.swing.BorderFactory;
21import javax.swing.BoxLayout;
22import javax.swing.JLabel;
23import javax.swing.JPanel;
24import javax.swing.JTextField;
25import javax.swing.Popup;
26import javax.swing.PopupFactory;
27
28import org.openstreetmap.josm.Main;
29import org.openstreetmap.josm.data.coor.LatLon;
30import org.openstreetmap.josm.data.osm.OsmPrimitive;
31import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
32import org.openstreetmap.josm.tools.GBC;
33
34/**
35 * A component that manages some status information display about the map.
36 * It keeps a status line below the map up to date and displays some tooltip
37 * information if the user hold the mouse long enough at some point.
38 *
39 * All this is done in background to not disturb other processes.
40 *
41 * The background thread does not alter any data of the map (read only thread).
42 * Also it is rather fail safe. In case of some error in the data, it just do
43 * nothing instead of whining and complaining.
44 *
45 * @author imi
46 */
47public class MapStatus extends JPanel {
48
49 /**
50 * The MapView this status belongs.
51 */
52 final MapView mv;
53 /**
54 * The position of the mouse cursor.
55 */
56 JTextField positionText = new JTextField("-000.00000000000000 -000.00000000000000".length());
57 /**
58 * The field holding the name of the object under the mouse.
59 */
60 JTextField nameText = new JTextField(30);
61
62 /**
63 * The collector class that waits for notification and then update
64 * the display objects.
65 *
66 * @author imi
67 */
68 private final class Collector implements Runnable {
69 /**
70 * The last object displayed in status line.
71 */
72 Collection<OsmPrimitive> osmStatus;
73 /**
74 * The old modifiers, that was pressed the last time this collector ran.
75 */
76 private int oldModifiers;
77 /**
78 * The popup displayed to show additional information
79 */
80 private Popup popup;
81
82 private MapFrame parent;
83
84 public Collector(MapFrame parent) {
85 this.parent = parent;
86 }
87
88 /**
89 * Execution function for the Collector.
90 */
91 public void run() {
92 for (;;) {
93 MouseState ms = new MouseState();
94 synchronized (this) {
95 try {wait();} catch (InterruptedException e) {}
96 ms.modifiers = mouseState.modifiers;
97 ms.mousePos = mouseState.mousePos;
98 }
99 if (parent != Main.map)
100 return; // exit, if new parent.
101 if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null)
102 continue; // freeze display when holding down ctrl
103
104 if (mv.center == null)
105 continue;
106
107 // This try/catch is a hack to stop the flooding bug reports about this.
108 // The exception needed to handle with in the first place, means that this
109 // access to the data need to be restarted, if the main thread modifies
110 // the data.
111 try {
112 Collection<OsmPrimitive> osms = mv.getAllNearest(ms.mousePos);
113
114 if (osms == null && osmStatus == null && ms.modifiers == oldModifiers)
115 continue;
116 if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers)
117 continue;
118
119 osmStatus = osms;
120 oldModifiers = ms.modifiers;
121
122 OsmPrimitive osmNearest = null;
123 // Set the text label in the bottom status bar
124 osmNearest = mv.getNearest(ms.mousePos, (ms.modifiers & MouseEvent.ALT_DOWN_MASK) != 0);
125 if (osmNearest != null) {
126 NameVisitor visitor = new NameVisitor();
127 osmNearest.visit(visitor);
128 nameText.setText(visitor.name);
129 } else
130 nameText.setText("");
131
132 // Popup Information
133 if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 && osms != null) {
134 if (popup != null)
135 popup.hide();
136
137 JPanel c = new JPanel(new GridBagLayout());
138 for (final OsmPrimitive osm : osms) {
139 NameVisitor visitor = new NameVisitor();
140 osm.visit(visitor);
141 final StringBuilder text = new StringBuilder();
142 if (osm.id == 0 || osm.modified)
143 visitor.name = "<i><b>"+visitor.name+"*</b></i>";
144 text.append(visitor.name);
145 if (osm.id != 0)
146 text.append("<br>id="+osm.id);
147 for (Entry<String, String> e : osm.entrySet())
148 text.append("<br>"+e.getKey()+"="+e.getValue());
149 final JLabel l = new JLabel("<html>"+text.toString()+"</html>", visitor.icon, JLabel.HORIZONTAL);
150 l.setFont(l.getFont().deriveFont(Font.PLAIN));
151 l.setVerticalTextPosition(JLabel.TOP);
152 l.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
153 l.addMouseListener(new MouseAdapter(){
154 @Override public void mouseEntered(MouseEvent e) {
155 l.setText("<html><u color='blue'>"+text.toString()+"</u></html>");
156 }
157 @Override public void mouseExited(MouseEvent e) {
158 l.setText("<html>"+text.toString()+"</html>");
159 }
160 @Override public void mouseClicked(MouseEvent e) {
161 Main.ds.setSelected(osm);
162 mv.repaint();
163 }
164 });
165 c.add(l, GBC.eol());
166 }
167
168 Point p = mv.getLocationOnScreen();
169 popup = PopupFactory.getSharedInstance().getPopup(mv, c, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16);
170 popup.show();
171 } else if (popup != null) {
172 popup.hide();
173 popup = null;
174 }
175 } catch (ConcurrentModificationException x) {
176 } catch (NullPointerException x) {
177 }
178 }
179 }
180 }
181
182 /**
183 * Everything, the collector is interested of. Access must be synchronized.
184 * @author imi
185 */
186 class MouseState {
187 Point mousePos;
188 int modifiers;
189 }
190 /**
191 * The last sent mouse movement event.
192 */
193 MouseState mouseState = new MouseState();
194
195 /**
196 * Construct a new MapStatus and attach it to the map view.
197 * @param mv The MapView the status line is part of.
198 */
199 public MapStatus(final MapFrame mapFrame) {
200 this.mv = mapFrame.mapView;
201
202 // Listen for mouse movements and set the position text field
203 mv.addMouseMotionListener(new MouseMotionListener(){
204 public void mouseDragged(MouseEvent e) {
205 mouseMoved(e);
206 }
207 public void mouseMoved(MouseEvent e) {
208 if (mv.center == null)
209 return;
210 // Do not update the view, if ctrl is pressed.
211 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
212 LatLon p = mv.getLatLon(e.getX(),e.getY());
213 positionText.setText(p.lat()+" "+p.lon());
214 }
215 }
216 });
217
218 positionText.setEditable(false);
219 nameText.setEditable(false);
220 setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
221 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
222 add(new JLabel(tr("Lat/Lon")+" "));
223 add(positionText);
224 add(new JLabel(" "+tr("Object")+" "));
225 add(nameText);
226
227 // The background thread
228 final Collector collector = new Collector(mapFrame);
229 new Thread(collector).start();
230
231 // Listen to keyboard/mouse events for pressing/releasing alt key and
232 // inform the collector.
233 Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
234 public void eventDispatched(AWTEvent event) {
235 synchronized (collector) {
236 mouseState.modifiers = ((InputEvent)event).getModifiersEx();
237 if (event instanceof MouseEvent)
238 mouseState.mousePos = ((MouseEvent)event).getPoint();
239 collector.notify();
240 }
241 }
242 }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
243 }
244}
Note: See TracBrowser for help on using the repository browser.