|
|
@@ -0,0 +1,211 @@ |
|
|
|
--- |
|
|
|
title: Tree |
|
|
|
order: 26 |
|
|
|
layout: page |
|
|
|
--- |
|
|
|
|
|
|
|
[[components.tree]] |
|
|
|
= Tree |
|
|
|
|
|
|
|
ifdef::web[] |
|
|
|
[.sampler] |
|
|
|
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/grids-and-trees/tree"] |
|
|
|
endif::web[] |
|
|
|
|
|
|
|
IMPORTANT: The [classname]#Tree# component is currently being developed and only available in the Framework 8.1 prerelease versions, starting from 8.1.0.beta1. |
|
|
|
|
|
|
|
[[components.tree.overview]] |
|
|
|
== Overview |
|
|
|
|
|
|
|
The [classname]#Tree# component allows a natural way to represent data that has hierarchical relationships. |
|
|
|
The user can drill down in the hierarchy by expanding items by clicking on the expand arrow, and likewise collapse items. |
|
|
|
[classname]#Tree# is a selection component that allows selecting items. |
|
|
|
It also supports drag and drop, so you can drag items to and from a tree, and drop them in the hierarchy. |
|
|
|
|
|
|
|
A typical use of the [classname]#Tree# component is for displaying a hierarchical menu, as illustrated in <<figure.components.tree>>, or for displaying file systems or hierarchical datasets. |
|
|
|
|
|
|
|
[[figure.components.tree]] |
|
|
|
.A [classname]#Tree# component |
|
|
|
image::img/tree-basic.png[width=70%, scaledwidth=100%] |
|
|
|
|
|
|
|
[[components.tree.data]] |
|
|
|
== Binding to Data |
|
|
|
|
|
|
|
[classname]#Tree# is used by binding it to a hierarchical data provider. The data provider can be based on in-memory or back end data. For in-memory data, the [classname]#InMemoryHierarchicalDataProvider# can be used, and for loading data from a back end, you need to implement three methods from the [interfacename]#HierarchicalDataProvider# interface. Usage of both data providers is described in |
|
|
|
<<dummy/../../../framework/datamodel/datamodel-hierarchical.asciidoc#datamodel.hierarchical,"Hierarchical Data">>. |
|
|
|
|
|
|
|
|
|
|
|
The [classname]#HierarchyData# class can be used to build the hierarchical data structure, |
|
|
|
and it can then be passed on to [classname]#InMemoryHierarchicalDataProvider#. It is simply a hierarchical |
|
|
|
collection, that the data provider uses to populate the [classname]#Tree#. |
|
|
|
|
|
|
|
The [methodname]#setItems# method in [classname]#Tree# can be used to set the root level items. Internally |
|
|
|
an [classname]#InMemoryHierarchicalDataProvider# with [classname]#HierarchyData# is used. |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
// An initial planet tree |
|
|
|
Tree<String> tree = new Tree<>(); |
|
|
|
HierarchyData<String> hierarchyData = new HierarchyData<>(); |
|
|
|
|
|
|
|
// Couple of childless root items |
|
|
|
hierarchyData.addItem(null,"Mercury"); |
|
|
|
hierarchyData.addItem(null,"Venus"); |
|
|
|
|
|
|
|
// Items with hierarchy |
|
|
|
hierarchyData.addItem(null,"Earth"); |
|
|
|
hierarchyData.addItem("Earth","The Moon"); |
|
|
|
|
|
|
|
inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(hierarchyData); |
|
|
|
tree.setDataProvider(inMemoryDataProvider); |
|
|
|
tree.expand("Earth"); // Expand programmatically |
|
|
|
---- |
|
|
|
|
|
|
|
If at any time you want to modify |
|
|
|
the in-memory data in the tree, you may do it as follows: |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
// Add Mars with satellites |
|
|
|
hierarchyData.addItem(null, "Mars"); |
|
|
|
hierarchyData.addItem("Mars", "Phobos"); |
|
|
|
hierarchyData.addItem("Mars", "Deimos"); |
|
|
|
inMemoryDataProvider.refreshAll(); |
|
|
|
|
|
|
|
---- |
|
|
|
|
|
|
|
|
|
|
|
The result was shown in <<figure.components.tree>>. |
|
|
|
|
|
|
|
The caption and the icon of tree items is generated by the [classname]#ItemCaptionGenerator# and the |
|
|
|
[classname]#IconGenerator#, set with [methodname]#setItemCaptionGenerator()# and [methodname]#setItemIconGenerator()# respectively. |
|
|
|
|
|
|
|
[[components.tree.selection]] |
|
|
|
== Handling Selection and Clicks |
|
|
|
|
|
|
|
[classname]#Tree# supports single selection mode, you can use [methodname]#asSingleSelect()# to access the selection |
|
|
|
object, which supports selection listeners and data binding. For more details, see link:<<dummy/../../../framework/datamodel/datamodel-selection.asciidoc#datamodel.selection,"Selecting Items">>. |
|
|
|
The [classname]#Tree# also supports the shortcut method [methodname]#addSelectionListener()#. |
|
|
|
|
|
|
|
//// |
|
|
|
todo not implemented yet. |
|
|
|
[classname]#Tree# also emits [classname]##ItemClickEvent##s when items are clicked. |
|
|
|
This way you can handle item clicks also when selection is not enabled or you want special user interaction specifically on clicks. |
|
|
|
|
|
|
|
|
|
|
|
[source, Java] |
|
|
|
---- |
|
|
|
tree.addItemClickListener( |
|
|
|
new ItemClickEvent.ItemClickListener() { |
|
|
|
public void itemClick(ItemClickEvent event) { |
|
|
|
// Pick only left mouse clicks |
|
|
|
if (event.getButton() == ItemClickEvent.BUTTON_LEFT) |
|
|
|
Notification.show("Left click", |
|
|
|
Notification.Type.HUMANIZED_MESSAGE); |
|
|
|
} |
|
|
|
}); |
|
|
|
---- |
|
|
|
//// |
|
|
|
|
|
|
|
[[components.tree.expandcollapse]] |
|
|
|
== Expanding and Collapsing Nodes |
|
|
|
|
|
|
|
[classname]#Tree# nodes that have children can be expanded and collapsed by either user interaction or through the server-side API: |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
// Expands a child project. If the child project is not yet |
|
|
|
// in the visible hierarchy, nothing will be shown. |
|
|
|
tree.expand(childProject); |
|
|
|
// Expands the root project. If child project now becomes |
|
|
|
// visible it is also expanded into view. |
|
|
|
tree.expand(rootProject); |
|
|
|
// Collapses the child project. |
|
|
|
tree.collapse(childProject); |
|
|
|
---- |
|
|
|
|
|
|
|
To use the server-side API with a backend data provider the [methodname]#hashCode# and [methodname]#equals# methods for the node's type must be implemented so that when the desired node is retrieved from the backend it can be correctly matched with the object passed to either [methodname]#expand# or [methodname]#collapse#. |
|
|
|
|
|
|
|
The [classname]#Tree# component supports listening to the expansion and collapsing of items in its hierarchy. |
|
|
|
The expand and collapse listeners can be added as follows: |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
tree.addExpandListener(event -> log("Item expanded: " + event.getExpandedItem())); |
|
|
|
tree.addCollapseListener(event -> log("Item collapsed: " + event.getCollapsedItem())); |
|
|
|
---- |
|
|
|
|
|
|
|
The return types of the methods `getExpandedItem` and `getCollapsedItem` are the same as the type of the [classname]#Tree# the events originated from. |
|
|
|
Note that collapse listeners will not be triggered for any expanded subtrees of the collapsed item. |
|
|
|
|
|
|
|
//// |
|
|
|
todo not implemented yet |
|
|
|
[[components.tree.node.collapsing]] |
|
|
|
== Prevent Node Collapsing |
|
|
|
|
|
|
|
[classname]#Tree# supports setting a callback method that can allow or prevent the user from collapsing an expanded node. |
|
|
|
It can be set with [methodname]#setItemCollapseAllowedProvider# method, that takes a [interfacename]#SerializablePredicate#. |
|
|
|
For nodes that cannot be collapsed, the [literal]#++collapse-disabled++# class name is applied to the expansion element |
|
|
|
|
|
|
|
Avoid doing any heavy operations in the method, since it is called for each item when it is being sent to the client. |
|
|
|
|
|
|
|
Example using a predefined set of persons that can not be collapsed: |
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
Set<Person> alwaysExpanded; |
|
|
|
personTree.setItemCollapseAllowedProvider(person -> |
|
|
|
!alwaysExpanded.contains(person)); |
|
|
|
---- |
|
|
|
//// |
|
|
|
|
|
|
|
[[components.treegrid.keyboard]] |
|
|
|
== Keyboard Navigation and Focus Handling in TreeGrid |
|
|
|
|
|
|
|
The user can navigate through rows with kbd:[Up] and kbd:[Down], collapse rows with kbd:[Left], |
|
|
|
and expand them with kbd:[Right]. |
|
|
|
|
|
|
|
//// |
|
|
|
todo styling documentation |
|
|
|
[[components.tree.css]] |
|
|
|
== CSS Style Rules |
|
|
|
|
|
|
|
[source, css] |
|
|
|
---- |
|
|
|
.v-tree {} |
|
|
|
.v-tree-node {} /* A node (item) */ |
|
|
|
.v-tree-node-caption {} /* Caption of the node */ |
|
|
|
.v-tree-node-children {} /* Contains child nodes */ |
|
|
|
.v-tree-node-root {} /* If node is a root node */ |
|
|
|
.v-tree-node-leaf {} /* If node has no children */ |
|
|
|
---- |
|
|
|
|
|
|
|
[[components.tree.css.itemstyles]] |
|
|
|
=== Generating Item Styles |
|
|
|
|
|
|
|
You can style each tree item individually by generating a style name for them with a [interfacename]#Tree.ItemStyleGenerator#, which you assign to a tree with [methodname]#setItemStyleGenerator()#. |
|
|
|
The generator should return a style name for each item or `null`. |
|
|
|
|
|
|
|
[source, Java] |
|
|
|
---- |
|
|
|
// Show all leaf nodes as disabled |
|
|
|
tree.setItemStyleGenerator(new Tree.ItemStyleGenerator() { |
|
|
|
@Override |
|
|
|
public String getStyle(Tree source, Object itemId) { |
|
|
|
if (! tree.hasChildren(itemId)) |
|
|
|
return "disabled"; |
|
|
|
return null; |
|
|
|
} |
|
|
|
}); |
|
|
|
---- |
|
|
|
|
|
|
|
The style names are prefixed with `v-tree-node-caption-`. |
|
|
|
You could thereby define the item styling as follows: |
|
|
|
|
|
|
|
[source, CSS] |
|
|
|
---- |
|
|
|
.v-tree-node-caption-disabled { |
|
|
|
color: graytext; |
|
|
|
font-style: italic; |
|
|
|
} |
|
|
|
---- |
|
|
|
//// |