Ignore:
Timestamp:
2013-03-30T20:21:20+01:00 (11 years ago)
Author:
akks
Message:

Improved filtering tracks by date: more convenient (see #8416)
allow sorting track table, ignore broken timestamps for filtering and colorizing
DateEditorWithSlider widget can be reused

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    r5717 r5815  
    115115   
    116116    /**
    117     * returns minimum and maximum timestamps for all tracks
     117    * Returns minimum and maximum timestamps for all tracks
     118    * Warning: there are lot of track with broken timestamps,
     119    * so we just ingore points from future and from year before 1970 in this method
     120    * works correctly @since 5815
    118121    */
    119122    public Date[] getMinMaxTimeForAllTracks() {
    120         double min=Double.MIN_VALUE, max=Double.MAX_VALUE, t;
     123        double min=1e100, max=-1e100, t;
     124        double now = new Date().getTime()/1000.0;
    121125        for (GpxTrack trk: data.tracks) {
    122126            for (GpxTrackSegment seg : trk.getSegments()) {
    123127                for (WayPoint pnt : seg.getWayPoints()) {
    124128                    t = pnt.time;
    125                     if (t!=0) {
     129                    if (t>0 && t<=now) {
    126130                        if (t>max) max=t;
    127131                        if (t<min) min=t;
     
    130134            }
    131135        }
    132         if (min==Double.MIN_VALUE || max==Double.MAX_VALUE) return null;
     136        //System.out.println("scanning "+data.tracks.size()+" tracks, found min,max"+min+"--"+max);
     137        if (min==1e100 || max==-1e100) return null;
    133138        return new Date[]{new Date((long) (min * 1000)), new Date((long) (max * 1000)), };
    134139    }
     
    528533                oldWp = null;
    529534            }
     535            double now = new Date().getTime()/1000.0;
    530536            if (colored == colorModes.time) {
    531                 for (GpxTrack trk : data.tracks) {
    532                     for (GpxTrackSegment segment : trk.getSegments()) {
    533                         for (WayPoint trkPnt : segment.getWayPoints()) {
    534                             double t=trkPnt.time;
    535                             if (t==0) {
    536                                 continue; // skip non-dated trackpoints
    537                             }
    538                             if(t > maxval) {
    539                                 maxval = t;
    540                             }
    541                             if(t < minval) {
    542                                 minval = t;
    543                             }
    544                         }
    545                     }
    546                 }
    547             }
    548 
     537                Date bounds[] = getMinMaxTimeForAllTracks();
     538                if (bounds!=null) {
     539                    minval = bounds[0].getTime()/1000.0;
     540                    maxval = bounds[1].getTime()/1000.0;
     541                } else {
     542                    minval = 0; maxval=now;
     543                }
     544            }
     545           
    549546            for (GpxTrack trk : data.tracks) {
    550547                for (GpxTrackSegment segment : trk.getSegments()) {
     
    592589                                break;
    593590                            case time:
    594                                 if (trkPnt.time>0){
    595                                     int tColor = (int) Math.round((trkPnt.time-minval)*255/(maxval-minval));
     591                                double t=trkPnt.time;
     592                                if (t>0 && t<=now){ // skip bad timestamps
     593                                    int tColor = (int) Math.round((t-minval)*255/(maxval-minval));
    596594                                    trkPnt.customColoring = colors[tColor];
    597595                                } else {
  • trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java

    r5717 r5815  
    66import java.awt.GridBagLayout;
    77import java.awt.event.ActionEvent;
     8import java.awt.event.ActionListener;
    89import java.awt.event.MouseAdapter;
    910import java.awt.event.MouseEvent;
    1011import java.awt.event.MouseListener;
    11 import java.text.DateFormat;
    12 import java.text.SimpleDateFormat;
    13 import java.util.Date;
    14 import java.util.GregorianCalendar;
    1512import java.util.Map;
    1613import javax.swing.AbstractAction;
    17 import javax.swing.JButton;
    18 import javax.swing.JCheckBox;
    1914import javax.swing.JComponent;
    2015import javax.swing.JLabel;
    2116import javax.swing.JPanel;
    2217import javax.swing.JScrollPane;
    23 import javax.swing.JSlider;
    24 import javax.swing.JSpinner;
    2518import javax.swing.JTable;
     19import javax.swing.JToggleButton;
    2620import javax.swing.ListSelectionModel;
    27 import javax.swing.SpinnerDateModel;
    28 import javax.swing.event.ChangeEvent;
    29 import javax.swing.event.ChangeListener;
    3021import javax.swing.event.ListSelectionEvent;
    3122import javax.swing.event.ListSelectionListener;
     
    5041    private final GpxLayer layer;
    5142 
     43    DateFilterPanel dateFilter;
    5244    JTable table;
    53     JDateWithSlider dateFrom = new JDateWithSlider(tr("From"));
    54     JDateWithSlider dateTo = new JDateWithSlider(tr("To"));
    55     JCheckBox checkBox  = new JCheckBox(tr("No timestamp"));
    56     private boolean showNoTimestamp;
    5745   
    5846    public ChooseTrackVisibilityAction(final GpxLayer layer) {
     
    8472     * Builds an non-editable table whose 5th column will open a browser when double clicked.
    8573     * The table will fill its parent. */
    86     private JTable buildTable(String[] headers, Object[][] content) {
     74    private JTable buildTable(Object[][] content) {
     75        final String[] headers = {tr("Name"), tr("Description"), tr("Timespan"), tr("Length"), tr("URL")};
    8776        final JTable t = new JTable(content, headers) {
    8877            @Override
     
    127116            }
    128117        };
     118        t.setAutoCreateRowSorter(true);
    129119        t.addMouseListener(urlOpener);
    130120        t.setFillsViewportHeight(true);
     
    134124    boolean noUpdates=false;
    135125   
    136     private void filterTracksByDate() {
    137         layer.filterTracksByDate(dateFrom.getDate(), dateTo.getDate(), checkBox.isSelected());
    138     }
    139    
    140     /** selects all rows (=tracks) in the table that are currently visible */
     126    /** selects all rows (=tracks) in the table that are currently visible on the layer*/
    141127    private void selectVisibleTracksInTable() {
    142128        // don't select any tracks if the layer is not visible
     
    158144            @Override
    159145            public void valueChanged(ListSelectionEvent e) {
    160                 if (!(e.getSource() instanceof ListSelectionModel)) {
    161                     return;
    162                 }
    163                 if (!noUpdates) updateVisibilityFromTable();
     146                if (noUpdates || !(e.getSource() instanceof ListSelectionModel)) {
     147                    return;
     148                }
     149                updateVisibilityFromTable();
    164150            }
    165151        });
     
    169155        ListSelectionModel s = (ListSelectionModel) table.getSelectionModel();
    170156        for (int i = 0; i < layer.trackVisibility.length; i++) {
    171             layer.trackVisibility[i] = s.isSelectedIndex(i);
    172             System.out.printf("changed %d:=%s", i, ""+layer.trackVisibility[i]);
     157            layer.trackVisibility[table.convertRowIndexToModel(i)] = s.isSelectedIndex(i);
    173158        }
    174159        Main.map.mapView.preferenceChanged(null);
    175160        Main.map.repaint(100);
    176161    }
    177    
    178     private static final String PREF_DATE0 = "gpx.traces.showzerotimestamp";
    179     private static final String PREF_DATE1 = "gpx.traces.mintime";
    180     private static final String PREF_DATE2 = "gpx.traces.maxtime";
    181162   
    182163    @Override
     
    184165        final JPanel msg = new JPanel(new GridBagLayout());
    185166       
    186         final Date startTime, endTime;
    187         Date[] bounds = layer.getMinMaxTimeForAllTracks();
     167        dateFilter = new DateFilterPanel(layer, "gpx.traces", false);
     168        dateFilter.setFilterAppliedListener(new ActionListener(){
     169            @Override public void actionPerformed(ActionEvent e) {
     170                noUpdates = true;
     171                selectVisibleTracksInTable();
     172                noUpdates = false;
     173                Main.map.mapView.preferenceChanged(null);
     174                Main.map.repaint(100);
     175            }
     176        });
     177        dateFilter.loadFromPrefs();
    188178       
    189         startTime = (bounds==null) ? new GregorianCalendar(2000, 1, 1).getTime():bounds[0];
    190         endTime = (bounds==null) ? new Date() : bounds[2];
    191 
    192         long d1 = Main.pref.getLong(PREF_DATE1, 0);
    193         if (d1==0) d1=new GregorianCalendar(2000, 1, 1).getTime().getTime();
    194         long d2 = Main.pref.getLong(PREF_DATE2, 0);
    195         if (d2==0) d2=System.currentTimeMillis();
     179        final JToggleButton b = new JToggleButton(new AbstractAction(tr("Select by date")) {
     180            @Override public void actionPerformed(ActionEvent e) {
     181                if (((JToggleButton) e.getSource()).isSelected()) {
     182                    dateFilter.setEnabled(true);
     183                    dateFilter.applyFilter();
     184                } else {
     185                    dateFilter.setEnabled(false);
     186                }
     187            }
     188        });
     189        dateFilter.setEnabled(false);
     190        msg.add(b, GBC.std().insets(0,0,5,0));
     191        msg.add(dateFilter, GBC.eol().insets(0,0,10,0).fill(GBC.HORIZONTAL));
    196192       
    197         dateFrom.setValue(new Date(d1));
    198         dateTo.setValue(new Date(d2));
    199         dateFrom.setRange(startTime, endTime);
    200         dateTo.setRange(startTime, endTime);
    201         checkBox.setSelected(Main.pref.getBoolean(PREF_DATE0, true));
    202        
    203         JButton selectDate = new JButton();
    204         msg.add(selectDate, GBC.std().grid(1,1).insets(0, 0, 20, 0));
    205         msg.add(checkBox, GBC.std().grid(2,1).insets(0, 0, 20, 0));
    206         msg.add(dateFrom, GBC.std().grid(3,1).fill(GBC.HORIZONTAL));
    207         msg.add(dateTo, GBC.eol().grid(4,1).fill(GBC.HORIZONTAL));
    208         msg.add(new JLabel(tr("<html>Select all tracks that you want to be displayed. You can drag select a " + "range of tracks or use CTRL+Click to select specific ones. The map is updated live in the " + "background. Open the URLs by double clicking them.</html>")), GBC.eol().fill(GBC.HORIZONTAL));
     193        msg.add(new JLabel(tr("<html>Select all tracks that you want to be displayed. You can drag select a " + "range of tracks or use CTRL+Click to select specific ones. The map is updated live in the " + "background. Open the URLs by double clicking them.</html>")), GBC.eop().fill(GBC.HORIZONTAL));
    209194        // build table
    210195        final boolean[] trackVisibilityBackup = layer.trackVisibility.clone();
    211         final String[] headers = {tr("Name"), tr("Description"), tr("Timespan"), tr("Length"), tr("URL")};
    212         table = buildTable(headers, buildTableContents());
     196        table = buildTable(buildTableContents());
    213197        selectVisibleTracksInTable();
    214198        listenToSelectionChanges();
     
    216200        JScrollPane scrollPane = new JScrollPane(table);
    217201        msg.add(scrollPane, GBC.eol().fill(GBC.BOTH));
    218        
    219         selectDate.setAction(new AbstractAction(tr("Select by date")) {
    220             @Override
    221             public void actionPerformed(ActionEvent e) {
    222                 Main.pref.putLong(PREF_DATE1, dateFrom.getDate().getTime());
    223                 Main.pref.putLong(PREF_DATE2, dateTo.getDate().getTime());
    224                 Main.pref.put(PREF_DATE0, checkBox.isSelected());
    225                 noUpdates = true;
    226                 filterTracksByDate();
    227                 selectVisibleTracksInTable();
    228                 noUpdates = false;
    229                 updateVisibilityFromTable();
    230             }
    231         });
    232        
     202
    233203        // build dialog
    234204        ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Set track visibility for {0}", layer.getName()), new String[]{tr("Show all"), tr("Show selected only"), tr("Cancel")});
     
    240210        ed.setRememberWindowGeometry(getClass().getName() + ".geometry", WindowGeometry.centerInWindow(Main.parent, new Dimension(1000, 500)));
    241211        ed.showDialog();
     212        dateFilter.saveInPrefs();
    242213        int v = ed.getValue();
    243214        // cancel for unknown buttons and copy back original settings
     
    254225        final boolean all = v == 1 || s.isSelectionEmpty();
    255226        for (int i = 0; i < layer.trackVisibility.length; i++) {
    256             layer.trackVisibility[i] = all || s.isSelectedIndex(i);
     227            layer.trackVisibility[table.convertRowIndexToModel(i)] = all || s.isSelectedIndex(i);
    257228        }
    258229        // ...sync with layer visibility instead to avoid having two ways to hide everything
    259230        layer.setVisible(v == 1 || !s.isSelectionEmpty());
     231
     232        Main.map.mapView.preferenceChanged(null);
    260233        Main.map.repaint();
    261234    }
    262235   
    263    
    264     public static class JDateWithSlider extends JPanel {
    265         private JSpinner spinner;
    266         private JSlider slider;
    267         private Date dateMin;
    268         private Date dateMax;
    269         private static final int MAX_SLIDER=300;
    270 
    271         public JDateWithSlider(String msg) {
    272             super(new GridBagLayout());
    273             spinner = new JSpinner( new SpinnerDateModel() );
    274             String pattern = ((SimpleDateFormat)DateFormat.getDateInstance()).toPattern();
    275             JSpinner.DateEditor timeEditor = new JSpinner.DateEditor(spinner,pattern);
    276             spinner.setEditor(timeEditor);
    277             slider = new JSlider(0,MAX_SLIDER);
    278             slider.addChangeListener(new ChangeListener() {
    279                 public void stateChanged(ChangeEvent e) {
    280                     spinner.setValue(dateFromInt(slider.getValue()));
    281                 }
    282             });
    283             add(new JLabel(msg),GBC.std());
    284             add(spinner,GBC.std().insets(10,0,0,0));
    285             add(slider,GBC.eol().insets(10,0,0,0).fill(GBC.HORIZONTAL));
    286            
    287             dateMin = new Date(0); dateMax =new Date();
    288         }
    289 
    290         private Date dateFromInt(int value) {
    291             double k = 1.0*value/MAX_SLIDER;
    292             return new Date((long)(dateMax.getTime()*k+ dateMin.getTime()*(1-k)));
    293         }
    294         private int intFromDate(Date date) {
    295             return (int)(300.0*(date.getTime()-dateMin.getTime()) /
    296                     (dateMax.getTime()-dateMin.getTime()));
    297         }
    298 
    299         private void setRange(Date dateMin, Date dateMax) {
    300             this.dateMin = dateMin;
    301             this.dateMax = dateMax;
    302         }
    303        
    304         private void setValue(Date date) {
    305             spinner.setValue(date);
    306         }
    307 
    308         private Date getDate() {
    309             return (Date) spinner.getValue();
    310         }
    311     }
    312    
    313236}
Note: See TracChangeset for help on using the changeset viewer.