KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > layoutmgr > FlowLayoutManager


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: FlowLayoutManager.java 453310 2006-10-05 18:44:15Z spepping $ */
19
20 package org.apache.fop.layoutmgr;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.fop.fo.pagination.Flow;
25 import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
26 import org.apache.fop.area.Area;
27 import org.apache.fop.area.BlockParent;
28
29 import java.util.LinkedList JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.ListIterator JavaDoc;
32
33 /**
34  * LayoutManager for an fo:flow object.
35  * Its parent LM is the PageSequenceLayoutManager.
36  * This LM is responsible for getting columns of the appropriate size
37  * and filling them with block-level areas generated by its children.
38  * @todo Reintroduce emergency counter (generate error to avoid endless loop)
39  */

40 public class FlowLayoutManager extends BlockStackingLayoutManager
41                                implements BlockLevelLayoutManager {
42
43     /**
44      * logging instance
45      */

46     private static Log log = LogFactory.getLog(FlowLayoutManager.class);
47     
48     /** Array of areas currently being filled stored by area class */
49     private BlockParent[] currentAreas = new BlockParent[Area.CLASS_MAX];
50
51     private int currentSpan = EN_NONE;
52     
53     /**
54      * This is the top level layout manager.
55      * It is created by the PageSequence FO.
56      * @param pslm parent PageSequenceLayoutManager object
57      * @param node Flow object
58      */

59     public FlowLayoutManager(PageSequenceLayoutManager pslm, Flow node) {
60         super(node);
61         setParent(pslm);
62     }
63
64     /** @see org.apache.fop.layoutmgr.LayoutManager */
65     public LinkedList JavaDoc getNextKnuthElements(LayoutContext context, int alignment) {
66
67         // set layout dimensions
68
int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth();
69         int flowBPD = (int) getCurrentPV().getBodyRegion().getBPD();
70
71         // currently active LM
72
BlockLevelLayoutManager curLM;
73         LinkedList JavaDoc returnedList;
74         LinkedList JavaDoc returnList = new LinkedList JavaDoc();
75
76         while ((curLM = ((BlockLevelLayoutManager) getChildLM())) != null) {
77             if (curLM instanceof InlineLevelLayoutManager) {
78                 log.error("inline area not allowed under flow - ignoring");
79                 curLM.setFinished(true);
80                 continue;
81             }
82
83             int span = EN_NONE;
84             if (curLM instanceof BlockLayoutManager) {
85                 span = ((BlockLayoutManager)curLM).getBlockFO().getSpan();
86             } else if (curLM instanceof BlockContainerLayoutManager) {
87                 span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan();
88             }
89             if (currentSpan != span) {
90                 log.debug("span change from " + currentSpan + " to " + span);
91                 context.signalSpanChange(span);
92                 currentSpan = span;
93                 SpaceResolver.resolveElementList(returnList);
94                 return returnList;
95             }
96             
97             // Set up a LayoutContext
98
//MinOptMax bpd = context.getStackLimit();
99

100             LayoutContext childLC = new LayoutContext(0);
101             childLC.setStackLimit(context.getStackLimit());
102             childLC.setRefIPD(context.getRefIPD());
103             childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());
104             
105             // get elements from curLM
106
returnedList = curLM.getNextKnuthElements(childLC, alignment);
107             //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
108
if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
109                 context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
110                 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
111             }
112
113             // "wrap" the Position inside each element
114
LinkedList JavaDoc tempList = returnedList;
115             returnedList = new LinkedList JavaDoc();
116             wrapPositionElements(tempList, returnedList);
117
118             if (returnedList.size() == 1
119                 && ElementListUtils.endsWithForcedBreak(returnedList)) {
120                 // a descendant of this flow has break-before
121
returnList.addAll(returnedList);
122                 SpaceResolver.resolveElementList(returnList);
123                 return returnList;
124             } else {
125                 if (returnList.size() > 0) {
126                     // there is a block before this one
127
if (context.isKeepWithNextPending()
128                             || childLC.isKeepWithPreviousPending()) {
129                         //Clear pending keep flag
130
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
131                         childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
132                         // add an infinite penalty to forbid a break between blocks
133
returnList.add(new BreakElement(
134                                 new Position(this), KnuthElement.INFINITE, context));
135                     } else if (!((ListElement) returnList.getLast()).isGlue()) {
136                         // add a null penalty to allow a break between blocks
137
returnList.add(new BreakElement(
138                                 new Position(this), 0, context));
139                     }
140                 }
141                 if (returnedList.size() > 0) {
142                     returnList.addAll(returnedList);
143                     if (ElementListUtils.endsWithForcedBreak(returnList)) {
144                         // a descendant of this flow has break-after
145
SpaceResolver.resolveElementList(returnList);
146                         return returnList;
147                     }
148                 }
149             }
150             if (childLC.isKeepWithNextPending()) {
151                 //Clear and propagate
152
childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
153                 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
154             }
155         }
156
157         SpaceResolver.resolveElementList(returnList);
158         setFinished(true);
159
160         if (returnList.size() > 0) {
161             return returnList;
162         } else {
163             return null;
164         }
165     }
166
167     /**
168      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager
169      */

