001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.changeset.query; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.time.LocalDate; 007import java.time.ZonedDateTime; 008import java.time.format.DateTimeFormatter; 009import java.time.format.DateTimeParseException; 010import java.time.format.FormatStyle; 011 012import javax.swing.text.JTextComponent; 013 014import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator; 015import org.openstreetmap.josm.tools.Logging; 016 017/** 018 * Validates dates entered as text in a {@link JTextComponent}. Validates the input 019 * on the fly and gives feedback about whether the date is valid or not. 020 * 021 * Dates can be entered in one of four standard formats defined for the current locale. 022 * @since 11326 (extracted from AdvancedChangesetQueryPanel) 023 */ 024public class DateValidator extends AbstractTextComponentValidator { 025 026 /** 027 * Constructs a new {@code DateValidator} for the given text component. 028 * @param tc text component 029 */ 030 public DateValidator(JTextComponent tc) { 031 super(tc); 032 } 033 034 /** 035 * Decorates the given text component. 036 * @param tc text component to decorate 037 * @return new date validator attached to {@code tc} 038 */ 039 public static DateValidator decorate(JTextComponent tc) { 040 return new DateValidator(tc); 041 } 042 043 @Override 044 public boolean isValid() { 045 return getDate() != null; 046 } 047 048 /** 049 * Returns the standard tooltip text as HTML. 050 * @return the standard tooltip text as HTML 051 */ 052 public String getStandardTooltipTextAsHtml() { 053 return "<html>" + getStandardTooltipText() + "</html>"; 054 } 055 056 /** 057 * Returns the standard tooltip text. 058 * @return the standard tooltip text 059 */ 060 public String getStandardTooltipText() { 061 final ZonedDateTime now = ZonedDateTime.now(); 062 return tr( 063 "Please enter a date in the usual format for your locale.<br>" 064 + "Example: {0}<br>" 065 + "Example: {1}<br>" 066 + "Example: {2}<br>" 067 + "Example: {3}<br>", 068 DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(now), 069 DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(now), 070 DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).format(now), 071 DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(now) 072 ); 073 } 074 075 @Override 076 public void validate() { 077 if (!isValid()) { 078 String msg = "<html>The current value isn't a valid date.<br>" + getStandardTooltipText()+ "</html>"; 079 feedbackInvalid(msg); 080 } else { 081 String msg = "<html>" + getStandardTooltipText() + "</html>"; 082 feedbackValid(msg); 083 } 084 } 085 086 /** 087 * Returns the date. 088 * @return the date 089 */ 090 public LocalDate getDate() { 091 for (final FormatStyle format: FormatStyle.values()) { 092 DateTimeFormatter df = DateTimeFormatter.ofLocalizedDate(format); 093 try { 094 return LocalDate.parse(getComponent().getText(), df); 095 } catch (DateTimeParseException e) { 096 // Try next format 097 Logging.trace(e); 098 } 099 } 100 return null; 101 } 102}