// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.infomode; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.AWTEvent; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Stroke; import java.awt.Toolkit; import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; import javax.swing.Popup; import javax.swing.PopupFactory; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.mapmode.MapMode; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.coor.EastNorth; import org.openstreetmap.josm.data.gpx.GpxTrack; import org.openstreetmap.josm.data.gpx.GpxTrackSegment; import org.openstreetmap.josm.data.gpx.WayPoint; import org.openstreetmap.josm.gui.MapFrame; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.layer.GpxLayer; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.MapViewPaintable; import org.openstreetmap.josm.tools.Shortcut; class InfoMode extends MapMode implements MapViewPaintable, AWTEventListener { private MapView mv; private String statusText; //private boolean drawing; //private boolean ctrl; private boolean shift; //private boolean oldCtrl; //private boolean oldShift; private EastNorth pos; private WayPoint wpOld; private Popup oldPopup; private InfoPanel infoPanel; InfoMode(MapFrame mapFrame) { super(tr("InfoMode"), "infomode.png", tr("GPX info mode"), Shortcut.registerShortcut("mapmode:infomode", tr("Mode: {0}", tr("GPX info mode")), KeyEvent.VK_BACK_SLASH, Shortcut.DIRECT), mapFrame, Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); infoPanel = new InfoPanel(); } // <editor-fold defaultstate="collapsed" desc="Event listeners"> @Override public void enterMode() { if (!isEnabled()) return; super.enterMode(); mv = Main.map.mapView; Main.map.mapView.addMouseListener(this); Main.map.mapView.addMouseMotionListener(this); Main.map.mapView.addTemporaryLayer(this); /*if (!(Main.main.getActiveLayer() instanceof GpxLayer)) { boolean answer = ConditionalOptionPaneUtil.showConfirmationDialog( "scan_all_layers", Main.parent, tr("Please select GPX layer to view only its trackpoint info. Do you want to scan all GPX layers?"), tr("Select layer to scan"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_OPTION ); if(!answer) return; }*/ Main.map.statusLine.setHelpText(tr("Move the mouse to show trackpoint info for current layer. Hold shift to highlight tracks")); Main.map.statusLine.repaint(); try { Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK); } catch (SecurityException ex) { Main.error(ex); } } @Override public void exitMode() { super.exitMode(); Main.map.mapView.removeMouseListener(this); Main.map.mapView.removeMouseMotionListener(this); Main.map.mapView.removeTemporaryLayer(this); if (oldPopup != null) oldPopup.hide(); try { Toolkit.getDefaultToolkit().removeAWTEventListener(this); } catch (SecurityException ex) { Main.error(ex); } repaint(); } @Override public boolean layerIsSupported(Layer l) { return true; } ////////// Event listener methods @Override public void paint(Graphics2D g, MapView mv, Bounds bbox) { if (pos == null) return; Layer curL = mv.getLayerManager().getActiveLayer(); if (curL instanceof GpxLayer) showLayerInfo(g, curL, mv); else { for (Layer l : mv.getLayerManager().getLayers()) { if (l instanceof GpxLayer) { if (showLayerInfo(g, l, mv)) return; } } } } @Override public void eventDispatched(AWTEvent event) { updateKeyModifiers((InputEvent) event); if (event.getID() == KeyEvent.KEY_PRESSED) { doKeyEvent((KeyEvent) event); } // updateStatusLine(); repaint(); } @Override public void mousePressed(MouseEvent e) { if (!isEnabled()) return; if (e.getButton() != MouseEvent.BUTTON1) return; //setStatusLine(tr("Please move the mouse to draw new way")); repaint(); } @Override public void mouseReleased(MouseEvent e) { if (!isEnabled()) return; if (e.getButton() != MouseEvent.BUTTON1) return; if (oldPopup != null) { oldPopup.hide(); oldPopup = null; wpOld = null; } repaint(); } @Override public void mouseDragged(MouseEvent e) { if (oldPopup != null) { oldPopup.hide(); oldPopup = null; wpOld = null; } } @Override public void mouseMoved(MouseEvent e) { if (!isEnabled()) return; pos = mv.getEastNorth(e.getX(), e.getY()); repaint(); } private void doKeyEvent(KeyEvent e) { /// System.out.println(e); if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { filterTracks(); repaint(); } if (e.getKeyCode() == KeyEvent.VK_BACK_SLASH || e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_ESCAPE) { Main.map.selectSelectTool(false); } } /** * Updates shift and ctrl key states */ @Override protected void updateKeyModifiers(InputEvent e) { //oldCtrl = ctrl; //oldShift = shift; ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; } @Override protected void updateStatusLine() { Main.map.statusLine.setHelpText(statusText); Main.map.statusLine.repaint(); } // </editor-fold> private void repaint() { if (Main.map != null) Main.map.mapView.repaint(); } /*private void setStatusLine(String tr) { statusText=tr; updateStatusLine(); }*/ private synchronized void filterTracks() { Layer l = getLayerManager().getActiveLayer(); if (l instanceof GpxLayer && pos != null) { GpxLayer gpxL = (GpxLayer) l; Set<GpxTrack> toRemove = new HashSet<>(); for (GpxTrack track : gpxL.data.tracks) { boolean f = true; sg: for (GpxTrackSegment seg : track.getSegments()) { for (WayPoint S : seg.getWayPoints()) { if (S.time != 0) { f = false; break sg; } } } if (f) toRemove.add(track); } gpxL.data.tracks.removeAll(toRemove); } } private boolean showLayerInfo(Graphics2D g, Layer l, MapView mv) { GpxLayer gpxL = (GpxLayer) l; double minDist = 1e9, d; WayPoint wp = null, oldWp = null, prevWp = null; GpxTrack trk = null; double maxD = mv.getDist100Pixel()/3; for (GpxTrack track : gpxL.data.tracks) { for (GpxTrackSegment seg : track.getSegments()) { oldWp = null; // next segment will have new previous point for (WayPoint S : seg.getWayPoints()) { d = S.getEastNorth().distance(pos); if (d < minDist && d < maxD) { minDist = d; prevWp = oldWp; wp = S; trk = track; } oldWp = S; } } } if (wp != null) { Point p = mv.getPoint(wp.getCoor()); g.setColor(Color.RED); g.fillOval(p.x-10, p.y-10, 20, 20); // mark selected point if (shift) { // highlight track g.setColor(new Color(255, 30, 0, 128)); Stroke oldStroke = g.getStroke(); g.setStroke(new BasicStroke(10)); for (GpxTrackSegment seg : trk.getSegments()) { Point oldP = null, curP = null; // next segment will have new previous point for (WayPoint S : seg.getWayPoints()) { curP = mv.getPoint(S.getEastNorth()); if (oldP != null) g.drawLine(oldP.x, oldP.y, curP.x, curP.y); oldP = curP; } } g.setStroke(oldStroke); } Point s = mv.getLocationOnScreen(); int pcx = s.x+p.x-40; int pcy = s.y+p.y+30; if (shift) { pcx += 40; pcy -= 30; } if (wp != wpOld) { if (oldPopup != null) oldPopup.hide(); double vel = -1; if (prevWp != null && wp.time != prevWp.time) { vel = wp.getCoor().greatCircleDistance(prevWp.getCoor())/ (wp.time-prevWp.time)*3.6; } infoPanel.setData(wp, trk, vel, gpxL.data.tracks); Popup pp = PopupFactory.getSharedInstance().getPopup(mv, infoPanel, pcx, pcy); pp.show(); wpOld = wp; oldPopup = pp; } return true; } return false; } }