HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

"Building a Tree Viewer,"
Volume: 4 Issue: 4, p. 30

	

Listing 1.
 
 * Description: 
   Package contains common classes for the ViviGraphics Widget 
   Toolkit - a callback-based toolkit. 
   Originally, part of the Eva Toolkit - the prototype 
   implementation. 
 */ 
package com.wigitek.vivigraphics.widget.common; 

/** 
 * This class implements a one-level tree, which can be chained 
   together with other one-level trees to form a multi-level tree. 
   It maintains information about its branches and its parent. 
   It can also store the object and associated data about the 
   root of this tree. It cannot walk or display the tree. 
   That capability is left to the TreeWalker class to implement. 
   This allows us to separate the view from the tree model. 
   Note: This class should be enhanced to support multiple walker, 
   possibly to support multiple viewer. 
 * @version $Revision: 2.1 $ 
 * @author Originally written by Daniel Dee, 3/18/97 
 * @author Last updated by $Author$, $Date$ 
 * @see TreeWalker 
 */ 
public class TreeNode extends Object 
{ 
    /** 
     * Constructs a one-level Tree, i.e. a TreeNode with references 
       to its parent and its children. 
     * @param parent  the parent of this tree if any; 
use null if root of multi-level tree 
     * @param object  the object stored at the root of this 
one-level tree 
     * @param data    additional data stored at the root of this 
one-level tree 
     * @param name    the name for the root of this one-level tree 
     * @param walker  the instance of the TreeWalker class that provides
the capability 
to walk the multi-level tree for which this tree is a part 
     */ 
    public TreeNode( TreeNode parent, Object object, Object data, 
String name, TreeWalker walker ) 
    { 
        this.parent = parent; 
        this.object = object; 
        this.data   = data; 
        this.name   = name; 
        this.walker = walker; 
        if( parent != null ) 
            parent.add( this ); 
    } 

    /** 
     * Makes the subtree one of its children. 
     * @param subtree the subtree 
     */ 
    protected void add( TreeNode subtree ) 
    { 
        // If the children (subtrees) array is exceeded, expand it 
        // and copies existing children to the new array. 
        if( numberOfChildren >= maxNumberOfChildren ) 
        { 
            TreeNode[] newChildren; 

            maxNumberOfChildren = 2 * maxNumberOfChildren; 
            newChildren = new TreeNode[maxNumberOfChildren]; 
            for( int i=0; i < numberOfChildren; i++ ) 
                newChildren[i] = children[i]; 
            children = newChildren; 
            newChildren = null; 
        } 

        // Add the new children (subtree). 
        children[numberOfChildren++] = subtree; 

        // Tell the walker that the tree has been updated. 
        if( walker != null ) 
            walker.treeUpdate(this); 
    } 

    /** 
     * Removes this leaf from the parent. 
     */ 
    public void remove() 
    { 
        if( parent != null ) 
            parent.remove(this); 
        else if( walker != null ) 
            walker.treeRemove(this); 
    } 

    /** 
     * Removes the subtree from the list of children. 
     * @param the specified subtree 
     */ 
    public void remove( TreeNode subtree ) 
    { 
        if( walker != null ) 
            walker.treeRemove(subtree); 

        for( int i=0; i < numberOfChildren; i++ ) 
            if( children[i] == subtree ) 
            { 
                for( int j=i; j < numberOfChildren-1; j++ ) 
                    children[j] = children[j+1]; 
                numberOfChildren--; 
                break; 
            } 

        if( walker != null ) 
            walker.treeUpdate(this); 
    } 

    /** 
     * Detach the subtree from the parent. 
       Does not destroy the subtree. 
     * @param the specified subtree 
     */ 
    protected void detach( TreeNode subtree ) 
    { 
        for( int i=0; i < numberOfChildren; i++ ) 
            if( children[i] == subtree ) 
            { 
                for( int j=i; j < numberOfChildren-1; j++ ) 
                    children[j] = children[j+1]; 
                numberOfChildren--; 
                break; 
            } 
    } 

    /** 
     * Detach this leaf from its original parent and attach to the 
new parent. 
     * @param newparent new parent 
     */ 
    public void setParent( TreeNode newparent ) 
    { 
        parent.detach(this); 
        parent = newparent; 
        parent.add(this); 
    } 

