/* @ITMillApache2LicenseForJavaFiles@ */ package com.vaadin.data.util; import java.util.LinkedList; import com.vaadin.data.Property; /** * Formatting proxy for a property. * *
* This class can be used to implement formatting for any type of Property * datasources. The idea is to connect this as proxy between UI component and * the original datasource. *
* *
* For example
* textfield.setPropertyDataSource(new PropertyFormatter(property) {
public String format(Object value) {
return ((Double) value).toString() + "000000000";
}
public Object parse(String formattedValue) throws Exception {
return Double.parseDouble(formattedValue);
}
});
adds formatter for Double-typed property that extends standard
* "1.0" notation with more zeroes.
*
null
if
* none defined.
*/
public Property getPropertyDataSource() {
return dataSource;
}
/**
* Sets the specified Property as the data source for the formatter.
*
*
* * Remember that new data sources getValue() must return objects that are * compatible with parse() and format() methods. *
* * @param newDataSource * the new data source Property. */ public void setPropertyDataSource(Property newDataSource) { boolean readOnly = false; String prevValue = null; if (dataSource != null) { if (dataSource instanceof Property.ValueChangeNotifier) { ((Property.ValueChangeNotifier) dataSource) .removeListener(this); } if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { ((Property.ReadOnlyStatusChangeNotifier) dataSource) .removeListener(this); } readOnly = isReadOnly(); prevValue = toString(); } dataSource = newDataSource; if (dataSource != null) { if (dataSource instanceof Property.ValueChangeNotifier) { ((Property.ValueChangeNotifier) dataSource).addListener(this); } if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { ((Property.ReadOnlyStatusChangeNotifier) dataSource) .addListener(this); } } if (isReadOnly() != readOnly) { fireReadOnlyStatusChange(); } String newVal = toString(); if ((prevValue == null && newVal != null) || (prevValue != null && !prevValue.equals(newVal))) { fireValueChange(); } } /* Documented in the interface */ public Class getType() { return String.class; } /** * Get the formatted value. * * @return If the datasource returns null, this is null. Otherwise this is * String given by format(). */ public Object getValue() { return toString(); } /** * Get the formatted value. * * @return If the datasource returns null, this is null. Otherwise this is * String given by format(). */ @Override public String toString() { Object value = dataSource == null ? false : dataSource.getValue(); if (value == null) { return null; } return format(value); } /** Reflects the read-only status of the datasource. */ public boolean isReadOnly() { return dataSource == null ? false : dataSource.isReadOnly(); } /** * This method must be implemented to format the values received from * DataSource. * * @param value * Value object got from the datasource. This is guaranteed to be * non-null and of the type compatible with getType() of the * datasource. * @return */ abstract public String format(Object value); /** * Parse string and convert it to format compatible with datasource. * * The method is required to assure that parse(format(x)) equals x. * * @param formattedValue * This is guaranteed to be non-null string. * @return Non-null value compatible with datasource. * @throws Exception * Any type of exception can be thrown to indicate that the * conversion was not succesful. */ abstract public Object parse(String formattedValue) throws Exception; /** * Sets the Property's read-only mode to the specified status. * * @param newStatus * the new read-only status of the Property. */ public void setReadOnly(boolean newStatus) { if (dataSource != null) { dataSource.setReadOnly(newStatus); } } public void setValue(Object newValue) throws ReadOnlyException, ConversionException { if (dataSource == null) { return; } if (newValue == null) { dataSource.setValue(null); } try { dataSource.setValue(parse((String) newValue)); if (!newValue.equals(toString())) { fireValueChange(); } } catch (Exception e) { if (e instanceof ConversionException) { throw (ConversionException) e; } else { throw new ConversionException(e); } } } /** * AnEvent
object specifying the ObjectProperty whose value
* has changed.
*
* @author IT Mill Ltd.
* @since 5.3.0
*/
private class ValueChangeEvent extends java.util.EventObject implements
Property.ValueChangeEvent {
/**
* Constructs a new value change event for this object.
*
* @param source
* the source object of the event.
*/
protected ValueChangeEvent(PropertyFormatter source) {
super(source);
}
/**
* Gets the Property whose read-only state has changed.
*
* @return source the Property of the event.
*/
public Property getProperty() {
return (Property) getSource();
}
}
/**
* An Event
object specifying the Property whose read-only
* status has been changed.
*
* @author IT Mill Ltd.
* @since 5.3.0
*/
private class ReadOnlyStatusChangeEvent extends java.util.EventObject
implements Property.ReadOnlyStatusChangeEvent {
/**
* Constructs a new read-only status change event for this object.
*
* @param source
* source object of the event
*/
protected ReadOnlyStatusChangeEvent(PropertyFormatter source) {
super(source);
}
/**
* Gets the Property whose read-only state has changed.
*
* @return source Property of the event.
*/
public Property getProperty() {
return (Property) getSource();
}
}
/**
* Removes a previously registered value change listener.
*
* @param listener
* the listener to be removed.
*/
public void removeListener(Property.ValueChangeListener listener) {
if (valueChangeListeners != null) {
valueChangeListeners.remove(listener);
}
}
/**
* Registers a new value change listener for this ObjectProperty.
*
* @param listener
* the new Listener to be registered
*/
public void addListener(Property.ValueChangeListener listener) {
if (valueChangeListeners == null) {
valueChangeListeners = new LinkedList();
}
valueChangeListeners.add(listener);
}
/**
* Registers a new read-only status change listener for this Property.
*
* @param listener
* the new Listener to be registered
*/
public void addListener(Property.ReadOnlyStatusChangeListener listener) {
if (readOnlyStatusChangeListeners == null) {
readOnlyStatusChangeListeners = new LinkedList();
}
readOnlyStatusChangeListeners.add(listener);
}
/**
* Removes a previously registered read-only status change listener.
*
* @param listener
* the listener to be removed.
*/
public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
if (readOnlyStatusChangeListeners != null) {
readOnlyStatusChangeListeners.remove(listener);
}
}
/**
* Sends a value change event to all registered listeners.
*/
private void fireValueChange() {
if (valueChangeListeners != null) {
final Object[] l = valueChangeListeners.toArray();
final Property.ValueChangeEvent event = new ValueChangeEvent(this);
for (int i = 0; i < l.length; i++) {
((Property.ValueChangeListener) l[i]).valueChange(event);
}
}
}
/**
* Sends a read only status change event to all registered listeners.
*/
private void fireReadOnlyStatusChange() {
if (readOnlyStatusChangeListeners != null) {
final Object[] l = readOnlyStatusChangeListeners.toArray();
final Property.ReadOnlyStatusChangeEvent event = new ReadOnlyStatusChangeEvent(
this);
for (int i = 0; i < l.length; i++) {
((Property.ReadOnlyStatusChangeListener) l[i])
.readOnlyStatusChange(event);
}
}
}
/**
* Listens for changes in the datasource.
*
* This should not be called directly.
*/
public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
fireValueChange();
}
/**
* Listens for changes in the datasource.
*
* This should not be called directly.
*/
public void readOnlyStatusChange(
com.vaadin.data.Property.ReadOnlyStatusChangeEvent event) {
fireReadOnlyStatusChange();
}
}