Use sensible margins; added support for rendering interfaces implemented

and inner classes declared within the box for the appropriate class.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@193 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-07-17 07:18:09 +00:00
parent c695cdeb41
commit 539f587813
5 changed files with 192 additions and 17 deletions
@@ -1,5 +1,5 @@
// //
// $Id: Driver.java,v 1.4 2001/07/17 06:01:08 mdb Exp $ // $Id: Driver.java,v 1.5 2001/07/17 07:18:09 mdb Exp $
package com.samskivert.viztool; package com.samskivert.viztool;
@@ -49,16 +49,24 @@ public class Driver
if (print) { if (print) {
// we use the print system to render things // we use the print system to render things
PrinterJob job = PrinterJob.getPrinterJob(); PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(viz);
// pop up a dialog to format our pages // pop up a dialog to format our pages
// PageFormat format = job.pageDialog(job.defaultPage()); // PageFormat format = job.pageDialog(job.defaultPage());
PageFormat format = job.defaultPage(); PageFormat format = job.defaultPage();
// use sensible margins
Paper paper = new Paper();
paper.setImageableArea(72*0.5, 72*0.5, 72*7.5, 72*10);
format.setPaper(paper);
// pop up a dialog to control printing // pop up a dialog to control printing
job.printDialog(); job.printDialog();
// use our configured page format
job.setPrintable(viz, format);
try { try {
// invoke the printing process
job.print(); job.print();
} catch (PrinterException pe) { } catch (PrinterException pe) {
pe.printStackTrace(System.err); pe.printStackTrace(System.err);
@@ -1,11 +1,12 @@
// //
// $Id: CascadingChainVisualizer.java,v 1.7 2001/07/17 06:01:08 mdb Exp $ // $Id: CascadingChainVisualizer.java,v 1.8 2001/07/17 07:18:09 mdb Exp $
package com.samskivert.viztool.viz; package com.samskivert.viztool.viz;
import java.awt.Font; import java.awt.Font;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.font.TextLayout; import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import java.awt.geom.*; import java.awt.geom.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -38,6 +39,24 @@ public class CascadingChainVisualizer
// 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
Rectangle2D bounds = getTextBox(gfx, layout); Rectangle2D bounds = getTextBox(gfx, layout);
// add our inner classes and interface implementations, but only
// if we're not an out of package class
if (chain.inPackage()) {
String[] impls = chain.getImplementsNames();
for (int i = 0; i < impls.length; i++) {
bounds = accomodate(bounds, impls[i],
FontPicker.getImplementsFont(),
gfx.getFontRenderContext());
}
String[] decls = chain.getDeclaresNames();
for (int i = 0; i < decls.length; i++) {
bounds = accomodate(bounds, decls[i],
FontPicker.getDeclaresFont(),
gfx.getFontRenderContext());
}
}
double maxwid = bounds.getWidth(); double maxwid = bounds.getWidth();
// 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
@@ -62,6 +81,17 @@ public class CascadingChainVisualizer
chain.setBounds(cbounds.getX(), cbounds.getY(), maxwid, y); chain.setBounds(cbounds.getX(), cbounds.getY(), maxwid, y);
} }
protected Rectangle2D accomodate (Rectangle2D bounds, String name,
Font font, FontRenderContext frc)
{
TextLayout layout = new TextLayout(name, font, frc);
Rectangle2D tbounds = layout.getBounds();
bounds.setRect(bounds.getX(), bounds.getY(),
Math.max(bounds.getWidth(), tbounds.getWidth()+INSET),
bounds.getHeight() + tbounds.getHeight());
return bounds;
}
// docs inherited from interface // docs inherited from interface
public void renderChain (Chain chain, Graphics2D gfx) public void renderChain (Chain chain, Graphics2D gfx)
{ {
@@ -76,16 +106,55 @@ public class CascadingChainVisualizer
TextLayout layout = new TextLayout(chain.getName(), font, TextLayout layout = new TextLayout(chain.getName(), font,
gfx.getFontRenderContext()); gfx.getFontRenderContext());
// stroke a box that will contain the name
Rectangle2D tbounds = getTextBox(gfx, layout); Rectangle2D tbounds = getTextBox(gfx, layout);
double dx = -tbounds.getX(), dy = -tbounds.getY(); double dx = -tbounds.getX(), dy = -tbounds.getY();
tbounds.setRect(x, y, tbounds.getWidth(), tbounds.getHeight()); double maxwid = tbounds.getWidth();
gfx.draw(tbounds);
// now draw the name // draw the name
layout.draw(gfx, (float)(x + dx + HEADER_BORDER), layout.draw(gfx, (float)(x + dx + HEADER_BORDER),
(float)(y + dy + HEADER_BORDER)); (float)(y + dy + HEADER_BORDER));
// draw the interface and inner class info, but only if we're not
// an out of package class
double ix = x + HEADER_BORDER + INSET;
double iy = y + tbounds.getHeight() - HEADER_BORDER;
if (chain.inPackage()) {
String[] impls = chain.getImplementsNames();
for (int i = 0; i < impls.length; i++) {
TextLayout ilay =
new TextLayout(impls[i], FontPicker.getImplementsFont(),
gfx.getFontRenderContext());
Rectangle2D ibounds = ilay.getBounds();
double newwid = ibounds.getWidth() + 2*HEADER_BORDER + INSET;
if (newwid > maxwid) {
maxwid = newwid;
}
ilay.draw(gfx, (float)(ix - ibounds.getX()),
(float)(iy - ibounds.getY()));
iy += ibounds.getHeight();
}
String[] decls = chain.getDeclaresNames();
for (int i = 0; i < decls.length; i++) {
TextLayout ilay =
new TextLayout(decls[i], FontPicker.getDeclaresFont(),
gfx.getFontRenderContext());
Rectangle2D ibounds = ilay.getBounds();
double newwid = ibounds.getWidth() + 2*HEADER_BORDER + INSET;
if (newwid > maxwid) {
maxwid = newwid;
}
ilay.draw(gfx, (float)(ix - ibounds.getX()),
(float)(iy - ibounds.getY()));
iy += ibounds.getHeight();
}
}
// stroke a box that will contain the name
tbounds.setRect(x, y, maxwid, iy - y + HEADER_BORDER);
gfx.draw(tbounds);
// render our connecty lines // render our connecty lines
ArrayList kids = chain.getChildren(); ArrayList kids = chain.getChildren();
if (kids.size() > 0) { if (kids.size() > 0) {
@@ -139,4 +208,10 @@ public class CascadingChainVisualizer
* The number of points of spacing between each child chain. * The number of points of spacing between each child chain.
*/ */
protected static final double GAP = 4; protected static final double GAP = 4;
/**
* The number of points that interfaces and inner class declarations
* are indented.
*/
protected static final double INSET = 3;
} }
@@ -1,5 +1,5 @@
// //
// $Id: Chain.java,v 1.4 2001/07/17 01:54:19 mdb Exp $ // $Id: Chain.java,v 1.5 2001/07/17 07:18:09 mdb Exp $
package com.samskivert.viztool.viz; package com.samskivert.viztool.viz;
@@ -16,10 +16,11 @@ public class Chain implements Element
/** /**
* Constructs a chain with the specified class as its root. * Constructs a chain with the specified class as its root.
*/ */
public Chain (String name, Class root) public Chain (String name, Class root, boolean inpkg)
{ {
_name = name; _name = name;
_root = root; _root = root;
_inpkg = inpkg;
} }
/** /**
@@ -39,6 +40,15 @@ public class Chain implements Element
return _root; return _root;
} }
/**
* Returns true if the class represented by this point in the chain is
* in the package we are visualizing, false if it is not.
*/
public boolean inPackage ()
{
return _inpkg;
}
/** /**
* Returns the name of the class that forms the root of this chain. * Returns the name of the class that forms the root of this chain.
*/ */
@@ -47,6 +57,77 @@ public class Chain implements Element
return _root.getName(); return _root.getName();
} }
/**
* Returns the names of the interfaces implemented by this class.
*/
public String[] getImplementsNames ()
{
Class[] ifaces = _root.getInterfaces();
String[] names = new String[ifaces.length];
String pkg = ChainUtil.pkgFromClass(_root.getName());
for (int i = 0; i < ifaces.length; i++) {
String name = ifaces[i].getName();
String ipkg = ChainUtil.pkgFromClass(name);
if (pkg.equals(ipkg)) {
names[i] = ChainUtil.nameFromClass(name);
} else {
names[i] = removeOverlap(pkg, name);
}
}
return names;
}
protected static String removeOverlap (String pkg, String name)
{
// strip off package elements until we've eliminated all but one
// level of overlap
String overlap = "";
int didx;
while ((didx = pkg.indexOf(".", overlap.length()+1)) != -1) {
// see if this chunk still overlaps
String prefix = pkg.substring(0, didx);
if (name.startsWith(prefix)) {
overlap = prefix;
} else {
// we've stopped overlapping, we need to back up one
// element and then we're good to go
if ((didx = overlap.lastIndexOf(".")) == -1) {
overlap = "";
} else {
overlap = overlap.substring(0, didx);
}
break;
}
}
// if there's an overlap, remove it
if (overlap.length() > 0) {
return ".." + name.substring(overlap.length());
} else {
return name;
}
}
/**
* Returns the names of the inner classes declared by this class.
*/
public String[] getDeclaresNames ()
{
Class[] decls = _root.getDeclaredClasses();
String[] names = new String[decls.length];
for (int i = 0; i < decls.length; i++) {
String name = decls[i].getName();
int didx = name.indexOf("$");
names[i] = (didx == -1) ? name : name.substring(didx+1);
}
return names;
}
/** /**
* Returns a <code>Rectangle2D</code> instance representing the size * Returns a <code>Rectangle2D</code> instance representing the size
* of this chain (and all contained subchains). * of this chain (and all contained subchains).
@@ -100,7 +181,11 @@ public class Chain implements Element
*/ */
public void addClass (String name, Class child) public void addClass (String name, Class child)
{ {
Chain chain = new Chain(name, child); // we assume that the addition of a derived class is only done for
// classes that are in the package we're visualizing. out of
// package classes are only included as roots of chains that
// subsequently contain classes that are in the package
Chain chain = new Chain(name, child, true);
if (!_children.contains(chain)) { if (!_children.contains(chain)) {
_children.add(chain); _children.add(chain);
} }
@@ -157,6 +242,7 @@ public class Chain implements Element
protected String _name; protected String _name;
protected Class _root; protected Class _root;
protected boolean _inpkg;
protected ArrayList _children = new ArrayList(); protected ArrayList _children = new ArrayList();
protected Rectangle2D _bounds = new Rectangle2D.Double(); protected Rectangle2D _bounds = new Rectangle2D.Double();
@@ -1,5 +1,5 @@
// //
// $Id: ChainUtil.java,v 1.3 2001/07/14 00:55:21 mdb Exp $ // $Id: ChainUtil.java,v 1.4 2001/07/17 07:18:09 mdb Exp $
package com.samskivert.viztool.viz; package com.samskivert.viztool.viz;
@@ -115,7 +115,7 @@ public class ChainUtil
// if we have no parent, we want to insert ourselves as a root // if we have no parent, we want to insert ourselves as a root
// class // class
if (parent == null || parent.equals(Object.class)) { if (parent == null || parent.equals(Object.class)) {
insertRoot(roots, name, target); insertRoot(roots, name, target, true);
} else { } else {
String tpkg = pkgFromClass(target.getName()); String tpkg = pkgFromClass(target.getName());
@@ -125,7 +125,7 @@ public class ChainUtil
// into the hierarchy as a root class // into the hierarchy as a root class
if (!tpkg.equals(ppkg)) { if (!tpkg.equals(ppkg)) {
String pname = generateName(parent, pkgroot, true); String pname = generateName(parent, pkgroot, true);
insertRoot(roots, pname, parent); insertRoot(roots, pname, parent, false);
} }
// and now hang ourselves off of our parent class // and now hang ourselves off of our parent class
@@ -196,9 +196,9 @@ public class ChainUtil
} }
protected static boolean insertRoot (ArrayList roots, String name, protected static boolean insertRoot (ArrayList roots, String name,
Class root) Class root, boolean inpkg)
{ {
Chain chroot = new Chain(name, root); Chain chroot = new Chain(name, root, inpkg);
// make sure no chain already exists for this root // make sure no chain already exists for this root
if (!roots.contains(chroot)) { if (!roots.contains(chroot)) {
roots.add(chroot); roots.add(chroot);
@@ -1,5 +1,5 @@
// //
// $Id: HierarchyVisualizer.java,v 1.6 2001/07/17 05:28:46 mdb Exp $ // $Id: HierarchyVisualizer.java,v 1.7 2001/07/17 07:18:09 mdb Exp $
package com.samskivert.viztool.viz; package com.samskivert.viztool.viz;
@@ -37,7 +37,13 @@ public class HierarchyVisualizer implements Printable
// dump all the classes into an array list so that we can // dump all the classes into an array list so that we can
// repeatedly scan through the list // repeatedly scan through the list
while (iter.hasNext()) { while (iter.hasNext()) {
_classes.add(iter.next()); // strip out inner classes, we'll catch those via their
// declaring classes
String name = (String)iter.next();
if (name.indexOf("$") != -1) {
continue;
}
_classes.add(name);
} }
// compile a list of all packages in our collection // compile a list of all packages in our collection