    /** 
     * Gets the parent. 
     */ 
    public TreeNode getParent() 
    { 
        return parent; 
    } 

    /** 
     * Gets the "width" of the subtree rooted at this TreeNode 
       without considering the grandchildren. It returns the 
       number of children of this TreeNode unless it is 0. 
       If it is 0, then getWidth returns 1. 
     */ 
    public int getWidth() 
    { 
        return numberOfChildren <= 1 ? 1 : numberOfChildren; 
    } 

    /** 
     * Gets the object stored at the root of the Tree. 
     */ 
    public Object getObject() 
    { 
        return object; 
    } 

    /** 
     * Gets the number of children in the tree. 
     */ 
    public int getNumberOfChildren() 
    { 
        return numberOfChildren; 
    } 

    /** 
     * Gets the 0-based i-th child. 
     * @param i the index of the child. 
     */ 
    public TreeNode getChild( int i ) 
    { 
        return children[i]; 
    } 

    /** 
     * Gets the data stored at the root of the tree. 
     */ 
    public Object getData() 
    { 
        return data; 
    } 

    /** 
     * Gets the name of the button. 
       Implements getName() method of the Widget interface. 
     */ 
    public String getName() 
    { 
        return name; 
    } 

    /** 
     * Returns a String that represents the value of this Object. 
       Overrides the method in java.lang.Object. 
     * @return a String 
     * @see Object 
     */ 
    public String toString() 
    { 
        String string = super.toString(); 
        int length = string.length(); 
        return string.substring( 0, length-1 ) + ",name=" + name + "]"; 
    } 
  

    // The name of an instance of this class 
    private String name; 

    // Initial array allocation to store Tree children 
    private int maxNumberOfChildren = 50;         // initial array size 
    private TreeNode[] children = new TreeNode[maxNumberOfChildren]; 
    private int numberOfChildren = 0; 

    private TreeNode parent;         // Tree parent 
    private TreeWalker walker;   // Instance of TreeWalker class that can 
walk this tree from the root 
    private Object object;       // Object stored at the root of the Tree 
    private Object data;         // Other information stored at the 
root of the Tree 
} 

Listing 2.
 
/** 
 * Copyright (c) 1997 Daniel Dee 
 * Description: 
   Package contains common classes for the Vivigraphics widget 
   Toolkit - a callback-based toolkit. 
   Originally, part of the Eva Toolkit - the prototype 
   implementation. 
 */ 
package com.wigitek.vivigraphics.widget.common; 

/** 
 * This class implements the skeleton tree walking capability 
   for the Tree class. 
 * Bugs: BREADTH_FIRST traversal not yet implemented. 
 * @version $Revision$ 
 * @author Originally written by Daniel Dee, 4/11/97 
 * @author Last updated by $Author$, $Date$ 
 * @see Tree 
 */ 
public abstract class TreeWalker extends Object 
{ 
    /** 
     * Constructs a new TreeWalker. 
     */ 
    public TreeWalker() 
    { 
        currentTree = null; 
    } 

    /** 
     * Updates the tree to which the subtree belong. 
     * @param subtree the subtree belonging to the tree to be updated. 
     */ 
    public void treeUpdate( TreeNode subtree ) 
    { 
        if( subtree != null ) 
            walk( currentTree = getRoot(subtree), DEPTH_FIRST ); 
    } 

    /** 
     * Updates the last updated tree. 
     */ 
    public void treeUpdate() 
    { 
        if( currentTree != null ) 
            walk(currentTree, DEPTH_FIRST); 
    } 

    /** 
     * Gets the root of the entire tree to which the specified subtree
belongs. 
     * @param subtree the specified subtree 
     */ 
    public TreeNode getRoot( TreeNode subtree ) 
    { 
        TreeNode parent; 

        while( (parent = subtree.getParent()) != null ) 
            subtree = parent; 
        return subtree; 
    } 

    /** 
     * Removes the subtree. 
     * @param subtree the subtree to be removed. 
     */ 
    public abstract void treeRemove( TreeNode subtree ); 

    /** 
     * Walks the tree starting at tree. 
     * @param tree     the starting root of the tree to walk 
     * @param walkType DEPTH_FIRST or BREADTH_FIRST 
     */ 
    protected abstract void walk( TreeNode tree, int walkType ); 

