/* * 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; import org.apache.fop.fo.FObj; import org.apache.fop.fo.FONode; import org.apache.fop.area.Area; import org.apache.fop.area.PageViewport; import org.apache.fop.fo.Constants; import org.apache.fop.fo.flow.RetrieveMarker; import java.util.LinkedList; import java.util.List; import java.util.ArrayList; import java.util.ListIterator; import java.util.Map; /** * The base class for most LayoutManagers. */ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager implements Constants { protected LayoutManager parentLM = null; protected List childLMs = null; protected ListIterator fobjIter = null; protected Map markers = null; /** True if this LayoutManager has handled all of its content. */ private boolean bFinished = false; /** child LM and child LM iterator during getNextBreakPoss phase */ protected LayoutManager curChildLM = null; protected ListIterator childLMiter = null; /** * Abstract layout manager. */ public AbstractLayoutManager() { } /** * Abstract layout manager. * * @param fo the formatting object for this layout manager */ public AbstractLayoutManager(FObj fo) { super(fo); if (fo == null) { throw new IllegalStateException("Null formatting object found."); } markers = fo.getMarkers(); fobjIter = fo.getChildNodes(); childLMiter = new LMiter(this); } public void setParent(LayoutManager lm) { this.parentLM = lm; } public LayoutManager getParent() { return this.parentLM; } public void initialize() { // Empty } /** * Return currently active child LayoutManager or null if * all children have finished layout. * Note: child must implement LayoutManager! If it doesn't, skip it * and print a warning. */ protected LayoutManager getChildLM() { if (curChildLM != null && !curChildLM.isFinished()) { return curChildLM; } while (childLMiter.hasNext()) { curChildLM = (LayoutManager) childLMiter.next(); curChildLM.initialize(); return curChildLM; } return null; } /** * Reset the layoutmanager "iterator" so that it will start * with the passed Position's generating LM * on the next call to getChildLM. * @param pos a Position returned by a child layout manager * representing a potential break decision. * If pos is null, then back up to the first child LM. */ protected void reset(org.apache.fop.layoutmgr.Position pos) { //if (lm == null) return; LayoutManager lm = (pos != null) ? pos.getLM() : null; if (curChildLM != lm) { // ASSERT curChildLM == (LayoutManager)childLMiter.previous() if (childLMiter.hasPrevious() && curChildLM != (LayoutManager) childLMiter.previous()) { //log.error("LMiter problem!"); } while (curChildLM != lm && childLMiter.hasPrevious()) { curChildLM.resetPosition(null); curChildLM = (LayoutManager) childLMiter.previous(); } // Otherwise next returns same object childLMiter.next(); } if (curChildLM != null) { curChildLM.resetPosition(pos); } if (isFinished()) { setFinished(false); } } public void resetPosition(Position resetPos) { // if (resetPos == null) { // reset(null); // } } /** * Tell whether this LayoutManager has handled all of its content. * @return True if there are no more break possibilities, * ie. the last one returned represents the end of the content. */ public boolean isFinished() { return bFinished; } public void setFinished(boolean fin) { bFinished = fin; } /** * @see org.apache.fop.layoutmgr.LayoutManager#addAreas(org.apache.fop.layoutmgr.PositionIterator, org.apache.fop.layoutmgr.LayoutContext) */ public void addAreas(PositionIterator posIter, LayoutContext context) { } /** * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int) */ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) { log.warn("null implementation of getNextKnuthElements() called!"); setFinished(true); return null; } public LinkedList getChangedKnuthElements(List oldList, /*int flaggedPenalty,*/ int alignment) { log.warn("null implementation of getChangeKnuthElement() called!"); return 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. */ public Area getParentArea(Area childArea) { return null; } /** * Add a child area to the current area. If this causes the maximum * dimension of the current area to be exceeded, the parent LM is called * to add it. */ public void addChildArea(Area childArea) { } /** * Create the LM instances for the children of the * formatting object being handled by this LM. * @param size the requested number of child LMs * @return the list with the preloaded child LMs */ protected List createChildLMs(int size) { if (fobjIter == null) { return null; } List newLMs = new ArrayList(size); while (fobjIter.hasNext() && newLMs.size() < size ) { Object theobj = fobjIter.next(); if (theobj instanceof FONode) { FONode foNode = (FONode) theobj; if (foNode instanceof RetrieveMarker) { foNode = getPSLM().resolveRetrieveMarker( (RetrieveMarker) foNode); } if (foNode != null) { getPSLM().getLayoutManagerMaker(). makeLayoutManagers(foNode, newLMs); } } } return newLMs; } /** * @see org.apache.fop.layoutmgr.PageSequenceLayoutManager#getPSLM */ public PageSequenceLayoutManager getPSLM() { return parentLM.getPSLM(); } /** * @see org.apache.fop.layoutmgr.PageSequenceLayoutManager#getCurrentPV */ public PageViewport getCurrentPV() { return getPSLM().getCurrentPV(); } /** * @see org.apache.fop.layoutmgr.LayoutManager#createNextChildLMs */ public boolean createNextChildLMs(int pos) { List newLMs = createChildLMs(pos + 1 - childLMs.size()); addChildLMs(newLMs); return pos < childLMs.size(); } /** * @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs */ public List getChildLMs() { if (childLMs == null) { childLMs = new java.util.ArrayList(10); } return childLMs; } /** * @see org.apache.fop.layoutmgr.LayoutManager#addChildLM */ public void addChildLM(LayoutManager lm) { if (lm == null) { return; } lm.setParent(this); if (childLMs == null) { childLMs = new java.util.ArrayList(10); } childLMs.add(lm); log.trace(this.getClass().getName() + ": Adding child LM " + lm.getClass().getName()); } /** * @see org.apache.fop.layoutmgr.LayoutManager#addChildLMs */ public void addChildLMs(List newLMs) { if (newLMs == null || newLMs.size() == 0) { return; } ListIterator iter = newLMs.listIterator(); while (iter.hasNext()) { LayoutManager lm = (LayoutManager) iter.next(); addChildLM(lm); } } }