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

Last change on this file since 100 was 100, checked in by imi, 19 years ago
  • fixed JOSM crash when importing GeoImages on layers without timestamp
  • fixed merging: incomplete segments do not overwrite complete on ways
  • fixed focus when entering the popups from PropertyDialog
  • fixed broken "draw lines between gps points"
  • added doubleclick on bookmarklist
  • added background color configuration
  • added GpxImport to import 1.0 and 1.1 GPX files

This is release JOSM 1.3

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