Moved to separate repository.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@1619 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2005-03-13 22:33:59 +00:00
parent 97879b0051
commit e9d198ee16
45 changed files with 0 additions and 5176 deletions
-59
View File
@@ -1,59 +0,0 @@
* Release 1.1:
2001-12-03 Michael Bayne <mdb@bering>
* src/java/com/samskivert/viztool/DriverTask.java:
Use File.toURI() rather than build the URI by hand.
* src/java/com/samskivert/viztool/Driver.java:
Added ability to generate postscript output file.
* various:
More Visualizer interface improvements. Created ANT task for invoking
viztool which is much nicer than the script.
* README:
Added documentation for the ANT task.
* build.xml:
Added targets to test the ANT driver task.
* src/java/com/samskivert/viztool/summary/ClassSummary.java, src/java/com/samskivert/viztool/summary/SummaryVisualizer.java:
Summary visualization enhancements.
* src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java:
Made sorting by height optional.
2001-12-01 Michael Bayne <mdb@bering>
* various:
Created a visualization that displays classes, their public fields,
members and constructors rather than the inheritance hierarchy.
* various:
Refactored things into layout and render utility classes. Other
cleanups. Upped the on screen font size.
2001-11-30 Michael Bayne <mdb@bering>
* various:
Rearranged packages in preparation for the addition of a new type of
visualization.
* Release 1.01:
2001-08-13 Michael Bayne <mdb@bering>
* bin/runjava: Wasn't incorporating the CLASSPATH environment
variable properly.
* various: Added a better user interface for displaying
visualizations on the screen rather than printing them.
* Release 1.0:
2001-08-12 Michael Bayne <mdb@bering>
* various: Initial release.
$Id: NEWS,v 1.4 2001/12/03 10:00:39 mdb Exp $
-102
View File
@@ -1,102 +0,0 @@
VIZTOOL: An extensible tool for visualizing Java classes
--------------------------------------------------------
As the catchy subtitle claims, viztool is used to generate visualizations
of collections of Java classes. These visualizations are intended to be
printed out and taped to the wall or set on the desk beside you or folded
into paper airplanes and sailed around the room. Thus viztool does not
include a sophisticated user interface for viewing these presentations
onscreen (use ghostscript for that), although you can actually display
them on the screen because the rendering is done via the Java 2D rendering
engine.
viztool was born from my repeated desire to be able to glance over all of
the myriad classes that come to be involved in any large project. I knew I
could go out and pay thousands of dollars for a single user license for
some object oriented design tool that would diagram my classes three ways
to Sunday, generate code, count my chickens and make toast on the side,
but I couldn't find a free, simple tool for generating basic class
diagrams.
Building viztool
----------------
Building viztool is very simple. First ensure that the necessary third
party jar files are available either in the lib/ directory or in the
system wide jar file location specified in build.xml. See lib/README for a
list of the necessary third party jar files and how to get them.
The library is built using ant, a modern build tool available from The
Jakarta Project. If you aren't already using ant for other projects, it
can be found here:
http://jakarta.apache.org/ant/
Invoke ant with any of the following targets:
all: builds the class files and javadoc documentation
compile: builds only the class files (dist/classes)
javadoc: builds only the javadoc documentation (dist/docs)
dist: builds the distribution jar file (dist/viztool.jar)
Look at the build.xml file for configurable build parameters.
Using viztool
-------------
viztool is designed to be easily invoked from ant. Simply ensure that
viztool.jar and its associated dependent jar files are in the classpath of
the JVM that invokes ant and then add a task like the following to your
build.xml file:
<target name="hierviz">
<taskdef name="viztool" classname="com.samskivert.viztool.DriverTask"/>
<viztool pkgroot="com.samskivert.viztool"
classes="com.samskivert.viztool.*"
visualizer="com.samskivert.viztool.hierarchy.HierarchyVisualizer">
<classpath refid="classpath"/>
</viztool>
</target>
the parameters passed to the task are:
pkgroot: the base package name which will be used to strip common text
from the front of fully qualified class names
classes: a regular expression matching the classes to be visualized
visualizer: the classname of the visualizer to use
the <viztool> element should contain a <classpath> element which defines the
classpath over which viztool will iterate, searching for classes that
match the specified pattern.
There is also an included shell script (bin/viztool). Add the classes that
you wish to visualize to your CLASSPATH environment variable and then
invoke the viztool script with the package prefix you wish to visualize.
For example:
% export CLASSPATH=<here>/foo.jar:<there>/bar.jar:<everywhere>/baz.jar
% ./bin/viztool --print com.whoever.mygreatpackage
Because the classes are actually resolved by the JVM when visualizing, all
classes that the visualized classes depend upon must also be loadable
(meaning included in the class path).
If you want to write your own script, take a look at the viztool script to
see what arguments to pass to the visualization driver class.
Distribution
------------
viztool is released under the GPL. The most recent version of the code is
available here:
http://www.waywardgeeks.org/code/viztool/
Contribution
------------
Contributions are welcome. Patches and suggestions can be sent to Michael
Bayne <mdb@samskivert.com>.
$Id: README,v 1.3 2001/12/03 08:34:05 mdb Exp $
-42
View File
@@ -1,42 +0,0 @@
#!/bin/sh
#
# $Id: build-dist.sh,v 1.2 2001/08/12 04:21:13 mdb Exp $
#
# Builds a distribution archive. This should be run from the top-level
# project directory and it will place the distribution archive into the
# directory identified by $DISTDIR.
USAGE="Usage: $0 distname (eg. viztool-1.4)"
DISTDIR=dist
if [ -z "$1" ]; then
echo $USAGE
exit -1
else
TARGET=$1
fi
# build our excludes file
cat > .excludes <<EOF
build-dist.sh
CVS
dist
lib/*.jar
code
.excludes
.cvsignore
EOF
# create our distribution directory
mkdir /tmp/$TARGET
# temporarily move the distribution files into temp so that we can put
# them into a properly named directory
tar --exclude-from=.excludes -cf - * | tar -C /tmp/$TARGET -xf -
# now build the actual archive file
tar -C /tmp -czf $DISTDIR/$TARGET.tgz $TARGET
# and clean up after ourselves
rm -rf /tmp/$TARGET
rm .excludes
-105
View File
@@ -1,105 +0,0 @@
#!/usr/bin/perl -w
#
# $Id: runjava,v 1.3 2001/08/13 23:30:52 mdb Exp $
#
# A script for invoking java. The project root is inferred to be one
# directory above the directory in which this script lives. Based on the
# root, all .jar files in the lib subdirectory are added to the classpath.
# Additionally all shared libraries in lib/$arch, where $arch is generated
# via uname and looks something like i686-Linux, are added to the
# LD_LIBRARY_PATH environment variable. Classes are assumed to live in
# $classdir as defined below.
use strict;
use Getopt::Std;
# this is where our classfiles live (relative to the project root)
my $classdir = "dist/classes";
# parse the arguments
my %opts;
getopts('p:v', \%opts);
my $pid_file = $opts{"p"};
my $verbose = $opts{"v"};
# make sure they specified a classfile
my $usage = "Usage: $0 [-p pid_file] [-v] [-- args to pass to java] class\n";
die $usage unless (@ARGV);
# get the server root by popping the /bin off of our directory
my $location;
chomp($location = `dirname $0`);
my @parts = split(/\//, $location);
pop(@parts);
my $root = join("/", @parts);
# figure out where our JVM lives
my $jhome = $ENV{"JAVA_HOME"};
# make sure JAVA_HOME is set
if (!defined $jhome) {
warn "$0: Error: No JAVA_HOME specified!\n";
warn "\n";
warn "You must set your JAVA_HOME environment variable to the\n";
warn "the absolute path of your JDK installation. For example:\n";
warn "\n";
warn " % JAVA_HOME=/usr/local/jdk1.2\n";
warn " % export JAVA_HOME\n";
die "\n";
}
my $java = "$jhome/bin/java";
my $jlib = "$jhome/lib/classes.zip";
# use rt.jar if necessary
if (! -f $jlib) {
$jlib = "$jhome/lib/rt.jar";
}
if (! -f $jlib) {
$jlib = "$jhome/jre/lib/rt.jar";
}
# make sure we can run the jvm
if (! -x $java) {
die "$0: Can't find a java interpreter in '$jhome'.\n";
}
# determine our machine architecture
my $ostype = `uname -s`;
my $machtype = `uname -m`;
chomp($ostype);
chomp($machtype);
my $arch = "$machtype-$ostype";
# add our native libraries to the runtime library path
my $libs = "$root/lib/$arch";
my $libpath = $ENV{"LD_LIBRARY_PATH"};
if (defined $libpath) {
$ENV{"LD_LIBRARY_PATH"} = "$libs:$libpath";
} else {
$ENV{"LD_LIBRARY_PATH"} = $libs;
}
# put everything in our class path
my $classpath = "$jlib:$root/$classdir";
# if there's an environment variable set, we'll need to include that too
my $ecpath = $ENV{"CLASSPATH"};
$classpath = "$ecpath:$classpath" if (defined $ecpath);
# any zip or jar files in our lib/ directory get added to the class path
if (opendir(DIR, "$root/lib")) {
my $lib;
foreach $lib (grep { /.(zip|jar)/ && -f "$root/lib/$_" } readdir(DIR)) {
$classpath .= ":$root/lib/$lib";
}
closedir DIR;
}
# log the pid file if requested to do so
print `echo $$ > $pid_file` if (defined $pid_file);
my $cmd = "$java -mx256M -classpath $classpath " . join(" ", @ARGV);
print "$cmd\n" if ($verbose);
exec($cmd);
-72
View File
@@ -1,72 +0,0 @@
#!/bin/sh
#
# $Id: viztool,v 1.2 2001/11/08 19:38:54 mdb Exp $
#
# Sets up the classpath and invokes viztool with arguments supplied to
# this script.
BINDIR=`dirname $0`
RUNJAVA=$BINDIR/runjava
VIZAPP=com.samskivert.viztool.Driver
usage ()
{
echo "Usage: $0 [OPTIONS] package_prefix"
cat << EOH
options:
[--exclude=pkg:pkg:...]
Note that sub-packages must explicitly be enumerated in this
list. Excluding foo.bar will not automatically exclude
foo.bar.baz.
[--print]
[--cpath="jar_file|directory [jar_file|directory ...]"]
A list of jar files and directories to include in the classpath
(separated by spaces). This will be globbed for you, so you can
pass in --cpath="lib/*.jar".
EOH
exit -1
}
if [ $# = 0 ]; then
usage
fi
while test $# -gt 0
do
case "$1" in
-h|-\?)
usage
;;
--print)
OPTIONS="$OPTIONS -print"
;;
--exclude=*)
EXCL=`echo $1 | sed 's:--exclude=::g'`
JOPTIONS="$JOPTIONS -Dexclude=$EXCL"
;;
--cpath=*)
ELEMS=`echo $1 | sed 's:--cpath=::g'`
if [ -z "$CLASSPATH" ] ; then
export CLASSPATH=`echo $ELEMS | sed 's/ /:/g'`
else
export CLASSPATH=$CLASSPATH:`echo $ELEMS | sed 's/ /:/g'`
fi
;;
-*)
echo "Unknown option: $1"
exit -1
;;
*)
PACKAGE=$1
;;
esac
shift
done
if [ -z "$PACKAGE" ]; then
usage
fi
# invoke the program
$RUNJAVA -- $JOPTIONS $VIZAPP $OPTIONS $PACKAGE
-114
View File
@@ -1,114 +0,0 @@
<!-- build configuration -->
<project name="viztool" default="compile" basedir=".">
<!-- things you may want to change -->
<property name="app.name" value="viztool"/>
<property name="doc.packages" value="com.samskivert.*"/>
<property name="doc.overview" value="com/samskivert/viztool/overview.html"/>
<property name="copyright.holder" value="Michael Bayne"/>
<property name="build.compiler" value="jikes"/>
<property name="java.libraries" value="/usr/share/java"/>
<!-- things you probably don't want to change -->
<property name="src.dir" value="src/java"/>
<property name="deploy.dir" value="dist"/>
<property name="dist.jar" value="${app.name}.jar"/>
<property name="javadoc.dir" value="${deploy.dir}/docs"/>
<property name="savedoc.dir" value="docs"/>
<!-- declare our classpath business -->
<path id="base.classpath">
<pathelement location="${deploy.dir}/classes"/>
<fileset dir="lib" includes="**/*.jar"/>
</path>
<path id="classpath">
<path refid="base.classpath"/>
</path>
<!-- include JAVA_LIBS jars in our classpath if it exists -->
<target name="check-java-libs" if="env.JAVA_LIBS">
<!-- overwrite the classpath with one that contains JAVA_LIBS jars -->
<path id="classpath">
<path refid="base.classpath"/>
<fileset dir="${env.JAVA_LIBS}" includes="**/*.jar"/>
</path>
</target>
<!-- prepares the application directories -->
<target name="prepare">
<mkdir dir="${deploy.dir}"/>
<mkdir dir="${deploy.dir}/classes"/>
<mkdir dir="${javadoc.dir}"/>
<copy todir="${deploy.dir}/classes">
<fileset dir="${src.dir}" includes="**/*.properties"/>
</copy>
</target>
<!-- cleans out the installed application -->
<target name="clean">
<delete dir="${deploy.dir}"/>
</target>
<!-- build the java class files -->
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}" destdir="${deploy.dir}/classes"
debug="on" optimize="off" deprecation="off">
<classpath refid="classpath"/>
</javac>
</target>
<!-- build the javadoc documentation -->
<target name="javadoc" depends="prepare">
<javadoc sourcepath="${src.dir}"
packagenames="${doc.packages}"
windowtitle="${app.name} API"
doctitle="${app.name} API"
overview="${src.dir}/${doc.overview}"
bottom="Copyright &#169; 2001 ${copyright.holder}. All Rights Reserved."
destdir="${javadoc.dir}"
additionalparam="-breakiterator">
<classpath refid="classpath"/>
<link href="http://samskivert.com/code/samskivert/samskivert/dist/api"/>
<link href="http://java.sun.com/j2se/1.4/docs/api/"/>
</javadoc>
</target>
<!-- builds the javadocs and stuffs them in a directory where they won't
be blown away when we do "clean" next time -->
<target name="savedoc" depends="javadoc">
<delete dir="${savedoc.dir}/api"/>
<copy todir="${savedoc.dir}/api">
<fileset dir="${javadoc.dir}" includes="**/*"/>
</copy>
</target>
<!-- a target for rebuilding everything -->
<target name="all" depends="clean,prepare,compile,javadoc,dist"/>
<!-- builds our distribution files (war and jar) -->
<target name="dist" depends="prepare,compile">
<jar file="${deploy.dir}/${dist.jar}"
basedir="${deploy.dir}/classes"/>
</target>
<!-- invoke the visualizer on itself for testing -->
<target name="sumtest" depends="prepare,compile">
<taskdef name="viztool" classname="com.samskivert.viztool.DriverTask"/>
<viztool visualizer="com.samskivert.viztool.summary.SummaryVisualizer"
pkgroot="com.samskivert.viztool"
classes="com.samskivert.viztool.*">
<classpath refid="classpath"/>
</viztool>
</target>
<target name="hiertest" depends="prepare,compile">
<taskdef name="viztool" classname="com.samskivert.viztool.DriverTask"/>
<viztool visualizer="com.samskivert.viztool.hierarchy.HierarchyVisualizer"
pkgroot="com.samskivert.viztool"
classes="com.samskivert.viztool.*"
output="hiertest.ps">
<classpath refid="classpath"/>
</viztool>
</target>
</project>
-60
View File
@@ -1,60 +0,0 @@
viztool notes -*- mode: outline -*-
* Driver enhancements
Create a driver that loads parameters from a properties file. That file
can specify what visualization to use, parameters for that visualization
and overall parameters like packages to exclude, etc.
Add support for regular expressions in the package inclusion and exclusion
specifications.
Move the package exclusion processing into the PackageEnumerator rather
than the current hack of having the HierarchyVisualizer do it.
** From <jon@latchkey.com>:
Create an Ant Task that allows you to do something like this:
<target name="viztool">
<viztool properties="viztool.properties">
<classpath>
</classpath>
</viztool>
</target>
Or:
<target name="viztool">
<viztool exclude="" include="">
<classpath>
</classpath>
</viztool>
</target>
That would be fun.
* Chain visualization enhancements
Lay chains out vertically rather than horizontally to achieve better
density and a more aesthetic arrangement. This will probably require a
searching algorithm to try to determine how tall to make each column to
make best use of space.
Provide the option to arrange packages in the order that allows them to
fit most compactly on the page rather than visualizing them in
alphabetical order and pushing a package to a new page when it doesn't fit
in the remaining space on the current page.
Provide an option to split packages up to fit them in the remaining space
on a page rather than pushing them to the next page.
* Summary visualization enhancements
Format field/method names in bold
* General visualization enhancements
Add page numbers somewhere. [shaper@waywardgeeks.org]
* Printing enhancements
Add current date to printed page.
* Architecture
Create renderable primitives and build the visualizations from those
primitives rather than encapsulating things in Layout/RenderUtil.
-1
View File
@@ -1 +0,0 @@
*.jar
-16
View File
@@ -1,16 +0,0 @@
Required external libraries
---------------------------
The viztool code requires the following external Java libraries (JAR
files) to be placed here in the lib/ directory or in the shared library
directory specified in the build.xml file (${java.libraries}).
* samskivert library:
http://samskivert.com/code/samskivert/
Once the jar files are in place (regardless of what they are named), the
build system will automatically include them in the compile-time
classpath.
--
$Id: README,v 1.3 2001/08/12 02:40:25 mdb Exp $
@@ -1,151 +0,0 @@
//
// $Id: Driver.java,v 1.16 2001/12/03 08:53:31 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
import java.awt.*;
import java.awt.print.*;
import java.util.ArrayList;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.viztool.clenum.*;
import com.samskivert.viztool.hierarchy.HierarchyVisualizer;
import com.samskivert.viztool.summary.SummaryVisualizer;
import com.samskivert.viztool.util.FontPicker;
/**
* The application driver. This class parses the command line arguments
* and invokes the visualization code.
*/
public class Driver
{
public static void main (String[] args)
{
if (args.length < 1) {
System.err.println(USAGE);
System.exit(-1);
}
// parse our arguments
String pkgroot = "";
String regexp = null;
boolean print = false;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-print")) {
print = true;
} else if (regexp == null) {
regexp = args[i];
}
}
// run ourselves on the classpath
String classpath = System.getProperty("java.class.path");
// System.err.println("Scanning " + classpath + ".");
ClassEnumerator clenum = new ClassEnumerator(classpath);
// print out the warnings
ClassEnumerator.Warning[] warnings = clenum.getWarnings();
for (int i = 0; i < warnings.length; i++) {
System.err.println("Warning: " + warnings[i].reason);
}
// initialize the font picker
FontPicker.init(print);
// and finally generate the visualization
FilterEnumerator fenum = null;
try {
fenum = new RegexpEnumerator(regexp, null, clenum);
} catch (Exception e) {
Log.warning("Invalid package regular expression " +
"[regexp=" + regexp + ", error=" + e + "].");
System.exit(-1);
}
ArrayList classes = new ArrayList();
while (fenum.hasNext()) {
String cname = (String)fenum.next();
// skip inner classes, the visualizations pick those up
// themselves
if (cname.indexOf("$") != -1) {
continue;
}
try {
classes.add(Class.forName(cname));
} catch (Throwable t) {
Log.warning("Unable to introspect class [class=" + cname +
", error=" + t + "].");
}
}
// Visualizer viz = new HierarchyVisualizer(pkgroot, penum);
Visualizer viz = new SummaryVisualizer();
viz.setPackageRoot(pkgroot);
viz.setClasses(classes.iterator());
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();
// use sensible margins
Paper paper = new Paper();
paper.setImageableArea(72*0.5, 72*0.5, 72*7.5, 72*10);
format.setPaper(paper);
// use our configured page format
job.setPrintable(viz, format);
// pop up a dialog to control printing
if (job.printDialog()) {
try {
// invoke the printing process
job.print();
} catch (PrinterException pe) {
pe.printStackTrace(System.err);
}
} else {
Log.info("Printing cancelled.");
}
// printing starts up the AWT threads, so we have to
// explicitly exit at this point
System.exit(0);
} else {
VizFrame frame = new VizFrame(viz);
frame.pack();
SwingUtil.centerWindow(frame);
frame.setVisible(true);
}
}
protected static final String USAGE =
"Usage: Driver [-mode hier|sum] [-print] package_regexp " +
"[package_root]\n" +
" hier = class hierarchy visualization\n" +
" sum = class summary visualization\n"
;
}
@@ -1,229 +0,0 @@
//
// $Id: DriverTask.java,v 1.4 2003/01/28 22:39:34 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Destination;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Path;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.viztool.clenum.ClassEnumerator;
import com.samskivert.viztool.clenum.FilterEnumerator;
import com.samskivert.viztool.clenum.RegexpEnumerator;
import com.samskivert.viztool.util.FontPicker;
/**
* The viztool ant task. It takes the following arguments:
*
* <pre>
* pkgroot = the base package from which names will be shortened
* classes = a regular expression matching the classes to be visualized
* visualizer = the classname of the visualizer to be used
* </pre>
*
* The task should contain an embedded &lt;classpath&gt; element to
* provide the classpath over which we will iterate, looking for matching
* classes.
*/
public class DriverTask extends Task
{
public void setVisualizer (String vizclass)
{
_vizclass = vizclass;
}
public void setPkgroot (String pkgroot)
{
_pkgroot = pkgroot;
}
public void setClasses (String classes)
{
_classes = classes;
}
public void setExclude (String exclude)
{
_exclude = exclude;
}
public void setOutput (File output)
{
_output = output;
}
public Path createClasspath ()
{
return _cmdline.createClasspath(project).createPath();
}
/**
* Performs the actual work of the task.
*/
public void execute () throws BuildException
{
// make sure everything was set up properly
ensureSet(_vizclass, "Must specify the visualizer class " +
"via the 'visualizer' attribute.");
ensureSet(_pkgroot, "Must specify the package root " +
"via the 'pkgroot' attribute.");
ensureSet(_pkgroot, "Must specify the class regular expression " +
"via the 'classes' attribute.");
Path classpath = _cmdline.getClasspath();
ensureSet(classpath, "Must provide a <classpath> subelement " +
"describing the classpath to be searched for classes.");
// initialize the font picker
FontPicker.init(_output != null);
// create the classloader we'll use to load the visualized classes
ClassLoader cl = new AntClassLoader(null, project, classpath, false);
// scan the classpath and determine which classes will be
// visualized
ClassEnumerator clenum = new ClassEnumerator(classpath.toString());
FilterEnumerator fenum = null;
try {
fenum = new RegexpEnumerator(_classes, _exclude, clenum);
} catch (Exception e) {
throw new BuildException("Invalid package regular expression " +
"[classes=" + _classes +
", exclude=" + _exclude + "].", e);
}
ArrayList classes = new ArrayList();
while (fenum.hasNext()) {
String cname = (String)fenum.next();
// skip inner classes, the visualizations pick those up
// themselves
if (cname.indexOf("$") != -1) {
continue;
}
try {
classes.add(cl.loadClass(cname));
} catch (Throwable t) {
log("Unable to introspect class [class=" + cname +
", error=" + t + "].");
}
}
// // remove the packages on our exclusion list
// String expkg = System.getProperty("exclude");
// if (expkg != null) {
// StringTokenizer tok = new StringTokenizer(expkg, ":");
// while (tok.hasMoreTokens()) {
// pkgset.remove(tok.nextToken());
// }
// }
// now create our visualizer and go to work
Visualizer viz = null;
try {
viz = (Visualizer)Class.forName(_vizclass).newInstance();
} catch (Throwable t) {
throw new BuildException("Unable to instantiate visualizer " +
"[vizclass=" + _vizclass +
", error=" + t + "].");
}
viz.setPackageRoot(_pkgroot);
viz.setClasses(classes.iterator());
// if no output file was specified, pop up a window
if (_output == null) {
VizFrame frame = new VizFrame(viz);
frame.pack();
SwingUtil.centerWindow(frame);
frame.setVisible(true);
// prevent ant from kicking the JVM out from under us
synchronized (this) {
while (true) {
try {
wait();
} catch (InterruptedException ie) {
}
}
}
} else {
// we use the print system to render things
PrinterJob job = PrinterJob.getPrinterJob();
// use sensible margins
PageFormat format = job.defaultPage();
Paper paper = new Paper();
paper.setImageableArea(72*0.5, 72*0.5, 72*7.5, 72*10);
format.setPaper(paper);
// use our configured page format
job.setPrintable(viz, format);
// tell our printjob to print to a file
PrintRequestAttributeSet attrs =
new HashPrintRequestAttributeSet();
attrs.add(new Destination(_output.toURI()));
// invoke the printing process
try {
log("Generating visualization to '" + _output.getPath() + "'.");
job.print(attrs);
} catch (PrinterException pe) {
throw new BuildException("Error printing visualization.", pe);
}
}
}
protected void ensureSet (Object value, String errmsg)
throws BuildException
{
if (value == null) {
throw new BuildException(errmsg);
}
}
protected String _vizclass;
protected String _pkgroot;
protected String _classes, _exclude;
protected File _output;
// use use this for accumulating our classpath
protected CommandlineJava _cmdline = new CommandlineJava();
}
@@ -1,55 +0,0 @@
//
// $Id: Log.java,v 1.3 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
/**
* A placeholder class that contains a reference to the log object used by
* the viztool package.
*/
public class Log
{
public static com.samskivert.util.Log log =
new com.samskivert.util.Log("viztool");
/** Convenience function. */
public static void debug (String message)
{
log.debug(message);
}
/** Convenience function. */
public static void info (String message)
{
log.info(message);
}
/** Convenience function. */
public static void warning (String message)
{
log.warning(message);
}
/** Convenience function. */
public static void logStackTrace (Throwable t)
{
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
}
}
@@ -1,63 +0,0 @@
//
// $Id: Visualizer.java,v 1.5 2001/12/03 08:34:53 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
import java.awt.Graphics2D;
import java.awt.print.Printable;
import java.util.Iterator;
/**
* The interface via which the driver accesses whichever visualizer is
* desired for a particular invocation.
*/
public interface Visualizer extends Printable
{
/**
* Provides the visualizer with the root package which it can use to
* format package names relative to the root package.
*/
public void setPackageRoot (String pkgroot);
/**
* Provides the visualizer with an iterator over all of the {@link
* Class} instances that it will be visualizing.
*/
public void setClasses (Iterator iterator);
/**
* Requests that the visualization lay itself out in pages with the
* specified dimensions. Subsequent calls to {@link #print} or {@link
* #paint} will assume that things are laid out according to the most
* recent call to this method.
*/
public void layout (Graphics2D gfx, double x, double y,
double width, double height);
/**
* Renders the specified page of this visualization.
*/
public void paint (Graphics2D gfx, int pageIndex);
/**
* Returns the number of pages occupied by the visualization.
*/
public int getPageCount ();
}
@@ -1,124 +0,0 @@
//
// $Id: VizController.java,v 1.4 2001/12/01 05:28:01 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
import java.awt.event.ActionEvent;
import java.awt.print.*;
import com.samskivert.swing.*;
/**
* The viz controller manages the user interface and effects actions that
* are requested by the user (like moving forward or backward a page).
*/
public class VizController extends Controller
{
/** The action command for moving forward one page. */
public static final String FORWARD_PAGE = "forward_page";
/** The action command for moving backward one page. */
public static final String BACKWARD_PAGE = "backward_page";
/** The action command for printing. */
public static final String PRINT = "print";
/** The action command for quitting. */
public static final String QUIT = "quit";
public VizController (VizPanel vpanel)
{
_vpanel = vpanel;
// create a print job in case we need to print
_job = PrinterJob.getPrinterJob();
_format = _job.defaultPage();
// use sensible margins
Paper paper = new Paper();
paper.setImageableArea(
LEFT_MARGIN, TOP_MARGIN, PAGE_WIDTH, PAGE_HEIGHT);
_format.setPaper(paper);
}
public boolean handleAction (ActionEvent action)
{
String cmd = action.getActionCommand();
if (cmd.equals(FORWARD_PAGE)) {
int pno = _vpanel.getPage();
if (pno < _vpanel.getPageCount()-1) {
_vpanel.setPage(pno+1);
}
return true;
} else if (cmd.equals(BACKWARD_PAGE)) {
int pno = _vpanel.getPage();
if (pno > 0) {
_vpanel.setPage(pno-1);
}
return true;
} else if (cmd.equals(PRINT)) {
// create a pageable to be used by our print job that does the
// right thing
Pageable pable = new Pageable() {
public int getNumberOfPages () {
return _vpanel.getVisualizer().getPageCount();
}
public PageFormat getPageFormat (int pageIndex) {
return _format;
}
public Printable getPrintable (int pageIndex) {
return _vpanel.getVisualizer();
}
};
_job.setPageable(pable);
// pop up a dialog to control printing
if (_job.printDialog()) {
try {
// invoke the printing process
_job.print();
} catch (PrinterException pe) {
pe.printStackTrace(System.err);
}
}
return true;
} else if (cmd.equals(QUIT)) {
System.exit(0);
}
return false;
}
protected VizPanel _vpanel;
protected PrinterJob _job;
protected PageFormat _format;
// these should be configurable...
protected static final double LEFT_MARGIN = 72*0.5;
protected static final double TOP_MARGIN = 72*0.5;
protected static final double PAGE_WIDTH = 72*7.5;
protected static final double PAGE_HEIGHT = 72*10;
}
@@ -1,99 +0,0 @@
//
// $Id: VizFrame.java,v 1.6 2001/11/30 22:57:31 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
import java.awt.BorderLayout;
import javax.swing.*;
import com.samskivert.swing.*;
/**
* The top-level frame in which visualizations are displayed.
*/
public class VizFrame extends JFrame
{
public VizFrame (Visualizer viz)
{
super("viztool");
// quit if we're closed
setDefaultCloseOperation(EXIT_ON_CLOSE);
// create our controller and panel for displaying visualizations
VizPanel vpanel = new VizPanel(viz);
VizController vctrl = new VizController(vpanel);
// create some control buttons
GroupLayout gl = new HGroupLayout(GroupLayout.NONE);
gl.setJustification(GroupLayout.RIGHT);
JPanel bpanel = new JPanel(gl);
JButton btn;
btn = new JButton("Print");
btn.setActionCommand(VizController.PRINT);
btn.addActionListener(VizController.DISPATCHER);
bpanel.add(btn);
btn = new JButton("Previous page");
btn.setActionCommand(VizController.BACKWARD_PAGE);
btn.addActionListener(VizController.DISPATCHER);
bpanel.add(btn);
btn = new JButton("Next page");
btn.setActionCommand(VizController.FORWARD_PAGE);
btn.addActionListener(VizController.DISPATCHER);
bpanel.add(btn);
btn = new JButton("Quit");
btn.setActionCommand(VizController.QUIT);
btn.addActionListener(VizController.DISPATCHER);
bpanel.add(btn);
// create a content pane to contain everything
JPanel content = new ContentPanel(vctrl);
gl = new VGroupLayout(GroupLayout.STRETCH);
content.setLayout(gl);
content.setBorder(BorderFactory.createEmptyBorder(
BORDER, BORDER, BORDER, BORDER));
content.add(vpanel);
content.add(bpanel, GroupLayout.FIXED);
setContentPane(content);
}
protected static final class ContentPanel
extends JPanel
implements ControllerProvider
{
public ContentPanel (VizController ctrl)
{
_ctrl = ctrl;
}
public Controller getController ()
{
return _ctrl;
}
protected Controller _ctrl;
}
protected static final int BORDER = 5; // pixels
}
@@ -1,114 +0,0 @@
//
// $Id: VizPanel.java,v 1.8 2001/12/01 05:28:01 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
/**
* A very simple UI element for displaying visualizations on screen.
*/
public class VizPanel extends JPanel
{
/**
* Constructs a panel for displaying a particular visualization.
*/
public VizPanel (Visualizer viz)
{
// we'll need this later
_viz = viz;
// set the font
Font font = new Font("Courier", Font.PLAIN, 10);
setFont(font);
}
public void doLayout ()
{
super.doLayout();
Graphics2D gfx = (Graphics2D)getGraphics();
Rectangle2D bounds = getBounds();
_viz.layout(gfx, 0, 0, bounds.getWidth(), bounds.getHeight());
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
_viz.paint((Graphics2D)g, _currentPage);
}
public Dimension getPreferredSize ()
{
return new Dimension(PAGE_WIDTH, PAGE_HEIGHT);
}
/**
* Returns the number of pages in our current visualization. This is
* only valid after we've been rendered at least once because we
* needed the rendering graphics to realize the visualization.
*/
public int getPageCount ()
{
return _viz.getPageCount();
}
/**
* Requests that the panel display the specified page number (indexed
* from zero). Requests to display invalid page numbers will be
* ignored.
*/
public void setPage (int pageno)
{
if (pageno < _viz.getPageCount()) {
_currentPage = pageno;
repaint();
} else {
Log.warning("Requested to display invalid page " +
"[pageno=" + pageno +
", pages=" + _viz.getPageCount() + "].");
}
}
/**
* Returns the index of the page that we're currently displaying.
*/
public int getPage ()
{
return _currentPage;
}
/**
* Returns the visualizer we're currently displaying.
*/
public Visualizer getVisualizer ()
{
return _viz;
}
protected Visualizer _viz;
protected int _currentPage = 0;
// our preferred size is one page at 72 pixels per inch
protected static final int PAGE_WIDTH = (int)(72 * 8.5);
protected static final int PAGE_HEIGHT = (int)(72 * 11);
}
@@ -1,210 +0,0 @@
//
// $Id: ClassEnumerator.java,v 1.4 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Iterator;
/**
* The class enumerator is supplied with a classpath which it decomposes
* and enumerates over all of the classes available via those classpath
* componenets. To do this it uses component enumerators which know how to
* enumerate all of the classes in a directory tree, in a jar file, etc.
* The component enumerators are structured so that new enumerators can be
* authored for new kinds of classpath component.
*/
public class ClassEnumerator implements Iterator
{
/**
* Constructs a class enumerator with the supplied classpath. A set of
* component enumerators will be chosen for each element and warnings
* will be generated for components that cannot be processed for some
* reason or other. Those will be available following the completion
* of the constructor via <code>getWarnings()</code>.
*
* @see #getWarnings
*/
public ClassEnumerator (String classpath)
{
// decompose the path and select enumerators for each component
StringTokenizer tok = new StringTokenizer(classpath, ":");
ArrayList warnings = new ArrayList();
ArrayList enums = new ArrayList();
while (tok.hasMoreTokens()) {
String component = tok.nextToken();
// locate an enumerator for this token
ComponentEnumerator cenum = matchEnumerator(component);
if (cenum == null) {
String wmsg = "Unable to match enumerator for " +
"component '" + component + "'.";
warnings.add(new Warning(wmsg));
} else {
try {
// System.out.println("Adding [enum=" + cenum +
// ", component=" + component + "].");
// construct an enumerator to enumerate this component
// and put it on our list
enums.add(cenum.enumerate(component));
} catch (EnumerationException ee) {
// if there was a problem creating an enumerator for
// said component, create a warning to that effect
warnings.add(new Warning(ee.getMessage()));
}
}
}
// convert our list into an array
_enums = new ComponentEnumerator[enums.size()];
enums.toArray(_enums);
// convert the warnings into an array
_warnings = new Warning[warnings.size()];
warnings.toArray(_warnings);
// scan to the first class
scanToNextClass();
}
/**
* Locates an enumerator that matches the specified component and
* returns the prototype instance of that enumerator. Returns null if
* no enumerator could be matched.
*/
protected ComponentEnumerator matchEnumerator (String component)
{
for (int i = 0; i < _enumerators.size(); i++) {
ComponentEnumerator cenum =
(ComponentEnumerator)_enumerators.get(i);
if (cenum.matchesComponent(component)) {
return cenum;
}
}
return null;
}
/**
* Returns the warnings generated in parsing the classpath and
* constructing enumerators for each component. For example, if a
* classpath component specified a directory that was non-existent or
* inaccessible, a warning would be generated for that component. If
* no warnings were generated, a zero length array will be returned.
*/
public Warning[] getWarnings ()
{
return _warnings;
}
public boolean hasNext ()
{
return (_nextClass != null);
}
public Object next ()
{
String clazz = _nextClass;
_nextClass = null;
scanToNextClass();
return clazz;
}
public void remove ()
{
// not supported
}
/**
* Queues up the next enumerator in the list or clears out our
* enumerator reference if we have no remaining enumerators.
*/
protected void scanToNextClass ()
{
if (_enumidx < _enums.length) {
// grab the current enumerator
ComponentEnumerator cenum = _enums[_enumidx];
// if it has more classes
if (cenum.hasMoreClasses()) {
// get the next one
_nextClass = cenum.nextClass();
return;
} else {
// otherwise try the next enum
_enumidx++;
scanToNextClass();
}
}
}
protected ComponentEnumerator[] _enums;
protected int _enumidx;
protected String _nextClass;
protected Warning[] _warnings;
/**
* A warning is generated when a component of the classpath cannot be
* processed for some reason or other.
*/
public static class Warning
{
public String reason;
public Warning (String reason)
{
this.reason = reason;
}
}
public static void main (String[] args)
{
// run ourselves on the classpath
String classpath = System.getProperty("java.class.path");
ClassEnumerator cenum = new ClassEnumerator(classpath);
// print out the warnings
Warning[] warnings = cenum.getWarnings();
for (int i = 0; i < warnings.length; i++) {
System.out.println("Warning: " + warnings[i].reason);
}
// enumerate over whatever classes we can
while (cenum.hasNext()) {
System.out.println("Class: " + cenum.next());
}
}
protected static ArrayList _enumerators = new ArrayList();
static {
// register our enumerators
_enumerators.add(new ZipFileEnumerator());
_enumerators.add(new JarFileEnumerator());
// the directory enumerator should always be last in the list
// because it picks up all stragglers and tries enumerating them
// as if they were directories
_enumerators.add(new DirectoryEnumerator());
}
}
@@ -1,80 +0,0 @@
//
// $Id: ComponentEnumerator.java,v 1.2 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import com.samskivert.util.StringUtil;
/**
* A component enumerator knows how to enumerate all of the classes in a
* particular classpath component. Examples include a zip file enumerator,
* a directory tree enumerator and a jar file enumerator.
*/
public abstract class ComponentEnumerator
{
/**
* To determine which component enumerator should be used for a given
* classpath component, one instance of each is maintained and used
* for the matching process.
*
* @return true if this enumerator should be used to enumerate the
* specified classpath component; false otherwise.
*/
public abstract boolean matchesComponent (String component);
/**
* Instantiates an instance of the underlying enumerator and
* configures it to enumerate the specified classpath component.
*
* @exception EnumerationException thrown if some problem (like file
* or directory not existing or being inaccessible) prevents the
* enumerator from enumerating the component.
*/
public abstract ComponentEnumerator enumerate (String component)
throws EnumerationException;
/**
* Returns true if there are more classes yet to be enumerated for
* this component.
*/
public abstract boolean hasMoreClasses ();
/**
* Returns the next class in this component's enumeration.
*/
public abstract String nextClass ();
/**
* Converts a classfile path to a class name (eg. foo/bar/Baz.class
* converts to foo.bar.Baz).
*/
protected String pathToClassName (String path)
{
// strip off the .class suffix
path = path.substring(0, path.length() - CLASS_SUFFIX.length());
// convert slashes to dots
return StringUtil.replace(path, "/", ".");
}
/**
* This is used to identify class files.
*/
protected static final String CLASS_SUFFIX = ".class";
}
@@ -1,181 +0,0 @@
//
// $Id: DirectoryEnumerator.java,v 1.2 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import java.io.*;
import java.util.ArrayList;
import com.samskivert.util.StringUtil;
import com.samskivert.viztool.Log;
/**
* The directory enumerator enumerates all of the classes in a directory
* hierarchy.
*/
public class DirectoryEnumerator extends ComponentEnumerator
{
/**
* Constructs a prototype enumerator that can be used for matching.
*/
public DirectoryEnumerator ()
{
}
/**
* Constructs a directory enumerator with the specified root directory
* for enumeration.
*/
public DirectoryEnumerator (String dirpath)
throws EnumerationException
{
_root = new File(dirpath);
_rootpath = _root.getAbsolutePath();
// make sure the specified component exists
if (!_root.exists()) {
String msg = "Can't enumerate '" + dirpath +
"': directory doesn't exist";
throw new EnumerationException(msg);
}
// make sure the specified component is a directory
if (!_root.isDirectory()) {
String msg = "Can't enumerate non-directory '" + dirpath + "'.";
throw new EnumerationException(msg);
}
// create a directory record for our root directory
addDirectory(_root);
// and scan to the first class
scanToNextClass();
}
// documentation inherited from interface
public boolean matchesComponent (String component)
{
// the directory enumerator picks up anything that falls through
// the zip or jar file enumerators
return true;
}
// documentation inherited from interface
public ComponentEnumerator enumerate (String component)
throws EnumerationException
{
return new DirectoryEnumerator(component);
}
// documentation inherited from interface
public boolean hasMoreClasses ()
{
return (_nextClass != null);
}
// documentation inherited from interface
public String nextClass ()
{
String clazz = _nextClass;
_nextClass = null;
scanToNextClass();
return clazz;
}
protected void scanToNextClass ()
{
// if we have no drecords, we have nothing to do
while (_drecords.size() > 0) {
// grab a reference to the last drecord in the list
DirRecord rec = (DirRecord)_drecords.get(_drecords.size()-1);
// grab the file related to our current position
File target = rec.kids[rec.kidpos];
// bump up the kidpos so that things are in place for the next
// iteration; if we just grabbed the last kid, pop this record
// off of the stack
if (++rec.kidpos >= rec.kids.length) {
_drecords.remove(_drecords.size()-1);
}
// if our target file is a directory, push another drecord
// onto the stack and recurse into it
if (target.isDirectory()) {
addDirectory(target);
continue;
}
// otherwise, process it as a file
String path = target.getAbsolutePath();
// make sure it's readable
if (!target.canRead()) {
Log.warning("Can't read file '" + path + "'.");
continue;
}
// check to see if it matches our filename pattern
if (path.endsWith(CLASS_SUFFIX)) {
// strip off the root path (plus one for the trailing slash)
path = path.substring(_rootpath.length()+1);
_nextClass = pathToClassName(path);
return;
}
// if we didn't match, we loop back through and process the
// next kid (potentially popping back up the directory record
// stack in the process)
}
}
protected void addDirectory (File dir)
{
DirRecord rec = new DirRecord(dir);
if (rec.kids == null) {
String path = dir.getAbsolutePath();
// complain if there was an error reading the directory
Log.warning("Unable to scan directory '" + path + "'.");
} else if (rec.kids.length > 0) {
// only add the record if the directory actually has some
// children that we can scan
_drecords.add(rec);
}
}
protected static class DirRecord
{
public File directory;
public File[] kids;
public int kidpos;
public DirRecord (File directory)
{
this.directory = directory;
kids = directory.listFiles();
}
}
protected File _root;
protected String _rootpath;
protected ArrayList _drecords = new ArrayList();
protected String _nextClass;
}
@@ -1,35 +0,0 @@
//
// $Id: EnumerationException.java,v 1.2 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
/**
* An enumeration exception is thrown when some problem occurs while
* attempting to enumerate over a classpath component. This may be when
* initially attempting to read a zip or jar file, or during the process
* of enumeration.
*/
public class EnumerationException extends Exception
{
public EnumerationException (String message)
{
super(message);
}
}
@@ -1,92 +0,0 @@
//
// $Id: FilterEnumerator.java,v 1.3 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import java.util.Iterator;
/**
* The filter enumerator provides the framework by which a particular
* subset of classes can be filtered from the total enumeration of classes
* in a classpath. This is useful for doing things like only considering
* classes in a particular package or only considering interfaces, and so
* on.
*/
public abstract class FilterEnumerator implements Iterator
{
/**
* Constructs a filter enumerator with the supplied class enumerator
* as the source of classes.
*/
public FilterEnumerator (Iterator source)
{
_source = source;
// we'd love to call scanToNextClass() here but that calls
// filterClass() and it's extremely bad form to call a function
// provided by a derived class in the super class's constructor
// because the derived class's constructor hasn't yet been
// executed. sigh.
}
public boolean hasNext ()
{
if (_nextClass == null) {
scanToNextClass();
}
return _nextClass != null;
}
public Object next ()
{
if (_nextClass == null) {
scanToNextClass();
}
String clazz = _nextClass;
_nextClass = null;
scanToNextClass();
return clazz;
}
public void remove ()
{
// not supported
}
protected void scanToNextClass ()
{
while (_source.hasNext()) {
String clazz = (String)_source.next();
if (!filterClass(clazz)) {
_nextClass = clazz;
break;
}
}
}
/**
* Derived classes should override this method and return true if the
* specified class should be filtered (meaning it should be excluded
* from the classes returned) or false if it should be included.
*/
protected abstract boolean filterClass (String clazz);
protected Iterator _source;
protected String _nextClass;
}
@@ -1,53 +0,0 @@
//
// $Id: JarFileEnumerator.java,v 1.2 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
/**
* The jar file enumerator enumerates all of the classes in a .jar class
* archive.
*/
public class JarFileEnumerator extends ZipFileEnumerator
{
/**
* Constructs a prototype enumerator that can be used for matching.
*/
public JarFileEnumerator ()
{
}
/**
* Constructs a jar file enumerator with the specified jar file for
* enumeration.
*/
public JarFileEnumerator (String jarpath)
throws EnumerationException
{
super(jarpath);
}
// documentation inherited from interface
public boolean matchesComponent (String component)
{
return component.endsWith(JAR_SUFFIX);
}
protected static final String JAR_SUFFIX = ".jar";
}
@@ -1,70 +0,0 @@
//
// $Id: PackageEnumerator.java,v 1.3 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import java.util.Iterator;
/**
* The package enumerator filters out only classes from the specified
* package from the class enumerator provided at construct time.
*/
public class PackageEnumerator extends FilterEnumerator
{
public PackageEnumerator (String pkg, Iterator source, boolean subpkgs)
{
super(source);
_package = pkg;
_subpkgs = subpkgs;
}
protected boolean filterClass (String clazz)
{
if (!clazz.startsWith(_package)) {
return true;
}
return _subpkgs ? false:
(clazz.substring(_package.length()+1).indexOf(".") != -1);
}
public static void main (String[] args)
{
// run ourselves on the classpath
String classpath = System.getProperty("java.class.path");
ClassEnumerator clenum = new ClassEnumerator(classpath);
String pkg = "com.samskivert.viztool.clenum";
PackageEnumerator penum = new PackageEnumerator(pkg, clenum, true);
// print out the warnings
ClassEnumerator.Warning[] warnings = clenum.getWarnings();
for (int i = 0; i < warnings.length; i++) {
System.out.println("Warning: " + warnings[i].reason);
}
// enumerate over whatever classes match our package
while (penum.hasNext()) {
System.out.println("Class: " + penum.next());
}
}
protected String _package;
protected boolean _subpkgs;
}
@@ -1,50 +0,0 @@
//
// $Id: RegexpEnumerator.java,v 1.2 2003/01/28 22:39:35 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import java.util.Iterator;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* The regex enumerator filters classes based on a regular expression.
*/
public class RegexpEnumerator extends FilterEnumerator
{
public RegexpEnumerator (String regexp, String exregex, Iterator source)
throws PatternSyntaxException
{
super(source);
_regexp = Pattern.compile(regexp);
if (exregex != null) {
_exreg = Pattern.compile(exregex);
}
}
protected boolean filterClass (String clazz)
{
return !(_regexp.matcher(clazz).matches() &&
(_exreg == null || !_exreg.matcher(clazz).matches()));
}
protected Pattern _regexp;
protected Pattern _exreg;
}
@@ -1,125 +0,0 @@
//
// $Id: ZipFileEnumerator.java,v 1.2 2001/08/12 04:36:57 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.clenum;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.*;
import com.samskivert.viztool.Log;
/**
* The zip file enumerator enumerates all of the classes in a .zip class
* archive.
*/
public class ZipFileEnumerator extends ComponentEnumerator
{
/**
* Constructs a prototype enumerator that can be used for matching.
*/
public ZipFileEnumerator ()
{
}
/**
* Constructs a zip file enumerator with the specified zip file for
* enumeration.
*/
public ZipFileEnumerator (String zippath)
throws EnumerationException
{
try {
_zipfile = new ZipFile(zippath);
_entenum = _zipfile.entries();
scanToNextClass();
} catch (IOException ioe) {
String msg = "Can't enumerate zip file '" + zippath + "': " +
ioe.getMessage();
throw new EnumerationException(msg);
}
}
// documentation inherited from interface
public boolean matchesComponent (String component)
{
return component.endsWith(ZIP_SUFFIX);
}
// documentation inherited from interface
public ComponentEnumerator enumerate (String component)
throws EnumerationException
{
return new ZipFileEnumerator(component);
}
// documentation inherited from interface
public boolean hasMoreClasses ()
{
return (_nextClass != null);
}
// documentation inherited from interface
public String nextClass ()
{
String clazz = _nextClass;
_nextClass = null;
scanToNextClass();
return clazz;
}
protected void scanToNextClass ()
{
// if we've already scanned to the end of our zipfile, we can bail
// immediately
if (_zipfile == null) {
return;
}
// otherwise scan through the zip contents for the next thing that
// looks like a class
while (_entenum.hasMoreElements()) {
ZipEntry entry = (ZipEntry)_entenum.nextElement();
String nextClass = entry.getName();
if (nextClass.endsWith(CLASS_SUFFIX)) {
_nextClass = pathToClassName(nextClass);
break;
}
}
// if we've reached the end of the zip file, we want to close
// things up
if (_zipfile != null && _nextClass == null) {
try {
_zipfile.close();
} catch (IOException ioe) {
Log.warning("Error closing archive: " + ioe.getMessage());
}
_zipfile = null;
}
}
protected ZipFile _zipfile;
protected Enumeration _entenum;
protected String _nextClass;
protected static final String ZIP_SUFFIX = ".zip";
}
@@ -1,45 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: package.html,v 1.2 2001/08/12 04:36:57 mdb Exp $
viztool - a tool for visualizing collections of java classes
Copyright (C) 2001 Michael Bayne
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
</head>
<body bgcolor="white">
Provides the ability to enumerate over all classes in the classpath
and filter those enumerations.
<p> The main interface for enumerating classes is the {@link
com.samskivert.viztool.enum.ClassEnumerator}. It scans through the
class path and attempts to match a component enumerator to each
component. The {@link
com.samskivert.viztool.enum.DirectoryEnumerator} is used for all
components that don't match one of the other (zip or jar)
enumerators. These component enumerators are then used in turn to
enumerate through all of the classes in the class path.
<p> The enumeration can be filtered by making use of a {@link
com.samskivert.viztool.enum.FilterEnumerator}.
</body>
</html>
@@ -1,189 +0,0 @@
//
// $Id: CascadingChainVisualizer.java,v 1.11 2001/12/01 05:28:01 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.hierarchy;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import java.awt.geom.*;
import java.util.ArrayList;
import com.samskivert.viztool.util.FontPicker;
import com.samskivert.viztool.util.LayoutUtil;
import com.samskivert.viztool.util.RenderUtil;
/**
* The cascading chain visualizer lays out chains in the standard
* cascading format that looks something like this:
*
* <pre>
* Foo
* |
* +-> Bar
* | |
* | +-> Biff
* |
* +-> Baz
* </pre>
*/
public class CascadingChainVisualizer
implements ChainVisualizer
{
// docs inherited from interface
public void layoutChain (Chain chain, Graphics2D gfx)
{
FontRenderContext frc = gfx.getFontRenderContext();
// the header will be the name of this chain surrounded by N
// points of space and a box
Rectangle2D bounds = LayoutUtil.getTextBox(
chain.getRoot().isInterface() ? FontPicker.getInterfaceFont() :
FontPicker.getClassFont(), frc, chain.getName());
// 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();
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getImplementsFont(),
frc, LayoutUtil.SUBORDINATE_INSET, impls);
String[] decls = chain.getDeclaresNames();
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getDeclaresFont(),
frc, LayoutUtil.SUBORDINATE_INSET, decls);
}
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
double x = 2*LayoutUtil.GAP, y = bounds.getHeight();
ArrayList kids = chain.getChildren();
for (int i = 0; i < kids.size(); i++) {
Chain kid = (Chain)kids.get(i);
Rectangle2D kbounds = kid.getBounds();
y += LayoutUtil.GAP; // add the gap
kid.setBounds(x, y, kbounds.getWidth(), kbounds.getHeight());
y += kbounds.getHeight(); // add the dimensions of the kid
// track max width
if (maxwid < (x + kbounds.getWidth())) {
maxwid = x + kbounds.getWidth();
}
}
// set the dimensions of the main chain
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() + LayoutUtil.HEADER_BORDER;
double y = bounds.getY() + LayoutUtil.HEADER_BORDER;
double maxwid = 0;
// draw the name
FontRenderContext frc = gfx.getFontRenderContext();
Font font = chain.getRoot().isInterface() ?
FontPicker.getInterfaceFont() : FontPicker.getClassFont();
Rectangle2D bnds =
RenderUtil.renderString(gfx, frc, font, x, y, chain.getName());
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER);
y += bnds.getHeight();
// draw the interface and inner class info, but only if we're not
// an out of package class
if (chain.inPackage()) {
// render the implemented interfaces
String[] impls = chain.getImplementsNames();
bnds = RenderUtil.renderStrings(
gfx, frc, FontPicker.getImplementsFont(),
x + LayoutUtil.SUBORDINATE_INSET, y, impls);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER +
LayoutUtil.SUBORDINATE_INSET);
y += bnds.getHeight();
// render the declared inner classes
String[] decls = chain.getDeclaresNames();
bnds = RenderUtil.renderStrings(
gfx, frc, FontPicker.getDeclaresFont(),
x + LayoutUtil.SUBORDINATE_INSET, y, decls);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER +
LayoutUtil.SUBORDINATE_INSET);
y += bnds.getHeight();
}
// leave a border at the bottom as well
y += LayoutUtil.HEADER_BORDER;
// stroke a box that will contain the name
Rectangle2D outline = new Rectangle2D.Double(
bounds.getX(), bounds.getY(), maxwid, y - bounds.getY());
gfx.draw(outline);
// keep track of the bottom
double height = y;
// reset our top level coords
x = bounds.getX();
y = bounds.getY();
// 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)height);
for (int i = 0; i < kids.size(); i++) {
Chain kid = (Chain)kids.get(i);
kbounds = kid.getBounds();
double ly = y + kbounds.getY() + 2*LayoutUtil.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);
}
}
@@ -1,418 +0,0 @@
//
// $Id: Chain.java,v 1.10 2001/11/30 22:57:31 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.hierarchy;
import java.util.*;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import com.samskivert.viztool.layout.Element;
/**
* A chain is used by the hierarchy visualizer to represent inheritance
* chains.
*/
public class Chain implements Element
{
/**
* Constructs a chain with the specified class as its root.
*/
public Chain (String name, Class root, boolean inpkg)
{
_name = name;
_root = root;
_inpkg = inpkg;
}
/**
* Returns the name of this chain (which should be used when
* displaying the chain).
*/
public String getName ()
{
return _name;
}
/**
* Returns the class that forms the root of this chain.
*/
public Class getRoot ()
{
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.
*/
public String getRootName ()
{
return _root.getName();
}
/**
* Sorts this chain's children and the children's children so that a
* particular ordering is observed throughout the tree (generally
* alphabetical, but other orderings could be used).
*/
public void sortChildren (Comparator comp)
{
// my kingdom for List.sort() or even ArrayList.sort()... sigh.
Chain[] kids = new Chain[_children.size()];
_children.toArray(kids);
Arrays.sort(kids, comp);
_children.clear();
for (int i = 0; i < kids.length; i++) {
// sort each child
kids[i].sortChildren(comp);
_children.add(kids[i]);
}
}
/**
* 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();
ArrayList names = new ArrayList();
for (int i = 0; i < decls.length; i++) {
String name = decls[i].getName();
// strip off anything up to and including the dollar
int didx = name.indexOf("$");
if (didx != -1) {
name = name.substring(didx+1);
}
// if this inner class name is a number, it's an anonymous
// class and we want to skip it
try {
Integer.parseInt(name);
continue;
} catch (NumberFormatException nfe) {
}
// otherwise it passes the test
names.add(name);
}
String[] anames = new String[names.size()];
names.toArray(anames);
return anames;
}
/**
* Returns a <code>Rectangle2D</code> instance representing the size
* of this chain (and all contained subchains).
*/
public Rectangle2D getBounds ()
{
return _bounds;
}
/**
* Sets the bounds of this chain.
*
* @see #getBounds
*/
public void setBounds (double x, double y, double width, double height)
{
_bounds.setRect(x, y, width, height);
}
/**
* Returns an array list containing the children chains of this chain.
* If this chain has no children the list will be of zero length but
* will not be null. This list should <em>not</em> be modified. Oh,
* for a <code>const</code> keyword.
*/
public ArrayList getChildren ()
{
return _children;
}
/**
* Lays out all of the children of this chain and then requests that
* the supplied layout manager arrange those children and compute the
* dimensions of this chain based on all of that information.
*
* @param gfx the graphics context to use when computing dimensions.
* @param cviz the chain visualizer to be used for laying out.
* @param width the width in which the chain must fit.
* @param height the height in which the chain must fit.
*
* @return if the chain cannot be laid out in the required dimensions,
* branches of the chain will be removed so that it can fit into the
* necessary dimensions. A new chain will be created with the
* remaining branches which should be laid out itself so that it too
* may further prune itself to fit into the necessary dimensions. If
* the chain fits into the requested dimensions, null will be
* returned.
*/
public Chain layout (Graphics2D gfx, ChainVisualizer cviz,
double width, double height)
{
// lay everything out
layout(gfx, cviz);
// determine if we need to do some pruning (we only deal with
// height pruning presently)
if (_bounds.getHeight() <= height) {
return null;
}
double x = 0, y = 0;
Chain oflow = pruneOverflow(x, y, width, height);
// if something wigged out and we try to overflow our whole selves
// at this point (like this chain is one big fat chain with no
// children that doesn't fit into the space) we must punt and
// pretend like there's no overflow
return (oflow == this) ? null : oflow;
}
protected 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(gfx, cviz);
}
// now lay ourselves out
cviz.layoutChain(this, gfx);
}
protected Chain pruneOverflow (
double x, double y, double width, double height)
{
// offset our current position by the position of this chain
Rectangle2D bounds = getBounds();
x += bounds.getX();
y += bounds.getY();
Chain oflow = null;
for (int i = 0; i < _children.size(); i++) {
Chain child = (Chain)_children.get(i);
// if we've switched to flowing over, just add this chain to
// the overflow chain (and remove it from ourselves)
if (oflow != null) {
_children.remove(i--);
oflow._children.add(child);
continue;
}
Rectangle2D cbounds = child.getBounds();
double cx = cbounds.getX(), cy = cbounds.getY();
// if this child doesn't fit in the current space, we need to
// break it up and overflow the extra nodes
if (y + cy + cbounds.getHeight() > height) {
Chain coflow = child.pruneOverflow(x, y, width, height);
// make sure this child claims some sort of overflow (if
// it doesn't something is wacked, but we'll try to deal)
if (coflow != null) {
// if this entire child is overflowed
if (coflow == child) {
// remove the child from this chain and add it to our
// overflow chain
_children.remove(i--);
}
// regardless, add what we got to the overflow chain
oflow = createOverflowChain();
oflow._children.add(coflow);
} else {
System.err.println("Overflowing child unable " +
"to overflow " + child._name + ".");
}
}
}
// if we have no children (or we overflowed *all* of our children)
// then we need to overflow ourselves rather than create a new
// chain for overflowing
if (_children.size() == 0) {
// grab our kids back from the overflow chain
if (oflow != null) {
_children = oflow._children;
}
return this;
} else {
// otherwise, adjust our height to just enclose the height of
// our last child because we removed some children and changed
// our dimensions. this is sort of a hack because it assumes
// that the chain visualizer isn't leaving any gap beyond the
// bottom of a child chain but it's somewhat safe because if
// they did, that gap would accumulate unaesthetically
Chain child = (Chain)_children.get(_children.size()-1);
Rectangle2D cbounds = child.getBounds();
_bounds.setRect(_bounds.getX(), _bounds.getY(), _bounds.getWidth(),
cbounds.getY() + cbounds.getHeight());
}
return oflow;
}
protected Chain createOverflowChain ()
{
return new Chain(_name, _root, _inpkg);
}
/**
* 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 (String name, Class 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)) {
_children.add(chain);
}
}
/**
* Locates the chain for the specified target class and returns it if
* it is a registered child of this chain. Returns null if no child
* chain of this chain contains the specified target class.
*/
public Chain getChain (Class target)
{
if (_root.equals(target)) {
return this;
}
// just do a depth first search because it's fun
for (int i = 0; i < _children.size(); i++) {
Chain chain = ((Chain)_children.get(i)).getChain(target);
if (chain != null) {
return chain;
}
}
return null;
}
public boolean equals (Object other)
{
if (other == null) {
return false;
} else if (other instanceof Chain) {
return ((Chain)other)._root.equals(_root);
} else {
return false;
}
}
public String toString ()
{
StringBuffer out = new StringBuffer();
toString("", out);
return out.toString();
}
protected void toString (String indent, StringBuffer out)
{
out.append(indent).append(_name).append("\n");
for (int i = 0; i < _children.size(); i++) {
Chain child = (Chain)_children.get(i);
child.toString(indent + " ", out);
}
}
protected String _name;
protected Class _root;
protected boolean _inpkg;
protected ArrayList _children = new ArrayList();
protected Rectangle2D _bounds = new Rectangle2D.Double();
}
@@ -1,257 +0,0 @@
//
// $Id: ChainGroup.java,v 1.13 2001/12/03 08:34:53 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.hierarchy;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.font.TextLayout;
import java.util.*;
import com.samskivert.viztool.layout.ElementLayout;
import com.samskivert.viztool.layout.PackedColumnElementLayout;
import com.samskivert.viztool.util.FontPicker;
/**
* 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, pkg, iter);
// sort our roots
for (int i = 0; i < _roots.size(); i++) {
Chain root = (Chain)_roots.get(i);
root.sortChildren(NAME_COMP);
}
// System.err.println(_roots.size() + " chains for " + pkg + ".");
}
protected ChainGroup (String pkg, ArrayList roots)
{
_pkg = pkg;
_roots = roots;
}
/**
* Returns the dimensions of this chain group. This value is only
* valid after <code>layout</code> has been called.
*/
public Rectangle2D getBounds ()
{
return _size;
}
/**
* Sets the upper left coordinate of this group. The group itself
* never looks at this information, but it will be made available as
* the x and y coordinates of the rectangle returned by
* <code>getBounds</code>.
*/
public void setPosition (double x, double y)
{
_size.setRect(x, y, _size.getWidth(), _size.getHeight());
}
/**
* Returns the page on which this group should be rendered.
*/
public int getPage ()
{
return _page;
}
/**
* Sets the page on which this group should be rendered.
*/
public void setPage (int page)
{
_page = page;
}
/**
* Lays out the chains in this group and returns the total size. If
* the layout process requires that this chain group be split across
* multiple pages, a new chain group containing the overflow chains
* will be returned. If the group fits in the allotted space, null
* will be returned.
*/
public ChainGroup layout (
Graphics2D gfx, double pageWidth, double pageHeight)
{
// we'll need room to incorporate our title
TextLayout layout = new TextLayout(_pkg, FontPicker.getTitleFont(),
gfx.getFontRenderContext());
// we let the title stick halfway up out of our rectangular
// bounding box
Rectangle2D tbounds = layout.getBounds();
double titleAscent = tbounds.getHeight()/2;
// keep room for our border and title
pageWidth -= 2*BORDER;
pageHeight -= (2*BORDER + titleAscent);
// lay out the internal structure of our chains
ChainVisualizer clay = new CascadingChainVisualizer();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
Chain oflow = chain.layout(gfx, clay, pageWidth, pageHeight);
// if this chain overflowed when being laid out, add the newly
// created root to our list
if (oflow != null) {
_roots.add(i+1, oflow);
}
}
// arrange them on the page
ElementLayout elay = new PackedColumnElementLayout();
ArrayList overflow = new ArrayList();
_size = elay.layout(_roots, pageWidth, pageHeight, overflow);
// make sure we're wide enough for our title
double width = Math.max(_size.getWidth(), layout.getAdvance() + 4);
// adjust for our border and title
double height = _size.getHeight() + titleAscent;
_size.setRect(0, 0, width + 2*BORDER, height + 2*BORDER);
// if we have overflow elements, create a new chain group with
// these elements, remove them from our roots list and be on our
// way
if (overflow.size() > 0) {
// remove the overflow roots from our list
for (int i = 0; i < overflow.size(); i++) {
_roots.remove(overflow.get(i));
}
return new ChainGroup(_pkg, overflow);
}
return null;
}
/**
* Renders the chains in this group to the supplied graphics object.
* This function requires that <code>layout</code> has previously been
* called to lay out the group's chains.
*
* @see #layout
*/
public void render (Graphics2D gfx, double x, double y)
{
TextLayout layout = new TextLayout(_pkg, FontPicker.getTitleFont(),
gfx.getFontRenderContext());
// we let the title stick halfway up out of our rectangular
// bounding box
Rectangle2D tbounds = layout.getBounds();
double titleAscent = tbounds.getHeight()/2;
double dy = -tbounds.getY();
// print our title
layout.draw(gfx, (float)(x + BORDER + 2), (float)(y + dy));
// shift everything down by the ascent of the title
y += titleAscent;
// translate to our rendering area
double cx = x + BORDER;
double cy = y + BORDER;
gfx.translate(cx, cy);
// render our chains
ChainVisualizer renderer = new CascadingChainVisualizer();
for (int i = 0; i < _roots.size(); i++) {
Chain chain = (Chain)_roots.get(i);
Rectangle2D bounds = chain.getBounds();
// render the chain
renderer.renderChain(chain, gfx);
}
// undo the translation
gfx.translate(-cx, -cy);
// print our border box
double height = _size.getHeight() - titleAscent;
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);
}
public Chain getRoot (int index)
{
return (Chain)_roots.get(index);
}
public String toString ()
{
return "[pkg=" + _pkg + ", roots=" + _roots.size() +
", size=" + _size + ", page=" + _page + "]";
}
protected String _pkg;
protected ArrayList _roots;
protected Rectangle2D _size;
protected int _page;
protected static final double BORDER = 72/8;
/**
* Compares the names of two chains. Used to sort them into
* alphabetical order.
*/
protected static class NameComparator implements Comparator
{
public int compare (Object o1, Object o2)
{
Chain c1 = (Chain)o1;
Chain c2 = (Chain)o2;
return c1.getName().compareTo(c2.getName());
}
public boolean equals (Object other)
{
return (other == this);
}
}
protected static final Comparator NAME_COMP = new NameComparator();
}
@@ -1,209 +0,0 @@
//
// $Id: ChainUtil.java,v 1.8 2001/12/03 08:34:53 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.hierarchy;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import com.samskivert.viztool.Log;
/**
* Chain related utility functions.
*/
public class ChainUtil
{
/**
* Builds a list of chains for the classes enumerated by the supplied
* enumerator. Classes outside the specified package root will be
* ignored except where they are the direct parent of an enumerated
* class inside the package root.
*
* @return an array list containing all of the root chains.
*/
public static ArrayList buildChains (
String pkgroot, String pkg, Iterator iter)
{
ArrayList roots = new ArrayList();
computeRoots(pkgroot, pkg, iter, roots);
return roots;
}
/**
* Looks up the chain that contains the specified target class as it's
* root class in the supplied array list of chains.
*
* @return the matching chain or null if no chain could be found.
*/
public static Chain getChain (ArrayList roots, Class target)
{
// figure out which of our root chains (if any) contains the
// specified class
for (int i = 0; i < roots.size(); i++) {
Chain root = (Chain)roots.get(i);
Chain chain = root.getChain(target);
if (chain != null) {
return chain;
}
}
return null;
}
/**
* Dumps the classes in the supplied array list of chain instances to
* stdout.
*/
public static void dumpClasses (PrintStream out, ArrayList roots)
{
for (int i = 0; i < roots.size(); i++) {
Chain root = (Chain)roots.get(i);
out.print(root.toString());
}
out.flush();
}
/**
* Scans the list of classes provided by the supplied iterator and
* constructs a hierarchical representation of those classes.
*/
protected static void computeRoots (
String pkgroot, String pkg, Iterator iter, ArrayList roots)
{
while (iter.hasNext()) {
Class clazz = (Class)iter.next();
String name = clazz.getName();
// skip classes not in the package in question
if (!name.startsWith(pkg) ||
name.substring(pkg.length()+1).indexOf(".") != -1) {
continue;
}
insertClass(roots, pkgroot, clazz, false);
}
}
/**
* 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, 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, name, target, true);
} 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 (!tpkg.equals(ppkg)) {
String pname = generateName(parent, pkgroot, true);
insertRoot(roots, pname, parent, false);
}
// and now hang ourselves off of our parent class
Chain chain = getChain(roots, parent);
if (chain == null) {
// if there's no chain for our parent class, we'll need to
// insert it into the hierarchy
boolean samepkg = pkgFromClass(parent.getName()).equals(
pkgFromClass(target.getName()));
insertClass(roots, pkgroot, parent, !samepkg);
// and refetch our chain
chain = getChain(roots, parent);
// sanity check
if (chain == null) {
Log.warning("Chain still doesn't exist even though " +
"we inserted our parent " +
"[class=" + target.getName() +
", parent=" + parent.getName() + "].");
return;
}
}
// add class will ignore our request if this class was already
// added due to some previous operation
chain.addClass(name, target);
}
}
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, boolean inpkg)
{
Chain chroot = new Chain(name, root, inpkg);
// make sure no chain already exists for this root
if (!roots.contains(chroot)) {
roots.add(chroot);
return true;
} else {
return false;
}
}
}
@@ -1,53 +0,0 @@
//
// $Id: ChainVisualizer.java,v 1.4 2001/11/30 22:57:31 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.hierarchy;
import java.awt.Graphics2D;
/**
* 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 ChainVisualizer
{
/**
* Assigns positions to the children of the supplied chain based on
* the layout policies desired by the implementation and assigns
* dimensions to the specified chain based on the dimensions of its
* children and the aforementioned layout policies. The children of
* the provided chain instance are guaranteed to have been layed out
* (meaning they have dimensions but no position) prior to this call.
*
* @param chain the chain to be layed out.
* @param gfx the graphics context to use when computing dimensions.
*/
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);
}
@@ -1,195 +0,0 @@
//
// $Id: HierarchyVisualizer.java,v 1.16 2001/12/03 08:34:53 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.hierarchy;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.print.*;
import java.util.*;
import com.samskivert.util.Comparators;
import com.samskivert.util.CollectionUtil;
import com.samskivert.viztool.Log;
import com.samskivert.viztool.Visualizer;
import com.samskivert.viztool.clenum.PackageEnumerator;
/**
* The hierarchy visualizer displays inheritance hierarchies in a compact
* representation so that an entire package can be displayed on a single
* page (or small number of pages).
*/
public class HierarchyVisualizer implements Visualizer
{
// documentation inherited
public void setPackageRoot (String pkgroot)
{
_pkgroot = pkgroot;
}
// documentation inherited
public void setClasses (Iterator iter)
{
// dump all the classes into an array list so that we can
// repeatedly scan through the list
CollectionUtil.addAll(_classes, iter);
// compile a list of all packages in our collection
HashSet pkgset = new HashSet();
iter = _classes.iterator();
while (iter.hasNext()) {
Class cl = (Class)iter.next();
pkgset.add(ChainUtil.pkgFromClass(cl.getName()));
}
// 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);
// System.err.println("Scanned " + _packages.length + " packages.");
// now create chain groups for each package
_groups = new ArrayList();
for (int i = 0; i < _packages.length; i++) {
_groups.add(new ChainGroup(_pkgroot, _packages[i],
_classes.iterator()));
}
}
/**
* Lays out and renders each of the chain groups that make up this
* package hierarchy visualization.
*/
public int print (Graphics g, PageFormat pf, int pageIndex)
throws PrinterException
{
Graphics2D gfx = (Graphics2D)g;
// adjust the stroke
gfx.setStroke(new BasicStroke(0.1f));
// only relay things out if the page format has changed
if (!pf.equals(_format)) {
// keep this around
_format = pf;
// and do the layout
layout(gfx, pf.getImageableX(), pf.getImageableY(),
pf.getImageableWidth(), pf.getImageableHeight());
}
// render the groups on the requested page
int rendered = 0;
for (int i = 0; i < _groups.size(); i++) {
ChainGroup group = (ChainGroup)_groups.get(i);
// skip groups not on this page
if (group.getPage() != pageIndex) {
continue;
}
Rectangle2D bounds = group.getBounds();
group.render(gfx, bounds.getX(), bounds.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 = y;
int pageno = 0;
// lay out our groups
for (int i = 0; i < _groups.size(); i++) {
ChainGroup group = (ChainGroup)_groups.get(i);
// lay out the group in question
ChainGroup ngrp = group.layout(gfx, width, height);
// if the process of laying this group out caused it to become
// split across pages, insert this new group into the list
if (ngrp != null) {
_groups.add(i+1, ngrp);
}
// determine if we need to skip to the next page or not
Rectangle2D bounds = group.getBounds();
if ((y > starty) && (y + bounds.getHeight() > height + starty)) {
y = starty;
pageno++;
}
// assign x and y coordinates to this group
group.setPosition(x, y);
// make a note of our page index
group.setPage(pageno);
// increment our y location
y += (bounds.getHeight() + GAP);
}
// our page count is one more than the highest page number
_pageCount = pageno+1;
}
public void paint (Graphics2D gfx, int pageIndex)
{
// render the groups on the requested page
for (int i = 0; i < _groups.size(); i++) {
ChainGroup group = (ChainGroup)_groups.get(i);
// skip groups not on this page
if (group.getPage() != pageIndex) {
continue;
}
Rectangle2D bounds = group.getBounds();
group.render((Graphics2D)gfx, bounds.getX(), bounds.getY());
}
}
/**
* Returns the number of pages occupied by this visualization. This is
* only valid after a call to {@link #layout}.
*
* @return the page count or -1 if we've not yet been laid out.
*/
public int getPageCount ()
{
return _pageCount;
}
protected String _pkgroot;
protected ArrayList _classes = new ArrayList();
protected String[] _packages;
protected ArrayList _groups;
protected int _pageCount = -1;
protected PageFormat _format;
protected static final int GAP = 72/4;
}
@@ -1,46 +0,0 @@
//
// $Id: Element.java,v 1.4 2001/11/30 22:57:31 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.layout;
import java.awt.geom.Rectangle2D;
/**
* A page is composed of elements which have some rectangular bounds.
* They can be laid out by <code>ElementLayout</code> implementations in a
* general purpose way.
*/
public interface Element
{
/**
* Returns the name of this element.
*/
public String getName ();
/**
* Returns the bounds of this element.
*/
public Rectangle2D getBounds ();
/**
* Sets the bounds of this element.
*/
public void setBounds (double x, double y, double width, double height);
}
@@ -1,44 +0,0 @@
//
// $Id: ElementLayout.java,v 1.5 2001/11/30 22:57:31 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.layout;
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
* <code>setBounds()</code> with the expectation that the location of the
* elements will be used later in the rendering process.
*/
public interface ElementLayout
{
/**
* Lay out the supplied list of elements. Any elements that do not fit
* into the allotted space should be added to the overflow list. The
* supplied elements list should not be modified.
*
* @return the bounding dimensions of the collection of elements that
* were laid out.
*/
public Rectangle2D layout (List elements, double pageWidth,
double pageHeight, List overflow);
}
@@ -1,148 +0,0 @@
//
// $Id: PackedColumnElementLayout.java,v 1.9 2001/12/03 06:13:54 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.layout;
import java.awt.geom.Rectangle2D;
import java.util.*;
/**
* Lays out the elements in columns of balanced height with elements
* vertically arranged from tallest to shortest.
*/
public class PackedColumnElementLayout implements ElementLayout
{
/**
* Configures the element layout to (or not to) first sort by height
* before falling back to alphabetical sort.
*/
public void setSortByHeight (boolean byHeight)
{
_byHeight = byHeight;
}
// docs inherited from interface
public Rectangle2D layout (List elements, double pageWidth,
double pageHeight, List overflow)
{
// sort the elements first by height then alphabetically
Element[] elems = new Element[elements.size()];
elements.toArray(elems);
Arrays.sort(elems, new ElementComparator(_byHeight));
// lay out the elements across the page
double x = 0, y = 0, rowheight = 0, maxwidth = 0;
for (int i = 0; i < elems.length; i++) {
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 + bounds.getWidth()) > pageWidth)) {
// strip off the trailing GAP
x -= GAP;
// track our maxwidth
if (x > maxwidth) {
maxwidth = x;
}
// move down to the next row
x = 0;
y += (rowheight + GAP);
// reset our max rowheight (we set it to -GAP because we
// will add rowheight to our last y position to compute
// the total height and if no more elements are laid out,
// we'll want to remove that trailing gap)
rowheight = -GAP;
}
// make sure we fit on this page (but force placement if we're
// currently at the top margin)
if ((y > 0) && ((y + bounds.getHeight()) > pageHeight)) {
// if we didn't fit, we go onto the overflow list
overflow.add(elems[i]);
// and continue on because maybe some shorter elements
// further down the list will fit
continue;
}
// lay this element out at our current coordinates
elems[i].setBounds(x, y, bounds.getWidth(), bounds.getHeight());
// keep track of the maximum row height
if (bounds.getHeight() > rowheight) {
rowheight = bounds.getHeight();
}
// advance in the x direction
x += (bounds.getWidth() + GAP);
}
// take a final stab at our maxwidth
x -= GAP;
if (x > maxwidth) {
maxwidth = x;
}
return new Rectangle2D.Double(0, 0, maxwidth, y+rowheight);
}
/**
* Compares the sizes of two elements. Used to sort them into order
* from highest to lowest. Secondarily sorts alphabetically on the
* element names.
*/
protected static class ElementComparator implements Comparator
{
public ElementComparator (boolean byHeight)
{
_byHeight = byHeight;
}
public int compare (Object o1, Object o2)
{
Element e1 = (Element)o1;
Element e2 = (Element)o2;
int diff = 0;
// if we're sorting by height, check that now
if (_byHeight) {
diff = (int)(e2.getBounds().getHeight() -
e1.getBounds().getHeight());
}
// if they are the same height (or we're not sorting by
// height), sort alphabetically
return (diff != 0) ? diff : e1.getName().compareTo(e2.getName());
}
public boolean equals (Object other)
{
return (other == this);
}
protected boolean _byHeight;
}
/** Whether or not we're sorting by height. */
protected boolean _byHeight = true;
// hard coded for now, half inch margins
protected static final double GAP = 72/4;
}
@@ -1,34 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: package.html,v 1.3 2001/12/03 10:08:33 mdb Exp $
viztool - a tool for visualizing collections of java classes
Copyright (C) 2001 Michael Bayne
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
</head>
<body bgcolor="white">
General purpose layout support classes. These include the {@link
com.samskivert.viztool.layout.Element} and {@link
com.samskivert.viztool.layout.ElementLayout} interfaces.
</body>
</html>
@@ -1,51 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: overview.html,v 1.2 2001/08/12 04:36:57 mdb Exp $
viztool - a tool for visualizing collections of java classes
Copyright (C) 2001 Michael Bayne
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
</head>
<body bgcolor="white">
<p> viztool is used to generate visualizations of collections of Java
classes. These visualizations are intended to be printed out and
taped to the wall or set on the desk beside you or folded into paper
airplanes and sailed around the room. Thus viztool does not include
a sophisticated user interface for viewing these presentations
onscreen (use ghostscript for that), although you can actually
display them on the screen because the rendering is done via the
Java 2D rendering engine.
<p> viztool aims to provide an extensible framework for generating
visualizations of collections of classes. It currently generates
inheritance diagrams organized by package, with information on
interfaces implemented and (non-anonymous) inner classes as well.
<p> It is a fairly small and simple collection of code, which is
hopefully understandable enough on its own to allow one to dive in
and create their own visualizations or enhance an existing
one. Comments and contributions are always welcome.
<p> -- <a href="mailto:mdb@samskivert.com">mdb@samskivert.com</a>
</body>
</html>
@@ -1,32 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: package.html,v 1.2 2001/08/12 04:36:57 mdb Exp $
viztool - a tool for visualizing collections of java classes
Copyright (C) 2001 Michael Bayne
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
</head>
<body bgcolor="white">
Top-level stuff like the application driver and log wrapper.
</body>
</html>
@@ -1,423 +0,0 @@
//
// $Id: ClassSummary.java,v 1.2 2001/12/03 06:14:03 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.summary;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import com.samskivert.viztool.Log;
import com.samskivert.viztool.layout.Element;
import com.samskivert.viztool.util.FontPicker;
import com.samskivert.viztool.util.LayoutUtil;
import com.samskivert.viztool.util.RenderUtil;
/**
* A class summary displays information about a particular class
* (specifically, the interfaces it implements, the class it extends, its
* public instances, member functions, and inner class definitions).
*/
public class ClassSummary
implements Element
{
/**
* Constructs a class summary for the specified class.
*/
public ClassSummary (Class subject, SummaryVisualizer viz)
{
_viz = viz;
_subject = subject;
_name = _viz.name(_subject);
// obtain information on our subject class
Class parent = _subject.getSuperclass();
if (parent != null && !parent.equals(Object.class)) {
_parentName = _viz.name(parent);
}
// get the implemented interfaces
Class[] interfaces = _subject.getInterfaces();
int icount = interfaces.length;
_interfaces = new String[icount];
for (int i = 0; i < icount; i++) {
_interfaces[i] = _viz.name(interfaces[i]);
}
// create a comparator that we can use to sort the fields and
// methods alphabetically and by staticness
Comparator comp = new Comparator() {
public int compare (Object o1, Object o2) {
Member m1 = (Member)o1;
Member m2 = (Member)o2;
int s1 = m1.getModifiers() & Modifier.STATIC;
int s2 = m2.getModifiers() & Modifier.STATIC;
// if one's static and one isn't...
if (s1 + s2 == Modifier.STATIC) {
// put the statics after the non-statics
return s1 - s2;
} else {
// otherwise compare names
return m1.getName().compareTo(m2.getName());
}
}
public boolean equals (Object other) {
return (other == this);
}
};
// get the public fields
Field[] fields = _subject.getDeclaredFields();
Arrays.sort(fields, comp);
ArrayList fsigtypes = new ArrayList();
ArrayList fsigs = new ArrayList();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
if ((f.getModifiers() & Modifier.PUBLIC) != 0) {
fsigtypes.add(genFieldTypeSig(f));
fsigs.add(f.getName());
}
}
_fieldTypes = new String[fsigtypes.size()];
fsigtypes.toArray(_fieldTypes);
_fields = new String[fsigs.size()];
fsigs.toArray(_fields);
// get the public constructors and methods
ArrayList sigrets = new ArrayList();
ArrayList sigs = new ArrayList();
Constructor[] ctors = _subject.getConstructors();
for (int i = 0; i < ctors.length; i++) {
Constructor c = ctors[i];
// make sure it's public
if ((c.getModifiers() & Modifier.PUBLIC) != 0 &&
// skip the zero argument constructor because it's
// uninteresting
c.getParameterTypes().length > 0) {
sigrets.add(" ");
sigs.add(genConstructorSig(c));
}
}
Method[] methods = _subject.getDeclaredMethods();
Arrays.sort(methods, comp);
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if ((m.getModifiers() & Modifier.PUBLIC) != 0) {
sigrets.add(genMethodRetSig(m));
sigs.add(genMethodSig(m));
}
}
_methodReturns = new String[sigrets.size()];
sigrets.toArray(_methodReturns);
_methods = new String[sigs.size()];
sigs.toArray(_methods);
}
/**
* Introspects on our subject class and determines how much space
* we'll need to visualize it.
*
* @param gfx the graphics context in which this summary will
* eventually be rendered.
*/
public void layout (Graphics2D gfx)
{
FontRenderContext frc = gfx.getFontRenderContext();
// the header will be the name of this class surrounded by N
// points of space and a box
Rectangle2D bounds = LayoutUtil.getTextBox(
_subject.isInterface() ? FontPicker.getInterfaceFont() :
FontPicker.getClassFont(), frc, _name);
double spacing = 0;
// add our parent class if we've got one
if (_parentName != null) {
String subtext = "extends " + _parentName;
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getDeclaresFont(), frc,
LayoutUtil.SUBORDINATE_INSET, subtext);
}
// add our interfaces
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getImplementsFont(), frc,
LayoutUtil.SUBORDINATE_INSET, _interfaces);
// add our fields
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getClassFont(), frc, 0, _fieldTypes, _fields);
spacing += (_fields.length > 0) ? 2*LayoutUtil.HEADER_BORDER : 0;
// add our constructors and methods
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getClassFont(), frc, 0,
_methodReturns, _methods);
spacing += (_methods.length > 0) ? 2*LayoutUtil.HEADER_BORDER : 0;
// incorporate space for the gaps
bounds.setRect(bounds.getX(), bounds.getY(), bounds.getWidth(),
bounds.getHeight() + spacing);
// grab the new bounds
_bounds = bounds;
}
/**
* Renders this class summary to the specified graphics context.
*/
public void render (Graphics2D gfx)
{
// figure out where we'll be rendering
Rectangle2D bounds = getBounds();
double x = bounds.getX() + LayoutUtil.HEADER_BORDER;
double y = bounds.getY() + LayoutUtil.HEADER_BORDER;
double maxwid = 0, sy1 = 0, sy2 = 0;
// draw the name
FontRenderContext frc = gfx.getFontRenderContext();
Font font = _subject.isInterface() ?
FontPicker.getInterfaceFont() : FontPicker.getClassFont();
Rectangle2D bnds =
RenderUtil.renderString(gfx, frc, font, x, y, _name);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER);
y += bnds.getHeight();
// render the parent classname
if (_parentName != null) {
bnds = RenderUtil.renderString(
gfx, frc, FontPicker.getDeclaresFont(),
x + LayoutUtil.SUBORDINATE_INSET, y, _parentName);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER +
LayoutUtil.SUBORDINATE_INSET);
y += bnds.getHeight();
}
// render our implemented interfaces
bnds = RenderUtil.renderStrings(
gfx, frc, FontPicker.getImplementsFont(),
x + LayoutUtil.SUBORDINATE_INSET, y, _interfaces);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER +
LayoutUtil.SUBORDINATE_INSET);
y += bnds.getHeight();
// stroke a box that contains the header
Rectangle2D outline = new Rectangle2D.Double(
bounds.getX(), bounds.getY(),
maxwid, y + LayoutUtil.HEADER_BORDER - bounds.getY());
gfx.draw(outline);
// leave space for a separator
if (_fields.length > 0) {
y += LayoutUtil.HEADER_BORDER;
sy1 = y;
y += LayoutUtil.HEADER_BORDER;
}
// render our fields
bnds = RenderUtil.renderStrings(
gfx, frc, FontPicker.getClassFont(), x, y, _fieldTypes, _fields);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER);
y += bnds.getHeight();
// leave space for a separator
if (_methods.length > 0) {
y += LayoutUtil.HEADER_BORDER;
sy2 = y;
y += LayoutUtil.HEADER_BORDER;
}
// render our constructors and methods
bnds = RenderUtil.renderStrings(
gfx, frc, FontPicker.getClassFont(), x, y,
_methodReturns, _methods);
maxwid = Math.max(maxwid, bnds.getWidth() +
2*LayoutUtil.HEADER_BORDER);
y += bnds.getHeight();
// draw our separators now that we know how wide things are
double x1 = bounds.getX(), x2 = x1 + maxwid;
if (sy1 > 0) {
gfx.draw(new Line2D.Double(x1, sy1, x2, sy1));
}
if (sy2 > 0) {
gfx.draw(new Line2D.Double(x1, sy2, x2, sy2));
}
}
// documentation inherited
public String getName ()
{
return _subject.getName();
}
// documentation inherited
public Rectangle2D getBounds ()
{
return _bounds;
}
// documentation inherited
public void setBounds (double x, double y, double width, double height)
{
_bounds.setRect(x, y, width, height);
}
/**
* Generates a signature for the type of the supplied field.
*/
public String genFieldTypeSig (Field field)
{
StringBuffer buf = new StringBuffer();
if ((field.getModifiers() & Modifier.STATIC) != 0) {
buf.append("static ");
}
buf.append(_viz.name(field.getType())).append(" ");
return buf.toString();
}
/**
* Generates a signature for the supplied constructor.
*/
public String genConstructorSig (Constructor ctor)
{
StringBuffer buf = new StringBuffer();
buf.append(_viz.name(ctor.getDeclaringClass())).append(" (");
Class[] ptypes = ctor.getParameterTypes();
for (int i = 0; i < ptypes.length; i++) {
if (i > 0) {
buf.append(", ");
}
buf.append(_viz.name(ptypes[i]));
}
buf.append(")");
Class[] etypes = ctor.getExceptionTypes();
if (etypes.length > 0) {
buf.append(" throws ");
for (int i = 0; i < etypes.length; i++) {
if (i > 0) {
buf.append(", ");
}
buf.append(_viz.name(etypes[i]));
}
}
return buf.toString();
}
/**
* Generates a signature for the return value of the supplied method.
*/
public String genMethodRetSig (Method method)
{
StringBuffer buf = new StringBuffer();
if ((method.getModifiers() & Modifier.STATIC) != 0) {
buf.append("static ");
}
buf.append(_viz.name(method.getReturnType()));
return buf.toString();
}
/**
* Generates a signature for the supplied method (minus return type).
*/
public String genMethodSig (Method method)
{
StringBuffer buf = new StringBuffer();
buf.append(method.getName()).append(" (");
Class[] ptypes = method.getParameterTypes();
for (int i = 0; i < ptypes.length; i++) {
if (i > 0) {
buf.append(", ");
}
buf.append(_viz.name(ptypes[i]));
}
buf.append(")");
Class[] etypes = method.getExceptionTypes();
if (etypes.length > 0) {
buf.append(" throws ");
for (int i = 0; i < etypes.length; i++) {
if (i > 0) {
buf.append(", ");
}
buf.append(_viz.name(etypes[i]));
}
}
return buf.toString();
}
public String toString ()
{
return "[subject=" + _subject.getName() + "]";
}
/** The package we're visualizing, which we'll strip from the front of
* class names. */
protected SummaryVisualizer _viz;
/** The class for which we're generating a summary visualization. */
protected Class _subject;
/** The cleaned up name of the class we're summarizing. */
protected String _name;
/** The name of our parent class or null if we don't have an
* interesting parent class. */
protected String _parentName;
/** The names of interfaces that we implement. */
protected String[] _interfaces;
/** The types of our public fields. */
protected String[] _fieldTypes;
/** The names of our public fields. */
protected String[] _fields;
/** The return types of our public constructors and methods. */
protected String[] _methodReturns;
/** The signatures of our public constructors and methods (minus
* return type). */
protected String[] _methods;
/** Our bounds. */
protected Rectangle2D _bounds = new Rectangle2D.Double();
}
@@ -1,225 +0,0 @@
//
// $Id: SummaryVisualizer.java,v 1.3 2001/12/03 08:34:53 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.summary;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.util.ArrayList;
import java.util.Iterator;
import com.samskivert.util.StringUtil;
import com.samskivert.viztool.Log;
import com.samskivert.viztool.Visualizer;
import com.samskivert.viztool.layout.PackedColumnElementLayout;
/**
* The summary visualizer displays summaries of the enumerated classes.
*/
public class SummaryVisualizer implements Visualizer
{
// documentation inherited
public void setPackageRoot (String pkgroot)
{
_pkgroot = pkgroot;
}
// documentation inherited
public void setClasses (Iterator iter)
{
// remove any old summaries
_summaries.clear();
// create the new summaries
while (iter.hasNext()) {
_summaries.add(new ClassSummary((Class)iter.next(), this));
}
}
/**
* Configures the visualizer to prefix classnames with their package
* names (when they are outside of the visualized package root) or
* not.
*/
public void setDisplayPackageNames (boolean displayPackageNames)
{
_displayPackageNames = displayPackageNames;
}
/**
* Lays out the class summary visualizations into the specified page
* dimensions.
*/
public void layout (Graphics2D gfx, double x, double y,
double width, double height)
{
// first layout all of our summaries (giving them dimensions)
for (int i = 0; i < _summaries.size(); i++) {
ClassSummary sum = (ClassSummary)_summaries.get(i);
sum.layout(gfx);
}
// now arrange our summaries onto pages
_pages = new ArrayList();
ArrayList list = new ArrayList(_summaries);
ArrayList next = new ArrayList();
PackedColumnElementLayout elay = new PackedColumnElementLayout();
elay.setSortByHeight(false);
while (list.size() > 0) {
// lay out the elements that fit on this page
elay.layout(list, width, height, next);
// remove the overflowed elements from the list for this page
list.removeAll(next);
// append this page to the pages list
_pages.add(list);
// move to the next page
list = next;
next = new ArrayList();
}
// finally adjust all of the bounds of the class summaries by the
// x and y offset of the page
for (int i = 0; i < _summaries.size(); i++) {
ClassSummary sum = (ClassSummary)_summaries.get(i);
Rectangle2D b = sum.getBounds();
sum.setBounds(b.getX()+x, b.getY()+y, b.getWidth(), b.getHeight());
}
}
/**
* Lays out and renders each of the classes that make up this package
* summary visualization.
*/
public int print (Graphics g, PageFormat pf, int pageIndex)
throws PrinterException
{
Graphics2D gfx = (Graphics2D)g;
// relay things out if the page format has changed or if we've
// never been laid out
if (!pf.equals(_format) || _pages == null) {
// keep this around
_format = pf;
// and do the layout
layout(gfx, pf.getImageableX(), pf.getImageableY(),
pf.getImageableWidth(), pf.getImageableHeight());
}
// adjust the stroke
gfx.setStroke(new BasicStroke(0.1f));
// make sure we're rendering a page that we have
if (pageIndex < 0 || pageIndex >= _pages.size()) {
return NO_SUCH_PAGE;
}
// render the summaries on the requested page
ArrayList list = (ArrayList)_pages.get(pageIndex);
for (int i = 0; i < list.size(); i++) {
((ClassSummary)list.get(i)).render(gfx);
}
return PAGE_EXISTS;
}
/**
* Renders the specified page to the supplied graphics context.
*/
public void paint (Graphics2D gfx, int pageIndex)
{
// ignore them if we haven't been laid out or if we have
// absolutely nothing to display
if (_pages == null || _pages.size() == 0) {
return;
}
// sanity check
if (pageIndex >= _pages.size()) {
Log.info("Requested to render non-existent page " +
"[index=" + pageIndex + "].");
return;
}
// adjust the stroke
gfx.setStroke(new BasicStroke(0.1f));
// render the summaries on the requested page
ArrayList list = (ArrayList)_pages.get(pageIndex);
for (int i = 0; i < list.size(); i++) {
((ClassSummary)list.get(i)).render(gfx);
}
}
/**
* Returns the number of pages occupied by this visualization. This is
* only valid after a call to {@link #layout}.
*
* @return the page count or -1 if we've not yet been laid out.
*/
public int getPageCount ()
{
return (_pages == null) ? -1 : _pages.size();
}
/**
* Cleans up a fully qualified class name according to our
* configuration and the package root.
*/
public String name (Class clazz)
{
if (clazz.isArray()) {
return name(clazz.getComponentType()) + "[]";
}
String name = clazz.getName();
if (_displayPackageNames) {
if (name.startsWith(_pkgroot)) {
return "." + name.substring(_pkgroot.length());
} else if (name.startsWith("java.lang")) {
return name.substring(10);
} else {
return name;
}
} else {
int ldidx = name.lastIndexOf(".");
return (ldidx == -1) ? name : name.substring(ldidx+1);
}
}
protected String _pkgroot = "";
protected ArrayList _summaries = new ArrayList();
protected ArrayList _pages;
protected PageFormat _format;
protected boolean _displayPackageNames = false;
protected static final int GAP = 72/4;
}
@@ -1,98 +0,0 @@
//
// $Id: Dumper.java,v 1.4 2001/08/14 06:23:08 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.util;
import java.lang.reflect.*;
import com.samskivert.util.StringUtil;
/**
* A simple utility that dumps out information available via reflection.
*/
public class Dumper
{
public void dump (Class clazz)
{
System.out.println("Dumping: " + clazz.getName());
Class parent = clazz.getSuperclass();
if (parent == null) {
System.out.println("P: none");
} else {
System.out.println("P: " + parent.getName());
}
Class[] ifaces = clazz.getInterfaces();
for (int i = 0; i < ifaces.length; i++) {
System.out.println("I: " + ifaces[i].getName());
}
dumpFields("F", clazz.getDeclaredFields());
dump("C", clazz.getDeclaredConstructors());
dumpMethods("M", clazz.getDeclaredMethods());
}
protected void dumpFields (String prefix, Field[] fields)
{
for (int i = 0; i < fields.length; i++) {
System.out.println(prefix + ": " + fields[i].getName() +
" / " + fields[i].getType().getName());
}
}
protected void dumpMethods (String prefix, Method[] methods)
{
for (int i = 0; i < methods.length; i++) {
System.out.println(prefix + ": " + methods[i].getName() +
StringUtil.toString(
methods[i].getParameterTypes()));
}
}
protected void dump (String prefix, Member[] members)
{
for (int i = 0; i < members.length; i++) {
System.out.println(prefix + ": " + members[i].getName());
}
}
public static void main (String[] args)
{
if (args.length < 1) {
System.err.println("Usage: Dumper classname [classname ...]");
System.exit(-1);
}
String classpath = System.getProperty("java.class.path", ".");
System.out.println("Classpath: " + classpath);
Dumper dumper = new Dumper();
for (int i = 0; i < args.length; i++) {
try {
dumper.dump(Class.forName(args[i]));
} catch (Exception e) {
System.err.println("Unable to instantiate class: " + args[i]);
e.printStackTrace();
}
}
}
}
@@ -1,75 +0,0 @@
//
// $Id: FontPicker.java,v 1.4 2001/12/01 05:28:01 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.util;
import java.awt.Font;
/**
* The font picker provides the proper font based on operating condtions.
*/
public class FontPicker
{
/**
* Instructs the font picker to choose fonts for printing or fonts for
* displaying on the screen based on the value of the
* <code>printing</code> argument.
*/
public static void init (boolean printing)
{
int size = printing ? 8 : 12;
_titleFont = new Font("Helvetica", Font.BOLD, size);
_classFont = new Font("Helvetica", Font.PLAIN, size);
_ifaceFont = new Font("Helvetica", Font.ITALIC, size);
_implsFont = new Font("Helvetica", Font.ITALIC, size-2);
_declsFont = new Font("Helvetica", Font.PLAIN, size-2);
}
public static Font getTitleFont ()
{
return _titleFont;
}
public static Font getClassFont ()
{
return _classFont;
}
public static Font getInterfaceFont ()
{
return _ifaceFont;
}
public static Font getImplementsFont ()
{
return _implsFont;
}
public static Font getDeclaresFont ()
{
return _declsFont;
}
protected static Font _titleFont;
protected static Font _classFont;
protected static Font _ifaceFont;
protected static Font _implsFont;
protected static Font _declsFont;
}
@@ -1,140 +0,0 @@
//
// $Id: LayoutUtil.java,v 1.2 2001/12/01 06:22:18 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.util;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
/**
* Layout related utility functions.
*/
public class LayoutUtil
{
/**
* The number of points surrounding the name of the chain.
*/
public static double HEADER_BORDER = 3;
/**
* The number of points of spacing between each child chain.
*/
public static double GAP = 4;
/**
* The number of points that interfaces, inner classes and generally
* any text that is subordinate to other text is indented.
*/
public static double SUBORDINATE_INSET = 3;
/**
* Returns a rectangle that contains the supplied text with space
* around the text for an aesthetically pleasing border.
*/
public static Rectangle2D getTextBox (
Font font, FontRenderContext frc, String text)
{
TextLayout layout = new TextLayout(text, font, frc);
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;
}
/**
* Returns a rectangle that accomodates the specified text at the
* bottom of the supplied rectangle, taking into account the preferred
* text spacing and the specified inset for the accomodated text.
*/
public static Rectangle2D accomodate (
Rectangle2D bounds, Font font, FontRenderContext frc, double inset,
String text)
{
TextLayout layout = new TextLayout(text, 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;
}
/**
* Returns a rectangle that accomodates the specified lines of text at
* the bottom of the supplied rectangle, taking into account the
* preferred text spacing and the specified inset for the accomodated
* text.
*/
public static Rectangle2D accomodate (
Rectangle2D bounds, Font font, FontRenderContext frc, double inset,
String[] text)
{
double maxwid = bounds.getWidth();
double height = 0;
for (int i = 0; i < text.length; i++) {
TextLayout layout = new TextLayout(text[i], font, frc);
Rectangle2D tbounds = layout.getBounds();
maxwid = Math.max(maxwid, tbounds.getWidth()+inset);
height += tbounds.getHeight();
}
bounds.setRect(bounds.getX(), bounds.getY(),
maxwid, bounds.getHeight() + height);
return bounds;
}
/**
* Returns a rectangle that accomodates the two specified columns of
* text at the bottom of the supplied rectangle, taking into account
* the preferred text spacing and the specified inset for the
* accomodated text.
*/
public static Rectangle2D accomodate (
Rectangle2D bounds, Font font, FontRenderContext frc, double inset,
String[] left, String[] right)
{
double maxleft = 0, maxwid = bounds.getWidth();
double height = 0;
Rectangle2D[] bndl = new Rectangle2D[left.length];
Rectangle2D[] bndr = new Rectangle2D[right.length];
// first compute our dimensions
for (int i = 0; i < left.length; i++) {
bndl[i] = new TextLayout(left[i], font, frc).getBounds();
bndr[i] = new TextLayout(right[i], font, frc).getBounds();
maxleft = Math.max(maxleft, bndl[i].getWidth());
}
// now that we have the maxleft width we can calculate the rest
for (int i = 0; i < left.length; i++) {
maxwid = Math.max(maxwid, maxleft+GAP+bndr[i].getWidth()+inset);
height += Math.max(bndl[i].getHeight(), bndr[i].getHeight());
}
bounds.setRect(bounds.getX(), bounds.getY(),
maxwid, bounds.getHeight() + height);
return bounds;
}
}
@@ -1,160 +0,0 @@
//
// $Id: RenderUtil.java,v 1.2 2001/12/01 06:22:18 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.viztool.util;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
/**
* Rendering related utility functions.
*/
public class RenderUtil
{
/**
* Renders a string to the specified graphics context, in the
* specified font at the specified coordinates.
*
* @return the bounds occupied by the rendered string.
*/
public static Rectangle2D renderString (
Graphics2D gfx, FontRenderContext frc, Font font,
double x, double y, String text)
{
// do the rendering
TextLayout ilay = new TextLayout(text, font, frc);
Rectangle2D ibounds = ilay.getBounds();
ilay.draw(gfx, (float)(x - ibounds.getX()),
(float)(y - ibounds.getY()));
// return the dimensions occupied by the rendered string
return ibounds;
}
/**
* Renders an array of strings to the specified graphics context, in
* the specified font at the specified coordinates.
*
* @return the bounds occupied by the rendered strings.
*/
public static Rectangle2D renderStrings (
Graphics2D gfx, FontRenderContext frc, Font font,
double x, double y, String[] text)
{
return renderStrings(gfx, frc, font, x, y, text, (String)null);
}
/**
* Renders an array of strings to the specified graphics context, in
* the specified font at the specified coordinates. If prefix is
* non-null, it will be prefixed to the first string and subsequent
* strings will be rendered with the space necessary to line them up
* with the first string.
*
* @return the bounds occupied by the rendered strings.
*/
public static Rectangle2D renderStrings (
Graphics2D gfx, FontRenderContext frc, Font font,
double x, double y, String[] text, String prefix)
{
double maxwid = 0, starty = y;
double inset = 0;
if (prefix != null) {
TextLayout play = new TextLayout(prefix, font, frc);
inset = play.getBounds().getWidth();
}
for (int i = 0; i < text.length; i++) {
// figure some stuff out
String string = (i == 0 && prefix != null) ?
(prefix + text[i]) : text[i];
double sinset = ((i == 0) ? 0 : inset);
// do the rendering
TextLayout ilay = new TextLayout(string, font, frc);
Rectangle2D ibounds = ilay.getBounds();
ilay.draw(gfx, (float)(x - ibounds.getX() + sinset),
(float)(y - ibounds.getY()));
maxwid = Math.max(sinset + ibounds.getWidth(), maxwid);
y += ibounds.getHeight();
}
// return the dimensions occupied by the rendered strings
return new Rectangle2D.Double(x, y, maxwid, y-starty);
}
/**
* Renders a two column array of strings to the specified graphics
* context, in the specified font at the specified coordinates. The
* left column is right align and the right, left aligned.
*
* @return the bounds occupied by the rendered strings.
*/
public static Rectangle2D renderStrings (
Graphics2D gfx, FontRenderContext frc, Font font,
double x, double y, String[] left, String[] right)
{
double maxleft = 0, maxwid = 0, starty = y;
double inset = 0;
// first generate text layout instances and compute bounds for all
// entries in both columns
TextLayout[] llay = new TextLayout[left.length];
Rectangle2D[] lbnds = new Rectangle2D[left.length];
TextLayout[] rlay = new TextLayout[right.length];
Rectangle2D[] rbnds = new Rectangle2D[right.length];
// compute the dimensions
for (int i = 0; i < left.length; i++) {
llay[i] = new TextLayout(left[i], font, frc);
lbnds[i] = llay[i].getBounds();
rlay[i] = new TextLayout(right[i], font, frc);
rbnds[i] = rlay[i].getBounds();
maxleft = Math.max(maxleft, lbnds[i].getWidth());
}
// do the rendering
for (int i = 0; i < left.length; i++) {
double lw = lbnds[i].getWidth();
llay[i].draw(gfx, (float)(x - lbnds[i].getX() + maxleft - lw),
// we actually mean to use rbnds[i] here because
// the right hand side (usually being the method
// declaration), tends to be taller than the left
// hand side (because of the parenthesis) and
// would appear a bit lower than the left hand
// side if we didn't use it's y offset
(float)(y - rbnds[i].getY()));
rlay[i].draw(gfx, (float)(x - rbnds[i].getX() + maxleft +
LayoutUtil.GAP),
(float)(y - rbnds[i].getY()));
maxwid = Math.max(maxwid, maxleft + LayoutUtil.GAP +
rbnds[i].getWidth());
y += Math.max(lbnds[i].getHeight(), rbnds[i].getHeight());
}
// return the dimensions occupied by the rendered strings
return new Rectangle2D.Double(x, y, maxwid, y-starty);
}
}
@@ -1,32 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: package.html,v 1.2 2001/08/12 04:36:57 mdb Exp $
viztool - a tool for visualizing collections of java classes
Copyright (C) 2001 Michael Bayne
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
</head>
<body bgcolor="white">
Various and sundry utilities.
</body>
</html>