More progress. Har!

git-svn-id: https://samskivert.googlecode.com/svn/trunk@185 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-07-14 00:55:21 +00:00
parent e8dcfce0db
commit b28665494b
7 changed files with 274 additions and 66 deletions
@@ -0,0 +1,34 @@
//
// $Id: Driver.java,v 1.1 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool;
import com.samskivert.viztool.enum.*;
import com.samskivert.viztool.viz.*;
public class Driver
{
public static void main (String[] args)
{
if (args.length < 1) {
System.err.println("Usage: Driver package_root");
System.exit(-1);
}
String pkgroot = args[0];
// run ourselves on the classpath
String classpath = System.getProperty("java.class.path");
ClassEnumerator enum = new ClassEnumerator(classpath);
// print out the warnings
ClassEnumerator.Warning[] warnings = enum.getWarnings();
for (int i = 0; i < warnings.length; i++) {
System.err.println("Warning: " + warnings[i].reason);
}
// and finally generate the visualization
PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true);
HierarchyVisualizer viz = new HierarchyVisualizer(pkgroot, penum);
viz.render(10, System.out);
}
}
@@ -1,5 +1,5 @@
//
// $Id: CascadingChainVisualizer.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
// $Id: CascadingChainVisualizer.java,v 1.2 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool.viz;
@@ -40,7 +40,7 @@ public class CascadingChainLayout
// the children will be below the name of this chain and inset by
// four points to make space for the connecty lines
int x = GAP, y = hhei;
int x = 2*GAP, y = hhei;
ArrayList kids = chain.getChildren();
for (int i = 0; i < kids.size(); i++) {
@@ -1,5 +1,5 @@
//
// $Id: Chain.java,v 1.2 2001/07/13 23:25:13 mdb Exp $
// $Id: Chain.java,v 1.3 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool.viz;
@@ -16,14 +16,10 @@ public class Chain implements Element
/**
* Constructs a chain with the specified class as its root.
*/
public Chain (String pkgroot, Class root)
public Chain (String name, Class root)
{
_pkgroot = pkgroot;
_name = name;
_root = root;
_name = _root.getName();
if (_name.startsWith(pkgroot)) {
_name = _name.substring(_pkgroot.length()+1);
}
}
/**
@@ -135,9 +131,9 @@ public class Chain implements Element
* Adds a child to this chain. The specified class is assumed to
* directly inherit from the class that is the root of this chain.
*/
public void addClass (Class child)
public void addClass (String name, Class child)
{
Chain chain = new Chain(_pkgroot, child);
Chain chain = new Chain(name, child);
if (!_children.contains(chain)) {
_children.add(chain);
}
@@ -192,9 +188,8 @@ public class Chain implements Element
}
}
protected String _pkgroot;
protected Class _root;
protected String _name;
protected Class _root;
protected ArrayList _children = new ArrayList();
protected Dimension _size = new Dimension(0, 0);
@@ -0,0 +1,106 @@
//
// $Id: ChainGroup.java,v 1.1 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool.viz;
import java.awt.Dimension;
import java.awt.Point;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
/**
* A chain group is used to group together all of the classes from a
* particular package.
*/
public class ChainGroup
{
/**
* Constructs a chain group for a particular package with the
* specified package root and an iterator that is configured only to
* return classes from the specified package.
*/
public ChainGroup (String pkgroot, String pkg, Iterator iter)
{
// keep track of the package
_pkg = pkg;
// process the classes provided by our enumerator
_roots = ChainUtil.buildChains(pkgroot, iter);
}
/**
* Lays out the chains in this group and returns the total size.
*/
public Dimension layout (int pointSize)
{
// lay out the internal structure of our chains
ChainLayout clay = new CascadingChainLayout();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
chain.layout(pointSize, clay);
}
// arrange them on the page
ElementLayout elay = new PackedColumnElementLayout();
Dimension[] dims = elay.layout(_roots, MAX_WIDTH, MAX_HEIGHT);
// 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;
return _size;
}
/**
* Renders the chains in this group to the supplied output stream.
* This function requires that <code>layoutGroup</code> 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)
{
// render our chains
ChainRenderer renderer = new CascadingChainRenderer();
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);
}
// print our title and a box around our border
out.println("/tname (" + _pkg + ") def");
out.println("/twid tname stringwidth pop def");
int bx = x + BORDER + 2, by = y - pointSize/2;
out.println(bx + " " + by + " moveto");
out.println("tname abshow");
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");
}
protected String _pkg;
protected ArrayList _roots;
protected Dimension _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;
}
@@ -1,5 +1,5 @@
//
// $Id: ChainUtil.java,v 1.2 2001/07/13 23:25:13 mdb Exp $
// $Id: ChainUtil.java,v 1.3 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool.viz;
@@ -71,7 +71,7 @@ public class ChainUtil
void computeRoots (String pkgroot, Iterator iter, ArrayList roots)
{
while (iter.hasNext()) {
insertClass(roots, pkgroot, (String)iter.next());
insertClass(roots, pkgroot, (String)iter.next(), false);
}
}
@@ -79,8 +79,8 @@ public class ChainUtil
* Loads the supplied class and inserts it into the appropriate
* position in the hierarchy based on its inheritance properties.
*/
protected static
void insertClass (ArrayList roots, String pkgroot, String clazz)
protected static void insertClass (
ArrayList roots, String pkgroot, String clazz, boolean outpkg)
{
try {
// sanity check
@@ -92,7 +92,7 @@ public class ChainUtil
}
// load and insert the class
insertClass(roots, pkgroot, Class.forName(clazz));
insertClass(roots, pkgroot, Class.forName(clazz), outpkg);
} catch (Exception e) {
Log.warning("Unable to process class [class=" + clazz +
@@ -105,22 +105,27 @@ public class ChainUtil
* Inserts the specified class into the appropriate position in the
* hierarchy based on its inheritance properties.
*/
protected static
void insertClass (ArrayList roots, String pkgroot, Class target)
protected static void insertClass (
ArrayList roots, String pkgroot, Class target, boolean outpkg)
{
// insert the parent of this class into the hierarchy
Class parent = target.getSuperclass();
String name = generateName(target, pkgroot, outpkg);
// if we have no parent, we want to insert ourselves as a root
// class
if (parent == null || parent.equals(Object.class)) {
insertRoot(roots, pkgroot, target);
insertRoot(roots, name, target);
} else {
String tpkg = pkgFromClass(target.getName());
String ppkg = pkgFromClass(parent.getName());
// if our parent is not in this package, we want to insert it
// into the hierarchy as a root class
if (!parent.getName().startsWith(pkgroot)) {
insertRoot(roots, pkgroot, parent);
if (!tpkg.equals(ppkg)) {
String pname = generateName(parent, pkgroot, true);
insertRoot(roots, pname, parent);
}
// and now hang ourselves off of our parent class
@@ -128,7 +133,9 @@ public class ChainUtil
if (chain == null) {
// if there's no chain for our parent class, we'll need to
// insert it into the hierarchy
insertClass(roots, pkgroot, parent);
boolean samepkg = pkgFromClass(parent.getName()).equals(
pkgFromClass(target.getName()));
insertClass(roots, pkgroot, parent, !samepkg);
// and refetch our chain
chain = getChain(roots, parent);
// sanity check
@@ -140,16 +147,58 @@ public class ChainUtil
return;
}
}
// add class will ignore our request if this class was already
// added due to some previous operation
chain.addClass(target);
chain.addClass(name, target);
}
}
protected static boolean insertRoot (ArrayList roots, String pkgroot,
protected static String generateName (Class target, String pkgroot,
boolean outpkg)
{
String name;
if (outpkg) {
// start with the fully qualified class name
name = target.getName();
// if we're in the package root, we want to strip off the
// package root and prefix ...
if (name.startsWith(pkgroot)) {
name = ".." + name.substring(pkgroot.length());
}
} else {
name = nameFromClass(target.getName());
}
return name;
}
/**
* Returns just the package qualifier given a fully qualified class
* name.
*/
public static String pkgFromClass (String fqn)
{
int didx = fqn.lastIndexOf(".");
return (didx == -1) ? fqn : fqn.substring(0, didx);
}
/**
* Returns the unqualified class name given a fully qualified class
* name.
*/
public static String nameFromClass (String fqn)
{
int didx = fqn.lastIndexOf(".");
return (didx == -1) ? fqn : fqn.substring(didx+1);
}
protected static boolean insertRoot (ArrayList roots, String name,
Class root)
{
Chain chroot = new Chain(pkgroot, root);
Chain chroot = new Chain(name, root);
// make sure no chain already exists for this root
if (!roots.contains(chroot)) {
roots.add(chroot);
@@ -1,13 +1,16 @@
//
// $Id: HierarchyVisualizer.java,v 1.2 2001/07/13 23:25:13 mdb Exp $
// $Id: HierarchyVisualizer.java,v 1.3 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool.viz;
import java.awt.Dimension;
import java.awt.Point;
import java.io.PrintStream;
import java.util.*;
import com.samskivert.viztool.Log;
import com.samskivert.viztool.enum.PackageEnumerator;
import com.samskivert.util.Comparators;
/**
* The hierarchy visualizer displays inheritance hierarchies in a compact
@@ -33,64 +36,80 @@ public class HierarchyVisualizer
// dump all the classes into an array list so that we can
// repeatedly scan through the list
_classes = new ArrayList();
while (iter.hasNext()) {
_classes.add(iter.next());
}
// process the classes provided by our enumerator
_roots = ChainUtil.buildChains(pkgroot, _classes.iterator());
// compile a list of all packages in our collection
HashSet pkgset = new HashSet();
iter = _classes.iterator();
while (iter.hasNext()) {
pkgset.add(ChainUtil.pkgFromClass((String)iter.next()));
}
// now we need to sort out
// sort our package names
_packages = new String[pkgset.size()];
iter = pkgset.iterator();
for (int i = 0; iter.hasNext(); i++) {
_packages[i] = (String)iter.next();
}
Arrays.sort(_packages, Comparators.STRING);
// now create chain groups for each package
_groups = new ChainGroup[_packages.length];
for (int i = 0; i < _groups.length; i++) {
PackageEnumerator penum = new PackageEnumerator(
_packages[i], _classes.iterator(), false);
_groups[i] = new ChainGroup(pkgroot, _packages[i], penum);
}
}
/**
* Processes the hierarchy of class chains assigning coordinates to
* all of the chains and subchains so that they can be used to
* generate a visualization.
* Lays out and renders each of the chain groups that make up this
* package hierarchy visualization.
*/
public void layoutChains (int pointSize)
public void render (int pointSize, PrintStream out)
{
// lay out the internal structure of our chains
ChainLayout clay = new CascadingChainLayout();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
chain.layout(pointSize, clay);
}
int x = X_MARGIN, y = Y_MARGIN;
// arrange them on the page
ElementLayout elay = new PackedColumnElementLayout();
Dimension[] pdims = elay.layout(_roots, PAGE_WIDTH, PAGE_HEIGHT);
// print the preamble for the first page
out.println("0 setlinewidth");
// render them
for (int p = 0; p < pdims.length; p++) {
ChainRenderer renderer = new CascadingChainRenderer();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
// skip chains not on this page
if (chain.getPage() != p) {
continue;
}
Point loc = chain.getLocation();
renderer.renderChain(chain, System.out, pointSize,
X_MARGIN, Y_MARGIN);
for (int i = 0; i < _groups.length; i++) {
// lay out the group in question
Dimension dims = _groups[i].layout(pointSize);
// 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;
}
System.out.println("showpage");
}
}
public void dumpClasses ()
{
ChainUtil.dumpClasses(System.err, _roots);
// render the group at the requested location
_groups[i].render(pointSize, out, x, y);
// increment our y location
y += (dims.height + GAP);
}
// print the postamble for the final page
out.println("showpage");
}
protected String _pkgroot;
protected ArrayList _roots;
protected ArrayList _classes;
protected ArrayList _classes = new ArrayList();
protected String[] _packages;
protected ChainGroup[] _groups;
protected static final int PAGE_WIDTH = (int)(72 * 7.5);
protected static final int PAGE_HEIGHT = (int)(72 * 10);
protected static final int X_MARGIN = 72/2;
protected static final int Y_MARGIN = 72/2;
protected static final int GAP = 72/4;
}
@@ -1,5 +1,5 @@
//
// $Id: PackedColumnElementLayout.java,v 1.1 2001/07/13 23:25:13 mdb Exp $
// $Id: PackedColumnElementLayout.java,v 1.2 2001/07/14 00:55:21 mdb Exp $
package com.samskivert.viztool.viz;
@@ -70,6 +70,11 @@ public class PackedColumnElementLayout implements ElementLayout
x += (size.width + GAP);
}
// take a final stab at our maxwidth
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()];