blob: cb33e9b0cdd7895d0dca6e275e1e38915a733b8b [file] [log] [blame]
/*
* 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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 implements LayoutManager, 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;
/**
* logging instance
*/
protected static Log log = LogFactory.getLog(LayoutManager.class);
/**
* Abstract layout manager.
*/
public AbstractLayoutManager() {
}
/**
* Abstract layout manager.
*
* @param fo the formatting object for this layout manager
*/
public AbstractLayoutManager(FObj 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;
}
/**
* 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();
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) {
}
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);
}
}
}