From d6758265bfd68a8cb8e0d5eb00ad2ea68b2c5ca0 Mon Sep 17 00:00:00 2001 From: mdb Date: Sat, 1 Dec 2001 05:28:01 +0000 Subject: [PATCH] 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 --- .../java/com/samskivert/viztool/Driver.java | 4 +- .../com/samskivert/viztool/VizController.java | 14 +- .../java/com/samskivert/viztool/VizPanel.java | 16 +- .../hierarchy/CascadingChainVisualizer.java | 161 +++++++----------- .../samskivert/viztool/util/FontPicker.java | 4 +- .../samskivert/viztool/util/LayoutUtil.java | 106 ++++++++++++ .../samskivert/viztool/util/RenderUtil.java | 107 ++++++++++++ 7 files changed, 290 insertions(+), 122 deletions(-) create mode 100644 projects/viztool/src/java/com/samskivert/viztool/util/LayoutUtil.java create mode 100644 projects/viztool/src/java/com/samskivert/viztool/util/RenderUtil.java diff --git a/projects/viztool/src/java/com/samskivert/viztool/Driver.java b/projects/viztool/src/java/com/samskivert/viztool/Driver.java index 2174342d..fcda052a 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/Driver.java +++ b/projects/viztool/src/java/com/samskivert/viztool/Driver.java @@ -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 diff --git a/projects/viztool/src/java/com/samskivert/viztool/VizController.java b/projects/viztool/src/java/com/samskivert/viztool/VizController.java index b88a0bef..7b97375d 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/VizController.java +++ b/projects/viztool/src/java/com/samskivert/viztool/VizController.java @@ -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(); } }; diff --git a/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java b/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java index 3d0b0cfe..3e23bf3d 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java +++ b/projects/viztool/src/java/com/samskivert/viztool/VizPanel.java @@ -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 () diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java index f43badd2..6e283d05 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java @@ -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; } diff --git a/projects/viztool/src/java/com/samskivert/viztool/util/FontPicker.java b/projects/viztool/src/java/com/samskivert/viztool/util/FontPicker.java index 197d563d..40d3a423 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/util/FontPicker.java +++ b/projects/viztool/src/java/com/samskivert/viztool/util/FontPicker.java @@ -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); diff --git a/projects/viztool/src/java/com/samskivert/viztool/util/LayoutUtil.java b/projects/viztool/src/java/com/samskivert/viztool/util/LayoutUtil.java new file mode 100644 index 00000000..710b26f4 --- /dev/null +++ b/projects/viztool/src/java/com/samskivert/viztool/util/LayoutUtil.java @@ -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; + } +} diff --git a/projects/viztool/src/java/com/samskivert/viztool/util/RenderUtil.java b/projects/viztool/src/java/com/samskivert/viztool/util/RenderUtil.java new file mode 100644 index 00000000..44c0add0 --- /dev/null +++ b/projects/viztool/src/java/com/samskivert/viztool/util/RenderUtil.java @@ -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); + } +}