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);