import java.lang.reflect.Method;
import java.util.EventObject;
import java.util.Objects;
-import com.vaadin.server.Setter;
+
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;
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.
* 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, boolean userOriginated) {
- this(component, component, userOriginated);
+ COMPONENT component, V oldValue, boolean userOriginated) {
+ this(component, component, oldValue, userOriginated);
}
/**
* 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,
- boolean userOriginated) {
+ V oldValue, boolean userOriginated) {
super(hasValue);
this.userOriginated = userOriginated;
this.component = component;
+ this.oldValue = oldValue;
+ value = hasValue.getValue();
}
/**
- * Returns the new value of the event source.
- * <p>
- * This a shorthand method for {@link HasValue#getValue()} for the event
- * source {@link #getSource()}. Thus the value is always the most recent
- * one, even if has been changed after the firing of this event.
- *
- * @see 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 getSource().getValue();
+ return value;
}
/**
public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
implements SelectionEvent<T> {
- private final Set<T> oldSelection;
-
/**
* Creates a new event.
*
*/
public MultiSelectionEvent(AbstractMultiSelect<T> source,
Set<T> oldSelection, boolean userOriginated) {
- super(source, userOriginated);
- this.oldSelection = oldSelection;
+ super(source, oldSelection, userOriginated);
}
/**
*/
public MultiSelectionEvent(Component component, MultiSelect<T> source,
Set<T> oldSelection, boolean userOriginated) {
- super(component, source, userOriginated);
- this.oldSelection = oldSelection;
+ super(component, source, oldSelection, userOriginated);
}
/**
* @return a set of items selected before the selection was changed
*/
public Set<T> getOldSelection() {
- return Collections.unmodifiableSet(oldSelection);
+ return Collections.unmodifiableSet(getOldValue());
}
/**
* @return the items that were removed from selection
*/
public Set<T> getRemovedSelection() {
- LinkedHashSet<T> copy = new LinkedHashSet<>(oldSelection);
+ LinkedHashSet<T> copy = new LinkedHashSet<>(getOldValue());
copy.removeAll(getNewSelection());
return copy;
}
*/
public Set<T> getAddedSelection() {
LinkedHashSet<T> copy = new LinkedHashSet<>(getValue());
- copy.removeAll(oldSelection);
+ copy.removeAll(getOldValue());
return copy;
}
*
* @param source
* the listing that fired the event
+ * @param oldSelection
+ * the item that was previously selected
* @param userOriginated
* {@code true} if this event originates from the client,
* {@code false} otherwise.
*/
- public SingleSelectionEvent(AbstractSingleSelect<T> source,
+ public SingleSelectionEvent(AbstractSingleSelect<T> source, T oldSelection,
boolean userOriginated) {
- super(source, userOriginated);
+ super(source, oldSelection, userOriginated);
}
/**
* the component where the event originated
* @param source
* the single select source
+ * @param oldSelection
+ * the item that was previously selected
* @param userOriginated
* {@code true} if this event originates from the client,
* {@code false} otherwise.
*/
public SingleSelectionEvent(Component component, SingleSelect<T> source,
- boolean userOriginated) {
- super(component, source, userOriginated);
+ T oldSelection, boolean userOriginated) {
+ super(component, source, oldSelection, userOriginated);
}
/**
* If value was changed fire the ValueChangeEvent
*/
if (oldDate != null) {
- fireEvent(createValueChange(true));
+ fireEvent(createValueChange(oldDate, true));
}
markAsDirty();
if (!isDifferentValue(value)) {
return false;
}
+ T oldValue = this.getValue();
doSetValue(value);
if (!userOriginated) {
markAsDirty();
}
- fireEvent(createValueChange(userOriginated));
+ fireEvent(createValueChange(oldValue, userOriginated));
return true;
}
/**
* Returns a new value change event instance.
*
+ * @param oldValue
+ * the value of this field before this value change event
* @param userOriginated
* {@code true} if this event originates from the client,
* {@code false} otherwise.
* @return the new event
*/
- protected ValueChangeEvent<T> createValueChange(boolean userOriginated) {
- return new ValueChangeEvent<>(this, userOriginated);
+ protected ValueChangeEvent<T> createValueChange(T oldValue,
+ boolean userOriginated) {
+ return new ValueChangeEvent<>(this, oldValue, userOriginated);
}
@Override
public Registration addValueChangeListener(
HasValue.ValueChangeListener<Set<T>> listener) {
return addSelectionListener(event -> listener.valueChange(
- new ValueChangeEvent<>(this, event.isUserOriginated())));
+ new ValueChangeEvent<>(this, event.getOldValue(),
+ event.isUserOriginated())));
}
/**
public Registration addValueChangeListener(
HasValue.ValueChangeListener<T> listener) {
return addSelectionListener(event -> listener.valueChange(
- new ValueChangeEvent<>(this, event.isUserOriginated())));
+ new ValueChangeEvent<>(this, event.getOldValue(),
+ event.isUserOriginated())));
}
@Override
return;
}
+ T oldSelection = getSelectedItem().orElse(getEmptyValue());
doSetSelectedKey(key);
// Update diffstate so that a change will be sent to the client if the
updateDiffstate("selectedItemKey",
key == null ? Json.createNull() : Json.create(key));
- fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, true));
+ fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
+ oldSelection, true));
}
/**
return;
}
+ T oldSelection = getSelectedItem().orElse(getEmptyValue());
doSetSelectedKey(key);
- fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, false));
+
+ fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
+ oldSelection, false));
}
/**
HasValue.ValueChangeListener<T> listener) {
return addSelectionListener(event -> {
listener.valueChange(new ValueChangeEvent<>(event.getComponent(),
- this, event.isUserOriginated()));
+ this, event.getOldValue(), event.isUserOriginated()));
});
}
@Override
public void select(int x, int y) {
+ Color oldValue = colorGrid[x][y];
ColorPickerGrid.this.x = x;
ColorPickerGrid.this.y = y;
- fireEvent(new ValueChangeEvent<>(ColorPickerGrid.this, true));
+ fireEvent(new ValueChangeEvent<>(ColorPickerGrid.this, oldValue,
+ true));
}
@Override
ColorPickerGrid grid = new ColorPickerGrid(ROWS, COLUMNS);
grid.setWidth("100%");
grid.setPosition(0, 0);
- grid.addValueChangeListener(event -> fireEvent(
- new ValueChangeEvent<>(this, event.isUserOriginated())));
+ grid.addValueChangeListener(
+ event -> fireEvent(new ValueChangeEvent<>(this,
+ event.getOldValue(), event.isUserOriginated())));
return grid;
}
/** The resize button. */
private final Button resize = new Button("show/hide history");
+ /** The previously selected color. */
+ private Color previouslySelectedColor = Color.WHITE;
+
/** The selected color. */
private Color selectedColor = Color.WHITE;
}
private void okButtonClick(ClickEvent event) {
- fireEvent(new ValueChangeEvent<>(this, true));
+ fireEvent(new ValueChangeEvent<>(this, previouslySelectedColor, true));
close();
}
public void setValue(Color color) {
Objects.requireNonNull(color, "color cannot be null");
+ previouslySelectedColor = selectedColor;
selectedColor = color;
hsvGradient.setValue(selectedColor);
private void valueChange(ValueChangeEvent<String> event) {
String value = event.getValue();
+ Color oldColor = color;
try {
if (value != null) {
/*
}
oldValue = value;
- fireEvent(
- new ValueChangeEvent<>(this, event.isUserOriginated()));
+ fireEvent(new ValueChangeEvent<>(this, oldColor,
+ event.isUserOriginated()));
}
} catch (NumberFormatException nfe) {
return;
}
+ T oldSelection = this.getSelectedItem().orElse(null);
doSetSelectedKey(key);
- fireEvent(
- new SingleSelectionEvent<>(getGrid(), asSingleSelect(), true));
+ fireEvent(new SingleSelectionEvent<>(getGrid(), asSingleSelect(),
+ oldSelection, true));
}
/**
return;
}
+ T oldSelection = this.getSelectedItem()
+ .orElse(asSingleSelect().getEmptyValue());
doSetSelectedKey(key);
- fireEvent(
- new SingleSelectionEvent<>(getGrid(), asSingleSelect(), false));
+ fireEvent(new SingleSelectionEvent<>(getGrid(), asSingleSelect(),
+ oldSelection, false));
}
/**
select = grid.asSingleSelect();
List<Sex> selected = new ArrayList<>();
+ List<Sex> oldSelected = new ArrayList<>();
List<Boolean> userOriginated = new ArrayList<>();
select.addValueChangeListener(event -> {
selected.add(event.getValue());
+ oldSelected.add(event.getOldValue());
userOriginated.add(event.isUserOriginated());
assertSame(grid, event.getComponent());
// cannot compare that the event source is the select since a new
assertEquals(Arrays.asList(Sex.UNKNOWN, Sex.MALE, null, Sex.FEMALE),
selected);
+ assertEquals(Arrays.asList(null, Sex.UNKNOWN, Sex.MALE, null),
+ oldSelected);
assertEquals(Arrays.asList(false, true, true, false), userOriginated);
}
customGrid.setItems("Foo", "Bar", "Baz");
List<String> selectionChanges = new ArrayList<>();
+ List<String> oldSelectionValues = new ArrayList<>();
((SingleSelectionModelImpl<String>) customGrid.getSelectionModel())
- .addSingleSelectionListener(
- e -> selectionChanges.add(e.getValue()));
+ .addSingleSelectionListener(e -> {
+ selectionChanges.add(e.getValue());
+ oldSelectionValues.add(e.getOldValue());
+ });
customGrid.getSelectionModel().select("Foo");
assertEquals("Foo",
customGrid.getSelectionModel().getFirstSelectedItem().get());
assertEquals(Arrays.asList("Foo"), selectionChanges);
+ assertEquals(Arrays.asList((String) null), oldSelectionValues);
customGrid.setSelectionMode(SelectionMode.MULTI);
assertEquals(Arrays.asList("Foo", null), selectionChanges);
+ assertEquals(Arrays.asList(null, "Foo"), oldSelectionValues);
}
@Test
Assert.assertSame(registration, actualRegistration);
selectionListener.get().selectionChange(new SingleSelectionEvent<>(grid,
- select.asSingleSelect(), true));
+ select.asSingleSelect(), null, true));
Assert.assertEquals(grid, event.get().getComponent());
Assert.assertEquals(value, event.get().getValue());
+ Assert.assertEquals(null, event.get().getOldValue());
Assert.assertTrue(event.get().isUserOriginated());
}
grid.getSelectionModel().deselect("foo");
+ event = eventCapture.getValue();
assertNotNull(event);
assertFalse(event.isUserOriginated());
assertEquals("bar", event.getFirstSelected().get());
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
private Registration registration;
+ private List<Set<String>> values;
+
+ private List<Set<String>> oldValues;
+
@Before
public void setUp() {
selectToTest.deselectAll();
DataProvider.create("3", "2", "1", "5", "8", "7", "4", "6"));
rpc = ComponentTest.getRpcProxy(selectToTest,
MultiSelectServerRpc.class);
+
+ values = new ArrayList<>();
+ oldValues = new ArrayList<>();
+ selectToTest
+ .addValueChangeListener(event -> values.add(event.getValue()));
+ selectToTest.addValueChangeListener(
+ event -> oldValues.add(event.getOldValue()));
}
@After
new LinkedHashSet<>(Arrays.asList("5", "2")),
new LinkedHashSet<>(Arrays.asList("3", "8")));
assertSelectionOrder("7", "5", "2");
+ verifyValueChangeEvents();
}
@Test
// deselect completely not selected
selectToTest.select("1", "4");
Assert.assertEquals(8, listenerCount.get());
+ verifyValueChangeEvents();
}
@Test
rpcUpdateSelection(new String[] { "6", "8" }, new String[] { "6" });
Assert.assertEquals(11, listenerCount.get());
assertSelectionOrder("6", "4", "8");
+ verifyValueChangeEvents();
}
@Test
set.add("3");
selectToTest.select("3");
Assert.assertEquals(set, selectToTest.getValue());
+ verifyValueChangeEvents();
}
@Test
};
Assert.assertSame(set, select.getValue());
+ verifyValueChangeEvents();
}
@Test
selectToTest.setValue(set);
Assert.assertEquals(set, selectToTest.getSelectedItems());
+ verifyValueChangeEvents();
}
@Test
Assert.assertEquals(Arrays.asList(selectionOrder),
new ArrayList<>(selectToTest.getSelectedItems()));
}
+
+ private void verifyValueChangeEvents() {
+ if (oldValues.size() > 0) {
+ Assert.assertTrue(oldValues.get(0).isEmpty());
+ Assert.assertEquals(values.size(), oldValues.size());
+ for (int i = 0; i < oldValues.size() - 1; i++) {
+ Assert.assertEquals(values.get(i), oldValues.get(i + 1));
+ }
+ }
+ }
}
public class AbstractSingleSelectTest {
private List<Person> selectionChanges;
+ private List<Person> oldSelections;
private static class PersonListing extends AbstractSingleSelect<Person>
implements Listing<Person, DataProvider<Person, ?>> {
public void initListing() {
listing = new PersonListing();
listing.setItems(PERSON_A, PERSON_B, PERSON_C);
+
selectionChanges = new ArrayList<>();
+ oldSelections = new ArrayList<>();
listing.addSelectionListener(e -> selectionChanges.add(e.getValue()));
+ listing.addSelectionListener(e -> oldSelections.add(e.getOldValue()));
}
public static final Person PERSON_C = new Person("c", 3);
assertEquals(Optional.of(PERSON_B), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_B), selectionChanges);
+ verifyValueChanges();
}
@Test
assertFalse(listing.getSelectedItem().isPresent());
assertEquals(Arrays.asList(PERSON_B, null), selectionChanges);
+ verifyValueChanges();
}
@Test
assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_B, PERSON_C), selectionChanges);
+ verifyValueChanges();
}
@Test
assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_C), selectionChanges);
+ verifyValueChanges();
}
@Test
assertFalse(listing.getSelectedItem().isPresent());
assertEquals(Arrays.asList(PERSON_C, null), selectionChanges);
+ verifyValueChanges();
}
@Test
listing.setValue(null);
Assert.assertNull(listing.getValue());
+ verifyValueChanges();
}
@Test
listing.setValue(null);
Assert.assertFalse(listing.getSelectedItem().isPresent());
+ verifyValueChanges();
}
@Test
Assert.assertSame(registration, actualRegistration);
selectionListener.get()
- .selectionChange(new SingleSelectionEvent<>(select, true));
+ .selectionChange(
+ new SingleSelectionEvent<>(select, value, true));
Assert.assertEquals(select, event.get().getComponent());
+ Assert.assertEquals(value, event.get().getOldValue());
Assert.assertEquals(value, event.get().getValue());
Assert.assertTrue(event.get().isUserOriginated());
}
+ private void verifyValueChanges() {
+ if (oldSelections.size() > 0) {
+ assertEquals(null, oldSelections.get(0));
+ assertEquals(selectionChanges.size(), oldSelections.size());
+ for (int i = 0; i < oldSelections.size() - 1; i++) {
+ assertEquals(selectionChanges.get(i), oldSelections.get(i + 1));
+ }
+ }
+ }
}