Get items of TreeGrid

Is there a way to get the items of a TreeGrid without access to the list of items that were used to create the dataProvider?

It doesn’t matter to me right now whether such a list would only contain only top-level items, or if it contains all their children too. I can’t find a way for getting either, but I havent worked with TreeGrids before so it’s possible I may have overlooked something.

For Grids, I can use ((ListDataProvider<Foo>) fooGrid.getDataProvider()).getItems();, but the TreeDataProvider that the TreeGrid uses does not have getItems().

Edit:
I have just now found the way to get all top-level items: Collection<Foo> sourceItems = ((TreeDataProvider<Foo>) fooTreeGrid.getDataProvider()).getTreeData().getRootItems();.

Good to hear! And thanks for sharing the answer so others can benefit from it.

Turns out the getRootItems() returns an unmodifiable Collection. Is there a reason for this? I now need to create a new ArrayList using the unmodifiable list from the TreeDataProvider, so I can remove one item from the TreeGrid.

Context for why I need this: I want to implement drag&drop between two TreeGrids of the same Type (Foo), and remove the dragged item from the source treegrid, using the same approach as in the [code examples for Grid]
(https://vaadin.com/components/vaadin-grid/java-examples/drag-and-drop), second example: in the definition of the dropListener, (because there are no drag&drop examples for TreeGrid)

A way to do that is by using this pattern:

List<T> list = service.getList();
grid.setItems(list);
...
list.remove(entity);
grid.getDataProvider().refreshAll();

Or:

grid.setItems(service.getList());
...
service.remove(entity);
grid.setItems(service.getList());

Alejandro Duarte:
list.remove(entity);

except that I don’t have access to that list directly in my case (just like in the code example, linked below). I need to fetch that list from the dataProvider again. That list is then unmodifiable, so I have to do this:

List<Foo> sourceRootItemsUnmodifiable = ((TreeDataProvider<Foo>) dragSource.getDataProvider()).getTreeData().getRootItems();
List<Foo> sourceRootItems = new ArrayList<>(sourceRootItemsUnmodifiable);

if(sourceRootItems.contains(draggedItem)) {
	sourceRootItems.remove(draggedItem);
	dragSource.setItems(sourceRootItems);
	dragSource.getDataProvider().refreshAll();
}

I have my TreeGrid-adaptation of the [second drag&drop example for Grid]
(https://vaadin.com/components/vaadin-grid/java-examples/drag-and-drop) now almost ready and will probably post it here for completeness (and in hopes that someday the code examples for the TreeGrid component will be updated with a drag&drop example.)

As promised, here is my implementation of drag-n-drop between two TreeGrids. I’m aware that I have sidetracked a little from the original question of the Thread, but I don’t want to open a new Thread just to post my code. I think people can find this well enough when googling for it. Feel free to use any or all code.

It bases on the previously linked code example for drag-n-drop for Grid, but some additions needed to be made - for example checking if the dragged item or any of its descendants are already in the target treegrid. There is also a new complication when removing the dragged item from the source grid - removing root-items is easy but removing a child does need some more implementation on the actual Bean class (bidirectional relation, and a removeChild() method). Adding the dragged item as a child of the dropTarget (depending on GridDropMode) also needs to be adressed.

@Route("treegrid-dnd")
public class TreeGridDNDView extends VerticalLayout {
    private Foo draggedItem = null;
    private Grid<Foo> dragSource = null;
    private int globalFooSeq = 0;

    public TreeGridDNDView(){
        add(new H1("TreeGrid Drag&Drop View"));
        SplitLayout splitLayout = new SplitLayout();
        splitLayout.setSizeFull();

        Set<Foo> primaryRootItems = mockTreeGridData();
        splitLayout.addToPrimary(prepareTreeGrid(primaryRootItems, GridDropMode.ON_GRID, true));

        Set<Foo> secondaryRootItems = mockTreeGridData();
        splitLayout.addToSecondary(prepareTreeGrid(secondaryRootItems, GridDropMode.ON_TOP, false));

        add(splitLayout);
    }

    private TreeGrid<Foo> prepareTreeGrid(Set<Foo> rootItems, GridDropMode gridDropMode, boolean removeFromSouce) {
        TreeGrid<Foo> treeGrid = new TreeGrid<>();
        treeGrid.setItems(rootItems, Foo::getChildren);
        Grid.Column<Foo> hierarchyColumn = treeGrid.addHierarchyColumn(Foo::getName).setHeader("Name");
        treeGrid.addColumn(Foo::getChildrenCount).setHeader("Direct Children Count");
        treeGrid.addColumn(Foo::getChildrenCountRecursive).setHeader("Recursive Children Count");

        treeGrid.sort(Collections.singletonList(new GridSortOrder<>(hierarchyColumn, SortDirection.ASCENDING)));
        treeGrid.setHeight("800px");

        prepareDragNDrop(treeGrid, gridDropMode, removeFromSouce);

        return treeGrid;
    }

    private void prepareDragNDrop(TreeGrid<Foo> treeGrid, GridDropMode gridDropMode, boolean removeFromSource) {
        treeGrid.setRowsDraggable(true);
        treeGrid.setDropMode(gridDropMode);
        treeGrid.addDragStartListener(event -> {
            draggedItem = event.getDraggedItems().get(0);
            dragSource = event.getSource();
        });
        treeGrid.addDragEndListener(event -> {
            draggedItem = null;
            dragSource = null;
        });
        treeGrid.addDropListener(event -> {
            // check if the draggedItem or its descendants is already in the target treegrid
            // get all items of the target-treegrid recursively (not only root-items)
            List<Foo> targetRootItemsUnmodifiable = ((TreeDataProvider<Foo>) treeGrid.getDataProvider()).getTreeData().getRootItems();
            Set<Foo> targetRootItems = new HashSet<>(targetRootItemsUnmodifiable);
            Set<Foo> targetItemsWithDescendants = getAllItemsDescendants(targetRootItems);

            // get all descendants of the dragged item recursivley
            Set<Foo> draggedItemDescendants = new HashSet<>();
            draggedItemDescendants.add(draggedItem);
            draggedItemDescendants = getAllItemsDescendants(draggedItemDescendants);

            // compare descendants from draggedItem with all items from target-treegrid
            boolean alreadyPresent = false;
            for (Foo draggedItemDescendant : draggedItemDescendants) {
                if(targetItemsWithDescendants.contains(draggedItemDescendant)){
                    alreadyPresent = true;
                }
            }

            if(alreadyPresent){
                Notification.show("This item (or a descendant thereof) is already in the target grid. Nothing is going to happen.");
            } else {
                // add draggedItem in target treegrid
                // depending on gridDropMode, it will be added as root-item, or as child of the dropTarget
                boolean mustHaveDropTargetItem = !gridDropMode.equals(GridDropMode.ON_GRID);
                if(mustHaveDropTargetItem){
                    // add draggedItem as child of dropTarget
                    Optional<Foo> dropTarget = event.getDropTargetItem();
                    if(dropTarget.isPresent()){
                        dropTarget.get().addChild(draggedItem);
                    }
                } else {
                    // add draggedItem as root-item to target treegrid
                    targetRootItems.add(draggedItem);
                }
				// refresh target treegrid
                treeGrid.setItems(targetRootItems, Foo::getChildren);
                treeGrid.getDataProvider().refreshAll();

                // remove dragged item from source-treegrid
                if(removeFromSource && dragSource instanceof TreeGrid) {
                    List<Foo> sourceRootItemsUnmodifiable = ((TreeDataProvider<Foo>) dragSource.getDataProvider()).getTreeData().getRootItems();
                    List<Foo> sourceRootItems = new ArrayList<>(sourceRootItemsUnmodifiable);

                    // only if dragged item is a root item in the source-treegrid
                    // removing non-root-items is feasible, but depends on specific bean implementations
                    if(sourceRootItems.contains(draggedItem)) {
                        sourceRootItems.remove(draggedItem);
                    } else {
                        // remove from parent bean
                        draggedItem.getParent().removeChild(draggedItem);
                    }
					// refresh source treegrid
                    ((TreeGrid<Foo>)dragSource).setItems(sourceRootItems, Foo::getChildren);
                    dragSource.getDataProvider().refreshAll();
                }
            }
        });
    }

     private Set<Foo> getAllItemsDescendants(Set<Foo> viewEntries) {
         Set<Foo> allItemsRecursive = new HashSet<>();
         viewEntries.forEach(entity -> {
             allItemsRecursive.add(entity);
             allItemsRecursive.addAll(getAllItemsDescendants(entity.getChildren()));
         });
         return allItemsRecursive;
     }

     //creates a list of 10 root-items, with each 2 children, which again have 5 children
    private Set<Foo> mockTreeGridData() {
        Set<Foo> viewEntries = new HashSet<>();
        for (int i = 1; i <= 10; i++) {
            globalFooSeq++;
            Foo rootFoo = new Foo(String.format("Foo - %d", globalFooSeq));
            for (int j = 1; j <= 2; j++) {
                String secondLevelFooName = String.format("Foo - %d.%d", globalFooSeq, j);
                Foo secondLevelFoo = new Foo(secondLevelFooName);
                for (int k = 1; k <= 5; k++) {
                    String thirdLevelName = String.format("Foo - %d.%d.%d", globalFooSeq, j, k);
                    Foo thirdLevelFoo = new Foo(thirdLevelName);
                    secondLevelFoo.addChild(thirdLevelFoo);
                }
                rootFoo.addChild(secondLevelFoo);
            }
            viewEntries.add(rootFoo);
        }
        return viewEntries;
    }

    public class Foo {
        private String name;
        private Set<Foo> children = new HashSet<>();
        private Foo parent = null;
        
        public Foo(String name){
            this.name = name;
        }
        
        public String getName(){
            return name;
        }
        
        public Set<Foo> getChildren(){
            return children;
        }

        public void addChild(Foo child){
            child.setParent(this);
            children.add(child);
        }

        public void removeChild(Foo child){
            child.setParent(null);
            children.remove(child);
        }

        public void setParent(Foo parent){
            this.parent = parent;
        }

        public Foo getParent(){
            return parent;
        }

        public int getChildrenCount(){
            return getChildren().size();
        }

        public int getChildrenCountRecursive(){
            int count = 0;
            for (Foo child : getChildren()) {
                count++;
                count += child.getChildrenCountRecursive();
            }
            return count;
        }
    }
}