package com.revolsys.swing.tree;
import java.awt.Rectangle;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
import javax.swing.DropMode;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import com.revolsys.collection.EmptyReference;
import com.revolsys.collection.map.LinkedHashMapEx;
import com.revolsys.collection.map.MapEx;
import com.revolsys.properties.ObjectWithProperties;
import com.revolsys.swing.menu.MenuFactory;
import com.revolsys.swing.parallel.Invoke;
import com.revolsys.swing.tree.dnd.TreeTransferHandler;
import com.revolsys.swing.tree.node.OpenStateTreeNode;
public class BaseTree extends JTree implements ObjectWithProperties {
private static Reference<BaseTreeNode> menuNode = new EmptyReference<>();
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
public static <V extends BaseTreeNode> V getMenuNode() {
return (V)menuNode.get();
}
protected static void setMenuNode(final BaseTreeNode menuNode) {
BaseTree.menuNode = new WeakReference<>(menuNode);
}
private final MapEx properties = new LinkedHashMapEx();
private boolean menuEnabled = true;
private BaseTreeListener treeListener = new BaseTreeListener(this);
public BaseTree(final BaseTreeNode root) {
super(new DefaultTreeModel(root, true));
setRoot(root);
setRootVisible(true);
setShowsRootHandles(true);
setLargeModel(true);
setToggleClickCount(0);
setRowHeight(0);
setCellRenderer(new BaseTreeCellRenderer());
setExpandsSelectedPaths(true);
setTransferHandler(new TreeTransferHandler());
setDragEnabled(true);
setDropMode(DropMode.ON_OR_INSERT);
final DefaultTreeSelectionModel selectionModel = new DefaultTreeSelectionModel();
selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
setSelectionModel(selectionModel);
expandPath(root);
final ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
toolTipManager.registerComponent(this);
}
public void collapsePath(final List<Object> items) {
final TreePath path = getTreePath(items);
collapsePath(path);
}
public void collapsePath(final Object... items) {
if (items != null) {
collapsePath(Arrays.asList(items));
}
}
@Override
public void collapsePath(final TreePath path) {
final Object node = path.getLastPathComponent();
if (node instanceof BaseTreeNode) {
final BaseTreeNode treeNode = (BaseTreeNode)node;
treeNode.collapseChildren();
treeNode.nodeCollapsed(treeNode);
}
super.collapsePath(path);
}
public void expandAllNodes() {
expandAllNodes(0, getRowCount());
}
private void expandAllNodes(final int startingIndex, final int rowCount) {
for (int i = startingIndex; i < rowCount; ++i) {
expandRow(i);
}
if (getRowCount() != rowCount) {
expandAllNodes(rowCount, getRowCount());
}
}
public void expandPath(final List<?> items) {
final TreePath path = getTreePath(items);
expandPath(path);
}
public void expandPath(final Object... items) {
if (items != null) {
expandPath(Arrays.asList(items));
}
}
public MenuFactory getMenuFactory(final TreePath path) {
final Object node = path.getLastPathComponent();
if (node instanceof BaseTreeNode) {
final BaseTreeNode treeNode = (BaseTreeNode)node;
return treeNode.getMenu();
} else {
return null;
}
}
@Override
public DefaultTreeModel getModel() {
return (DefaultTreeModel)super.getModel();
}
@Override
public Rectangle getPathBounds(final TreePath path) {
final Object lastPathComponent = path.getLastPathComponent();
if (lastPathComponent instanceof BaseTreeNode) {
final BaseTreeNode treeNode = (BaseTreeNode)lastPathComponent;
if (!treeNode.isVisible()) {
return null;
}
}
return super.getPathBounds(path);
}
@Override
public MapEx getProperties() {
return this.properties;
}
public BaseTreeNode getRootNode() {
final TreeModel model = getModel();
final BaseTreeNode root = (BaseTreeNode)model.getRoot();
return root;
}
public TreePath getTreePath(final List<?> items) {
final BaseTreeNode root = getRootNode();
if (root == null) {
return null;
} else {
return root.getTreePath(items);
}
}
public boolean isMenuEnabled() {
return this.menuEnabled;
}
@Override
public void removeNotify() {
setTransferHandler(null);
setDragEnabled(false);
getRootNode().setParent(null);
}
@Override
protected void setExpandedState(final TreePath path, final boolean state) {
Invoke.later(() -> {
super.setExpandedState(path, state);
if (isExpanded(path) == state) {
final Object node = path.getLastPathComponent();
if (node instanceof OpenStateTreeNode) {
final OpenStateTreeNode openState = (OpenStateTreeNode)node;
openState.setOpen(state);
}
if (node instanceof BaseTreeNode) {
final BaseTreeNode treeNode = (BaseTreeNode)node;
if (treeNode.isAllowsChildren()) {
for (final BaseTreeNode childNode : treeNode.getChildren()) {
if (childNode instanceof OpenStateTreeNode) {
final OpenStateTreeNode childState = (OpenStateTreeNode)childNode;
if (childState.isOpen()) {
final TreePath childPath = childNode.getTreePath();
setExpandedState(childPath, true);
}
}
}
}
}
}
});
}
public void setMenuEnabled(final boolean menuEnabled) {
this.menuEnabled = menuEnabled;
}
public void setRoot(final BaseTreeNode root) {
final DefaultTreeModel model = getModel();
final BaseTreeNode oldRoot = getRootNode();
if (oldRoot != null && root != oldRoot) {
oldRoot.delete();
}
model.setRoot(root);
if (root != null) {
root.setTree(this);
}
}
public void setRoot(final Object root) {
final BaseTreeNode rootNode = BaseTreeNode.newTreeNode(root);
setRoot(rootNode);
}
public void setTreeListener(final BaseTreeListener treeListener) {
if (this.treeListener != treeListener) {
this.treeListener.close();
}
this.treeListener = treeListener;
}
}