StandardLayouter.java
/*
* @(#)StandardLayouter.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: © by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package CH.ifa.draw.contrib;
import CH.ifa.draw.framework.*;
import CH.ifa.draw.contrib.*;
import CH.ifa.draw.util.*;
import java.awt.*;
import java.io.*;
/**
* A StandardLayouter contains standard algorithm for
* layouting a Layoutable. As a standard behaviour
* all child components of a Layoutable are laid out
* underneath each other starting from top to bottom while the
* x position of all child components stays the same and the width
* is forced to the width of the maximum width. At the end
* the presentation figure of the Layoutable is
* set to the maximum x and y size to encompass all contained
* child components graphically as well.
*
* @author Wolfram Kaiser
* @version <$CURRENT_VERSION$>
*/
public class StandardLayouter implements Layouter {
/**
* The Layoutable which should be laid out.
*/
private Layoutable myLayoutable;
/**
* Insets to calculate a border
*/
private Insets myInsets;
static final long serialVersionUID = 2928651014089117493L;
/**
* Default constructor which is needed for the Storable mechanism.
* Usually, the constructor which takes a Layoutable
* should be used as each StandardLayouter is associated
* with exactly one Layoutable.
*/
public StandardLayouter() {
}
/**
* Constructor which associates a StandardLayouter with
* a certain Layoutable.
*
* @param newLayoutable Layoutable to be laid out
*/
public StandardLayouter(Layoutable newLayoutable) {
setInsets(new Insets(0, 0, 0, 0));
setLayoutable(newLayoutable);
}
/**
* Get the figure upon which the layout strategy operates.
*
* @return associated figure which should be laid out
*/
public Layoutable getLayoutable() {
return myLayoutable;
}
/**
* Set the figure upon which the layout strategy operates.
*
* @param newLayoutable Layoutable to be laid out
*/
public void setLayoutable(Layoutable newLayoutable) {
myLayoutable = newLayoutable;
}
/*
* Calculate the layout for the figure and all its subelements. The
* layout is not actually performed but just its dimensions are calculated.
* Insets are added for all non-top-level figures.
*
* @param origin start point for the layout
* @param corner minimum corner point for the layout
*/
public Rectangle calculateLayout(Point origin, Point corner) {
int maxWidth = Math.abs(corner.x - origin.x);
int maxHeight = 0;
// layout enclosed Layoutable and find maximum width
FigureEnumeration enum3 = getLayoutable().figures();
while (enum3.hasMoreElements()) {
Figure currentFigure = enum3.nextFigure();
Rectangle r = null;
if (currentFigure instanceof Layoutable) {
Layouter layoutStrategy = ((Layoutable)currentFigure).getLayouter();
r = layoutStrategy.calculateLayout(
new Point(0, 0), new Point(0, 0));
// add insets to calculated rectangle
r.grow(layoutStrategy.getInsets().left + layoutStrategy.getInsets().right,
layoutStrategy.getInsets().top + layoutStrategy.getInsets().bottom);
}
else {
r = new Rectangle(currentFigure.displayBox().getBounds());
}
maxWidth = Math.max(maxWidth, r.width);
maxHeight += r.height;
}
return new Rectangle(origin.x, origin.y, maxWidth, maxHeight);
}
/**
* Method which lays out a figure. It is called by the figure
* if a layout task is to be performed. First, the layout dimension for
* the figure is calculated and then the figure is arranged newly.
* All child component are place beneath another. The figure and all
* its children are forced to the minimium width
*
* @param origin start point for the layout
* @param corner minimum corner point for the layout
*/
public Rectangle layout(Point origin, Point corner) {
// calculate the layout of the figure and its sub-figures first
Rectangle r = calculateLayout(origin, corner);
int maxHeight = getInsets().top;
/*FigureEnumeration enum = getLayoutable().figures();
while (enum.hasMoreElements()) {
Figure currentFigure = enum.nextFigure();
Point partOrigin = new Point(r.x + getInsets().left, r.y + maxHeight);
Point partCorner = new Point(r.x + getInsets().left + r.width, r.y + currentFigure.displayBox().height);
currentFigure.displayBox(partOrigin, partCorner);
maxHeight += currentFigure.displayBox().height;
}
*/
// the maximum width has been already calculated
return new Rectangle(r.x, r.y, r.x + r.width, r.y + maxHeight + getInsets().bottom);
}
/**
* Reads the contained figures from StorableInput.
*/
public void read(StorableInput dr) throws IOException {
setLayoutable((Layoutable)dr.readStorable());
}
/**
* Writes the contained figures to the StorableOutput.
*/
public void write(StorableOutput dw) {
dw.writeStorable(getLayoutable());
}
/**
* Set the insets for spacing between the figure and its subfigures
*
* @param newInsets new spacing dimensions
*/
public void setInsets(Insets newInsets) {
myInsets = newInsets;
}
/**
* Get the insets for spacing between the figure and its subfigures
*
* @return spacing dimensions
*/
public Insets getInsets() {
return myInsets;
}
}