]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add events and functionality to Tree (#9318)
authorTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>
Tue, 16 May 2017 06:36:22 +0000 (09:36 +0300)
committerPekka Hyvönen <pekka@vaadin.com>
Tue, 16 May 2017 06:36:22 +0000 (09:36 +0300)
* Add ItemClick event to Tree
* Add collapse provider and style generator to Tree

server/src/main/java/com/vaadin/ui/Tree.java
uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java
uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java

index 8f02c8c88fa9b9fe4938936eff424fbeb982889d..97e1b94cecd96ca87744fb035c6a95468ba373ec 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.vaadin.ui;
 
+import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -30,15 +31,19 @@ import com.vaadin.data.provider.DataProvider;
 import com.vaadin.data.provider.HierarchicalDataProvider;
 import com.vaadin.event.CollapseEvent;
 import com.vaadin.event.CollapseEvent.CollapseListener;
+import com.vaadin.event.ConnectorEvent;
 import com.vaadin.event.ExpandEvent;
 import com.vaadin.event.ExpandEvent.ExpandListener;
+import com.vaadin.event.SerializableEventListener;
 import com.vaadin.event.selection.SelectionListener;
 import com.vaadin.server.Resource;
+import com.vaadin.server.SerializablePredicate;
 import com.vaadin.shared.Registration;
 import com.vaadin.shared.ui.grid.HeightMode;
 import com.vaadin.shared.ui.tree.TreeRendererState;
 import com.vaadin.ui.Grid.SelectionMode;
 import com.vaadin.ui.renderers.AbstractRenderer;
+import com.vaadin.util.ReflectTools;
 
 import elemental.json.JsonObject;
 
@@ -54,6 +59,72 @@ import elemental.json.JsonObject;
  */
 public class Tree<T> extends Composite implements HasDataProvider<T> {
 
+    @Deprecated
+    private static final Method ITEM_CLICK_METHOD = ReflectTools
+            .findMethod(ItemClickListener.class, "itemClick", ItemClick.class);
+
+    /**
+     * A listener for item click events.
+     *
+     * @param <T>
+     *            the tree item type
+     *
+     * @see ItemClick
+     * @see Registration
+     * @since 8.1
+     */
+    @FunctionalInterface
+    public interface ItemClickListener<T> extends SerializableEventListener {
+        /**
+         * Invoked when this listener receives a item click event from a Tree to
+         * which it has been added.
+         *
+         * @param event
+         *            the received event, not {@code null}
+         */
+        public void itemClick(Tree.ItemClick<T> event);
+    }
+
+    /**
+     * Tree item click event.
+     *
+     * @param <T>
+     *            the data type of tree
+     * @since 8.1
+     */
+    public static class ItemClick<T> extends ConnectorEvent {
+
+        private final T item;
+
+        /**
+         * Constructs a new item click.
+         *
+         * @param source
+         *            the tree component
+         * @param item
+         *            the clicked item
+         */
+        protected ItemClick(Tree<T> source, T item) {
+            super(source);
+            this.item = item;
+        }
+
+        /**
+         * Returns the clicked item.
+         *
+         * @return the clicked item
+         */
+        public T getItem() {
+            return item;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Tree<T> getSource() {
+            return (Tree<T>) super.getSource();
+        }
+    }
+
     /**
      * String renderer that handles icon resources and stores their identifiers
      * into data objects.
@@ -142,6 +213,8 @@ public class Tree<T> extends Composite implements HasDataProvider<T> {
                 e.isUserOriginated()));
         treeGrid.addCollapseListener(e -> fireCollapseEvent(
                 e.getCollapsedItem(), e.isUserOriginated()));
+        treeGrid.addItemClickListener(
+                e -> fireEvent(new ItemClick<>(this, e.getItem())));
     }
 
     /**
@@ -388,6 +461,49 @@ public class Tree<T> extends Composite implements HasDataProvider<T> {
         treeGrid.getDataCommunicator().reset();
     }
 
+    /**
+     * Sets the item collapse allowed provider for this Tree. The provider
+     * should return {@code true} for any item that the user can collapse.
+     * <p>
+     * <strong>Note:</strong> This callback will be accessed often when sending
+     * data to the client. The callback should not do any costly operations.
+     *
+     * @param provider
+     *            the item collapse allowed provider, not {@code null}
+     */
+    public void setItemCollapseAllowedProvider(
+            SerializablePredicate<T> provider) {
+        treeGrid.setItemCollapseAllowedProvider(provider);
+    }
+
+    /**
+     * Sets the style generator that is used for generating class names for
+     * items in this tree. Returning null from the generator results in no
+     * custom style name being set.
+     *
+     * @see StyleGenerator
+     *
+     * @param styleGenerator
+     *            the item style generator to set, not {@code null}
+     * @throws NullPointerException
+     *             if {@code styleGenerator} is {@code null}
+     */
+    public void setStyleGenerator(StyleGenerator<T> styleGenerator) {
+        treeGrid.setStyleGenerator(styleGenerator);
+    }
+
+    /**
+     * Adds an item click listener. The listener is called when an item of this
+     * {@code Tree} is clicked.
+     *
+     * @param listener
+     *            the item click listener, not null
+     * @return a registration for the listener
+     */
+    public Registration addItemClickListener(ItemClickListener<T> listener) {
+        return addListener(ItemClick.class, listener, ITEM_CLICK_METHOD);
+    }
+
     /**
      * @deprecated This component's height is always set to be undefined.
      *             Calling this method will have no effect.
index a2078c237e19ffbc4d75967d095b73d764b8e934..e0fa469fa8d488fe07b251cb8af30dd59b3884de 100644 (file)
@@ -11,11 +11,13 @@ import com.vaadin.icons.VaadinIcons;
 import com.vaadin.server.ClassResource;
 import com.vaadin.server.ThemeResource;
 import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.Registration;
 import com.vaadin.tests.components.AbstractTestUIWithLog;
 import com.vaadin.tests.data.bean.HierarchicalTestBean;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.IconGenerator;
 import com.vaadin.ui.MenuBar;
+import com.vaadin.ui.MenuBar.Command;
 import com.vaadin.ui.MenuBar.MenuItem;
 import com.vaadin.ui.Tree;
 import com.vaadin.ui.VerticalLayout;
@@ -66,6 +68,43 @@ public class TreeBasicFeatures extends AbstractTestUIWithLog {
         MenuItem componentMenu = menu.addItem("Component", null);
         createIconMenu(componentMenu.addItem("Icons", null));
         createCaptionMenu(componentMenu.addItem("Captions", null));
+        componentMenu.addItem("Item Click Listener", new Command() {
+
+            private Registration registration;
+
+            @Override
+            public void menuSelected(MenuItem selectedItem) {
+                removeRegistration();
+
+                if (selectedItem.isChecked()) {
+                    registration = tree.addItemClickListener(
+                            e -> log("ItemClick: " + e.getItem()));
+                }
+            }
+
+            private void removeRegistration() {
+                if (registration != null) {
+                    registration.remove();
+                    registration = null;
+                }
+            }
+
+        }).setCheckable(true);
+        MenuItem collapseAllowed = componentMenu.addItem("Collapse Allowed",
+                menuItem -> tree.setItemCollapseAllowedProvider(
+                        t -> menuItem.isChecked()));
+        collapseAllowed.setCheckable(true);
+
+        // Simulate the first click
+        collapseAllowed.setChecked(true);
+        collapseAllowed.getCommand().menuSelected(collapseAllowed);
+
+        componentMenu
+                .addItem("Style Generator",
+                        menuItem -> tree.setStyleGenerator(menuItem.isChecked()
+                                ? t -> "level" + t.getDepth() : t -> null))
+                .setCheckable(true);
+
         return menu;
     }
 
index 682c2028d5dd5c0c4efda95a72c596a3c7e87bf1..8d95bf5ef64e832f95009ff73289ae84c9bb8aec 100644 (file)
@@ -10,6 +10,7 @@ import org.openqa.selenium.By;
 
 import com.vaadin.testbench.TestBenchElement;
 import com.vaadin.testbench.elements.TreeElement;
+import com.vaadin.testbench.elements.TreeGridElement;
 import com.vaadin.tests.tb3.MultiBrowserTest;
 
 public class TreeBasicFeaturesTest extends MultiBrowserTest {
@@ -127,4 +128,40 @@ public class TreeBasicFeaturesTest extends MultiBrowserTest {
 
         assertNoErrorNotifications();
     }
+
+    @Test
+    public void tree_item_click() {
+        selectMenuPath("Component", "Item Click Listener");
+        $(TreeElement.class).first().getItem(1).click();
+        Assert.assertTrue(logContainsText("ItemClick: 0 | 1"));
+    }
+
+    @Test
+    public void tree_style_generator() {
+        selectMenuPath("Component", "Style Generator");
+        TreeElement tree = $(TreeElement.class).first();
+        Assert.assertTrue("Style name not present",
+                tree.wrap(TreeGridElement.class).getRow(0).getAttribute("class")
+                        .contains("level0"));
+        tree.expand(0);
+        Assert.assertTrue("Style name not present",
+                tree.wrap(TreeGridElement.class).getRow(1).getAttribute("class")
+                        .contains("level1"));
+        tree.expand(1);
+        Assert.assertTrue("Style name not present",
+                tree.wrap(TreeGridElement.class).getRow(2).getAttribute("class")
+                        .contains("level2"));
+    }
+
+    @Test
+    public void tree_disable_collapse() {
+        selectMenuPath("Component", "Collapse Allowed");
+        TreeElement tree = $(TreeElement.class).first();
+        tree.expand(0);
+        tree.expand(1);
+        Assert.assertEquals("2 | 0", tree.getItem(2).getText());
+        tree.collapse(1);
+        Assert.assertEquals("Tree should prevent collapsing all nodes.",
+                "2 | 0", tree.getItem(2).getText());
+    }
 }