package com.cedarsoft.spring.rcp.tree;
import com.cedarsoft.lookup.DynamicLookup;
import com.cedarsoft.lookup.Lookup;
import com.cedarsoft.lookup.Lookups;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.event.MouseEvent;
import java.util.Arrays;
/**
*
*/
public class TreeUtils {
private TreeUtils() {
}
/**
* Expand the children
*
* @param tree the tree
* @param parentPath the parent path
* @param children the children
*/
public static void expandChildren( @NotNull JTree tree, @NotNull Object[] parentPath, @NotNull Iterable<?> children ) {
Object[] path = new Object[parentPath.length + 1];
System.arraycopy( parentPath, 0, path, 0, parentPath.length );
for ( Object child : children ) {
path[path.length - 1] = child;
tree.expandPath( new TreePath( path ) );
}
}
/**
* Make the children visible
*
* @param tree the tree
* @param parentPath the parent path
* @param children the children
*/
public static void makeChildrenVisible( @NotNull JTree tree, @NotNull Object[] parentPath, @NotNull Iterable<?> children ) {
Object[] path = new Object[parentPath.length + 1];
System.arraycopy( parentPath, 0, path, 0, parentPath.length );
for ( Object child : children ) {
path[path.length - 1] = child;
tree.makeVisible( new TreePath( path ) );
}
}
/**
* Format the given path
*
* @param treePath the path that is formated
* @return the formated path
*/
@NotNull
@NonNls
public static String format( @NotNull TreePath treePath ) {
return format( treePath, 0 );
}
/**
* Format the given path
*
* @param treePath the path
* @param leadingTabCount the amount of leading tabs
* @return the formated path
*/
public static String format( @NotNull TreePath treePath, int leadingTabCount ) {
StringBuilder path = new StringBuilder();
int depth = leadingTabCount;
for ( Object element : treePath.getPath() ) {
for ( int i = 0; i < depth; i++ ) {
path.append( '\t' );
}
path.append( "--> " );
path.append( element );
path.append( '\n' );
depth++;
}
if ( path.length() > 0 ) {
path.deleteCharAt( path.length() - 1 );
}
return path.toString();
}
/**
* Creates an array with indicies
*
* @param firstIndex the first index
* @param lastIndex the last index
* @return an array containing the indicies from firstIndex to lastIndex
*/
@NotNull
public static int[] createIndicies( int firstIndex, int lastIndex ) {
int count = lastIndex - firstIndex + 1;
int[] indicies = new int[count];
for ( int i = 0; i < count; i++ ) {
indicies[i] = i + firstIndex;
}
return indicies;
}
/**
* Creates an array filled with objects
*
* @param firstIndex the first index
* @param lastIndex the last index
* @return the object array
*/
@NotNull
public static Object[] createFilledObjectArray( int firstIndex, int lastIndex ) {
int count = lastIndex - firstIndex + 1;
return createFilledObjectArray( count );
}
/**
* Creates an array with the given size. This array is filled with new objects
*
* @param size the size of the array
* @return a new array with the given size filled with empty objects
*/
@NotNull
public static Object[] createFilledObjectArray( int size ) {
Object[] objects = new Object[size];
Arrays.fill( objects, new Object() );
return objects;
}
/**
* Returns the node for the given parent with the given user object
*
* @param parent the parent
* @param childUserObject the user object of the child node
* @return the child node
* @throws IllegalArgumentException
*/
@NotNull
public static DefaultMutableTreeNode findNode( @NotNull DefaultMutableTreeNode parent, @NotNull Object childUserObject ) throws IllegalArgumentException {
for ( int i = 0; i < parent.getChildCount(); i++ ) {
DefaultMutableTreeNode node = ( DefaultMutableTreeNode ) parent.getChildAt( i );
if ( node.getUserObject() == childUserObject ) {
return node;
}
}
throw new IllegalArgumentException( "No node found for " + childUserObject );
}
/**
* Unwraps a path of default tree nodes
*
* @param path the path (expected to contain {@link DefaultMutableTreeNode}s)
* @return the user objects
*/
@NotNull
public static Lookup unwrap( @NotNull Object... path ) {
DynamicLookup lookup = Lookups.dynamicLookup();
for ( Object pathElement : path ) {
if ( pathElement instanceof DefaultMutableTreeNode ) {
Object userObject = ( ( DefaultMutableTreeNode ) pathElement ).getUserObject();
if ( userObject != null ) {
lookup.addValue( userObject );
}
} else {
lookup.addValue( pathElement );
}
}
return lookup;
}
/**
* Extracts the clicked tree path of a mouse event (for a jtree)
*
* @param event the mouse event
* @return the clicked tree path (or null if no path has been clicked)
*/
@Nullable
public static TreePath getClickedPath( @NotNull MouseEvent event ) {
JTree tree = ( JTree ) event.getSource();
int clickedRow = tree.getRowForLocation( event.getX(), event.getY() );
if ( clickedRow == -1 ) {
return null;
}
return tree.getPathForLocation( event.getX(), event.getY() );
}
/**
* Returns the clicked user object
*
* @param event the click event
* @return the clicked user object
*/
@Nullable
public static Object getClickedUserObject( @NotNull MouseEvent event ) {
TreePath path = getClickedPath( event );
if ( path == null ) {
return null;
}
Object clickedNode = path.getLastPathComponent();
return getUserObject( clickedNode );
}
/**
* Returns the user object for a given node
*
* @param node the node
* @return the user object
*/
@NotNull
public static Object getUserObject( @NotNull Object node ) {
Object userObject = ( ( DefaultMutableTreeNode ) node ).getUserObject();
if ( userObject == null ) {
throw new IllegalArgumentException( "Invalid node - no user object set" );
}
return userObject;
}
}