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; 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 // 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 = GAP, y = hhei; int x = 2*GAP, y = hhei;
ArrayList kids = chain.getChildren(); ArrayList kids = chain.getChildren();
for (int i = 0; i < kids.size(); i++) { 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; package com.samskivert.viztool.viz;
@@ -16,14 +16,10 @@ 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 pkgroot, Class root) public Chain (String name, Class root)
{ {
_pkgroot = pkgroot; _name = name;
_root = root; _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 * Adds a child to this chain. The specified class is assumed to
* directly inherit from the class that is the root of this chain. * 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)) { if (!_children.contains(chain)) {
_children.add(chain); _children.add(chain);
} }
@@ -192,9 +188,8 @@ public class Chain implements Element
} }
} }
protected String _pkgroot;
protected Class _root;
protected String _name; protected String _name;
protected Class _root;
protected ArrayList _children = new ArrayList(); protected ArrayList _children = new ArrayList();
protected Dimension _size = new Dimension(0, 0); 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; package com.samskivert.viztool.viz;
@@ -71,7 +71,7 @@ public class ChainUtil
void computeRoots (String pkgroot, Iterator iter, ArrayList roots) void computeRoots (String pkgroot, Iterator iter, ArrayList roots)
{ {
while (iter.hasNext()) { 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 * Loads the supplied class and inserts it into the appropriate
* position in the hierarchy based on its inheritance properties. * position in the hierarchy based on its inheritance properties.
*/ */
protected static protected static void insertClass (
void insertClass (ArrayList roots, String pkgroot, String clazz) ArrayList roots, String pkgroot, String clazz, boolean outpkg)
{ {
try { try {
// sanity check // sanity check
@@ -92,7 +92,7 @@ public class ChainUtil
} }
// load and insert the class // load and insert the class
insertClass(roots, pkgroot, Class.forName(clazz)); insertClass(roots, pkgroot, Class.forName(clazz), outpkg);
} catch (Exception e) { } catch (Exception e) {
Log.warning("Unable to process class [class=" + clazz + 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 * Inserts the specified class into the appropriate position in the
* hierarchy based on its inheritance properties. * hierarchy based on its inheritance properties.
*/ */
protected static protected static void insertClass (
void insertClass (ArrayList roots, String pkgroot, Class target) ArrayList roots, String pkgroot, Class target, boolean outpkg)
{ {
// insert the parent of this class into the hierarchy // insert the parent of this class into the hierarchy
Class parent = target.getSuperclass(); Class parent = target.getSuperclass();
String name = generateName(target, pkgroot, outpkg);
// 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, pkgroot, target); insertRoot(roots, name, target);
} else { } else {
String tpkg = pkgFromClass(target.getName());
String ppkg = pkgFromClass(parent.getName());
// if our parent is not in this package, we want to insert it // if our parent is not in this package, we want to insert it
// into the hierarchy as a root class // into the hierarchy as a root class
if (!parent.getName().startsWith(pkgroot)) { if (!tpkg.equals(ppkg)) {
insertRoot(roots, pkgroot, parent); String pname = generateName(parent, pkgroot, true);
insertRoot(roots, pname, parent);
} }
// and now hang ourselves off of our parent class // and now hang ourselves off of our parent class
@@ -128,7 +133,9 @@ public class ChainUtil
if (chain == null) { if (chain == null) {
// if there's no chain for our parent class, we'll need to // if there's no chain for our parent class, we'll need to
// insert it into the hierarchy // 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 // and refetch our chain
chain = getChain(roots, parent); chain = getChain(roots, parent);
// sanity check // sanity check
@@ -140,16 +147,58 @@ public class ChainUtil
return; return;
} }
} }
// add class will ignore our request if this class was already // add class will ignore our request if this class was already
// added due to some previous operation // 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) Class root)
{ {
Chain chroot = new Chain(pkgroot, root); Chain chroot = new Chain(name, root);
// 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,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; package com.samskivert.viztool.viz;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Point; import java.awt.Point;
import java.io.PrintStream;
import java.util.*; import java.util.*;
import com.samskivert.viztool.Log; 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 * 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 // dump all the classes into an array list so that we can
// repeatedly scan through the list // repeatedly scan through the list
_classes = new ArrayList();
while (iter.hasNext()) { while (iter.hasNext()) {
_classes.add(iter.next()); _classes.add(iter.next());
} }
// process the classes provided by our enumerator // compile a list of all packages in our collection
_roots = ChainUtil.buildChains(pkgroot, _classes.iterator()); 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 * Lays out and renders each of the chain groups that make up this
* all of the chains and subchains so that they can be used to * package hierarchy visualization.
* generate a visualization.
*/ */
public void layoutChains (int pointSize) public void render (int pointSize, PrintStream out)
{ {
// lay out the internal structure of our chains int x = X_MARGIN, y = Y_MARGIN;
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 // print the preamble for the first page
ElementLayout elay = new PackedColumnElementLayout(); out.println("0 setlinewidth");
Dimension[] pdims = elay.layout(_roots, PAGE_WIDTH, PAGE_HEIGHT);
// render them for (int i = 0; i < _groups.length; i++) {
for (int p = 0; p < pdims.length; p++) { // lay out the group in question
ChainRenderer renderer = new CascadingChainRenderer(); Dimension dims = _groups[i].layout(pointSize);
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i); // determine if we need to skip to the next page or not
// skip chains not on this page if ((y > 0) && (y + dims.height > PAGE_HEIGHT)) {
if (chain.getPage() != p) { // print the postamble for this page and preamble for the
continue; // new page
} out.println("showpage");
Point loc = chain.getLocation(); out.println("0 setlinewidth");
renderer.renderChain(chain, System.out, pointSize, y = Y_MARGIN;
X_MARGIN, Y_MARGIN);
} }
System.out.println("showpage");
}
}
public void dumpClasses () // render the group at the requested location
{ _groups[i].render(pointSize, out, x, y);
ChainUtil.dumpClasses(System.err, _roots);
// increment our y location
y += (dims.height + GAP);
}
// print the postamble for the final page
out.println("showpage");
} }
protected String _pkgroot; protected String _pkgroot;
protected ArrayList _roots; protected ArrayList _classes = new ArrayList();
protected ArrayList _classes;
protected String[] _packages;
protected ChainGroup[] _groups;
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);
protected static final int X_MARGIN = 72/2; protected static final int X_MARGIN = 72/2;
protected static final int Y_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; package com.samskivert.viztool.viz;
@@ -70,6 +70,11 @@ public class PackedColumnElementLayout implements ElementLayout
x += (size.width + GAP); 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 // make a note of how big the final page is
pagedims.add(new Dimension(maxwidth, y+rowheight)); pagedims.add(new Dimension(maxwidth, y+rowheight));
Dimension[] dims = new Dimension[pagedims.size()]; Dimension[] dims = new Dimension[pagedims.size()];