package org.rr.commons.swing.components.tree;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTree;
import javax.swing.tree.TreePath;
import org.rr.commons.utils.ListUtils;
public class TreeUtil {
public static final String PATH_SEPARATOR = "\t";
/**
* Cleans the separator chars from the given node name.
*/
private static String cleanNodeName(String nodeName) {
if(nodeName != null) {
nodeName = nodeName.replaceAll("[\\t\\\n]", "_");
}
return nodeName;
}
private static List<TreePath> getExpandedNodeNames(JTree tree) {
List<TreePath> result = new ArrayList<>();
int rowCount = tree.getRowCount();
for (int i = 0; i < rowCount; i++) {
TreePath rowPath = tree.getPathForRow(i);
if(tree.isExpanded(rowPath)) {
result.add(rowPath);
}
}
return result;
}
/**
* Get the tree path names in a separated string
*/
private static String getTreePathName(TreePath path, String separator) {
Object[] pathArray = path.getPath();
StringBuilder result = new StringBuilder();
for(Object p : pathArray) {
if(p instanceof NamedNode) {
String name = cleanNodeName(((NamedNode)p).getName());
if(name != null) {
if(result.length() > 0) {
result.append(separator);
}
result.append(name);
}
}
}
return result.toString();
}
private static TreePath restoreTreePathByName(JTree tree, String pathString, String separator) {
List<String> split = ListUtils.split(pathString, separator);
int row = 0;
TreePath lastRowPath = null;
for(String s : split) {
s = cleanNodeName(s);
int rowCount = tree.getRowCount();
for (; row < rowCount; row++) {
TreePath rowPath = tree.getPathForRow(row);
Object pathComponent = rowPath.getLastPathComponent();
if(pathComponent instanceof NamedNode) {
String cleanedNodeName = cleanNodeName(((NamedNode) pathComponent).getName());
if(pathComponent instanceof NamedNode && cleanedNodeName.equals(s)) {
tree.expandRow(row);
lastRowPath = rowPath;
break;
}
}
}
}
return lastRowPath;
}
/**
* Get the expansion states for the expanded nodes of the given {@link JTree} as string.
* Only those nodes gets collected that implements the {@link NamedNode} interface.
* @see #restoreExpanstionState(JRTree, String)
*/
public static String getExpansionStates(JTree tree) {
List<TreePath> expandedNodeNames = getExpandedNodeNames(tree);
StringBuilder result = new StringBuilder();
for(TreePath path : expandedNodeNames) {
String treePathName = getTreePathName(path, PATH_SEPARATOR);
if(result.length() > 0) {
result.append("\n");
}
result.append(treePathName);
}
return result.toString();
}
/**
* Restores the expansion states from the given String.
* @see TreeUtil#getExpansionStates(JRTree)
*/
public static TreePath restoreExpanstionState(JTree tree, String expansionStates) {
if(expansionStates != null) {
List<String> expansionStatesList = ListUtils.split(expansionStates, "\n");
TreePath lastExpandedRow = null;
for(String expansionState : expansionStatesList) {
lastExpandedRow = restoreTreePathByName(tree, expansionState, PATH_SEPARATOR);
}
return lastExpandedRow;
}
return null;
}
/**
* Tells if the given rootPath ends with a member of the given childPath.
* @param path1 The root path
* @param path2 The path which is tested if the root is the same.
* @return <code>true</code> if the rootPath ends with a member of the given childPath and <code>false</code> otherwise.
*/
public static boolean isChild(TreePath rootPath, TreePath childPath) {
if(childPath == null || rootPath == null) {
return false;
}
Object lastRootPathComponent = rootPath.getLastPathComponent();
TreePath childParentPath = childPath;
do {
if(childParentPath.getLastPathComponent().equals(lastRootPathComponent)) {
return true;
}
childParentPath = childParentPath.getParentPath();
} while(childParentPath != null);
return false;
}
}