From 539f587813ae27fd7b7f63385bde0b4540ad7fef Mon Sep 17 00:00:00 2001 From: mdb Date: Tue, 17 Jul 2001 07:18:09 +0000 Subject: [PATCH] Use sensible margins; added support for rendering interfaces implemented and inner classes declared within the box for the appropriate class. git-svn-id: https://samskivert.googlecode.com/svn/trunk@193 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../java/com/samskivert/viztool/Driver.java | 12 ++- .../hierarchy/CascadingChainVisualizer.java | 85 ++++++++++++++++- .../samskivert/viztool/hierarchy/Chain.java | 92 ++++++++++++++++++- .../viztool/hierarchy/ChainUtil.java | 10 +- .../hierarchy/HierarchyVisualizer.java | 10 +- 5 files changed, 192 insertions(+), 17 deletions(-) diff --git a/projects/viztool/src/java/com/samskivert/viztool/Driver.java b/projects/viztool/src/java/com/samskivert/viztool/Driver.java index 57169627..6abc3892 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.4 2001/07/17 06:01:08 mdb Exp $ +// $Id: Driver.java,v 1.5 2001/07/17 07:18:09 mdb Exp $ package com.samskivert.viztool; @@ -49,16 +49,24 @@ public class Driver if (print) { // we use the print system to render things PrinterJob job = PrinterJob.getPrinterJob(); - job.setPrintable(viz); // pop up a dialog to format our pages // PageFormat format = job.pageDialog(job.defaultPage()); PageFormat format = job.defaultPage(); + // use sensible margins + Paper paper = new Paper(); + paper.setImageableArea(72*0.5, 72*0.5, 72*7.5, 72*10); + format.setPaper(paper); + // pop up a dialog to control printing job.printDialog(); + // use our configured page format + job.setPrintable(viz, format); + try { + // invoke the printing process job.print(); } catch (PrinterException pe) { pe.printStackTrace(System.err); 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 d235a936..291b1788 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/CascadingChainVisualizer.java @@ -1,11 +1,12 @@ // -// $Id: CascadingChainVisualizer.java,v 1.7 2001/07/17 06:01:08 mdb Exp $ +// $Id: CascadingChainVisualizer.java,v 1.8 2001/07/17 07:18:09 mdb Exp $ package com.samskivert.viztool.viz; import java.awt.Font; import java.awt.Graphics2D; import java.awt.font.TextLayout; +import java.awt.font.FontRenderContext; import java.awt.geom.*; import java.util.ArrayList; @@ -38,6 +39,24 @@ public class CascadingChainVisualizer // the header will be the name of this chain surrounded by N // points of space and a box Rectangle2D bounds = getTextBox(gfx, layout); + + // 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()); + } + String[] decls = chain.getDeclaresNames(); + for (int i = 0; i < decls.length; i++) { + bounds = accomodate(bounds, decls[i], + FontPicker.getDeclaresFont(), + gfx.getFontRenderContext()); + } + } + double maxwid = bounds.getWidth(); // the children will be below the name of this chain and inset by @@ -62,6 +81,17 @@ 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) { @@ -76,16 +106,55 @@ public class CascadingChainVisualizer TextLayout layout = new TextLayout(chain.getName(), font, gfx.getFontRenderContext()); - // stroke a box that will contain the name Rectangle2D tbounds = getTextBox(gfx, layout); double dx = -tbounds.getX(), dy = -tbounds.getY(); - tbounds.setRect(x, y, tbounds.getWidth(), tbounds.getHeight()); - gfx.draw(tbounds); + double maxwid = tbounds.getWidth(); - // now draw the name + // draw the name layout.draw(gfx, (float)(x + dx + HEADER_BORDER), (float)(y + dy + HEADER_BORDER)); + // 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()) { + 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(); + } + + 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(); + } + } + + // stroke a box that will contain the name + tbounds.setRect(x, y, maxwid, iy - y + HEADER_BORDER); + gfx.draw(tbounds); + // render our connecty lines ArrayList kids = chain.getChildren(); if (kids.size() > 0) { @@ -139,4 +208,10 @@ public class CascadingChainVisualizer * 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/hierarchy/Chain.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java index 981abe00..e0634197 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/Chain.java @@ -1,5 +1,5 @@ // -// $Id: Chain.java,v 1.4 2001/07/17 01:54:19 mdb Exp $ +// $Id: Chain.java,v 1.5 2001/07/17 07:18:09 mdb Exp $ package com.samskivert.viztool.viz; @@ -16,10 +16,11 @@ public class Chain implements Element /** * Constructs a chain with the specified class as its root. */ - public Chain (String name, Class root) + public Chain (String name, Class root, boolean inpkg) { _name = name; _root = root; + _inpkg = inpkg; } /** @@ -39,6 +40,15 @@ public class Chain implements Element return _root; } + /** + * Returns true if the class represented by this point in the chain is + * in the package we are visualizing, false if it is not. + */ + public boolean inPackage () + { + return _inpkg; + } + /** * Returns the name of the class that forms the root of this chain. */ @@ -47,6 +57,77 @@ public class Chain implements Element return _root.getName(); } + /** + * Returns the names of the interfaces implemented by this class. + */ + public String[] getImplementsNames () + { + Class[] ifaces = _root.getInterfaces(); + String[] names = new String[ifaces.length]; + String pkg = ChainUtil.pkgFromClass(_root.getName()); + + for (int i = 0; i < ifaces.length; i++) { + String name = ifaces[i].getName(); + String ipkg = ChainUtil.pkgFromClass(name); + if (pkg.equals(ipkg)) { + names[i] = ChainUtil.nameFromClass(name); + } else { + names[i] = removeOverlap(pkg, name); + } + } + + return names; + } + + protected static String removeOverlap (String pkg, String name) + { + // strip off package elements until we've eliminated all but one + // level of overlap + String overlap = ""; + int didx; + + while ((didx = pkg.indexOf(".", overlap.length()+1)) != -1) { + // see if this chunk still overlaps + String prefix = pkg.substring(0, didx); + if (name.startsWith(prefix)) { + overlap = prefix; + } else { + // we've stopped overlapping, we need to back up one + // element and then we're good to go + if ((didx = overlap.lastIndexOf(".")) == -1) { + overlap = ""; + } else { + overlap = overlap.substring(0, didx); + } + break; + } + } + + // if there's an overlap, remove it + if (overlap.length() > 0) { + return ".." + name.substring(overlap.length()); + } else { + return name; + } + } + + /** + * Returns the names of the inner classes declared by this class. + */ + public String[] getDeclaresNames () + { + Class[] decls = _root.getDeclaredClasses(); + String[] names = new String[decls.length]; + + for (int i = 0; i < decls.length; i++) { + String name = decls[i].getName(); + int didx = name.indexOf("$"); + names[i] = (didx == -1) ? name : name.substring(didx+1); + } + + return names; + } + /** * Returns a Rectangle2D instance representing the size * of this chain (and all contained subchains). @@ -100,7 +181,11 @@ public class Chain implements Element */ public void addClass (String name, Class child) { - Chain chain = new Chain(name, child); + // we assume that the addition of a derived class is only done for + // classes that are in the package we're visualizing. out of + // package classes are only included as roots of chains that + // subsequently contain classes that are in the package + Chain chain = new Chain(name, child, true); if (!_children.contains(chain)) { _children.add(chain); } @@ -157,6 +242,7 @@ public class Chain implements Element protected String _name; protected Class _root; + protected boolean _inpkg; protected ArrayList _children = new ArrayList(); protected Rectangle2D _bounds = new Rectangle2D.Double(); diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainUtil.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainUtil.java index a43b01aa..bdea8a59 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainUtil.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainUtil.java @@ -1,5 +1,5 @@ // -// $Id: ChainUtil.java,v 1.3 2001/07/14 00:55:21 mdb Exp $ +// $Id: ChainUtil.java,v 1.4 2001/07/17 07:18:09 mdb Exp $ package com.samskivert.viztool.viz; @@ -115,7 +115,7 @@ public class ChainUtil // if we have no parent, we want to insert ourselves as a root // class if (parent == null || parent.equals(Object.class)) { - insertRoot(roots, name, target); + insertRoot(roots, name, target, true); } else { String tpkg = pkgFromClass(target.getName()); @@ -125,7 +125,7 @@ public class ChainUtil // into the hierarchy as a root class if (!tpkg.equals(ppkg)) { String pname = generateName(parent, pkgroot, true); - insertRoot(roots, pname, parent); + insertRoot(roots, pname, parent, false); } // and now hang ourselves off of our parent class @@ -196,9 +196,9 @@ public class ChainUtil } protected static boolean insertRoot (ArrayList roots, String name, - Class root) + Class root, boolean inpkg) { - Chain chroot = new Chain(name, root); + Chain chroot = new Chain(name, root, inpkg); // make sure no chain already exists for this root if (!roots.contains(chroot)) { roots.add(chroot); diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java index b8907a4d..e6cebedd 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/HierarchyVisualizer.java @@ -1,5 +1,5 @@ // -// $Id: HierarchyVisualizer.java,v 1.6 2001/07/17 05:28:46 mdb Exp $ +// $Id: HierarchyVisualizer.java,v 1.7 2001/07/17 07:18:09 mdb Exp $ package com.samskivert.viztool.viz; @@ -37,7 +37,13 @@ public class HierarchyVisualizer implements Printable // dump all the classes into an array list so that we can // repeatedly scan through the list while (iter.hasNext()) { - _classes.add(iter.next()); + // strip out inner classes, we'll catch those via their + // declaring classes + String name = (String)iter.next(); + if (name.indexOf("$") != -1) { + continue; + } + _classes.add(name); } // compile a list of all packages in our collection