Change-Id: I9addcf8bec802967b1dfa39512dd140b8a4e4a25tags/8.0.0.alpha1
@@ -0,0 +1,153 @@ | |||
/* | |||
* Copyright 2000-2014 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.util.function.Consumer; | |||
import com.vaadin.event.ConnectorEvent; | |||
import com.vaadin.event.ConnectorEventListener; | |||
import com.vaadin.event.Registration; | |||
import com.vaadin.server.ClientConnector; | |||
/** | |||
* 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. | |||
* | |||
* @since | |||
* @param <V> | |||
* the value type | |||
*/ | |||
public interface HasValue<V> extends Serializable { | |||
/** | |||
* An event fired when the value of a {@code HasValue} changes. | |||
* | |||
* @param <V> | |||
* the value type | |||
*/ | |||
public class ValueChange<V> extends ConnectorEvent { | |||
private final V value; | |||
private final boolean userOriginated; | |||
/** | |||
* Creates a new {@code ValueChange} event containing the current value | |||
* of the given value-bearing source connector. | |||
* | |||
* @param <C> | |||
* the type of the source connector | |||
* @param source | |||
* the source connector bearing the value, not null | |||
* @param userOriginated | |||
* {@code true} if this event originates from the client, | |||
* {@code false} otherwise. | |||
*/ | |||
public <C extends ClientConnector & HasValue<V>> ValueChange( | |||
C source, boolean userOriginated) { | |||
super(source); | |||
this.value = source.getValue(); | |||
this.userOriginated = userOriginated; | |||
} | |||
/** | |||
* Returns the new value of the source connector. | |||
* | |||
* @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; | |||
} | |||
} | |||
/** | |||
* A listener for value change events. | |||
* | |||
* @param <V> | |||
* the value type | |||
* | |||
* @see ValueChange | |||
* @see Registration | |||
*/ | |||
@FunctionalInterface | |||
public interface ValueChangeListener<V> extends Consumer<ValueChange<V>>, | |||
ConnectorEventListener { | |||
/** | |||
* 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 | |||
*/ | |||
// In addition to customizing the Javadoc, this override is needed | |||
// to make ReflectTools.findMethod work as expected. It uses | |||
// Class.getDeclaredMethod, but even if it used getMethod instead, the | |||
// superinterface argument type is Object, not Event, after type | |||
// erasure. | |||
@Override | |||
public void accept(ValueChange<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 an {@link ValueChangeListener}. 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<? super V> listener); | |||
} |
@@ -20,11 +20,29 @@ import java.util.EventObject; | |||
import com.vaadin.server.ClientConnector; | |||
/** | |||
* A base class for user interface events fired by connectors. | |||
* | |||
* @author Vaadin Ltd. | |||
* @since 7.0 | |||
*/ | |||
public abstract class ConnectorEvent extends EventObject { | |||
/** | |||
* Creates a new event fired by the given source. | |||
* | |||
* @param source | |||
* the source connector | |||
*/ | |||
public ConnectorEvent(ClientConnector source) { | |||
super(source); | |||
} | |||
/** | |||
* Returns the connector that fired the event. | |||
* | |||
* @return the source connector | |||
*/ | |||
public ClientConnector getConnector() { | |||
return (ClientConnector) getSource(); | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
* Copyright 2000-2014 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.event; | |||
import java.io.Serializable; | |||
/** | |||
* A registration object for removing an event listener added to a source. | |||
* | |||
* @author Vaadin Ltd. | |||
* @since | |||
*/ | |||
@FunctionalInterface | |||
public interface Registration extends Serializable { | |||
/** | |||
* Removes the associated listener from the event source. | |||
*/ | |||
public void remove(); | |||
} |
@@ -62,10 +62,10 @@ import com.vaadin.ui.declarative.DesignContext; | |||
* </p> | |||
* | |||
* <p> | |||
* LegacyAbstractField also provides the {@link com.vaadin.data.Buffered} interface | |||
* for buffering the data source value. By default the LegacyField is in write | |||
* through-mode and {@link #setWriteThrough(boolean)}should be called to enable | |||
* buffering. | |||
* LegacyAbstractField also provides the {@link com.vaadin.data.Buffered} | |||
* interface for buffering the data source value. By default the LegacyField is | |||
* in write through-mode and {@link #setWriteThrough(boolean)}should be called | |||
* to enable buffering. | |||
* </p> | |||
* | |||
* <p> | |||
@@ -75,10 +75,17 @@ import com.vaadin.ui.declarative.DesignContext; | |||
* | |||
* @author Vaadin Ltd. | |||
* @since 3.0 | |||
* | |||
* @deprecated This class is, apart from the rename, identical to the Vaadin 7 | |||
* {@code com.vaadin.ui.AbstractField}. It is provided for | |||
* compatibility and migration purposes. As of 8.0, new field | |||
* implementations should extend the new | |||
* {@link com.vaadin.ui.AbstractField} instead. | |||
*/ | |||
@SuppressWarnings("serial") | |||
public abstract class LegacyAbstractField<T> extends AbstractComponent implements | |||
LegacyField<T>, Property.ReadOnlyStatusChangeListener, | |||
@Deprecated | |||
public abstract class LegacyAbstractField<T> extends AbstractComponent | |||
implements LegacyField<T>, Property.ReadOnlyStatusChangeListener, | |||
Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier { | |||
/* Private members */ | |||
@@ -187,11 +194,11 @@ public abstract class LegacyAbstractField<T> extends AbstractComponent implement | |||
} | |||
/** | |||
* Returns the type of the LegacyField. The methods <code>getValue</code> and | |||
* <code>setValue</code> must be compatible with this type: one must be able | |||
* to safely cast the value returned from <code>getValue</code> to the given | |||
* type and pass any variable assignable to this type as an argument to | |||
* <code>setValue</code>. | |||
* Returns the type of the LegacyField. The methods <code>getValue</code> | |||
* and <code>setValue</code> must be compatible with this type: one must be | |||
* able to safely cast the value returned from <code>getValue</code> to the | |||
* given type and pass any variable assignable to this type as an argument | |||
* to <code>setValue</code>. | |||
* | |||
* @return the type of the LegacyField | |||
*/ | |||
@@ -834,9 +841,9 @@ public abstract class LegacyAbstractField<T> extends AbstractComponent implement | |||
* Returns the current value (as returned by {@link #getValue()}) converted | |||
* to the data source type. | |||
* <p> | |||
* This returns the same as {@link LegacyAbstractField#getValue()} if no converter | |||
* has been set. The value is not necessarily the same as the data source | |||
* value e.g. if the field is in buffered mode and has been modified. | |||
* This returns the same as {@link LegacyAbstractField#getValue()} if no | |||
* converter has been set. The value is not necessarily the same as the data | |||
* source value e.g. if the field is in buffered mode and has been modified. | |||
* </p> | |||
* | |||
* @return The converted value that is compatible with the data source type | |||
@@ -870,7 +877,7 @@ public abstract class LegacyAbstractField<T> extends AbstractComponent implement | |||
@Override | |||
public void addValidator(Validator validator) { | |||
if (validators == null) { | |||
validators = new LinkedList<Validator>(); | |||
validators = new LinkedList<>(); | |||
} | |||
validators.add(validator); | |||
markAsDirty(); | |||
@@ -993,7 +1000,7 @@ public abstract class LegacyAbstractField<T> extends AbstractComponent implement | |||
} | |||
} | |||
List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>(); | |||
List<InvalidValueException> validationExceptions = new ArrayList<>(); | |||
if (validators != null) { | |||
// Gets all the validation errors | |||
for (Validator v : validators) { | |||
@@ -1384,10 +1391,10 @@ public abstract class LegacyAbstractField<T> extends AbstractComponent implement | |||
} | |||
/** | |||
* Sets the internal field value. This is purely used by LegacyAbstractField to | |||
* change the internal LegacyField value. It does not trigger valuechange events. | |||
* It can be overridden by the inheriting classes to update all dependent | |||
* variables. | |||
* Sets the internal field value. This is purely used by LegacyAbstractField | |||
* to change the internal LegacyField value. It does not trigger valuechange | |||
* events. It can be overridden by the inheriting classes to update all | |||
* dependent variables. | |||
* | |||
* Subclasses can also override {@link #getInternalValue()} if necessary. | |||
* | |||
@@ -1619,8 +1626,8 @@ public abstract class LegacyAbstractField<T> extends AbstractComponent implement | |||
/** | |||
* A ready-made {@link ShortcutListener} that focuses the given | |||
* {@link Focusable} (usually a {@link LegacyField}) when the keyboard shortcut is | |||
* invoked. | |||
* {@link Focusable} (usually a {@link LegacyField}) when the keyboard | |||
* shortcut is invoked. | |||
* | |||
*/ | |||
public static class FocusShortcut extends ShortcutListener { |
@@ -17,32 +17,37 @@ | |||
package com.vaadin.legacy.ui; | |||
import com.vaadin.data.BufferedValidatable; | |||
import com.vaadin.data.HasValue.ValueChange; | |||
import com.vaadin.data.Property; | |||
import com.vaadin.ui.Component; | |||
import com.vaadin.ui.Component.Event; | |||
import com.vaadin.ui.Component.Focusable; | |||
/** | |||
* LegacyField interface is implemented by all classes (field components) that have a | |||
* value that the user can change through the user interface. | |||
* LegacyField interface is implemented by all legacy field components that have | |||
* a value that the user can change through the user interface. | |||
* | |||
* LegacyField components are built upon the framework defined in the LegacyField interface | |||
* and the {@link com.vaadin.LegacyAbstractField} base class. | |||
* LegacyField components are built upon the framework defined in the | |||
* LegacyField interface and the {@link com.vaadin.LegacyAbstractField} base | |||
* class. | |||
* | |||
* The LegacyField interface inherits the {@link com.vaadin.ui.Component} | |||
* superinterface and also the {@link com.vaadin.ui.Property} interface to have | |||
* a value for the field. | |||
* | |||
* | |||
* @author Vaadin Ltd. | |||
* | |||
* @param T | |||
* @param <T> | |||
* the type of values in the field, which might not be the same type | |||
* as that of the data source if converters are used | |||
* | |||
* @author IT Mill Ltd. | |||
* @deprecated This interface is, apart from the rename, identical to the Vaadin | |||
* 7 {@code com.vaadin.ui.Field}. It is provided for compatibility | |||
* and migration purposes. As of 8.0, new field components should | |||
* extend {@link com.vaadin.ui.AbstractField} instead. | |||
*/ | |||
public interface LegacyField<T> extends Component, BufferedValidatable, Property<T>, | |||
@Deprecated | |||
public interface LegacyField<T> extends Component, BufferedValidatable, | |||
Property<T>, | |||
Property.ValueChangeNotifier, Property.ValueChangeListener, | |||
Property.Editor, Focusable { | |||
@@ -85,14 +90,18 @@ public interface LegacyField<T> extends Component, BufferedValidatable, Property | |||
public String getRequiredError(); | |||
/** | |||
* An <code>Event</code> object specifying the LegacyField whose value has been | |||
* changed. | |||
* An <code>Event</code> object specifying the LegacyField whose value has | |||
* been changed. | |||
* | |||
* @author Vaadin Ltd. | |||
* @since 3.0 | |||
* | |||
* @deprecated As of 8.0, replaced by {@link ValueChange}. | |||
*/ | |||
@Deprecated | |||
@SuppressWarnings("serial") | |||
public static class ValueChangeEvent extends Component.Event implements | |||
public static class ValueChangeEvent extends | |||
Component.Event implements | |||
Property.ValueChangeEvent { | |||
/** | |||
@@ -114,6 +123,7 @@ public interface LegacyField<T> extends Component, BufferedValidatable, Property | |||
public Property getProperty() { | |||
return (Property) getSource(); | |||
} | |||
} | |||
/** |
@@ -0,0 +1,182 @@ | |||
/* | |||
* Copyright 2000-2014 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.ui; | |||
import java.lang.reflect.Method; | |||
import java.util.Collection; | |||
import java.util.Objects; | |||
import org.jsoup.nodes.Attributes; | |||
import org.jsoup.nodes.Element; | |||
import com.vaadin.data.HasValue; | |||
import com.vaadin.event.Registration; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.util.ReflectTools; | |||
/** | |||
* An abstract implementation of a field, or a {@code Component} allowing user | |||
* input. Implements {@link HasValue} to represent the input value. Examples of | |||
* typical field components include text fields, date pickers, and check boxes. | |||
* <p> | |||
* This class replaces the Vaadin 7 {@code com.vaadin.ui.AbstractField} class. | |||
* The old {@code AbstractField} is retained, under the new name | |||
* {@link com.vaadin.legacy.ui.LegacyAbstractField}, for compatibility and | |||
* migration purposes. | |||
* | |||
* @author Vaadin Ltd. | |||
* @since | |||
* | |||
* @param <T> | |||
* the input value type | |||
*/ | |||
public abstract class AbstractField<T> extends AbstractComponent | |||
implements HasValue<T> { | |||
@Deprecated | |||
private static final Method VALUE_CHANGE_METHOD = ReflectTools.findMethod( | |||
ValueChangeListener.class, "accept", ValueChange.class); | |||
@Override | |||
public void setValue(T value) { | |||
setValue(value, false); | |||
} | |||
/** | |||
* Returns whether the value of this field can be changed by the user or | |||
* not. By default fields are not read-only. | |||
* | |||
* @return {@code true} if this field is in read-only mode, {@code false} | |||
* otherwise. | |||
* | |||
* @see #setReadOnly(boolean) | |||
*/ | |||
@Override | |||
public boolean isReadOnly() { | |||
return super.isReadOnly(); | |||
} | |||
/** | |||
* Sets whether the value of this field can be changed by the user or not. A | |||
* field in read-only mode typically looks visually different to signal to | |||
* the user that the value cannot be edited. | |||
* <p> | |||
* The server ignores (potentially forged) value change requests from the | |||
* client to fields that are read-only. Programmatically changing the field | |||
* value via {@link #setValue(T)} is still possible. | |||
* <p> | |||
* The read-only mode is distinct from the | |||
* {@linkplain Component#setEnabled(boolean) disabled} state. When disabled, | |||
* a component cannot be interacted with at all, and its content should be | |||
* considered irrelevant or not applicable. In contrast, the user should | |||
* still be able to read the content and otherwise interact with a read-only | |||
* field even though changing the value is disallowed. | |||
* | |||
* @param readOnly | |||
* {@code true} to set read-only mode, {@code false} otherwise. | |||
*/ | |||
@Override | |||
public void setReadOnly(boolean readOnly) { | |||
super.setReadOnly(readOnly); | |||
} | |||
@Override | |||
public Registration addValueChangeListener( | |||
ValueChangeListener<? super T> listener) { | |||
Objects.requireNonNull(listener, "listener cannot be null"); | |||
addListener(ValueChange.class, listener, VALUE_CHANGE_METHOD); | |||
return () -> removeListener(ValueChange.class, listener); | |||
} | |||
@Override | |||
public void readDesign(Element design, DesignContext designContext) { | |||
super.readDesign(design, designContext); | |||
Attributes attr = design.attributes(); | |||
if (attr.hasKey("readonly")) { | |||
setReadOnly(DesignAttributeHandler.readAttribute("readonly", attr, | |||
Boolean.class)); | |||
} | |||
} | |||
@Override | |||
public void writeDesign(Element design, DesignContext designContext) { | |||
super.writeDesign(design, designContext); | |||
AbstractField<T> def = designContext.getDefaultInstance(this); | |||
Attributes attr = design.attributes(); | |||
DesignAttributeHandler.writeAttribute("readonly", attr, | |||
super.isReadOnly(), def.isReadOnly(), Boolean.class); | |||
} | |||
@Override | |||
protected Collection<String> getCustomAttributes() { | |||
Collection<String> attributes = super.getCustomAttributes(); | |||
attributes.add("readonly"); | |||
// must be handled by subclasses | |||
attributes.add("value"); | |||
return attributes; | |||
} | |||
/** | |||
* Sets the value of this field if it has changed and fires a value change | |||
* event. If the value originates from the client and this field is | |||
* read-only, does nothing. Invokes {@link #doSetValue(Object) doSetValue} | |||
* to actually store the value. | |||
* | |||
* @param value | |||
* the new value to set | |||
* @return {@code true} if this event originates from the client, | |||
* {@code false} otherwise. | |||
*/ | |||
protected void setValue(T value, boolean userOriginated) { | |||
if (userOriginated && isReadOnly()) { | |||
return; | |||
} | |||
if (Objects.equals(value, getValue())) { | |||
return; | |||
} | |||
doSetValue(value); | |||
if (!userOriginated) { | |||
markAsDirty(); | |||
} | |||
fireEvent(createValueChange(userOriginated)); | |||
} | |||
/** | |||
* Sets the value of this field. May do sanitization or throw | |||
* {@code IllegalArgumentException} if the value is invalid. Typically saves | |||
* the value to shared state. | |||
* | |||
* @param value | |||
* the new value of the field | |||
* @throws IllegalArgumentException | |||
* if the value is invalid | |||
*/ | |||
protected abstract void doSetValue(T value); | |||
/** | |||
* Returns a new value change event instance. | |||
* | |||
* @param userOriginated | |||
* {@code true} if this event originates from the client, | |||
* {@code false} otherwise. | |||
* @return the new event | |||
*/ | |||
protected ValueChange<T> createValueChange(boolean userOriginated) { | |||
return new ValueChange<>(this, userOriginated); | |||
} | |||
} |
@@ -379,10 +379,10 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
/** | |||
* Tests whether the component is in the read-only mode. The user can not | |||
* change the value of a read-only component. As only {@link LegacyField} | |||
* components normally have a value that can be input or changed by the | |||
* user, this is mostly relevant only to field components, though not | |||
* restricted to them. | |||
* change the value of a read-only component. As only {@link AbstractField} | |||
* or {@link LegacyField} components normally have a value that can be input | |||
* or changed by the user, this is mostly relevant only to field components, | |||
* though not restricted to them. | |||
* | |||
* <p> | |||
* Notice that the read-only mode only affects whether the user can change | |||
@@ -406,9 +406,9 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* can not change the value of a read-only component. | |||
* | |||
* <p> | |||
* As only {@link LegacyField} components normally have a value that can be input | |||
* or changed by the user, this is mostly relevant only to field components, | |||
* though not restricted to them. | |||
* As only {@link AbstractField} or{@link LegacyField} components normally | |||
* have a value that can be input or changed by the user, this is mostly | |||
* relevant only to field components, though not restricted to them. | |||
* </p> | |||
* | |||
* <p> | |||
@@ -596,7 +596,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* public class AttachExample extends CustomComponent { | |||
* public AttachExample() { | |||
* // ERROR: We can't access the application object yet. | |||
* ClassResource r = new ClassResource("smiley.jpg", getApplication()); | |||
* ClassResource r = new ClassResource("smiley.jpg", | |||
* getApplication()); | |||
* Embedded image = new Embedded("Image:", r); | |||
* setCompositionRoot(image); | |||
* } | |||
@@ -622,7 +623,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* super.attach(); // Must call. | |||
* | |||
* // Now we know who ultimately owns us. | |||
* ClassResource r = new ClassResource("smiley.jpg", getApplication()); | |||
* ClassResource r = new ClassResource("smiley.jpg", | |||
* getApplication()); | |||
* Embedded image = new Embedded("Image:", r); | |||
* setCompositionRoot(image); | |||
* } | |||
@@ -879,7 +881,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* getWindow().showNotification("Click!"); | |||
* | |||
* // Display source component and event class names | |||
* status.setValue("Event from " + event.getSource().getClass().getName() | |||
* status.setValue("Event from " + event.getSource().getClass() | |||
* .getName() | |||
* + ": " + event.getClass().getName()); | |||
* } | |||
* } | |||
@@ -904,11 +907,13 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* <pre> | |||
* public void componentEvent(Event event) { | |||
* // Act according to the source of the event | |||
* if (event.getSource() == ok && event.getClass() == Button.ClickEvent.class) | |||
* if (event.getSource() == ok && event | |||
* .getClass() == Button.ClickEvent.class) | |||
* getWindow().showNotification("Click!"); | |||
* | |||
* // Display source component and event class names | |||
* status.setValue("Event from " + event.getSource().getClass().getName() | |||
* status.setValue("Event from " + event.getSource().getClass() | |||
* .getName() | |||
* + ": " + event.getClass().getName()); | |||
* } | |||
* </pre> | |||
@@ -956,7 +961,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* if (event.getSource() == ok) | |||
* getWindow().showNotification("Click!"); | |||
* | |||
* status.setValue("Event from " + event.getSource().getClass().getName() | |||
* status.setValue("Event from " + event.getSource().getClass() | |||
* .getName() | |||
* + ": " + event.getClass().getName()); | |||
* } | |||
* } | |||
@@ -1028,9 +1034,10 @@ public interface Component extends ClientConnector, Sizeable, Serializable { | |||
* <p> | |||
* Focus can be set with {@link #focus()}. This interface does not provide | |||
* an accessor that would allow finding out the currently focused component; | |||
* focus information can be acquired for some (but not all) {@link LegacyField} | |||
* components through the {@link com.vaadin.event.FieldEvents.FocusListener} | |||
* and {@link com.vaadin.event.FieldEvents.BlurListener} interfaces. | |||
* focus information can be acquired for some (but not all) | |||
* {@link LegacyField} components through the | |||
* {@link com.vaadin.event.FieldEvents.FocusListener} and | |||
* {@link com.vaadin.event.FieldEvents.BlurListener} interfaces. | |||
* </p> | |||
* | |||
* @see FieldEvents |
@@ -0,0 +1,122 @@ | |||
package com.vaadin.ui; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertSame; | |||
import org.easymock.Capture; | |||
import org.easymock.EasyMock; | |||
import org.easymock.EasyMockSupport; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.HasValue.ValueChange; | |||
import com.vaadin.data.HasValue.ValueChangeListener; | |||
import com.vaadin.server.ClientConnector; | |||
public class AbstractFieldTest extends EasyMockSupport { | |||
class TextField extends AbstractField<String> { | |||
String value = ""; | |||
@Override | |||
public String getValue() { | |||
return value; | |||
} | |||
@Override | |||
protected void doSetValue(String value) { | |||
this.value = value; | |||
} | |||
} | |||
TextField field; | |||
ValueChangeListener<String> l; | |||
Capture<ValueChange<String>> capture; | |||
@Before | |||
public void setUp() { | |||
field = new TextField(); | |||
l = mockListener(); | |||
capture = new Capture<>(); | |||
} | |||
@Test | |||
public void readOnlyFieldAcceptsValueChangeFromServer() { | |||
field.setReadOnly(true); | |||
field.setValue("foo"); | |||
assertEquals("foo", field.getValue()); | |||
} | |||
@Test | |||
public void readOnlyFieldIgnoresValueChangeFromClient() { | |||
field.setReadOnly(true); | |||
field.setValue("bar", true); | |||
assertEquals("", field.getValue()); | |||
} | |||
@Test | |||
public void valueChangeListenerInvoked() { | |||
l.accept(EasyMock.capture(capture)); | |||
replayAll(); | |||
field.setValue("foo"); | |||
field.addValueChangeListener(l); | |||
field.setValue("bar"); | |||
assertEventEquals(capture.getValue(), "bar", field, false); | |||
verifyAll(); | |||
} | |||
@Test | |||
public void valueChangeListenerInvokedFromClient() { | |||
l.accept(EasyMock.capture(capture)); | |||
replayAll(); | |||
field.setValue("foo"); | |||
field.addValueChangeListener(l); | |||
field.setValue("bar", true); | |||
assertEventEquals(capture.getValue(), "bar", field, true); | |||
verifyAll(); | |||
} | |||
@Test | |||
public void valueChangeListenerNotInvokedIfValueUnchanged() { | |||
// expect zero invocations of l | |||
replayAll(); | |||
field.setValue("foo"); | |||
field.addValueChangeListener(l); | |||
field.setValue("foo"); | |||
verifyAll(); | |||
} | |||
@Test | |||
public void valueChangeListenerNotInvokedAfterRemove() { | |||
// expect zero invocations of l | |||
replayAll(); | |||
field.addValueChangeListener(l).remove(); | |||
field.setValue("foo"); | |||
verifyAll(); | |||
} | |||
@SuppressWarnings("unchecked") | |||
private ValueChangeListener<String> mockListener() { | |||
return createStrictMock(ValueChangeListener.class); | |||
} | |||
private void assertEventEquals(ValueChange<String> e, String value, | |||
ClientConnector source, boolean userOriginated) { | |||
assertEquals("event value", value, e.getValue()); | |||
assertSame("event source", source, e.getSource()); | |||
assertSame("event source connector", source, e.getConnector()); | |||
assertEquals("event from user", userOriginated, e.isUserOriginated()); | |||
} | |||
} |