/* @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.data.Validator.InvalidValueException; import com.vaadin.event.FieldEvents; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.UserError; import com.vaadin.terminal.gwt.client.ui.VDateField; import com.vaadin.terminal.gwt.client.ui.VPopupCalendar; /** *
* A date editor component that can be bound to any bindable Property. that is
* compatible with java.util.Date
.
*
* Since DateField
extends AbstractField
it implements
* the {@link com.vaadin.data.Buffered}interface. A DateField
is in
* write-through mode by default, so
* {@link com.vaadin.ui.AbstractField#setWriteThrough(boolean)}must be called to
* enable buffering.
*
DateField
with no caption.
*/
public DateField() {
setInvalidAllowed(false);
}
/**
* Constructs an empty DateField
with caption.
*
* @param caption
* the caption of the datefield.
*/
public DateField(String caption) {
setCaption(caption);
setInvalidAllowed(false);
}
/**
* Constructs a new DateField
that's bound to the specified
* Property
and has the given caption String
.
*
* @param caption
* the caption String
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 DateField
that's bound to the specified
* Property
and has no caption.
*
* @param dataSource
* the Property to be edited with this editor.
*/
public DateField(Property dataSource) throws IllegalArgumentException {
setInvalidAllowed(false);
if (!Date.class.isAssignableFrom(dataSource.getType())) {
throw new IllegalArgumentException("Can't use "
+ dataSource.getType().getName()
+ " typed property as datasource");
}
setPropertyDataSource(dataSource);
}
/**
* Constructs a new DateField
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 String
for the editor.
* @param value
* the Date value.
*/
public DateField(String caption, Date value) {
setInvalidAllowed(false);
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);
}
if (!isLenient()) {
target.addAttribute("strict", true);
}
target.addAttribute(VDateField.WEEK_NUMBERS, isShowISOWeekNumbers());
target.addAttribute("parsable", parsingSucceeded);
// 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;
}
}
}
/*
* 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, MapCalendar.getInstance
* 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 Vaadin 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;
}
/**
* Specifies whether or not date/time interpretation in component is to be
* lenient.
*
* @see Calendar#setLenient(boolean)
* @see #isLenient()
*
* @param lenient
* true if the lenient mode is to be turned on; false if it is to
* be turned off.
*/
public void setLenient(boolean lenient) {
this.lenient = lenient;
requestRepaint();
}
/**
* Returns whether date/time interpretation is to be lenient.
*
* @see #setLenient(boolean)
*
* @return true if the interpretation mode of this calendar is lenient;
* false otherwise.
*/
public boolean isLenient() {
return lenient;
}
public void addListener(FocusListener listener) {
addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
FocusListener.focusMethod);
}
public void removeListener(FocusListener listener) {
removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
}
public void addListener(BlurListener listener) {
addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
BlurListener.blurMethod);
}
public void removeListener(BlurListener listener) {
removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
}
/**
* Checks whether ISO 8601 week numbers are shown in the date selector.
*
* @return true if week numbers are shown, false otherwise.
*/
public boolean isShowISOWeekNumbers() {
return showISOWeekNumbers;
}
/**
* Sets the visibility of ISO 8601 week numbers in the date selector. ISO
* 8601 defines that a week always starts with a Monday so the week numbers
* are only shown if this is the case.
*
* @param showWeekNumbers
* true if week numbers should be shown, false otherwise.
*/
public void setShowISOWeekNumbers(boolean showWeekNumbers) {
showISOWeekNumbers = showWeekNumbers;
requestRepaint();
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractField#isEmpty()
*/
@Override
protected boolean isEmpty() {
/*
* Logically isEmpty() should return false also in the case that the
* entered value is invalid.
*/
boolean empty = (dateString == null || dateString.equals(""));
return empty;
}
@Override
public void valueChange(Property.ValueChangeEvent event) {
/*
* We also need to update the dateString if the value of the property
* data source changes. This has to be done before super fires the value
* change event in case someone checks isEmpty in a value change
* listener.
*/
Object value = getValue();
if (value != null) {
dateString = value.toString();
}
super.valueChange(event);
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractField#isValid()
*/
@Override
public boolean isValid() {
/*
* For the DateField to be valid it has to be parsable also
*/
boolean parsable = isEmpty() || (!isEmpty() && getValue() != null);
return parsable && super.isValid();
}
}