diff options
Diffstat (limited to 'src/org/apache/fop/layoutmgr')
18 files changed, 1634 insertions, 46 deletions
diff --git a/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java index 519eaade8..34682b143 100644 --- a/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java @@ -8,14 +8,12 @@ package org.apache.fop.layoutmgr; import org.apache.fop.fo.FObj; -import org.apache.fop.fo.FONode; import org.apache.fop.area.Area; import org.apache.fop.area.Resolveable; import org.apache.fop.area.PageViewport; import org.apache.fop.fo.PropertyManager; import java.util.ListIterator; -import java.util.ArrayList; /** * The base class for all LayoutManagers. @@ -106,18 +104,10 @@ public abstract class AbstractLayoutManager implements LayoutManager { return m_curChildLM; } while (m_childLMiter.hasNext()) { - Object obj = m_childLMiter.next(); - if (obj instanceof LayoutManager) { - m_curChildLM = (LayoutManager) obj; - m_curChildLM.setParentLM(this); - m_curChildLM.init(); - return m_curChildLM; - } else { - m_childLMiter.remove(); - //log.warn( - // "child LM not a LayoutManager: " + - // obj.getClass().getName()); - } + m_curChildLM = (LayoutManager) m_childLMiter.next(); + m_curChildLM.setParentLM(this); + m_curChildLM.init(); + return m_curChildLM; } return null; } @@ -257,26 +247,69 @@ public abstract class AbstractLayoutManager implements LayoutManager { return false; } + /** + * Delegate getting the current page number to the parent layout manager. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ public String getCurrentPageNumber() { return parentLM.getCurrentPageNumber(); } + /** + * Delegate resolving the id reference to the parent layout manager. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ public PageViewport resolveRefID(String ref) { return parentLM.resolveRefID(ref); } + /** + * Add the id to the page. + * If the id string is not null then add the id to the current page. + */ protected void addID() { if(foID != null) { addIDToPage(foID); } } + /** + * Delegate adding id reference to the parent layout manager. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ public void addIDToPage(String id) { parentLM.addIDToPage(id); } + /** + * Delegate adding unresolved area to the parent layout manager. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ public void addUnresolvedArea(String id, Resolveable res) { parentLM.addUnresolvedArea(id, res); } + + /** + * Delegate adding marker to the parent layout manager. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ + public void addMarker(String name, LayoutManager lm, boolean start) { + parentLM.addMarker(name, lm, start); + } + + /** + * Delegate retrieve marker to the parent layout manager. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ + public LayoutManager retrieveMarker(String name, int pos, int boundary) { + return parentLM.retrieveMarker(name, pos, boundary); + } + } diff --git a/src/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java index 4c6ea73ff..dbca5cdd0 100644 --- a/src/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java @@ -231,27 +231,26 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager { if (curBlockArea == null) { viewportBlockArea = new BlockViewport(); if(abProps.absolutePosition == AbsolutePosition.ABSOLUTE) { - Rectangle2D rect = new Rectangle2D.Double(abProps.left, - abProps.top, abProps.right - abProps.left, - abProps.bottom - abProps.top); - viewportBlockArea.setBounds(rect); + viewportBlockArea.setXOffset(abProps.left); + viewportBlockArea.setYOffset(abProps.top); + viewportBlockArea.setWidth(abProps.right - abProps.left); + viewportBlockArea.setHeight(abProps.bottom - abProps.top); + viewportBlockArea.setCTM(absoluteCTM); viewportBlockArea.setClip(clip); } else { double[] vals = absoluteCTM.toArray(); boolean rotated = vals[0] == 0.0; if(rotated) { - Rectangle2D rect = new Rectangle2D.Double(0, 0, - relDims.bpd, getRotatedIPD()); - viewportBlockArea.setBounds(rect); + viewportBlockArea.setWidth(relDims.bpd); + viewportBlockArea.setHeight(getRotatedIPD()); viewportBlockArea.setCTM(absoluteCTM); viewportBlockArea.setClip(clip); } else if(vals[0] == -1.0) { // need to set bpd to actual size for rotation // and stacking - Rectangle2D rect = new Rectangle2D.Double(0, 0, - relDims.ipd, relDims.bpd); - viewportBlockArea.setBounds(rect); + viewportBlockArea.setWidth(relDims.ipd); + viewportBlockArea.setWidth(relDims.bpd); viewportBlockArea.setCTM(absoluteCTM); viewportBlockArea.setClip(clip); } @@ -289,5 +288,10 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager { reset(null); } } + + public void addMarker(String name, LayoutManager lm, boolean start) { + parentLM.addMarker(name, lm, start); + } + } diff --git a/src/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/org/apache/fop/layoutmgr/BlockLayoutManager.java index bf507a965..ec6e58c18 100644 --- a/src/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -211,20 +211,11 @@ public class BlockLayoutManager extends BlockStackingLayoutManager { public boolean addChild(Area childArea) { if (curBlockArea != null) { if (childArea instanceof LineArea) { - // Something about widows and orphans - // Position the line area and calculate size... curBlockArea.addLineArea((LineArea) childArea); - MinOptMax targetDim = parentArea.getAvailBPD(); - MinOptMax currentDim = curBlockArea.getContentBPD(); - //if(currentDim.min > targetDim.max) { - // return true; - //} - return false; } else { curBlockArea.addBlock((Block) childArea); - //return super.addChild(childArea); return false; } diff --git a/src/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java b/src/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java index 1b091a662..249500931 100644 --- a/src/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java @@ -1,6 +1,6 @@ /* * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. */ @@ -48,8 +48,6 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager { this.parentArea = parentArea; } - - protected MinOptMax resolveSpaceSpecifier(Area nextArea) { SpaceSpecifier spaceSpec = new SpaceSpecifier(false); // Area prevArea = getCurrentArea().getLast(); @@ -126,8 +124,9 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager { * Force current area to be added to parent area. */ protected boolean flush() { - if (getCurrentArea() != null) + if (getCurrentArea() != null) { return parentLM.addChild(getCurrentArea()); + } return false; } diff --git a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java index b9342b28c..9d9eaf5d5 100644 --- a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java +++ b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java @@ -13,7 +13,7 @@ import java.util.List; public class BreakPossPosIter extends PositionIterator { private int m_iterCount ; - BreakPossPosIter(List bpList, int startPos, int endPos) { + public BreakPossPosIter(List bpList, int startPos, int endPos) { super(bpList.listIterator(startPos)); m_iterCount = endPos - startPos; } diff --git a/src/org/apache/fop/layoutmgr/ContentLayoutManager.java b/src/org/apache/fop/layoutmgr/ContentLayoutManager.java index 7ca005c0c..a27d7f120 100644 --- a/src/org/apache/fop/layoutmgr/ContentLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/ContentLayoutManager.java @@ -178,5 +178,15 @@ public class ContentLayoutManager implements LayoutManager { public void addUnresolvedArea(String id, Resolveable res) { parentLM.addUnresolvedArea(id, res); } + + /** @see org.apache.fop.layoutmgr.LayoutManager */ + public void addMarker(String name, LayoutManager lm, boolean start) { + parentLM.addMarker(name, lm, start); + } + + /** @see org.apache.fop.layoutmgr.LayoutManager */ + public LayoutManager retrieveMarker(String name, int pos, int boundary) { + return parentLM.retrieveMarker(name, pos, boundary); + } } diff --git a/src/org/apache/fop/layoutmgr/FlowLayoutManager.java b/src/org/apache/fop/layoutmgr/FlowLayoutManager.java index 4b12bd385..4d4dc0e02 100644 --- a/src/org/apache/fop/layoutmgr/FlowLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/FlowLayoutManager.java @@ -138,5 +138,16 @@ public class FlowLayoutManager extends BlockStackingLayoutManager { reset(null); } } + + /** + * Retrieve marker is not allowed in the flow so this reports an + * error and returns null. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ + public LayoutManager retrieveMarker(String name, int pos, int boundary) { + // error cannot retrieve markers in flow + return null; + } } diff --git a/src/org/apache/fop/layoutmgr/LayoutManager.java b/src/org/apache/fop/layoutmgr/LayoutManager.java index cac65a075..664730fd9 100644 --- a/src/org/apache/fop/layoutmgr/LayoutManager.java +++ b/src/org/apache/fop/layoutmgr/LayoutManager.java @@ -64,11 +64,60 @@ public interface LayoutManager { public void getWordChars(StringBuffer sbChars, Position bp1, Position bp2); + /** + * Get the string of the current page number. + * + * @return the string for the current page number + */ public String getCurrentPageNumber(); + /** + * Resolve the id reference. + * This is called by an area looking for an id reference. + * If the id reference is not found then it should add a resolveable object. + * + * @param ref the id reference + * @return the page containing the id reference or null if not found + */ public PageViewport resolveRefID(String ref); + /** + * Add an id to the page. + * @todo add the location of the area on the page + * + * @param id the id reference to add. + */ public void addIDToPage(String id); + /** + * Add an unresolved area. + * The is used to add a resolveable object to the page for a given id. + * + * @param id the id reference this object needs for resolving + * @param res the resolveable object + */ public void addUnresolvedArea(String id, Resolveable res); + + /** + * Add the marker. + * A number of formatting objects may contain markers. This + * method is used to add those markers to the page. + * + * @param name the marker class name + * @param lm the layout manager of the marker child + * @param start true if the formatting object is starting false is finishing + */ + public void addMarker(String name, LayoutManager lm, boolean start); + + /** + * Retrieve a marker. + * This method is used when retrieve a marker. + * + * @param name the class name of the marker + * @param pos the retrieve position + * @param boundary the boundary for retrieving the marker + * @return the layout manaager of the retrieved marker if any + */ + public LayoutManager retrieveMarker(String name, int pos, int boundary); + } diff --git a/src/org/apache/fop/layoutmgr/PageLayoutManager.java b/src/org/apache/fop/layoutmgr/PageLayoutManager.java index a1a09d6f7..c22bc589e 100644 --- a/src/org/apache/fop/layoutmgr/PageLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/PageLayoutManager.java @@ -164,6 +164,19 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable areaTree.addUnresolvedID(id, curPage); } + public void addMarker(String name, LayoutManager lm, boolean start) { + if(start) { + // add marker to page on area tree + } else { + // add end marker to page on area tree + } + } + + public LayoutManager retrieveMarker(String name, int pos, int boundary) { + // get marker from the current markers on area tree + return null; + } + /** * For now, only handle normal flow areas. */ diff --git a/src/org/apache/fop/layoutmgr/PositionIterator.java b/src/org/apache/fop/layoutmgr/PositionIterator.java index 66d5e3a3e..5e951a09f 100644 --- a/src/org/apache/fop/layoutmgr/PositionIterator.java +++ b/src/org/apache/fop/layoutmgr/PositionIterator.java @@ -23,7 +23,7 @@ public abstract class PositionIterator implements Iterator { //checkNext(); } - LayoutManager getNextChildLM() { + public LayoutManager getNextChildLM() { // Move to next "segment" of iterator, ie: new childLM if (m_childLM == null && m_nextObj != null) { m_childLM = getLM(m_nextObj); diff --git a/src/org/apache/fop/layoutmgr/StaticContentLayoutManager.java b/src/org/apache/fop/layoutmgr/StaticContentLayoutManager.java index 9932e1a45..b4c673e74 100644 --- a/src/org/apache/fop/layoutmgr/StaticContentLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/StaticContentLayoutManager.java @@ -1,19 +1,18 @@ /* * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. */ package org.apache.fop.layoutmgr; -import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FObj; -import org.apache.fop.fo.properties.Constants; -import org.apache.fop.area.*; +import org.apache.fop.area.RegionReference; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; import java.util.ArrayList; -import java.util.List; /** * LayoutManager for an fo:flow object. @@ -24,7 +23,7 @@ import java.util.List; public class StaticContentLayoutManager extends BlockStackingLayoutManager { private RegionReference region; - ArrayList blockBreaks = new ArrayList(); + private ArrayList blockBreaks = new ArrayList(); public StaticContentLayoutManager(FObj fobj) { super(fobj); @@ -46,7 +45,7 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager { if (!curLM.isFinished()) { if ((bp = curLM.getNextBreakPoss(childLC)) != null) { blockBreaks.add(bp); - if(bp.isForcedBreak()) { + if (bp.isForcedBreak()) { System.out.println("Forced breaks are not allowed in static content"); return null; } @@ -98,5 +97,14 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager { return region; } + /** + * Markers are not allowed in static areas so this reports an + * error and does nothing. + * + * @see org.apache.fop.layoutmgr.LayoutManager + */ + public void addMarker(String name, LayoutManager lm, boolean start) { + // error markers not allowed in static + } } diff --git a/src/org/apache/fop/layoutmgr/table/Body.java b/src/org/apache/fop/layoutmgr/table/Body.java new file mode 100644 index 000000000..902c14bea --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/Body.java @@ -0,0 +1,213 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.LeafPosition; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.BreakPossPosIter; +import org.apache.fop.layoutmgr.Position; +import org.apache.fop.fo.FObj; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.MinOptMax; + +import java.util.ArrayList; +import java.util.List; + +/** + * LayoutManager for a table-header, table-footer and table body FO. + * These fo objects have either rows or cells underneath. + * Cells are organised into rows. + */ +public class Body extends BlockStackingLayoutManager { + + private boolean rows = true; + private List columns; + + private int yoffset; + private int bodyHeight; + + private Block curBlockArea; + + private ArrayList childBreaks = new ArrayList(); + + /** + * Create a new body layout manager. + * + * @param fobj the formatting object that created this manager + */ + public Body(FObj fobj) { + super(fobj); + } + + /** + * Set the columns from the table. + * + * @param cols the list of columns used for this body + */ + public void setColumns(List cols) { + columns = cols; + } + + /** + * Breaks for this layout manager are of the form of before + * or after a row and inside a row. + * + * @param context the layout context for finding the breaks + * @return the next break possibility + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + Row curLM; // currently active LM + + MinOptMax stackSize = new MinOptMax(); + BreakPoss lastPos = null; + + while ((curLM = (Row)getChildLM()) != null) { + // Make break positions + // Set up a LayoutContext + int ipd = context.getRefIPD(); + BreakPoss bp; + + LayoutContext childLC = new LayoutContext(0); + childLC.setStackLimit( + MinOptMax.subtract(context.getStackLimit(), + stackSize)); + childLC.setRefIPD(ipd); + + curLM.setColumns(columns); + + while (!curLM.isFinished()) { + if ((bp = curLM.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + if (stackSize.min > context.getStackLimit().max) { + // reset to last break + if (lastPos != null) { + reset(lastPos.getPosition()); + } else { + curLM.resetPosition(null); + } + break; + } + lastPos = bp; + childBreaks.add(bp); + + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + BreakPoss breakPoss = new BreakPoss( + new LeafPosition(this, childBreaks.size() - 1)); + breakPoss.setStackingSize(stackSize); + return breakPoss; + } + + setFinished(true); + return null; + } + + /** + * Set the y offset of this body within the table. + * This is used to set the row offsets. + * + * @param off the y offset position + */ + public void setYOffset(int off) { + yoffset = off; + } + + /** + * Add the areas for the break points. + * This sets the offset of each row as it is added. + * + * @param parentIter the position iterator + * @param layoutContext the layout context for adding areas + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + getParentArea(null); + addID(); + + Row childLM; + int iStartPos = 0; + LayoutContext lc = new LayoutContext(0); + int rowoffset = 0; + while (parentIter.hasNext()) { + LeafPosition lfp = (LeafPosition) parentIter.next(); + // Add the block areas to Area + PositionIterator breakPosIter = + new BreakPossPosIter(childBreaks, iStartPos, + lfp.getLeafPos() + 1); + iStartPos = lfp.getLeafPos() + 1; + while ((childLM = (Row)breakPosIter.getNextChildLM()) != null) { + childLM.setYOffset(yoffset + rowoffset); + childLM.addAreas(breakPosIter, lc); + rowoffset += childLM.getRowHeight(); + } + } + bodyHeight = rowoffset; + + flush(); + + childBreaks.clear(); + curBlockArea = null; + } + + /** + * Get the body height of the body after adjusting. + * Should only be called after adding the body areas. + * + * @return the body height of this body + */ + public int getBodyHeight() { + return bodyHeight; + } + + /** + * Return an Area which can contain the passed childArea. The childArea + * may not yet have any content, but it has essential traits set. + * In general, if the LayoutManager already has an Area it simply returns + * it. Otherwise, it makes a new Area of the appropriate class. + * It gets a parent area for its area by calling its parent LM. + * Finally, based on the dimensions of the parent area, it initializes + * its own area. This includes setting the content IPD and the maximum + * BPD. + * + * @param childArea the child area + * @return the parent are of the child + */ + public Area getParentArea(Area childArea) { + return parentLM.getParentArea(childArea); + } + + /** + * Add the child area. + * The table-header, table-footer and table-body areas return + * the areas return by the children. + * + * @param childArea the child area to add + * @return unused + */ + public boolean addChild(Area childArea) { + return parentLM.addChild(childArea); + } + + /** + * Reset the position of the layout manager. + * + * @param resetPos the position to reset to + */ + public void resetPosition(Position resetPos) { + if (resetPos == null) { + reset(null); + } + } +} + diff --git a/src/org/apache/fop/layoutmgr/table/Caption.java b/src/org/apache/fop/layoutmgr/table/Caption.java new file mode 100644 index 000000000..4e310034c --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/Caption.java @@ -0,0 +1,190 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LeafPosition; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.BreakPossPosIter; +import org.apache.fop.layoutmgr.Position; +import org.apache.fop.fo.FObj; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.MinOptMax; + +import java.util.ArrayList; + +/** + * LayoutManager for a table-caption FO. + * The table caption contains blocks that are placed beside the + * table. + */ +public class Caption extends BlockStackingLayoutManager { + + private Block curBlockArea; + + private ArrayList childBreaks = new ArrayList(); + + /** + * Create a new Caption layout manager. + * + * @param fobj the formatting object that created this manager + */ + public Caption(FObj fobj) { + super(fobj); + } + + /** + * Get the next break position for the caption. + * + * @param context the layout context for finding breaks + * @return the next break possibility + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + LayoutManager curLM; // currently active LM + + MinOptMax stackSize = new MinOptMax(); + // if starting add space before + // stackSize.add(spaceBefore); + BreakPoss lastPos = null; + + // if there is a caption then get the side and work out when + // to handle it + + while ((curLM = getChildLM()) != null) { + // Make break positions and return blocks! + // Set up a LayoutContext + int ipd = context.getRefIPD(); + BreakPoss bp; + + LayoutContext childLC = new LayoutContext(0); + // if line layout manager then set stack limit to ipd + // line LM actually generates a LineArea which is a block + childLC.setStackLimit( + MinOptMax.subtract(context.getStackLimit(), + stackSize)); + childLC.setRefIPD(ipd); + + while (!curLM.isFinished()) { + if ((bp = curLM.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + if (stackSize.min > context.getStackLimit().max) { + // reset to last break + if (lastPos != null) { + reset(lastPos.getPosition()); + } else { + curLM.resetPosition(null); + } + break; + } + lastPos = bp; + childBreaks.add(bp); + + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + BreakPoss breakPoss = new BreakPoss( + new LeafPosition(this, childBreaks.size() - 1)); + breakPoss.setStackingSize(stackSize); + return breakPoss; + } + setFinished(true); + return null; + } + + /** + * Add the areas to the parent. + * + * @param parentIter the position iterator of the breaks + * @param layoutContext the layout context for adding areas + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + getParentArea(null); + addID(); + + LayoutManager childLM; + int iStartPos = 0; + LayoutContext lc = new LayoutContext(0); + while (parentIter.hasNext()) { + LeafPosition lfp = (LeafPosition) parentIter.next(); + // Add the block areas to Area + PositionIterator breakPosIter = + new BreakPossPosIter(childBreaks, iStartPos, + lfp.getLeafPos() + 1); + iStartPos = lfp.getLeafPos() + 1; + while ((childLM = breakPosIter.getNextChildLM()) != null) { + childLM.addAreas(breakPosIter, lc); + } + } + + flush(); + + childBreaks.clear(); + curBlockArea = null; + } + + /** + * Return an Area which can contain the passed childArea. The childArea + * may not yet have any content, but it has essential traits set. + * In general, if the LayoutManager already has an Area it simply returns + * it. Otherwise, it makes a new Area of the appropriate class. + * It gets a parent area for its area by calling its parent LM. + * Finally, based on the dimensions of the parent area, it initializes + * its own area. This includes setting the content IPD and the maximum + * BPD. + * + * @param childArea the child area + * @return the parent area from this caption + */ + public Area getParentArea(Area childArea) { + if (curBlockArea == null) { + curBlockArea = new Block(); + // Set up dimensions + // Must get dimensions from parent area + Area parentArea = parentLM.getParentArea(curBlockArea); + int referenceIPD = parentArea.getIPD(); + curBlockArea.setIPD(referenceIPD); + // Get reference IPD from parentArea + setCurrentArea(curBlockArea); // ??? for generic operations + } + return curBlockArea; + } + + /** + * Add the child to the caption area. + * + * @param childArea the child area to add + * @return unused + */ + public boolean addChild(Area childArea) { + if (curBlockArea != null) { + curBlockArea.addBlock((Block) childArea); + //return super.addChild(childArea); + + return false; + } + return false; + } + + /** + * Reset the layout position. + * + * @param resetPos the position to reset to + */ + public void resetPosition(Position resetPos) { + if (resetPos == null) { + reset(null); + } + } +} + diff --git a/src/org/apache/fop/layoutmgr/table/Cell.java b/src/org/apache/fop/layoutmgr/table/Cell.java new file mode 100644 index 000000000..57dd6b2cf --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/Cell.java @@ -0,0 +1,215 @@ +/* + * $Id$ + * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LeafPosition; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.BreakPossPosIter; +import org.apache.fop.layoutmgr.Position; +import org.apache.fop.fo.FObj; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.MinOptMax; + +import java.util.ArrayList; + +/** + * LayoutManager for a table-cell FO. + * A cell contains blocks. These blocks fill the cell. + */ +public class Cell extends BlockStackingLayoutManager { + + private Block curBlockArea; + + private ArrayList childBreaks = new ArrayList(); + + private int xoffset; + private int yoffset; + private int cellIPD; + + /** + * Create a new Cell layout manager. + * @param fobj the formatting object for the cell + */ + public Cell(FObj fobj) { + super(fobj); + } + + /** + * Get the next break possibility for this cell. + * A cell contains blocks so there are breaks around the blocks + * and inside the blocks. + * + * @param context the layout context + * @return the next break possibility + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + LayoutManager curLM; // currently active LM + + MinOptMax stackSize = new MinOptMax(); + // if starting add space before + // stackSize.add(spaceBefore); + BreakPoss lastPos = null; + + cellIPD = context.getRefIPD(); + + while ((curLM = getChildLM()) != null) { + // Set up a LayoutContext + int ipd = context.getRefIPD(); + BreakPoss bp; + + LayoutContext childLC = new LayoutContext(0); + childLC.setStackLimit(MinOptMax.subtract(context.getStackLimit(), + stackSize)); + childLC.setRefIPD(ipd); + + while (!curLM.isFinished()) { + if ((bp = curLM.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + if (stackSize.min > context.getStackLimit().max) { + // reset to last break + if (lastPos != null) { + reset(lastPos.getPosition()); + } else { + curLM.resetPosition(null); + } + break; + } + lastPos = bp; + childBreaks.add(bp); + + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + BreakPoss breakPoss = new BreakPoss( + new LeafPosition(this, childBreaks.size() - 1)); + breakPoss.setStackingSize(stackSize); + return breakPoss; + } + setFinished(true); + return null; + } + + /** + * Set the y offset of this cell. + * This offset is used to set the absolute position of the cell. + * + * @param off the y direction offset + */ + public void setYOffset(int off) { + yoffset = off; + } + + /** + * Set the x offset of this cell. + * This offset is used to set the absolute position of the cell. + * + * @param off the x offset + */ + public void setXOffset(int off) { + xoffset = off; + } + + /** + * Add the areas for the break points. + * The cell contains block stacking layout managers + * that add block areas. + * + * @param parentIter the iterator of the break positions + * @param layoutContext the layout context for adding the areas + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + getParentArea(null); + addID(); + + LayoutManager childLM; + int iStartPos = 0; + LayoutContext lc = new LayoutContext(0); + while (parentIter.hasNext()) { + LeafPosition lfp = (LeafPosition) parentIter.next(); + // Add the block areas to Area + PositionIterator breakPosIter = + new BreakPossPosIter(childBreaks, iStartPos, + lfp.getLeafPos() + 1); + iStartPos = lfp.getLeafPos() + 1; + while ((childLM = breakPosIter.getNextChildLM()) != null) { + childLM.addAreas(breakPosIter, lc); + } + } + + flush(); + + childBreaks.clear(); + curBlockArea = null; + } + + /** + * Return an Area which can contain the passed childArea. The childArea + * may not yet have any content, but it has essential traits set. + * In general, if the LayoutManager already has an Area it simply returns + * it. Otherwise, it makes a new Area of the appropriate class. + * It gets a parent area for its area by calling its parent LM. + * Finally, based on the dimensions of the parent area, it initializes + * its own area. This includes setting the content IPD and the maximum + * BPD. + * + * @param childArea the child area to get the parent for + * @return the parent area + */ + public Area getParentArea(Area childArea) { + if (curBlockArea == null) { + curBlockArea = new Block(); + curBlockArea.setPositioning(Block.ABSOLUTE); + // set position + curBlockArea.setXOffset(xoffset); + curBlockArea.setYOffset(yoffset); + curBlockArea.setWidth(cellIPD); + //curBlockArea.setHeight(); + + // Set up dimensions + Area parentArea = parentLM.getParentArea(curBlockArea); + int referenceIPD = parentArea.getIPD(); + curBlockArea.setIPD(referenceIPD); + // Get reference IPD from parentArea + setCurrentArea(curBlockArea); // ??? for generic operations + } + return curBlockArea; + } + + /** + * Add the child to the cell block area. + * + * @param childArea the child to add to the cell + * @return unused + */ + public boolean addChild(Area childArea) { + if (curBlockArea != null) { + curBlockArea.addBlock((Block) childArea); + return false; + } + return false; + } + + /** + * Reset the position of the layout. + * + * @param resetPos the position to reset to + */ + public void resetPosition(Position resetPos) { + if (resetPos == null) { + reset(null); + } + } +} + diff --git a/src/org/apache/fop/layoutmgr/table/Column.java b/src/org/apache/fop/layoutmgr/table/Column.java new file mode 100644 index 000000000..c44de25cb --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/Column.java @@ -0,0 +1,92 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.AbstractLayoutManager; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.fo.flow.TableColumn; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; + +/** + * LayoutManager for a table-column FO. + * The table creates an area for the table-column background, this class + * is used to do the area creation. This is used during the layout to handle + * column properties. + */ +public class Column extends AbstractLayoutManager { + private int columnWidth; + + /** + * Create a new column layout manager. + * + * @param fobj the table-column formatting object + */ + public Column(TableColumn fobj) { + super(fobj); + columnWidth = fobj.getColumnWidth(); + } + + /** + * Get the next break possibility. + * Columns do not create or return any areas. + * + * @param context the layout context + * @return the break possibility, always null + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + return null; + } + + /** + * Add the areas. + * Although this adds no areas it is used to add the id + * reference of the table-column. + * + * @param parentIter the position iterator + * @param layoutContext the context + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + addID(); + } + + /** + * Get the parent area. + * This does nothing. + * + * @param childArea the child area + * @return always null + */ + public Area getParentArea(Area childArea) { + return null; + } + + /** + * Get the width of this column. + * + * @return the width of the column + */ + public int getWidth() { + return columnWidth; + } + + /** + * Create a column area. + * This area has the background and width set. + * The Body manager will then set the offset of the column. + * + * @return the new column area + */ + public Area createColumnArea() { + return new Block(); + } +} + diff --git a/src/org/apache/fop/layoutmgr/table/Row.java b/src/org/apache/fop/layoutmgr/table/Row.java new file mode 100644 index 000000000..ebca76f59 --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/Row.java @@ -0,0 +1,277 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LeafPosition; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.BreakPossPosIter; +import org.apache.fop.layoutmgr.Position; +import org.apache.fop.fo.FObj; +import org.apache.fop.area.Area; +import org.apache.fop.area.MinOptMax; + +import java.util.Iterator; +import java.util.ArrayList; +import java.util.List; + +/** + * LayoutManager for a table-row FO. + * The row contains cells that are organised according to the columns. + * A break in a table row will contain breaks for each table cell. + * If there are row spanning cells then these cells belong to this row + * but effect the occupied columns of future rows. + */ +public class Row extends BlockStackingLayoutManager { + + private List cellList = null; + private List columns = null; + private int rowHeight; + private int yoffset; + + private class RowPosition extends LeafPosition { + protected List cellBreaks; + protected RowPosition(LayoutManager lm, int pos, List l) { + super(lm, pos); + cellBreaks = l; + } + } + + /** + * Create a new row layout manager. + * + * @param fobj the table-row formatting object + */ + public Row(FObj fobj) { + super(fobj); + } + + /** + * Set the columns from the table. + * + * @param cols the list of columns for this table + */ + public void setColumns(List cols) { + columns = cols; + } + + private void setupCells() { + cellList = new ArrayList(); + // add cells to list + while (m_childLMiter.hasNext()) { + m_curChildLM = (LayoutManager) m_childLMiter.next(); + m_curChildLM.setParentLM(this); + m_curChildLM.init(); + cellList.add(m_curChildLM); + } + } + + /** + * Get the layout manager for a cell. + * + * @param pos the position of the cell + * @return the cell layout manager + */ + protected Cell getCellLM(int pos) { + if (cellList == null) { + setupCells(); + } + if (pos < cellList.size()) { + return (Cell)cellList.get(pos); + } + return null; + } + + /** + * Get the next break possibility. + * A row needs to get the possible breaks for each cell + * in the row and find a suitable break across all cells. + * + * @param context the layout context for getting breaks + * @return the next break possibility + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + LayoutManager curLM; // currently active LM + + BreakPoss lastPos = null; + ArrayList breakList = new ArrayList(); + + int min = 0; + int opt = 0; + int max = 0; + + int cellcount = 0; + while ((curLM = getCellLM(cellcount++)) != null) { + + ArrayList childBreaks = new ArrayList(); + MinOptMax stackSize = new MinOptMax(); + + // Set up a LayoutContext + // the ipd is from the current column + int ipd = context.getRefIPD(); + BreakPoss bp; + + LayoutContext childLC = new LayoutContext(0); + childLC.setStackLimit( + MinOptMax.subtract(context.getStackLimit(), + stackSize)); + + Column col = (Column)columns.get(cellcount - 1); + childLC.setRefIPD(col.getWidth()); + + while (!curLM.isFinished()) { + if ((bp = curLM.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + if (stackSize.min > context.getStackLimit().max) { + // reset to last break + if (lastPos != null) { + reset(lastPos.getPosition()); + } else { + curLM.resetPosition(null); + } + break; + } + lastPos = bp; + childBreaks.add(bp); + + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + // the min is the maximum min of all cells + if (stackSize.min > min) { + min = stackSize.min; + } + // the optimum is the average of all optimums + opt += stackSize.opt; + // the maximum is the largest maximum + if (stackSize.max > max) { + max = stackSize.max; + } + + breakList.add(childBreaks); + } + opt = opt / cellcount; + if (opt < min) { + opt = min; + } + rowHeight = opt; + + MinOptMax rowSize = new MinOptMax(min, opt, max); + + setFinished(true); + RowPosition rp = new RowPosition(this, breakList.size() - 1, breakList); + BreakPoss breakPoss = new BreakPoss(rp); + breakPoss.setStackingSize(rowSize); + return breakPoss; + } + + /** + * Set the y position offset of this row. + * This is used to set the position of the areas returned by this row. + * + * @param off the y offset + */ + public void setYOffset(int off) { + yoffset = off; + } + + /** + * Add the areas for the break points. + * This sets the offset of each cell as it is added. + * + * @param parentIter the position iterator + * @param layoutContext the layout context for adding areas + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + getParentArea(null); + addID(); + + Cell childLM; + int iStartPos = 0; + LayoutContext lc = new LayoutContext(0); + while (parentIter.hasNext()) { + RowPosition lfp = (RowPosition) parentIter.next(); + // Add the block areas to Area + + int cellcount = 0; + int xoffset = 0; + for (Iterator iter = lfp.cellBreaks.iterator(); iter.hasNext();) { + List cellsbr = (List)iter.next(); + PositionIterator breakPosIter; + breakPosIter = new BreakPossPosIter(cellsbr, 0, cellsbr.size()); + iStartPos = lfp.getLeafPos() + 1; + Column col = (Column)columns.get(cellcount++); + while ((childLM = (Cell)breakPosIter.getNextChildLM()) != null) { + childLM.setXOffset(xoffset); + childLM.setYOffset(yoffset); + childLM.addAreas(breakPosIter, lc); + } + xoffset += col.getWidth(); + } + } + + flush(); + + } + + /** + * Get the row height of the row after adjusting. + * Should only be called after adding the row areas. + * + * @return the row height of this row after adjustment + */ + public int getRowHeight() { + return rowHeight; + } + + /** + * Return an Area which can contain the passed childArea. The childArea + * may not yet have any content, but it has essential traits set. + * In general, if the LayoutManager already has an Area it simply returns + * it. Otherwise, it makes a new Area of the appropriate class. + * It gets a parent area for its area by calling its parent LM. + * Finally, based on the dimensions of the parent area, it initializes + * its own area. This includes setting the content IPD and the maximum + * BPD. + * + * @param childArea the child area + * @return the parent are for the child + */ + public Area getParentArea(Area childArea) { + return parentLM.getParentArea(childArea); + } + + /** + * Add the child. + * Rows return the areas returned by the child elements. + * This simply adds the area to the parent layout manager. + * + * @param childArea the child area + * @return unused + */ + public boolean addChild(Area childArea) { + return parentLM.addChild(childArea); + } + + /** + * Reset the position of this layout manager. + * + * @param resetPos the position to reset to + */ + public void resetPosition(Position resetPos) { + if (resetPos == null) { + reset(null); + } + } +} + diff --git a/src/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java b/src/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java new file mode 100644 index 000000000..dc7ffe21c --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java @@ -0,0 +1,192 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LeafPosition; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.BreakPossPosIter; +import org.apache.fop.layoutmgr.Position; +import org.apache.fop.fo.FObj; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.MinOptMax; + +import java.util.ArrayList; + +/** + * LayoutManager for a table-and-caption FO. + * A table and caption consists of a table and a caption. + * The caption contains blocks that are positioned next to the + * table on the caption side. + * The caption blocks have an implicit keep with the table. + */ +public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager { + + private Block curBlockArea; + + private ArrayList childBreaks = new ArrayList(); + + /** + * Create a new table and caption layout manager. + * + * @param fobj the table-and-caption formatting object + */ + public TableAndCaptionLayoutManager(FObj fobj) { + super(fobj); + } + + /** + * Get the next break possibility. + * + * @param context the layout context for getting breaks + * @return the next break possibility + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + LayoutManager curLM; // currently active LM + + MinOptMax stackSize = new MinOptMax(); + // if starting add space before + // stackSize.add(spaceBefore); + BreakPoss lastPos = null; + + // if there is a caption then get the side and work out when + // to handle it + + while ((curLM = getChildLM()) != null) { + // Make break positions and return blocks! + // Set up a LayoutContext + int ipd = context.getRefIPD(); + BreakPoss bp; + + LayoutContext childLC = new LayoutContext(0); + // if line layout manager then set stack limit to ipd + // line LM actually generates a LineArea which is a block + childLC.setStackLimit( + MinOptMax.subtract(context.getStackLimit(), + stackSize)); + childLC.setRefIPD(ipd); + + while (!curLM.isFinished()) { + if ((bp = curLM.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + if (stackSize.min > context.getStackLimit().max) { + // reset to last break + if (lastPos != null) { + reset(lastPos.getPosition()); + } else { + curLM.resetPosition(null); + } + break; + } + lastPos = bp; + childBreaks.add(bp); + + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + BreakPoss breakPoss = new BreakPoss( + new LeafPosition(this, childBreaks.size() - 1)); + breakPoss.setStackingSize(stackSize); + return breakPoss; + } + setFinished(true); + return null; + } + + /** + * Add the areas. + * + * @param parentIter the position iterator + * @param layoutContext the layout context for adding areas + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + getParentArea(null); + addID(); + + LayoutManager childLM; + int iStartPos = 0; + LayoutContext lc = new LayoutContext(0); + while (parentIter.hasNext()) { + LeafPosition lfp = (LeafPosition) parentIter.next(); + // Add the block areas to Area + PositionIterator breakPosIter = + new BreakPossPosIter(childBreaks, iStartPos, + lfp.getLeafPos() + 1); + iStartPos = lfp.getLeafPos() + 1; + while ((childLM = breakPosIter.getNextChildLM()) != null) { + childLM.addAreas(breakPosIter, lc); + } + } + + flush(); + + childBreaks.clear(); + curBlockArea = null; + } + + /** + * Return an Area which can contain the passed childArea. The childArea + * may not yet have any content, but it has essential traits set. + * In general, if the LayoutManager already has an Area it simply returns + * it. Otherwise, it makes a new Area of the appropriate class. + * It gets a parent area for its area by calling its parent LM. + * Finally, based on the dimensions of the parent area, it initializes + * its own area. This includes setting the content IPD and the maximum + * BPD. + * + * @param childArea the child area to locate the parent + * @return the area for this table and caption + */ + public Area getParentArea(Area childArea) { + if (curBlockArea == null) { + curBlockArea = new Block(); + // Set up dimensions + // Must get dimensions from parent area + Area parentArea = parentLM.getParentArea(curBlockArea); + int referenceIPD = parentArea.getIPD(); + curBlockArea.setIPD(referenceIPD); + // Get reference IPD from parentArea + setCurrentArea(curBlockArea); // ??? for generic operations + } + return curBlockArea; + } + + /** + * Add the child to the current area. + * + * @param childArea the area to add + * @return unused + */ + public boolean addChild(Area childArea) { + if (curBlockArea != null) { + curBlockArea.addBlock((Block) childArea); + //return super.addChild(childArea); + + return false; + } + return false; + } + + /** + * Reset the position of this layout manager. + * + * @param resetPos the position to reset to + */ + public void resetPosition(Position resetPos) { + if (resetPos == null) { + reset(null); + } + } +} + diff --git a/src/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/org/apache/fop/layoutmgr/table/TableLayoutManager.java new file mode 100644 index 000000000..9dda28697 --- /dev/null +++ b/src/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -0,0 +1,291 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.layoutmgr.table; + +import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LeafPosition; +import org.apache.fop.layoutmgr.BreakPoss; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.BreakPossPosIter; +import org.apache.fop.layoutmgr.Position; +import org.apache.fop.fo.FObj; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.MinOptMax; + +import java.util.ArrayList; +import java.util.List; + +/** + * LayoutManager for a table FO. + * A table consists of columns, table header, table footer and multiple + * table bodies. + * The header, footer and body add the areas created from the table cells. + * The table then creates areas for the columns, bodies and rows + * the render background. + */ +public class TableLayoutManager extends BlockStackingLayoutManager { + private List columns = null; + private Body tableHeader = null; + private Body tableFooter = null; + + private Block curBlockArea; + + private ArrayList bodyBreaks = new ArrayList(); + private BreakPoss headerBreak; + private BreakPoss footerBreak; + + private class SectionPosition extends LeafPosition { + protected List list; + protected SectionPosition(LayoutManager lm, int pos, List l) { + super(lm, pos); + list = l; + } + } + + /** + * Create a new table layout manager. + * + * @param fobj the table formatting object + */ + public TableLayoutManager(FObj fobj) { + super(fobj); + } + + /** + * Set the columns for this table. + * + * @param cols the list of column layout managers + */ + public void setColumns(List cols) { + columns = cols; + } + + /** + * Set the table header. + * + * @param th the table header layout manager + */ + public void setTableHeader(Body th) { + tableHeader = th; + } + + /** + * Set the table footer. + * + * @param tf the table footer layout manager + */ + public void setTableFooter(Body tf) { + tableFooter = tf; + } + + /** + * Get the next break possibility. + * The break possibility depends on the height of the header and footer + * and possible breaks inside the table body. + * + * @param context the layout context for finding breaks + * @return the next break possibility + */ + public BreakPoss getNextBreakPoss(LayoutContext context) { + Body curLM; // currently active LM + + MinOptMax stackSize = new MinOptMax(); + // if starting add space before + // stackSize.add(spaceBefore); + BreakPoss lastPos = null; + + MinOptMax headerSize = null; + if (tableHeader != null) { + headerBreak = getHeight(tableHeader, context); + headerSize = headerBreak.getStackingSize(); + } + + MinOptMax footerSize = null; + if (tableFooter != null) { + footerBreak = getHeight(tableFooter, context); + footerSize = footerBreak.getStackingSize(); + } + + while ((curLM = (Body)getChildLM()) != null) { + // Make break positions + // Set up a LayoutContext + int ipd = context.getRefIPD(); + BreakPoss bp; + + LayoutContext childLC = new LayoutContext(0); + childLC.setStackLimit( + MinOptMax.subtract(context.getStackLimit(), + stackSize)); + childLC.setRefIPD(ipd); + + curLM.setColumns(columns); + + while (!curLM.isFinished()) { + if ((bp = curLM.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + if (stackSize.min > context.getStackLimit().max) { + // reset to last break + if (lastPos != null) { + reset(lastPos.getPosition()); + } else { + curLM.resetPosition(null); + } + break; + } + lastPos = bp; + bodyBreaks.add(bp); + + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + BreakPoss breakPoss = new BreakPoss( + new LeafPosition(this, bodyBreaks.size() - 1)); + breakPoss.setStackingSize(stackSize); + return breakPoss; + } + setFinished(true); + return null; + } + + /** + * Get the break possibility and height of the table header or footer. + * + * @param lm the header or footer layout manager + * @param context the parent layout context + * @return the break possibility containing the stacking size + */ + protected BreakPoss getHeight(Body lm, LayoutContext context) { + int ipd = context.getRefIPD(); + BreakPoss bp; + + MinOptMax stackSize = new MinOptMax(); + + LayoutContext childLC = new LayoutContext(0); + childLC.setStackLimit(context.getStackLimit()); + childLC.setRefIPD(ipd); + + lm.setColumns(columns); + + ArrayList breaks = new ArrayList(); + while (!lm.isFinished()) { + if ((bp = lm.getNextBreakPoss(childLC)) != null) { + stackSize.add(bp.getStackingSize()); + breaks.add(bp); + childLC.setStackLimit(MinOptMax.subtract( + context.getStackLimit(), stackSize)); + } + } + BreakPoss breakPoss = new BreakPoss( + new SectionPosition(this, breaks.size() - 1, breaks)); + breakPoss.setStackingSize(stackSize); + return breakPoss; + + } + + /** + * The table area is a reference area that contains areas for + * columns, bodies, rows and the contents are in cells. + * + * @param parentIter the position iterator + * @param layoutContext the layout context for adding areas + */ + public void addAreas(PositionIterator parentIter, + LayoutContext layoutContext) { + getParentArea(null); + addID(); + + // add column, body then row areas + + // add table header areas + + int tableHeight = 0; + + Body childLM; + int iStartPos = 0; + LayoutContext lc = new LayoutContext(0); + while (parentIter.hasNext()) { + LeafPosition lfp = (LeafPosition) parentIter.next(); + // Add the block areas to Area + PositionIterator breakPosIter = + new BreakPossPosIter(bodyBreaks, iStartPos, + lfp.getLeafPos() + 1); + iStartPos = lfp.getLeafPos() + 1; + while ((childLM = (Body)breakPosIter.getNextChildLM()) != null) { + childLM.addAreas(breakPosIter, lc); + tableHeight += childLM.getBodyHeight(); + } + } + + // add footer areas + + curBlockArea.setHeight(tableHeight); + + flush(); + + bodyBreaks.clear(); + curBlockArea = null; + } + + /** + * Return an Area which can contain the passed childArea. The childArea + * may not yet have any content, but it has essential traits set. + * In general, if the LayoutManager already has an Area it simply returns + * it. Otherwise, it makes a new Area of the appropriate class. + * It gets a parent area for its area by calling its parent LM. + * Finally, based on the dimensions of the parent area, it initializes + * its own area. This includes setting the content IPD and the maximum + * BPD. + * + * @param childArea the child area + * @return the parent area of the child + */ + public Area getParentArea(Area childArea) { + if (curBlockArea == null) { + curBlockArea = new Block(); + // Set up dimensions + // Must get dimensions from parent area + Area parentArea = parentLM.getParentArea(curBlockArea); + int referenceIPD = parentArea.getIPD(); + curBlockArea.setIPD(referenceIPD); + // Get reference IPD from parentArea + setCurrentArea(curBlockArea); // ??? for generic operations + } + return curBlockArea; + } + + /** + * Add the child area to this layout manager. + * + * @param childArea the child area to add + * @return unused + */ + public boolean addChild(Area childArea) { + if (curBlockArea != null) { + curBlockArea.addBlock((Block) childArea); + + return false; + } + return false; + } + + /** + * Reset the position of this layout manager. + * + * @param resetPos the position to reset to + */ + public void resetPosition(Position resetPos) { + if (resetPos == null) { + reset(null); + } + } +} + |