From 42ceb61b642702d31daf740771b39cedc052c308 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Thu, 15 May 2008 12:44:09 +0000 Subject: [PATCH] fixed bad code code style svn changeset:4509/svn branch:trunk --- src/com/itmill/toolkit/ui/AbstractField.java | 1848 +++++++++--------- 1 file changed, 926 insertions(+), 922 deletions(-) diff --git a/src/com/itmill/toolkit/ui/AbstractField.java b/src/com/itmill/toolkit/ui/AbstractField.java index f067cd961e..7fef394a97 100644 --- a/src/com/itmill/toolkit/ui/AbstractField.java +++ b/src/com/itmill/toolkit/ui/AbstractField.java @@ -49,927 +49,931 @@ import com.itmill.toolkit.terminal.PaintTarget; * @since 3.0 */ public abstract class AbstractField extends AbstractComponent implements Field, - Property.ReadOnlyStatusChangeNotifier { - - /* Private members ************************************************* */ - - private boolean delayedFocus; - - /** - * Value of the datafield. - */ - private Object value; - - /** - * Connected data-source. - */ - private Property dataSource = null; - - /** - * The list of validators. - */ - private LinkedList validators = null; - - /** - * Auto commit mode. - */ - private boolean writeTroughMode = true; - - /** - * Reads the value from data-source, when it is not modified. - */ - private boolean readTroughMode = true; - - /** - * Is the field modified but not committed. - */ - private boolean modified = false; - - /** - * Current source exception. - */ - private Buffered.SourceException currentBufferedSourceException = null; - - /** - * Are the invalid values alloved in fields ? - */ - private boolean invalidAllowed = true; - - /** - * Are the invalid values committed ? - */ - private boolean invalidCommitted = false; - - /** - * The tab order number of this field. - */ - private int tabIndex = 0; - - /** - * Required field. - */ - private boolean required = false; - - /* Component basics ************************************************ */ - - /* - * Paints the field. Don't add a JavaDoc comment here, we use the default - * documentation from the implemented interface. - */ - public void paintContent(PaintTarget target) throws PaintException { - - // The tab ordering number - if (tabIndex > 0) { - target.addAttribute("tabindex", tabIndex); - } - - // If the field is modified, but not committed, set modified attribute - if (isModified()) { - target.addAttribute("modified", true); - } - - // Adds the required attribute - if (isRequired()) { - target.addAttribute("required", true); - } - } - - /* - * Gets the field type Don't add a JavaDoc comment here, we use the default - * documentation from the implemented interface. - */ - public abstract Class getType(); - - /** - * The abstract field is read only also if the data source is in readonly - * mode. - */ - public boolean isReadOnly() { - return super.isReadOnly() - || (dataSource != null && dataSource.isReadOnly()); - } - - /** - * Changes the readonly state and throw read-only status change events. - * - * @see com.itmill.toolkit.ui.Component#setReadOnly(boolean) - */ - public void setReadOnly(boolean readOnly) { - super.setReadOnly(readOnly); - fireReadOnlyStatusChange(); - } - - /** - * Tests if the invalid data is committed to datasource. - * - * @see com.itmill.toolkit.data.BufferedValidatable#isInvalidCommitted() - */ - public boolean isInvalidCommitted() { - return invalidCommitted; - } - - /** - * Sets if the invalid data should be committed to datasource. - * - * @see com.itmill.toolkit.data.BufferedValidatable#setInvalidCommitted(boolean) - */ - public void setInvalidCommitted(boolean isCommitted) { - invalidCommitted = isCommitted; - } - - /* - * Saves the current value to the data source Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - public void commit() throws Buffered.SourceException { - if (dataSource != null && (isInvalidCommitted() || isValid()) - && !dataSource.isReadOnly()) { - final Object newValue = getValue(); - try { - - // Commits the value to datasource. - dataSource.setValue(newValue); - - } catch (final Throwable e) { - - // Sets the buffering state. - currentBufferedSourceException = new Buffered.SourceException( - this, e); - requestRepaint(); - - // Throws the source exception. - throw currentBufferedSourceException; - } - } - - boolean repaintNeeded = false; - - // The abstract field is not modified anymore - if (modified) { - modified = false; - repaintNeeded = true; - } - - // If successful, remove set the buffering state to be ok - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - repaintNeeded = true; - } - - if (repaintNeeded) { - requestRepaint(); - } - } - - /* - * Updates the value from the data source. Don't add a JavaDoc comment here, - * we use the default documentation from the implemented interface. - */ - public void discard() throws Buffered.SourceException { - if (dataSource != null) { - - // Gets the correct value from datasource - Object newValue; - try { - - // Discards buffer by overwriting from datasource - newValue = dataSource.getValue(); - - // If successful, remove set the buffering state to be ok - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - requestRepaint(); - } - } catch (final Throwable e) { - - // Sets the buffering state - currentBufferedSourceException = new Buffered.SourceException( - this, e); - requestRepaint(); - - // Throws the source exception - throw currentBufferedSourceException; - } - - final boolean wasModified = isModified(); - modified = false; - - // If the new value differs from the previous one - if ((newValue == null && value != null) - || (newValue != null && !newValue.equals(value))) { - setInternalValue(newValue); - fireValueChange(false); - } - - // If the value did not change, but the modification status did - else if (wasModified) { - requestRepaint(); - } - } - } - - /* - * Has the field been modified since the last commit()? Don't add a JavaDoc - * comment here, we use the default documentation from the implemented - * interface. - */ - public boolean isModified() { - return modified; - } - - /* - * Tests if the field is in write-through mode. Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - public boolean isWriteThrough() { - return writeTroughMode; - } - - /* - * Sets the field's write-through mode to the specified status Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. - */ - public void setWriteThrough(boolean writeTrough) - throws Buffered.SourceException { - if (writeTroughMode == writeTrough) { - return; - } - writeTroughMode = writeTrough; - if (writeTroughMode) { - commit(); - } - } - - /* - * Tests if the field is in read-through mode. Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - public boolean isReadThrough() { - return readTroughMode; - } - - /* - * Sets the field's read-through mode to the specified status Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. - */ - public void setReadThrough(boolean readTrough) - throws Buffered.SourceException { - if (readTroughMode == readTrough) { - return; - } - readTroughMode = readTrough; - if (!isModified() && readTroughMode && dataSource != null) { - setInternalValue(dataSource.getValue()); - fireValueChange(false); - } - } - - /* Property interface implementation ******************************* */ - - /** - * Returns the value of the Property in human readable textual format. - * - * @see java.lang.Object#toString() - */ - public String toString() { - final Object value = getValue(); - if (value == null) { - return null; - } - return getValue().toString(); - } - - /** - * Gets the current value of the field. This is the visible, modified and - * possible invalid value the user have entered to the field. In the - * read-through mode, the abstract buffer is also updated and validation is - * performed. - * - * @return the current value of the field. - */ - public Object getValue() { - - // Give the value from abstract buffers if the field if possible - if (dataSource == null || !isReadThrough() || isModified()) { - return value; - } - - final Object newValue = dataSource.getValue(); - if ((newValue == null && value != null) - || (newValue != null && !newValue.equals(value))) { - setInternalValue(newValue); - fireValueChange(false); - } - - return newValue; - } - - /** - * Sets the value of the field. - * - * @param newValue - * the New value of the field. - * @throws Property.ReadOnlyException - * @throws Property.ConversionException - */ - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException { - setValue(newValue, false); - } - - /** - * Sets the value of the field. - * - * @param newValue - * the New value of the field. - * @param repaintIsNotNeeded - * True iff caller is sure that repaint is not needed. - * @throws Property.ReadOnlyException - * @throws Property.ConversionException - */ - protected void setValue(Object newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Property.ConversionException { - - if ((newValue == null && value != null) - || (newValue != null && !newValue.equals(value))) { - - // Read only fields can not be changed - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - // If invalid values are not allowed, the value must be checked - if (!isInvalidAllowed()) { - final Collection v = getValidators(); - if (v != null) { - for (final Iterator i = v.iterator(); i.hasNext();) { - ((Validator) i.next()).validate(newValue); - } - } - } - - // Changes the value - setInternalValue(newValue); - modified = dataSource != null; - - // In write trough mode , try to commit - if (isWriteThrough() && dataSource != null - && (isInvalidCommitted() || isValid())) { - try { - - // Commits the value to datasource - dataSource.setValue(newValue); - - // The buffer is now unmodified - modified = false; - - } catch (final Throwable e) { - - // Sets the buffering state - currentBufferedSourceException = new Buffered.SourceException( - this, e); - requestRepaint(); - - // Throws the source exception - throw currentBufferedSourceException; - } - } - - // If successful, remove set the buffering state to be ok - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - requestRepaint(); - } - - // Fires the value change - fireValueChange(repaintIsNotNeeded); - } - } - - /* External data source ******************************************** */ - - /** - * Gets the current data source of the field, if any. - * - * @return the current data source as a Property, or null if - * none defined. - */ - public Property getPropertyDataSource() { - return dataSource; - } - - /** - *

- * Sets the specified Property as the data source for the field. All - * uncommitted changes to the field are discarded and the value is refreshed - * from the new data source. - *

- * - *

- * If the datasource has any validators, the same validators are added to - * the field. Because the default behavior of the field is to allow invalid - * values, but not to allow committing them, this only adds visual error - * messages to fields and do not allow committing them as long as the value - * is invalid. After the value is valid, the error message is not shown and - * the commit can be done normally. - *

- * - * @param newDataSource - * the new data source Property. - */ - public void setPropertyDataSource(Property newDataSource) { - - // Saves the old value - final Object oldValue = value; - - // Discards all changes to old datasource - try { - discard(); - } catch (final Buffered.SourceException ignored) { - } - - // Stops listening the old data source changes - if (dataSource != null - && Property.ValueChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ValueChangeNotifier) dataSource).removeListener(this); - } - - // Sets the new data source - dataSource = newDataSource; - - // Gets the value from source - try { - if (dataSource != null) { - setInternalValue(dataSource.getValue()); - } - modified = false; - } catch (final Throwable e) { - currentBufferedSourceException = new Buffered.SourceException(this, - e); - modified = true; - } - - // Listens the new data source if possible - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - - // Copy the validators from the data source - if (dataSource instanceof Validatable) { - final Collection validators = ((Validatable) dataSource) - .getValidators(); - if (validators != null) { - for (final Iterator i = validators.iterator(); i.hasNext();) { - addValidator((Validator) i.next()); - } - } - } - - // Fires value change if the value has changed - if ((value != oldValue) - && ((value != null && !value.equals(oldValue)) || value == null)) { - fireValueChange(false); - } - } - - /* Validation ****************************************************** */ - - /** - * Adds a new validator for the field's value. All validators added to a - * field are checked each time the its value changes. - * - * @param validator - * the new validator to be added. - */ - public void addValidator(Validator validator) { - if (validators == null) { - validators = new LinkedList(); - } - validators.add(validator); - } - - /** - * Gets the validators of the field. - * - * @return the Unmodifiable collection that holds all validators for the - * field. - */ - public Collection getValidators() { - if (validators == null || validators.isEmpty()) { - return null; - } - return Collections.unmodifiableCollection(validators); - } - - /** - * Removes the validator from the field. - * - * @param validator - * the validator to remove. - */ - public void removeValidator(Validator validator) { - if (validators != null) { - validators.remove(validator); - } - } - - /** - * Tests the current value against all registered validators. - * - * @return true if all registered validators claim that the - * current value is valid, false otherwise. - */ - public boolean isValid() { - - if (validators == null) { - return true; - } - - final Object value = getValue(); - for (final Iterator i = validators.iterator(); i.hasNext();) { - if (!((Validator) i.next()).isValid(value)) { - return false; - } - } - - return true; - } - - /** - * Checks the validity of the validatable - * - * @see com.itmill.toolkit.data.Validatable#validate() - */ - public void validate() throws Validator.InvalidValueException { - - // If there is no validator, there can not be any errors - if (validators == null) { - return; - } - - // Initialize temps - Validator.InvalidValueException firstError = null; - LinkedList errors = null; - final Object value = getValue(); - - // Gets all the validation errors - for (final Iterator i = validators.iterator(); i.hasNext();) { - try { - ((Validator) i.next()).validate(value); - } catch (final Validator.InvalidValueException e) { - if (firstError == null) { - firstError = e; - } else { - if (errors == null) { - errors = new LinkedList(); - errors.add(firstError); - } - errors.add(e); - } - } - } - - // If there were no error - if (firstError == null) { - return; - } - - // If only one error occurred, throw it forwards - if (errors == null) { - throw firstError; - } - - // Creates composite validator - final Validator.InvalidValueException[] exceptions = new Validator.InvalidValueException[errors - .size()]; - int index = 0; - for (final Iterator i = errors.iterator(); i.hasNext();) { - exceptions[index++] = (Validator.InvalidValueException) i.next(); - } - - throw new Validator.InvalidValueException(null, exceptions); - } - - /** - * Fields allow invalid values by default. In most cases this is wanted, - * because the field otherwise visually forget the user input immediately. - * - * @return true iff the invalid values are allowed. - * @see com.itmill.toolkit.data.Validatable#isInvalidAllowed() - */ - public boolean isInvalidAllowed() { - return invalidAllowed; - } - - /** - * Fields allow invalid values by default. In most cases this is wanted, - * because the field otherwise visually forget the user input immediately. - *

- * In common setting where the user wants to assure the correctness of the - * datasource, but allow temporarily invalid contents in the field, the user - * should add the validators to datasource, that should not allow invalid - * values. The validators are automatically copied to the field when the - * datasource is set. - *

- * - * @see com.itmill.toolkit.data.Validatable#setInvalidAllowed(boolean) - */ - public void setInvalidAllowed(boolean invalidAllowed) - throws UnsupportedOperationException { - this.invalidAllowed = invalidAllowed; - } - - /** - * Error messages shown by the fields are composites of the error message - * thrown by the superclasses (that is the component error message), - * validation errors and buffered source errors. - * - * @see com.itmill.toolkit.ui.AbstractComponent#getErrorMessage() - */ - public ErrorMessage getErrorMessage() { - - // Check validation errors - ErrorMessage validationError = null; - try { - validate(); - } catch (Validator.InvalidValueException e) { - validationError = e; - } - - // Check if there are any systems errors - final ErrorMessage superError = super.getErrorMessage(); - - // Return if there are no errors at all - if (superError == null && validationError == null - && currentBufferedSourceException == null) - return null; - - // Throw combination of the error types - return new CompositeErrorMessage(new ErrorMessage[] { superError, - validationError, currentBufferedSourceException }); - - } - - /* Value change events ****************************************** */ - - private static final Method VALUE_CHANGE_METHOD; - - static { - try { - VALUE_CHANGE_METHOD = Property.ValueChangeListener.class - .getDeclaredMethod("valueChange", - new Class[] { Property.ValueChangeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(); - } - } - - /* - * Adds a value change listener for the field. Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - public void addListener(Property.ValueChangeListener listener) { - addListener(AbstractField.ValueChangeEvent.class, listener, - VALUE_CHANGE_METHOD); - } - - /* - * Removes a value change listener from the field. Don't add a JavaDoc - * comment here, we use the default documentation from the implemented - * interface. - */ - public void removeListener(Property.ValueChangeListener listener) { - removeListener(AbstractField.ValueChangeEvent.class, listener, - VALUE_CHANGE_METHOD); - } - - /** - * Emits the value change event. The value contained in the field is - * validated before the event is created. - */ - protected void fireValueChange(boolean repaintIsNotNeeded) { - fireEvent(new AbstractField.ValueChangeEvent(this)); - if (!repaintIsNotNeeded) { - requestRepaint(); - } - } - - /* Read-only status change events *************************************** */ - - private static final Method READ_ONLY_STATUS_CHANGE_METHOD; - - static { - try { - READ_ONLY_STATUS_CHANGE_METHOD = Property.ReadOnlyStatusChangeListener.class - .getDeclaredMethod( - "readOnlyStatusChange", - new Class[] { Property.ReadOnlyStatusChangeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(); - } - } - - /** - * An Event object specifying the Property whose read-only - * status has changed. - * - * @author IT Mill Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class ReadOnlyStatusChangeEvent extends Component.Event implements - Property.ReadOnlyStatusChangeEvent { - - /** - * Serial generated by eclipse. - */ - private static final long serialVersionUID = 3258688823264161846L; - - /** - * New instance of text change event. - * - * @param source - * the Source of the event. - */ - public ReadOnlyStatusChangeEvent(AbstractField source) { - super(source); - } - - /** - * Property where the event occurred. - * - * @return the Source of the event. - */ - public Property getProperty() { - return (Property) getSource(); - } - } - - /* - * Adds a read-only status change listener for the field. Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. - */ - public void addListener(Property.ReadOnlyStatusChangeListener listener) { - addListener(Property.ReadOnlyStatusChangeEvent.class, listener, - READ_ONLY_STATUS_CHANGE_METHOD); - } - - /* - * Removes a read-only status change listener from the field. Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. - */ - public void removeListener(Property.ReadOnlyStatusChangeListener listener) { - removeListener(Property.ReadOnlyStatusChangeEvent.class, listener, - READ_ONLY_STATUS_CHANGE_METHOD); - } - - /** - * Emits the read-only status change event. The value contained in the field - * is validated before the event is created. - */ - protected void fireReadOnlyStatusChange() { - fireEvent(new AbstractField.ReadOnlyStatusChangeEvent(this)); - } - - /** - * This method listens to data source value changes and passes the changes - * forwards. - * - * @param event - * the value change event telling the data source contents have - * changed. - */ - public void valueChange(Property.ValueChangeEvent event) { - if (isReadThrough() || !isModified()) { - fireValueChange(false); - } - } - - public void changeVariables(Object source, Map variables) { - super.changeVariables(source, variables); - if (validators != null && !validators.isEmpty()) requestRepaint(); - } - - /** - * Asks the terminal to place the cursor to this field. - */ - public void focus() { - final Application app = getApplication(); - if (app != null) { - app.setFocusedComponent(this); - } else { - delayedFocus = true; - } - } - - /** - * Creates abstract field by the type of the property. - * - *

- * This returns most suitable field type for editing property of given type. - *

- * - * @param propertyType - * the Type of the property, that needs to be edited. - */ - public static AbstractField constructField(Class propertyType) { - - // Null typed properties can not be edited - if (propertyType == null) { - return null; - } - - // Date field - if (Date.class.isAssignableFrom(propertyType)) { - return new DateField(); - } - - // Boolean field - if (Boolean.class.isAssignableFrom(propertyType)) { - final Button button = new Button(""); - button.setSwitchMode(true); - button.setImmediate(false); - return button; - } - - // Text field is used by default - return new TextField(); - } - - /** - * Gets the tab index of this field. The tab index property is used to - * specify the natural tab ordering of fields. - * - * @return the Tab index of this field. Negative value means unspecified. - */ - public int getTabIndex() { - return tabIndex; - } - - /** - * Gets the tab index of this field. The tab index property is used to - * specify the natural tab ordering of fields. - * - * @param tabIndex - * the tab order of this component. Negative value means - * unspecified. - */ - public void setTabIndex(int tabIndex) { - this.tabIndex = tabIndex; - } - - /** - * Sets the internal field value. This is purely used by AbstractField to - * change the internal Field value. It does not trigger any events. It can - * be overriden by the inheriting classes to update all dependent variables. - * - * @param newValue - * the new value to be set. - */ - protected void setInternalValue(Object newValue) { - value = newValue; - } - - /** - * Notifies the component that it is connected to an application. - * - * @see com.itmill.toolkit.ui.Component#attach() - */ - public void attach() { - super.attach(); - if (delayedFocus) { - delayedFocus = false; - focus(); - } - } - - /** - * Is this field required. Required fields must filled by the user. - * - * @return true if the field is required .otherwise - * false. - */ - public boolean isRequired() { - return required; - } - - /** - * Sets the field required. Required fields must filled by the user. - * - * @param required - * Is the field required. - */ - public void setRequired(boolean required) { - this.required = required; - requestRepaint(); - } + Property.ReadOnlyStatusChangeNotifier { + + /* Private members ************************************************* */ + + private boolean delayedFocus; + + /** + * Value of the datafield. + */ + private Object value; + + /** + * Connected data-source. + */ + private Property dataSource = null; + + /** + * The list of validators. + */ + private LinkedList validators = null; + + /** + * Auto commit mode. + */ + private boolean writeTroughMode = true; + + /** + * Reads the value from data-source, when it is not modified. + */ + private boolean readTroughMode = true; + + /** + * Is the field modified but not committed. + */ + private boolean modified = false; + + /** + * Current source exception. + */ + private Buffered.SourceException currentBufferedSourceException = null; + + /** + * Are the invalid values allowed in fields ? + */ + private boolean invalidAllowed = true; + + /** + * Are the invalid values committed ? + */ + private boolean invalidCommitted = false; + + /** + * The tab order number of this field. + */ + private int tabIndex = 0; + + /** + * Required field. + */ + private boolean required = false; + + /* Component basics ************************************************ */ + + /* + * Paints the field. Don't add a JavaDoc comment here, we use the default + * documentation from the implemented interface. + */ + public void paintContent(PaintTarget target) throws PaintException { + + // The tab ordering number + if (tabIndex > 0) { + target.addAttribute("tabindex", tabIndex); + } + + // If the field is modified, but not committed, set modified attribute + if (isModified()) { + target.addAttribute("modified", true); + } + + // Adds the required attribute + if (isRequired()) { + target.addAttribute("required", true); + } + } + + /* + * Gets the field type Don't add a JavaDoc comment here, we use the default + * documentation from the implemented interface. + */ + public abstract Class getType(); + + /** + * The abstract field is read only also if the data source is in read only + * mode. + */ + public boolean isReadOnly() { + return super.isReadOnly() + || (dataSource != null && dataSource.isReadOnly()); + } + + /** + * Changes the readonly state and throw read-only status change events. + * + * @see com.itmill.toolkit.ui.Component#setReadOnly(boolean) + */ + public void setReadOnly(boolean readOnly) { + super.setReadOnly(readOnly); + fireReadOnlyStatusChange(); + } + + /** + * Tests if the invalid data is committed to datasource. + * + * @see com.itmill.toolkit.data.BufferedValidatable#isInvalidCommitted() + */ + public boolean isInvalidCommitted() { + return invalidCommitted; + } + + /** + * Sets if the invalid data should be committed to datasource. + * + * @see com.itmill.toolkit.data.BufferedValidatable#setInvalidCommitted(boolean) + */ + public void setInvalidCommitted(boolean isCommitted) { + invalidCommitted = isCommitted; + } + + /* + * Saves the current value to the data source Don't add a JavaDoc comment + * here, we use the default documentation from the implemented interface. + */ + public void commit() throws Buffered.SourceException { + if (dataSource != null && (isInvalidCommitted() || isValid()) + && !dataSource.isReadOnly()) { + final Object newValue = getValue(); + try { + + // Commits the value to datasource. + dataSource.setValue(newValue); + + } catch (final Throwable e) { + + // Sets the buffering state. + currentBufferedSourceException = new Buffered.SourceException( + this, e); + requestRepaint(); + + // Throws the source exception. + throw currentBufferedSourceException; + } + } + + boolean repaintNeeded = false; + + // The abstract field is not modified anymore + if (modified) { + modified = false; + repaintNeeded = true; + } + + // If successful, remove set the buffering state to be ok + if (currentBufferedSourceException != null) { + currentBufferedSourceException = null; + repaintNeeded = true; + } + + if (repaintNeeded) { + requestRepaint(); + } + } + + /* + * Updates the value from the data source. Don't add a JavaDoc comment here, + * we use the default documentation from the implemented interface. + */ + public void discard() throws Buffered.SourceException { + if (dataSource != null) { + + // Gets the correct value from datasource + Object newValue; + try { + + // Discards buffer by overwriting from datasource + newValue = dataSource.getValue(); + + // If successful, remove set the buffering state to be ok + if (currentBufferedSourceException != null) { + currentBufferedSourceException = null; + requestRepaint(); + } + } catch (final Throwable e) { + + // Sets the buffering state + currentBufferedSourceException = new Buffered.SourceException( + this, e); + requestRepaint(); + + // Throws the source exception + throw currentBufferedSourceException; + } + + final boolean wasModified = isModified(); + modified = false; + + // If the new value differs from the previous one + if ((newValue == null && value != null) + || (newValue != null && !newValue.equals(value))) { + setInternalValue(newValue); + fireValueChange(false); + } + + // If the value did not change, but the modification status did + else if (wasModified) { + requestRepaint(); + } + } + } + + /* + * Has the field been modified since the last commit()? Don't add a JavaDoc + * comment here, we use the default documentation from the implemented + * interface. + */ + public boolean isModified() { + return modified; + } + + /* + * Tests if the field is in write-through mode. Don't add a JavaDoc comment + * here, we use the default documentation from the implemented interface. + */ + public boolean isWriteThrough() { + return writeTroughMode; + } + + /* + * Sets the field's write-through mode to the specified status Don't add a + * JavaDoc comment here, we use the default documentation from the + * implemented interface. + */ + public void setWriteThrough(boolean writeTrough) + throws Buffered.SourceException { + if (writeTroughMode == writeTrough) { + return; + } + writeTroughMode = writeTrough; + if (writeTroughMode) { + commit(); + } + } + + /* + * Tests if the field is in read-through mode. Don't add a JavaDoc comment + * here, we use the default documentation from the implemented interface. + */ + public boolean isReadThrough() { + return readTroughMode; + } + + /* + * Sets the field's read-through mode to the specified status Don't add a + * JavaDoc comment here, we use the default documentation from the + * implemented interface. + */ + public void setReadThrough(boolean readTrough) + throws Buffered.SourceException { + if (readTroughMode == readTrough) { + return; + } + readTroughMode = readTrough; + if (!isModified() && readTroughMode && dataSource != null) { + setInternalValue(dataSource.getValue()); + fireValueChange(false); + } + } + + /* Property interface implementation ******************************* */ + + /** + * Returns the value of the Property in human readable textual format. + * + * @see java.lang.Object#toString() + */ + public String toString() { + final Object value = getValue(); + if (value == null) { + return null; + } + return getValue().toString(); + } + + /** + * Gets the current value of the field. This is the visible, modified and + * possible invalid value the user have entered to the field. In the + * read-through mode, the abstract buffer is also updated and validation is + * performed. + * + * @return the current value of the field. + */ + public Object getValue() { + + // Give the value from abstract buffers if the field if possible + if (dataSource == null || !isReadThrough() || isModified()) { + return value; + } + + final Object newValue = dataSource.getValue(); + if ((newValue == null && value != null) + || (newValue != null && !newValue.equals(value))) { + setInternalValue(newValue); + fireValueChange(false); + } + + return newValue; + } + + /** + * Sets the value of the field. + * + * @param newValue + * the New value of the field. + * @throws Property.ReadOnlyException + * @throws Property.ConversionException + */ + public void setValue(Object newValue) throws Property.ReadOnlyException, + Property.ConversionException { + setValue(newValue, false); + } + + /** + * Sets the value of the field. + * + * @param newValue + * the New value of the field. + * @param repaintIsNotNeeded + * True iff caller is sure that repaint is not needed. + * @throws Property.ReadOnlyException + * @throws Property.ConversionException + */ + protected void setValue(Object newValue, boolean repaintIsNotNeeded) + throws Property.ReadOnlyException, Property.ConversionException { + + if ((newValue == null && value != null) + || (newValue != null && !newValue.equals(value))) { + + // Read only fields can not be changed + if (isReadOnly()) { + throw new Property.ReadOnlyException(); + } + + // If invalid values are not allowed, the value must be checked + if (!isInvalidAllowed()) { + final Collection v = getValidators(); + if (v != null) { + for (final Iterator i = v.iterator(); i.hasNext();) { + ((Validator) i.next()).validate(newValue); + } + } + } + + // Changes the value + setInternalValue(newValue); + modified = dataSource != null; + + // In write trough mode , try to commit + if (isWriteThrough() && dataSource != null + && (isInvalidCommitted() || isValid())) { + try { + + // Commits the value to datasource + dataSource.setValue(newValue); + + // The buffer is now unmodified + modified = false; + + } catch (final Throwable e) { + + // Sets the buffering state + currentBufferedSourceException = new Buffered.SourceException( + this, e); + requestRepaint(); + + // Throws the source exception + throw currentBufferedSourceException; + } + } + + // If successful, remove set the buffering state to be ok + if (currentBufferedSourceException != null) { + currentBufferedSourceException = null; + requestRepaint(); + } + + // Fires the value change + fireValueChange(repaintIsNotNeeded); + } + } + + /* External data source ******************************************** */ + + /** + * Gets the current data source of the field, if any. + * + * @return the current data source as a Property, or null if + * none defined. + */ + public Property getPropertyDataSource() { + return dataSource; + } + + /** + *

+ * Sets the specified Property as the data source for the field. All + * uncommitted changes to the field are discarded and the value is refreshed + * from the new data source. + *

+ * + *

+ * If the datasource has any validators, the same validators are added to + * the field. Because the default behavior of the field is to allow invalid + * values, but not to allow committing them, this only adds visual error + * messages to fields and do not allow committing them as long as the value + * is invalid. After the value is valid, the error message is not shown and + * the commit can be done normally. + *

+ * + * @param newDataSource + * the new data source Property. + */ + public void setPropertyDataSource(Property newDataSource) { + + // Saves the old value + final Object oldValue = value; + + // Discards all changes to old datasource + try { + discard(); + } catch (final Buffered.SourceException ignored) { + } + + // Stops listening the old data source changes + if (dataSource != null + && Property.ValueChangeNotifier.class + .isAssignableFrom(dataSource.getClass())) { + ((Property.ValueChangeNotifier) dataSource).removeListener(this); + } + + // Sets the new data source + dataSource = newDataSource; + + // Gets the value from source + try { + if (dataSource != null) { + setInternalValue(dataSource.getValue()); + } + modified = false; + } catch (final Throwable e) { + currentBufferedSourceException = new Buffered.SourceException(this, + e); + modified = true; + } + + // Listens the new data source if possible + if (dataSource instanceof Property.ValueChangeNotifier) { + ((Property.ValueChangeNotifier) dataSource).addListener(this); + } + + // Copy the validators from the data source + if (dataSource instanceof Validatable) { + final Collection validators = ((Validatable) dataSource) + .getValidators(); + if (validators != null) { + for (final Iterator i = validators.iterator(); i.hasNext();) { + addValidator((Validator) i.next()); + } + } + } + + // Fires value change if the value has changed + if ((value != oldValue) + && ((value != null && !value.equals(oldValue)) || value == null)) { + fireValueChange(false); + } + } + + /* Validation ****************************************************** */ + + /** + * Adds a new validator for the field's value. All validators added to a + * field are checked each time the its value changes. + * + * @param validator + * the new validator to be added. + */ + public void addValidator(Validator validator) { + if (validators == null) { + validators = new LinkedList(); + } + validators.add(validator); + } + + /** + * Gets the validators of the field. + * + * @return the Unmodifiable collection that holds all validators for the + * field. + */ + public Collection getValidators() { + if (validators == null || validators.isEmpty()) { + return null; + } + return Collections.unmodifiableCollection(validators); + } + + /** + * Removes the validator from the field. + * + * @param validator + * the validator to remove. + */ + public void removeValidator(Validator validator) { + if (validators != null) { + validators.remove(validator); + } + } + + /** + * Tests the current value against all registered validators. + * + * @return true if all registered validators claim that the + * current value is valid, false otherwise. + */ + public boolean isValid() { + + if (validators == null) { + return true; + } + + final Object value = getValue(); + for (final Iterator i = validators.iterator(); i.hasNext();) { + if (!((Validator) i.next()).isValid(value)) { + return false; + } + } + + return true; + } + + /** + * Checks the validity of the validatable + * + * @see com.itmill.toolkit.data.Validatable#validate() + */ + public void validate() throws Validator.InvalidValueException { + + // If there is no validator, there can not be any errors + if (validators == null) { + return; + } + + // Initialize temps + Validator.InvalidValueException firstError = null; + LinkedList errors = null; + final Object value = getValue(); + + // Gets all the validation errors + for (final Iterator i = validators.iterator(); i.hasNext();) { + try { + ((Validator) i.next()).validate(value); + } catch (final Validator.InvalidValueException e) { + if (firstError == null) { + firstError = e; + } else { + if (errors == null) { + errors = new LinkedList(); + errors.add(firstError); + } + errors.add(e); + } + } + } + + // If there were no error + if (firstError == null) { + return; + } + + // If only one error occurred, throw it forwards + if (errors == null) { + throw firstError; + } + + // Creates composite validator + final Validator.InvalidValueException[] exceptions = new Validator.InvalidValueException[errors + .size()]; + int index = 0; + for (final Iterator i = errors.iterator(); i.hasNext();) { + exceptions[index++] = (Validator.InvalidValueException) i.next(); + } + + throw new Validator.InvalidValueException(null, exceptions); + } + + /** + * Fields allow invalid values by default. In most cases this is wanted, + * because the field otherwise visually forget the user input immediately. + * + * @return true iff the invalid values are allowed. + * @see com.itmill.toolkit.data.Validatable#isInvalidAllowed() + */ + public boolean isInvalidAllowed() { + return invalidAllowed; + } + + /** + * Fields allow invalid values by default. In most cases this is wanted, + * because the field otherwise visually forget the user input immediately. + *

+ * In common setting where the user wants to assure the correctness of the + * datasource, but allow temporarily invalid contents in the field, the user + * should add the validators to datasource, that should not allow invalid + * values. The validators are automatically copied to the field when the + * datasource is set. + *

+ * + * @see com.itmill.toolkit.data.Validatable#setInvalidAllowed(boolean) + */ + public void setInvalidAllowed(boolean invalidAllowed) + throws UnsupportedOperationException { + this.invalidAllowed = invalidAllowed; + } + + /** + * Error messages shown by the fields are composites of the error message + * thrown by the superclasses (that is the component error message), + * validation errors and buffered source errors. + * + * @see com.itmill.toolkit.ui.AbstractComponent#getErrorMessage() + */ + public ErrorMessage getErrorMessage() { + + // Check validation errors + ErrorMessage validationError = null; + try { + validate(); + } catch (Validator.InvalidValueException e) { + validationError = e; + } + + // Check if there are any systems errors + final ErrorMessage superError = super.getErrorMessage(); + + // Return if there are no errors at all + if (superError == null && validationError == null + && currentBufferedSourceException == null) { + return null; + } + + // Throw combination of the error types + return new CompositeErrorMessage(new ErrorMessage[] { superError, + validationError, currentBufferedSourceException }); + + } + + /* Value change events ****************************************** */ + + private static final Method VALUE_CHANGE_METHOD; + + static { + try { + VALUE_CHANGE_METHOD = Property.ValueChangeListener.class + .getDeclaredMethod("valueChange", + new Class[] { Property.ValueChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException(); + } + } + + /* + * Adds a value change listener for the field. Don't add a JavaDoc comment + * here, we use the default documentation from the implemented interface. + */ + public void addListener(Property.ValueChangeListener listener) { + addListener(AbstractField.ValueChangeEvent.class, listener, + VALUE_CHANGE_METHOD); + } + + /* + * Removes a value change listener from the field. Don't add a JavaDoc + * comment here, we use the default documentation from the implemented + * interface. + */ + public void removeListener(Property.ValueChangeListener listener) { + removeListener(AbstractField.ValueChangeEvent.class, listener, + VALUE_CHANGE_METHOD); + } + + /** + * Emits the value change event. The value contained in the field is + * validated before the event is created. + */ + protected void fireValueChange(boolean repaintIsNotNeeded) { + fireEvent(new AbstractField.ValueChangeEvent(this)); + if (!repaintIsNotNeeded) { + requestRepaint(); + } + } + + /* Read-only status change events *************************************** */ + + private static final Method READ_ONLY_STATUS_CHANGE_METHOD; + + static { + try { + READ_ONLY_STATUS_CHANGE_METHOD = Property.ReadOnlyStatusChangeListener.class + .getDeclaredMethod( + "readOnlyStatusChange", + new Class[] { Property.ReadOnlyStatusChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException(); + } + } + + /** + * An Event object specifying the Property whose read-only + * status has changed. + * + * @author IT Mill Ltd. + * @version + * @VERSION@ + * @since 3.0 + */ + public class ReadOnlyStatusChangeEvent extends Component.Event implements + Property.ReadOnlyStatusChangeEvent { + + /** + * Serial generated by eclipse. + */ + private static final long serialVersionUID = 3258688823264161846L; + + /** + * New instance of text change event. + * + * @param source + * the Source of the event. + */ + public ReadOnlyStatusChangeEvent(AbstractField source) { + super(source); + } + + /** + * Property where the event occurred. + * + * @return the Source of the event. + */ + public Property getProperty() { + return (Property) getSource(); + } + } + + /* + * Adds a read-only status change listener for the field. Don't add a + * JavaDoc comment here, we use the default documentation from the + * implemented interface. + */ + public void addListener(Property.ReadOnlyStatusChangeListener listener) { + addListener(Property.ReadOnlyStatusChangeEvent.class, listener, + READ_ONLY_STATUS_CHANGE_METHOD); + } + + /* + * Removes a read-only status change listener from the field. Don't add a + * JavaDoc comment here, we use the default documentation from the + * implemented interface. + */ + public void removeListener(Property.ReadOnlyStatusChangeListener listener) { + removeListener(Property.ReadOnlyStatusChangeEvent.class, listener, + READ_ONLY_STATUS_CHANGE_METHOD); + } + + /** + * Emits the read-only status change event. The value contained in the field + * is validated before the event is created. + */ + protected void fireReadOnlyStatusChange() { + fireEvent(new AbstractField.ReadOnlyStatusChangeEvent(this)); + } + + /** + * This method listens to data source value changes and passes the changes + * forwards. + * + * @param event + * the value change event telling the data source contents + * have changed. + */ + public void valueChange(Property.ValueChangeEvent event) { + if (isReadThrough() || !isModified()) { + fireValueChange(false); + } + } + + public void changeVariables(Object source, Map variables) { + super.changeVariables(source, variables); + if (validators != null && !validators.isEmpty()) { + requestRepaint(); + } + } + + /** + * Asks the terminal to place the cursor to this field. + */ + public void focus() { + final Application app = getApplication(); + if (app != null) { + app.setFocusedComponent(this); + } else { + delayedFocus = true; + } + } + + /** + * Creates abstract field by the type of the property. + * + *

+ * This returns most suitable field type for editing property of given type. + *

+ * + * @param propertyType + * the Type of the property, that needs to be edited. + */ + public static AbstractField constructField(Class propertyType) { + + // Null typed properties can not be edited + if (propertyType == null) { + return null; + } + + // Date field + if (Date.class.isAssignableFrom(propertyType)) { + return new DateField(); + } + + // Boolean field + if (Boolean.class.isAssignableFrom(propertyType)) { + final Button button = new Button(""); + button.setSwitchMode(true); + button.setImmediate(false); + return button; + } + + // Text field is used by default + return new TextField(); + } + + /** + * Gets the tab index of this field. The tab index property is used to + * specify the natural tab ordering of fields. + * + * @return the Tab index of this field. Negative value means unspecified. + */ + public int getTabIndex() { + return tabIndex; + } + + /** + * Gets the tab index of this field. The tab index property is used to + * specify the natural tab ordering of fields. + * + * @param tabIndex + * the tab order of this component. Negative value means + * unspecified. + */ + public void setTabIndex(int tabIndex) { + this.tabIndex = tabIndex; + } + + /** + * Sets the internal field value. This is purely used by AbstractField to + * change the internal Field value. It does not trigger any events. It can + * be overriden by the inheriting classes to update all dependent variables. + * + * @param newValue + * the new value to be set. + */ + protected void setInternalValue(Object newValue) { + value = newValue; + } + + /** + * Notifies the component that it is connected to an application. + * + * @see com.itmill.toolkit.ui.Component#attach() + */ + public void attach() { + super.attach(); + if (delayedFocus) { + + delayedFocus = false; + focus(); + } + } + + /** + * Is this field required. Required fields must filled by the user. + * + * @return true if the field is required .otherwise + * false. + */ + public boolean isRequired() { + return required; + } + + /** + * Sets the field required. Required fields must filled by the user. + * + * @param required + * Is the field required. + */ + public void setRequired(boolean required) { + this.required = required; + requestRepaint(); + } } \ No newline at end of file -- 2.39.5