| /* |
| * Copyright 1999-2005 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.layoutmgr.table; |
| |
| import org.apache.fop.fo.flow.TableCaption; |
| 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.area.Area; |
| import org.apache.fop.area.Block; |
| import org.apache.fop.traits.MinOptMax; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * LayoutManager for a table-caption FO. |
| * The table caption contains blocks that are placed beside the |
| * table. |
| */ |
| public class Caption extends BlockStackingLayoutManager { |
| private TableCaption fobj; |
| |
| private Block curBlockArea; |
| |
| private List childBreaks = new ArrayList(); |
| |
| /** |
| * Create a new Caption layout manager. |
| * |
| */ |
| public Caption(TableCaption node) { |
| super(node); |
| fobj = node; |
| } |
| |
| /** |
| * 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); |
| |
| boolean over = false; |
| |
| while (!curLM.isFinished()) { |
| if ((bp = curLM.getNextBreakPoss(childLC)) != null) { |
| if (stackSize.opt + bp.getStackingSize().opt > context.getStackLimit().max) { |
| // reset to last break |
| if (lastPos != null) { |
| LayoutManager lm = lastPos.getLayoutManager(); |
| lm.resetPosition(lastPos.getPosition()); |
| if (lm != curLM) { |
| curLM.resetPosition(null); |
| } |
| } else { |
| curLM.resetPosition(null); |
| } |
| over = true; |
| break; |
| } |
| stackSize.add(bp.getStackingSize()); |
| lastPos = bp; |
| childBreaks.add(bp); |
| |
| if (bp.nextBreakOverflows()) { |
| over = true; |
| break; |
| } |
| |
| childLC.setStackLimit(MinOptMax.subtract( |
| context.getStackLimit(), stackSize)); |
| } |
| } |
| BreakPoss breakPoss = new BreakPoss( |
| new LeafPosition(this, childBreaks.size() - 1)); |
| if (over) { |
| breakPoss.setFlag(BreakPoss.NEXT_OVERFLOWS, true); |
| } |
| 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); |
| getPSLM().addIDToPage(fobj.getId()); |
| |
| 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 |
| */ |
| public void addChildArea(Area childArea) { |
| if (curBlockArea != null) { |
| curBlockArea.addBlock((Block) childArea); |
| } |
| } |
| |
| /** |
| * Reset the layout position. |
| * |
| * @param resetPos the position to reset to |
| */ |
| public void resetPosition(Position resetPos) { |
| if (resetPos == null) { |
| reset(null); |
| } |
| } |
| } |
| |