KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > layoutmgr > inline > InlineStackingLayoutManager


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: InlineStackingLayoutManager.java 426576 2006-07-28 15:44:37Z jeremias $ */
19
20 package org.apache.fop.layoutmgr.inline;
21
22 import java.util.LinkedList JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.ListIterator JavaDoc;
26 import java.util.HashMap JavaDoc;
27
28 import org.apache.fop.fo.FObj;
29 import org.apache.fop.fo.properties.SpaceProperty;
30 import org.apache.fop.layoutmgr.AbstractLayoutManager;
31 import org.apache.fop.layoutmgr.KnuthElement;
32 import org.apache.fop.layoutmgr.LayoutContext;
33 import org.apache.fop.layoutmgr.LayoutManager;
34 import org.apache.fop.layoutmgr.NonLeafPosition;
35 import org.apache.fop.layoutmgr.Position;
36 import org.apache.fop.layoutmgr.PositionIterator;
37 import org.apache.fop.area.Area;
38 import org.apache.fop.area.inline.Space;
39 import org.apache.fop.traits.MinOptMax;
40
41 /**
42  * Class modelling the commonalities of layoutmanagers for objects
43  * which stack children in the inline direction, such as Inline or
44  * Line. It should not be instantiated directly.
45  */

46 public class InlineStackingLayoutManager extends AbstractLayoutManager
47                                          implements InlineLevelLayoutManager {
48
49
50     protected static class StackingIter extends PositionIterator {
51
52         StackingIter(Iterator JavaDoc parentIter) {
53             super(parentIter);
54         }
55
56         protected LayoutManager getLM(Object JavaDoc nextObj) {
57             return ((Position) nextObj).getLM();
58         }
59
60         protected Position getPos(Object JavaDoc nextObj) {
61             return ((Position) nextObj);
62         }
63     }
64
65
66     /**
67      * Size of any start or end borders and padding.
68      */

69     private MinOptMax allocIPD = new MinOptMax(0);
70
71     /**
72      * Size of border and padding in BPD (ie, before and after).
73      */

74     protected MinOptMax extraBPD;
75
76     private Area currentArea; // LineArea or InlineParent
77

78     //private BreakPoss prevBP;
79

80     /** The child layout context */
81     protected LayoutContext childLC;
82
83     private boolean bAreaCreated = false;
84
85     //private LayoutManager currentLM = null;
86

87     /** Used to store previous content IPD for each child LM. */
88     private HashMap JavaDoc hmPrevIPD = new HashMap JavaDoc();
89
90     /**
91      * Create an inline stacking layout manager.
92      * This is used for fo's that create areas that
93      * contain inline areas.
94      *
95      * @param node the formatting object that creates the area
96      */

97     protected InlineStackingLayoutManager(FObj node) {
98         super(node);
99         extraBPD = new MinOptMax(0);
100     }
101
102     /**
103      * Set the iterator.
104      *
105      * @param iter the iterator for this LM
106      */

107     public void setLMiter(ListIterator JavaDoc iter) {
108         childLMiter = iter;
109     }
110
111     /**
112      * Returns the extra IPD needed for any leading or trailing fences for the
113      * current area.
114      * @param bNotFirst true if not the first area for this layout manager
115      * @param bNotLast true if not the last area for this layout manager
116      * @return the extra IPD as a MinOptMax spec
117      */

118     protected MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
119         return new MinOptMax(0);
120     }
121
122
123     /**
124      * Indication if the current area has a leading fence.
125      * @param bNotFirst true if not the first area for this layout manager
126      * @return the leading fence flag
127      */

128     protected boolean hasLeadingFence(boolean bNotFirst) {
129         return false;
130     }
131
132     /**
133      * Indication if the current area has a trailing fence.
134      * @param bNotLast true if not the last area for this layout manager
135      * @return the trailing fence flag
136      */

137     protected boolean hasTrailingFence(boolean bNotLast) {
138         return false;
139     }
140
141     /**
142      * Get the space at the start of the inline area.
143      * @return the space property describing the space
144      */

