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

de.factoryfx.javafx.widget.tree.DataTreeWidget Maven / Gradle / Ivy

package de.factoryfx.javafx.widget.tree;

import com.google.common.collect.TreeTraverser;
import de.factoryfx.data.Data;
import de.factoryfx.data.attribute.Attribute;
import de.factoryfx.data.attribute.AttributeVisitor;
import de.factoryfx.data.attribute.ReferenceAttribute;
import de.factoryfx.data.attribute.ReferenceListAttribute;
import de.factoryfx.javafx.editor.data.DataEditor;
import de.factoryfx.javafx.util.DataTextFieldTreeCell;
import de.factoryfx.javafx.util.UniformDesign;
import de.factoryfx.javafx.widget.CloseAwareWidget;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;

import java.util.function.Consumer;

public class DataTreeWidget implements CloseAwareWidget {
    private final Data root;
    private final DataEditor dataEditor;
    private final UniformDesign uniformDesign;

    public DataTreeWidget(DataEditor dataEditor, Data root, UniformDesign uniformDesign) {
        this.dataEditor=dataEditor;
        this.root = root;
        this.uniformDesign = uniformDesign;
    }

    @Override
    public void closeNotifier() {
//        listener.changed(null, null, null);
    }

    @Override
    public Node createContent() {
        SplitPane splitPane = new SplitPane();
        splitPane.getItems().addAll(dataEditor.createContent(),createTree());
        splitPane.setDividerPosition(0,0.75);
        return splitPane;
    }
    
    boolean programmaticallySelect=false;

    private Node createTree(){
        TreeView tree = new TreeView<>();
        tree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        tree.setCellFactory(param -> new DataTextFieldTreeCell<>(TreeData::getData, TreeData::getDisplayText));
        tree.setRoot(constructTreeFromRoot());

        tree.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue!=null && !programmaticallySelect && newValue.getValue()!=null && newValue.getValue().getData()!=null){
                dataEditor.edit(newValue.getValue().getData());
            }
        });

        ChangeListener dataChangeListener = (observable, oldValue, newValue) -> {
            Platform.runLater(() -> {//javafx bug workaround http://stackoverflow.com/questions/26343495/indexoutofboundsexception-while-updating-a-listview-in-javafx
                if (treeStructureChanged(root)){
                    TreeItem treeItemRoot = constructTreeFromRoot();
                    tree.setRoot(treeItemRoot);
                }

                tree.getSelectionModel().clearSelection();
                for (TreeItem item : treeViewTraverser.breadthFirstTraversal(tree.getRoot())) {
                    programmaticallySelect=true;
                    if (item.getValue().match(newValue)) {
                        tree.getSelectionModel().select(item);
                    }
                    programmaticallySelect=false;
                }
            });

        };
        dataEditor.editData().addListener(dataChangeListener);
        dataChangeListener.changed(dataEditor.editData(),dataEditor.editData().get(),dataEditor.editData().get());

        ScrollPane scrollPane = new ScrollPane(tree);
        scrollPane.setFitToHeight(true);
        scrollPane.setFitToWidth(true);

        ContextMenu contextMenu = new ContextMenu();
        MenuItem menuItem = new MenuItem("expand all");
        menuItem.setOnAction(event -> {
            for (TreeItem item : treeViewTraverser.breadthFirstTraversal(tree.getRoot())) {
                item.setExpanded(true);
            }
        });
        contextMenu.getItems().addAll(menuItem);
        tree.setContextMenu(contextMenu);

        return scrollPane;
    }

    TreeTraverser> treeViewTraverser = new TreeTraverser>() {
        @Override
        public Iterable> children(TreeItem data) {
            return data.getChildren();
        }
    };

    long lastSize=0;
    private boolean treeStructureChanged(Data root){
        if (root!=null) {
            return lastSize != root.internal().collectChildrenDeep().size();
        }
        return false;
    }


    private TreeItem constructTreeFromRoot(){
        lastSize=root.internal().collectChildrenDeep().size();
        return constructTree(root);
    }

    private TreeItem constructTree(Data data){
        if (data!=null){
            TreeItem dataTreeItem = new TreeItem<>(new TreeData(data,null));
            data.internal().visitAttributesFlat((attributeVariableName, attribute) -> {
                attribute.internal_visit(data1 -> {
                    TreeItem refDataTreeItem = new TreeItem<>(new TreeData(null,uniformDesign.getLabelText(attribute)));
                    dataTreeItem.getChildren().add(refDataTreeItem);

                    final TreeItem treeItem = constructTree(data1);
                    if (treeItem!=null){
                        refDataTreeItem.getChildren().add(treeItem);
                    }
                });

            });
            return dataTreeItem;
        }
        return null;
    }

    public static class TreeData{
        private final Data data;
        private final String text;

        public TreeData(Data data, String text) {
            if (data==null){
                System.out.println();
            }
            this.data = data;
            this.text = text;
        }

        public String getDisplayText() {
            if (text==null && data!=null){
                return data.internal().getDisplayText();
            }
            return text;
        }


        public Data getData(){
            return data;
        }

        public boolean match(Data newValue) {
            return text==null && newValue==data;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy