blob: a0af4fd4475371dbd4c6844cdcb2fdbf2cea9c60 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.list;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpacedBorderedPaddedBlockLayoutManager;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
/**
* LayoutManager for a list-block FO.
* A list block contains list items which are stacked within
* the list block area..
*/
public class ListBlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManager {
/** logging instance */
private static Log log = LogFactory.getLog(ListBlockLayoutManager.class);
private Block curBlockArea;
/**
* Create a new list block layout manager.
* @param node list-block to create the layout manager for
*/
public ListBlockLayoutManager(ListBlock node) {
super(node);
}
@Override
protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
return getListBlockFO().getCommonBorderPaddingBackground();
}
/**
* Convenience method.
* @return the ListBlock node
*/
protected ListBlock getListBlockFO() {
return (ListBlock)fobj;
}
/** {@inheritDoc} */
@Override
public void initialize() {
foSpaceBefore = new SpaceVal(
getListBlockFO().getCommonMarginBlock().spaceBefore, this).getSpace();
foSpaceAfter = new SpaceVal(
getListBlockFO().getCommonMarginBlock().spaceAfter, this).getSpace();
startIndent = getListBlockFO().getCommonMarginBlock().startIndent.getValue(this);
endIndent = getListBlockFO().getCommonMarginBlock().endIndent.getValue(this);
}
private void resetSpaces() {
this.discardBorderBefore = false;
this.discardBorderAfter = false;
this.discardPaddingBefore = false;
this.discardPaddingAfter = false;
this.effSpaceBefore = null;
this.effSpaceAfter = null;
}
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
Position restartPosition, LayoutManager restartAtLM) {
resetSpaces();
List returnList;
returnList = super.getNextKnuthElements(context, alignment, lmStack, restartPosition, restartAtLM);
//fox:widow-content-limit
int widowRowLimit = getListBlockFO().getWidowContentLimit().getValue();
if (widowRowLimit != 0) {
ElementListUtils.removeLegalBreaks(returnList, widowRowLimit);
}
//fox:orphan-content-limit
int orphanRowLimit = getListBlockFO().getOrphanContentLimit().getValue();
if (orphanRowLimit != 0) {
ElementListUtils.removeLegalBreaksFromEnd(returnList, orphanRowLimit);
}
return returnList;
}
/**
* A list block generates one or more normal block areas whose child areas are
* normal block areas returned by the children of fo:list-block. See XSL-FO 1.1 6.8.2.
*
* @param parentIter the position iterator
* @param layoutContext the layout context for adding areas
*/
@Override
public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
getParentArea(null);
// if this will create the first block area in a page
// and display-align is after or center, add space before
if (layoutContext.getSpaceBefore() > 0) {
addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
}
addId();
// the list block contains areas stacked from each list item
LayoutManager childLM;
LayoutContext lc = LayoutContext.offspringOf(layoutContext);
LayoutManager firstLM = null;
LayoutManager lastLM = null;
Position firstPos = null;
Position lastPos = null;
// "unwrap" the NonLeafPositions stored in parentIter
// and put them in a new list;
LinkedList<Position> positionList = new LinkedList<Position>();
Position pos;
while (parentIter.hasNext()) {
pos = parentIter.next();
if (pos.getIndex() >= 0) {
if (firstPos == null) {
firstPos = pos;
}
lastPos = pos;
}
if (pos instanceof NonLeafPosition
&& (pos.getPosition() != null)
&& pos.getPosition().getLM() != this) {
// pos was created by a child of this ListBlockLM
positionList.add(pos.getPosition());
lastLM = pos.getPosition().getLM();
if (firstLM == null) {
firstLM = lastLM;
}
}
}
registerMarkers(true, isFirst(firstPos), isLast(lastPos));
PositionIterator childPosIter = new PositionIterator(positionList.listIterator());
while ((childLM = childPosIter.getNextChildLM()) != null) {
// Add the block areas to Area
// set the space adjustment ratio
lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
lc.setStackLimitBP(layoutContext.getStackLimitBP());
childLM.addAreas(childPosIter, lc);
}
registerMarkers(false, isFirst(firstPos), isLast(lastPos));
// We are done with this area add the background
TraitSetter.addBackground(curBlockArea,
getListBlockFO().getCommonBorderPaddingBackground(),
this);
TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter);
flush();
curBlockArea = null;
resetSpaces();
checkEndOfLayout(lastPos);
}
/**
* 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
*/
@Override
public Area getParentArea(Area childArea) {
if (curBlockArea == null) {
curBlockArea = new Block();
// Set up dimensions
// Must get dimensions from parent area
/*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
// set traits
TraitSetter.setProducerID(curBlockArea, getListBlockFO().getId());
TraitSetter.addBorders(curBlockArea,
getListBlockFO().getCommonBorderPaddingBackground(),
discardBorderBefore, discardBorderAfter, false, false, this);
TraitSetter.addPadding(curBlockArea,
getListBlockFO().getCommonBorderPaddingBackground(),
discardPaddingBefore, discardPaddingAfter, false, false, this);
TraitSetter.addMargins(curBlockArea,
getListBlockFO().getCommonBorderPaddingBackground(),
getListBlockFO().getCommonMarginBlock(),
this);
TraitSetter.addBreaks(curBlockArea,
getListBlockFO().getBreakBefore(),
getListBlockFO().getBreakAfter());
int contentIPD = referenceIPD - getIPIndents();
curBlockArea.setIPD(contentIPD);
curBlockArea.setBidiLevel(getListBlockFO().getBidiLevel());
setCurrentArea(curBlockArea);
}
return curBlockArea;
}
/**
* Add the child area to this layout manager.
*
* @param childArea the child area to add
*/
@Override
public void addChildArea(Area childArea) {
if (curBlockArea != null) {
curBlockArea.addBlock((Block) childArea);
}
}
/** {@inheritDoc} */
@Override
public KeepProperty getKeepTogetherProperty() {
return getListBlockFO().getKeepTogether();
}
/** {@inheritDoc} */
@Override
public KeepProperty getKeepWithPreviousProperty() {
return getListBlockFO().getKeepWithPrevious();
}
/** {@inheritDoc} */
@Override
public KeepProperty getKeepWithNextProperty() {
return getListBlockFO().getKeepWithNext();
}
}