KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > layoutmgr > table > TableCellLayoutManager


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: TableCellLayoutManager.java 453310 2006-10-05 18:44:15Z spepping $ */
19  
20 package org.apache.fop.layoutmgr.table;
21
22 import java.util.LinkedList JavaDoc;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.fop.fo.FONode;
27 import org.apache.fop.fo.flow.Table;
28 import org.apache.fop.fo.flow.TableCell;
29 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
30 import org.apache.fop.layoutmgr.AreaAdditionUtil;
31 import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
32 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
33 import org.apache.fop.layoutmgr.BreakElement;
34 import org.apache.fop.layoutmgr.KnuthElement;
35 import org.apache.fop.layoutmgr.KnuthGlue;
36 import org.apache.fop.layoutmgr.LayoutContext;
37 import org.apache.fop.layoutmgr.ListElement;
38 import org.apache.fop.layoutmgr.PositionIterator;
39 import org.apache.fop.layoutmgr.Position;
40 import org.apache.fop.layoutmgr.SpaceResolver;
41 import org.apache.fop.layoutmgr.TraitSetter;
42 import org.apache.fop.area.Area;
43 import org.apache.fop.area.Block;
44 import org.apache.fop.area.Trait;
45 import org.apache.fop.traits.MinOptMax;
46
47 /**
48  * LayoutManager for a table-cell FO.
49  * A cell contains blocks. These blocks fill the cell.
50  */

51 public class TableCellLayoutManager extends BlockStackingLayoutManager
52             implements BlockLevelLayoutManager {
53
54     /**
55      * logging instance
56      */

57     private static Log log = LogFactory.getLog(TableCellLayoutManager.class);
58     
59     private PrimaryGridUnit gridUnit;
60     
61     private Block curBlockArea;
62
63     private int inRowIPDOffset;
64     
65     private int xoffset;
66     private int yoffset;
67     private int cellIPD;
68     private int rowHeight;
69     private int usedBPD;
70     private int startBorderWidth;
71     private int endBorderWidth;
72     private int borderAndPaddingBPD;
73     private boolean emptyCell = true;
74
75     /**
76      * Create a new Cell layout manager.
77      * @param node table-cell FO for which to create the LM
78      * @param pgu primary grid unit for the cell
79      */

80     public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) {
81         super(node);
82         fobj = node;
83         this.gridUnit = pgu;
84     }
85
86     /** @return the table-cell FO */
87     public TableCell getTableCell() {
88         return (TableCell)this.fobj;
89     }
90     
91     private boolean isSeparateBorderModel() {
92         return getTable().isSeparateBorderModel();
93     }
94     
95     /** @see org.apache.fop.layoutmgr.LayoutManager#initialize() */
96     public void initialize() {
97         borderAndPaddingBPD = 0;
98         borderAndPaddingBPD += getTableCell()
99             .getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
100         borderAndPaddingBPD += getTableCell()
101             .getCommonBorderPaddingBackground().getBorderAfterWidth(false);
102         if (!isSeparateBorderModel()) {
103             borderAndPaddingBPD /= 2;
104         }
105         borderAndPaddingBPD += getTableCell().getCommonBorderPaddingBackground()
106                 .getPaddingBefore(false, this);
107         borderAndPaddingBPD += getTableCell().getCommonBorderPaddingBackground()
108                 .getPaddingAfter(false, this);
109     }
110     
111     /**
112      * @return the table owning this cell
113      */

114     public Table getTable() {
115         FONode node = fobj.getParent();
116         while (!(node instanceof Table)) {
117             node = node.getParent();
118         }
119         return (Table)node;
120     }
121     
122
123     /** @see org.apache.fop.layoutmgr.BlockStackingLayoutManager#getIPIndents() */
124     protected int getIPIndents() {
125         int iIndents = 0;
126         int[] startEndBorderWidths = gridUnit.getStartEndBorderWidths();
127         startBorderWidth += startEndBorderWidths[0];
128         endBorderWidth += startEndBorderWidths[1];
129         iIndents += startBorderWidth;
130         iIndents += endBorderWidth;
131         if (!isSeparateBorderModel()) {
132             iIndents /= 2;
133         }
134         iIndents += getTableCell().getCommonBorderPaddingBackground().getPaddingStart(false, this);
135         iIndents += getTableCell().getCommonBorderPaddingBackground().getPaddingEnd(false, this);
136         return iIndents;
137     }
138     
139     /**
140      * @see org.apache.fop.layoutmgr.LayoutManager
141      */

