From e78b9578399cd4e918038e653edd110079e8b0c0 Mon Sep 17 00:00:00 2001 From: mdb Date: Tue, 24 Jul 2001 18:07:35 +0000 Subject: [PATCH] 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 --- .../java/com/samskivert/viztool/Driver.java | 3 +- .../viztool/hierarchy/ChainGroup.java | 90 ++++++++++++++++--- .../hierarchy/HierarchyVisualizer.java | 63 +++++++------ .../viztool/layout/ElementLayout.java | 15 ++-- .../layout/PackedColumnElementLayout.java | 38 ++++---- 5 files changed, 138 insertions(+), 71 deletions(-) diff --git a/projects/viztool/src/java/com/samskivert/viztool/Driver.java b/projects/viztool/src/java/com/samskivert/viztool/Driver.java index 6abc3892..8c728ccb 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.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 diff --git a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java index bfad782f..2e3ea5af 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java +++ b/projects/viztool/src/java/com/samskivert/viztool/hierarchy/ChainGroup.java @@ -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 layout 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 + * getBounds. + */ + 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; } 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 e6cebedd..24eed0a5 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.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); diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java b/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java index 8e9865e8..182defdd 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java +++ b/projects/viztool/src/java/com/samskivert/viztool/layout/ElementLayout.java @@ -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); } diff --git a/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java b/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java index f387e41d..74fe1203 100644 --- a/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java +++ b/projects/viztool/src/java/com/samskivert/viztool/layout/PackedColumnElementLayout.java @@ -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