/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.data;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.EventObject;
import java.util.Objects;
import java.util.Optional;
import com.vaadin.event.SerializableEventListener;
import com.vaadin.server.Setter;
import com.vaadin.shared.Registration;
import com.vaadin.ui.Component;
import com.vaadin.util.ReflectTools;
/**
* A generic interface for field components and other user interface objects
* that have a user-editable value. Emits change events whenever the value is
* changed, either by the user or programmatically.
*
* @author Vaadin Ltd.
*
* @param <V>
* the value type
*
* @since 8.0
*/
public interface HasValue<V> extends Serializable {
/**
* An event fired when the value of a {@code HasValue} changes.
*
* @param <V>
* the value type
*/
public class ValueChangeEvent<V> extends EventObject {
private final boolean userOriginated;
private final Component component;
private final V oldValue;
private final V value;
/**
* Creates a new {@code ValueChange} event containing the current value
* of the given value-bearing source component.
*
* @param <COMPONENT>
* the type of the source component
* @param component
* the source component bearing the value, not null
* @param oldValue
* the previous value held by the source of this event
* @param userOriginated
* {@code true} if this event originates from the client,
* {@code false} otherwise.
*/
public <COMPONENT extends Component & HasValue<V>> ValueChangeEvent(
COMPONENT component, V oldValue, boolean userOriginated) {
this(component, component, oldValue, userOriginated);
}
/**
* Creates a new {@code ValueChange} event containing the given value,
* originating from the given source component.
*
* @param component
* the component, not null
* @param hasValue
* the HasValue instance bearing the value, not null
* @param oldValue
* the previous value held by the source of this event
* @param userOriginated
* {@code true} if this event originates from the client,
* {@code false} otherwise.
*/
public ValueChangeEvent(Component component, HasValue<V> hasValue,
V oldValue, boolean userOriginated) {
super(hasValue);
this.userOriginated = userOriginated;
this.component = component;
this.oldValue = oldValue;
value = hasValue.getValue();
}
/**
* Returns the value of the source before this value change event
* occurred.
*
* @return the value previously held by the source of this event
*/
public V getOldValue() {
return oldValue;
}
/**
* Returns the new value that triggered this value change event.
*
* @return the new value
*/
public V getValue() {
return value;
}
/**
* Returns whether this event was triggered by user interaction, on the
* client side, or programmatically, on the server side.
*
* @return {@code true} if this event originates from the client,
* {@code false} otherwise.
*/
public boolean isUserOriginated() {
return userOriginated;
}
/**
* Returns the component.
*
* @return the component, not null
*/
public Component getComponent() {
return component;
}
@SuppressWarnings("unchecked")
@Override
public HasValue<V> getSource() {
return (HasValue<V>) super.getSource();
}
}
/**
* A listener for value change events.
*
* @param <V>
* the value type
*
* @see ValueChangeEvent
* @see Registration
*/
@FunctionalInterface
public interface ValueChangeListener<V> extends SerializableEventListener {
/** For internal use only. Might be removed in the future. */
@Deprecated
public static final Method VALUE_CHANGE_METHOD = ReflectTools
.findMethod(ValueChangeListener.class, "valueChange",
ValueChangeEvent.class);
/**
* Invoked when this listener receives a value change event from an
* event source to which it has been added.
*
* @param event
* the received event, not null
*/
public void valueChange(ValueChangeEvent<V> event);
}
/**
* Sets the value of this object. If the new value is not equal to
* {@code getValue()}, fires a value change event. May throw
* {@code IllegalArgumentException} if the value is not acceptable.
* <p>
* <i>Implementation note:</i> the implementing class should document
* whether null values are accepted or not.
*
* @param value
* the new value
* @throws IllegalArgumentException
* if the value is invalid
*/
public void setValue(V value);
/**
* Returns the current value of this object.
* <p>
* <i>Implementation note:</i> the implementing class should document
* whether null values may be returned or not.
*
* @return the current value
*/
public V getValue();
/**
* Adds a value change listener. The listener is called when the value of
* this {@code HasValue} is changed either by the user or programmatically.
*
* @param listener
* the value change listener, not null
* @return a registration for the listener
*/
public Registration addValueChangeListener(ValueChangeListener<V> listener);
/**
* Returns the value that represents an empty value.
* <p>
* By default {@link HasValue} is expected to support {@code null} as empty
* values. Specific implementations might not support this.
*
* @return empty value
* @see Binder#bind(HasValue, ValueProvider, Setter)
*/
public default V getEmptyValue() {
return null;
}
/**
* Returns the current value of this object, wrapped in an {@code Optional}.
* <p>
* The {@code Optional} will be empty if the value is {@code null} or
* {@code isEmpty()} returns {@code true}.
*
* @return the current value, wrapped in an {@code Optional}
*/
public default Optional<V> getOptionalValue() {
return isEmpty() ? Optional.empty() : Optional.ofNullable(getValue());
}
/**
* Returns whether this {@code HasValue} is considered to be empty.
* <p>
* By default this is an equality check between current value and empty
* value.
*
* @return {@code true} if considered empty; {@code false} if not
*/
public default boolean isEmpty() {
return Objects.equals(getValue(), getEmptyValue());
}
/**
* Sets the required indicator visible or not.
* <p>
* If set visible, it is visually indicated in the user interface.
*
* @param requiredIndicatorVisible
* <code>true</code> to make the required indicator visible,
* <code>false</code> if not
*/
public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible);
/**
* Checks whether the required indicator is visible.
*
* @return <code>true</code> if visible, <code>false</code> if not
*/
public boolean isRequiredIndicatorVisible();
/**
* Sets the read-only mode of this {@code HasValue} to given mode. The user
* can't change the value when in read-only mode.
* <p>
* A {@code HasValue} with a visual component in read-only mode typically
* looks visually different to signal to the user that the value cannot be
* edited.
*
* @param readOnly
* a boolean value specifying whether the component is put
* read-only mode or not
*/
public void setReadOnly(boolean readOnly);
/**
* Returns whether this {@code HasValue} is in read-only mode or not.
*
* @return {@code false} if the user can modify the value, {@code true} if
* not.
*/
public boolean isReadOnly();
/**
* Resets the value to the empty one.
* <p>
* This is just a shorthand for resetting the value, see the methods
* {@link #setValue(Object)} and {@link #getEmptyValue()}.
*
* @see #setValue(Object)
* @see #getEmptyValue()
*/
public default void clear() {
setValue(getEmptyValue());
}
}