170     public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
171         log.debug(" FLM.negotiateBPDAdjustment> " + adj);
172
173         if (lastElement.getPosition() instanceof NonLeafPosition) {
174             // this element was not created by this FlowLM
175
NonLeafPosition savedPos = (NonLeafPosition)lastElement.getPosition();
176             lastElement.setPosition(savedPos.getPosition());
177             int returnValue = ((BlockLevelLayoutManager)lastElement.getLayoutManager())
178                     .negotiateBPDAdjustment(adj, lastElement);
179             lastElement.setPosition(savedPos);
180             log.debug(" FLM.negotiateBPDAdjustment> result " + returnValue);
181             return returnValue;
182         } else {
183             return 0;
184         }
185     }
186
187     /**
188      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager
189      */

190     public void discardSpace(KnuthGlue spaceGlue) {
191         log.debug(" FLM.discardSpace> ");
192
193         if (spaceGlue.getPosition() instanceof NonLeafPosition) {
194             // this element was not created by this FlowLM
195
NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition();
196             spaceGlue.setPosition(savedPos.getPosition());
197             ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
198             spaceGlue.setPosition(savedPos);
199         }
200     }
201
202     /** @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether() */
203     public boolean mustKeepTogether() {
204         return false;
205     }
206
207     /** @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious() */
208     public boolean mustKeepWithPrevious() {
209         return false;
210     }
211
212     /** @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext() */
213     public boolean mustKeepWithNext() {
214         return false;
215     }
216
217     /**
218      * @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(java.util.List, int)
219      */