    /** 
     * Walks the tree depth-first starting at tree. Since the 
       method may be used recursively, parameter level 
       allows walkDepth to count the number of levels it has 
       recursed. 
     * @param tree the specified tree 
     * @param level the recursion level; must be supplied with default 
     */ 
    protected abstract void walkDepth( TreeNode tree, int level ); 
  

    protected TreeNode currentTree; // the last tree walked 

    public final static int DEPTH_FIRST = 0;   // depth-first walk 
    public final static int BREADTH_FIRST = 1; // breadth-first walk 
} 

Listing 3.
 
class TreePrinter extends TreeWalker 
{ 
    public void treeRemove( Tree subtree ) 
    { 
    } 

    protected void walk( Tree tree, int walkType ) 
    { 
        walkDepth( tree, 0 ); 
    } 

    protected void walkDepth( Tree tree, int level ) 
    { 
        for( int i=0; i < level; i++ ) 
            System.out.print( " " ); 
        System.out.println( tree.getName() ); 

        int numberOfChildren = tree.getNumberOfChildren(); 
        for( int i=0; i < numberOfChildren; i++ ) 
            walkDepth( tree.getChild(i), level+1 ); 
    } 
} 

Listing 4.
 
Root 
Level 1.1 
Root 
Level 1.1 
Level 1.2 
Root 
Level 1.1 
Level 1.2 
Level 1.3 
Root 
Level 1.1 
Level 1.2 
Level 2.1 
Level 1.3 
Root 
Level 1.1 
Level 1.2 
Level 2.1 
Level 2.2 
Level 1.3 
Root 
Level 1.1 
Level 1.2 
Level 2.1 
Level 2.2 
Level 2.3 
Level 1.3 

Listing 5.
 
/** 
 * Copyright (c) 1997 Daniel Dee 
 * Description: 
   Package contains common classes for the Vivigraphics widget 
   Toolkit - a callback-based toolkit. 
   Originally, part of the Eva Toolkit - the prototype 
   implementation. 
 */ 
package com.wigitek.vivigraphics.widget.gui; 

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.Event; 
import java.awt.Frame; 
import java.awt.Image; 
import java.awt.Insets; 
import java.awt.Point; 
import java.awt.Graphics; 
import java.util.Hashtable; 
import java.util.Enumeration; 

import com.wigitek.vivigraphics.widget.gui.Button; 
import com.wigitek.vivigraphics.widget.gui.Panel; 
import com.wigitek.vivigraphics.widget.common.Callbackable; 
import com.wigitek.vivigraphics.widget.common.Alignment; 
import com.wigitek.vivigraphics.widget.common.Orientation; 
import com.wigitek.vivigraphics.widget.common.Widget; 
import com.wigitek.vivigraphics.widget.common.TreeNode; 
import com.wigitek.vivigraphics.widget.common.TreeWalker; 
import com.wigitek.vivigraphics.widget.common.PositionableGridConstraints; 
import com.wigitek.vivigraphics.widget.gui.PositionableGridLayout; 

/** 
 * This class extends TreeWalker to implement a Tree viewer 
   for the Tree class. TreeViewer uses GridLayout to layout 
   the leaves in the tree. 
 * Restrictions: 
   (1) Collapsing and expanding of subtree not implemented 
       in this version. 
   (2) BREADTH_FIRST traversal not yet implemented. 
   (3) One Viewer can have view only one Tree. . 
 * @version $Revision$ 
 * @author Originally written by Daniel Dee, 4/11/97 
 * @author Last updated by $Author$, $Date$ 
 * @see Tree 
 * @see TreeWalker 
 */ 
public class TreeViewer extends TreeWalker 
{ 
    /** 
     * Constructs a "unnamed" TreeViewer with VERTICAL orientation. 
     */ 
    public TreeViewer() 
    { 
        this( "Unnamed", Orientation.VERTICAL ); 
    } 

    /** 
     * Constructs a TreeViewer with given name and orientation. 
     * @param name   the specified name 
     * @param orient the specified orientation 
     */ 
    public TreeViewer( String name, Orientation 
orient ) 
    { 
        super(); 
        this.orient = orient; 
        panel = new TreeViewerPanel(name,this); 
        layout = new PositionableGridLayout(); 
        panel.setLayout( layout ); 
        comptable = new Hashtable(); // TRADEOFF 
    } 