145     protected SpaceProperty getSpaceStart() {
146         return null;
147     }
148     
149     /**
150      * Get the space at the end of the inline area.
151      * @return the space property describing the space
152      */

153     protected SpaceProperty getSpaceEnd() {
154         return null;
155     }
156
157     /**
158      * Reset position for returning next BreakPossibility.
159      * @param prevPos a Position returned by this layout manager
160      * representing a potential break decision.
161      */

162     public void resetPosition(Position prevPos) {
163         if (prevPos != null) {
164             // ASSERT (prevPos.getLM() == this)
165
if (prevPos.getLM() != this) {
166                 //getLogger().error(
167
// "InlineStackingLayoutManager.resetPosition: " +
168
// "LM mismatch!!!");
169
}
170             // Back up the child LM Position
171
Position childPos = prevPos.getPosition();
172             reset(childPos);
173             /*
174             if (prevBP != null
175                     && prevBP.getLayoutManager() != childPos.getLM()) {
176                 childLC = null;
177             }
178             prevBP = new BreakPoss(childPos);
179             */

180         } else {
181             // Backup to start of first child layout manager
182
//prevBP = null;
183
// super.resetPosition(prevPos);
184
reset(prevPos);
185             // If any areas created, we are restarting!
186
bAreaCreated = false;
187         }
188         // Do we need to reset some context like pending or prevContent?
189
// What about prevBP?
190
}
191
192     /**
193      * TODO: Explain this method
194      * @param lm ???
195      * @return ???
196      */

197     protected MinOptMax getPrevIPD(LayoutManager lm) {
198         return (MinOptMax) hmPrevIPD.get(lm);
199     }
200
201     /**
202      * Clear the previous IPD calculation.
203      */

204     protected void clearPrevIPD() {
205         hmPrevIPD.clear();
206     }
207
208     /**
209      * This method is called by addAreas() so IDs can be added to a page for FOs that
210      * support the 'id' property.
211      */

212     protected void addId() {
213         // Do nothing here, overriden in subclasses that have an 'id' property.
214
}
215     
216     /**
217      * Returns the current area.
218      * @return the current area
219      */

220     protected Area getCurrentArea() {
221         return currentArea;
222     }
223
224     /**
225      * Set the current area.
226      * @param area the current area
227      */

228     protected void setCurrentArea(Area area) {
229         currentArea = area;
230     }
231
232     /**
233      * Trait setter to be overridden by subclasses.
234      * @param bNotFirst true if this is not the first child area added
235      * @param bNotLast true if this is not the last child area added
236      */

237     protected void setTraits(boolean bNotFirst, boolean bNotLast) {
238     }
239
240     /**
241      * Set the current child layout context
242      * @param lc the child layout context
243      */

244     protected void setChildContext(LayoutContext lc) {
245         childLC = lc;
246     }
247
248     /**
249      * Current child layout context
250      * @return the current child layout context
251      */

252     protected LayoutContext getContext() {
253         return childLC;
254     }
255
256     /**
257      * Adds a space to the area
258      * @param parentArea the area to which to add the space
259      * @param spaceRange the space range specifier
260      * @param dSpaceAdjust the factor by which to stretch or shrink the space
261      */