220     public LinkedList JavaDoc getChangedKnuthElements(List JavaDoc oldList, /*int flaggedPenalty,*/ int alignment) {
221         ListIterator JavaDoc oldListIterator = oldList.listIterator();
222         KnuthElement returnedElement;
223         LinkedList JavaDoc returnedList = new LinkedList JavaDoc();
224         LinkedList JavaDoc returnList = new LinkedList JavaDoc();
225         KnuthElement prevElement = null;
226         KnuthElement currElement = null;
227         int fromIndex = 0;
228
229         // "unwrap" the Positions stored in the elements
230
KnuthElement oldElement;
231         while (oldListIterator.hasNext()) {
232             oldElement = (KnuthElement)oldListIterator.next();
233             if (oldElement.getPosition() instanceof NonLeafPosition) {
234                 // oldElement was created by a descendant of this FlowLM
235
oldElement.setPosition(((NonLeafPosition)oldElement.getPosition()).getPosition());
236             } else {
237                 // thisElement was created by this FlowLM, remove it
238
oldListIterator.remove();
239             }
240         }
241         // reset the iterator
242
oldListIterator = oldList.listIterator();
243
244
245         while (oldListIterator.hasNext()) {
246             currElement = (KnuthElement) oldListIterator.next();
247             if (prevElement != null
248                 && prevElement.getLayoutManager() != currElement.getLayoutManager()) {
249                 // prevElement is the last element generated by the same LM
250
BlockLevelLayoutManager prevLM = (BlockLevelLayoutManager)
251                                                  prevElement.getLayoutManager();
252                 BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
253                                                  currElement.getLayoutManager();
254                 returnedList.addAll(prevLM.getChangedKnuthElements(
255                         oldList.subList(fromIndex, oldListIterator.previousIndex()), alignment));
256                 fromIndex = oldListIterator.previousIndex();
257
258                 // there is another block after this one
259
if (prevLM.mustKeepWithNext()
260                     || currLM.mustKeepWithPrevious()) {
261                     // add an infinite penalty to forbid a break between blocks
262
returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
263                             new Position(this), false));
264                 } else if (!((KnuthElement) returnedList.getLast()).isGlue()) {
265                     // add a null penalty to allow a break between blocks
266
returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
267                 }
268             }
269             prevElement = currElement;
270         }
271         if (currElement != null) {
272             BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
273                                              currElement.getLayoutManager();
274             returnedList.addAll(currLM.getChangedKnuthElements(
275                     oldList.subList(fromIndex, oldList.size()), alignment));
276         }
277
278         // "wrap" the Position stored in each element of returnedList
279
// and add elements to returnList
280
ListIterator JavaDoc listIter = returnedList.listIterator();
281         while (listIter.hasNext()) {
282             returnedElement = (KnuthElement)listIter.next();
283             if (returnedElement.getLayoutManager() != this) {
284                 returnedElement.setPosition(
285                         new NonLeafPosition(this, returnedElement.getPosition()));
286             }
287             returnList.add(returnedElement);
288         }
289
290         return returnList;
291     }
292
293     /**
294      * @see org.apache.fop.layoutmgr.LayoutManager#addAreas(PositionIterator, LayoutContext)
295      */

296     public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
297         AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
298         flush();
299     }
300
301     /**
302      * Add child area to a the correct container, depending on its
303      * area class. A Flow can fill at most one area container of any class
304      * at any one time. The actual work is done by BlockStackingLM.
305      * @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
306      */

307     public void addChildArea(Area childArea) {
308         getParentArea(childArea);
309         addChildToArea(childArea,
310                           this.currentAreas[childArea.getAreaClass()]);
311     }
312
313     /**
314      * @see org.apache.fop.layoutmgr.LayoutManager#getParentArea(Area)
315      */

316     public Area getParentArea(Area childArea) {
317         BlockParent parentArea = null;
318         int aclass = childArea.getAreaClass();
319         
320         if (aclass == Area.CLASS_NORMAL) {
321             parentArea = getCurrentPV().getCurrentFlow();
322         } else if (aclass == Area.CLASS_BEFORE_FLOAT) {
323             parentArea = getCurrentPV().getBodyRegion().getBeforeFloat();
324         } else if (aclass == Area.CLASS_FOOTNOTE) {
325             parentArea = getCurrentPV().getBodyRegion().getFootnote();
326         } else {
327             throw new IllegalStateException JavaDoc("(internal error) Invalid "
328                     + "area class (" + aclass + ") requested.");
329         }
330         
331         this.currentAreas[aclass] = parentArea;
332         setCurrentArea(parentArea);
333         return parentArea;
334     }
335
336     /**
337      * @see org.apache.fop.layoutmgr.LayoutManager#resetPosition(Position)
338      */

339     public void resetPosition(Position resetPos) {
340         if (resetPos == null) {
341             reset(null);
342         }
343     }
344     /**
345      * Returns the IPD of the content area
346      * @return the IPD of the content area
347      */

348     public int getContentAreaIPD() {
349         return getCurrentPV().getCurrentSpan().getColumnWidth();
350     }
351    
352     /**
353      * Returns the BPD of the content area
354      * @return the BPD of the content area
355      */

356     public int getContentAreaBPD() {
357         return (int) getCurrentPV().getBodyRegion().getBPD();
358     }
359     
360 }
361
362
Popular Tags