    /** 
     * Constructs a fixed-grid TreeViewer with given name and orientation. 
     * @param name   the specified name 
     * @param width  the fixed width 
     * @param height the fixed height 
     * @param orient the specified orientation 
     */ 
    public TreeViewer( String name, int width, int height, Orientation orient ) 
    { 
        super(); 
        this.orient = orient; 
        panel = new TreeViewerPanel(name,this); 
        layout = new PositionableGridLayout(width, height,new 
Insets(2,2,2,2), PositionableGridLayout.NO_ADJUST); 
        panel.setLayout( layout ); 
        comptable = new Hashtable(); // TRADEOFF 
    } 

    /** 
     * Sets the display alignment for the Tree. 
     * @param align the display alignment 
     */ 
    public void setAlignment( Alignment align ) 
    { 
        this.align = align; 
        treeUpdate(); 
    } 

    /** 
     * Sets the display orientation for the Tree. 
     * @param orient the display orientation 
     */ 
    public void setOrientation( Orientation orient ) 
    { 
        this.orient = orient; 
        treeUpdate(); 
    } 

    /** 
     * Sets the layout constraints for the specified component. 
       TreeViewer uses GridLayout for layout 
       and the associated GridConstraints for the GridLayout constraints. 
       Note that this GridLayout is a completely different implementation 
       from AWTís GridLayout. 
     * @param comp        the component 
     * @param constraints the componentís layout constraints 
     */ 
    protected void setConstraints( Component comp, 
PositionableGridConstraints constraints ) 
    { 
        layout.setConstraints(comp, constraints); 
    } 

    /** 
     * Adds a Widget as a child of the specified parent in a Tree. 
     * @param comp    the specified Widget 
     * @param parent  the specified parent 
     */ 
    public void add( Widget comp, Widget parent ) // TRADEOFF 
    { 
setConstraints( (Component)comp, new PositionableGridConstraints(0,0,PositionableGridConstraints.PREFERRED_SIZE,
PositionableGridConstraints.PREFERRED_SIZE,PositionableGridConstraints.NORTHWEST) ); 
// set the Widget to the origin initially 
        panel.add((Component)comp) // add it to the panel which displays the tree 

        if( comp.isDraggable() ) 
         comp.addCallback( Button.DRAG_CALLBACK, new 
TreeViewerMouseDragCallback(comp,this,panel) ); 

        TreeNode tree = new TreeNode((parent != null) ? (TreeNode)
comptable.get(parent): null, 
                            comp, new TreeViewerData(new Point(0,0)), 
comp.getName(), this); // now actually create the Tree for this Widget 
        comptable.put( comp, tree ); // adds tree to the hashtable with comp as key 
    } 

    /** 
     * Removes the specified Widget from the Tree. 
     * @param comp the specified Widget 
     */ 
    public void remove( Widget comp ) 
    { 
        ((TreeNode)comptable.get(comp)).remove(); 
    } 

   /** 
    * Gets the current grid dimensions of the associated layout 
      (i.e., number of cells in each dimension). 
    */ 
    public Dimension getLayoutDimension() 
    { 
        return layout.getLayoutDimension(); 
    } 

    /** 
     * Returns the preferred dimensions for this layout given the components 
       in the specified parent. 
     * @param parent the parent which needs to be laid out 
     * @see #minimumLayoutSize 
     */ 
    public Dimension getPreferredLayoutSize(Container parent) 
    { 
        Insets insets = parent.insets(); 
        Dimension size = layout.preferredLayoutSize(panel); 
        Dimension gridSize = layout.getGridSize(); 

        // Add extra 1-grid-element margin as preferredSize. 
        size.width += gridSize.width; 
        size.height += gridSize.height; 
        Dimension dim = new Dimension( size.width + insets.left + insets.right, 
                                       size.height + insets.top + insets.bottom ); 
        return dim; 
    } 

