package org.vaadin.touchkit.ui; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import org.vaadin.touchkit.gwt.client.vcom.DatePickerServerRpc; import org.vaadin.touchkit.gwt.client.vcom.DatePickerState; import org.vaadin.touchkit.gwt.client.vcom.DatePickerState.Resolution; import com.vaadin.v7.ui.AbstractField; import com.vaadin.v7.ui.DateField; /** * DatePicker is a field used to ask time values from the user. In contrast to * the standard Vaadin {@link DateField}, this component shows a native * DatePicker in browsers that support this. Browsers that do not support native * date pickers show a touch friendly fallback. * * Browsers that have good support for native date pickers: * <ul> * <li>iOS - full support since 5.0, earlier versions have partial support</li> * <li>Android - partial, but good support in 4.2+</li> * </ul> * Earlier versions of Android have very limited support for native date * pickers. */ @SuppressWarnings("serial") public class DatePicker extends AbstractField<Date> { /** * Constructs a new DatePicker instance with day resolution. */ public DatePicker() { registerRpc(rpc); setResolution(Resolution.DAY); } /** * Constructs a new DatePicker instance with day resolution and the * specified caption. * * @param caption * The caption */ public DatePicker(String caption) { this(); setCaption(caption); } private final DatePickerServerRpc rpc = new DatePickerServerRpc() { @Override public void valueChanged(String date) { if (date != null) { DatePicker.this.setValue(fromStr(date), false); } else { DatePicker.this.setValue(null, false); } } }; @Override public Class<Date> getType() { return Date.class; } @Override protected DatePickerState getState() { return (DatePickerState) super.getState(); } @Override public void beforeClientResponse(boolean initial) { super.beforeClientResponse(initial); Date value = getValue(); if (value == null) { getState().date = null; } else { getState().date = getFormat().format(getValue()); } Locale locale = getLocale(); if (locale != null) { getState().locale = locale.toString(); } else { getState().locale = null; } } private SimpleDateFormat getFormat() { switch (getResolution()) { case MONTH: return new SimpleDateFormat("yyyy-MM", getLocale()); case DAY: return new SimpleDateFormat("yyyy-MM-dd", getLocale()); case TIME: default: return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm", getLocale()); } } private String toStr(Date d) { return getFormat().format(d); } private Date fromStr(String dateStr) { try { return getFormat().parse(dateStr); } catch (ParseException e) { throw new RuntimeException(e); } } /** * @return The current resolution */ public Resolution getResolution() { return getState().resolution; } /** * Sets the current resolution of this DatePicker * * @param resolution * The resolution. Not all resolutions are supported on all * devices. */ public void setResolution(Resolution resolution) { getState().resolution = resolution; } /** * <p> * Sets whether to use native date field when possible or always use the * fallback. E.g. iOS Safari fully supports native date fields since iOS * version 5. * </p> * * <p> * Note that when using the native date field, {@link #setLocale(Locale)} * will have no effect, since the locale for the native field is defined by * the browser locale * </p> * * @param useNative * If true native date field is used with browsers supporting it */ public void setUseNative(boolean useNative) { getState().useNative = useNative; } /** * @return true if native date field is used in supported browsers. * @see #setUseNative(boolean) */ public boolean isUseNative() { return getState().useNative; } /** * Sets the minimum date value accepted from the user. Notice that, in * native mode, this is supported only by some devices. This function is * here for future use. * * @param min * The minimum date value accepted from the user. Set to null to * clear. The value must be before the maximum date value (if * defined). */ public void setMin(Date min) { if (min != null && getState().max != null) { if (min.after(getMax())) { throw new IllegalArgumentException("Given minimal value (" + min.toString() + "), is after maximal value (" + getState().max.toString() + ")"); } } getState().min = toStr(min); } /** * @return The minimum date value accepted from the user, null if undefined. */ public Date getMin() { return fromStr(getState().min); } /** * Sets the maximum date value accepted from the user. Notice that, in * native mode, this is supported only by some devices. This function is * here for future use. * * @param max * Maximum date value accepted from the user. Set to null to * clear. The value must be after the minimum date value (if * defined). */ public void setMax(Date max) { if (max != null && getState().min != null) { if (max.before(getMin())) { throw new IllegalArgumentException("Given maximal value (" + max.toString() + "), is before minimal value (" + getState().min.toString() + ")"); } } getState().max = toStr(max); } /** * @return The maximum date value accepted from the user, null if undefined. */ public Date getMax() { return fromStr(getState().max); } }