]> source.dussan.org Git - vaadin-framework.git/commitdiff
Include old value in ValueChangeEvent (#8229)
authorAleksi Hietanen <aleksi@vaadin.com>
Fri, 13 Jan 2017 06:36:51 +0000 (08:36 +0200)
committerPekka Hyvönen <pekka@vaadin.com>
Fri, 13 Jan 2017 06:36:51 +0000 (08:36 +0200)
* Include old value in ValueChangeEvent

18 files changed:
server/src/main/java/com/vaadin/data/HasValue.java
server/src/main/java/com/vaadin/event/selection/MultiSelectionEvent.java
server/src/main/java/com/vaadin/event/selection/SingleSelectionEvent.java
server/src/main/java/com/vaadin/ui/AbstractDateField.java
server/src/main/java/com/vaadin/ui/AbstractField.java
server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java
server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
server/src/main/java/com/vaadin/ui/ComboBox.java
server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java
server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java
server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java
server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java
server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModelImpl.java
server/src/test/java/com/vaadin/data/GridAsSingleSelectInBinderTest.java
server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java
server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java
server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java
server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java

index b5707605cd2325887a50248e142e661652546ef1..962a3e9620b121a555169924dadaed60849d0319 100644 (file)
@@ -19,8 +19,9 @@ import java.io.Serializable;
 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;
@@ -50,6 +51,9 @@ public interface HasValue<V> extends Serializable {
         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.
@@ -58,13 +62,15 @@ public interface HasValue<V> extends Serializable {
          *            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);
         }
 
         /**
@@ -75,31 +81,39 @@ public interface HasValue<V> extends Serializable {
          *            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;
         }
 
         /**
index 3c89a53f509c7f92478ae21e8a77c01291c4d2e0..e00c60dca6d9bbc180d2d03fdc9e4a7301bb0ed7 100644 (file)
@@ -39,8 +39,6 @@ import com.vaadin.ui.MultiSelect;
 public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
         implements SelectionEvent<T> {
 
-    private final Set<T> oldSelection;
-
     /**
      * Creates a new event.
      *
@@ -54,8 +52,7 @@ public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
      */
     public MultiSelectionEvent(AbstractMultiSelect<T> source,
             Set<T> oldSelection, boolean userOriginated) {
-        super(source, userOriginated);
-        this.oldSelection = oldSelection;
+        super(source, oldSelection, userOriginated);
     }
 
     /**
@@ -73,8 +70,7 @@ public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
      */
     public MultiSelectionEvent(Component component, MultiSelect<T> source,
             Set<T> oldSelection, boolean userOriginated) {
-        super(component, source, userOriginated);
-        this.oldSelection = oldSelection;
+        super(component, source, oldSelection, userOriginated);
     }
 
     /**
@@ -98,7 +94,7 @@ public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
      * @return a set of items selected before the selection was changed
      */
     public Set<T> getOldSelection() {
-        return Collections.unmodifiableSet(oldSelection);
+        return Collections.unmodifiableSet(getOldValue());
     }
 
     /**
@@ -111,7 +107,7 @@ public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
      * @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;
     }
@@ -127,7 +123,7 @@ public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
      */
     public Set<T> getAddedSelection() {
         LinkedHashSet<T> copy = new LinkedHashSet<>(getValue());
-        copy.removeAll(oldSelection);
+        copy.removeAll(getOldValue());
         return copy;
     }
 
index 89f30e186913e97d1c657680c2c74a6f49e39803..db78e0591b6f4a2f0447e6777d029e03a6604f52 100644 (file)
@@ -42,13 +42,15 @@ public class SingleSelectionEvent<T> extends ValueChangeEvent<T>
      *
      * @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);
     }
 
     /**
@@ -58,13 +60,15 @@ public class SingleSelectionEvent<T> extends ValueChangeEvent<T>
      *            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);
     }
 
     /**
index 0a6cf8fc514aa8d712e13052a80e8f442e69703d..57e0b0ce5fc250980df23d427ecc0a521c71ae35 100644 (file)
@@ -297,7 +297,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
                      * If value was changed fire the ValueChangeEvent
                      */
                     if (oldDate != null) {
-                        fireEvent(createValueChange(true));
+                        fireEvent(createValueChange(oldDate, true));
                     }
 
                     markAsDirty();
