Modified code to deal better with splitting chain groups across pages. It

still chokes if a single chain won't fit on a page, but what to do there
is complicated and non-obvious.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@205 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-07-24 18:07:35 +00:00
parent 8e80f60a40
commit e78b957839
5 changed files with 138 additions and 71 deletions
@@ -1,5 +1,5 @@
//
// $Id: Driver.java,v 1.5 2001/07/17 07:18:09 mdb Exp $
// $Id: Driver.java,v 1.6 2001/07/24 18:07:35 mdb Exp $
package com.samskivert.viztool;
@@ -31,6 +31,7 @@ public class Driver
// run ourselves on the classpath
String classpath = System.getProperty("java.class.path");
// System.err.println("Scanning " + classpath + ".");
ClassEnumerator enum = new ClassEnumerator(classpath);
// print out the warnings
@@ -1,5 +1,5 @@
//
// $Id: ChainGroup.java,v 1.6 2001/07/17 06:01:08 mdb Exp $
// $Id: ChainGroup.java,v 1.7 2001/07/24 18:07:35 mdb Exp $
package com.samskivert.viztool.viz;
@@ -28,13 +28,60 @@ public class ChainGroup
// process the classes provided by our enumerator
_roots = ChainUtil.buildChains(pkgroot, iter);
// System.err.println(_roots.size() + " chains for " + pkg + ".");
}
protected ChainGroup (String pkg, ArrayList roots)
{
_pkg = pkg;
_roots = roots;
}
/**
* Lays out the chains in this group and returns the total size.
* Returns the dimensions of this chain group. This value is only
* valid after <code>layout</code> has been called.
*/
public Rectangle2D layout (Graphics2D gfx, double pageWidth,
double pageHeight)
public Rectangle2D getBounds ()
{
return _size;
}
/**
* Sets the upper left coordinate of this group. The group itself
* never looks at this information, but it will be made available as
* the x and y coordinates of the rectangle returned by
* <code>getBounds</code>.
*/
public void setPosition (double x, double y)
{
_size.setRect(x, y, _size.getWidth(), _size.getHeight());
}
/**
* Returns the page on which this group should be rendered.
*/
public int getPage ()
{
return _page;
}
/**
* Sets the page on which this group should be rendered.
*/
public void setPage (int page)
{
_page = page;
}
/**
* Lays out the chains in this group and returns the total size. If
* the layout process requires that this chain group be split across
* multiple pages, a new chain group containing the overflow chains
* will be returned. If the group fits in the allotted space, null
* will be returned.
*/
public ChainGroup layout (
Graphics2D gfx, double pageWidth, double pageHeight)
{
// lay out the internal structure of our chains
ChainVisualizer clay = new CascadingChainVisualizer();
@@ -58,19 +105,28 @@ public class ChainGroup
// arrange them on the page
ElementLayout elay = new PackedColumnElementLayout();
Rectangle2D[] dims = elay.layout(_roots, pageWidth, pageHeight);
// for now we're punting and assume that no group will exceed a
// single page in size
double width = dims[0].getWidth();
double height = dims[0].getHeight() + titleAscent;
ArrayList overflow = new ArrayList();
_size = elay.layout(_roots, pageWidth, pageHeight, overflow);
// make sure we're wide enough for our title
width = Math.max(width, layout.getAdvance() + 4);
double width = Math.max(_size.getWidth(), layout.getAdvance() + 4);
_size = new Rectangle2D.Double();
// adjust for our border and title
double height = _size.getHeight() + titleAscent;
_size.setRect(0, 0, width + 2*BORDER, height + 2*BORDER);
return _size;
// if we have overflow elements, create a new chain group with
// these elements, remove them from our roots list and be on our
// way
if (overflow.size() > 0) {
// remove the overflow roots from our list
for (int i = 0; i < overflow.size(); i++) {
_roots.remove(overflow.get(i));
}
return new ChainGroup(_pkg, overflow);
}
return null;
}
/**
@@ -132,9 +188,17 @@ public class ChainGroup
return (Chain)_roots.get(index);
}
public String toString ()
{
return "[pkg=" + _pkg + ", roots=" + _roots.size() +
", size=" + _size + ", page=" + _page + "]";
}
protected String _pkg;
protected ArrayList _roots;
protected Rectangle2D _size;
protected int _page;
protected static final double BORDER = 72/8;
}
@@ -1,5 +1,5 @@
//
// $Id: HierarchyVisualizer.java,v 1.7 2001/07/17 07:18:09 mdb Exp $
// $Id: HierarchyVisualizer.java,v 1.8 2001/07/24 18:07:35 mdb Exp $
package com.samskivert.viztool.viz;
@@ -45,6 +45,7 @@ public class HierarchyVisualizer implements Printable
}
_classes.add(name);
}
// System.err.println("Scanned " + _classes.size() + " classes.");
// compile a list of all packages in our collection
HashSet pkgset = new HashSet();
@@ -60,18 +61,15 @@ public class HierarchyVisualizer implements Printable
_packages[i] = (String)iter.next();
}
Arrays.sort(_packages, Comparators.STRING);
// System.err.println("Scanned " + _packages.length + " packages.");
// now create chain groups for each package
_groups = new ChainGroup[_packages.length];
for (int i = 0; i < _groups.length; i++) {
_groups = new ArrayList();
for (int i = 0; i < _packages.length; i++) {
PackageEnumerator penum = new PackageEnumerator(
_packages[i], _classes.iterator(), false);
_groups[i] = new ChainGroup(pkgroot, _packages[i], penum);
_groups.add(new ChainGroup(pkgroot, _packages[i], penum));
}
// we'll need these for later
_bounds = new Rectangle2D.Double[_packages.length];
_pagenos = new int[_packages.length];
}
/**
@@ -98,12 +96,16 @@ public class HierarchyVisualizer implements Printable
// render the groups on the requested page
int rendered = 0;
for (int i = 0; i < _groups.length; i++) {
for (int i = 0; i < _groups.size(); i++) {
ChainGroup group = (ChainGroup)_groups.get(i);
// skip groups not on this page
if (_pagenos[i] != pageIndex) {
if (group.getPage() != pageIndex) {
continue;
}
_groups[i].render(gfx, _bounds[i].getX(), _bounds[i].getY());
Rectangle2D bounds = group.getBounds();
group.render(gfx, bounds.getX(), bounds.getY());
rendered++;
}
@@ -113,26 +115,32 @@ public class HierarchyVisualizer implements Printable
public void layout (Graphics2D gfx, double x, double y,
double width, double height)
{
double starty = x;
double starty = y;
int pageno = 0;
// lay out our groups
for (int i = 0; i < _groups.length; i++) {
for (int i = 0; i < _groups.size(); i++) {
ChainGroup group = (ChainGroup)_groups.get(i);
// lay out the group in question
Rectangle2D bounds = _groups[i].layout(gfx, width, height);
ChainGroup ngrp = group.layout(gfx, width, height);
// if the process of laying this group out caused it to become
// split across pages, insert this new group into the list
if (ngrp != null) {
_groups.add(i+1, ngrp);
}
// determine if we need to skip to the next page or not
if ((y > 0) && (y + bounds.getHeight() > height)) {
Rectangle2D bounds = group.getBounds();
if ((y > starty) && (y + bounds.getHeight() > height + starty)) {
y = starty;
pageno++;
}
// assign x and y coordinates to this group
bounds.setRect(x, y, bounds.getWidth(), bounds.getHeight());
// and store it
_bounds[i] = bounds;
// also make a note of our page index
_pagenos[i] = pageno;
group.setPosition(x, y);
// make a note of our page index
group.setPage(pageno);
// increment our y location
y += (bounds.getHeight() + GAP);
@@ -142,13 +150,16 @@ public class HierarchyVisualizer implements Printable
public void paint (Graphics2D gfx, int pageIndex)
{
// render the groups on the requested page
for (int i = 0; i < _groups.length; i++) {
for (int i = 0; i < _groups.size(); i++) {
ChainGroup group = (ChainGroup)_groups.get(i);
// skip groups not on this page
if (_pagenos[i] != pageIndex) {
if (group.getPage() != pageIndex) {
continue;
}
_groups[i].render((Graphics2D)gfx,
_bounds[i].getX(), _bounds[i].getY());
Rectangle2D bounds = group.getBounds();
group.render((Graphics2D)gfx, bounds.getX(), bounds.getY());
}
}
@@ -156,11 +167,9 @@ public class HierarchyVisualizer implements Printable
protected ArrayList _classes = new ArrayList();
protected String[] _packages;
protected ChainGroup[] _groups;
protected ArrayList _groups;
protected PageFormat _format;
protected Rectangle2D[] _bounds;
protected int[] _pagenos;
protected static final int PAGE_WIDTH = (int)(72 * 7.5);
protected static final int PAGE_HEIGHT = (int)(72 * 10);
@@ -1,5 +1,5 @@
//
// $Id: ElementLayout.java,v 1.2 2001/07/17 01:54:19 mdb Exp $
// $Id: ElementLayout.java,v 1.3 2001/07/24 18:07:35 mdb Exp $
package com.samskivert.viztool.viz;
@@ -15,12 +15,13 @@ import java.util.List;
public interface ElementLayout
{
/**
* Lay out the supplied list of elements. Page numbers should be
* assigned to all elements if the layout spans multiple pages.
* Lay out the supplied list of elements. Any elements that do not fit
* into the allotted space should be added to the overflow list. The
* supplied elements list should not be modified.
*
* @return an array of rectangle objects representing the width and
* height of each page that was laid out.
* @return the bounding dimensions of the collection of elements that
* were laid out.
*/
public Rectangle2D[] layout (List elements,
double pageWidth, double pageHeight);
public Rectangle2D layout (List elements, double pageWidth,
double pageHeight, List overflow);
}
@@ -1,5 +1,5 @@
//
// $Id: PackedColumnElementLayout.java,v 1.4 2001/07/17 05:16:16 mdb Exp $
// $Id: PackedColumnElementLayout.java,v 1.5 2001/07/24 18:07:35 mdb Exp $
package com.samskivert.viztool.viz;
@@ -13,19 +13,16 @@ import java.util.*;
public class PackedColumnElementLayout implements ElementLayout
{
// docs inherited from interface
public Rectangle2D[] layout (List elements,
double pageWidth, double pageHeight)
public Rectangle2D layout (List elements, double pageWidth,
double pageHeight, List overflow)
{
// create a new list containing the elements whose order we can
// manipulate willy nilly
// sort the elements first by height then alphabetically
Element[] elems = new Element[elements.size()];
elements.toArray(elems);
Arrays.sort(elems, HEIGHT_COMP);
// lay out the elements across the page
ArrayList pagedims = new ArrayList();
double x = 0, y = 0, rowheight = 0, maxwidth = 0;
int pageno = 0;
for (int i = 0; i < elems.length; i++) {
Rectangle2D bounds = elems[i].getBounds();
@@ -42,26 +39,25 @@ public class PackedColumnElementLayout implements ElementLayout
// move down to the next row
x = 0;
y += (rowheight + GAP);
// reset our max rowheight
rowheight = bounds.getHeight();
// reset our max rowheight (we set it to -GAP because we
// will add rowheight to our last y position to compute
// the total height and if no more elements are laid out,
// we'll want to remove that trailing gap)
rowheight = -GAP;
}
// make sure we fit on this page (but force placement if we're
// currently at the top margin)
if ((y > 0) && ((y + bounds.getHeight()) > pageHeight)) {
// make a note of how big the current page is
pagedims.add(new Rectangle2D.Double(0, 0, maxwidth, y));
// move to the next page
x = 0;
y = 0;
rowheight = bounds.getHeight();
maxwidth = 0;
pageno++;
// if we didn't fit, we go onto the overflow list
overflow.add(elems[i]);
// and continue on because maybe some shorter elements
// further down the list will fit
continue;
}
// lay this element out at our current coordinates
elems[i].setBounds(x, y, bounds.getWidth(), bounds.getHeight());
// elems[i].setPage(pageno);
// keep track of the maximum row height
if (bounds.getHeight() > rowheight) {
@@ -78,11 +74,7 @@ public class PackedColumnElementLayout implements ElementLayout
maxwidth = x;
}
// make a note of how big the final page is
pagedims.add(new Rectangle2D.Double(0, 0, maxwidth, y+rowheight));
Rectangle2D[] dims = new Rectangle2D[pagedims.size()];
pagedims.toArray(dims);
return dims;
return new Rectangle2D.Double(0, 0, maxwidth, y+rowheight);
}
protected static class HeightComparator implements Comparator