// if there are duplicates, some item is both added & removed, just
// discard that and leave things as was before
- addedItems.removeIf(item -> removedItems.remove(item));
+ DataProvider<T, ?> dataProvider = internalGetDataProvider();
+ addedItems.removeIf(item -> {
+ Object addedId = dataProvider.getId(item);
+ return removedItems.stream().map(dataProvider::getId)
+ .anyMatch(addedId::equals)? removedItems.remove(item):false;
+ });
- if (selection.containsAll(addedItems)
- && Collections.disjoint(selection, removedItems)) {
+ if (isAllSelected(addedItems) && isNoneSelected(removedItems)) {
return;
}
updateSelection(set -> {
// order of add / remove does not matter since no duplicates
- set.removeAll(removedItems);
+ set.removeIf(item -> {
+ Object itemId = dataProvider.getId(item);
+
+ return removedItems.stream().map(dataProvider::getId)
+ .anyMatch(itemId::equals);
+ });
set.addAll(addedItems);
}, userOriginated);
}
}
+ private boolean isAllSelected(Collection<T> items) {
+ for (T item : items) {
+ if (!isSelected(item)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean isNoneSelected(Collection<T> items) {
+ for (T item : items) {
+ if (isSelected(item)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Deselects the given item. If the item is not currently selected, does
* nothing.
--- /dev/null
+/*
+ * 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.ui;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.data.provider.ListDataProvider;
+
+public class AbstractMultiSelectUsingIdTest {
+
+ public TwinColSelect<ItemWithId> selectToTest;
+
+ public static class ItemWithId {
+ private int id;
+
+ public ItemWithId() {
+ }
+
+ public ItemWithId(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ selectToTest = new TwinColSelect<>();
+ List<ItemWithId> items = new ArrayList<>();
+ items.add(new ItemWithId(3));
+ items.add(new ItemWithId(2));
+ items.add(new ItemWithId(1));
+ items.add(new ItemWithId(8));
+ items.add(new ItemWithId(7));
+ items.add(new ItemWithId(4));
+ items.add(new ItemWithId(6));
+ ListDataProvider<ItemWithId> dataProvider = new ListDataProvider<ItemWithId>(
+ items) {
+ @Override
+ public Object getId(ItemWithId item) {
+ return item.getId();
+ }
+ };
+ selectToTest.setDataProvider(dataProvider);
+
+ }
+
+ @Test
+ public void selectTwiceSelectsOnce() {
+ selectToTest.select(new ItemWithId(1));
+ assertSelectionOrder(1);
+ selectToTest.select(new ItemWithId(1));
+ assertSelectionOrder(1);
+ }
+
+ @Test
+ public void deselectWorks() {
+ selectToTest.select(new ItemWithId(1));
+ selectToTest.deselect(new ItemWithId(1));
+ assertSelectionOrder();
+ }
+
+ private void assertSelectionOrder(Integer... selectionOrder) {
+ List<Integer> asList = Arrays.asList(selectionOrder);
+ assertEquals(asList, selectToTest.getSelectedItems().stream()
+ .map(ItemWithId::getId).collect(Collectors.toList()));
+ }
+
+}
--- /dev/null
+package com.vaadin.tests.components.checkboxgroup;
+
+import com.vaadin.data.provider.DataProvider;
+import com.vaadin.data.provider.ListDataProvider;
+import com.vaadin.server.SerializablePredicate;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.CheckBoxGroup;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+
+public class CheckCheckBoxGroupWithId extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ DataProvider<MyObject, SerializablePredicate<MyObject>> dataProvider = new ListDataProvider<MyObject>(
+ Arrays.asList(new MyObject("Yellow", "real"),
+ new MyObject("Red", "real"))) {
+ @Override
+ public Object getId(MyObject item) {
+ return item.getName();
+ }
+ };
+
+ CheckBoxGroup<MyObject> checkBoxGroup = new CheckBoxGroup<>();
+ checkBoxGroup.setItemCaptionGenerator(MyObject::getName);
+ checkBoxGroup.setDataProvider(dataProvider);
+ checkBoxGroup.setValue(
+ new HashSet<>(Arrays.asList(new MyObject("Yellow", null))));
+
+ addComponent(checkBoxGroup);
+ addButton("Deselect",
+ event -> checkBoxGroup.deselect(new MyObject("Yellow", "XX")));
+ }
+
+ public static class MyObject {
+ private final String name;
+ private final String other;
+
+ public MyObject(String name, String other) {
+ this.name = name;
+ this.other = other;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getOther() {
+ return other;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ MyObject myObject = (MyObject) o;
+ return Objects.equals(name, myObject.name)
+ && Objects.equals(other, myObject.other);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, other);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.tests.components.twincolselect;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Objects;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.data.provider.ListDataProvider;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TwinColSelect;
+
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class TwinColSelectAndIdBasedDataProvider extends AbstractTestUIWithLog {
+
+ public static class MyObject {
+ private int id;
+ private String name;
+
+ public MyObject() {
+
+ }
+
+ public MyObject(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "MyObject{" + "id=" + id + ", name='" + name + '\'' + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MyObject myObject = (MyObject) o;
+ return id == myObject.id && Objects.equals(name, myObject.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name);
+ }
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ ListDataProvider<MyObject> dataProvider = new ListDataProvider<MyObject>(
+ Arrays.asList(new MyObject(0, "Zero"),
+ new MyObject(1, "One"))) {
+
+ @Override
+ public Object getId(MyObject item) {
+ return item.getId();
+ }
+ };
+
+ TwinColSelect<MyObject> twinColSelect = new TwinColSelect<>();
+ twinColSelect.setDataProvider(dataProvider);
+
+ twinColSelect.setValue(Collections.singleton(new MyObject(1, null)));
+
+ twinColSelect.addValueChangeListener(
+ event1 -> log.log("value: " + event1.getValue()));
+
+ addComponent(twinColSelect);
+ addComponent(new Button("Deselect id=1", e -> {
+ twinColSelect.deselect(new MyObject(1, "foo"));
+ }));
+ }
+
+}
--- /dev/null
+package com.vaadin.tests.components.checkboxgroup;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.CheckBoxGroupElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class CheckCheckBoxGroupWithIdTest extends MultiBrowserTest {
+ private CheckBoxGroupElement checkBoxGroup;
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ checkBoxGroup = $(CheckBoxGroupElement.class).first();
+ }
+
+ @Test
+ public void TestSelection() {
+ assertEquals(checkBoxGroup.getValue().size(), 1);
+ $(ButtonElement.class).first().click();
+ assertEquals(checkBoxGroup.getValue().size(), 0);
+ }
+}
--- /dev/null
+package com.vaadin.tests.components.twincolselect;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.TwinColSelectElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class TwinColSelectAndIdBasedDataProviderTest extends MultiBrowserTest {
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ }
+
+ @Test
+ public void TestSelection() {
+ assertEquals(getTwinColElement().getValues().size(), 1);
+ $(ButtonElement.class).first().click();
+ assertEquals(getTwinColElement().getValues().size(), 0);
+ }
+
+ private TwinColSelectElement getTwinColElement() {
+ return $(TwinColSelectElement.class).first();
+ }
+}