Switched to rendering via the Java2D graphics API. Finished up first pass.
Everything mostly works and I can visualize my projects and end up with a useful set of printouts. git-svn-id: https://samskivert.googlecode.com/svn/trunk@186 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -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;
|
package com.samskivert.viztool;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.print.*;
|
||||||
|
|
||||||
import com.samskivert.viztool.enum.*;
|
import com.samskivert.viztool.enum.*;
|
||||||
import com.samskivert.viztool.viz.*;
|
import com.samskivert.viztool.viz.*;
|
||||||
|
|
||||||
@@ -16,6 +19,11 @@ public class Driver
|
|||||||
}
|
}
|
||||||
String pkgroot = args[0];
|
String pkgroot = args[0];
|
||||||
|
|
||||||
|
boolean print = false;
|
||||||
|
if (args.length > 1) {
|
||||||
|
print = (args[1].equals("-print"));
|
||||||
|
}
|
||||||
|
|
||||||
// run ourselves on the classpath
|
// run ourselves on the classpath
|
||||||
String classpath = System.getProperty("java.class.path");
|
String classpath = System.getProperty("java.class.path");
|
||||||
ClassEnumerator enum = new ClassEnumerator(classpath);
|
ClassEnumerator enum = new ClassEnumerator(classpath);
|
||||||
@@ -29,6 +37,33 @@ public class Driver
|
|||||||
// and finally generate the visualization
|
// and finally generate the visualization
|
||||||
PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true);
|
PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true);
|
||||||
HierarchyVisualizer viz = new HierarchyVisualizer(pkgroot, penum);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
+93
-27
@@ -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;
|
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;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cascading chain layout lays out chains in the standard cascading
|
* The cascading chain visualizer lays out chains in the standard
|
||||||
* format that looks something like this:
|
* cascading format that looks something like this:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* Foo
|
* Foo
|
||||||
@@ -19,47 +21,111 @@ import java.util.ArrayList;
|
|||||||
* |
|
* |
|
||||||
* +-> Baz
|
* +-> Baz
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
|
||||||
* It should be used in tandem with the
|
|
||||||
* <code>CascadingChainRenderer</code>.
|
|
||||||
*
|
|
||||||
* @see CascadingChainRenderer
|
|
||||||
*/
|
*/
|
||||||
public class CascadingChainLayout
|
public class CascadingChainVisualizer
|
||||||
implements ChainLayout, CascadingConstants
|
implements ChainVisualizer, CascadingConstants
|
||||||
{
|
{
|
||||||
// docs inherited from interface
|
// 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
|
// the header will be the name of this chain surrounded by N
|
||||||
// points of space and a box
|
// points of space and a box
|
||||||
int hwid = PostscriptUtil.estimateWidth(chain.getName(), pointSize) +
|
Rectangle2D bounds = getTextBox(gfx, layout);
|
||||||
2*HEADER_BORDER;
|
double maxwid = bounds.getWidth();
|
||||||
int hhei = 2*HEADER_BORDER + pointSize;
|
|
||||||
int maxwid = hwid;
|
|
||||||
|
|
||||||
// the children will be below the name of this chain and inset by
|
// the children will be below the name of this chain and inset by
|
||||||
// four points to make space for the connecty lines
|
// 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();
|
ArrayList kids = chain.getChildren();
|
||||||
|
|
||||||
for (int i = 0; i < kids.size(); i++) {
|
for (int i = 0; i < kids.size(); i++) {
|
||||||
Chain kid = (Chain)kids.get(i);
|
Chain kid = (Chain)kids.get(i);
|
||||||
Dimension ksize = kid.getSize();
|
Rectangle2D kbounds = kid.getBounds();
|
||||||
y += GAP; // add the gap
|
y += GAP; // add the gap
|
||||||
kid.setLocation(x, y);
|
kid.setBounds(x, y, kbounds.getWidth(), kbounds.getHeight());
|
||||||
y += ksize.height; // add the dimensions of the kid
|
y += kbounds.getHeight(); // add the dimensions of the kid
|
||||||
// System.err.println("Locating " + kid.getName() +
|
|
||||||
// " at +" + x + "+" + y + ".");
|
|
||||||
// track max width
|
// track max width
|
||||||
if (maxwid < (x + ksize.width)) {
|
if (maxwid < (x + kbounds.getWidth())) {
|
||||||
maxwid = x + ksize.width;
|
maxwid = x + kbounds.getWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the dimensions of the main chain
|
// set the dimensions of the main chain
|
||||||
// System.err.println("Sizing " + chain.getName() +
|
Rectangle2D cbounds = chain.getBounds();
|
||||||
// " to " + maxwid + "x" + y + ".");
|
chain.setBounds(cbounds.getX(), cbounds.getY(), maxwid, y);
|
||||||
chain.setSize(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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.awt.Dimension;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Point;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A chain is used by the hierarchy visualizer to represent inheritance
|
* A chain is used by the hierarchy visualizer to represent inheritance
|
||||||
@@ -48,55 +48,22 @@ public class Chain implements Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a <code>Dimension</code> instance representing the size of
|
* Returns a <code>Rectangle2D</code> instance representing the size
|
||||||
* this chain (and all contained subchains). All coordinates are in
|
* of this chain (and all contained subchains).
|
||||||
* points.
|
|
||||||
*/
|
*/
|
||||||
public Dimension getSize ()
|
public Rectangle2D getBounds ()
|
||||||
{
|
{
|
||||||
return _size;
|
return _bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the location of this chain relative to its parent chain.
|
* Sets the bounds of this chain.
|
||||||
* All coordinates are in points.
|
|
||||||
*/
|
|
||||||
public Point getLocation ()
|
|
||||||
{
|
|
||||||
return _location;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the size of this chain. All coordinates are in points.
|
|
||||||
*
|
*
|
||||||
* @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);
|
_bounds.setRect(x, y, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,16 +82,16 @@ public class Chain implements Element
|
|||||||
* the supplied layout manager arrange those children and compute the
|
* the supplied layout manager arrange those children and compute the
|
||||||
* dimensions of this chain based on all of that information.
|
* 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
|
// first layout our children
|
||||||
for (int i = 0; i < _children.size(); i++) {
|
for (int i = 0; i < _children.size(); i++) {
|
||||||
Chain child = (Chain)_children.get(i);
|
Chain child = (Chain)_children.get(i);
|
||||||
child.layout(pointSize, clay);
|
child.layout(gfx, cviz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now lay ourselves out
|
// 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 Class _root;
|
||||||
|
|
||||||
protected ArrayList _children = new ArrayList();
|
protected ArrayList _children = new ArrayList();
|
||||||
protected Dimension _size = new Dimension(0, 0);
|
protected Rectangle2D _bounds = new Rectangle2D.Double();
|
||||||
protected Point _location = new Point(0, 0);
|
|
||||||
protected int _pageno;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.*;
|
||||||
import java.awt.Point;
|
import java.awt.geom.GeneralPath;
|
||||||
import java.io.PrintStream;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.font.TextLayout;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@@ -32,75 +33,99 @@ public class ChainGroup
|
|||||||
/**
|
/**
|
||||||
* Lays out the chains in this group and returns the total size.
|
* 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
|
// lay out the internal structure of our chains
|
||||||
ChainLayout clay = new CascadingChainLayout();
|
ChainVisualizer clay = new CascadingChainVisualizer();
|
||||||
for (int i = 0; i < _roots.size(); i++) {
|
for (int i = 0; i < _roots.size(); i++) {
|
||||||
Chain chain = (Chain)_roots.get(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
|
// arrange them on the page
|
||||||
ElementLayout elay = new PackedColumnElementLayout();
|
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
|
// for now we're punting and assume that no group will exceed a
|
||||||
// single page in size
|
// single page in size
|
||||||
_size = new Dimension();
|
double width = dims[0].getWidth();
|
||||||
_size.width = dims[0].width + 2*BORDER;
|
double height = dims[0].getHeight() + layout.getAscent();
|
||||||
_size.height = dims[0].height + 2*BORDER;
|
|
||||||
|
|
||||||
|
// 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;
|
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 <code>layoutGroup</code> has previously
|
* This function requires that <code>layoutGroup</code> has previously
|
||||||
* been called to lay out the group's chains.
|
* been called to lay out the group's chains.
|
||||||
*
|
*
|
||||||
* @return the size of the rectangle occupied by the rendered chain
|
|
||||||
* group.
|
|
||||||
*
|
|
||||||
* @see #layoutGroup
|
* @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
|
// render our chains
|
||||||
ChainRenderer renderer = new CascadingChainRenderer();
|
ChainVisualizer renderer = new CascadingChainVisualizer();
|
||||||
for (int i = 0; i < _roots.size(); i++) {
|
for (int i = 0; i < _roots.size(); i++) {
|
||||||
Chain chain = (Chain)_roots.get(i);
|
Chain chain = (Chain)_roots.get(i);
|
||||||
Point loc = chain.getLocation();
|
Rectangle2D bounds = chain.getBounds();
|
||||||
renderer.renderChain(chain, out, pointSize,
|
// render the chain
|
||||||
x + BORDER, y + BORDER);
|
renderer.renderChain(chain, gfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// undo the translation
|
||||||
|
gfx.translate(-cx, -cy);
|
||||||
|
|
||||||
// print our title and a box around our border
|
// print our title and a box around our border
|
||||||
out.println("/tname (" + _pkg + ") def");
|
layout.draw(gfx, (float)(x + BORDER + 2), (float)y);
|
||||||
out.println("/twid tname stringwidth pop def");
|
|
||||||
|
|
||||||
int bx = x + BORDER + 2, by = y - pointSize/2;
|
double height = _size.getHeight() - layout.getAscent();
|
||||||
out.println(bx + " " + by + " moveto");
|
GeneralPath path = new GeneralPath();
|
||||||
out.println("tname abshow");
|
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");
|
public Chain getRoot (int index)
|
||||||
out.println("-" + (BORDER - 2) + " 0 rlineto");
|
{
|
||||||
out.println("0 " + _size.height + " rlineto");
|
return (Chain)_roots.get(index);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String _pkg;
|
protected String _pkg;
|
||||||
protected ArrayList _roots;
|
protected ArrayList _roots;
|
||||||
protected Dimension _size;
|
protected Rectangle2D _size;
|
||||||
|
|
||||||
protected static final int PAGE_WIDTH = (int)(72 * 7.5);
|
protected static final double BORDER = 72/8;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The chain layout is used to compute the dimensions of chains and their
|
* The chain visualizer is used to compute the dimensions of chains and
|
||||||
* children in preparation for rendering them in a particular manner. In
|
* their children in preparation for rendering and then to perform said
|
||||||
* general a layout is coupled with one or more renderers which generate
|
* rendering.
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
public interface ChainLayout
|
public interface ChainVisualizer
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Assigns positions to the children of the supplied chain based on
|
* 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.
|
* (meaning they have dimensions but no position) prior to this call.
|
||||||
*
|
*
|
||||||
* @param chain the chain to be layed out.
|
* @param chain the chain to be layed out.
|
||||||
* @param pointSize the point size of the font to be used in computing
|
* @param gfx the graphics context to use when computing dimensions.
|
||||||
* our dimensions (all coordinates are in points).
|
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
+85
-27
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.*;
|
||||||
import java.awt.Point;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.io.PrintStream;
|
import java.awt.print.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import com.samskivert.viztool.Log;
|
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
|
* representation so that an entire package can be displayed on a single
|
||||||
* page (or small number of pages).
|
* page (or small number of pages).
|
||||||
*/
|
*/
|
||||||
public class HierarchyVisualizer
|
public class HierarchyVisualizer implements Printable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructs a hierarchy visualizer with the supplied enumerator as
|
* Constructs a hierarchy visualizer with the supplied enumerator as
|
||||||
@@ -62,41 +62,95 @@ public class HierarchyVisualizer
|
|||||||
_packages[i], _classes.iterator(), false);
|
_packages[i], _classes.iterator(), false);
|
||||||
_groups[i] = new ChainGroup(pkgroot, _packages[i], penum);
|
_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
|
* Lays out and renders each of the chain groups that make up this
|
||||||
* package hierarchy visualization.
|
* 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
|
// adjust the stroke
|
||||||
out.println("0 setlinewidth");
|
gfx.setStroke(new BasicStroke(0.1f));
|
||||||
|
|
||||||
for (int i = 0; i < _groups.length; i++) {
|
// and the font
|
||||||
// lay out the group in question
|
Font font = new Font("Courier", Font.PLAIN, 8);
|
||||||
Dimension dims = _groups[i].layout(pointSize);
|
gfx.setFont(font);
|
||||||
|
|
||||||
// determine if we need to skip to the next page or not
|
// only relay things out if the page format has changed
|
||||||
if ((y > 0) && (y + dims.height > PAGE_HEIGHT)) {
|
if (!pf.equals(_format)) {
|
||||||
// print the postamble for this page and preamble for the
|
// keep this around
|
||||||
// new page
|
_format = pf;
|
||||||
out.println("showpage");
|
|
||||||
out.println("0 setlinewidth");
|
|
||||||
y = Y_MARGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// render the group at the requested location
|
// and do the layout
|
||||||
_groups[i].render(pointSize, out, x, y);
|
layout(gfx, pf.getImageableX(), pf.getImageableY(),
|
||||||
|
pf.getImageableWidth(), pf.getImageableHeight());
|
||||||
// increment our y location
|
|
||||||
y += (dims.height + GAP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// print the postamble for the final page
|
// render the groups on the requested page
|
||||||
out.println("showpage");
|
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;
|
protected String _pkgroot;
|
||||||
@@ -105,6 +159,10 @@ public class HierarchyVisualizer
|
|||||||
protected String[] _packages;
|
protected String[] _packages;
|
||||||
protected ChainGroup[] _groups;
|
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_WIDTH = (int)(72 * 7.5);
|
||||||
protected static final int PAGE_HEIGHT = (int)(72 * 10);
|
protected static final int PAGE_HEIGHT = (int)(72 * 10);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
@@ -14,10 +14,10 @@ public interface CascadingConstants
|
|||||||
/**
|
/**
|
||||||
* The number of points surrounding the name of the chain.
|
* 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.
|
* The number of points of spacing between each child chain.
|
||||||
*/
|
*/
|
||||||
public static final int GAP = 4;
|
public static final double GAP = 4;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
import java.awt.Point;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.Dimension;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 <code>ElementLayout</code> implementations in a
|
* They can be laid out by <code>ElementLayout</code> implementations in a
|
||||||
* general purpose way.
|
* general purpose way.
|
||||||
*/
|
*/
|
||||||
@@ -19,23 +18,12 @@ public interface Element
|
|||||||
public String getName ();
|
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
|
* Sets the bounds of this element.
|
||||||
* in points.
|
|
||||||
*/
|
*/
|
||||||
public void setLocation (int x, int y);
|
public void setBounds (double x, double y, double width, double height);
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the page number of this element.
|
|
||||||
*/
|
|
||||||
public void setPage (int pageno);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the page number previously set by <code>setPage</code>.
|
|
||||||
*/
|
|
||||||
public int getPage ();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The element layout is used to lay a collection of elements out on a
|
* 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
|
* page. It computes the desired position of each element and sets it via
|
||||||
* <code>setLocation()</code> with the expectation that the location of the
|
* <code>setBounds()</code> with the expectation that the location of the
|
||||||
* elements will be used later in the rendering process.
|
* elements will be used later in the rendering process.
|
||||||
*/
|
*/
|
||||||
public interface ElementLayout
|
public interface ElementLayout
|
||||||
@@ -18,8 +18,9 @@ public interface ElementLayout
|
|||||||
* Lay out the supplied list of elements. Page numbers should be
|
* Lay out the supplied list of elements. Page numbers should be
|
||||||
* assigned to all elements if the layout spans multiple pages.
|
* 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.
|
* 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);
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-23
@@ -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;
|
package com.samskivert.viztool.viz;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lays out the elements in columns of balanced height with elements
|
* Lays out the elements in columns of balanced height with elements
|
||||||
@@ -16,7 +13,8 @@ import java.util.List;
|
|||||||
public class PackedColumnElementLayout implements ElementLayout
|
public class PackedColumnElementLayout implements ElementLayout
|
||||||
{
|
{
|
||||||
// docs inherited from interface
|
// 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
|
// create a new list containing the elements whose order we can
|
||||||
// manipulate willy nilly
|
// manipulate willy nilly
|
||||||
@@ -24,15 +22,22 @@ public class PackedColumnElementLayout implements ElementLayout
|
|||||||
elements.toArray(elems);
|
elements.toArray(elems);
|
||||||
Arrays.sort(elems, HEIGHT_COMP);
|
Arrays.sort(elems, HEIGHT_COMP);
|
||||||
|
|
||||||
|
System.out.println("Laying out in " +
|
||||||
|
pageWidth + "x" + pageHeight + ".");
|
||||||
|
|
||||||
// lay out the elements across the page
|
// lay out the elements across the page
|
||||||
ArrayList pagedims = new ArrayList();
|
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++) {
|
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
|
// see if we fit into this row or not (but force placement if
|
||||||
// we're currently at the left margin)
|
// 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
|
// track our maxwidth
|
||||||
if (x > maxwidth) {
|
if (x > maxwidth) {
|
||||||
maxwidth = x;
|
maxwidth = x;
|
||||||
@@ -41,43 +46,46 @@ public class PackedColumnElementLayout implements ElementLayout
|
|||||||
x = 0;
|
x = 0;
|
||||||
y += (rowheight + GAP);
|
y += (rowheight + GAP);
|
||||||
// reset our max rowheight
|
// reset our max rowheight
|
||||||
rowheight = size.height;
|
rowheight = bounds.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we fit on this page (but force placement if we're
|
// make sure we fit on this page (but force placement if we're
|
||||||
// currently at the top margin)
|
// 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
|
// 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
|
// move to the next page
|
||||||
x = 0;
|
x = 0;
|
||||||
y = 0;
|
y = 0;
|
||||||
rowheight = size.height;
|
rowheight = bounds.getHeight();
|
||||||
maxwidth = 0;
|
maxwidth = 0;
|
||||||
pageno++;
|
pageno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lay this element out at our current coordinates
|
// lay this element out at our current coordinates
|
||||||
elems[i].setLocation(x, y);
|
elems[i].setBounds(x, y, bounds.getWidth(), bounds.getHeight());
|
||||||
elems[i].setPage(pageno);
|
// elems[i].setPage(pageno);
|
||||||
|
System.out.println("Laying out " + elems[i].getName() +
|
||||||
|
" at " + elems[i].getBounds() + ".");
|
||||||
|
|
||||||
// keep track of the maximum row height
|
// keep track of the maximum row height
|
||||||
if (size.height > rowheight) {
|
if (bounds.getHeight() > rowheight) {
|
||||||
rowheight = size.height;
|
rowheight = bounds.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance in the x direction
|
// advance in the x direction
|
||||||
x += (size.width + GAP);
|
x += (bounds.getWidth() + GAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
// take a final stab at our maxwidth
|
// take a final stab at our maxwidth
|
||||||
|
x -= GAP;
|
||||||
if (x > maxwidth) {
|
if (x > maxwidth) {
|
||||||
maxwidth = x;
|
maxwidth = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a note of how big the final page is
|
// make a note of how big the final page is
|
||||||
pagedims.add(new Dimension(maxwidth, y+rowheight));
|
pagedims.add(new Rectangle2D.Double(0, 0, maxwidth, y+rowheight));
|
||||||
Dimension[] dims = new Dimension[pagedims.size()];
|
Rectangle2D[] dims = new Rectangle2D[pagedims.size()];
|
||||||
pagedims.toArray(dims);
|
pagedims.toArray(dims);
|
||||||
return dims;
|
return dims;
|
||||||
}
|
}
|
||||||
@@ -90,7 +98,8 @@ public class PackedColumnElementLayout implements ElementLayout
|
|||||||
Element e2 = (Element)o2;
|
Element e2 = (Element)o2;
|
||||||
|
|
||||||
// tallest element wins
|
// 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
|
// if they are the same height, sort alphabetically
|
||||||
return (diff != 0) ? diff : e1.getName().compareTo(e2.getName());
|
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
|
// 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();
|
protected static final Comparator HEIGHT_COMP = new HeightComparator();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user