262     protected void addSpace(Area parentArea, MinOptMax spaceRange,
263                             double dSpaceAdjust) {
264         if (spaceRange != null) {
265             int iAdjust = spaceRange.opt;
266             if (dSpaceAdjust > 0.0) {
267                 // Stretch by factor
268
iAdjust += (int) ((double) (spaceRange.max
269                                           - spaceRange.opt) * dSpaceAdjust);
270             } else if (dSpaceAdjust < 0.0) {
271                 // Shrink by factor
272
iAdjust += (int) ((double) (spaceRange.opt
273                                           - spaceRange.min) * dSpaceAdjust);
274             }
275             if (iAdjust != 0) {
276                 //getLogger().debug("Add leading space: " + iAdjust);
277
Space ls = new Space();
278                 ls.setIPD(iAdjust);
279                 parentArea.addChildArea(ls);
280             }
281         }
282     }
283
284     /** @see InlineLevelLayoutManager#addALetterSpaceTo(List) */
285     public List JavaDoc addALetterSpaceTo(List JavaDoc oldList) {
286         // old list contains only a box, or the sequence: box penalty glue box
287

288         ListIterator JavaDoc oldListIterator = oldList.listIterator();
289         KnuthElement element = null;
290         // "unwrap" the Position stored in each element of oldList
291
while (oldListIterator.hasNext()) {
292             element = (KnuthElement) oldListIterator.next();
293             element.setPosition(((NonLeafPosition)element.getPosition()).getPosition());
294         }
295
296         // The last element may not have a layout manager (its position == null);
297
// this may happen if it is a padding box; see bug 39571.
298
InlineLevelLayoutManager LM =
299             (InlineLevelLayoutManager) element.getLayoutManager();
300         if (LM != null) {
301             oldList = LM.addALetterSpaceTo(oldList);
302         }
303         // "wrap" again the Position stored in each element of oldList
304
oldListIterator = oldList.listIterator();
305         while (oldListIterator.hasNext()) {
306             element = (KnuthElement) oldListIterator.next();
307             element.setPosition(notifyPos(new NonLeafPosition(this, element.getPosition())));
308         }
309
310         return oldList;
311     }
312
313     /**
314      * remove the AreaInfo object represented by the given elements,
315      * so that it won't generate any element when getChangedKnuthElements
316      * will be called
317      *
318      * @param oldList the elements representing the word space
319      */

320     public void removeWordSpace(List JavaDoc oldList) {
321         ListIterator JavaDoc oldListIterator = oldList.listIterator();
322         KnuthElement element = null;
323         // "unwrap" the Position stored in each element of oldList
324
while (oldListIterator.hasNext()) {
325             element = (KnuthElement) oldListIterator.next();
326             element.setPosition(((NonLeafPosition)element.getPosition()).getPosition());
327         }
328
329         ((InlineLevelLayoutManager)
330                    element.getLayoutManager()).removeWordSpace(oldList);
331
332     }
333
334     /** @see InlineLevelLayoutManager#getWordChars(StringBuffer, Position) */
335     public void getWordChars(StringBuffer JavaDoc sbChars, Position pos) {
336         Position newPos = ((NonLeafPosition) pos).getPosition();
337         ((InlineLevelLayoutManager)
338          newPos.getLM()).getWordChars(sbChars, newPos);
339     }
340
341     /** @see InlineLevelLayoutManager#hyphenate(Position, HyphContext) */
342     public void hyphenate(Position pos, HyphContext hc) {
343         Position newPos = ((NonLeafPosition) pos).getPosition();
344         ((InlineLevelLayoutManager)
345          newPos.getLM()).hyphenate(newPos, hc);
346     }
347
348     /** @see InlineLevelLayoutManager#applyChanges(List) */
349     public boolean applyChanges(List JavaDoc oldList) {
350         // "unwrap" the Positions stored in the elements
351
ListIterator JavaDoc oldListIterator = oldList.listIterator();
352         KnuthElement oldElement;
353         while (oldListIterator.hasNext()) {
354             oldElement = (KnuthElement) oldListIterator.next();
355             oldElement.setPosition
356                 (((NonLeafPosition) oldElement.getPosition()).getPosition());
357         }
358         // reset the iterator
359
oldListIterator = oldList.listIterator();
360
361         InlineLevelLayoutManager prevLM = null;
362         InlineLevelLayoutManager currLM;
363         int fromIndex = 0;
364
365         boolean bSomethingChanged = false;
366         while (oldListIterator.hasNext()) {
367             oldElement = (KnuthElement) oldListIterator.next();
368             currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
369             // initialize prevLM
370
if (prevLM == null) {
371                 prevLM = currLM;
372             }
373
374             if (currLM != prevLM || !oldListIterator.hasNext()) {
375                 if (prevLM == this || currLM == this) {
376                     prevLM = currLM;
377                 } else if (oldListIterator.hasNext()) {
378                     bSomethingChanged
379                         = prevLM.applyChanges(oldList.subList(fromIndex
380                                                               , oldListIterator.previousIndex()))
381                         || bSomethingChanged;
382                     prevLM = currLM;
383                     fromIndex = oldListIterator.previousIndex();
384                 } else if (currLM == prevLM) {
385                     bSomethingChanged
386                         = prevLM.applyChanges(oldList.subList(fromIndex, oldList.size()))
387                             || bSomethingChanged;
388                 } else {
389                     bSomethingChanged
390                         = prevLM.applyChanges(oldList.subList(fromIndex
391                                                               , oldListIterator.previousIndex()))
392                             || bSomethingChanged;
393                     if (currLM != null) {
394                         bSomethingChanged
395                             = currLM.applyChanges(oldList.subList(oldListIterator.previousIndex()
396                                                                   , oldList.size()))
397                             || bSomethingChanged;
398                     }
399                 }
400             }
401         }
402
403         // "wrap" again the Positions stored in the elements
404
oldListIterator = oldList.listIterator();
405         while (oldListIterator.hasNext()) {
406             oldElement = (KnuthElement) oldListIterator.next();
407             oldElement.setPosition
408                 (notifyPos(new NonLeafPosition(this, oldElement.getPosition())));
409         }
410         return bSomethingChanged;
411     }
412
413     /**
414      * @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(List, int)
415      */

