*/
package com.vaadin.ui;
+import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
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;
*/
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.
e.isUserOriginated()));
treeGrid.addCollapseListener(e -> fireCollapseEvent(
e.getCollapsedItem(), e.isUserOriginated()));
+ treeGrid.addItemClickListener(
+ e -> fireEvent(new ItemClick<>(this, e.getItem())));
}
/**
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.
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;
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;
}
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 {
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());
+ }
}