001// License: GPL. See LICENSE file for details.
002package org.openstreetmap.josm.gui.layer.gpx;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.awt.GridBagLayout;
008import java.awt.event.ActionEvent;
009import java.awt.event.ActionListener;
010import java.util.Date;
011import java.util.GregorianCalendar;
012
013import javax.swing.JCheckBox;
014import javax.swing.JPanel;
015import javax.swing.Timer;
016import javax.swing.event.ChangeEvent;
017import javax.swing.event.ChangeListener;
018
019import org.openstreetmap.josm.Main;
020import org.openstreetmap.josm.gui.layer.GpxLayer;
021import org.openstreetmap.josm.gui.widgets.DateEditorWithSlider;
022import org.openstreetmap.josm.tools.GBC;
023
024public class DateFilterPanel extends JPanel {
025    DateEditorWithSlider dateFrom = new DateEditorWithSlider(tr("From"));
026    DateEditorWithSlider dateTo = new DateEditorWithSlider(tr("To"));
027    JCheckBox noTimestampCb  = new JCheckBox(tr("No timestamp"));
028    GpxLayer layer;
029    
030    ActionListener filterAppliedListener;
031    
032    final String PREF_DATE_0;
033    final String PREF_DATE_MIN;
034    final String PREF_DATE_MAX;
035
036    /**
037     * Create the panel to filter tracks on GPX layer @param layer by date
038     * Preferences will be stored in @param preferencePrefix
039     * If @param enabled = true, the the panel is created as active and filtering occurs immediately.
040     */
041    public DateFilterPanel(GpxLayer layer, String preferencePrefix, boolean enabled) {
042        super(new GridBagLayout());
043        PREF_DATE_0 = preferencePrefix+".showzerotimestamp";
044        PREF_DATE_MIN = preferencePrefix+".mintime";
045        PREF_DATE_MAX = preferencePrefix+".maxtime";
046        this.layer = layer;
047        
048        final Date startTime, endTime;
049        Date[] bounds = layer.getMinMaxTimeForAllTracks();
050        startTime = (bounds==null) ? new GregorianCalendar(2000, 1, 1).getTime():bounds[0];
051        endTime = (bounds==null) ? new Date() : bounds[1];
052                
053        dateFrom.setDate(startTime); 
054        dateTo.setDate(endTime);
055        dateFrom.setRange(startTime, endTime); 
056        dateTo.setRange(startTime, endTime); 
057        
058        add(noTimestampCb, GBC.std().grid(1,1).insets(0, 0, 5, 0));
059        add(dateFrom, GBC.std().grid(2,1).fill(GBC.HORIZONTAL));
060        add(dateTo, GBC.eol().grid(3,1).fill(GBC.HORIZONTAL));
061        
062        setEnabled(enabled);
063        
064        dateFrom.addDateListener(changeListener);
065        dateTo.addDateListener(changeListener);
066        noTimestampCb.addChangeListener(changeListener);
067    }
068    
069    private ChangeListener changeListener = new ChangeListener() {
070        @Override public void stateChanged(ChangeEvent e) {
071            if (isEnabled()) applyFilterWithDelay();
072        }
073    };
074    
075    private Timer t = new Timer(200 , new ActionListener() {
076        @Override  public void actionPerformed(ActionEvent e) {
077            applyFilter();
078        }
079    });
080    
081    /**
082     * Do filtering but little bit later (to reduce cpu load)
083     */
084    public void applyFilterWithDelay() {
085        if (t.isRunning()) {
086            t.restart();
087        } else {
088            t.start();
089        }
090    }
091    
092    public void applyFilter() {
093        t.stop();
094        filterTracksByDate();
095        if (filterAppliedListener!=null)
096           filterAppliedListener.actionPerformed(null);
097    }
098    
099    /**
100     * Called by other components when it is correct time to save date filtering parameters
101     */
102    public void saveInPrefs() {
103        Main.pref.putLong(PREF_DATE_MIN, dateFrom.getDate().getTime());
104        Main.pref.putLong(PREF_DATE_MAX, dateTo.getDate().getTime());
105        Main.pref.put(PREF_DATE_0, noTimestampCb.isSelected());
106    }
107
108    /**
109     * If possible, load date ragne and "zero timestamp" option from preferences
110     * Called by other components when it is needed.
111     */
112    public void loadFromPrefs() {
113        long t1 =Main.pref.getLong(PREF_DATE_MIN, 0);
114        if (t1!=0) dateFrom.setDate(new Date(t1));
115        long t2 =Main.pref.getLong(PREF_DATE_MAX, 0);
116        if (t2!=0) dateTo.setDate(new Date(t2));
117        noTimestampCb.setSelected(Main.pref.getBoolean(PREF_DATE_0, false));
118    }
119
120    public void setFilterAppliedListener(ActionListener filterAppliedListener) {
121        this.filterAppliedListener = filterAppliedListener;
122    }
123    
124    private void filterTracksByDate() {
125        Date from = dateFrom.getDate();
126        Date to = dateTo.getDate();
127        layer.filterTracksByDate(from, to, noTimestampCb.isSelected());
128    }
129
130    @Override
131    public void setEnabled(boolean enabled) {
132        super.setEnabled(enabled); 
133        for (Component c: getComponents()) {
134            c.setEnabled(enabled);
135        }
136    }
137    
138    
139    
140 
141}