001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.extensions.markup.html.form.datetime; 018 019import java.time.LocalDate; 020import java.time.chrono.IsoChronology; 021import java.time.format.DateTimeFormatter; 022import java.time.format.DateTimeFormatterBuilder; 023import java.time.format.DateTimeParseException; 024import java.time.format.FormatStyle; 025import java.time.temporal.TemporalAccessor; 026import java.util.Locale; 027 028import org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider; 029import org.apache.wicket.markup.html.form.TextField; 030import org.apache.wicket.model.IModel; 031import org.apache.wicket.util.convert.IConverter; 032import org.apache.wicket.util.convert.converter.LocalDateConverter; 033import org.apache.wicket.util.string.Strings; 034 035/** 036 * A TextField that is mapped to a <code>java.time.LocalDate</code> object and that uses java.time time to 037 * parse and format values. 038 * 039 * @see java.time.format.DateTimeFormatter 040 * 041 * @author eelcohillenius 042 */ 043public class LocalDateTextField extends TextField<LocalDate> implements ITextFormatProvider 044{ 045 private static final long serialVersionUID = 1L; 046 047 /** 048 * The converter for the TextField 049 */ 050 private final TextFormatConverter converter; 051 052 /** 053 * Construct with a pattern. 054 * 055 * @param id 056 * the component id 057 * @param pattern 058 * the pattern to use 059 */ 060 public LocalDateTextField(String id, String pattern) 061 { 062 this(id, null, pattern); 063 } 064 065 /** 066 * Construct with a pattern. 067 * 068 * @param id 069 * the component id 070 * @param model 071 * the model 072 * @param pattern 073 * the pattern to use 074 */ 075 public LocalDateTextField(String id, IModel<LocalDate> model, String pattern) 076 { 077 this(id, model, pattern, pattern); 078 } 079 080 /** 081 * Construct with pattern for formatting and parsing. 082 * 083 * @param id 084 * the component id 085 * @param model 086 * the model 087 * @param formatPattern 088 * the pattern to use for formatting 089 * @param parsePattern 090 * the pattern to use for parsing 091 */ 092 public LocalDateTextField(String id, IModel<LocalDate> model, String formatPattern, String parsePattern) 093 { 094 super(id, model, LocalDate.class); 095 096 this.converter = new TextFormatConverter() { 097 private static final long serialVersionUID = 1L; 098 099 @Override 100 protected DateTimeFormatter getDateTimeFormatter() 101 { 102 return DateTimeFormatter.ofPattern(formatPattern); 103 } 104 105 /** 106 * Overwritten to support a custom parse pattern. 107 */ 108 @Override 109 public LocalDate convertToObject(final String value, Locale locale) 110 { 111 if (Strings.isEmpty(value)) 112 { 113 return null; 114 } 115 116 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(parsePattern).withLocale(locale); 117 TemporalAccessor temporalAccessor; 118 try { 119 temporalAccessor = dateTimeFormatter.parse(value); 120 } catch (DateTimeParseException ex) { 121 throw newConversionException("Cannot parse '" + value, value, locale); 122 } 123 124 return createTemporal(temporalAccessor); 125 } 126 127 @Override 128 public String getTextFormat(Locale locale) 129 { 130 return formatPattern; 131 } 132 }; 133 } 134 135 /** 136 * Construct with a style. 137 * 138 * @param id 139 * the component id 140 * @param dateStyle 141 * the style to use 142 */ 143 public LocalDateTextField(String id, FormatStyle dateStyle) 144 { 145 this(id, null, dateStyle); 146 } 147 148 /** 149 * Construct with a style. 150 * 151 * @param id 152 * the component id 153 * @param model 154 * the model 155 * @param dateStyle 156 * the style to use 157 */ 158 public LocalDateTextField(String id, IModel<LocalDate> model, FormatStyle dateStyle) 159 { 160 super(id, model, LocalDate.class); 161 162 this.converter = new TextFormatConverter() { 163 private static final long serialVersionUID = 1L; 164 165 @Override 166 protected DateTimeFormatter getDateTimeFormatter() 167 { 168 return DateTimeFormatter.ofLocalizedDate(dateStyle); 169 } 170 171 @Override 172 public String getTextFormat(Locale locale) 173 { 174 return DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, null, IsoChronology.INSTANCE, locale); 175 } 176 }; 177 } 178 179 /** 180 * @return The specialized converter. 181 * @see org.apache.wicket.Component#createConverter(java.lang.Class) 182 */ 183 @Override 184 protected IConverter<?> createConverter(Class<?> clazz) 185 { 186 if (LocalDate.class.isAssignableFrom(clazz)) 187 { 188 return converter; 189 } 190 return null; 191 } 192 193 /** 194 * @see org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider#getTextFormat() 195 */ 196 @Override 197 public final String getTextFormat() 198 { 199 return converter.getTextFormat(getLocale()); 200 } 201 202 private abstract class TextFormatConverter extends LocalDateConverter { 203 private static final long serialVersionUID = 1L; 204 205 public abstract String getTextFormat(Locale locale); 206 } 207}