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

com.dlsc.gemsfx.treeview.TreeNodeCell Maven / Gradle / Ivy

There is a newer version: 2.67.0
Show newest version
package com.dlsc.gemsfx.treeview;

import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;

import java.util.Objects;

public class TreeNodeCell extends BorderPane {

    private static final boolean DEFAULT_EXPANDED = true;

    private static final String DEFAULT_STYLE_CLASS = "tree-node-cell";
    private static final PseudoClass EXPANDED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("expanded");
    private static final PseudoClass COLLAPSED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("collapsed");
    private InvalidationListener invalidationListener;
    private final Label innerLabel;
    private final StackPane arrowWrapper;

    public TreeNodeCell() {
        getStyleClass().setAll(DEFAULT_STYLE_CLASS);
        innerLabel = new Label();
        innerLabel.getStyleClass().add("tree-node-cell-label");
        innerLabel.graphicProperty().bind(graphicProperty());
        innerLabel.textProperty().bind(textProperty());
        innerLabel.setMaxWidth(Double.MAX_VALUE);

        Region arrow = new Region();
        arrow.getStyleClass().setAll("disclosure-arrow");

        arrowWrapper = new StackPane(arrow);
        arrowWrapper.getStyleClass().setAll("arrow-wrapper");
        arrowWrapper.managedProperty().bind(arrowWrapper.visibleProperty());
        arrowWrapper.visibleProperty().bind(Bindings.createBooleanBinding(() ->
                getTreeNode() != null && !getTreeNode().getChildren().isEmpty(), treeNodeProperty()));

        arrowWrapper.setOnMousePressed(event -> {
            if (getTreeNode() != null && !getTreeNode().getChildren().isEmpty()) {
                setExpanded(!isExpanded());
            }
            event.consume();
        });

        setCenter(innerLabel);
        setRight(arrowWrapper);

        itemProperty().addListener((ob, ov, nv) -> updateItem(nv));
        treeNodeProperty().addListener((ob, oldTreeNode, newTreeNode) -> {
            if (oldTreeNode != null && invalidationListener != null) {
                expandedProperty().unbindBidirectional(oldTreeNode.expandedProperty());
                oldTreeNode.getChildren().removeListener(invalidationListener);
            }
            if (newTreeNode != null) {
                expandedProperty().bindBidirectional(newTreeNode.expandedProperty());
                invalidationListener = it -> updateItem(getItem());
                newTreeNode.getChildren().addListener(invalidationListener);
            }
            updateItem(getItem());
        });

        expandedProperty().addListener((ob, ov, newExpanded) -> {
            pseudoClassStateChanged(EXPANDED_PSEUDOCLASS_STATE, newExpanded);
            pseudoClassStateChanged(COLLAPSED_PSEUDOCLASS_STATE, !newExpanded);
            updateItem(getItem());
        });

    }

    public TreeNodeCell(T item) {
        this();
        setItem(item);
    }

    private final ObjectProperty item = new SimpleObjectProperty<>(this, "item");

    public T getItem() {
        return item.get();
    }

    public ObjectProperty itemProperty() {
        return item;
    }

    public void setItem(T item) {
        this.item.set(item);
    }

    private final ReadOnlyObjectWrapper> treeNode = new ReadOnlyObjectWrapper<>(this, "treeNode");

    public TreeNode getTreeNode() {
        return treeNode.get();
    }

    public ReadOnlyObjectProperty> treeNodeProperty() {
        return treeNode.getReadOnlyProperty();
    }

    protected void setTreeNode(TreeNode treeNode) {
        this.treeNode.set(treeNode);
    }

    private final BooleanProperty expanded = new SimpleBooleanProperty(this, "expanded", DEFAULT_EXPANDED);

    public boolean isExpanded() {
        return expanded.get();
    }

    public BooleanProperty expandedProperty() {
        return expanded;
    }

    public void setExpanded(boolean expanded) {
        this.expanded.set(expanded);
    }

    private final ObjectProperty graphic = new SimpleObjectProperty<>(this, "graphic");

    public Node getGraphic() {
        return graphic.get();
    }

    public ObjectProperty graphicProperty() {
        return graphic;
    }

    public void setGraphic(Node graphic) {
        this.graphic.set(graphic);
    }

    private final StringProperty text = new SimpleStringProperty(this, "text");

    public String getText() {
        return text.get();
    }

    public StringProperty textProperty() {
        return text;
    }

    public void setText(String text) {
        this.text.set(text);
    }

    protected void updateItem(T item) {
        if (item != null) {
            setText(item.toString());
        } else {
            setText("");
        }
    }

    @Override
    public String getUserAgentStylesheet() {
        return Objects.requireNonNull(TreeNodeCell.class.getResource("tree-view.css")).toExternalForm();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy