diff --git a/projects/viztool/src/java/com/samskivert/viztool/Driver.java b/projects/viztool/src/java/com/samskivert/viztool/Driver.java index 0b1e3d0d..c2f886f8 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/Driver.java +++ b/projects/viztool/src/java/com/samskivert/viztool/Driver.java @@ -1,8 +1,11 @@ // -// $Id: Driver.java,v 1.1 2001/07/14 00:55:21 mdb Exp $ +// $Id: Driver.java,v 1.2 2001/07/17 01:54:19 mdb Exp $ package com.samskivert.viztool; +import java.awt.*; +import java.awt.print.*; + import com.samskivert.viztool.enum.*; import com.samskivert.viztool.viz.*; @@ -16,6 +19,11 @@ public class Driver } String pkgroot = args[0]; + boolean print = false; + if (args.length > 1) { + print = (args[1].equals("-print")); + } + // run ourselves on the classpath String classpath = System.getProperty("java.class.path"); ClassEnumerator enum = new ClassEnumerator(classpath); @@ -29,6 +37,33 @@ public class Driver // and finally generate the visualization PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true); HierarchyVisualizer viz = new HierarchyVisualizer(pkgroot, penum); - viz.render(10, System.out); + + if (print) { + // we use the print system to render things + PrinterJob job = PrinterJob.getPrinterJob(); + // pop up a dialog to format our pages + // PageFormat format = job.pageDialog(job.defaultPage()); + PageFormat format = job.defaultPage(); + job.setPrintable(viz); + // pop up a dialog to control printing + job.printDialog(); + + try { + job.print(); + } catch (PrinterException pe) { + pe.printStackTrace(System.err); + } + System.exit(0); + } else { + TestFrame frame = new TestFrame(viz); + + // center the frame in the screen and show it + Toolkit tk = frame.getToolkit(); + Dimension ss = tk.getScreenSize(); + int width = 640, height = 480; + frame.setBounds((ss.width-width)/2, (ss.height-height)/2, + width, height); + frame.setVisible(true); + } } } diff --git a/projects/viztool/src/java/com/samskivert/viztool/VizFrame.java b/projects/viztool/src/java/com/samskivert/viztool/VizFrame.java new file mode 100644 index 00000000..264996d2 --- /dev/null +++ b/projects/viztool/src/java/com/samskivert/viztool/VizFrame.java @@ -0,0 +1,23 @@ +// +// $Id: VizFrame.java,v 1.1 2001/07/17 01:54:19 mdb Exp $ + +package com.samskivert.viztool; + +import java.awt.BorderLayout; +import javax.swing.*; + +import com.samskivert.viztool.viz.HierarchyVisualizer; + +public class TestFrame extends JFrame +{ + public TestFrame (HierarchyVisualizer viz) + { + super("Test Frame"); + + // quit if we're closed + setDefaultCloseOperation(EXIT_ON_CLOSE); + + TestPanel panel = new TestPanel(viz); + getContentPane().add(panel, BorderLayout.CENTER); + } +} diff --git a/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java b/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java new file mode 100644 index 00000000..1f5f4ffc --- /dev/null +++ b/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java @@ -0,0 +1,32 @@ +// +// $Id: VizPanel.java,v 1.1 2001/07/17 01:54:19 mdb Exp $ + +package com.samskivert.viztool; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import javax.swing.*; + +import com.samskivert.viztool.viz.HierarchyVisualizer; + +public class TestPanel extends JPanel +{ + public TestPanel (HierarchyVisualizer viz) + { + _viz = viz; + + // set the font + Font font = new Font("Courier", Font.PLAIN, 10); + setFont(font); + } + + public void paintComponent (Graphics g) + { + Graphics2D gfx = (Graphics2D)g; + Rectangle2D bounds = getBounds(); + _viz.layout(gfx, 0, 0, bounds.getWidth(), bounds.getHeight()); + _viz.paint(gfx, 0); + } + + protected HierarchyVisualizer _viz; +} diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java index 6caf8ce4..6aab73ce 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java @@ -1,14 +1,16 @@ // -// $Id: CascadingChainVisualizer.java,v 1.2 2001/07/14 00:55:21 mdb Exp $ +// $Id: CascadingChainVisualizer.java,v 1.3 2001/07/17 01:54:19 mdb Exp $ package com.samskivert.viztool.viz; -import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.*; +import java.awt.font.TextLayout; import java.util.ArrayList; /** - * The cascading chain layout lays out chains in the standard cascading - * format that looks something like this: + * The cascading chain visualizer lays out chains in the standard + * cascading format that looks something like this: * *
* Foo @@ -19,47 +21,111 @@ import java.util.ArrayList; * | * +-> Baz *- * - * It should be used in tandem with the - *
CascadingChainRenderer.
- *
- * @see CascadingChainRenderer
*/
-public class CascadingChainLayout
- implements ChainLayout, CascadingConstants
+public class CascadingChainVisualizer
+ implements ChainVisualizer, CascadingConstants
{
// docs inherited from interface
- public void layoutChain (Chain chain, int pointSize)
+ public void layoutChain (Chain chain, Graphics2D gfx)
{
+ // create a text layout based on the current rendering conditions
+ TextLayout layout = new TextLayout(chain.getName(), gfx.getFont(),
+ gfx.getFontRenderContext());
+
// the header will be the name of this chain surrounded by N
// points of space and a box
- int hwid = PostscriptUtil.estimateWidth(chain.getName(), pointSize) +
- 2*HEADER_BORDER;
- int hhei = 2*HEADER_BORDER + pointSize;
- int maxwid = hwid;
+ Rectangle2D bounds = getTextBox(gfx, layout);
+ double maxwid = bounds.getWidth();
// the children will be below the name of this chain and inset by
// four points to make space for the connecty lines
- int x = 2*GAP, y = hhei;
+ double x = 2*GAP, y = bounds.getHeight();
ArrayList kids = chain.getChildren();
for (int i = 0; i < kids.size(); i++) {
Chain kid = (Chain)kids.get(i);
- Dimension ksize = kid.getSize();
+ Rectangle2D kbounds = kid.getBounds();
y += GAP; // add the gap
- kid.setLocation(x, y);
- y += ksize.height; // add the dimensions of the kid
-// System.err.println("Locating " + kid.getName() +
-// " at +" + x + "+" + y + ".");
+ kid.setBounds(x, y, kbounds.getWidth(), kbounds.getHeight());
+ y += kbounds.getHeight(); // add the dimensions of the kid
// track max width
- if (maxwid < (x + ksize.width)) {
- maxwid = x + ksize.width;
+ if (maxwid < (x + kbounds.getWidth())) {
+ maxwid = x + kbounds.getWidth();
}
}
// set the dimensions of the main chain
-// System.err.println("Sizing " + chain.getName() +
-// " to " + maxwid + "x" + y + ".");
- chain.setSize(maxwid, y);
+ Rectangle2D cbounds = chain.getBounds();
+ chain.setBounds(cbounds.getX(), cbounds.getY(), maxwid, y);
+ }
+
+ // docs inherited from interface
+ public void renderChain (Chain chain, Graphics2D gfx)
+ {
+ // figure out where we'll be rendering
+ Rectangle2D bounds = chain.getBounds();
+ double x = bounds.getX();
+ double y = bounds.getY();
+
+// System.err.println("Rendering " + chain.getName() +
+// " at +" + x + "+" + y + ".");
+
+ // create a text layout based on the current rendering conditions
+ TextLayout layout = new TextLayout(chain.getName(), gfx.getFont(),
+ gfx.getFontRenderContext());
+
+ // stroke a box that will contain the name
+ Rectangle2D tbounds = getTextBox(gfx, layout);
+ double tx = -bounds.getX(), ty = -bounds.getY();
+ tbounds.setRect(x, y, tbounds.getWidth(), tbounds.getHeight());
+ gfx.draw(tbounds);
+
+ // now draw the name
+ layout.draw(gfx, (float)(x + HEADER_BORDER),
+ (float)(y + layout.getAscent() + HEADER_BORDER));
+
+ // render our connecty lines
+ ArrayList kids = chain.getChildren();
+ if (kids.size() > 0) {
+ GeneralPath path = new GeneralPath();
+ Rectangle2D kbounds = ((Chain)kids.get(0)).getBounds();
+ double half = kbounds.getX()/2;
+ path.moveTo((float)(x + half), (float)(y + tbounds.getHeight()));
+
+ for (int i = 0; i < kids.size(); i++) {
+ Chain kid = (Chain)kids.get(i);
+ kbounds = kid.getBounds();
+ double ly = y + kbounds.getY() + layout.getAscent() +
+ HEADER_BORDER;
+ path.lineTo((float)(x + half), (float)ly);
+ path.lineTo((float)(x + kbounds.getX()), (float)ly);
+ path.moveTo((float)(x + half), (float)ly);
+ }
+
+ gfx.draw(path);
+ }
+
+ // translate the gfx so that 0,0 is at our origin
+ gfx.translate(x, y);
+
+ // now render the kids
+ for (int i = 0; i < kids.size(); i++) {
+ Chain kid = (Chain)kids.get(i);
+ renderChain(kid, gfx);
+ }
+
+ // undo our prior translation
+ gfx.translate(-x, -y);
+ }
+
+ protected static Rectangle2D getTextBox (Graphics2D gfx,
+ TextLayout layout)
+ {
+ Rectangle2D bounds = layout.getBounds();
+ // incorporate room for the border in the bounds
+ bounds.setRect(bounds.getX(), bounds.getY(),
+ bounds.getWidth() + 2*HEADER_BORDER,
+ bounds.getHeight() + 2*HEADER_BORDER);
+ return bounds;
}
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java
index e3d2a404..981abe00 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java
@@ -1,11 +1,11 @@
//
-// $Id: Chain.java,v 1.3 2001/07/14 00:55:21 mdb Exp $
+// $Id: Chain.java,v 1.4 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
import java.util.ArrayList;
-import java.awt.Dimension;
-import java.awt.Point;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
/**
* A chain is used by the hierarchy visualizer to represent inheritance
@@ -48,55 +48,22 @@ public class Chain implements Element
}
/**
- * Returns a Dimension instance representing the size of
- * this chain (and all contained subchains). All coordinates are in
- * points.
+ * Returns a Rectangle2D instance representing the size
+ * of this chain (and all contained subchains).
*/
- public Dimension getSize ()
+ public Rectangle2D getBounds ()
{
- return _size;
+ return _bounds;
}
/**
- * Returns the location of this chain relative to its parent chain.
- * All coordinates are in points.
- */
- public Point getLocation ()
- {
- return _location;
- }
-
- /**
- * Sets the size of this chain. All coordinates are in points.
+ * Sets the bounds of this chain.
*
- * @see #getSize
+ * @see #getBounds
*/
- public void setSize (int width, int height)
+ public void setBounds (double x, double y, double width, double height)
{
- _size = new Dimension(width, height);
- }
-
- /**
- * Sets the location of this chain relative to its parent. All
- * coordinates are in points.
- *
- * @see #getLocation
- */
- public void setLocation (int x, int y)
- {
- _location = new Point(x, y);
- }
-
- // inherited from interface
- public void setPage (int pageno)
- {
- _pageno = pageno;
- }
-
- // inherited from interface
- public int getPage ()
- {
- return _pageno;
+ _bounds.setRect(x, y, width, height);
}
/**
@@ -115,16 +82,16 @@ public class Chain implements Element
* the supplied layout manager arrange those children and compute the
* dimensions of this chain based on all of that information.
*/
- public void layout (int pointSize, ChainLayout clay)
+ public void layout (Graphics2D gfx, ChainVisualizer cviz)
{
// first layout our children
for (int i = 0; i < _children.size(); i++) {
Chain child = (Chain)_children.get(i);
- child.layout(pointSize, clay);
+ child.layout(gfx, cviz);
}
// now lay ourselves out
- clay.layoutChain(this, pointSize);
+ cviz.layoutChain(this, gfx);
}
/**
@@ -192,7 +159,5 @@ public class Chain implements Element
protected Class _root;
protected ArrayList _children = new ArrayList();
- protected Dimension _size = new Dimension(0, 0);
- protected Point _location = new Point(0, 0);
- protected int _pageno;
+ protected Rectangle2D _bounds = new Rectangle2D.Double();
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java
index 1134c362..0f4c0a2c 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java
@@ -1,11 +1,12 @@
//
-// $Id: ChainGroup.java,v 1.1 2001/07/14 00:55:21 mdb Exp $
+// $Id: ChainGroup.java,v 1.2 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
-import java.awt.Dimension;
-import java.awt.Point;
-import java.io.PrintStream;
+import java.awt.*;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.awt.font.TextLayout;
import java.util.ArrayList;
import java.util.Iterator;
@@ -32,75 +33,99 @@ public class ChainGroup
/**
* Lays out the chains in this group and returns the total size.
*/
- public Dimension layout (int pointSize)
+ public Rectangle2D layout (Graphics2D gfx, double pageWidth,
+ double pageHeight)
{
// lay out the internal structure of our chains
- ChainLayout clay = new CascadingChainLayout();
+ ChainVisualizer clay = new CascadingChainVisualizer();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
- chain.layout(pointSize, clay);
+ chain.layout(gfx, clay);
}
+ // we'll need room to incorporate our title
+ TextLayout layout = new TextLayout(_pkg, gfx.getFont(),
+ gfx.getFontRenderContext());
+
+ // keep room for our border
+ pageWidth -= 2*BORDER;
+ pageHeight -= (2*BORDER + layout.getAscent());
+
// arrange them on the page
ElementLayout elay = new PackedColumnElementLayout();
- Dimension[] dims = elay.layout(_roots, MAX_WIDTH, MAX_HEIGHT);
+ Rectangle2D[] dims = elay.layout(_roots, pageWidth, pageHeight);
// for now we're punting and assume that no group will exceed a
// single page in size
- _size = new Dimension();
- _size.width = dims[0].width + 2*BORDER;
- _size.height = dims[0].height + 2*BORDER;
+ double width = dims[0].getWidth();
+ double height = dims[0].getHeight() + layout.getAscent();
+ // make sure we're wide enough for our title
+ width = Math.max(width, layout.getAdvance() + 4);
+
+ _size = new Rectangle2D.Double();
+ _size.setRect(0, 0, width + 2*BORDER, height + 2*BORDER);
+
+ System.out.println("L(" + _pkg + ") " + _size.getWidth() + "x" +
+ _size.getHeight() + "+" + _size.getX() + "+" + _size.getY() + ".");
return _size;
}
/**
- * Renders the chains in this group to the supplied output stream.
+ * Renders the chains in this group to the supplied graphics object.
* This function requires that layoutGroup has previously
* been called to lay out the group's chains.
*
- * @return the size of the rectangle occupied by the rendered chain
- * group.
- *
* @see #layoutGroup
*/
- public void render (int pointSize, PrintStream out, int x, int y)
+ public void render (Graphics2D gfx, double x, double y)
{
+ TextLayout layout = new TextLayout(_pkg, gfx.getFont(),
+ gfx.getFontRenderContext());
+
+ // shift everything down to the ascent of the title
+ y += layout.getAscent();
+
+ // translate to our rendering area
+ double cx = x + BORDER;
+ double cy = y + BORDER;
+ gfx.translate(cx, cy);
+
// render our chains
- ChainRenderer renderer = new CascadingChainRenderer();
+ ChainVisualizer renderer = new CascadingChainVisualizer();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
- Point loc = chain.getLocation();
- renderer.renderChain(chain, out, pointSize,
- x + BORDER, y + BORDER);
+ Rectangle2D bounds = chain.getBounds();
+ // render the chain
+ renderer.renderChain(chain, gfx);
}
+ // undo the translation
+ gfx.translate(-cx, -cy);
+
// print our title and a box around our border
- out.println("/tname (" + _pkg + ") def");
- out.println("/twid tname stringwidth pop def");
+ layout.draw(gfx, (float)(x + BORDER + 2), (float)y);
- int bx = x + BORDER + 2, by = y - pointSize/2;
- out.println(bx + " " + by + " moveto");
- out.println("tname abshow");
+ double height = _size.getHeight() - layout.getAscent();
+ GeneralPath path = new GeneralPath();
+ path.moveTo((float)(x + BORDER), (float)y);
+ path.lineTo((float)x, (float)y);
+ path.lineTo((float)x, (float)(y + height));
+ path.lineTo((float)(x + _size.getWidth()),
+ (float)(y + height));
+ path.lineTo((float)(x + _size.getWidth()), (float)y);
+ path.lineTo((float)(x + BORDER + layout.getAdvance() + 4), (float)y);
+ gfx.draw(path);
+ }
- out.println((x + BORDER - 2) + " " + y + " moveto");
- out.println("-" + (BORDER - 2) + " 0 rlineto");
- out.println("0 " + _size.height + " rlineto");
- out.println(_size.width + " 0 rlineto");
- out.println("0 -" + _size.height + " rlineto");
- out.println((_size.width - BORDER - 4) + " twid sub neg 0 rlineto");
- out.println("stroke");
+ public Chain getRoot (int index)
+ {
+ return (Chain)_roots.get(index);
}
protected String _pkg;
protected ArrayList _roots;
- protected Dimension _size;
+ protected Rectangle2D _size;
- protected static final int PAGE_WIDTH = (int)(72 * 7.5);
- protected static final int PAGE_HEIGHT = (int)(72 * 10);
-
- protected static final int BORDER = 72/8;
-
- protected static final int MAX_WIDTH = PAGE_WIDTH - 2*BORDER;
- protected static final int MAX_HEIGHT = PAGE_HEIGHT - 2*BORDER;
+ protected static final double BORDER = 72/8;
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainVisualizer.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainVisualizer.java
index b20bc3e9..12d8317a 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainVisualizer.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainVisualizer.java
@@ -1,20 +1,16 @@
//
-// $Id: ChainVisualizer.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
+// $Id: ChainVisualizer.java,v 1.2 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
+import java.awt.Graphics2D;
+
/**
- * The chain layout is used to compute the dimensions of chains and their
- * children in preparation for rendering them in a particular manner. In
- * general a layout is coupled with one or more renderers which generate
- * the proper rendering instructions based on the layout information
- * computed by this layout manager. The reason rendering is decoupled from
- * layout is to facilitate easier support for rendering the same layout
- * via different formatting languages (postscript and vml for example).
- *
- * @see ChainRenderer
+ * The chain visualizer is used to compute the dimensions of chains and
+ * their children in preparation for rendering and then to perform said
+ * rendering.
*/
-public interface ChainLayout
+public interface ChainVisualizer
{
/**
* Assigns positions to the children of the supplied chain based on
@@ -25,8 +21,16 @@ public interface ChainLayout
* (meaning they have dimensions but no position) prior to this call.
*
* @param chain the chain to be layed out.
- * @param pointSize the point size of the font to be used in computing
- * our dimensions (all coordinates are in points).
+ * @param gfx the graphics context to use when computing dimensions.
*/
- public void layoutChain (Chain chain, int pointSize);
+ public void layoutChain (Chain chain, Graphics2D gfx);
+
+ /**
+ * Renders the specified chain (and its subchains) based on the layout
+ * information (dimensions) already computed for this chain.
+ *
+ * @param chain the chain to be rendered.
+ * @param gfx the graphics context in which to render the chain.
+ */
+ public void renderChain (Chain chain, Graphics2D gfx);
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java
index e376a58e..d791a104 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java
@@ -1,11 +1,11 @@
//
-// $Id: HierarchyVisualizer.java,v 1.3 2001/07/14 00:55:21 mdb Exp $
+// $Id: HierarchyVisualizer.java,v 1.4 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
-import java.awt.Dimension;
-import java.awt.Point;
-import java.io.PrintStream;
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.print.*;
import java.util.*;
import com.samskivert.viztool.Log;
@@ -17,7 +17,7 @@ import com.samskivert.util.Comparators;
* representation so that an entire package can be displayed on a single
* page (or small number of pages).
*/
-public class HierarchyVisualizer
+public class HierarchyVisualizer implements Printable
{
/**
* Constructs a hierarchy visualizer with the supplied enumerator as
@@ -62,41 +62,95 @@ public class HierarchyVisualizer
_packages[i], _classes.iterator(), false);
_groups[i] = new ChainGroup(pkgroot, _packages[i], penum);
}
+
+ // we'll need these for later
+ _bounds = new Rectangle2D.Double[_packages.length];
+ _pagenos = new int[_packages.length];
}
/**
* Lays out and renders each of the chain groups that make up this
* package hierarchy visualization.
*/
- public void render (int pointSize, PrintStream out)
+ public int print (Graphics g, PageFormat pf, int pageIndex)
+ throws PrinterException
{
- int x = X_MARGIN, y = Y_MARGIN;
+ Graphics2D gfx = (Graphics2D)g;
- // print the preamble for the first page
- out.println("0 setlinewidth");
+ // adjust the stroke
+ gfx.setStroke(new BasicStroke(0.1f));
- for (int i = 0; i < _groups.length; i++) {
- // lay out the group in question
- Dimension dims = _groups[i].layout(pointSize);
+ // and the font
+ Font font = new Font("Courier", Font.PLAIN, 8);
+ gfx.setFont(font);
- // determine if we need to skip to the next page or not
- if ((y > 0) && (y + dims.height > PAGE_HEIGHT)) {
- // print the postamble for this page and preamble for the
- // new page
- out.println("showpage");
- out.println("0 setlinewidth");
- y = Y_MARGIN;
- }
+ // only relay things out if the page format has changed
+ if (!pf.equals(_format)) {
+ // keep this around
+ _format = pf;
- // render the group at the requested location
- _groups[i].render(pointSize, out, x, y);
-
- // increment our y location
- y += (dims.height + GAP);
+ // and do the layout
+ layout(gfx, pf.getImageableX(), pf.getImageableY(),
+ pf.getImageableWidth(), pf.getImageableHeight());
}
- // print the postamble for the final page
- out.println("showpage");
+ // render the groups on the requested page
+ int rendered = 0;
+ for (int i = 0; i < _groups.length; i++) {
+ // skip groups not on this page
+ if (_pagenos[i] != pageIndex) {
+ continue;
+ }
+ _groups[i].render(gfx, _bounds[i].getX(), _bounds[i].getY());
+ rendered++;
+ }
+
+ return (rendered > 0) ? PAGE_EXISTS : NO_SUCH_PAGE;
+ }
+
+ public void layout (Graphics2D gfx, double x, double y,
+ double width, double height)
+ {
+ double starty = x;
+ int pageno = 0;
+
+ System.out.println("Laying out " + width + "x" + height +
+ "+" + x + "+" + y + ".");
+
+ // lay out our groups
+ for (int i = 0; i < _groups.length; i++) {
+ // lay out the group in question
+ Rectangle2D bounds = _groups[i].layout(gfx, width, height);
+
+ // determine if we need to skip to the next page or not
+ if ((y > 0) && (y + bounds.getHeight() > height)) {
+ y = starty;
+ pageno++;
+ }
+
+ // assign x and y coordinates to this group
+ bounds.setRect(x, y, bounds.getWidth(), bounds.getHeight());
+ // and store it
+ _bounds[i] = bounds;
+ // also make a note of our page index
+ _pagenos[i] = pageno;
+
+ // increment our y location
+ y += (bounds.getHeight() + GAP);
+ }
+ }
+
+ public void paint (Graphics2D gfx, int pageIndex)
+ {
+ // render the groups on the requested page
+ for (int i = 0; i < _groups.length; i++) {
+ // skip groups not on this page
+ if (_pagenos[i] != pageIndex) {
+ continue;
+ }
+ _groups[i].render((Graphics2D)gfx,
+ _bounds[i].getX(), _bounds[i].getY());
+ }
}
protected String _pkgroot;
@@ -105,6 +159,10 @@ public class HierarchyVisualizer
protected String[] _packages;
protected ChainGroup[] _groups;
+ protected PageFormat _format;
+ protected Rectangle2D[] _bounds;
+ protected int[] _pagenos;
+
protected static final int PAGE_WIDTH = (int)(72 * 7.5);
protected static final int PAGE_HEIGHT = (int)(72 * 10);
diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingChainRenderer.java b/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingChainRenderer.java
deleted file mode 100644
index 1e3321df..00000000
--- a/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingChainRenderer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// $Id: CascadingChainRenderer.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
-
-package com.samskivert.viztool.viz;
-
-import java.awt.Dimension;
-import java.awt.Point;
-import java.io.PrintStream;
-import java.util.ArrayList;
-
-/**
- * Renders a chain that has been layed out by the cascading chain layout
- * manager.
- *
- * @see CascadingChainLayout
- */
-public class CascadingChainRenderer
- implements ChainRenderer, CascadingConstants
-{
- // docs inherited from interface
- public void renderChain (Chain chain, PrintStream out,
- int pointSize, int x, int y)
- {
- Point loc = chain.getLocation();
-
- // figure out where we'll be located
- x += loc.x;
- y += loc.y;
-
-// System.err.println("Rendering " + chain.getName() +
-// " at +" + x + "+" + y + ".");
-
- // work out some useful stuff
- out.println("gsave");
- out.println("/size " + pointSize + " def");
- out.println(x + " " + y + " translate");
- out.println("/cname (" + chain.getName() + ") def");
- out.println("/nwid cname stringwidth pop def");
- out.println("/nhei size def");
- out.println("/border " + HEADER_BORDER + " def");
- out.println("/dborder border 2 mul def");
-
- // stroke a box that will contain the name
- out.println("0 0 nwid dborder add nhei dborder add rectstroke");
-// out.println("border border nwid nhei rectstroke");
- out.println("border border moveto cname abshow");
-
- // render our connecty lines
- ArrayList kids = chain.getChildren();
- if (kids.size() > 0) {
- Point kloc = ((Chain)kids.get(0)).getLocation();
- int half = kloc.x/2;
- out.println(half + " nhei dborder add moveto");
-
- for (int i = 0; i < kids.size(); i++) {
- Chain kid = (Chain)kids.get(i);
- kloc = kid.getLocation();
- out.println(half + " " +
- (kloc.y + pointSize/2 + HEADER_BORDER) + " lineto");
- out.println(half + " 0 rlineto");
- out.println(half + " neg 0 rmoveto");
- }
- out.println("stroke");
- }
- out.println("grestore");
-
- // now render the kids
- for (int i = 0; i < kids.size(); i++) {
- Chain kid = (Chain)kids.get(i);
- renderChain(kid, out, pointSize, x, y);
- }
- }
-}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingConstants.java b/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingConstants.java
index c1acf0c2..878d7298 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingConstants.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/layout/CascadingConstants.java
@@ -1,5 +1,5 @@
//
-// $Id: CascadingConstants.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
+// $Id: CascadingConstants.java,v 1.2 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
@@ -14,10 +14,10 @@ public interface CascadingConstants
/**
* The number of points surrounding the name of the chain.
*/
- public static final int HEADER_BORDER = 3;
+ public static final double HEADER_BORDER = 3;
/**
* The number of points of spacing between each child chain.
*/
- public static final int GAP = 4;
+ public static final double GAP = 4;
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/ChainRenderer.java b/projects/viztool/src/java/com/samskivert/viztool/layout/ChainRenderer.java
deleted file mode 100644
index bd17c9cd..00000000
--- a/projects/viztool/src/java/com/samskivert/viztool/layout/ChainRenderer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// $Id: ChainRenderer.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
-
-package com.samskivert.viztool.viz;
-
-import java.io.PrintStream;
-
-/**
- * The chain renderer is used to generate rendering output based on a
- * previously layed-out chain. This generally means that renderers are
- * tightly coupled to layout managers. This is intentional and the
- * decoupling that exists only exists to facilitate multiple renderer
- * implementations for multiple output formats (postscript and vml, for
- * example).
- *
- * @see ChainLayout
- */
-public interface ChainRenderer
-{
- /**
- * Generates rendering instructions for the specified chain (and its
- * subchains) based on the layout information (dimensions) already
- * computed for this chain.
- *
- * @param chain the chain to be rendered.
- * @param out the output stream on which to write the rendering
- * instructions.
- * @param pointSize the point size of the font to be used when
- * rendering this chain.
- * @param x the x coordinate at which to render the chain (any
- * relative coordinates maintained by the chain should be used as
- * offsets to this absolute coordinate).
- * @param y the y coordinate at which to render the chain.
- */
- public void renderChain (Chain chain, PrintStream out,
- int pointSize, int x, int y);
-}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/Element.java b/projects/viztool/src/java/com/samskivert/viztool/layout/Element.java
index 06924f8c..498ebf31 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/layout/Element.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/layout/Element.java
@@ -1,13 +1,12 @@
//
-// $Id: Element.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
+// $Id: Element.java,v 1.2 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
-import java.awt.Point;
-import java.awt.Dimension;
+import java.awt.geom.Rectangle2D;
/**
- * A page is composed of elements which have some rectangular dimension.
+ * A page is composed of elements which have some rectangular bounds.
* They can be laid out by ElementLayout implementations in a
* general purpose way.
*/
@@ -19,23 +18,12 @@ public interface Element
public String getName ();
/**
- * Returns the size of this element. All coordinates are in points.
+ * Returns the bounds of this element.
*/
- public Dimension getSize ();
+ public Rectangle2D getBounds ();
/**
- * Sets the upper left position of this element. All coordinates are
- * in points.
+ * Sets the bounds of this element.
*/
- public void setLocation (int x, int y);
-
- /**
- * Sets the page number of this element.
- */
- public void setPage (int pageno);
-
- /**
- * Returns the page number previously set by setPage.
- */
- public int getPage ();
+ public void setBounds (double x, double y, double width, double height);
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java b/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java
index c96adfc0..8e9865e8 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java
@@ -1,15 +1,15 @@
//
-// $Id: ElementLayout.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
+// $Id: ElementLayout.java,v 1.2 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
-import java.awt.Dimension;
+import java.awt.geom.Rectangle2D;
import java.util.List;
/**
* The element layout is used to lay a collection of elements out on a
* page. It computes the desired position of each element and sets it via
- * setLocation() with the expectation that the location of the
+ * setBounds() with the expectation that the location of the
* elements will be used later in the rendering process.
*/
public interface ElementLayout
@@ -18,8 +18,9 @@ public interface ElementLayout
* Lay out the supplied list of elements. Page numbers should be
* assigned to all elements if the layout spans multiple pages.
*
- * @return an array of dimension objects representing the width and
+ * @return an array of rectangle objects representing the width and
* height of each page that was laid out.
*/
- public Dimension[] layout (List elements, int pageWidth, int pageHeight);
+ public Rectangle2D[] layout (List elements,
+ double pageWidth, double pageHeight);
}
diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java b/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java
index 2cdfec99..3369f150 100644
--- a/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java
+++ b/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java
@@ -1,13 +1,10 @@
//
-// $Id: PackedColumnElementLayout.java,v 1.2 2001/07/14 00:55:21 mdb Exp $
+// $Id: PackedColumnElementLayout.java,v 1.3 2001/07/17 01:54:19 mdb Exp $
package com.samskivert.viztool.viz;
-import java.awt.Dimension;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
+import java.awt.geom.Rectangle2D;
+import java.util.*;
/**
* Lays out the elements in columns of balanced height with elements
@@ -16,7 +13,8 @@ import java.util.List;
public class PackedColumnElementLayout implements ElementLayout
{
// docs inherited from interface
- public Dimension[] layout (List elements, int pageWidth, int pageHeight)
+ public Rectangle2D[] layout (List elements,
+ double pageWidth, double pageHeight)
{
// create a new list containing the elements whose order we can
// manipulate willy nilly
@@ -24,15 +22,22 @@ public class PackedColumnElementLayout implements ElementLayout
elements.toArray(elems);
Arrays.sort(elems, HEIGHT_COMP);
+ System.out.println("Laying out in " +
+ pageWidth + "x" + pageHeight + ".");
+
// lay out the elements across the page
ArrayList pagedims = new ArrayList();
- int x = 0, y = 0, rowheight = 0, maxwidth = 0, pageno = 0;
+ double x = 0, y = 0, rowheight = 0, maxwidth = 0;
+ int pageno = 0;
+
for (int i = 0; i < elems.length; i++) {
- Dimension size = elems[i].getSize();
+ Rectangle2D bounds = elems[i].getBounds();
// see if we fit into this row or not (but force placement if
// we're currently at the left margin)
- if ((x > 0) && ((x + size.width) > pageWidth)) {
+ if ((x > 0) && ((x + bounds.getWidth()) > pageWidth)) {
+ // strip off the trailing GAP
+ x -= GAP;
// track our maxwidth
if (x > maxwidth) {
maxwidth = x;
@@ -41,43 +46,46 @@ public class PackedColumnElementLayout implements ElementLayout
x = 0;
y += (rowheight + GAP);
// reset our max rowheight
- rowheight = size.height;
+ rowheight = bounds.getHeight();
}
// make sure we fit on this page (but force placement if we're
// currently at the top margin)
- if ((y > 0) && ((y + size.height) > pageHeight)) {
+ if ((y > 0) && ((y + bounds.getHeight()) > pageHeight)) {
// make a note of how big the current page is
- pagedims.add(new Dimension(maxwidth, y));
+ pagedims.add(new Rectangle2D.Double(0, 0, maxwidth, y));
// move to the next page
x = 0;
y = 0;
- rowheight = size.height;
+ rowheight = bounds.getHeight();
maxwidth = 0;
pageno++;
}
// lay this element out at our current coordinates
- elems[i].setLocation(x, y);
- elems[i].setPage(pageno);
+ elems[i].setBounds(x, y, bounds.getWidth(), bounds.getHeight());
+// elems[i].setPage(pageno);
+ System.out.println("Laying out " + elems[i].getName() +
+ " at " + elems[i].getBounds() + ".");
// keep track of the maximum row height
- if (size.height > rowheight) {
- rowheight = size.height;
+ if (bounds.getHeight() > rowheight) {
+ rowheight = bounds.getHeight();
}
// advance in the x direction
- x += (size.width + GAP);
+ x += (bounds.getWidth() + GAP);
}
// take a final stab at our maxwidth
+ x -= GAP;
if (x > maxwidth) {
maxwidth = x;
}
// make a note of how big the final page is
- pagedims.add(new Dimension(maxwidth, y+rowheight));
- Dimension[] dims = new Dimension[pagedims.size()];
+ pagedims.add(new Rectangle2D.Double(0, 0, maxwidth, y+rowheight));
+ Rectangle2D[] dims = new Rectangle2D[pagedims.size()];
pagedims.toArray(dims);
return dims;
}
@@ -90,7 +98,8 @@ public class PackedColumnElementLayout implements ElementLayout
Element e2 = (Element)o2;
// tallest element wins
- int diff = e2.getSize().height - e1.getSize().height;
+ int diff = (int)(e2.getBounds().getHeight() -
+ e1.getBounds().getHeight());
// if they are the same height, sort alphabetically
return (diff != 0) ? diff : e1.getName().compareTo(e2.getName());
@@ -103,7 +112,7 @@ public class PackedColumnElementLayout implements ElementLayout
}
// hard coded for now, half inch margins
- protected static final int GAP = 72/4;
+ protected static final double GAP = 72/4;
protected static final Comparator HEIGHT_COMP = new HeightComparator();
}