001// License: GPL. For details, see LICENSE file. 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 private final DateEditorWithSlider dateFrom = new DateEditorWithSlider(tr("From")); 026 private final DateEditorWithSlider dateTo = new DateEditorWithSlider(tr("To")); 027 private final JCheckBox noTimestampCb = new JCheckBox(tr("No timestamp")); 028 private final transient GpxLayer layer; 029 030 private transient ActionListener filterAppliedListener; 031 032 private final String prefDate0; 033 private final String prefDateMin; 034 private final String prefDateMax; 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, then the panel is created as active and filtering occurs immediately. 040 * @param layer GPX layer 041 * @param preferencePrefix preference prefix 042 * @param enabled panel initial enabled state 043 */ 044 public DateFilterPanel(GpxLayer layer, String preferencePrefix, boolean enabled) { 045 super(new GridBagLayout()); 046 prefDate0 = preferencePrefix+".showzerotimestamp"; 047 prefDateMin = preferencePrefix+".mintime"; 048 prefDateMax = preferencePrefix+".maxtime"; 049 this.layer = layer; 050 051 final Date startTime, endTime; 052 Date[] bounds = layer.data.getMinMaxTimeForAllTracks(); 053 startTime = (bounds.length == 0) ? new GregorianCalendar(2000, 1, 1).getTime() : bounds[0]; 054 endTime = (bounds.length == 0) ? new Date() : bounds[1]; 055 056 dateFrom.setDate(startTime); 057 dateTo.setDate(endTime); 058 dateFrom.setRange(startTime, endTime); 059 dateTo.setRange(startTime, endTime); 060 061 add(noTimestampCb, GBC.std().grid(1, 1).insets(0, 0, 5, 0)); 062 add(dateFrom, GBC.std().grid(2, 1).fill(GBC.HORIZONTAL)); 063 add(dateTo, GBC.eol().grid(3, 1).fill(GBC.HORIZONTAL)); 064 065 setEnabled(enabled); 066 067 dateFrom.addDateListener(changeListener); 068 dateTo.addDateListener(changeListener); 069 noTimestampCb.addChangeListener(changeListener); 070 } 071 072 private final transient ChangeListener changeListener = new ChangeListener() { 073 @Override public void stateChanged(ChangeEvent e) { 074 if (isEnabled()) applyFilterWithDelay(); 075 } 076 }; 077 078 private final Timer t = new Timer(200, new ActionListener() { 079 @Override public void actionPerformed(ActionEvent e) { 080 applyFilter(); 081 } 082 }); 083 084 /** 085 * Do filtering but little bit later (to reduce cpu load) 086 */ 087 public void applyFilterWithDelay() { 088 if (t.isRunning()) { 089 t.restart(); 090 } else { 091 t.start(); 092 } 093 } 094 095 public void applyFilter() { 096 t.stop(); 097 filterTracksByDate(); 098 if (filterAppliedListener != null) 099 filterAppliedListener.actionPerformed(null); 100 } 101 102 /** 103 * Called by other components when it is correct time to save date filtering parameters 104 */ 105 public void saveInPrefs() { 106 Main.pref.putLong(prefDateMin, dateFrom.getDate().getTime()); 107 Main.pref.putLong(prefDateMax, dateTo.getDate().getTime()); 108 Main.pref.put(prefDate0, noTimestampCb.isSelected()); 109 } 110 111 /** 112 * If possible, load date ragne and "zero timestamp" option from preferences 113 * Called by other components when it is needed. 114 */ 115 public void loadFromPrefs() { 116 long t1 = Main.pref.getLong(prefDateMin, 0); 117 if (t1 != 0) dateFrom.setDate(new Date(t1)); 118 long t2 = Main.pref.getLong(prefDateMax, 0); 119 if (t2 != 0) dateTo.setDate(new Date(t2)); 120 noTimestampCb.setSelected(Main.pref.getBoolean(prefDate0, false)); 121 } 122 123 public void setFilterAppliedListener(ActionListener filterAppliedListener) { 124 this.filterAppliedListener = filterAppliedListener; 125 } 126 127 private void filterTracksByDate() { 128 Date from = dateFrom.getDate(); 129 Date to = dateTo.getDate(); 130 layer.filterTracksByDate(from, to, noTimestampCb.isSelected()); 131 } 132 133 @Override 134 public final void setEnabled(boolean enabled) { 135 super.setEnabled(enabled); 136 for (Component c: getComponents()) { 137 c.setEnabled(enabled); 138 } 139 } 140}