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: AbstractLayoutManager.java 453310 2006-10-05 18:44:15Z spepping $ */
019:
020: package org.apache.fop.layoutmgr;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.apache.fop.fo.FObj;
025: import org.apache.fop.fo.FONode;
026: import org.apache.fop.area.Area;
027: import org.apache.fop.area.PageViewport;
028: import org.apache.fop.fo.Constants;
029: import org.apache.fop.fo.flow.RetrieveMarker;
030:
031: import java.util.LinkedList;
032: import java.util.List;
033: import java.util.ArrayList;
034: import java.util.ListIterator;
035: import java.util.Map;
036:
037: /**
038: * The base class for most LayoutManagers.
039: */
040: public abstract class AbstractLayoutManager extends
041: AbstractBaseLayoutManager implements Constants {
042:
043: /**
044: * logging instance
045: */
046: private static Log log = LogFactory
047: .getLog(AbstractLayoutManager.class);
048:
049: /** Parent LayoutManager for this LayoutManager */
050: protected LayoutManager parentLM = null;
051: /** List of child LayoutManagers */
052: protected List childLMs = null;
053: /** Iterator for child LayoutManagers */
054: protected ListIterator fobjIter = null;
055: /** Marker map for markers related to this LayoutManager */
056: protected Map markers = null;
057:
058: /** True if this LayoutManager has handled all of its content. */
059: private boolean bFinished = false;
060:
061: /** child LM and child LM iterator during getNextKnuthElement phase */
062: protected LayoutManager curChildLM = null;
063: /** child LM and child LM iterator during getNextKnuthElement phase */
064: protected ListIterator childLMiter = null;
065:
066: private int lastGeneratedPosition = -1;
067: private int smallestPosNumberChecked = Integer.MAX_VALUE;
068:
069: /**
070: * Abstract layout manager.
071: */
072: public AbstractLayoutManager() {
073: }
074:
075: /**
076: * Abstract layout manager.
077: *
078: * @param fo the formatting object for this layout manager
079: */
080: public AbstractLayoutManager(FObj fo) {
081: super (fo);
082: if (fo == null) {
083: throw new IllegalStateException(
084: "Null formatting object found.");
085: }
086: markers = fo.getMarkers();
087: fobjIter = fo.getChildNodes();
088: childLMiter = new LMiter(this );
089: }
090:
091: /** @see LayoutManager#setParent(LayoutManager) */
092: public void setParent(LayoutManager lm) {
093: this .parentLM = lm;
094: }
095:
096: /** @see LayoutManager#getParent */
097: public LayoutManager getParent() {
098: return this .parentLM;
099: }
100:
101: /** @see LayoutManager#initialize */
102: public void initialize() {
103: // Empty
104: }
105:
106: /**
107: * Return currently active child LayoutManager or null if
108: * all children have finished layout.
109: * Note: child must implement LayoutManager! If it doesn't, skip it
110: * and print a warning.
111: * @return the current child LayoutManager
112: */
113: protected LayoutManager getChildLM() {
114: if (curChildLM != null && !curChildLM.isFinished()) {
115: return curChildLM;
116: }
117: while (childLMiter.hasNext()) {
118: curChildLM = (LayoutManager) childLMiter.next();
119: curChildLM.initialize();
120: return curChildLM;
121: }
122: return null;
123: }
124:
125: /**
126: * Return indication if getChildLM will return another LM.
127: * @return true if another child LM is still available
128: */
129: protected boolean hasNextChildLM() {
130: return childLMiter.hasNext();
131: }
132:
133: /**
134: * Reset the layoutmanager "iterator" so that it will start
135: * with the passed Position's generating LM
136: * on the next call to getChildLM.
137: * @param pos a Position returned by a child layout manager
138: * representing a potential break decision.
139: * If pos is null, then back up to the first child LM.
140: */
141: protected void reset(org.apache.fop.layoutmgr.Position pos) {
142: //if (lm == null) return;
143: LayoutManager lm = (pos != null) ? pos.getLM() : null;
144: if (curChildLM != lm) {
145: // ASSERT curChildLM == (LayoutManager)childLMiter.previous()
146: if (childLMiter.hasPrevious()
147: && curChildLM != (LayoutManager) childLMiter
148: .previous()) {
149: //log.error("LMiter problem!");
150: }
151: while (curChildLM != lm && childLMiter.hasPrevious()) {
152: curChildLM.resetPosition(null);
153: curChildLM = (LayoutManager) childLMiter.previous();
154: }
155: // Otherwise next returns same object
156: childLMiter.next();
157: }
158: if (curChildLM != null) {
159: curChildLM.resetPosition(pos);
160: }
161: if (isFinished()) {
162: setFinished(false);
163: }
164: }
165:
166: /** @see LayoutManager#resetPosition(Position) */
167: public void resetPosition(Position resetPos) {
168: // if (resetPos == null) {
169: // reset(null);
170: // }
171: }
172:
173: /**
174: * Tell whether this LayoutManager has handled all of its content.
175: * @return True if there are no more break possibilities,
176: * ie. the last one returned represents the end of the content.
177: */
178: public boolean isFinished() {
179: return bFinished;
180: }
181:
182: /**
183: * Set the flag indicating the LayoutManager has handled all of its content.
184: * @param fin the flag value to be set
185: */
186: public void setFinished(boolean fin) {
187: bFinished = fin;
188: }
189:
190: /**
191: * @see org.apache.fop.layoutmgr.LayoutManager#addAreas(
192: * org.apache.fop.layoutmgr.PositionIterator
193: * , org.apache.fop.layoutmgr.LayoutContext)
194: */
195: public void addAreas(PositionIterator posIter, LayoutContext context) {
196: }
197:
198: /**
199: * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int)
200: */
201: public LinkedList getNextKnuthElements(LayoutContext context,
202: int alignment) {
203: log
204: .warn("null implementation of getNextKnuthElements() called!");
205: setFinished(true);
206: return null;
207: }
208:
209: /**
210: * @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(List, int)
211: */
212: public LinkedList getChangedKnuthElements(List oldList,
213: int alignment) {
214: log
215: .warn("null implementation of getChangeKnuthElement() called!");
216: return null;
217: }
218:
219: /**
220: * Return an Area which can contain the passed childArea. The childArea
221: * may not yet have any content, but it has essential traits set.
222: * In general, if the LayoutManager already has an Area it simply returns
223: * it. Otherwise, it makes a new Area of the appropriate class.
224: * It gets a parent area for its area by calling its parent LM.
225: * Finally, based on the dimensions of the parent area, it initializes
226: * its own area. This includes setting the content IPD and the maximum
227: * BPD.
228: * @param childArea the child area for which the parent area is wanted
229: * @return the parent area for the given child
230: */
231: public Area getParentArea(Area childArea) {
232: return null;
233: }
234:
235: /**
236: * Add a child area to the current area. If this causes the maximum
237: * dimension of the current area to be exceeded, the parent LM is called
238: * to add it.
239: * @param childArea the child area to be added
240: */
241: public void addChildArea(Area childArea) {
242: }
243:
244: /**
245: * Create the LM instances for the children of the
246: * formatting object being handled by this LM.
247: * @param size the requested number of child LMs
248: * @return the list with the preloaded child LMs
249: */
250: protected List createChildLMs(int size) {
251: if (fobjIter == null) {
252: return null;
253: }
254: List newLMs = new ArrayList(size);
255: while (fobjIter.hasNext() && newLMs.size() < size) {
256: Object theobj = fobjIter.next();
257: if (theobj instanceof FONode) {
258: FONode foNode = (FONode) theobj;
259: if (foNode instanceof RetrieveMarker) {
260: foNode = getPSLM().resolveRetrieveMarker(
261: (RetrieveMarker) foNode);
262: }
263: if (foNode != null) {
264: getPSLM().getLayoutManagerMaker()
265: .makeLayoutManagers(foNode, newLMs);
266: }
267: }
268: }
269: return newLMs;
270: }
271:
272: /**
273: * @see org.apache.fop.layoutmgr.PageSequenceLayoutManager#getPSLM
274: */
275: public PageSequenceLayoutManager getPSLM() {
276: return parentLM.getPSLM();
277: }
278:
279: /**
280: * @see org.apache.fop.layoutmgr.PageSequenceLayoutManager#getCurrentPage
281: */
282: public Page getCurrentPage() {
283: return getPSLM().getCurrentPage();
284: }
285:
286: /** @return the current page viewport */
287: public PageViewport getCurrentPV() {
288: return getPSLM().getCurrentPage().getPageViewport();
289: }
290:
291: /**
292: * @see org.apache.fop.layoutmgr.LayoutManager#createNextChildLMs
293: */
294: public boolean createNextChildLMs(int pos) {
295: List newLMs = createChildLMs(pos + 1 - childLMs.size());
296: addChildLMs(newLMs);
297: return pos < childLMs.size();
298: }
299:
300: /**
301: * @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs
302: */
303: public List getChildLMs() {
304: if (childLMs == null) {
305: childLMs = new java.util.ArrayList(10);
306: }
307: return childLMs;
308: }
309:
310: /**
311: * @see org.apache.fop.layoutmgr.LayoutManager#addChildLM
312: */
313: public void addChildLM(LayoutManager lm) {
314: if (lm == null) {
315: return;
316: }
317: lm.setParent(this );
318: if (childLMs == null) {
319: childLMs = new java.util.ArrayList(10);
320: }
321: childLMs.add(lm);
322: log.trace(this .getClass().getName() + ": Adding child LM "
323: + lm.getClass().getName());
324: }
325:
326: /**
327: * @see org.apache.fop.layoutmgr.LayoutManager#addChildLMs
328: */
329: public void addChildLMs(List newLMs) {
330: if (newLMs == null || newLMs.size() == 0) {
331: return;
332: }
333: ListIterator iter = newLMs.listIterator();
334: while (iter.hasNext()) {
335: LayoutManager lm = (LayoutManager) iter.next();
336: addChildLM(lm);
337: }
338: }
339:
340: /**
341: * Adds a Position to the Position participating in the first|last determination by assigning
342: * it a unique position index.
343: * @param pos the Position
344: * @return the same Position but with a position index
345: */
346: public Position notifyPos(Position pos) {
347: if (pos.getIndex() >= 0) {
348: throw new IllegalStateException(
349: "Position already got its index");
350: }
351: lastGeneratedPosition++;
352: pos.setIndex(lastGeneratedPosition);
353: return pos;
354: }
355:
356: /**
357: * Indicates whether the given Position is the first area-generating Position of this LM.
358: * @param pos the Position (must be one with a position index)
359: * @return True if it is the first Position
360: */
361: public boolean isFirst(Position pos) {
362: //log.trace("isFirst() smallestPosNumberChecked=" + smallestPosNumberChecked + " " + pos);
363: if (pos.getIndex() < 0) {
364: throw new IllegalArgumentException(
365: "Only Positions with an index can be checked");
366: }
367: if (pos.getIndex() == this .smallestPosNumberChecked) {
368: return true;
369: } else if (pos.getIndex() < this .smallestPosNumberChecked) {
370: this .smallestPosNumberChecked = pos.getIndex();
371: return true;
372: } else {
373: return false;
374: }
375: }
376:
377: /**
378: * Indicates whether the given Position is the last area-generating Position of this LM.
379: * @param pos the Position (must be one with a position index)
380: * @return True if it is the last Position
381: */
382: public boolean isLast(Position pos) {
383: //log.trace("isLast() lastGenPos=" + lastGeneratedPosition + " " + pos);
384: if (pos.getIndex() < 0) {
385: throw new IllegalArgumentException(
386: "Only Positions with an index can be checked");
387: }
388: return (pos.getIndex() == this .lastGeneratedPosition && isFinished());
389: }
390:
391: /**
392: * Transfers foreign attributes from the formatting object to the area.
393: * @param targetArea the area to set the attributes on
394: */
395: protected void transferForeignAttributes(Area targetArea) {
396: Map atts = getFObj().getForeignAttributes();
397: targetArea.setForeignAttributes(atts);
398: }
399: }
|