142     public LinkedList JavaDoc getNextKnuthElements(LayoutContext context, int alignment) {
143         MinOptMax stackLimit = new MinOptMax(context.getStackLimit());
144
145         referenceIPD = context.getRefIPD();
146         cellIPD = referenceIPD;
147         cellIPD -= getIPIndents();
148         if (isSeparateBorderModel()) {
149             int borderSep = getTable().getBorderSeparation().getLengthPair()
150                     .getIPD().getLength().getValue(this);
151             cellIPD -= borderSep;
152         }
153
154         LinkedList JavaDoc returnedList = null;
155         LinkedList JavaDoc contentList = new LinkedList JavaDoc();
156         LinkedList JavaDoc returnList = new LinkedList JavaDoc();
157
158         BlockLevelLayoutManager curLM; // currently active LM
159
BlockLevelLayoutManager prevLM = null; // previously active LM
160
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
161             LayoutContext childLC = new LayoutContext(0);
162             // curLM is a ?
163
childLC.setStackLimit(MinOptMax.subtract(context
164                     .getStackLimit(), stackLimit));
165             childLC.setRefIPD(cellIPD);
166
167             // get elements from curLM
168
returnedList = curLM.getNextKnuthElements(childLC, alignment);
169             if (childLC.isKeepWithNextPending()) {
170                 log.debug("child LM signals pending keep with next");
171             }
172             if (contentList.size() == 0 && childLC.isKeepWithPreviousPending()) {
173                 context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
174                 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
175             }
176             
177             if (returnedList.size() == 1
178                     && ((ListElement)returnedList.getFirst()).isForcedBreak()) {
179                 // a descendant of this block has break-before
180
if (returnList.size() == 0) {
181                     // the first child (or its first child ...) has
182
// break-before;
183
// all this block, including space before, will be put in
184
// the
185
// following page
186
}
187                 contentList.addAll(returnedList);
188
189                 // "wrap" the Position inside each element
190
// moving the elements from contentList to returnList
191
returnedList = new LinkedList JavaDoc();
192                 wrapPositionElements(contentList, returnList);
193
194                 //Space resolution
195
SpaceResolver.resolveElementList(returnList);
196                 
197                 return returnList;
198             } else {
199                 if (prevLM != null) {
200                     // there is a block handled by prevLM
201
// before the one handled by curLM
202
if (mustKeepTogether()
203                             || context.isKeepWithNextPending()
204                             || childLC.isKeepWithPreviousPending()) {
205                         //Clear keep pending flag
206
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
207                         childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
208                         // add an infinite penalty to forbid a break between
209
// blocks
210
contentList.add(new BreakElement(
211                                 new Position(this), KnuthElement.INFINITE, context));
212                         //contentList.add(new KnuthPenalty(0,
213
// KnuthElement.INFINITE, false,
214
// new Position(this), false));
215
} else if (!((ListElement) contentList.getLast()).isGlue()) {
216                         // add a null penalty to allow a break between blocks
217
contentList.add(new BreakElement(
218                                 new Position(this), 0, context));
219                         //contentList.add(new KnuthPenalty(0, 0, false,
220
// new Position(this), false));
221
} else {
222                         // the last element in contentList is a glue;
223
// it is a feasible breakpoint, there is no need to add
224
// a penalty
225
}
226                 }
227                 contentList.addAll(returnedList);
228                 if (returnedList.size() == 0) {
229                     //Avoid NoSuchElementException below (happens with empty blocks)
230
continue;
231                 }
232                 if (((ListElement)returnedList.getLast()).isForcedBreak()) {
233                     // a descendant of this block has break-after
234
if (curLM.isFinished()) {
235                         // there is no other content in this block;
236
// it's useless to add space after before a page break
237
setFinished(true);
238                     }
239
240                     returnedList = new LinkedList JavaDoc();
241                     wrapPositionElements(contentList, returnList);
242
243                     //Space resolution
244
SpaceResolver.resolveElementList(returnList);
245                     
246                     return returnList;
247                 }
248             }
249             if (childLC.isKeepWithNextPending()) {
250                 //Clear and propagate
251
childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
252                 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
253             }
254             prevLM = curLM;
255         }
256
257         returnedList = new LinkedList JavaDoc();
258         wrapPositionElements(contentList, returnList);
259         
260         //Space resolution
261
SpaceResolver.resolveElementList(returnList);
262         
263         getPSLM().notifyEndOfLayout(((TableCell)getFObj()).getId());
264         
265         setFinished(true);
266         return returnList;
267     }
268     
269     /**
270      * Set the y offset of this cell.
271      * This offset is used to set the absolute position of the cell.
272      *
273      * @param off the y direction offset
274      */

