001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: FootnoteLayoutManager.java 538198 2007-05-15 15:11:34Z lfurini $ */
019:
020: package org.apache.fop.layoutmgr.inline;
021:
022: import java.util.LinkedList;
023: import java.util.List;
024: import java.util.ListIterator;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.apache.fop.fo.flow.Footnote;
029: import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
030: import org.apache.fop.layoutmgr.InlineKnuthSequence;
031: import org.apache.fop.layoutmgr.KnuthElement;
032: import org.apache.fop.layoutmgr.KnuthSequence;
033: import org.apache.fop.layoutmgr.LayoutContext;
034: import org.apache.fop.layoutmgr.LayoutManager;
035: import org.apache.fop.layoutmgr.ListElement;
036: import org.apache.fop.layoutmgr.NonLeafPosition;
037: import org.apache.fop.layoutmgr.PositionIterator;
038:
039: /**
040: * Layout manager for fo:footnote.
041: */
042: public class FootnoteLayoutManager extends InlineStackingLayoutManager {
043:
044: /**
045: * logging instance
046: */
047: private static Log log = LogFactory
048: .getLog(FootnoteLayoutManager.class);
049:
050: private Footnote footnote;
051: private InlineStackingLayoutManager citationLM;
052: private FootnoteBodyLayoutManager bodyLM;
053: /** Represents the footnote citation **/
054: private KnuthElement forcedAnchor;
055:
056: /**
057: * Create a new footnote layout manager.
058: * @param node footnote to create the layout manager for
059: */
060: public FootnoteLayoutManager(Footnote node) {
061: super (node);
062: footnote = node;
063: }
064:
065: /** @see org.apache.fop.layoutmgr.LayoutManager#initialize() */
066: public void initialize() {
067: // create an InlineStackingLM handling the fo:inline child of fo:footnote
068: citationLM = new InlineLayoutManager(footnote
069: .getFootnoteCitation());
070:
071: // create a FootnoteBodyLM handling the fo:footnote-body child of fo:footnote
072: bodyLM = new FootnoteBodyLayoutManager(footnote
073: .getFootnoteBody());
074: }
075:
076: /** @see org.apache.fop.layoutmgr.LayoutManager */
077: public LinkedList getNextKnuthElements(LayoutContext context,
078: int alignment) {
079: // for the moment, this LM is set as the citationLM's parent
080: // later on, when this LM will have nothing more to do, the citationLM's parent
081: // will be set to the fotnoteLM's parent
082: citationLM.setParent(this );
083: citationLM.initialize();
084: bodyLM.setParent(this );
085: bodyLM.initialize();
086:
087: // get Knuth elements representing the footnote citation
088: LinkedList returnedList = new LinkedList();
089: while (!citationLM.isFinished()) {
090: LinkedList partialList = citationLM.getNextKnuthElements(
091: context, alignment);
092: if (partialList != null) {
093: returnedList.addAll(partialList);
094: }
095: }
096: if (returnedList.size() == 0) {
097: //Inline part of the footnote is empty. Need to send back an auxiliary
098: //zero-width, zero-height inline box so the footnote gets painted.
099: KnuthSequence seq = new InlineKnuthSequence();
100: //Need to use an aux. box, otherwise, the line height can't be forced to zero height.
101: forcedAnchor = new KnuthInlineBox(0, null, null, true);
102: seq.add(forcedAnchor);
103: returnedList.add(seq);
104: }
105: setFinished(true);
106:
107: addAnchor(returnedList);
108:
109: // "wrap" the Position stored in each list inside returnedList
110: ListIterator listIterator = returnedList.listIterator();
111: ListIterator elementIterator = null;
112: KnuthSequence list = null;
113: ListElement element = null;
114: while (listIterator.hasNext()) {
115: list = (KnuthSequence) listIterator.next();
116: elementIterator = list.listIterator();
117: while (elementIterator.hasNext()) {
118: element = (KnuthElement) elementIterator.next();
119: element.setPosition(notifyPos(new NonLeafPosition(this ,
120: element.getPosition())));
121: }
122: }
123:
124: return returnedList;
125: }
126:
127: /**
128: * @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(java.util.List, int)
129: */
130: public LinkedList getChangedKnuthElements(List oldList,
131: int alignment) {
132: LinkedList returnedList = super .getChangedKnuthElements(
133: oldList, alignment);
134: addAnchor(returnedList);
135: return returnedList;
136: }
137:
138: /**
139: * @see org.apache.fop.layoutmgr.LayoutManager#addAreas(PositionIterator posIter, LayoutContext context);
140: */
141: public void addAreas(PositionIterator posIter, LayoutContext context) {
142: // "Unwrap" the NonLeafPositions stored in posIter and put
143: // them in a new list, that will be given to the citationLM
144: LinkedList positionList = new LinkedList();
145: NonLeafPosition pos = null;
146: while (posIter.hasNext()) {
147: pos = (NonLeafPosition) posIter.next();
148: if (pos != null && pos.getPosition() != null) {
149: positionList.add(pos.getPosition());
150: }
151: }
152:
153: // FootnoteLM does not create any area,
154: // so the citationLM child will add directly to the FootnoteLM parent area
155: citationLM.setParent(getParent());
156:
157: // make the citationLM add its areas
158: LayoutContext childContext = new LayoutContext(context);
159: StackingIter childPosIter = new StackingIter(positionList
160: .listIterator());
161: LayoutManager childLM;
162: while ((childLM = childPosIter.getNextChildLM()) != null) {
163: childLM.addAreas(childPosIter, childContext);
164: childContext.setLeadingSpace(childContext
165: .getTrailingSpace());
166: childContext.setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
167: true);
168: }
169: }
170:
171: /**
172: * Find the last box in the sequence, and add a reference to the FootnoteBodyLM
173: * @param citationList the list of elements representing the footnote citation
174: */
175: private void addAnchor(LinkedList citationList) {
176: KnuthInlineBox lastBox = null;
177: // the list of elements is searched backwards, until we find a box
178: ListIterator citationIterator = citationList
179: .listIterator(citationList.size());
180: while (citationIterator.hasPrevious() && lastBox == null) {
181: Object obj = citationIterator.previous();
182: if (obj instanceof KnuthElement) {
183: // obj is an element
184: KnuthElement element = (KnuthElement) obj;
185: if (element instanceof KnuthInlineBox) {
186: lastBox = (KnuthInlineBox) element;
187: }
188: } else {
189: // obj is a sequence of elements
190: KnuthSequence seq = (KnuthSequence) obj;
191: ListIterator nestedIterator = seq.listIterator(seq
192: .size());
193: while (nestedIterator.hasPrevious() && lastBox == null) {
194: KnuthElement element = (KnuthElement) nestedIterator
195: .previous();
196: if (element instanceof KnuthInlineBox
197: && !element.isAuxiliary()
198: || element == forcedAnchor) {
199: lastBox = (KnuthInlineBox) element;
200: }
201: }
202: }
203: }
204: if (lastBox != null) {
205: lastBox.setFootnoteBodyLM(bodyLM);
206: } else {
207: //throw new IllegalStateException("No anchor box was found for a footnote.");
208: }
209: }
210: }
|