001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.widgets;
003
004import java.awt.Component;
005import java.awt.Dimension;
006import java.awt.GridBagLayout;
007import java.text.DateFormat;
008import java.text.SimpleDateFormat;
009import java.util.ArrayList;
010import java.util.Date;
011import java.util.List;
012import javax.swing.JLabel;
013import javax.swing.JPanel;
014import javax.swing.JSlider;
015import javax.swing.JSpinner;
016import javax.swing.SpinnerDateModel;
017import javax.swing.event.ChangeEvent;
018import javax.swing.event.ChangeListener;
019import org.openstreetmap.josm.tools.GBC;
020
021
022/**
023 * Widget originally created for date filtering of GPX tracks. 
024 * Allows to enter the date or choose it by using slider
025 */
026public class DateEditorWithSlider extends JPanel {
027    private JSpinner spinner;
028    private JSlider slider;
029    private Date dateMin;
030    private Date dateMax;
031    private static final int MAX_SLIDER=300;
032    private boolean watchSlider = true;
033    
034    private List<ChangeListener> listeners = new ArrayList<ChangeListener>();
035
036    public DateEditorWithSlider(String labelText) {
037        super(new GridBagLayout());
038        spinner = new JSpinner( new SpinnerDateModel() );
039        String pattern = ((SimpleDateFormat)DateFormat.getDateInstance()).toPattern();
040        JSpinner.DateEditor timeEditor = new JSpinner.DateEditor(spinner,pattern);
041        spinner.setEditor(timeEditor);
042        
043
044        spinner.setPreferredSize(new Dimension(spinner.getPreferredSize().width+5,
045        spinner.getPreferredSize().height));
046        
047        slider = new JSlider(0,MAX_SLIDER);
048        spinner.addChangeListener(new ChangeListener() {
049            @Override
050            public void stateChanged(ChangeEvent e) {
051                int i = slider.getValue();
052                Date d = (Date) spinner.getValue();
053                int j = intFromDate(d);
054                if (i!=j) {
055                    watchSlider=false;
056                    slider.setValue(j);
057                    watchSlider=true;
058                }
059                for (ChangeListener l : listeners) {
060                    l.stateChanged(e);
061                }
062            }
063        });
064        slider.addChangeListener(new ChangeListener() {
065            @Override
066            public void stateChanged(ChangeEvent e) {
067                if (!watchSlider) return;
068                Date d = (Date) spinner.getValue();
069                Date d1 = dateFromInt(slider.getValue());
070                if (!d.equals(d1)) {
071                    spinner.setValue(d1);
072                }
073            }
074        });
075        add(new JLabel(labelText),GBC.std());
076        add(spinner,GBC.std().insets(10,0,0,0));
077        add(slider,GBC.eol().insets(10,0,0,0).fill(GBC.HORIZONTAL));
078
079        dateMin = new Date(0); dateMax =new Date();
080    }
081
082    protected Date dateFromInt(int value) {
083        double k = 1.0*value/MAX_SLIDER;
084        return new Date((long)(dateMax.getTime()*k+ dateMin.getTime()*(1-k)));
085    }
086    
087    protected int intFromDate(Date date) {
088        return (int)(300.0*(date.getTime()-dateMin.getTime()) /
089                (dateMax.getTime()-dateMin.getTime()));
090    }
091
092    public void setRange(Date dateMin, Date dateMax) {
093        this.dateMin = dateMin;
094        this.dateMax = dateMax;
095    }
096
097    public void setDate(Date date) {
098        spinner.setValue(date);
099    }
100
101    public Date getDate() {
102        return (Date) spinner.getValue();
103    }
104    
105    public void addDateListener(ChangeListener l) {
106        listeners.add(l);
107    }
108
109    public void removeDateListener(ChangeListener l) {
110        listeners.remove(l);
111    }
112    
113    @Override
114    public void setEnabled(boolean enabled) {
115        super.setEnabled(enabled); 
116        for (Component c: getComponents()) {
117            c.setEnabled(enabled);
118        }
119    }
120   
121}