416     public LinkedList JavaDoc getChangedKnuthElements(List JavaDoc oldList, int alignment) {
417         // "unwrap" the Positions stored in the elements
418
ListIterator JavaDoc oldListIterator = oldList.listIterator();
419         KnuthElement oldElement;
420         while (oldListIterator.hasNext()) {
421             oldElement = (KnuthElement) oldListIterator.next();
422             oldElement.setPosition
423                 (((NonLeafPosition) oldElement.getPosition()).getPosition());
424         }
425         // reset the iterator
426
oldListIterator = oldList.listIterator();
427
428         KnuthElement returnedElement;
429         LinkedList JavaDoc returnedList = new LinkedList JavaDoc();
430         LinkedList JavaDoc returnList = new LinkedList JavaDoc();
431         InlineLevelLayoutManager prevLM = null;
432         InlineLevelLayoutManager currLM;
433         int fromIndex = 0;
434
435         while (oldListIterator.hasNext()) {
436             oldElement = (KnuthElement) oldListIterator.next();
437             currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
438             if (prevLM == null) {
439                 prevLM = currLM;
440             }
441
442             if (currLM != prevLM || !oldListIterator.hasNext()) {
443                 if (oldListIterator.hasNext()) {
444                     returnedList.addAll
445                         (prevLM.getChangedKnuthElements
446                          (oldList.subList(fromIndex,
447                                           oldListIterator.previousIndex()),
448                           /*flaggedPenalty,*/ alignment));
449                     prevLM = currLM;
450                     fromIndex = oldListIterator.previousIndex();
451                 } else if (currLM == prevLM) {
452                     returnedList.addAll
453                         (prevLM.getChangedKnuthElements
454                          (oldList.subList(fromIndex, oldList.size()),
455                           /*flaggedPenalty,*/ alignment));
456                 } else {
457                     returnedList.addAll
458                         (prevLM.getChangedKnuthElements
459                          (oldList.subList(fromIndex,
460                                           oldListIterator.previousIndex()),
461                           /*flaggedPenalty,*/ alignment));
462                     if (currLM != null) {
463                         returnedList.addAll
464                             (currLM.getChangedKnuthElements
465                              (oldList.subList(oldListIterator.previousIndex(),
466                                               oldList.size()),
467                               /*flaggedPenalty,*/ alignment));
468                     }
469                 }
470             }
471         }
472
473         // "wrap" the Position stored in each element of returnedList
474
ListIterator JavaDoc listIter = returnedList.listIterator();
475         while (listIter.hasNext()) {
476             returnedElement = (KnuthElement) listIter.next();
477             returnedElement.setPosition
478                 (notifyPos(new NonLeafPosition(this, returnedElement.getPosition())));
479             returnList.add(returnedElement);
480         }
481         return returnList;
482     }
483 }
484
Popular Tags