275     public void setYOffset(int off) {
276         yoffset = off;
277     }
278
279     /**
280      * Set the x offset of this cell (usually the same as its parent row).
281      * This offset is used to determine the absolute position of the cell.
282      *
283      * @param off the x offset
284      */

285     public void setXOffset(int off) {
286         xoffset = off;
287     }
288
289     /**
290      * Set the IPD offset of this cell inside the table-row.
291      * This offset is used to determine the absolute position of the cell.
292      * @param off the IPD offset
293      */

294     public void setInRowIPDOffset(int off) {
295         this.inRowIPDOffset = off;
296     }
297     
298     /**
299      * Set the content height for this cell. This method is used during
300      * addAreas() stage.
301      *
302      * @param h the height of the contents of this cell
303      */

304     public void setContentHeight(int h) {
305         usedBPD = h;
306     }
307     
308     /**
309      * Set the row height that contains this cell. This method is used during
310      * addAreas() stage.
311      *
312      * @param h the height of the row
313      */

314     public void setRowHeight(int h) {
315         rowHeight = h;
316     }
317
318     private int getContentHeight(int rowHeight, GridUnit gu) {
319         int bpd = rowHeight;
320         if (isSeparateBorderModel()) {
321             bpd -= gu.getPrimary().getBorders().getBorderBeforeWidth(false);
322             bpd -= gu.getPrimary().getBorders().getBorderAfterWidth(false);
323         } else {
324             bpd -= gu.getPrimary().getHalfMaxBorderWidth();
325         }
326         CommonBorderPaddingBackground cbpb
327             = gu.getCell().getCommonBorderPaddingBackground();
328         bpd -= cbpb.getPaddingBefore(false, this);
329         bpd -= cbpb.getPaddingAfter(false, this);
330         bpd -= 2 * ((TableLayoutManager)getParent()).getHalfBorderSeparationBPD();
331         return bpd;
332     }
333     
334     /**
335      * Add the areas for the break points.
336      * The cell contains block stacking layout managers
337      * that add block areas.
338      *
339      * @param parentIter the iterator of the break positions
340      * @param layoutContext the layout context for adding the areas
341      */

