123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- /*
- @ITMillApache2LicenseForJavaFiles@
- */
-
- package com.vaadin.ui;
-
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.Locale;
- import java.util.Map;
-
- import com.vaadin.data.Property;
- import com.vaadin.terminal.PaintException;
- import com.vaadin.terminal.PaintTarget;
-
- /**
- * <p>
- * A date editor component that can be bound to any bindable Property. that is
- * compatible with <code>java.util.Date</code>.
- * </p>
- * <p>
- * Since <code>DateField</code> extends <code>AbstractField</code> it implements
- * the {@link com.vaadin.data.Buffered}interface. A
- * <code>DateField</code> is in write-through mode by default, so
- * {@link com.vaadin.ui.AbstractField#setWriteThrough(boolean)}must be
- * called to enable buffering.
- * </p>
- *
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
- @SuppressWarnings("serial")
- public class DateField extends AbstractField {
-
- /* Private members */
-
- /**
- * Resolution identifier: milliseconds.
- */
- public static final int RESOLUTION_MSEC = 0;
-
- /**
- * Resolution identifier: seconds.
- */
- public static final int RESOLUTION_SEC = 1;
-
- /**
- * Resolution identifier: minutes.
- */
- public static final int RESOLUTION_MIN = 2;
-
- /**
- * Resolution identifier: hours.
- */
- public static final int RESOLUTION_HOUR = 3;
-
- /**
- * Resolution identifier: days.
- */
- public static final int RESOLUTION_DAY = 4;
-
- /**
- * Resolution identifier: months.
- */
- public static final int RESOLUTION_MONTH = 5;
-
- /**
- * Resolution identifier: years.
- */
- public static final int RESOLUTION_YEAR = 6;
-
- /**
- * Popup date selector (calendar).
- */
- protected static final String TYPE_POPUP = "popup";
-
- /**
- * Inline date selector (calendar).
- */
- protected static final String TYPE_INLINE = "inline";
-
- /**
- * Specified widget type.
- */
- protected String type = TYPE_POPUP;
-
- /**
- * Specified smallest modifiable unit.
- */
- private int resolution = RESOLUTION_MSEC;
-
- /**
- * Specified largest modifiable unit.
- */
- private static final int largestModifiable = RESOLUTION_YEAR;
-
- /**
- * The internal calendar to be used in java.utl.Date conversions.
- */
- private Calendar calendar;
-
- /**
- * Overridden format string
- */
- private String dateFormat;
-
- /**
- * Read-only content of an VTextualDate field - null for other types of date
- * fields.
- */
- private String dateString;
-
- /* Constructors */
-
- /**
- * Constructs an empty <code>DateField</code> with no caption.
- */
- public DateField() {
- }
-
- /**
- * Constructs an empty <code>DateField</code> with caption.
- *
- * @param caption
- * the caption of the datefield.
- */
- public DateField(String caption) {
- setCaption(caption);
- }
-
- /**
- * Constructs a new <code>DateField</code> that's bound to the specified
- * <code>Property</code> and has the given caption <code>String</code>.
- *
- * @param caption
- * the caption <code>String</code> for the editor.
- * @param dataSource
- * the Property to be edited with this editor.
- */
- public DateField(String caption, Property dataSource) {
- this(dataSource);
- setCaption(caption);
- }
-
- /**
- * Constructs a new <code>DateField</code> that's bound to the specified
- * <code>Property</code> and has no caption.
- *
- * @param dataSource
- * the Property to be edited with this editor.
- */
- public DateField(Property dataSource) throws IllegalArgumentException {
- if (!Date.class.isAssignableFrom(dataSource.getType())) {
- throw new IllegalArgumentException("Can't use "
- + dataSource.getType().getName()
- + " typed property as datasource");
- }
-
- setPropertyDataSource(dataSource);
- }
-
- /**
- * Constructs a new <code>DateField</code> with the given caption and
- * initial text contents. The editor constructed this way will not be bound
- * to a Property unless
- * {@link com.vaadin.data.Property.Viewer#setPropertyDataSource(Property)}
- * is called to bind it.
- *
- * @param caption
- * the caption <code>String</code> for the editor.
- * @param value
- * the Date value.
- */
- public DateField(String caption, Date value) {
- setValue(value);
- setCaption(caption);
- }
-
- /* Component basic features */
-
- /*
- * Paints this component. Don't add a JavaDoc comment here, we use the
- * default documentation from implemented interface.
- */
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- super.paintContent(target);
-
- // Adds the locale as attribute
- final Locale l = getLocale();
- if (l != null) {
- target.addAttribute("locale", l.toString());
- }
-
- if (getDateFormat() != null) {
- target.addAttribute("format", dateFormat);
- }
-
- target.addAttribute("type", type);
-
- // Gets the calendar
- final Calendar calendar = getCalendar();
- final Date currentDate = (Date) getValue();
-
- for (int r = resolution; r <= largestModifiable; r++) {
- switch (r) {
- case RESOLUTION_MSEC:
- target.addVariable(this, "msec", currentDate != null ? calendar
- .get(Calendar.MILLISECOND) : -1);
- break;
- case RESOLUTION_SEC:
- target.addVariable(this, "sec", currentDate != null ? calendar
- .get(Calendar.SECOND) : -1);
- break;
- case RESOLUTION_MIN:
- target.addVariable(this, "min", currentDate != null ? calendar
- .get(Calendar.MINUTE) : -1);
- break;
- case RESOLUTION_HOUR:
- target.addVariable(this, "hour", currentDate != null ? calendar
- .get(Calendar.HOUR_OF_DAY) : -1);
- break;
- case RESOLUTION_DAY:
- target.addVariable(this, "day", currentDate != null ? calendar
- .get(Calendar.DAY_OF_MONTH) : -1);
- break;
- case RESOLUTION_MONTH:
- target.addVariable(this, "month",
- currentDate != null ? calendar.get(Calendar.MONTH) + 1
- : -1);
- break;
- case RESOLUTION_YEAR:
- target.addVariable(this, "year", currentDate != null ? calendar
- .get(Calendar.YEAR) : -1);
- break;
- }
- }
- }
-
- /*
- * Gets the components UIDL tag string. Don't add a JavaDoc comment here, we
- * use the default documentation from implemented interface.
- */
- @Override
- public String getTag() {
- return "datefield";
- }
-
- /*
- * Invoked when a variable of the component changes. Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public void changeVariables(Object source, Map variables) {
- super.changeVariables(source, variables);
-
- if (!isReadOnly()
- && (variables.containsKey("year")
- || variables.containsKey("month")
- || variables.containsKey("day")
- || variables.containsKey("hour")
- || variables.containsKey("min")
- || variables.containsKey("sec")
- || variables.containsKey("msec") || variables
- .containsKey("dateString"))) {
-
- // Old and new dates
- final Date oldDate = (Date) getValue();
- final String oldDateString = dateString;
- Date newDate = null;
-
- // this enables analyzing invalid input on the server
- Object o = variables.get("dateString");
- if (o != null) {
- dateString = o.toString();
- } else {
- dateString = null;
- }
-
- // Gets the new date in parts
- // Null values are converted to negative values.
- int year = variables.containsKey("year") ? (variables.get("year") == null ? -1
- : ((Integer) variables.get("year")).intValue())
- : -1;
- int month = variables.containsKey("month") ? (variables
- .get("month") == null ? -1 : ((Integer) variables
- .get("month")).intValue() - 1) : -1;
- int day = variables.containsKey("day") ? (variables.get("day") == null ? -1
- : ((Integer) variables.get("day")).intValue())
- : -1;
- int hour = variables.containsKey("hour") ? (variables.get("hour") == null ? -1
- : ((Integer) variables.get("hour")).intValue())
- : -1;
- int min = variables.containsKey("min") ? (variables.get("min") == null ? -1
- : ((Integer) variables.get("min")).intValue())
- : -1;
- int sec = variables.containsKey("sec") ? (variables.get("sec") == null ? -1
- : ((Integer) variables.get("sec")).intValue())
- : -1;
- int msec = variables.containsKey("msec") ? (variables.get("msec") == null ? -1
- : ((Integer) variables.get("msec")).intValue())
- : -1;
-
- // If all of the components is < 0 use the previous value
- if (year < 0 && month < 0 && day < 0 && hour < 0 && min < 0
- && sec < 0 && msec < 0) {
- newDate = null;
- } else {
-
- // Clone the calendar for date operation
- final Calendar cal = getCalendar();
-
- // Make sure that meaningful values exists
- // Use the previous value if some of the variables
- // have not been changed.
- year = year < 0 ? cal.get(Calendar.YEAR) : year;
- month = month < 0 ? cal.get(Calendar.MONTH) : month;
- day = day < 0 ? cal.get(Calendar.DAY_OF_MONTH) : day;
- hour = hour < 0 ? cal.get(Calendar.HOUR_OF_DAY) : hour;
- min = min < 0 ? cal.get(Calendar.MINUTE) : min;
- sec = sec < 0 ? cal.get(Calendar.SECOND) : sec;
- msec = msec < 0 ? cal.get(Calendar.MILLISECOND) : msec;
-
- // Sets the calendar fields
- cal.set(Calendar.YEAR, year);
- cal.set(Calendar.MONTH, month);
- cal.set(Calendar.DAY_OF_MONTH, day);
- cal.set(Calendar.HOUR_OF_DAY, hour);
- cal.set(Calendar.MINUTE, min);
- cal.set(Calendar.SECOND, sec);
- cal.set(Calendar.MILLISECOND, msec);
-
- // Assigns the date
- newDate = cal.getTime();
- }
-
- if (newDate != oldDate
- && (newDate == null || !newDate.equals(oldDate))) {
- setValue(newDate, true); // Don't require a repaint, client
- // updates itself
- } else if (dateString != null && !"".equals(dateString)
- && !dateString.equals(oldDateString)) {
- setValue(handleUnparsableDateString(dateString));
- }
- }
- }
-
- /**
- * This method is called to handle the date string from the client if the
- * client could not parse it as a Date.
- *
- * By default, null is returned. If an exception is thrown, the current
- * value will not be modified.
- *
- * This can be overridden to handle conversions or to throw an exception, or
- * to fire an event.
- *
- * The default behavior is likely to change in the next major version of the
- * toolkit - a Property.ConversionException will be thrown.
- *
- * @param dateString
- * @return parsed Date
- * @throws Property.ConversionException
- * to keep the old value and indicate an error
- */
- protected Date handleUnparsableDateString(String dateString)
- throws Property.ConversionException {
- // TODO in the next major version, this should throw an exception to be
- // consistent with other fields
- // throw new Property.ConversionException();
- return null;
- }
-
- /* Property features */
-
- /*
- * Gets the edited property's type. Don't add a JavaDoc comment here, we use
- * the default documentation from implemented interface.
- */
- @Override
- public Class getType() {
- return Date.class;
- }
-
- /*
- * Returns the value of the property in human readable textual format. Don't
- * add a JavaDoc comment here, we use the default documentation from
- * implemented interface.
- */
- @Override
- public String toString() {
- final Date value = (Date) getValue();
- if (value != null) {
- return value.toString();
- }
- return null;
- }
-
- /*
- * Sets the value of the property. Don't add a JavaDoc comment here, we use
- * the default documentation from implemented interface.
- */
- @Override
- public void setValue(Object newValue) throws Property.ReadOnlyException,
- Property.ConversionException {
- setValue(newValue, false);
- }
-
- @Override
- public void setValue(Object newValue, boolean repaintIsNotNeeded)
- throws Property.ReadOnlyException, Property.ConversionException {
-
- // Allows setting dates directly
- if (newValue == null || newValue instanceof Date) {
- super.setValue(newValue, repaintIsNotNeeded);
- } else {
-
- // Try to parse as string
- try {
- final SimpleDateFormat parser = new SimpleDateFormat();
- final Date val = parser.parse(newValue.toString());
- super.setValue(val, repaintIsNotNeeded);
- } catch (final ParseException e) {
- throw new Property.ConversionException(e.getMessage());
- }
- }
- }
-
- /**
- * Sets the DateField datasource. Datasource type must assignable to Date.
- *
- * @see com.vaadin.data.Property.Viewer#setPropertyDataSource(Property)
- */
- @Override
- public void setPropertyDataSource(Property newDataSource) {
- if (newDataSource == null
- || Date.class.isAssignableFrom(newDataSource.getType())) {
- super.setPropertyDataSource(newDataSource);
- } else {
- throw new IllegalArgumentException(
- "DateField only supports Date properties");
- }
- }
-
- /**
- * Gets the resolution.
- *
- * @return int
- */
- public int getResolution() {
- return resolution;
- }
-
- /**
- * Sets the resolution of the DateField.
- *
- * @param resolution
- * the resolution to set.
- */
- public void setResolution(int resolution) {
- this.resolution = resolution;
- }
-
- /**
- * Returns new instance calendar used in Date conversions.
- *
- * Returns new clone of the calendar object initialized using the the
- * current date (if available)
- *
- * If this is no calendar is assigned the <code>Calendar.getInstance</code>
- * is used.
- *
- * @return the Calendar.
- * @see #setCalendar(Calendar)
- */
- private Calendar getCalendar() {
-
- // Makes sure we have an calendar instance
- if (calendar == null) {
- calendar = Calendar.getInstance();
- }
-
- // Clone the instance
- final Calendar newCal = (Calendar) calendar.clone();
-
- // Assigns the current time tom calendar.
- final Date currentDate = (Date) getValue();
- if (currentDate != null) {
- newCal.setTime(currentDate);
- }
-
- return newCal;
- }
-
- /**
- * Sets formatting used by some component implementations. See
- * {@link SimpleDateFormat} for format details.
- *
- * By default it is encouraged to used default formatting defined by Locale,
- * but due some JVM bugs it is sometimes necessary to use this method to
- * override formatting. See Toolkit issue #2200.
- *
- * @param dateFormat
- * the dateFormat to set
- *
- * @see com.vaadin.ui.AbstractComponent#setLocale(Locale))
- */
- public void setDateFormat(String dateFormat) {
- this.dateFormat = dateFormat;
- }
-
- /**
- * Reterns a format string used to format date value on client side or null
- * if default formatting from {@link Component#getLocale()} is used.
- *
- * @return the dateFormat
- */
- public String getDateFormat() {
- return dateFormat;
- }
-
- }
|