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.ChangeListener; 019 020import org.openstreetmap.josm.tools.GBC; 021import org.openstreetmap.josm.tools.date.DateUtils; 022 023/** 024 * Widget originally created for date filtering of GPX tracks. 025 * Allows to enter the date or choose it by using slider 026 * @since 5815 027 */ 028public class DateEditorWithSlider extends JPanel { 029 private final JSpinner spinner; 030 private final JSlider slider; 031 private Date dateMin; 032 private Date dateMax; 033 private static final int MAX_SLIDER = 300; 034 private boolean watchSlider = true; 035 036 private final transient List<ChangeListener> listeners = new ArrayList<>(); 037 038 /** 039 * Constructs a new {@code DateEditorWithSlider} with a given label 040 * @param labelText The label to display 041 */ 042 public DateEditorWithSlider(String labelText) { 043 super(new GridBagLayout()); 044 spinner = new JSpinner(new SpinnerDateModel()); 045 String pattern = ((SimpleDateFormat) DateUtils.getDateFormat(DateFormat.DEFAULT)).toPattern(); 046 JSpinner.DateEditor timeEditor = new JSpinner.DateEditor(spinner, pattern); 047 spinner.setEditor(timeEditor); 048 049 spinner.setPreferredSize(new Dimension(spinner.getPreferredSize().width+5, 050 spinner.getPreferredSize().height)); 051 052 slider = new JSlider(0, MAX_SLIDER); 053 spinner.addChangeListener(e -> { 054 int i = slider.getValue(); 055 Date d = (Date) spinner.getValue(); 056 int j = intFromDate(d); 057 if (i != j) { 058 watchSlider = false; 059 slider.setValue(j); 060 watchSlider = true; 061 } 062 for (ChangeListener l : listeners) { 063 l.stateChanged(e); 064 } 065 }); 066 slider.addChangeListener(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 add(new JLabel(labelText), GBC.std()); 075 add(spinner, GBC.std().insets(10, 0, 0, 0)); 076 add(slider, GBC.eol().insets(10, 0, 0, 0).fill(GBC.HORIZONTAL)); 077 078 dateMin = new Date(0); 079 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}