Created a visualization that displays classes, their public fields,
members and constructors rather than the inheritance hierarchy. git-svn-id: https://samskivert.googlecode.com/svn/trunk@488 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: Driver.java,v 1.13 2001/12/01 05:28:01 mdb Exp $
|
// $Id: Driver.java,v 1.14 2001/12/01 06:22:18 mdb Exp $
|
||||||
//
|
//
|
||||||
// viztool - a tool for visualizing collections of java classes
|
// viztool - a tool for visualizing collections of java classes
|
||||||
// Copyright (C) 2001 Michael Bayne
|
// Copyright (C) 2001 Michael Bayne
|
||||||
@@ -70,8 +70,8 @@ public class Driver
|
|||||||
|
|
||||||
// and finally generate the visualization
|
// and finally generate the visualization
|
||||||
PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true);
|
PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true);
|
||||||
Visualizer viz = new HierarchyVisualizer(pkgroot, penum);
|
// Visualizer viz = new HierarchyVisualizer(pkgroot, penum);
|
||||||
// Visualizer viz = new SummaryVisualizer(pkgroot, penum);
|
Visualizer viz = new SummaryVisualizer(pkgroot, penum);
|
||||||
|
|
||||||
if (print) {
|
if (print) {
|
||||||
// we use the print system to render things
|
// we use the print system to render things
|
||||||
|
|||||||
@@ -0,0 +1,382 @@
|
|||||||
|
//
|
||||||
|
// $Id: ClassSummary.java,v 1.1 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.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.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the public fields
|
||||||
|
Field[] fields = _subject.getDeclaredFields();
|
||||||
|
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];
|
||||||
|
if ((c.getModifiers() & Modifier.PUBLIC) != 0) {
|
||||||
|
sigrets.add(" ");
|
||||||
|
sigs.add(genConstructorSig(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Method[] methods = _subject.getDeclaredMethods();
|
||||||
|
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 _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
//
|
||||||
|
// $Id: SummaryVisualizer.java,v 1.1 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.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.viztool.Log;
|
||||||
|
import com.samskivert.viztool.Visualizer;
|
||||||
|
import com.samskivert.viztool.layout.ElementLayout;
|
||||||
|
import com.samskivert.viztool.layout.PackedColumnElementLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The summary visualizer displays summaries of the enumerated classes.
|
||||||
|
*/
|
||||||
|
public class SummaryVisualizer implements Visualizer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a summary visualizer with the supplied enumerator as its
|
||||||
|
* source of classes. If the summary enumerator should be limited to a
|
||||||
|
* particular set of classes (and it most likely should), a filter
|
||||||
|
* enumerator should be supplied that returns only the classes to be
|
||||||
|
* visualized.
|
||||||
|
*
|
||||||
|
* @param pkgroot The name of the top-level package in which the
|
||||||
|
* visualized classes reside. This will be used to shorten the package
|
||||||
|
* names that are displayed.
|
||||||
|
* @param iter The enumerator that will return the names of the
|
||||||
|
* classes for which visualization is desired.
|
||||||
|
*/
|
||||||
|
public SummaryVisualizer (String pkgroot, Iterator iter)
|
||||||
|
{
|
||||||
|
// keep track of the package root
|
||||||
|
_pkgroot = pkgroot;
|
||||||
|
|
||||||
|
// create our class summaries
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
// strip out inner classes, we'll catch those via their
|
||||||
|
// declaring classes
|
||||||
|
String name = (String)iter.next();
|
||||||
|
if (name.indexOf("$") != -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a class summary instance for this class
|
||||||
|
try {
|
||||||
|
Class subject = Class.forName(name);
|
||||||
|
_summaries.add(new ClassSummary(subject, this));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warning("Unable to introspect class [class=" + name +
|
||||||
|
", error=" + e + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
ElementLayout elay = new PackedColumnElementLayout();
|
||||||
|
|
||||||
|
while (list.size() > 0) {
|
||||||
|
// lay out the elements that fit on this page
|
||||||
|
Log.info("Laying out " + list.size() + " summaries in " +
|
||||||
|
width + "x" + height + "+" + x + "+" + y + ".");
|
||||||
|
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,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: LayoutUtil.java,v 1.1 2001/12/01 05:28:01 mdb Exp $
|
// $Id: LayoutUtil.java,v 1.2 2001/12/01 06:22:18 mdb Exp $
|
||||||
//
|
//
|
||||||
// viztool - a tool for visualizing collections of java classes
|
// viztool - a tool for visualizing collections of java classes
|
||||||
// Copyright (C) 2001 Michael Bayne
|
// Copyright (C) 2001 Michael Bayne
|
||||||
@@ -103,4 +103,38 @@ public class LayoutUtil
|
|||||||
maxwid, bounds.getHeight() + height);
|
maxwid, bounds.getHeight() + height);
|
||||||
return bounds;
|
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,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: RenderUtil.java,v 1.1 2001/12/01 05:28:01 mdb Exp $
|
// $Id: RenderUtil.java,v 1.2 2001/12/01 06:22:18 mdb Exp $
|
||||||
//
|
//
|
||||||
// viztool - a tool for visualizing collections of java classes
|
// viztool - a tool for visualizing collections of java classes
|
||||||
// Copyright (C) 2001 Michael Bayne
|
// Copyright (C) 2001 Michael Bayne
|
||||||
@@ -61,7 +61,7 @@ public class RenderUtil
|
|||||||
Graphics2D gfx, FontRenderContext frc, Font font,
|
Graphics2D gfx, FontRenderContext frc, Font font,
|
||||||
double x, double y, String[] text)
|
double x, double y, String[] text)
|
||||||
{
|
{
|
||||||
return renderStrings(gfx, frc, font, x, y, text, null);
|
return renderStrings(gfx, frc, font, x, y, text, (String)null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,4 +104,57 @@ public class RenderUtil
|
|||||||
// return the dimensions occupied by the rendered strings
|
// return the dimensions occupied by the rendered strings
|
||||||
return new Rectangle2D.Double(x, y, maxwid, y-starty);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user