Browse Source

Add events and functionality to Tree (#9318)

* Add ItemClick event to Tree
* Add collapse provider and style generator to Tree
tags/8.1.0.alpha8
Teemu Suo-Anttila 7 years ago
parent
commit
04e7259fb4

+ 116
- 0
server/src/main/java/com/vaadin/ui/Tree.java View 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.

+ 39
- 0
uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java View 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;
}


+ 37
- 0
uitest/src/test/java/com/vaadin/tests/components/tree/TreeBasicFeaturesTest.java View 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());
}
}

Loading…
Cancel
Save