    /** 
     * Returns the minimum dimensions needed to layout the components 
       contained in the specified parent. 
     * @param parent the parent which needs to be laid out 
     * @see #preferredLayoutSize 
     */ 
    public Dimension getMinimumLayoutSize(Container parent) 
    { 
        Insets insets = parent.insets(); 
        Dimension size = layout.minimumLayoutSize(panel); 
        Dimension dim = new Dimension( size.width + insets.left + insets.right, 
                                       size.height + insets.top + insets.bottom ); 
        return dim; 
    } 

    /** 
     * Gets the Panel in which this Tree is drawn. 
     */ 
    public Panel getPanel() 
    { 
        return panel; 
    } 

    /** 
     * Clears the Panel and updates all components and branches 
       in the subtree in the TreeViewer. 
     * @param subtree the specified subtree 
     */ 
    public void treeUpdate( TreeNode subtree ) 
    { 
        clearTree(); 
        super.treeUpdate(subtree); 
    } 

    /** 
     * Clears the Panel and updates all components and branches 
       in the last tree drawn in the TreeViewer. 
     */ 
    public void treeUpdate() 
    { 
        clearTree(); 
        super.treeUpdate(); 
    } 

    /** 
     * Clears the Panel the Tree is drawn in, removes the subtree 
       from its parent, and updates the TreeViewer. 
     * @param subtree the subtree to remove 
     */ 
    public void treeRemove( TreeNode subtree ) 
    { 
        clearTree(); 
        walkRemove(subtree); 
    } 

    /** 
     * Clears the Panel the Tree is drawn in. 
     */ 
    protected void clearTree() 
    { 
        Dimension dim = panel.size(); 
        Graphics g = panel.getGraphics(); 
        if( g != null ) 
            g.clearRect(0,0,dim.width,dim.height); 
    } 

    /** 
     * Walks the subtree and remove all components from the 
       Panel. 
     * @param subtree the specified subtree 
     */ 
    protected void walkRemove( TreeNode subtree ) 
    { 
        panel.remove( (Component)subtree.getObject() ); 
        int numberOfChildren = subtree.getNumberOfChildren(); 
        for( int i=0; i < numberOfChildren; i++ ) 
            walkRemove( subtree.getChild(i) ); 
    } 

 /** 
  * Finds the Widget at the x and y pixel position. 
  * @param x the x pixel position 
  * @param y the y pixel position 
  * @return the widget at the x and y pixel position 
  */ 
    public Widget findWidget( int x, int y ) 
    { 
        Enumeration widgets = comptable.keys(); 
        while( widgets.hasMoreElements() ) 
        { 
            Component w = (Component)widgets.nextElement(); 
            Point loc = w.location(); 
            Dimension size = w.size(); 
            if( x > loc.x && x < loc.x + size.width && 
                y > loc.y && y < loc.y + size.height ) 
                return (Widget)w; 
        } 
        return null; 
    } 

 /** 
  * Finds the Widget at the x and y pixel position 
    within a tolerance of e. 
  * @param x the x pixel position 
  * @param y the y pixel position 
  * @param e the tolerance 
  * @return the widget at the x and y pixel position 
  */ 
    public Widget findWidget( int x, int y, int e ) 
    { 
        Enumeration widgets = comptable.keys(); 
        while( widgets.hasMoreElements() ) 
        { 
            Component w = (Component)widgets.nextElement(); 
            Point loc = w.location(); 
            Dimension size = w.size(); 
            if( x > loc.x-e && x < loc.x+size.width+e && 
                y > loc.y-e && y < loc.y+size.height+e ) 
                return (Widget)w; 
        } 
        return null; 
    } 

 /** 
  * Finds the TreeNode that is the root of the subtree 
    located at the x and y pixel position. 
  * @param x the x pixel position 
  * @param y the y pixel position 
  * @return the TreeNode at the x and y pixel position 
  */ 
    public TreeNode findSubtree( int x, int y ) 
    { 
        Enumeration widgets = comptable.keys(); 
        while( widgets.hasMoreElements() ) 
        { 
            Component w = (Component)widgets.nextElement(); 
            Point loc = w.location(); 
            Dimension size = w.size(); 
            if( x > loc.x && x < loc.x + size.width && 
                y > loc.y && y < loc.y + size.height ) 
            { 
                TreeNode subtree = (TreeNode)comptable.get(w); 
                return subtree; 
            } 
        } 
        return null; 
    } 

