import java.applet.Applet;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Label;
import java.awt.LayoutManager;
import java.awt.List;
import java.awt.Rectangle;
import java.awt.TextField;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* Applet GUI demo of Gamelan TreeLayout layout manager. Constructs a tree and,
* for each entry, makes a button that jumps to it.
*
* The input language is a file like this: R Java Resources # root L - Resources
* at Sun # label B http://www.sun.com/foo/bar Interesting Stuff # URLbutton B
* http://javasoft.com/b/c More Stuff # URLbutton
*
* The result is (supposedly) a beautiful(?) tree. Each L is a top-level label,
* and each B is in the tree below it.
*
* Could be made much fancier with getParameter("FontName"), "FontSize",
* adjusting width with fontMetrics, etc. Works adequately for now.
*/
public class TreeLinkTest extends Applet {
TreeLayout tl;
public void init() {
tl = new TreeLayout();
setLayout(tl);
Button root = new Button("This is the root");
add("Root", root);
tl.setRoot(root);
Component x = new Label("A random label");
add("label", x);
tl.setParent(x, root);
Component y;
y = new TextField("Add any component");
add("comp", y);
tl.setParent(y, root);
x = new List();
((List) x).add("List entry");
((List) x).add("Similarly useless list entry");
add("list", x);
tl.setParent(x, root);
x = new Button("Extremely long and unnecessary button title");
add("button", x);
tl.setParent(x, y);
x = new MyCanvas(getImage(getDocumentBase(), "icons/tools.gif"));
add("image", x);
tl.setParent(x, y);
}
public void paint(Graphics g) {
super.paint(g);
tl.paintLines(g, getBackground());
}
class MyCanvas extends Canvas {
Image img;
MyCanvas(Image img) {
this.img = img;
}
public Dimension getPreferredSize() {
return new Dimension(64, 64);
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
g.drawImage(img, 0, getSize().height / 2 - 16, 32, 32, this);
}
}
}
/**
* Simple layout manager that arranges its children in a tree. The tree always
* expands to fill the available area, and the internal components are resized
* to fit the area proportional to their preferred size and the actual available
* size.
*
* This layout manager requires several method calls beyond the normal layout
* manager. Please notice the following: * Components must be added using the
* add(String, Component) method. The strings don't have to be unique, but must
* be present. * Each instance must have exactly one root object, which must be
* add()ed, <I>then </I> setRoot()ed. * Each component after the root must first
* be added and then must be connected into the tree using setParent(child,
* parent). * If you want lines between parents and children, you <EM>must
* </EM> call paintLines() from your applet's paint() method.
*
* @author name unknown, xxx@blackdown.org
*/
class TreeLayout implements LayoutManager {
TreeNode root;
Hashtable nodes;
public TreeLayout() {
nodes = new Hashtable();
}
public void addLayoutComponent(String name, Component comp) {
TreeNode tn = new TreeNode(comp);
nodes.put(comp, tn);
}
public void removeLayoutComponent(Component comp) {
nodes.remove(comp);
}
/**
* You <em>must</em> make this call, otherwise none of the components will
* be layed out.
*/
public void setRoot(Component c) {
root = (TreeNode) nodes.get(c);
}
/**
* Sets the tree parent of a child. The components <em>must</em> have been
* previously added. If either component has not previously been added, this
* injunction is silently ignored. Cycles are <em>not</em> checked.
*/
public void setParent(Component child, Component parent) {
TreeNode p = (TreeNode) nodes.get(parent);
TreeNode c = (TreeNode) nodes.get(child);
if ((p != null) && (c != null))
p.addChild(c);
}
public Dimension minimumLayoutSize(Container target) {
Dimension d = root.getMinimumSize();
Insets insets = target.getInsets();
d.width += insets.left + insets.right;
d.height += insets.top + insets.bottom;
return d;
}
public Dimension preferredLayoutSize(Container target) {
Dimension d = root.getPreferredSize();
Insets insets = target.getInsets();
d.width += insets.left + insets.right;
d.height += insets.top + insets.bottom;
return d;
}
public void layoutContainer(Container target) {
Insets insets = target.getInsets();
Dimension d = target.getSize();
Dimension root_pref = root.getPreferredSize();
double xscale = ((double) (d.width - insets.left - insets.right) / (double) (root_pref.width));
double yscale = ((double) (d.height - insets.top - insets.bottom) / (double) (root_pref.height));
root.doLayout(xscale, yscale, insets.left, insets.top);
}
/**
* This piece of hackery is needed since one cant really draw things from a
* layout manager. Call this if you want to draw lines between components.
*/
public void paintLines(Graphics g, Color bg) {
Color dk = bg.darker();
Color br = bg.brighter();
root.paintLines(g, dk, br);
}
}
class TreeNode {
Component comp;
Vector children;
Dimension prefSz, minSz;
TreeNode(Component comp) {
super();
this.comp = comp;
children = new Vector();
}
Dimension getMinimumSize() {
if (!comp.isVisible())
return new Dimension(0, 0);
if (minSz == null) {
Dimension d = comp.getMinimumSize();
minSz = new Dimension(d.width, d.height);
if (children.size() > 0) {
for (Enumeration e = children.elements(); e.hasMoreElements();) {
TreeNode t = (TreeNode) (e.nextElement());
if (t.comp.isVisible()) {
d = t.getMinimumSize();
minSz.height += d.height;
minSz.width = Math.max(d.width, minSz.width);
}
}
}
}
return minSz;
}
Dimension getPreferredSize() {
if (!comp.isVisible())
return new Dimension(0, 0);
if (prefSz == null) {
Dimension d = comp.getPreferredSize();
prefSz = new Dimension(d.width, d.height);
if (children.size() > 0) {
int wmax = 0;
for (Enumeration e = children.elements(); e.hasMoreElements();) {
TreeNode t = (TreeNode) (e.nextElement());
if (t.comp.isVisible()) {
d = t.getPreferredSize();
prefSz.height += d.height;
if (wmax < d.width) {
wmax = d.width;
}
}
}
prefSz.width += wmax;
}
}
return prefSz;
}
void addChild(TreeNode t) {
children.addElement(t);
prefSz = null;
minSz = null;
}
void removeChild(TreeNode t) {
children.removeElement(t);
prefSz = null;
minSz = null;
}
void paintLines(Graphics g, Color dk, Color br) {
if (comp.isVisible()) {
Rectangle b = comp.getBounds();
int x1off = b.x + b.width / 2;
int x2off = b.x + b.width;
int y1off = b.y;
for (Enumeration e = children.elements(); e.hasMoreElements();) {
TreeNode tn = (TreeNode) (e.nextElement());
if (tn.comp.isVisible()) {
Rectangle bn = tn.comp.getBounds();
int y2off = bn.y + bn.height / 2;
g.setColor(dk);
g.drawLine(x1off, y1off, x1off, y2off);
g.drawLine(x1off, y2off - 1, x2off, y2off - 1);
g.setColor(br);
g.drawLine(x1off + 1, y1off, x1off + 1, y2off);
g.drawLine(x1off, y2off, x2off, y2off);
tn.paintLines(g, dk, br);
}
}
}
}
void doLayout(double xscale, double yscale, int x, int y) {
// x and y are the offsets into the
// Container where we start doing the
// goodies for this Node
if (comp.isVisible()) {
Dimension pref = comp.getPreferredSize();
int ht = (int) Math.round(yscale * pref.height);
int wd = (int) Math.round(xscale * pref.width);
ht = (pref.height < ht) ? pref.height : ht;
wd = (pref.width < wd) ? pref.width : wd;
comp.setBounds(x, y, wd, ht);
y += ht;
x += wd;
for (Enumeration e = children.elements(); e.hasMoreElements();) {
TreeNode tn = (TreeNode) (e.nextElement());
if (tn.comp.isVisible()) {
pref = tn.getPreferredSize();
tn.doLayout(xscale, yscale, x, y);
y += (int) Math.round(yscale * pref.height);
}
}
}
}
}
|