Ignore:
Timestamp:
2014-06-10T00:04:18+02:00 (11 years ago)
Author:
zverik
Message:

wow, it works

Location:
applications/editors/josm/plugins/NanoLog/src/nanolog
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/NanoLog/src/nanolog/NanoLogEntry.java

    r27939 r30491  
    11package nanolog;
    22
    3 import java.util.Date;
     3import java.awt.*;
     4import java.util.*;
     5import org.openstreetmap.josm.Main;
     6import org.openstreetmap.josm.data.Bounds;
    47import org.openstreetmap.josm.data.coor.LatLon;
     8import org.openstreetmap.josm.gui.MapView;
    59
    610/**
     
    913 * @author zverik
    1014 */
    11 public class NanoLogEntry {
     15public class NanoLogEntry implements Comparable<NanoLogEntry> {
    1216    private LatLon pos;
    1317    private Date time;
    1418    private String message;
    15     private int direction;
    16     private LatLon tmpPos;
     19    private Integer direction;
     20    private Integer baseDir;
     21    private LatLon basePos;
    1722
    18     public int getDirection() {
     23    public NanoLogEntry( Date time, String message, LatLon basePos, Integer baseDir ) {
     24        this.basePos = basePos;
     25        this.baseDir = baseDir;
     26        this.pos = basePos;
     27        this.direction = baseDir;
     28        this.time = time;
     29        this.message = message;
     30        this.direction = direction;
     31    }
     32
     33    public NanoLogEntry( Date time, String message ) {
     34        this(time, message, null, null);
     35    }
     36   
     37    public Integer getDirection() {
    1938        return direction;
    2039    }
     
    2544
    2645    public LatLon getPos() {
    27         return tmpPos == null ? pos : tmpPos;
     46        return pos;
     47    }
     48
     49    public void setPos( LatLon pos ) {
     50        this.pos = pos;
     51    }
     52
     53    public void setDirection( Integer direction ) {
     54        this.direction = direction;
     55    }
     56
     57    public LatLon getBasePos() {
     58        return basePos;
     59    }
     60
     61    public Integer getBaseDir() {
     62        return baseDir;
    2863    }
    2964
     
    3166        return time;
    3267    }
     68
     69    @Override
     70    public int compareTo( NanoLogEntry t ) {
     71        return time.compareTo(t.time);
     72    }
    3373}
  • applications/editors/josm/plugins/NanoLog/src/nanolog/NanoLogLayer.java

    r27939 r30491  
    11package nanolog;
    22
    3 import java.awt.Color;
    4 import java.awt.Graphics2D;
    5 import java.awt.Point;
    6 import java.awt.Rectangle;
    7 import java.awt.event.ActionEvent;
    8 import java.beans.PropertyChangeListener;
     3import java.awt.*;
     4import java.awt.event.*;
    95import java.io.*;
    10 import java.util.ArrayList;
     6import java.text.ParseException;
     7import java.text.SimpleDateFormat;
     8import java.util.*;
    119import java.util.List;
    12 import javax.swing.AbstractAction;
    13 import javax.swing.Action;
    14 import javax.swing.Icon;
     10import java.util.regex.*;
     11import javax.swing.*;
    1512import org.openstreetmap.josm.Main;
    16 import org.openstreetmap.josm.actions.RenameLayerAction;
    17 import org.openstreetmap.josm.actions.SaveAction;
     13import org.openstreetmap.josm.actions.*;
    1814import org.openstreetmap.josm.data.Bounds;
     15import org.openstreetmap.josm.data.coor.EastNorth;
     16import org.openstreetmap.josm.data.coor.LatLon;
     17import org.openstreetmap.josm.data.gpx.WayPoint;
    1918import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    2019import org.openstreetmap.josm.gui.MapView;
    21 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    22 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
    23 import org.openstreetmap.josm.gui.layer.JumpToMarkerActions;
    24 import org.openstreetmap.josm.gui.layer.Layer;
     20import org.openstreetmap.josm.gui.dialogs.*;
     21import org.openstreetmap.josm.gui.layer.*;
    2522import static org.openstreetmap.josm.tools.I18n.tr;
    26 import static org.openstreetmap.josm.tools.I18n.trn;
    2723import org.openstreetmap.josm.tools.ImageProvider;
    2824
    2925/**
     26 * NanoLog layer: a set of points that can be georeferenced.
    3027 *
    3128 * @author zverik
     
    3532    private List<NanoLogEntry> log;
    3633    private int selectedEntry;
     34    private final Set<NanoLogLayerListener> listeners = new HashSet<NanoLogLayerListener>();
     35    private NLLMouseAdapter mouseListener;
     36   
     37    public NanoLogLayer( List<NanoLogEntry> entries ) {
     38        super(tr("NanoLog"));
     39        log = new ArrayList<NanoLogEntry>(entries);
     40        selectedEntry = -1;
     41        mouseListener = new NLLMouseAdapter();
     42        Main.map.mapView.addMouseListener(mouseListener);
     43        Main.map.mapView.addMouseMotionListener(mouseListener);
     44    }
     45
     46    @Override
     47    public void destroy() {
     48        Main.map.mapView.removeMouseListener(mouseListener);
     49        Main.map.mapView.removeMouseMotionListener(mouseListener);
     50        super.destroy();
     51    }
    3752   
    3853    public NanoLogLayer( File file ) throws IOException {
    39         super(tr("NanoLog"));
    40         log = readNanoLog(file);
    41         selectedEntry = -1;
     54        this(readNanoLog(file));
     55    }
     56
     57    public void addListener( NanoLogLayerListener listener ) {
     58        listeners.add(listener);
     59    }
     60
     61    public void removeListener( NanoLogLayerListener listener ) {
     62        listeners.remove(listener);
     63    }
     64
     65    protected void fireMarkersChanged() {
     66        for( NanoLogLayerListener listener : listeners )
     67            listener.markersUpdated(this);
     68    }
     69
     70    protected void fireMarkerSelected() {
     71        for( NanoLogLayerListener listener : listeners )
     72            listener.markerActivated(this, selectedEntry < 0 ? null : log.get(selectedEntry));
     73    }
     74
     75    public List<NanoLogEntry> getEntries() {
     76        return Collections.unmodifiableList(log);
    4277    }
    4378   
    4479    public static List<NanoLogEntry> readNanoLog( File file ) throws IOException {
     80        final Pattern NANOLOG_LINE = Pattern.compile("(.+?)\\t(.+?)(?:\\s*\\{\\{(-?\\d+\\.\\d+),\\s*(-?\\d+\\.\\d+)(?:,\\s*(\\d+))?\\}\\})?");
     81        final SimpleDateFormat fmt = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.SS");
    4582        List<NanoLogEntry> result = new ArrayList<NanoLogEntry>();
    4683        BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
     
    4885            String line = r.readLine();
    4986            if( line != null ) {
    50                 // parse it
     87                Matcher m = NANOLOG_LINE.matcher(line);
     88                if( m.matches() ) {
     89                    String time = m.group(1);
     90                    String message = m.group(2);
     91                    String lat = m.group(3);
     92                    String lon = m.group(4);
     93                    String dir = m.group(5);
     94                    Date timeDate = null;
     95                    try {
     96                        timeDate = fmt.parse(time);
     97                    } catch( ParseException e ) {
     98                    }
     99                    if( message == null || message.length() == 0 || timeDate == null )
     100                        continue;
     101                    LatLon pos = null;
     102                    Integer direction = null;
     103                    if( lat != null && lon != null ) {
     104                        try {
     105                            pos = new LatLon(Double.parseDouble(lat), Double.parseDouble(lon));
     106                            direction = new Integer(dir);
     107                        } catch( NumberFormatException e ) {
     108                            // well...
     109                        }
     110                    }
     111                    NanoLogEntry entry = new NanoLogEntry(timeDate, message, pos, direction);
     112                    result.add(entry);
     113                }
    51114            }
    52115        }
     
    58121    public void paint( Graphics2D g, MapView mv, Bounds box ) {
    59122        // todo
    60         int radius = 4;
    61         int width = Main.map.mapView.getWidth();
    62         int height = Main.map.mapView.getHeight();
    63         Rectangle clip = g.getClipBounds();
    64         for( NanoLogEntry entry : log ) {
     123        for( int i = 0; i < log.size(); i++  ) {
     124            NanoLogEntry entry = log.get(i);
     125            int radius = 4;
    65126            if( entry.getPos() != null ) {
    66127                Point p = mv.getPoint(entry.getPos());
    67                 g.setColor(Color.green);
     128                g.setColor(selectedEntry == i ? Color.red : Color.yellow);
    68129                g.fillOval(p.x - radius, p.y - radius, radius * 2, radius * 2);
    69130            }
    70         }
    71         if( selectedEntry >= 0 && selectedEntry < log.size() ) {
    72             Point p = mv.getPoint(log.get(selectedEntry).getPos());
    73             g.setColor(Color.red);
    74             g.fillOval(p.x - radius, p.y - radius, radius * 2, radius * 2);
    75131        }
    76132    }
     
    120176            new RenameLayerAction(null, this),
    121177            SeparatorLayerAction.INSTANCE,
    122             new CorrelateEntries(),
     178            new CorrelateEntries(true),
     179            new CorrelateEntries(false),
    123180            new SaveLayer(),
    124181            SeparatorLayerAction.INSTANCE,
     
    127184    }
    128185
     186    @Override
    129187    public void jumpToNextMarker() {
    130188        selectedEntry++;
     
    136194    }
    137195
     196    @Override
    138197    public void jumpToPreviousMarker() {
    139198        selectedEntry--;
     
    144203        Main.map.repaint();
    145204    }
    146    
    147     private class CorrelateEntries extends AbstractAction {
    148 
     205
     206    protected void setSelected( int i ) {
     207        int newSelected = i >= 0 && i < log.size() ? i : -1;
     208        if( newSelected != selectedEntry ) {
     209//            System.out.println("selected: " + log.get(newSelected).getMessage());
     210            selectedEntry = newSelected;
     211            fireMarkerSelected();
     212            Main.map.mapView.repaint();
     213        }
     214    }
     215
     216    public void setSelected( NanoLogEntry entry ) {
     217        if( entry == null )
     218            setSelected(-1);
     219        else {
     220            for( int i = 0; i < log.size(); i++ ) {
     221                if( entry.equals(log.get(i)) ) {
     222                    setSelected(i);
     223                    break;
     224                }
     225            }
     226        }
     227    }
     228
     229    private class NLLMouseAdapter extends MouseAdapter {
     230        private int dragging;
     231
     232        public int nearestEntry( MouseEvent e ) {
     233            LatLon ll = Main.map.mapView.getLatLon(e.getX(), e.getY());
     234            int radius = 8;
     235            if( ll != null ) {
     236                LatLon lld = Main.map.mapView.getLatLon(e.getX() + radius, e.getY() + radius);
     237                double distance = Math.max(lld.lat() - ll.lat(), lld.lon() - ll.lon());
     238                boolean selectedIsSelected = false;
     239                int newSelected = -1;
     240                for( int i = 0; i < log.size(); i++ ) {
     241                    if( log.get(i).getPos() != null && log.get(i).getPos().distance(ll) < distance ) {
     242                        newSelected = i;
     243                        if( i == selectedEntry )
     244                            selectedIsSelected = true;
     245                    }
     246                }
     247                if( newSelected >= 0 )
     248                    return selectedIsSelected ? selectedEntry : newSelected;
     249            }
     250            return -1;
     251        }
     252
     253        @Override
     254        public void mouseMoved( MouseEvent e ) {
     255            int nearest = nearestEntry(e);
     256            if( nearest > 0 )
     257                setSelected(nearest);
     258        }
     259
     260        @Override
     261        public void mouseDragged( MouseEvent e ) {
     262            doDrag(e);
     263        }
     264
     265        @Override
     266        public void mouseReleased( MouseEvent e ) {
     267            if( dragging > 0 ) {
     268                dragging = 0;
     269            }
     270        }
     271
     272        @Override
     273        public void mousePressed( MouseEvent e ) {
     274            int nearest = nearestEntry(e);
     275            if( nearest > 0 && Main.map.mapView.getActiveLayer() == NanoLogLayer.this ) {
     276                dragging = nearest;
     277                doDrag(e);
     278            }
     279        }
     280
     281        private void doDrag( MouseEvent e ) {
     282            if( dragging > 0 )
     283                dragTo(dragging, e.getX(), e.getY());
     284        }
     285    }
     286
     287    protected void dragTo( int entry, int x, int y ) {
     288        GpxLayer gpx = GPXChooser.topLayer();
     289        if( gpx == null )
     290            return;
     291        EastNorth eastNorth = Main.map.mapView.getEastNorth(x, y);
     292        double tolerance = eastNorth.distance(Main.map.mapView.getEastNorth(x + 300, y));
     293        WayPoint wp = gpx.data.nearestPointOnTrack(eastNorth, tolerance);
     294        if( wp == null )
     295            return;
     296        long newTime = Correlator.getGpxDate(gpx.data, wp.getCoor());
     297        if( newTime <= 0 )
     298            return;
     299        Correlator.revertPos(log);
     300        Correlator.correlate(log, gpx.data, log.get(entry).getTime().getTime() - newTime);
     301        Main.map.mapView.repaint();
     302    }
     303   
     304    private class CorrelateEntries extends JosmAction {
     305        private boolean toZero;
     306
     307        public CorrelateEntries() {
     308            this(false);
     309        }
     310
     311        public CorrelateEntries( boolean toZero ) {
     312            super(toZero ? tr("Correlate with GPX...") : tr("Put on GPX..."), "nanolog/correlate", tr("Correlate entries with GPS trace"), null, false);
     313            this.toZero = toZero;
     314        }
     315
     316        @Override
     317        public void actionPerformed( ActionEvent e ) {
     318            // 1. Select GPX trace or display message to load one
     319            // (better yet, disable when no GPX traces)
     320            GpxLayer layer = GPXChooser.chooseLayer();
     321            // 2. Correlate by default, sticking by date
     322            // (if does not match, shift so hours-minutes stay)
     323            if( layer != null ) {
     324                long offset = toZero ? 0 : Correlator.crudeMatch(log, layer.data);
     325                Correlator.revertPos(log);
     326                Correlator.correlate(log, layer.data, offset);
     327                fireMarkersChanged();
     328                Main.map.mapView.repaint();
     329            }
     330            // 3. Show non-modal (?) window with a slider and a text input
     331            // (todo: better slider, like in blender)
     332        }
     333    }
     334   
     335    private class SaveLayer extends JosmAction {
     336
     337        public SaveLayer() {
     338            super(tr("Save layer..."), "nanolog/save", tr("Save NanoLog layer"), null, false);
     339        }
     340
     341        @Override
    149342        public void actionPerformed( ActionEvent e ) {
    150343            // todo
    151         }
    152     }
    153    
    154     private class SaveLayer extends AbstractAction {
    155 
    156         public void actionPerformed( ActionEvent e ) {
    157             // todo
    158         }
     344            JOptionPane.showMessageDialog(Main.parent, "Sorry, no saving yet", "NanoLog", JOptionPane.ERROR_MESSAGE);
     345        }
     346    }
     347
     348    public static interface NanoLogLayerListener {
     349        void markersUpdated( NanoLogLayer layer );
     350        void markerActivated( NanoLogLayer layer, NanoLogEntry entry );
    159351    }
    160352}
  • applications/editors/josm/plugins/NanoLog/src/nanolog/NanoLogPanel.java

    r27960 r30491  
    11package nanolog;
    22
     3import java.awt.Rectangle;
     4import java.text.SimpleDateFormat;
     5import java.util.*;
    36import javax.swing.*;
     7import nanolog.NanoLogLayer.NanoLogLayerListener;
     8import org.openstreetmap.josm.Main;
     9import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
    410import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
     11import org.openstreetmap.josm.gui.layer.Layer;
    512import static org.openstreetmap.josm.tools.I18n.tr;
    613import org.openstreetmap.josm.tools.Shortcut;
     
    1118 * @author zverik
    1219 */
    13 public class NanoLogPanel extends ToggleDialog {
    14     private JList logPanel;
     20public class NanoLogPanel extends ToggleDialog implements LayerChangeListener, NanoLogLayerListener {
     21    private JList<String> logPanel;
    1522    private LogListModel listModel;
    1623   
    1724    public NanoLogPanel() {
    18         super(tr("NanoLog"), "nanolog", tr("Open NanoLog panel"), null, 150, true);
     25        super(tr("NanoLog"), "nanolog", tr("Open NanoLog panel"), null, 150, false);
    1926       
    2027        listModel = new LogListModel();
    21         logPanel = new JList(listModel);
     28        logPanel = new JList<String>(listModel);
    2229        createLayout(logPanel, true, null);
    2330    }
     31
     32    public void updateMarkers() {
     33        List<NanoLogEntry> entries = new ArrayList<NanoLogEntry>();
     34        for( NanoLogLayer l : Main.map.mapView.getLayersOfType(NanoLogLayer.class) ) {
     35            entries.addAll(l.getEntries());
     36        }
     37        listModel.setEntries(entries);
     38    }
     39
     40    @Override
     41    public void activeLayerChange( Layer oldLayer, Layer newLayer ) {
     42        // todo
     43    }
     44
     45    @Override
     46    public void layerAdded( Layer newLayer ) {
     47        if( newLayer instanceof NanoLogLayer )
     48            ((NanoLogLayer)newLayer).addListener(this);
     49        updateMarkers();
     50    }
     51
     52    @Override
     53    public void layerRemoved( Layer oldLayer ) {
     54        updateMarkers();
     55    }
     56
     57    @Override
     58    public void markersUpdated( NanoLogLayer layer ) {
     59        updateMarkers();
     60    }
     61
     62    @Override
     63    public void markerActivated( NanoLogLayer layer, NanoLogEntry entry ) {
     64        int idx = entry == null ? -1 : listModel.find(entry);
     65        if( idx >= 0 ) {
     66            logPanel.setSelectedIndex(idx);
     67            Rectangle rect = logPanel.getCellBounds(Math.max(0, idx-2), Math.min(idx+4, listModel.getSize()));
     68            logPanel.scrollRectToVisible(rect);
     69        }
     70    }
    2471   
    25     private class LogListModel extends AbstractListModel {
     72    private class LogListModel extends AbstractListModel<String> {
     73        private List<NanoLogEntry> entries;
     74        private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
    2675
    2776        public int getSize() {
    28             return 0;
     77            return entries.size();
    2978        }
    3079
    3180        public String getElementAt( int index ) {
    32             return ""; // todo
     81            return TIME_FORMAT.format(entries.get(index).getTime()) + " " + entries.get(index).getMessage();
     82        }
     83
     84        public void setEntries( List<NanoLogEntry> entries ) {
     85            this.entries = entries;
     86            fireContentsChanged(this, 0, entries.size());
     87        }
     88
     89        public int find( NanoLogEntry entry ) {
     90            return entries.indexOf(entry);
    3391        }
    3492    }
  • applications/editors/josm/plugins/NanoLog/src/nanolog/NanoLogPlugin.java

    r27939 r30491  
    22
    33import java.awt.event.ActionEvent;
     4import java.io.IOException;
     5import java.util.List;
    46import javax.swing.JFileChooser;
     7import javax.swing.JOptionPane;
    58import org.openstreetmap.josm.Main;
    69import org.openstreetmap.josm.actions.JosmAction;
    710import org.openstreetmap.josm.gui.MapFrame;
     11import org.openstreetmap.josm.gui.MapView;
    812import org.openstreetmap.josm.plugins.Plugin;
    913import org.openstreetmap.josm.plugins.PluginInformation;
     
    1822    public NanoLogPlugin( PluginInformation info ) {
    1923        super(info);
    20         Main.main.menu.fileMenu.add(new OpenNanoLogLayerAction());
     24        Main.main.menu.fileMenu.insert(new OpenNanoLogLayerAction(), 4);
    2125    }
    2226   
     
    2428    public void mapFrameInitialized( MapFrame oldFrame, MapFrame newFrame ) {
    2529        if( oldFrame == null && newFrame != null ) {
    26             newFrame.addToggleDialog(new NanoLogPanel());
     30            NanoLogPanel panel = new NanoLogPanel();
     31            newFrame.addToggleDialog(panel);
     32            MapView.addLayerChangeListener(panel);
    2733        }
    2834    }
     
    3743            JFileChooser fc = new JFileChooser();
    3844            if( fc.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION ) {
    39                 // open layer, ok
     45                try {
     46                    List<NanoLogEntry> entries = NanoLogLayer.readNanoLog(fc.getSelectedFile());
     47                    if( !entries.isEmpty() ) {
     48                        NanoLogLayer layer = new NanoLogLayer(entries);
     49                        Main.main.addLayer(layer);
     50                    }
     51                } catch( IOException ex ) {
     52                    JOptionPane.showMessageDialog(Main.parent, tr("Could not read NanoLog file:") + "\n" + ex.getMessage());
     53                }
    4054            }
    4155        }       
Note: See TracChangeset for help on using the changeset viewer.