 /** 
  * Finds the TreeNode that is the root of the subtree 
    located at the x and y pixel position within a tolerance 
    of e. 
  * @param x the x pixel position 
  * @param y the y pixel position 
  * @param e the tolerance 
  * @return the TreeNode at the x and y pixel position 
  */ 
    public TreeNode findSubtree( int x, int y, int e ) 
    { 
        Enumeration widgets = comptable.keys(); 
        while( widgets.hasMoreElements() ) 
        { 
            Component w = (Component)widgets.nextElement(); 
            Point loc = w.location(); 
            Dimension size = w.size(); 
            if( x > loc.x-e && x < loc.x+size.width+e && 
                y > loc.y-e && y < loc.y+size.height+e ) 
            { 
                TreeNode subtree = (TreeNode)comptable.get(w); 
                return subtree; 
            } 
        } 
        return null; 
    } 

 /** 
  * Finds the TreeNode counterpart of the Widget w. 
  * @param w the specified Widget 
  * @return the TreeNode 
  */ 
    public TreeNode findSubtree( Widget w ) 
    { 
        return (TreeNode)comptable.get(w); 
    } 

    /** 
     * Draws all components of the tree in the TreeViewer. 
     * @param tree the specified tree; cannot be null 
     * @param walkType DEPTH_FIRST or BREADTH_FIRST 
     */ 
    protected void walk( TreeNode tree, int walkType ) 
    { 
        width = -1; 
        depth = 0; 

        walkDepth( tree, 0 ); 
        layout.layoutContainer(panel); 
    } 

    /** 
  * Draws the plus sign enclosed in a box to represent 
    the icon that will expand a subtree. 
  * @param g the Graphics context of the TreeViewerPanel 
             on which the tree is being drawn 
  * @param x the x pixel position 
  * @param y the y pixel position 
  */ 
    protected void drawUnfoldIcon( Graphics g, int x, int y ) 
    { 
        g.setColor(Color.white); 
        g.fillRect( x-3, y-3, 6, 6 ); 
        g.setColor(Color.black); 
        g.drawRect( x-3, y-3, 6, 6 ); 
        g.drawLine( x-1, y, x+1, y ); 
        g.drawLine( x, y-1, x, y+1 ); 
    } 

    /** 
  * Draws the minus sign enclosed in a box to represent 
    the icon that will collapse a subtree. 
  * @param g the Graphics context of the TreeViewerPanel 
             on which the tree is being drawn 
  * @param x the x pixel position 
  * @param y the y pixel position 
  */ 
    protected void drawFoldIcon( Graphics g, int x, int y ) 
    { 
        g.setColor(Color.white); 
        g.fillRect( x-3, y-3, 6, 6 ); 
        g.setColor(Color.black); 
        g.drawRect( x-3, y-3, 6, 6 ); 
        g.drawLine( x-1, y, x+1, y ); 
    } 

 /** 
  * Gets the hierarchy level of the subtree rooted at the 
    specified TreeNode. 
  * @param subtree the TreeNode that is the root of the subtree 
                   for which the hierarchy level is to be 
                   determined 
  * @return the hierarchy level of the subtree 
  */ 
    public int getLevel( TreeNode subtree ) 
    { 
        TreeViewerData td = null; 
        if( subtree != null ) 
            td = (TreeViewerData)subtree.getData(); 
        return (td != null) ? td.getLevel() : 0; 
    } 

