From a8a6d25fe93002d8d11f958e9ddadc5c49604174 Mon Sep 17 00:00:00 2001 From: Adam Wagner Date: Tue, 18 Jul 2017 13:30:33 +0200 Subject: [PATCH] Add methods to change parent and to change child's position in hierarchical data (#9673) Resolves #9674 --- .../main/java/com/vaadin/data/TreeData.java | 83 +++++++++++++++++++ .../data/provider/TreeDataProviderTest.java | 45 ++++++++++ 2 files changed, 128 insertions(+) diff --git a/server/src/main/java/com/vaadin/data/TreeData.java b/server/src/main/java/com/vaadin/data/TreeData.java index b0bdcde835..bebf312614 100644 --- a/server/src/main/java/com/vaadin/data/TreeData.java +++ b/server/src/main/java/com/vaadin/data/TreeData.java @@ -367,6 +367,89 @@ public class TreeData implements Serializable { .unmodifiableList(itemToWrapperMap.get(item).getChildren()); } + /** + * Moves an item to become a child of the given parent item. The new parent + * item must exist in the hierarchy. Setting the parent to {@code null} + * makes the item a root item. After making changes to the tree data, {@link + * TreeDataProvider#refreshAll()} should be called. + * + * @param item + * the item to be set as the child of {@code parent} + * @param parent + * the item to be set as parent or {@code null} to set the item as + * root + * @since 8.1 + */ + public void setParent(T item, T parent) { + if (!contains(item)) { + throw new IllegalArgumentException( + "Item '" + item + "' not in the hierarchy"); + } + + if (parent != null && !contains(parent)) { + throw new IllegalArgumentException( + "Parent needs to be added before children. " + + "To set as root item, call with parent as null"); + } + + if (item.equals(parent)) { + throw new IllegalArgumentException( + "Item cannot be the parent of itself"); + } + + T oldParent = itemToWrapperMap.get(item).getParent(); + + if (!Objects.equals(oldParent, parent)) { + // Remove item from old parent's children + itemToWrapperMap.get(oldParent).removeChild(item); + + // Add item to parent's children + itemToWrapperMap.get(parent).addChild(item); + + // Set item's new parent + itemToWrapperMap.get(item).setParent(parent); + } + } + + /** + * Moves an item to the position immediately after a sibling item. The two + * items must have the same parent. After making changes to the tree data, + * {@link TreeDataProvider#refreshAll()} should be called. + * + * @param item + * the item to be moved + * @param sibling + * the item after which the moved item will be located + * @since 8.1 + */ + public void moveAfterSibling(T item, T sibling) { + if (!contains(item)) { + throw new IllegalArgumentException( + "Item '" + item + "' not in the hierarchy"); + } + + if (!contains(sibling)) { + throw new IllegalArgumentException( + "Item '" + sibling + "' not in the hierarchy"); + } + + T parent = itemToWrapperMap.get(item).getParent(); + + if (!Objects + .equals(parent, itemToWrapperMap.get(sibling).getParent())) { + throw new IllegalArgumentException( + "Items '" + item + "' and '" + sibling + + "' don't have the same parent"); + } + + List children = itemToWrapperMap.get(parent).getChildren(); + + // Move item to the position after the sibling + // If sibling is null, item is moved to the first position + children.remove(item); + children.add(children.indexOf(sibling) + 1, item); + } + /** * Check whether the given item is in this hierarchy. * diff --git a/server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java b/server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java index 186ed14e8a..8232d2fc45 100644 --- a/server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java +++ b/server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java @@ -80,6 +80,51 @@ public class TreeDataProviderTest Assert.assertTrue(data.getChildren(null).contains(item)); } + @Test + public void treeData_set_parent() { + StrBean item1 = rootData.get(0); + StrBean item2 = rootData.get(1); + Assert.assertEquals(0, data.getChildren(item2).size()); + Assert.assertEquals(10, data.getRootItems().size()); + + // Move item1 as item2's child + data.setParent(item1, item2); + Assert.assertEquals(1, data.getChildren(item2).size()); + Assert.assertEquals(9, data.getRootItems().size()); + Assert.assertEquals(item1, data.getChildren(item2).get(0)); + + // Move back to root + data.setParent(item1, null); + Assert.assertEquals(0, data.getChildren(item2).size()); + Assert.assertEquals(10, data.getRootItems().size()); + } + + @Test + public void treeData_move_after_sibling() { + StrBean root0 = rootData.get(0); + StrBean root9 = rootData.get(9); + Assert.assertEquals(root0, data.getRootItems().get(0)); + Assert.assertEquals(root9, data.getRootItems().get(9)); + + // Move to last position + data.moveAfterSibling(root0, root9); + Assert.assertEquals(root0, data.getRootItems().get(9)); + Assert.assertEquals(root9, data.getRootItems().get(8)); + + // Move back to first position + data.moveAfterSibling(root0, null); + Assert.assertEquals(root0, data.getRootItems().get(0)); + Assert.assertEquals(root9, data.getRootItems().get(9)); + } + + @Test(expected = IllegalArgumentException.class) + public void treeData_move_after_sibling_different_parents() { + StrBean root0 = rootData.get(0); + StrBean wrongSibling = data.getChildren(root0).get(0); + + data.moveAfterSibling(root0, wrongSibling); + } + @Test public void treeData_root_items() { TreeData data = new TreeData<>(); -- 2.39.5