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