342     public void addAreas(PositionIterator parentIter,
343                          LayoutContext layoutContext) {
344         getParentArea(null);
345
346         getPSLM().addIDToPage(getTableCell().getId());
347
348         if (isSeparateBorderModel()) {
349             if (!emptyCell || getTableCell().showEmptyCells()) {
350                 TraitSetter.addBorders(curBlockArea,
351                         getTableCell().getCommonBorderPaddingBackground(), this);
352             }
353         } else {
354             boolean[] outer = new boolean[] {
355                     gridUnit.getFlag(GridUnit.FIRST_IN_TABLE),
356                     gridUnit.getFlag(GridUnit.LAST_IN_TABLE),
357                     gridUnit.getFlag(GridUnit.IN_FIRST_COLUMN),
358                     gridUnit.getFlag(GridUnit.IN_LAST_COLUMN)};
359             if (!gridUnit.hasSpanning()) {
360                 //Can set the borders directly if there's no span
361
TraitSetter.addCollapsingBorders(curBlockArea,
362                         gridUnit.getBorders(), outer, this);
363             } else {
364                 int dy = yoffset;
365                 for (int y = 0; y < gridUnit.getRows().size(); y++) {
366                     GridUnit[] gridUnits = (GridUnit[])gridUnit.getRows().get(y);
367                     int dx = xoffset;
368                     int lastRowHeight = 0;
369                     for (int x = 0; x < gridUnits.length; x++) {
370                         GridUnit gu = gridUnits[x];
371                         if (!gu.hasBorders()) {
372                             continue;
373                         }
374                         
375                         //Blocks for painting grid unit borders
376
Block block = new Block();
377                         block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
378                         block.setPositioning(Block.ABSOLUTE);
379
380                         int bpd = getContentHeight(rowHeight, gu);
381                         if (isSeparateBorderModel()) {
382                             bpd += (gu.getBorders().getBorderBeforeWidth(false));
383                             bpd += (gu.getBorders().getBorderAfterWidth(false));
384                         } else {
385                             bpd += gridUnit.getHalfMaxBeforeBorderWidth()
386                                     - (gu.getBorders().getBorderBeforeWidth(false) / 2);
387                             bpd += gridUnit.getHalfMaxAfterBorderWidth()
388                                     - (gu.getBorders().getBorderAfterWidth(false) / 2);
389                         }
390                         block.setBPD(bpd);
391                         lastRowHeight = rowHeight;
392                         int ipd = gu.getColumn().getColumnWidth().getValue(this);
393                         int borderStartWidth = gu.getBorders().getBorderStartWidth(false) / 2;
394                         ipd -= borderStartWidth;
395                         ipd -= gu.getBorders().getBorderEndWidth(false) / 2;
396                         block.setIPD(ipd);
397                         block.setXOffset(dx + borderStartWidth);
398                         int halfCollapsingBorderHeight = 0;
399                         if (!isSeparateBorderModel()) {
400                             halfCollapsingBorderHeight
401                                 += gu.getBorders().getBorderBeforeWidth(false) / 2;
402                         }
403                         block.setYOffset(dy - halfCollapsingBorderHeight);
404                         TraitSetter.addCollapsingBorders(block, gu.getBorders(), outer, this);
405                         parentLM.addChildArea(block);
406                         dx += gu.getColumn().getColumnWidth().getValue(this);
407                     }
408                     dy += lastRowHeight;
409                 }
410                 log.warn("TODO Add collapsed border painting for spanned cells");
411             }
412         }
413
414         //Handle display-align
415
int contentBPD = getContentHeight(rowHeight, gridUnit);
416         if (usedBPD < contentBPD) {
417             if (getTableCell().getDisplayAlign() == EN_CENTER) {
418                 Block space = new Block();
419                 space.setBPD((contentBPD - usedBPD) / 2);
420                 curBlockArea.addBlock(space);
421             } else if (getTableCell().getDisplayAlign() == EN_AFTER) {
422                 Block space = new Block();
423                 space.setBPD((contentBPD - usedBPD));
424                 curBlockArea.addBlock(space);
425             }
426         }
427
428         AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
429         
430         curBlockArea.setBPD(contentBPD);
431
432         // Add background after we know the BPD
433
if (isSeparateBorderModel()) {
434             if (!emptyCell || getTableCell().showEmptyCells()) {
435                 TraitSetter.addBackground(curBlockArea,
436                         getTableCell().getCommonBorderPaddingBackground(),
437                         this);
438             }
439         } else {
440             TraitSetter.addBackground(curBlockArea,
441                     getTableCell().getCommonBorderPaddingBackground(),
442                     this);
443         }
444         
445         flush();
446
447         curBlockArea = null;
448     }
449
450     /**
451      * Return an Area which can contain the passed childArea. The childArea
452      * may not yet have any content, but it has essential traits set.
453      * In general, if the LayoutManager already has an Area it simply returns
454      * it. Otherwise, it makes a new Area of the appropriate class.
455      * It gets a parent area for its area by calling its parent LM.
456      * Finally, based on the dimensions of the parent area, it initializes
457      * its own area. This includes setting the content IPD and the maximum
458      * BPD.
459      *
460      * @param childArea the child area to get the parent for
461      * @return the parent area
462      */

