@@ -99,6 +99,50 @@ public interface HasHierarchicalDataProvider<T> extends HasDataProvider<T> { | |||
new TreeData<T>().addItems(rootItems, childItemProvider))); | |||
} | |||
/** | |||
* Sets the root data items of this component provided as a stream and | |||
* recursively populates them with child items with the given value | |||
* provider. | |||
* <p> | |||
* The provided items are wrapped into a {@link TreeDataProvider} backed by | |||
* a flat {@link TreeData} structure. The data provider instance is used as | |||
* a parameter for the {@link #setDataProvider(DataProvider)} method. It | |||
* means that the items collection can be accessed later on via | |||
* {@link #getTreeData()}: | |||
* | |||
* <pre> | |||
* <code> | |||
* Stream<Person> grandParents = getGrandParents(); | |||
* HasHierarchicalDataProvider<Person> treeGrid = new TreeGrid<>(); | |||
* treeGrid.setItems(grandParents, Person::getChildren); | |||
* ... | |||
* | |||
* TreeData<Person> data = treeGrid.getTreeData(); | |||
* </code> | |||
* </pre> | |||
* <p> | |||
* The returned {@link TreeData} instance may be used as-is to add, remove | |||
* or modify items in the hierarchy. These modifications to the object are | |||
* not automatically reflected back to the TreeGrid. Items modified should | |||
* be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} | |||
* and when adding or removing items | |||
* {@link HierarchicalDataProvider#refreshAll()} should be called. | |||
* | |||
* @param rootItems | |||
* the root items to display, not {@code null} | |||
* @param childItemProvider | |||
* the value provider used to recursively populate the given root | |||
* items with child items, not {@code null} | |||
*/ | |||
public default void setItems(Stream<T> rootItems, | |||
ValueProvider<T, Stream<T>> childItemProvider) { | |||
Objects.requireNonNull(rootItems, "Given root items may not be null"); | |||
Objects.requireNonNull(childItemProvider, | |||
"Given child item provider may not be null"); | |||
setDataProvider(new TreeDataProvider<>( | |||
new TreeData<T>().addItems(rootItems, childItemProvider))); | |||
} | |||
/** | |||
* Sets the data items of this component provided as a collection. | |||
* <p> |
@@ -23,6 +23,7 @@ import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import com.vaadin.data.provider.TreeDataProvider; | |||
@@ -226,6 +227,25 @@ public class TreeData<T> implements Serializable { | |||
return this; | |||
} | |||
/** | |||
* Adds the given items as root items and uses the given value provider to | |||
* recursively populate children of the root items. | |||
* | |||
* @param rootItems | |||
* the root items to add | |||
* @param childItemProvider | |||
* the value provider used to recursively populate this TreeData | |||
* from the given root items | |||
* @return this | |||
*/ | |||
public TreeData<T> addItems(Stream<T> rootItems, | |||
ValueProvider<T, Stream<T>> childItemProvider) { | |||
// Must collect to lists since the algorithm iterates multiple times | |||
return addItems(rootItems.collect(Collectors.toList()), | |||
item -> childItemProvider.apply(item) | |||
.collect(Collectors.toList())); | |||
} | |||
/** | |||
* Remove a given item from this structure. Additionally, this will | |||
* recursively remove any descendants of the item. |
@@ -5,6 +5,7 @@ import java.util.Arrays; | |||
import java.util.Comparator; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
@@ -12,8 +13,8 @@ import org.junit.Test; | |||
import com.vaadin.data.TreeData; | |||
import com.vaadin.server.SerializablePredicate; | |||
public class TreeDataProviderTest extends | |||
DataProviderTestBase<TreeDataProvider<StrBean>> { | |||
public class TreeDataProviderTest | |||
extends DataProviderTestBase<TreeDataProvider<StrBean>> { | |||
private TreeData<StrBean> data; | |||
private List<StrBean> flattenedData; | |||
@@ -46,8 +47,7 @@ public class TreeDataProviderTest extends | |||
@Test(expected = IllegalArgumentException.class) | |||
public void treeData_add_item_parent_not_in_hierarchy_throws() { | |||
new TreeData<>().addItem(new StrBean("", 0, 0), | |||
new StrBean("", 0, 0)); | |||
new TreeData<>().addItem(new StrBean("", 0, 0), new StrBean("", 0, 0)); | |||
} | |||
@Test(expected = NullPointerException.class) | |||
@@ -98,6 +98,24 @@ public class TreeDataProviderTest extends | |||
Assert.assertEquals(stringData.getChildren("a/b"), Arrays.asList()); | |||
} | |||
@Test | |||
public void populate_treeData_with_stream_child_item_provider() { | |||
TreeData<String> stringData = new TreeData<>(); | |||
Stream<String> rootItems = Stream.of("a", "b", "c"); | |||
stringData.addItems(rootItems, item -> { | |||
if (item.length() >= 3 || item.startsWith("c")) { | |||
return Stream.empty(); | |||
} | |||
return Stream.of(item + "/a", item + "/b", item + "/c"); | |||
}); | |||
Assert.assertEquals(stringData.getChildren("a"), | |||
Arrays.asList("a/a", "a/b", "a/c")); | |||
Assert.assertEquals(stringData.getChildren("b"), | |||
Arrays.asList("b/a", "b/b", "b/c")); | |||
Assert.assertEquals(stringData.getChildren("c"), Arrays.asList()); | |||
Assert.assertEquals(stringData.getChildren("a/b"), Arrays.asList()); | |||
} | |||
@Test | |||
public void setFilter() { | |||
getDataProvider().setFilter(item -> item.getValue().equals("Xyz") |