Refactored things into layout and render utility classes. Other cleanups.

Upped the on screen font size.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@487 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-12-01 05:28:01 +00:00
parent 0618cc9b8e
commit d6758265bf
7 changed files with 290 additions and 122 deletions
@@ -1,5 +1,5 @@
//
// $Id: Driver.java,v 1.12 2001/11/30 22:57:31 mdb Exp $
// $Id: Driver.java,v 1.13 2001/12/01 05:28:01 mdb Exp $
//
// viztool - a tool for visualizing collections of java classes
// Copyright (C) 2001 Michael Bayne
@@ -27,6 +27,7 @@ import com.samskivert.swing.util.SwingUtil;
import com.samskivert.viztool.enum.*;
import com.samskivert.viztool.hierarchy.HierarchyVisualizer;
import com.samskivert.viztool.summary.SummaryVisualizer;
import com.samskivert.viztool.util.FontPicker;
/**
@@ -70,6 +71,7 @@ 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);
if (print) {
// we use the print system to render things
@@ -1,5 +1,5 @@
//
// $Id: VizController.java,v 1.3 2001/08/14 00:58:49 mdb Exp $
// $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
@@ -79,20 +79,16 @@ public class VizController extends Controller
} 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 ()
{
Pageable pable = new Pageable() {
public int getNumberOfPages () {
return _vpanel.getVisualizer().getPageCount();
}
public PageFormat getPageFormat (int pageIndex)
{
public PageFormat getPageFormat (int pageIndex) {
return _format;
}
public Printable getPrintable (int pageIndex)
{
public Printable getPrintable (int pageIndex) {
return _vpanel.getVisualizer();
}
};
@@ -1,5 +1,5 @@
//
// $Id: VizPanel.java,v 1.7 2001/11/30 22:57:31 mdb Exp $
// $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
@@ -42,14 +42,18 @@ public class VizPanel extends JPanel
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);
Graphics2D gfx = (Graphics2D)g;
Rectangle2D bounds = getBounds();
_viz.layout(gfx, 0, 0, bounds.getWidth(), bounds.getHeight());
_viz.paint(gfx, _currentPage);
_viz.paint((Graphics2D)g, _currentPage);
}
public Dimension getPreferredSize ()
@@ -1,5 +1,5 @@
//
// $Id: CascadingChainVisualizer.java,v 1.10 2001/11/30 22:57:31 mdb Exp $
// $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
@@ -28,6 +28,8 @@ 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
@@ -49,44 +51,38 @@ public class CascadingChainVisualizer
// docs inherited from interface
public void layoutChain (Chain chain, Graphics2D gfx)
{
// create a text layout based on the current rendering conditions
Font font = chain.getRoot().isInterface() ?
FontPicker.getInterfaceFont() : FontPicker.getClassFont();
TextLayout layout = new TextLayout(chain.getName(), font,
gfx.getFontRenderContext());
FontRenderContext frc = gfx.getFontRenderContext();
// the header will be the name of this chain surrounded by N
// points of space and a box
Rectangle2D bounds = getTextBox(gfx, layout);
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();
for (int i = 0; i < impls.length; i++) {
bounds = accomodate(bounds, impls[i],
FontPicker.getImplementsFont(),
gfx.getFontRenderContext());
}
bounds = LayoutUtil.accomodate(
bounds, FontPicker.getImplementsFont(),
frc, LayoutUtil.SUBORDINATE_INSET, impls);
String[] decls = chain.getDeclaresNames();
for (int i = 0; i < decls.length; i++) {
bounds = accomodate(bounds, decls[i],
FontPicker.getDeclaresFont(),
gfx.getFontRenderContext());
}
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*GAP, y = bounds.getHeight();
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 += GAP; // add the gap
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
@@ -100,79 +96,63 @@ public class CascadingChainVisualizer
chain.setBounds(cbounds.getX(), cbounds.getY(), maxwid, y);
}
protected Rectangle2D accomodate (Rectangle2D bounds, String name,
Font font, FontRenderContext frc)
{
TextLayout layout = new TextLayout(name, 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;
}
// 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();
double y = bounds.getY();
// create a text layout based on the current rendering conditions
Font font = chain.getRoot().isInterface() ?
FontPicker.getInterfaceFont() : FontPicker.getClassFont();
TextLayout layout = new TextLayout(chain.getName(), font,
gfx.getFontRenderContext());
Rectangle2D tbounds = getTextBox(gfx, layout);
double dx = -tbounds.getX(), dy = -tbounds.getY();
double maxwid = tbounds.getWidth();
double x = bounds.getX() + LayoutUtil.HEADER_BORDER;
double y = bounds.getY() + LayoutUtil.HEADER_BORDER;
double maxwid = 0;
// draw the name
layout.draw(gfx, (float)(x + dx + HEADER_BORDER),
(float)(y + dy + HEADER_BORDER));
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
double ix = x + HEADER_BORDER + INSET;
double iy = y + tbounds.getHeight() - HEADER_BORDER;
if (chain.inPackage()) {
// render the implemented interfaces
String[] impls = chain.getImplementsNames();
for (int i = 0; i < impls.length; i++) {
TextLayout ilay =
new TextLayout(impls[i], FontPicker.getImplementsFont(),
gfx.getFontRenderContext());
Rectangle2D ibounds = ilay.getBounds();
double newwid = ibounds.getWidth() + 2*HEADER_BORDER + INSET;
if (newwid > maxwid) {
maxwid = newwid;
}
ilay.draw(gfx, (float)(ix - ibounds.getX()),
(float)(iy - ibounds.getY()));
iy += ibounds.getHeight();
}
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();
for (int i = 0; i < decls.length; i++) {
TextLayout ilay =
new TextLayout(decls[i], FontPicker.getDeclaresFont(),
gfx.getFontRenderContext());
Rectangle2D ibounds = ilay.getBounds();
double newwid = ibounds.getWidth() + 2*HEADER_BORDER + INSET;
if (newwid > maxwid) {
maxwid = newwid;
}
ilay.draw(gfx, (float)(ix - ibounds.getX()),
(float)(iy - ibounds.getY()));
iy += ibounds.getHeight();
}
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
tbounds.setRect(x, y, maxwid, iy - y + HEADER_BORDER);
gfx.draw(tbounds);
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();
@@ -180,12 +160,12 @@ public class CascadingChainVisualizer
GeneralPath path = new GeneralPath();
Rectangle2D kbounds = ((Chain)kids.get(0)).getBounds();
double half = kbounds.getX()/2;
path.moveTo((float)(x + half), (float)(y + tbounds.getHeight()));
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() + dy + HEADER_BORDER;
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);
@@ -206,31 +186,4 @@ public class CascadingChainVisualizer
// undo our prior translation
gfx.translate(-x, -y);
}
protected static Rectangle2D getTextBox (Graphics2D gfx,
TextLayout layout)
{
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;
}
/**
* The number of points surrounding the name of the chain.
*/
protected static final double HEADER_BORDER = 3;
/**
* The number of points of spacing between each child chain.
*/
protected static final double GAP = 4;
/**
* The number of points that interfaces and inner class declarations
* are indented.
*/
protected static final double INSET = 3;
}
@@ -1,5 +1,5 @@
//
// $Id: FontPicker.java,v 1.3 2001/11/30 22:57:31 mdb Exp $
// $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
@@ -34,7 +34,7 @@ public class FontPicker
*/
public static void init (boolean printing)
{
int size = printing ? 8 : 10;
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);
@@ -0,0 +1,106 @@
//
// $Id: LayoutUtil.java,v 1.1 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;
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;
}
}
@@ -0,0 +1,107 @@
//
// $Id: RenderUtil.java,v 1.1 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;
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, 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);
}
}