463     public Area getParentArea(Area childArea) {
464         if (curBlockArea == null) {
465             curBlockArea = new Block();
466             curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
467             TraitSetter.setProducerID(curBlockArea, getTableCell().getId());
468             curBlockArea.setPositioning(Block.ABSOLUTE);
469             int indent = 0;
470             indent += startBorderWidth;
471             if (!isSeparateBorderModel()) {
472                 indent /= 2;
473             }
474             indent += getTableCell()
475                     .getCommonBorderPaddingBackground().getPaddingStart(false, this);
476             // set position
477
int borderAdjust = 0;
478             if (!isSeparateBorderModel()) {
479                 if (gridUnit.hasSpanning()) {
480                     borderAdjust -= gridUnit.getHalfMaxBeforeBorderWidth();
481                 } else {
482                     borderAdjust += gridUnit.getHalfMaxBeforeBorderWidth();
483                 }
484             } else {
485                 //borderAdjust += gridUnit.getBorders().getBorderBeforeWidth(false);
486
}
487             TableLayoutManager tableLM = (TableLayoutManager)getParent();
488             curBlockArea.setXOffset(xoffset + inRowIPDOffset
489                     + tableLM.getHalfBorderSeparationIPD() + indent);
490             curBlockArea.setYOffset(yoffset - borderAdjust
491                     + tableLM.getHalfBorderSeparationBPD());
492             curBlockArea.setIPD(cellIPD);
493             //curBlockArea.setHeight();
494

495             // Set up dimensions
496
/*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
497             // Get reference IPD from parentArea
498
setCurrentArea(curBlockArea); // ??? for generic operations
499
}
500         return curBlockArea;
501     }
502
503     /**
504      * Add the child to the cell block area.
505      *
506      * @param childArea the child to add to the cell
507      */

508     public void addChildArea(Area childArea) {
509         if (curBlockArea != null) {
510             curBlockArea.addBlock((Block) childArea);
511         }
512     }
513
514     /**
515      * Reset the position of the layout.
516      *
517      * @param resetPos the position to reset to
518      */

519     public void resetPosition(Position resetPos) {
520         if (resetPos == null) {
521             reset(null);
522         }
523     }
524
525     /**
526      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager
527      */

528     public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
529         // TODO Auto-generated method stub
530
return 0;
531     }
532
533     /**
534      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager
535      */

536     public void discardSpace(KnuthGlue spaceGlue) {
537         // TODO Auto-generated method stub
538
}
539
540     /**
541      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
542      */

543     public boolean mustKeepTogether() {
544         //TODO Keeps will have to be more sophisticated sooner or later
545
boolean keep = ((BlockLevelLayoutManager)getParent()).mustKeepTogether();
546         if (gridUnit.getRow() != null) {
547             keep |= gridUnit.getRow().mustKeepTogether();
548         }
549         return keep;
550     }
551
552     /**
553      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
554      */

555     public boolean mustKeepWithPrevious() {
556         return false; //TODO FIX ME
557
/*
558         return !fobj.getKeepWithPrevious().getWithinPage().isAuto()
559             || !fobj.getKeepWithPrevious().getWithinColumn().isAuto();
560             */

561     }
562
563     /**
564      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
565      */

566     public boolean mustKeepWithNext() {
567         return false; //TODO FIX ME
568
/*
569         return !fobj.getKeepWithNext().getWithinPage().isAuto()
570             || !fobj.getKeepWithNext().getWithinColumn().isAuto();
571             */

572     }
573     
574     // --------- Property Resolution related functions --------- //
575

576     /**
577      * Returns the IPD of the content area
578      * @return the IPD of the content area
579      */

580     public int getContentAreaIPD() {
581         return cellIPD;
582     }
583    
584     /**
585      * Returns the BPD of the content area
586      * @return the BPD of the content area
587      */

588     public int getContentAreaBPD() {
589         if (curBlockArea != null) {
590             return curBlockArea.getBPD();
591         } else {
592             log.error("getContentAreaBPD called on unknown BPD");
593             return -1;
594         }
595     }
596    
597     /**
598      * @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesReferenceArea
599      */

600     public boolean getGeneratesReferenceArea() {
601         return true;
602     }
603    
604     /**
605      * @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesBlockArea
606      */

607     public boolean getGeneratesBlockArea() {
608         return true;
609     }
610
611 }
612
613
Popular Tags