    /** 
     * Draws all components of the tree in the TreeViewer. 
       Traversal is depth-first. Since the 
       method is used recursively, parameter level 
       allows walkDepth to count the number of levels it has 
       recursed. This method is always called from walk(). 
     * @param tree the specified tree; cannot be null 
     * @param level the recursion level; must be supplied with default 
     */ 
    protected void walkDepth( TreeNode tree, int level ) 
    { 
        TreeNode child; 
        Point treePos = (Point)((TreeViewerData)tree.getData()).getPoint(); 
        Point foldPos = (Point)((TreeViewerData)tree.getData()).getFoldPoint(); 
        Point firstPos, lastPos; 
        PositionableGridConstraints constraints =
		 layout.lookupConstraints((Component)tree.getObject()); 

        ((TreeViewerData)tree.getData()).setLevel(level); 

        // There is always a one-line spacing between levels. 
        // In other words, level 0 will be displayed on grid line 0, 
        // and level 1 will displayed on grid line 2, and so on. 
        treePos.y = level * 2; 

        // Count the depth of the tree. Always 1-based. 
        if( level+1 > depth ) 
            depth = level+1; 

        // If this subtree has no children, then it is a leaf node. 
        // Do some minor processing, and return immediately. 

        int numberOfChildren = tree.getNumberOfChildren(); 

        if( numberOfChildren == 0 ) 
        { 
            // Same as levels, there is also always a one-line spacing 
            // between adjacent nodes. 
            width += 2; 
            treePos.x = width - 1; 

            // Invert the grid x and y coordiates if HORIZONTAL. 
            // Otherwise, just save the calculated x and y position. 
            if( orient == Orientation.VERTICAL ) 
            { 
                constraints.gridx = treePos.x; 
                constraints.gridy = treePos.y; 
            } 
            else 
            { 
                constraints.gridx = treePos.y; 
                constraints.gridy = treePos.x; 
            } 

            return; 
        } 

        // If not a leaf node, recursively find leaf nodes on al 
        // its branches. 
        for( int i=0; i < numberOfChildren; i++ ) 
        { 
            child = tree.getChild(i); 
            { 
                Component widget = (Component)child.getObject(); 
                widget.show(); 
                walkDepth( child, level+1 ); 
            } 
        } 

        // Calculate the horizontal position of the current node 
        // which should between the leftmost and rightmost of its 
        // children. Invert these values if HORIZONTAL. 
        firstPos = (Point)((TreeViewerData)tree.getChild(0).getData()).getPoint(); 
        lastPos  =
 (Point)((TreeViewerData)tree.getChild(numberOfChildren-1).getData()).getPoint(); 

        { 
            if( align == Alignment.LEFT ) 
                treePos.x = firstPos.x; 
            else if( align == Alignment.RIGHT ) 
                treePos.x = lastPos.x; 
            else // Alignment.CENTER 
                treePos.x = (firstPos.x + lastPos.x) / 2; 
        } 

        if( orient == Orientation.VERTICAL ) 
        { 
            constraints.gridx = treePos.x; 
            constraints.gridy = treePos.y; 
        } 
        else 
        { 
            constraints.gridx = treePos.y; 
            constraints.gridy = treePos.x; 
        } 

        // Draw the branches. 
        Graphics graphics = panel.getGraphics(); 
        if( graphics != null ) 
        { 
            if( orient == Orientation.VERTICAL ) 
            { 
                Point treeCoord = layout.coordinates(treePos.x,treePos.y); 
                Point firstCoord = layout.coordinates(firstPos.x,firstPos.y); 
                Point lastCoord = layout.coordinates(lastPos.x,lastPos.y); 
                // Use objectís size instead of grid size so fold icon will 
                // not be fall underneath the object. 
                Dimension dim = ((Component)tree.getObject()).size(); 
                int x = treeCoord.x + dim.width/2; 
                int y  = (treeCoord.y + dim.height + firstCoord.y) / 2; 
                int xfirst = firstCoord.x + dim.width/2; 
                int xlast  = lastCoord.x + dim.width/2; 
                graphics.drawLine( x, treeCoord.y+layout.gridInsets().top, x, y ); 

                { 
                    graphics.drawLine( xfirst, y, xlast, y ); 
                    graphics.drawLine( xfirst, y, xfirst, firstCoord.y ); 
                    graphics.drawLine( xlast, y, xlast, lastCoord.y ); 
                } 

                for( int i=1; i < numberOfChildren-1; i++ ) 
                { 
                    Point childPos =
					 (Point)((TreeViewerData)tree.getChild(i).getData()).getPoint(); 
                    Point childCoord = layout.coordinates(childPos.x,childPos.y); 
                    x = childCoord.x + dim.width/2; 
                    graphics.drawLine( x, y, x, childCoord.y ); 
                } 
                foldPos.x = treeCoord.x + dim.width/2; 
                foldPos.y = (treeCoord.y + dim.height + firstCoord.y) / 2; 
                 drawFoldIcon( graphics, treeCoord.x + dim.width/2, (treeCoord.y +
				  dim.height + firstCoord.y) / 2 ); // <<< 
            } 
            else 
            { 
                Point treeCoord = layout.coordinates(treePos.y,treePos.x); 
                Point firstCoord = layout.coordinates(firstPos.y,firstPos.x); 
                Point lastCoord = layout.coordinates(lastPos.y,lastPos.x); 
                // Use objectís size instead of grid size so fold icon will 
                // not be fall underneath the object. 
                Dimension dim = ((Component)tree.getObject()).size(); 
                int x = (treeCoord.x + dim.width + firstCoord.x) / 2; 
                int y  = treeCoord.y + dim.height/2; 
                int yfirst = firstCoord.y + dim.height/2; 
                int ylast  = lastCoord.y + dim.height/2; 
                graphics.drawLine( treeCoord.x+layout.gridInsets().left, y, x, y ); 

                { 
                    graphics.drawLine( x, yfirst, x, ylast ); 
                    graphics.drawLine( x, yfirst, firstCoord.x, yfirst ); 
                    graphics.drawLine( x, ylast, lastCoord.x, ylast); 
                } 

                for( int i=1; i < numberOfChildren-1; i++ ) 
                { 
                    Point childPos =
					 (Point)((TreeViewerData)tree.getChild(i).getData()).getPoint(); 
                    Point childCoord = layout.coordinates(childPos.y,childPos.x); 
                    y = childCoord.y + dim.height/2; 
                    graphics.drawLine( x, y, childCoord.x, y ); 
                } 
                foldPos.x = (treeCoord.x + dim.width + firstCoord.x) / 2; 
                foldPos.y = treeCoord.y + dim.height/2; 
  
                 drawFoldIcon( graphics, (treeCoord.x + dim.width + firstCoord.x) / 2,
				  treeCoord.y + dim.height/2 ); // <<< 
            } 
        } 
    } 
  

