package pt.ist.renderers.extensions; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import javax.servlet.http.HttpServletRequest; import org.apache.struts.util.RequestUtils; import org.joda.time.DateTime; import pt.ist.renderers.InputRenderer; import pt.ist.renderers.components.HtmlComponent; import pt.ist.renderers.components.HtmlHiddenField; import pt.ist.renderers.components.HtmlInlineContainer; import pt.ist.renderers.components.HtmlText; import pt.ist.renderers.components.HtmlTextInput; import pt.ist.renderers.components.controllers.HtmlController; import pt.ist.renderers.components.converters.ConversionException; import pt.ist.renderers.components.converters.Converter; import pt.ist.renderers.components.state.IViewState; import pt.ist.renderers.converters.DateConverter; import pt.ist.renderers.layouts.Layout; import pt.ist.renderers.model.MetaSlotKey; import pt.ist.renderers.utils.RenderUtils; /** * This renderers provides a standard input presentation for a * DateTime from the Joda framework. The user is aked for a date an * hour and the minutes in three separate input fields. * *

* Example: hh:mm * * @author cfgi */ public class DateTimeInputRenderer extends InputRenderer { private String dateFormat; private String dateFormatText; private String dateBundle; private boolean dateKey; private String dateSize; private Integer dateMaxLength; public String getDateFormat() { return this.dateFormat == null ? DateConverter.DEFAULT_FORMAT : dateFormat; } /** * The format in which the date should be displayed. The format can have the * form accepted by SimpleDateFormat * *

* The default format is {@value DateConverter#DEFAULT_FORMAT}. * * @property */ public void setDateFormat(String dateFormat) { this.dateFormat = dateFormat; } public String getDateFormatText() { return this.dateFormatText; } /** * By default the value of dateFormat is used to show to the * user how to write the date. This property allows you to override that * default. This means that the value of the property will be shown instead. * * @property */ public void setDateFormatText(String dateFormatText) { this.dateFormatText = dateFormatText; } public String getDateBundle() { return this.dateBundle; } /** * When the value of the dateFormatText is a key this property * indicates the name of the bundle where the key will be looked for. * * @property */ public void setDateBundle(String dateBundle) { this.dateBundle = dateBundle; } public boolean isDateKey() { return this.dateKey; } /** * Indicates the the value of the dateFormatText property is a * key and not the text itself. * * @property */ public void setDateKey(boolean dateKey) { this.dateKey = dateKey; } public Integer getDateMaxLength() { return this.dateMaxLength; } /** * Sets the max length of the date field. * * @property */ public void setDateMaxLength(Integer dateMaxLength) { this.dateMaxLength = dateMaxLength; } public String getDateSize() { return this.dateSize; } /** * Chooses the size of the date field. * * @property */ public void setDateSize(String dateSize) { this.dateSize = dateSize; } protected Locale getLocale() { HttpServletRequest request = getInputContext().getViewState().getRequest(); return RequestUtils.getUserLocale(request, null); } @Override protected Layout getLayout(Object object, Class type) { return new DateTimeLayout(); } public class DateTimeLayout extends Layout { @Override public HtmlComponent createComponent(Object object, Class type) { DateTime dateTime = (DateTime) object; Date date = null; Calendar calendar = null; if (dateTime != null) { date = dateTime.toGregorianCalendar().getTime(); calendar = Calendar.getInstance(); calendar.setTime(date); } MetaSlotKey key = (MetaSlotKey) getInputContext().getMetaObject().getKey(); HtmlInlineContainer container = new HtmlInlineContainer(); HtmlHiddenField hiddenField = new HtmlHiddenField(); hiddenField.setTargetSlot(key); container.addChild(hiddenField); HtmlTextInput dateField = new HtmlTextInput(); dateField.setName(key.toString() + "_date"); dateField.setSize(getDateSize()); dateField.setMaxLength(getDateMaxLength()); container.addChild(dateField); container.addChild(new HtmlText(getFormatLabel())); Locale locale = getLocale(); SimpleDateFormat dateFormat = new SimpleDateFormat(getDateFormat(), locale); if (date != null) { dateField.setValue(dateFormat.format(date)); } HtmlTextInput hoursField = new HtmlTextInput(); hoursField.setName(key.toString() + "_hours"); hoursField.setSize("2"); hoursField.setMaxLength(2); container.addChild(hoursField); if (calendar != null) { hoursField.setValue(String.format("%02d", calendar.get(Calendar.HOUR_OF_DAY))); } container.addChild(new HtmlText("hh")); HtmlTextInput minutesField = new HtmlTextInput(); minutesField.setName(key.toString() + "_minutes"); minutesField.setSize("2"); minutesField.setMaxLength(2); container.addChild(minutesField); if (calendar != null) { minutesField.setValue(String.format("%02d", calendar.get(Calendar.MINUTE))); } container.addChild(new HtmlText("mm")); hiddenField.setConverter(new DateTimeConverter(dateField, hoursField, minutesField)); minutesField.setController(new DateTimeController(hiddenField, dateFormat, dateField, hoursField, minutesField)); return container; } protected String getFormatLabel() { if (isDateKey()) { return RenderUtils.getResourceString(getDateBundle(), getDateFormatText()); } else { if (getDateFormatText() != null) { return getDateFormatText(); } else { return getDateFormat(); } } } } private class DateTimeController extends HtmlController { private HtmlHiddenField valueField; private DateFormat dateFormat; private HtmlTextInput dateField; private HtmlTextInput hoursField; private HtmlTextInput minutesField; public DateTimeController(HtmlHiddenField hiddenField, DateFormat dateFormat, HtmlTextInput dateField, HtmlTextInput hoursField, HtmlTextInput minutesField) { this.valueField = hiddenField; this.dateFormat = dateFormat; this.dateField = dateField; this.hoursField = hoursField; this.minutesField = minutesField; } @Override public void execute(IViewState viewState) { DateConverter converter = new DateConverter(this.dateFormat); try { Date date = (Date) converter.convert(Date.class, this.dateField.getValue()); if (date == null) { if ((this.hoursField.getValue() != null && this.hoursField.getValue().length() > 0) || (this.minutesField.getValue() != null && this.minutesField.getValue().length() > 0)) { this.valueField.setValue(DateTimeConverter.INCOMPLETE); } else { this.valueField.setValue(""); } return; } String hours = DateTimeConverter.zeroPad(this.hoursField.getValue()); String minutes = DateTimeConverter.zeroPad(this.minutesField.getValue()); String value = String.format("%tFT%s:%s", date, hours, minutes); this.valueField.setValue(value); } catch (ConversionException e) { this.valueField.setValue(DateTimeConverter.INVALID); } } } public static class DateTimeConverter extends Converter { public static final String INVALID = "invalid"; public static final String INCOMPLETE = "incomplete"; private HtmlTextInput dateField; private HtmlTextInput hoursField; private HtmlTextInput minutesField; public DateTimeConverter(HtmlTextInput dateField, HtmlTextInput hoursField, HtmlTextInput minutesField) { this.dateField = dateField; this.hoursField = hoursField; this.minutesField = minutesField; } @Override public Object convert(Class type, Object value) { if (value == null || String.valueOf(value).length() == 0) { return null; } if (value.equals(INVALID)) { throw new ConversionException("fenix.renderers.converter.dateTime.invalid", true, this.dateField.getValue()); } String hours = zeroPad(this.hoursField.getValue()); String minutes = zeroPad(this.minutesField.getValue()); if (value.equals(INCOMPLETE)) { throw new ConversionException("fenix.renderers.converter.dateTime.incomplete", true, hours, minutes); } try { return new DateTime(value); } catch (IllegalArgumentException e) { String date = dateField.getValue(); throw new ConversionException("fenix.renderers.converter.dateTime.convert", e, true, date, hours, minutes); } } public static String zeroPad(String text) { if (text == null) { return "00"; } return (text.length() < 2 ? "0" : "") + (text.length() < 1 ? "0" : "") + text; } } }