source: osm/applications/editors/josm/plugins/NanoLog/src/nanolog/NanoLogLayer.java@ 30737

Last change on this file since 30737 was 30737, checked in by donvip, 11 years ago

[josm_plugins] fix Java 7 / unused code warnings

File size: 12.4 KB
Line 
1package nanolog;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.Color;
6import java.awt.Graphics2D;
7import java.awt.Point;
8import java.awt.event.ActionEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.io.BufferedReader;
12import java.io.File;
13import java.io.FileInputStream;
14import java.io.IOException;
15import java.io.InputStreamReader;
16import java.text.ParseException;
17import java.text.SimpleDateFormat;
18import java.util.ArrayList;
19import java.util.Collections;
20import java.util.Date;
21import java.util.HashSet;
22import java.util.List;
23import java.util.Set;
24import java.util.regex.Matcher;
25import java.util.regex.Pattern;
26
27import javax.swing.Action;
28import javax.swing.Icon;
29import javax.swing.JOptionPane;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.actions.JosmAction;
33import org.openstreetmap.josm.actions.RenameLayerAction;
34import org.openstreetmap.josm.data.Bounds;
35import org.openstreetmap.josm.data.coor.EastNorth;
36import org.openstreetmap.josm.data.coor.LatLon;
37import org.openstreetmap.josm.data.gpx.WayPoint;
38import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
39import org.openstreetmap.josm.gui.MapView;
40import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
41import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
42import org.openstreetmap.josm.gui.layer.GpxLayer;
43import org.openstreetmap.josm.gui.layer.JumpToMarkerActions;
44import org.openstreetmap.josm.gui.layer.Layer;
45import org.openstreetmap.josm.tools.ImageProvider;
46
47/**
48 * NanoLog layer: a set of points that can be georeferenced.
49 *
50 * @author zverik
51 */
52public class NanoLogLayer extends Layer implements JumpToMarkerActions.JumpToMarkerLayer {
53
54 private List<NanoLogEntry> log;
55 private int selectedEntry;
56 private final Set<NanoLogLayerListener> listeners = new HashSet<>();
57 private NLLMouseAdapter mouseListener;
58
59 public NanoLogLayer( List<NanoLogEntry> entries ) {
60 super(tr("NanoLog"));
61 log = new ArrayList<>(entries);
62 selectedEntry = -1;
63 mouseListener = new NLLMouseAdapter();
64 Main.map.mapView.addMouseListener(mouseListener);
65 Main.map.mapView.addMouseMotionListener(mouseListener);
66 }
67
68 @Override
69 public void destroy() {
70 Main.map.mapView.removeMouseListener(mouseListener);
71 Main.map.mapView.removeMouseMotionListener(mouseListener);
72 super.destroy();
73 }
74
75 public NanoLogLayer( File file ) throws IOException {
76 this(readNanoLog(file));
77 }
78
79 public void addListener( NanoLogLayerListener listener ) {
80 listeners.add(listener);
81 }
82
83 public void removeListener( NanoLogLayerListener listener ) {
84 listeners.remove(listener);
85 }
86
87 protected void fireMarkersChanged() {
88 for( NanoLogLayerListener listener : listeners )
89 listener.markersUpdated(this);
90 }
91
92 protected void fireMarkerSelected() {
93 for( NanoLogLayerListener listener : listeners )
94 listener.markerActivated(this, selectedEntry < 0 ? null : log.get(selectedEntry));
95 }
96
97 public List<NanoLogEntry> getEntries() {
98 return Collections.unmodifiableList(log);
99 }
100
101 public static List<NanoLogEntry> readNanoLog( File file ) throws IOException {
102 final Pattern NANOLOG_LINE = Pattern.compile("(.+?)\\t(.+?)(?:\\s*\\{\\{(-?\\d+\\.\\d+),\\s*(-?\\d+\\.\\d+)(?:,\\s*(\\d+))?\\}\\})?");
103 final SimpleDateFormat fmt = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.SS");
104 List<NanoLogEntry> result = new ArrayList<>();
105 BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
106 while( r.ready() ) {
107 String line = r.readLine();
108 if( line != null ) {
109 Matcher m = NANOLOG_LINE.matcher(line);
110 if( m.matches() ) {
111 String time = m.group(1);
112 String message = m.group(2);
113 String lat = m.group(3);
114 String lon = m.group(4);
115 String dir = m.group(5);
116 Date timeDate = null;
117 try {
118 timeDate = fmt.parse(time);
119 } catch( ParseException e ) {
120 }
121 if( message == null || message.length() == 0 || timeDate == null )
122 continue;
123 LatLon pos = null;
124 Integer direction = null;
125 if( lat != null && lon != null ) {
126 try {
127 pos = new LatLon(Double.parseDouble(lat), Double.parseDouble(lon));
128 direction = new Integer(dir);
129 } catch( NumberFormatException e ) {
130 // well...
131 }
132 }
133 NanoLogEntry entry = new NanoLogEntry(timeDate, message, pos, direction);
134 result.add(entry);
135 }
136 }
137 }
138 r.close();
139 return result;
140 }
141
142 @Override
143 public void paint( Graphics2D g, MapView mv, Bounds box ) {
144 // todo
145 for( int i = 0; i < log.size(); i++ ) {
146 NanoLogEntry entry = log.get(i);
147 int radius = 4;
148 if( entry.getPos() != null ) {
149 Point p = mv.getPoint(entry.getPos());
150 g.setColor(selectedEntry == i ? Color.red : Color.yellow);
151 g.fillOval(p.x - radius, p.y - radius, radius * 2, radius * 2);
152 }
153 }
154 }
155
156 @Override
157 public Icon getIcon() {
158 return ImageProvider.get("nanolog.png");
159 }
160
161 @Override
162 public String getToolTipText() {
163 return tr("NanoLog of {0} entries", log.size());
164 }
165
166 @Override
167 public void mergeFrom( Layer from ) {
168 // todo
169 }
170
171 @Override
172 public boolean isMergable( Layer other ) {
173 return other instanceof NanoLogLayer;
174 }
175
176 @Override
177 public void visitBoundingBox( BoundingXYVisitor v ) {
178 for( NanoLogEntry entry : log )
179 v.visit(entry.getPos());
180 }
181
182 @Override
183 public Object getInfoComponent() {
184 StringBuilder b = new StringBuilder();
185 int cnt = 0;
186 for( NanoLogEntry e : log )
187 if( e.getPos() != null )
188 cnt++;
189 b.append(tr("NanoLog of {0} lines, {1} of them with coordinates.", log.size(), cnt));
190 return b.toString();
191 }
192
193 @Override
194 public Action[] getMenuEntries() {
195 return new Action[] {
196 LayerListDialog.getInstance().createShowHideLayerAction(),
197 LayerListDialog.getInstance().createDeleteLayerAction(),
198 new RenameLayerAction(null, this),
199 SeparatorLayerAction.INSTANCE,
200 new CorrelateEntries(true),
201 new CorrelateEntries(false),
202 new SaveLayer(),
203 SeparatorLayerAction.INSTANCE,
204 new LayerListPopup.InfoAction(this)
205 };
206 }
207
208 @Override
209 public void jumpToNextMarker() {
210 selectedEntry++;
211 if( selectedEntry < 0 )
212 selectedEntry = 0;
213 else if( selectedEntry >= log.size() )
214 selectedEntry = log.size() - 1;
215 Main.map.repaint();
216 }
217
218 @Override
219 public void jumpToPreviousMarker() {
220 selectedEntry--;
221 if( selectedEntry < 0 )
222 selectedEntry = 0;
223 else if( selectedEntry >= log.size() )
224 selectedEntry = log.size() - 1;
225 Main.map.repaint();
226 }
227
228 protected void setSelected( int i ) {
229 int newSelected = i >= 0 && i < log.size() ? i : -1;
230 if( newSelected != selectedEntry ) {
231// System.out.println("selected: " + log.get(newSelected).getMessage());
232 selectedEntry = newSelected;
233 fireMarkerSelected();
234 Main.map.mapView.repaint();
235 }
236 }
237
238 public void setSelected( NanoLogEntry entry ) {
239 if( entry == null )
240 setSelected(-1);
241 else {
242 for( int i = 0; i < log.size(); i++ ) {
243 if( entry.equals(log.get(i)) ) {
244 setSelected(i);
245 break;
246 }
247 }
248 }
249 }
250
251 private class NLLMouseAdapter extends MouseAdapter {
252 private int dragging;
253
254 public int nearestEntry( MouseEvent e ) {
255 LatLon ll = Main.map.mapView.getLatLon(e.getX(), e.getY());
256 int radius = 8;
257 if( ll != null ) {
258 LatLon lld = Main.map.mapView.getLatLon(e.getX() + radius, e.getY() + radius);
259 double distance = Math.max(lld.lat() - ll.lat(), lld.lon() - ll.lon());
260 boolean selectedIsSelected = false;
261 int newSelected = -1;
262 for( int i = 0; i < log.size(); i++ ) {
263 if( log.get(i).getPos() != null && log.get(i).getPos().distance(ll) < distance ) {
264 newSelected = i;
265 if( i == selectedEntry )
266 selectedIsSelected = true;
267 }
268 }
269 if( newSelected >= 0 )
270 return selectedIsSelected ? selectedEntry : newSelected;
271 }
272 return -1;
273 }
274
275 @Override
276 public void mouseMoved( MouseEvent e ) {
277 int nearest = nearestEntry(e);
278 if( nearest > 0 )
279 setSelected(nearest);
280 }
281
282 @Override
283 public void mouseDragged( MouseEvent e ) {
284 doDrag(e);
285 }
286
287 @Override
288 public void mouseReleased( MouseEvent e ) {
289 if( dragging > 0 ) {
290 dragging = 0;
291 }
292 }
293
294 @Override
295 public void mousePressed( MouseEvent e ) {
296 int nearest = nearestEntry(e);
297 if( nearest > 0 && Main.map.mapView.getActiveLayer() == NanoLogLayer.this ) {
298 dragging = nearest;
299 doDrag(e);
300 }
301 }
302
303 private void doDrag( MouseEvent e ) {
304 if( dragging > 0 )
305 dragTo(dragging, e.getX(), e.getY());
306 }
307 }
308
309 protected void dragTo( int entry, int x, int y ) {
310 GpxLayer gpx = GPXChooser.topLayer();
311 if( gpx == null )
312 return;
313 EastNorth eastNorth = Main.map.mapView.getEastNorth(x, y);
314 double tolerance = eastNorth.distance(Main.map.mapView.getEastNorth(x + 300, y));
315 WayPoint wp = gpx.data.nearestPointOnTrack(eastNorth, tolerance);
316 if( wp == null )
317 return;
318 long newTime = Correlator.getGpxDate(gpx.data, wp.getCoor());
319 if( newTime <= 0 )
320 return;
321 Correlator.revertPos(log);
322 Correlator.correlate(log, gpx.data, log.get(entry).getTime().getTime() - newTime);
323 Main.map.mapView.repaint();
324 }
325
326 private class CorrelateEntries extends JosmAction {
327 private boolean toZero;
328
329 public CorrelateEntries( boolean toZero ) {
330 super(toZero ? tr("Correlate with GPX...") : tr("Put on GPX..."), "nanolog/correlate", tr("Correlate entries with GPS trace"), null, false);
331 this.toZero = toZero;
332 }
333
334 @Override
335 public void actionPerformed( ActionEvent e ) {
336 // 1. Select GPX trace or display message to load one
337 // (better yet, disable when no GPX traces)
338 GpxLayer layer = GPXChooser.chooseLayer();
339 // 2. Correlate by default, sticking by date
340 // (if does not match, shift so hours-minutes stay)
341 if( layer != null ) {
342 long offset = toZero ? 0 : Correlator.crudeMatch(log, layer.data);
343 Correlator.revertPos(log);
344 Correlator.correlate(log, layer.data, offset);
345 fireMarkersChanged();
346 Main.map.mapView.repaint();
347 }
348 // 3. Show non-modal (?) window with a slider and a text input
349 // (todo: better slider, like in blender)
350 }
351 }
352
353 private class SaveLayer extends JosmAction {
354
355 public SaveLayer() {
356 super(tr("Save layer..."), "nanolog/save", tr("Save NanoLog layer"), null, false);
357 }
358
359 @Override
360 public void actionPerformed( ActionEvent e ) {
361 // todo
362 JOptionPane.showMessageDialog(Main.parent, "Sorry, no saving yet", "NanoLog", JOptionPane.ERROR_MESSAGE);
363 }
364 }
365
366 public static interface NanoLogLayerListener {
367 void markersUpdated( NanoLogLayer layer );
368 void markerActivated( NanoLogLayer layer, NanoLogEntry entry );
369 }
370}
Note: See TracBrowser for help on using the repository browser.