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