index 9f1a275ad03d8d21c727e692545c50bcc6645f67..6990f19aa07ebc8a68a215ce2a7c229f1830297b 100644 (file)
@@ -136,11 +136,12 @@ public abstract class AbstractField<T> extends AbstractComponent
         if (!isDifferentValue(value)) {
             return false;
         }
+        T oldValue = this.getValue();
         doSetValue(value);
         if (!userOriginated) {
             markAsDirty();
         }
-        fireEvent(createValueChange(userOriginated));
+        fireEvent(createValueChange(oldValue, userOriginated));
 
         return true;
     }
@@ -178,13 +179,16 @@ public abstract class AbstractField<T> extends AbstractComponent
     /**
      * 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
index ce79da25a11aa8b08c7351a0542c1d7a976d6694..e104b1c4e669fcca4fcca6d7c86fdb1fbaaa369c 100644 (file)
@@ -230,7 +230,8 @@ public abstract class AbstractMultiSelect<T> extends AbstractListing<T>
     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())));
     }
 
     /**
index f98d15bf10222e3323c5b702757c4850e10b8ceb..967b84e6b6257a1ae5fcb166b786e3726271fb17 100644 (file)
@@ -154,7 +154,8 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
     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
@@ -227,6 +228,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
             return;
         }
 
+        T oldSelection = getSelectedItem().orElse(getEmptyValue());
         doSetSelectedKey(key);
 
         // Update diffstate so that a change will be sent to the client if the
@@ -234,7 +236,8 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
         updateDiffstate("selectedItemKey",
                 key == null ? Json.createNull() : Json.create(key));
 
-        fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, true));
+        fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
+                oldSelection, true));
     }
 
     /**
@@ -253,8 +256,11 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
             return;
         }
 
+        T oldSelection = getSelectedItem().orElse(getEmptyValue());
         doSetSelectedKey(key);
-        fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, false));
+
+        fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
+                oldSelection, false));
     }
 
     /**
index f742a22adc2e556647a1f185cf2659d069949de8..226269d72e8aa31a849cee9ea1ef6795a2436657 100644 (file)
@@ -552,7 +552,7 @@ public class ComboBox<T> extends AbstractSingleSelect<T>
             HasValue.ValueChangeListener<T> listener) {
         return addSelectionListener(event -> {
             listener.valueChange(new ValueChangeEvent<>(event.getComponent(),
-                    this, event.isUserOriginated()));
+                    this, event.getOldValue(), event.isUserOriginated()));
         });
     }
 
index 95229a2d6a5a2214adcd0c1ad56a9ae0f6fa1fb8..6ab1ac1ccb1b7666c1f04d5487db678e92019c5a 100644 (file)
@@ -38,9 +38,11 @@ public class ColorPickerGrid extends AbstractField<Color> {
 
         @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
index 101a4b642a7d0252c2618db00023ce431a74a8de..41606737d51bf49a02d1a6b5f62cce7adca9bdee 100644 (file)
@@ -50,8 +50,9 @@ public class ColorPickerHistory extends CustomField<Color> {
         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;
     }
index 9d88b03fa515f058daee313fcaa7593ae3f7150b..8d945e9e9ca101eca9b99a6e90d5e414fa194250 100644 (file)
@@ -73,6 +73,9 @@ public class ColorPickerPopup extends Window implements HasValue<Color> {
     /** 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;
 
@@ -448,7 +451,7 @@ public class ColorPickerPopup extends Window implements HasValue<Color> {
     }
 
     private void okButtonClick(ClickEvent event) {
-        fireEvent(new ValueChangeEvent<>(this, true));
+        fireEvent(new ValueChangeEvent<>(this, previouslySelectedColor, true));
         close();
     }
 
@@ -479,6 +482,7 @@ public class ColorPickerPopup extends Window implements HasValue<Color> {
     public void setValue(Color color) {
         Objects.requireNonNull(color, "color cannot be null");
 
+        previouslySelectedColor = selectedColor;
         selectedColor = color;
 
         hsvGradient.setValue(selectedColor);
index 0c99779658812575158aeb330b17a6017d64b4c5..6953d980f49cc8fcb91e95d917f4bb413c057a4c 100644 (file)
@@ -122,6 +122,7 @@ public class ColorPickerPreview extends CssLayout implements HasValue<Color> {
 
     private void valueChange(ValueChangeEvent<String> event) {
         String value = event.getValue();
+        Color oldColor = color;
         try {
             if (value != null) {
                 /*
@@ -174,8 +175,8 @@ public class ColorPickerPreview extends CssLayout implements HasValue<Color> {
                 }
 
                 oldValue = value;
-                fireEvent(
-                        new ValueChangeEvent<>(this, event.isUserOriginated()));
+                fireEvent(new ValueChangeEvent<>(this, oldColor,
+                        event.isUserOriginated()));
             }
 
         } catch (NumberFormatException nfe) {
index eeb57bab2676437930f0385f677743fc0c5fc3ad..4b3eb2d41c3d6cbe64ec7ee425e4ac597be1dec2 100644 (file)
@@ -163,9 +163,10 @@ public class SingleSelectionModelImpl<T> extends AbstractSelectionModel<T>
             return;
         }
 
+        T oldSelection = this.getSelectedItem().orElse(null);
         doSetSelectedKey(key);
-        fireEvent(
-                new SingleSelectionEvent<>(getGrid(), asSingleSelect(), true));
+        fireEvent(new SingleSelectionEvent<>(getGrid(), asSingleSelect(),
+                oldSelection, true));
     }
 
     /**
@@ -184,9 +185,11 @@ public class SingleSelectionModelImpl<T> extends AbstractSelectionModel<T>
             return;
         }
 
+        T oldSelection = this.getSelectedItem()
+                .orElse(asSingleSelect().getEmptyValue());
         doSetSelectedKey(key);
-        fireEvent(
-                new SingleSelectionEvent<>(getGrid(), asSingleSelect(), false));
+        fireEvent(new SingleSelectionEvent<>(getGrid(), asSingleSelect(),
+                oldSelection, false));
     }
 
     /**
index 9886df43fc1fa197403e2f0b1dbc4415634def74..077ca185a225b8930cfad7160bba70e1074807dd 100644 (file)
@@ -129,9 +129,11 @@ public class GridAsSingleSelectInBinderTest
         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
@@ -150,6 +152,8 @@ public class GridAsSingleSelectInBinderTest
 
         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);
     }
 
index cded4f878c868c664d9838d3ac48aa0c1895b810..ce4da636d0ddb74d03a94980b4157e062996a470 100644 (file)
@@ -96,17 +96,22 @@ public class GridSingleSelectionModelTest {
         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
@@ -314,10 +319,11 @@ public class GridSingleSelectionModelTest {
         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());
     }
 
index f545581bb3317d99690019b51942bb7f59a77627..a692ecc5663fcbbff5510e8b14603d530eb3f68c 100644 (file)
@@ -148,6 +148,7 @@ public class GridTest {
 
         grid.getSelectionModel().deselect("foo");
 
+        event = eventCapture.getValue();
         assertNotNull(event);
         assertFalse(event.isUserOriginated());
         assertEquals("bar", event.getFirstSelected().get());
index d98477c66d6117196665782ef95e3a578f634640..4b4ddbcae94aea6aaa08b67d4b792e19149e364e 100644 (file)
@@ -20,6 +20,7 @@ import java.util.Arrays;
 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;
@@ -60,6 +61,10 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
 
     private Registration registration;
 
+    private List<Set<String>> values;
+
+    private List<Set<String>> oldValues;
+
     @Before
     public void setUp() {
         selectToTest.deselectAll();
@@ -68,6 +73,13 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
                 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
@@ -102,6 +114,7 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
                 new LinkedHashSet<>(Arrays.asList("5", "2")),
                 new LinkedHashSet<>(Arrays.asList("3", "8")));
         assertSelectionOrder("7", "5", "2");
+        verifyValueChangeEvents();
     }
 
     @Test
@@ -140,6 +153,7 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
         // deselect completely not selected
         selectToTest.select("1", "4");
         Assert.assertEquals(8, listenerCount.get());
+        verifyValueChangeEvents();
     }
 
     @Test
@@ -216,6 +230,7 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
         rpcUpdateSelection(new String[] { "6", "8" }, new String[] { "6" });
         Assert.assertEquals(11, listenerCount.get());
         assertSelectionOrder("6", "4", "8");
+        verifyValueChangeEvents();
     }
 
     @Test
@@ -235,6 +250,7 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
         set.add("3");
         selectToTest.select("3");
         Assert.assertEquals(set, selectToTest.getValue());
+        verifyValueChangeEvents();
     }
 
     @Test
@@ -250,6 +266,7 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
         };
 
         Assert.assertSame(set, select.getValue());
+        verifyValueChangeEvents();
     }
 
     @Test
@@ -265,6 +282,7 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
         selectToTest.setValue(set);
 
         Assert.assertEquals(set, selectToTest.getSelectedItems());
+        verifyValueChangeEvents();
     }
 
     @Test
@@ -351,4 +369,14 @@ public class AbstractMultiSelectTest<S extends AbstractMultiSelect<String> & Lis
         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));
+            }
+        }
+    }
 }
index 9bbcc2ca43f57b241ce8f05cfdb6a2a8194dba43..cfcdba1f1c6b10c5b7d04ae541db68737d20f0e4 100644 (file)
@@ -49,6 +49,7 @@ import com.vaadin.ui.declarative.DesignContext;
 public class AbstractSingleSelectTest {
 
     private List<Person> selectionChanges;
+    private List<Person> oldSelections;
 
     private static class PersonListing extends AbstractSingleSelect<Person>
             implements Listing<Person, DataProvider<Person, ?>> {
@@ -79,8 +80,11 @@ public class AbstractSingleSelectTest {
     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);
@@ -106,6 +110,7 @@ public class AbstractSingleSelectTest {
         assertEquals(Optional.of(PERSON_B), listing.getSelectedItem());
 
         assertEquals(Arrays.asList(PERSON_B), selectionChanges);
+        verifyValueChanges();
     }
 
     @Test
@@ -123,6 +128,7 @@ public class AbstractSingleSelectTest {
         assertFalse(listing.getSelectedItem().isPresent());
 
         assertEquals(Arrays.asList(PERSON_B, null), selectionChanges);
+        verifyValueChanges();
     }
 
     @Test
@@ -140,6 +146,7 @@ public class AbstractSingleSelectTest {
         assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
 
         assertEquals(Arrays.asList(PERSON_B, PERSON_C), selectionChanges);
+        verifyValueChanges();
     }
 
     @Test
@@ -157,6 +164,7 @@ public class AbstractSingleSelectTest {
         assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
 
         assertEquals(Arrays.asList(PERSON_C), selectionChanges);
+        verifyValueChanges();
     }
 
     @Test
@@ -175,6 +183,7 @@ public class AbstractSingleSelectTest {
         assertFalse(listing.getSelectedItem().isPresent());
 
         assertEquals(Arrays.asList(PERSON_C, null), selectionChanges);
+        verifyValueChanges();
     }
 
     @Test
@@ -185,6 +194,7 @@ public class AbstractSingleSelectTest {
 
         listing.setValue(null);
         Assert.assertNull(listing.getValue());
+        verifyValueChanges();
     }
 
     @Test
@@ -211,6 +221,7 @@ public class AbstractSingleSelectTest {
         listing.setValue(null);
 
         Assert.assertFalse(listing.getSelectedItem().isPresent());
+        verifyValueChanges();
     }
 
     @Test
@@ -266,11 +277,22 @@ public class AbstractSingleSelectTest {
         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));
+            }
+        }
+    }
 }