    private TreeViewerPanel panel; // Panel on which the Tree is drawn 
    private PositionableGridLayout layout;     // GridLayout style for Panel 
    private int width;             // GridLayout width 
    private int depth;             // Depth of Tree 
    private Orientation orient;    // Orientation of Tree drawn 
    private Alignment align;       // Alignment of Tree drawn 
    private Hashtable comptable;   // Widget-to-Tree hashtable 
} 

/** 
 * Subclass of Panel Widget to force Tree Update. 
 */ 
class TreeViewerPanel extends Panel 
{ 
    /** 
     * Constructs a TreeViewerPanel. 
     * @param name   the name of the TreeViewerPanel 
     * @param viewer the viewer that has to be updated when paint is called 
     */ 
    public TreeViewerPanel( String name, TreeViewer viewer ) 
    { 
        super(name); 
        this.viewer = viewer; 
        addCallback( Panel.DRAG_CALLBACK, dcb = new TreeViewerPanelDragCallbackable(viewer,this) ); 
    } 

    /** 
     * Extends Panel.paint to call treeUpdate() first. 
     * @param g the Graphics context 
     */ 
    public void paint(Graphics g) 
    { 
        viewer.treeUpdate(); 
        super.paint(g); 
    } 
  
    public void setDragMode( boolean dragState ) 
    { 
        dragMode = dragState; 
    } 

    private TreeViewer viewer; 
    private TreeViewerPanelDragCallbackable dcb; 
    private boolean dragMode = false; 
} 

class TreeViewerPanelDragCallbackable extends Callbackable 
{ 
    public TreeViewerPanelDragCallbackable( TreeViewer viewer, TreeViewerPanel panel ) 
    { 
        this.viewer = viewer; 
        this.panel = panel; 
    } 

    public boolean activate( Event evt ) 
    { 
     if( comp == null ) 
      if( (comp = viewer.findWidget( evt.x, evt.y, 5 )) == null ) 
       return true; 
        Point loc = ((Component)comp).location(); 
        Dimension size = ((Component)comp).size(); 
        Graphics g = ((Component)panel).getGraphics(); 

  if( evt.id == Event.MOUSE_UP ) 
        { 
            g.setXORMode(Color.white); 
            if( compImage != null ) 
                g.drawImage(compImage,prevPoint.x-offset.x,prevPoint.y-offset.y,panel); 
            compImage = null; 
            compGraphics = null; 
            panel.setDragMode(false); 



  

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.