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
|
||||
// Copyright (C) 2001 Michael Bayne
|
||||
@@ -70,8 +70,8 @@ public class Driver
|
||||
|
||||
// and finally generate the visualization
|
||||
PackageEnumerator penum = new PackageEnumerator(pkgroot, enum, true);
|
||||
Visualizer viz = new HierarchyVisualizer(pkgroot, penum);
|
||||
// Visualizer viz = new SummaryVisualizer(pkgroot, penum);
|
||||
// Visualizer viz = new HierarchyVisualizer(pkgroot, penum);
|
||||
Visualizer viz = new SummaryVisualizer(pkgroot, penum);
|
||||
|
||||
if (print) {
|
||||
// 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
|
||||
// Copyright (C) 2001 Michael Bayne
|
||||
@@ -103,4 +103,38 @@ public class LayoutUtil
|
||||
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,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
|
||||
// Copyright (C) 2001 Michael Bayne
|
||||
@@ -61,7 +61,7 @@ public class RenderUtil
|
||||
Graphics2D gfx, FontRenderContext frc, Font font,
|
||||
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 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