123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194 |
- /*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.vaadin.ui;
-
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Optional;
- import java.util.Set;
- import java.util.UUID;
-
- import org.jsoup.nodes.Attributes;
- import org.jsoup.nodes.Element;
- import org.jsoup.select.Elements;
-
- import com.vaadin.data.Binder;
- import com.vaadin.data.HasHierarchicalDataProvider;
- import com.vaadin.data.SelectionModel;
- import com.vaadin.data.TreeData;
- import com.vaadin.data.provider.DataGenerator;
- import com.vaadin.data.provider.DataProvider;
- import com.vaadin.data.provider.HierarchicalDataProvider;
- import com.vaadin.data.provider.HierarchicalQuery;
- import com.vaadin.data.provider.TreeDataProvider;
- import com.vaadin.event.CollapseEvent;
- import com.vaadin.event.CollapseEvent.CollapseListener;
- import com.vaadin.event.ConnectorEvent;
- import com.vaadin.event.ContextClickEvent;
- 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.ErrorMessage;
- import com.vaadin.server.Resource;
- import com.vaadin.shared.EventId;
- import com.vaadin.shared.MouseEventDetails;
- import com.vaadin.shared.Registration;
- import com.vaadin.shared.ui.ContentMode;
- import com.vaadin.shared.ui.grid.HeightMode;
- import com.vaadin.shared.ui.grid.ScrollDestination;
- import com.vaadin.shared.ui.tree.TreeMultiSelectionModelState;
- import com.vaadin.shared.ui.tree.TreeRendererState;
- import com.vaadin.ui.Grid.SelectionMode;
- import com.vaadin.ui.components.grid.DescriptionGenerator;
- import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
- import com.vaadin.ui.components.grid.NoSelectionModel;
- import com.vaadin.ui.components.grid.SingleSelectionModelImpl;
- import com.vaadin.ui.declarative.DesignAttributeHandler;
- import com.vaadin.ui.declarative.DesignContext;
- import com.vaadin.ui.renderers.AbstractRenderer;
- import com.vaadin.util.ReflectTools;
-
- import elemental.json.JsonObject;
-
- /**
- * Tree component. A Tree can be used to select an item from a hierarchical set
- * of items.
- *
- * @author Vaadin Ltd
- * @since 8.1
- *
- * @param <T>
- * the data type
- */
- public class Tree<T> extends Composite
- implements HasHierarchicalDataProvider<T> {
-
- @Deprecated
- private static final Method ITEM_CLICK_METHOD = ReflectTools
- .findMethod(ItemClickListener.class, "itemClick", ItemClick.class);
- private Registration contextClickRegistration = null;
-
- /**
- * 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;
- private final MouseEventDetails mouseEventDetails;
-
- /**
- * Constructs a new item click.
- *
- * @param source
- * the tree component
- * @param item
- * the clicked item
- * @param mouseEventDetails
- * information about the original mouse event (mouse button
- * clicked, coordinates if available etc.)
- */
- protected ItemClick(Tree<T> source, T item,
- MouseEventDetails mouseEventDetails) {
- super(source);
- this.item = item;
- this.mouseEventDetails = mouseEventDetails;
- }
-
- /**
- * 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();
- }
-
- /**
- * Returns the mouse event details.
- *
- * @return the mouse event details
- */
- public MouseEventDetails getMouseEventDetails() {
- return mouseEventDetails;
- }
- }
-
- /**
- * String renderer that handles icon resources and stores their identifiers
- * into data objects.
- *
- * @since 8.1
- */
- public final class TreeRenderer extends AbstractRenderer<T, String>
- implements DataGenerator<T> {
-
- /**
- * Constructs a new TreeRenderer.
- */
- protected TreeRenderer() {
- super(String.class);
- }
-
- private Map<T, String> resourceKeyMap = new HashMap<>();
- private int counter = 0;
-
- @Override
- public void generateData(T item, JsonObject jsonObject) {
- Resource resource = iconProvider.apply(item);
- if (resource == null) {
- destroyData(item);
- return;
- }
-
- if (!resourceKeyMap.containsKey(item)) {
- resourceKeyMap.put(item, "icon" + (counter++));
- }
- setResource(resourceKeyMap.get(item), resource);
- jsonObject.put("itemIcon", resourceKeyMap.get(item));
- }
-
- @Override
- public void destroyData(T item) {
- if (resourceKeyMap.containsKey(item)) {
- setResource(resourceKeyMap.get(item), null);
- resourceKeyMap.remove(item);
- }
- }
-
- @Override
- public void destroyAllData() {
- Set<T> keys = new HashSet<>(resourceKeyMap.keySet());
- for (T key : keys) {
- destroyData(key);
- }
- }
-
- @Override
- protected TreeRendererState getState() {
- return (TreeRendererState) super.getState();
- }
-
- @Override
- protected TreeRendererState getState(boolean markAsDirty) {
- return (TreeRendererState) super.getState(markAsDirty);
- }
- }
-
- /**
- * Custom MultiSelectionModel for Tree. TreeMultiSelectionModel does not
- * show selection column.
- *
- * @param <T>
- * the tree item type
- *
- * @since 8.1
- */
- public static final class TreeMultiSelectionModel<T>
- extends MultiSelectionModelImpl<T> {
-
- @Override
- protected TreeMultiSelectionModelState getState() {
- return (TreeMultiSelectionModelState) super.getState();
- }
-
- @Override
- protected TreeMultiSelectionModelState getState(boolean markAsDirty) {
- return (TreeMultiSelectionModelState) super.getState(markAsDirty);
- }
- }
-
- private TreeGrid<T> treeGrid = new TreeGrid<>();
- private ItemCaptionGenerator<T> captionGenerator = String::valueOf;
- private IconGenerator<T> iconProvider = t -> null;
- private final TreeRenderer renderer;
- private boolean autoRecalculateWidth = true;
-
- /**
- * Constructs a new Tree Component.
- */
- public Tree() {
- setCompositionRoot(treeGrid);
- renderer = new TreeRenderer();
- treeGrid.getDataCommunicator().addDataGenerator(renderer);
- treeGrid.addColumn(i -> captionGenerator.apply(i), renderer)
- .setId("column");
- treeGrid.setHierarchyColumn("column");
- while (treeGrid.getHeaderRowCount() > 0) {
- treeGrid.removeHeaderRow(0);
- }
- treeGrid.setPrimaryStyleName("v-tree8");
- treeGrid.setRowHeight(28);
-
- setWidth("100%");
- treeGrid.setHeightUndefined();
- treeGrid.setHeightMode(HeightMode.UNDEFINED);
-
- treeGrid.addExpandListener(e -> {
- fireExpandEvent(e.getExpandedItem(), e.isUserOriginated());
- if (autoRecalculateWidth) {
- treeGrid.recalculateColumnWidths();
- }
- });
- treeGrid.addCollapseListener(e -> {
- fireCollapseEvent(e.getCollapsedItem(), e.isUserOriginated());
- if (autoRecalculateWidth) {
- treeGrid.recalculateColumnWidths();
- }
- });
- treeGrid.addItemClickListener(e -> fireEvent(
- new ItemClick<>(this, e.getItem(), e.getMouseEventDetails())));
- }
-
- /**
- * Constructs a new Tree Component with given caption.
- *
- * @param caption
- * the caption for component
- */
- public Tree(String caption) {
- this();
-
- setCaption(caption);
- }
-
- /**
- * Constructs a new Tree Component with given caption and {@code TreeData}.
- *
- * @param caption
- * the caption for component
- * @param treeData
- * the tree data for component
- */
- public Tree(String caption, TreeData<T> treeData) {
- this(caption, new TreeDataProvider<>(treeData));
- }
-
- /**
- * Constructs a new Tree Component with given caption and
- * {@code HierarchicalDataProvider}.
- *
- * @param caption
- * the caption for component
- * @param dataProvider
- * the hierarchical data provider for component
- */
- public Tree(String caption, HierarchicalDataProvider<T, ?> dataProvider) {
- this(caption);
-
- treeGrid.setDataProvider(dataProvider);
- }
-
- /**
- * Constructs a new Tree Component with given
- * {@code HierarchicalDataProvider}.
- *
- * @param dataProvider
- * the hierarchical data provider for component
- */
- public Tree(HierarchicalDataProvider<T, ?> dataProvider) {
- this(null, dataProvider);
- }
-
- @Override
- public HierarchicalDataProvider<T, ?> getDataProvider() {
- return treeGrid.getDataProvider();
- }
-
- @Override
- public void setDataProvider(DataProvider<T, ?> dataProvider) {
- treeGrid.setDataProvider(dataProvider);
- }
-
- /**
- * Adds an ExpandListener to this Tree.
- *
- * @see ExpandEvent
- *
- * @param listener
- * the listener to add
- * @return a registration for the listener
- */
- public Registration addExpandListener(ExpandListener<T> listener) {
- return addListener(ExpandEvent.class, listener,
- ExpandListener.EXPAND_METHOD);
- }
-
- /**
- * Adds a CollapseListener to this Tree.
- *
- * @see CollapseEvent
- *
- * @param listener
- * the listener to add
- * @return a registration for the listener
- */
- public Registration addCollapseListener(CollapseListener<T> listener) {
- return addListener(CollapseEvent.class, listener,
- CollapseListener.COLLAPSE_METHOD);
- }
-
- /**
- * Fires an expand event with given item.
- *
- * @param item
- * the expanded item
- * @param userOriginated
- * whether the expand was triggered by a user interaction or the
- * server
- */
- protected void fireExpandEvent(T item, boolean userOriginated) {
- fireEvent(new ExpandEvent<>(this, item, userOriginated));
- }
-
- /**
- * Fires a collapse event with given item.
- *
- * @param item
- * the collapsed item
- * @param userOriginated
- * whether the collapse was triggered by a user interaction or
- * the server
- */
- protected void fireCollapseEvent(T item, boolean userOriginated) {
- fireEvent(new CollapseEvent<>(this, item, userOriginated));
- }
-
- /**
- * Expands the given items.
- * <p>
- * If an item is currently expanded, does nothing. If an item does not have
- * any children, does nothing.
- *
- * @param items
- * the items to expand
- */
- public void expand(T... items) {
- treeGrid.expand(items);
- }
-
- /**
- * Expands the given items.
- * <p>
- * If an item is currently expanded, does nothing. If an item does not have
- * any children, does nothing.
- *
- * @param items
- * the items to expand
- */
- public void expand(Collection<T> items) {
- treeGrid.expand(items);
- }
-
- /**
- * Collapse the given items.
- * <p>
- * For items that are already collapsed, does nothing.
- *
- * @param items
- * the collection of items to collapse
- */
- public void collapse(T... items) {
- treeGrid.collapse(items);
- }
-
- /**
- * Collapse the given items.
- * <p>
- * For items that are already collapsed, does nothing.
- *
- * @param items
- * the collection of items to collapse
- */
- public void collapse(Collection<T> items) {
- treeGrid.collapse(items);
- }
-
- /**
- * Returns whether a given item is expanded or collapsed.
- *
- * @param item
- * the item to check
- * @return true if the item is expanded, false if collapsed
- */
- public boolean isExpanded(T item) {
- return treeGrid.isExpanded(item);
- }
-
- /**
- * This method is a shorthand that delegates to the currently set selection
- * model.
- *
- * @see #getSelectionModel()
- *
- * @return set of selected items
- */
- public Set<T> getSelectedItems() {
- return treeGrid.getSelectedItems();
- }
-
- /**
- * This method is a shorthand that delegates to the currently set selection
- * model.
- *
- * @param item
- * item to select
- *
- * @see SelectionModel#select(Object)
- * @see #getSelectionModel()
- */
- public void select(T item) {
- treeGrid.select(item);
- }
-
- /**
- * This method is a shorthand that delegates to the currently set selection
- * model.
- *
- * @param item
- * item to deselect
- *
- * @see SelectionModel#deselect(Object)
- * @see #getSelectionModel()
- */
- public void deselect(T item) {
- treeGrid.deselect(item);
- }
-
- /**
- * Adds a selection listener to the current selection model.
- * <p>
- * <strong>NOTE:</strong> If selection mode is switched with
- * {@link #setSelectionMode(SelectionMode)}, then this listener is not
- * triggered anymore when selection changes!
- *
- * @param listener
- * the listener to add
- * @return a registration handle to remove the listener
- *
- * @throws UnsupportedOperationException
- * if selection has been disabled with
- * {@link SelectionMode#NONE}
- */
- public Registration addSelectionListener(SelectionListener<T> listener) {
- return treeGrid.addSelectionListener(listener);
- }
-
- /**
- * Use this tree as a single select in {@link Binder}. Throws
- * {@link IllegalStateException} if the tree is not using
- * {@link SelectionMode#SINGLE}.
- *
- * @return the single select wrapper that can be used in binder
- */
- public SingleSelect<T> asSingleSelect() {
- return treeGrid.asSingleSelect();
- }
-
- /**
- * Returns the selection model for this Tree.
- *
- * @return the selection model, not <code>null</code>
- */
- public SelectionModel<T> getSelectionModel() {
- return treeGrid.getSelectionModel();
- }
-
- /**
- * Sets the item caption generator that is used to produce the strings shown
- * as the text for each item. By default, {@link String#valueOf(Object)} is
- * used.
- *
- * @param captionGenerator
- * the item caption provider to use, not <code>null</code>
- */
- public void setItemCaptionGenerator(
- ItemCaptionGenerator<T> captionGenerator) {
- Objects.requireNonNull(captionGenerator,
- "Caption generator must not be null");
- this.captionGenerator = captionGenerator;
- treeGrid.getDataCommunicator().reset();
- }
-
- /**
- * Sets the item icon generator that is used to produce custom icons for
- * items. The generator can return <code>null</code> for items with no icon.
- *
- * @see IconGenerator
- *
- * @param iconGenerator
- * the item icon generator to set, not <code>null</code>
- * @throws NullPointerException
- * if {@code itemIconGenerator} is {@code null}
- */
- public void setItemIconGenerator(IconGenerator<T> iconGenerator) {
- Objects.requireNonNull(iconGenerator,
- "Item icon generator must not be null");
- this.iconProvider = iconGenerator;
- 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(
- ItemCollapseAllowedProvider<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);
- }
-
- /**
- * Sets the description generator that is used for generating tooltip
- * descriptions for items.
- *
- * @since 8.2
- * @param descriptionGenerator
- * the item description generator to set, or <code>null</code> to
- * remove a previously set generator
- */
- public void setItemDescriptionGenerator(
- DescriptionGenerator<T> descriptionGenerator) {
- treeGrid.setDescriptionGenerator(descriptionGenerator);
- }
-
- /**
- * Gets the item caption generator.
- *
- * @return the item caption generator
- */
- public ItemCaptionGenerator<T> getItemCaptionGenerator() {
- return captionGenerator;
- }
-
- /**
- * Gets the item icon generator.
- *
- * @see IconGenerator
- *
- * @return the item icon generator
- */
- public IconGenerator<T> getItemIconGenerator() {
- return iconProvider;
- }
-
- /**
- * Gets the item collapse allowed provider.
- *
- * @return the item collapse allowed provider
- */
- public ItemCollapseAllowedProvider<T> getItemCollapseAllowedProvider() {
- return treeGrid.getItemCollapseAllowedProvider();
- }
-
- /**
- * Gets the style generator.
- *
- * @see StyleGenerator
- *
- * @return the item style generator
- */
- public StyleGenerator<T> getStyleGenerator() {
- return treeGrid.getStyleGenerator();
- }
-
- /**
- * Gets the item description generator.
- *
- * @since 8.2
- * @return the item description generator
- */
- public DescriptionGenerator<T> getItemDescriptionGenerator() {
- return treeGrid.getDescriptionGenerator();
- }
-
- /**
- * 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
- * @see #addContextClickListener
- */
- public Registration addItemClickListener(ItemClickListener<T> listener) {
- return addListener(ItemClick.class, listener, ITEM_CLICK_METHOD);
- }
-
- /**
- * Sets the tree's selection mode.
- * <p>
- * The built-in selection modes are:
- * <ul>
- * <li>{@link SelectionMode#SINGLE} <b>the default model</b></li>
- * <li>{@link SelectionMode#MULTI}</li>
- * <li>{@link SelectionMode#NONE} preventing selection</li>
- * </ul>
- *
- * @param selectionMode
- * the selection mode to switch to, not {@code null}
- * @return the used selection model
- *
- * @see SelectionMode
- */
- public SelectionModel<T> setSelectionMode(SelectionMode selectionMode) {
- Objects.requireNonNull(selectionMode,
- "Can not set selection mode to null");
- switch (selectionMode) {
- case MULTI:
- TreeMultiSelectionModel<T> model = new TreeMultiSelectionModel<>();
- treeGrid.setSelectionModel(model);
- return model;
- default:
- return treeGrid.setSelectionMode(selectionMode);
- }
- }
-
- private SelectionMode getSelectionMode() {
- SelectionModel<T> selectionModel = getSelectionModel();
- SelectionMode mode = null;
- if (selectionModel.getClass().equals(SingleSelectionModelImpl.class)) {
- mode = SelectionMode.SINGLE;
- } else if (selectionModel.getClass()
- .equals(TreeMultiSelectionModel.class)) {
- mode = SelectionMode.MULTI;
- } else if (selectionModel.getClass().equals(NoSelectionModel.class)) {
- mode = SelectionMode.NONE;
- }
- return mode;
- }
-
- @Override
- public void setCaption(String caption) {
- treeGrid.setCaption(caption);
- }
-
- @Override
- public String getCaption() {
- return treeGrid.getCaption();
- }
-
- @Override
- public void setIcon(Resource icon) {
- treeGrid.setIcon(icon);
- }
-
- @Override
- public Resource getIcon() {
- return treeGrid.getIcon();
- }
-
- @Override
- public String getStyleName() {
- return treeGrid.getStyleName();
- }
-
- @Override
- public void setStyleName(String style) {
- treeGrid.setStyleName(style);
- }
-
- @Override
- public void setStyleName(String style, boolean add) {
- treeGrid.setStyleName(style, add);
- }
-
- @Override
- public void addStyleName(String style) {
- treeGrid.addStyleName(style);
- }
-
- @Override
- public void removeStyleName(String style) {
- treeGrid.removeStyleName(style);
- }
-
- @Override
- public String getPrimaryStyleName() {
- return treeGrid.getPrimaryStyleName();
- }
-
- @Override
- public void setPrimaryStyleName(String style) {
- treeGrid.setPrimaryStyleName(style);
- }
-
- @Override
- public void setId(String id) {
- treeGrid.setId(id);
- }
-
- @Override
- public String getId() {
- return treeGrid.getId();
- }
-
- @Override
- public void setCaptionAsHtml(boolean captionAsHtml) {
- treeGrid.setCaptionAsHtml(captionAsHtml);
- }
-
- @Override
- public boolean isCaptionAsHtml() {
- return treeGrid.isCaptionAsHtml();
- }
-
- @Override
- public void setDescription(String description) {
- treeGrid.setDescription(description);
- }
-
- @Override
- public void setDescription(String description, ContentMode mode) {
- treeGrid.setDescription(description, mode);
- }
-
- @Override
- public ErrorMessage getErrorMessage() {
- return treeGrid.getErrorMessage();
- }
-
- @Override
- public ErrorMessage getComponentError() {
- return treeGrid.getComponentError();
- }
-
- @Override
- public void setComponentError(ErrorMessage componentError) {
- treeGrid.setComponentError(componentError);
- }
-
- /**
- * Sets the height of a row. If -1 (default), the row height is calculated
- * based on the theme for an empty row before the Tree is displayed.
- *
- * @param rowHeight
- * The height of a row in pixels or -1 for automatic calculation
- */
- public void setRowHeight(double rowHeight) {
- treeGrid.setRowHeight(rowHeight);
- }
-
- /**
- * Gets the currently set content mode of the item captions of this Tree.
- *
- * @since 8.1.3
- * @see ContentMode
- * @return the content mode of the item captions of this Tree
- */
- public ContentMode getContentMode() {
- return renderer.getState(false).mode;
- }
-
- /**
- * Sets the content mode of the item caption.
- *
- * @see ContentMode
- * @param contentMode
- * the content mode
- */
- public void setContentMode(ContentMode contentMode) {
- renderer.getState().mode = contentMode;
- }
-
- /**
- * Returns the current state of automatic width recalculation.
- *
- * @return {@code true} if enabled; {@code false} if disabled
- *
- * @since 8.1.1
- */
- public boolean isAutoRecalculateWidth() {
- return autoRecalculateWidth;
- }
-
- /**
- * Sets the automatic width recalculation on or off. This feature is on by
- * default.
- *
- * @param autoRecalculateWidth
- * {@code true} to enable recalculation; {@code false} to turn it
- * off
- *
- * @since 8.1.1
- */
- public void setAutoRecalculateWidth(boolean autoRecalculateWidth) {
- this.autoRecalculateWidth = autoRecalculateWidth;
-
- treeGrid.getColumns().get(0)
- .setMinimumWidthFromContent(autoRecalculateWidth);
- treeGrid.recalculateColumnWidths();
- }
-
- /**
- * Adds a context click listener that gets notified when a context click
- * happens.
- *
- * @param listener
- * the context click listener to add, not null actual event
- * provided to the listener is {@link TreeContextClickEvent}
- * @return a registration object for removing the listener
- *
- * @since 8.1
- * @see #addItemClickListener
- * @see Registration
- */
- @Override
- public Registration addContextClickListener(
- ContextClickEvent.ContextClickListener listener) {
- Registration registration = addListener(EventId.CONTEXT_CLICK,
- ContextClickEvent.class, listener,
- ContextClickEvent.CONTEXT_CLICK_METHOD);
- setupContextClickListener();
- return () -> {
- registration.remove();
- setupContextClickListener();
- };
- }
-
- @Override
- @Deprecated
- public void removeContextClickListener(
- ContextClickEvent.ContextClickListener listener) {
- super.removeContextClickListener(listener);
- setupContextClickListener();
- }
-
- @Override
- public void writeDesign(Element design, DesignContext designContext) {
- super.writeDesign(design, designContext);
- Attributes attrs = design.attributes();
-
- SelectionMode mode = getSelectionMode();
- if (mode != null) {
- DesignAttributeHandler.writeAttribute("selection-mode", attrs, mode,
- SelectionMode.SINGLE, SelectionMode.class, designContext);
- }
- DesignAttributeHandler.writeAttribute("content-mode", attrs,
- getContentMode(), ContentMode.TEXT, ContentMode.class,
- designContext);
-
- if (designContext.shouldWriteData(this)) {
- writeItems(design, designContext);
- }
- }
-
- private void writeItems(Element design, DesignContext designContext) {
- getDataProvider().fetch(new HierarchicalQuery<>(null, null))
- .forEach(item -> writeItem(design, designContext, item, null));
- }
-
- private void writeItem(Element design, DesignContext designContext, T item,
- T parent) {
-
- Element itemElement = design.appendElement("node");
- itemElement.attr("item", serializeDeclarativeRepresentation(item));
-
- if (parent != null) {
- itemElement.attr("parent",
- serializeDeclarativeRepresentation(parent));
- }
-
- if (getSelectionModel().isSelected(item)) {
- itemElement.attr("selected", "");
- }
-
- Resource icon = getItemIconGenerator().apply(item);
- DesignAttributeHandler.writeAttribute("icon", itemElement.attributes(),
- icon, null, Resource.class, designContext);
-
- String text = getItemCaptionGenerator().apply(item);
- itemElement.html(
- Optional.ofNullable(text).map(Object::toString).orElse(""));
-
- getDataProvider().fetch(new HierarchicalQuery<>(null, item)).forEach(
- childItem -> writeItem(design, designContext, childItem, item));
- }
-
- @Override
- public void readDesign(Element design, DesignContext designContext) {
- super.readDesign(design, designContext);
- Attributes attrs = design.attributes();
- if (attrs.hasKey("selection-mode")) {
- setSelectionMode(DesignAttributeHandler.readAttribute(
- "selection-mode", attrs, SelectionMode.class));
- }
- if (attrs.hasKey("content-mode")) {
- setContentMode(DesignAttributeHandler.readAttribute("content-mode",
- attrs, ContentMode.class));
- }
- readItems(design.children());
- }
-
- private void readItems(Elements bodyItems) {
- if (bodyItems.isEmpty()) {
- return;
- }
-
- DeclarativeValueProvider<T> valueProvider = new DeclarativeValueProvider<>();
- setItemCaptionGenerator(item -> valueProvider.apply(item));
-
- DeclarativeIconGenerator<T> iconGenerator = new DeclarativeIconGenerator<>(
- item -> null);
- setItemIconGenerator(iconGenerator);
-
- getSelectionModel().deselectAll();
- List<T> selectedItems = new ArrayList<>();
- TreeData<T> data = new TreeData<T>();
-
- for (Element row : bodyItems) {
- T item = deserializeDeclarativeRepresentation(row.attr("item"));
- T parent = null;
- if (row.hasAttr("parent")) {
- parent = deserializeDeclarativeRepresentation(
- row.attr("parent"));
- }
- data.addItem(parent, item);
- if (row.hasAttr("selected")) {
- selectedItems.add(item);
- }
-
- valueProvider.addValue(item, row.html());
- iconGenerator.setIcon(item, DesignAttributeHandler
- .readAttribute("icon", row.attributes(), Resource.class));
- }
-
- setDataProvider(new TreeDataProvider<>(data));
- selectedItems.forEach(getSelectionModel()::select);
- }
-
- /**
- * Deserializes a string to a data item. Used when reading from the
- * declarative format of this Tree.
- * <p>
- * Default implementation is able to handle only {@link String} as an item
- * type. There will be a {@link ClassCastException} if {@code T } is not a
- * {@link String}.
- *
- * @since 8.1.3
- *
- * @see #serializeDeclarativeRepresentation(Object)
- *
- * @param item
- * string to deserialize
- * @throws ClassCastException
- * if type {@code T} is not a {@link String}
- * @return deserialized item
- */
- @SuppressWarnings("unchecked")
- protected T deserializeDeclarativeRepresentation(String item) {
- if (item == null) {
- return (T) new String(UUID.randomUUID().toString());
- }
- return (T) new String(item);
- }
-
- /**
- * Serializes an {@code item} to a string. Used when saving this Tree to its
- * declarative format.
- * <p>
- * Default implementation delegates a call to {@code item.toString()}.
- *
- * @since 8.1.3
- *
- * @see #deserializeDeclarativeRepresentation(String)
- *
- * @param item
- * a data item
- * @return string representation of the {@code item}.
- */
- protected String serializeDeclarativeRepresentation(T item) {
- return item.toString();
- }
-
- private void setupContextClickListener() {
- if (hasListeners(ContextClickEvent.class)) {
- if (contextClickRegistration == null) {
- contextClickRegistration = treeGrid
- .addContextClickListener(event -> {
- T item = null;
- if (event instanceof Grid.GridContextClickEvent) {
- item = ((Grid.GridContextClickEvent<T>) event)
- .getItem();
- }
- fireEvent(new TreeContextClickEvent<>(this,
- event.getMouseEventDetails(), item));
- });
- }
- } else if (contextClickRegistration != null) {
- contextClickRegistration.remove();
- contextClickRegistration = null;
- }
- }
-
- /**
- * ContextClickEvent for the Tree Component.
- * <p>
- * Usage:
- *
- * <pre>
- * tree.addContextClickListener(event -> Notification.show(
- * ((TreeContextClickEvent<Person>) event).getItem() + " Clicked"));
- * </pre>
- *
- * @param <T>
- * the tree bean type
- * @since 8.1
- */
- public static class TreeContextClickEvent<T> extends ContextClickEvent {
-
- private final T item;
-
- /**
- * Creates a new context click event.
- *
- * @param source
- * the tree where the context click occurred
- * @param mouseEventDetails
- * details about mouse position
- * @param item
- * the item which was clicked or {@code null} if the click
- * happened outside any item
- */
- public TreeContextClickEvent(Tree<T> source,
- MouseEventDetails mouseEventDetails, T item) {
- super(source, mouseEventDetails);
- this.item = item;
- }
-
- /**
- * Returns the item of context clicked row.
- *
- * @return clicked item; {@code null} the click happened outside any
- * item
- */
- public T getItem() {
- return item;
- }
-
- @Override
- public Tree<T> getComponent() {
- return (Tree<T>) super.getComponent();
- }
- }
-
- /**
- * Scrolls to a certain item, using {@link ScrollDestination#ANY}.
- * <p>
- * If the item has an open details row, its size will also be taken into
- * account.
- *
- * @param row
- * zero based index of the item to scroll to in the current view.
- * @throws IllegalArgumentException
- * if the provided row is outside the item range
- */
- public void scrollTo(int row) throws IllegalArgumentException {
- treeGrid.scrollTo(row, ScrollDestination.ANY);
- }
-
- /**
- * Scrolls to a certain item, using user-specified scroll destination.
- * <p>
- * If the item has an open details row, its size will also be taken into
- * account.
- *
- * @param row
- * zero based index of the item to scroll to in the current view.
- * @param destination
- * value specifying desired position of scrolled-to row, not
- * {@code null}
- * @throws IllegalArgumentException
- * if the provided row is outside the item range
- */
- public void scrollTo(int row, ScrollDestination destination) {
- treeGrid.scrollTo(row, destination);
- }
-
- /**
- * Scrolls to the beginning of the first data row.
- */
- public void scrollToStart() {
- treeGrid.scrollToStart();
- }
-
- /**
- * Scrolls to the end of the last data row.
- */
- public void scrollToEnd() {
- treeGrid.scrollToEnd();
- }
-
- }
|