All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dominokit.domino.ui.tree.Tree Maven / Gradle / Ivy

/*
 * Copyright © 2019 Dominokit
 *
 * 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 org.dominokit.domino.ui.tree;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.tree.TreeStyles.*;
import static org.jboss.elemento.Elements.*;

import elemental2.dom.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.dominokit.domino.ui.collapsible.CollapseStrategy;
import org.dominokit.domino.ui.icons.Icon;
import org.dominokit.domino.ui.icons.Icons;
import org.dominokit.domino.ui.search.Search;
import org.dominokit.domino.ui.style.ColorScheme;
import org.dominokit.domino.ui.style.Styles;
import org.dominokit.domino.ui.style.Unit;
import org.dominokit.domino.ui.utils.BaseDominoElement;
import org.dominokit.domino.ui.utils.DominoElement;
import org.dominokit.domino.ui.utils.ParentTreeItem;
import org.jboss.elemento.IsElement;

/**
 * A component provides a tree representation of elements
 *
 * 

Customize the component can be done by overwriting classes provided by {@link TreeStyles} * *

For example: * *

 *     Tree hardwareTree =
 *         Tree.create("HARDWARE")
 *             .setToggleTarget(ToggleTarget.ICON)
 *             .addItemClickListener((treeItem) -> DomGlobal.console.info(treeItem.getValue()))
 *             .appendChild(
 *                 TreeItem.create("Computer", Icons.ALL.laptop_mdi())
 *                     .addClickListener((evt) -> Notification.create("Computer").show()))
 *             .appendChild(
 *                 TreeItem.create("Headset", Icons.ALL.headset_mdi())
 *                     .addClickListener((evt) -> Notification.create("Headset").show()))
 *             .appendChild(
 *                 TreeItem.create("Keyboard", Icons.ALL.keyboard_mdi())
 *                     .addClickListener((evt) -> Notification.create("Keyboard").show()))
 *             .appendChild(
 *                 TreeItem.create("Mouse", Icons.ALL.mouse_mdi())
 *                     .addClickListener((evt) -> Notification.create("Mouse").show()))
 *             .addSeparator()
 *             .appendChild(
 *                 TreeItem.create("Laptop", Icons.ALL.laptop_mdi())
 *                     .addClickListener((evt) -> Notification.create("Laptop").show()))
 *             .appendChild(
 *                 TreeItem.create("Smart phone", Icons.ALL.cellphone_mdi())
 *                     .addClickListener((evt) -> Notification.create("Smart phone").show()))
 *             .appendChild(
 *                 TreeItem.create("Tablet", Icons.ALL.tablet_mdi())
 *                     .addClickListener((evt) -> Notification.create("Tablet").show()))
 *             .appendChild(
 *                 TreeItem.create("Speaker", Icons.ALL.speaker_mdi())
 *                     .addClickListener((evt) -> Notification.create("Speaker").show()));
 * 
* * @param the type of the object * @see BaseDominoElement * @see ParentTreeItem */ public class Tree extends BaseDominoElement> implements ParentTreeItem>, IsElement { private final HTMLElement title = DominoElement.of(span()).css(TITLE).element(); private ToggleTarget toggleTarget = ToggleTarget.ANY; private TreeItemFilter> filter = (treeItem, searchToken) -> treeItem.getTitle().toLowerCase().contains(searchToken.toLowerCase()); private final HTMLLIElement header = DominoElement.of(li()).css(HEADER).css(MENU_HEADER).add(title).element(); private final HTMLUListElement root = DominoElement.of(ul()).add(header).css(LIST).element(); private final HTMLDivElement menu = DominoElement.of(div()).style("overflow-x: hidden").css(MENU).add(root).element(); private TreeItem activeTreeItem; private boolean autoCollapse = true; private final List> subItems = new ArrayList<>(); private boolean autoExpandFound; private ColorScheme colorScheme; private Search search; private Icon searchIcon; private Icon collapseAllIcon; private Icon expandAllIcon; private int levelPadding = 15; private T value; private final List> itemsClickListeners = new ArrayList<>(); private CollapseStrategy collapseStrategy; public Tree() { this(""); } public Tree(String treeTitle) { init(this); if (isNull(treeTitle) || treeTitle.trim().isEmpty()) { DominoElement.of(header).hide(); } title.textContent = treeTitle; } public Tree(String treeTitle, T value) { this(treeTitle); this.value = value; } public Tree(T value) { this(""); this.value = value; } /** * @param title the title of the tree * @return new instance */ public static Tree create(String title) { return new Tree<>(title); } /** @return new instance without title */ public static Tree create() { Tree tree = new Tree<>(); DominoElement.of(tree.header).hide(); return tree; } /** * @param title the title of the tree * @param value the default selected value * @param the type of the object * @return new instance */ public static Tree create(String title, T value) { return new Tree<>(title, value); } /** * @param value the default selected value * @param the type of the object * @return new instance */ public static Tree create(T value) { return new Tree<>(value); } /** * Adds a new tree item * * @param treeItem a new {@link TreeItem} * @return same instance */ public Tree appendChild(TreeItem treeItem) { root.appendChild(treeItem.element()); treeItem.setParent(this); treeItem.setLevel(1); treeItem.setLevelPadding(levelPadding); treeItem.setToggleTarget(this.toggleTarget); if (nonNull(collapseStrategy)) { treeItem.setCollapseStrategy(collapseStrategy); } this.subItems.add(treeItem); return this; } /** * Adds a new separator * * @return same instance */ public Tree addSeparator() { root.appendChild(DominoElement.of(li()).css("gap").css("separator").add(a()).element()); return this; } /** * Adds spaces between items * * @return same instance */ public Tree addGap() { root.appendChild(DominoElement.of(li()).css("gap").add(a()).element()); return this; } /** * Sets what is the target for toggling an item * * @param toggleTarget the {@link ToggleTarget} * @return same instance */ public Tree setToggleTarget(ToggleTarget toggleTarget) { if (nonNull(toggleTarget)) { subItems.forEach(item -> item.setToggleTarget(toggleTarget)); this.toggleTarget = toggleTarget; } return this; } /** * Sets level padding for item * * @param levelPadding string with padding for item * @return same instance */ public Tree setLevelPadding(int levelPadding) { this.levelPadding = levelPadding; subItems.forEach(item -> item.setLevelPadding(levelPadding)); return this; } /** * Sets the color scheme for the tree * * @param colorScheme the {@link ColorScheme} * @return same instance */ public Tree setColorScheme(ColorScheme colorScheme) { if (nonNull(this.colorScheme)) { removeCss(colorScheme.color().getBackground()); DominoElement.of(header).removeCss(this.colorScheme.darker_3().getBackground()); } this.colorScheme = colorScheme; addCss(colorScheme.color().getBackground()); DominoElement.of(header).addCss(this.colorScheme.darker_3().getBackground()); return this; } /** {@inheritDoc} */ @Override public TreeItem getActiveItem() { return activeTreeItem; } /** {@inheritDoc} */ @Override public void setActiveItem(TreeItem activeItem) { setActiveItem(activeItem, false); } /** {@inheritDoc} */ @Override public void setActiveItem(TreeItem activeItem, boolean silent) { if (nonNull(this.activeTreeItem) && !this.activeTreeItem.equals(activeItem)) { this.activeTreeItem.deactivate(); } this.activeTreeItem = activeItem; this.activeTreeItem.activate(); if (!silent) { onTreeItemClicked(activeItem); } } /** @return the header element */ public DominoElement getHeader() { return DominoElement.of(header); } /** @return the root element */ public DominoElement getRoot() { return DominoElement.of(root); } /** @return the title element */ public DominoElement getTitle() { return DominoElement.of(title); } /** * Sets the height of the tree to be automatic based on the content * * @return same instance */ public Tree autoHeight() { root.style.height = CSSProperties.HeightUnionType.of("calc(100vh - 83px)"); element().style.height = CSSProperties.HeightUnionType.of("calc(100vh - 70px)"); return this; } /** * Sets the height of the tree to be automatic based on the content with an offset * * @param offset the offset value * @return same instance */ public Tree autoHeight(int offset) { root.style.height = CSSProperties.HeightUnionType.of("calc(100vh - " + offset + 13 + "px)"); element().style.height = CSSProperties.HeightUnionType.of("calc(100vh - " + offset + "px)"); return this; } /** * Enables the search * * @return same instance */ public Tree enableSearch() { search = Search.create(true) .styler(style -> style.setHeight(Unit.px.of(40))) .onSearch(Tree.this::filter) .onClose(this::clearFilter); searchIcon = Icons.ALL .search() .setMarginBottom("0px") .setMarginTop("0px") .addCss(Styles.pull_right) .setCssProperty("cursor", "pointer"); this.header.appendChild(search.element()); this.header.appendChild(searchIcon.element()); searchIcon.element().addEventListener("click", evt -> search.open()); return this; } /** * Adds the ability to expand/collapse all items * * @return same instance */ public Tree enableFolding() { collapseAllIcon = Icons.ALL .fullscreen_exit() .setMarginBottom("0px") .setMarginTop("0px") .addCss(Styles.pull_right) .setCssProperty("cursor", "pointer"); collapseAllIcon.element().addEventListener("click", evt -> collapseAll()); expandAllIcon = Icons.ALL .fullscreen() .setMarginBottom("0px") .setMarginTop("0px") .addCss(Styles.pull_right) .setCssProperty("cursor", "pointer"); expandAllIcon.element().addEventListener("click", evt -> expandAll()); header.appendChild(expandAllIcon.element()); header.appendChild(collapseAllIcon.element()); return this; } /** Expand all items */ public void expandAll() { getSubItems().forEach(TreeItem::expandAll); } /** Collapse all items */ public void collapseAll() { getSubItems().forEach(TreeItem::collapseAll); } /** Deactivate all items */ public void deactivateAll() { getSubItems().forEach(TreeItem::deactivate); } /** * Expand the items found by the search automatically * * @return same instance */ public Tree autoExpandFound() { this.autoExpandFound = true; return this; } /** {@inheritDoc} */ @Override public boolean isAutoExpandFound() { return autoExpandFound; } /** * Sets if the items found by the search should be expanded automatically * * @param autoExpandFound true to expand automatically, false otherwise */ public void setAutoExpandFound(boolean autoExpandFound) { this.autoExpandFound = autoExpandFound; } /** Clears all the filters */ public void clearFilter() { subItems.forEach(TreeItem::clearFilter); } /** * Filter based on the search query * * @param searchToken the query */ public void filter(String searchToken) { subItems.forEach(treeItem -> treeItem.filter(searchToken)); } /** {@inheritDoc} */ @Override public Tree getTreeRoot() { return this; } /** * Sets if item should be collapsed automatically when it is deactivated * * @param autoCollapse true to collapse automatically, false otherwise * @return same instance */ public Tree setAutoCollapse(boolean autoCollapse) { this.autoCollapse = autoCollapse; return this; } /** * Sets the title of the tree * * @param title the title text * @return same instance */ public Tree setTitle(String title) { getTitle().setTextContent(title); if (getHeader().isCollapsed()) { getHeader().show(); } return this; } /** @return true if deactivated items should be collapsed automatically */ public boolean isAutoCollapse() { return autoCollapse; } /** {@inheritDoc} */ @Override public List> getSubItems() { return new ArrayList<>(subItems); } /** {@inheritDoc} */ @Override public Tree expand(boolean expandParent) { return this; } /** {@inheritDoc} */ @Override public Tree expand() { return this; } /** {@inheritDoc} */ @Override public Optional> getParent() { return Optional.empty(); } /** {@inheritDoc} */ @Override public void activate() {} /** {@inheritDoc} */ @Override public void activate(boolean activateParent) {} /** @return the search element */ public Search getSearch() { return search; } /** @return the search icon */ public Icon getSearchIcon() { return searchIcon; } /** @return the collapse all icon */ public Icon getCollapseAllIcon() { return collapseAllIcon; } /** @return the expand all icon */ public Icon getExpandAllIcon() { return expandAllIcon; } /** @return the current value */ public T getValue() { return value; } /** * Sets the value * * @param value the new value */ public void setValue(T value) { this.value = value; } /** * Adds a click listener to be called when item is clicked * * @param itemClickListener a {@link ItemClickListener} * @return same instance */ public Tree addItemClickListener(ItemClickListener itemClickListener) { this.itemsClickListeners.add(itemClickListener); return this; } /** * Removes a click listener * * @param itemClickListener a {@link ItemClickListener} to be removed * @return same instance */ public Tree removeItemClickListener(ItemClickListener itemClickListener) { this.itemsClickListeners.remove(itemClickListener); return this; } void onTreeItemClicked(TreeItem treeItem) { this.itemsClickListeners.forEach( itemClickListener -> itemClickListener.onTreeItemClicked(treeItem)); } /** @return the list of the items in the current active path */ public List> getActivePath() { List> activeItems = new ArrayList<>(); TreeItem activeItem = getActiveItem(); while (nonNull(activeItem)) { activeItems.add(activeItem); activeItem = activeItem.getActiveItem(); } return activeItems; } /** @return the list of values in the current active path */ public List getActivePathValues() { List activeValues = new ArrayList<>(); TreeItem activeItem = getActiveItem(); while (nonNull(activeItem)) { activeValues.add(activeItem.getValue()); activeItem = activeItem.getActiveItem(); } return activeValues; } /** {@inheritDoc} */ @Override public void removeItem(TreeItem item) { subItems.remove(item); item.remove(); } /** * Sets the filter that will be used when searching items, the default filter searches using the * title of the items * * @param filter a {@link TreeItemFilter} * @return same instance */ public Tree setFilter(TreeItemFilter> filter) { this.filter = filter; return this; } /** {@inheritDoc} */ @Override public TreeItemFilter> getFilter() { return this.filter; } public Tree setCollapseStrategy(CollapseStrategy collapseStrategy) { getSubItems().forEach(tTreeItem -> setCollapseStrategy(collapseStrategy)); this.collapseStrategy = collapseStrategy; return this; } public CollapseStrategy getCollapseStrategy() { return collapseStrategy; } /** {@inheritDoc} */ @Override public HTMLDivElement element() { return menu; } /** * A listener to be called when clicking on item * * @param the type of the object */ public interface ItemClickListener { void onTreeItemClicked(TreeItem treeItem); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy