1 17 18 19 20 package org.apache.fop.layoutmgr.table; 21 22 import java.util.LinkedList ; 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 51 public class TableCellLayoutManager extends BlockStackingLayoutManager 52 implements BlockLevelLayoutManager { 53 54 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 80 public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) { 81 super(node); 82 fobj = node; 83 this.gridUnit = pgu; 84 } 85 86 87 public TableCell getTableCell() { 88 return (TableCell)this.fobj; 89 } 90 91 private boolean isSeparateBorderModel() { 92 return getTable().isSeparateBorderModel(); 93 } 94 95 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 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 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 142 public LinkedList 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 returnedList = null; 155 LinkedList contentList = new LinkedList (); 156 LinkedList returnList = new LinkedList (); 157 158 BlockLevelLayoutManager curLM; BlockLevelLayoutManager prevLM = null; while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { 161 LayoutContext childLC = new LayoutContext(0); 162 childLC.setStackLimit(MinOptMax.subtract(context 164 .getStackLimit(), stackLimit)); 165 childLC.setRefIPD(cellIPD); 166 167 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 if (returnList.size() == 0) { 181 } 187 contentList.addAll(returnedList); 188 189 returnedList = new LinkedList (); 192 wrapPositionElements(contentList, returnList); 193 194 SpaceResolver.resolveElementList(returnList); 196 197 return returnList; 198 } else { 199 if (prevLM != null) { 200 if (mustKeepTogether() 203 || context.isKeepWithNextPending() 204 || childLC.isKeepWithPreviousPending()) { 205 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); 207 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); 208 contentList.add(new BreakElement( 211 new Position(this), KnuthElement.INFINITE, context)); 212 } else if (!((ListElement) contentList.getLast()).isGlue()) { 216 contentList.add(new BreakElement( 218 new Position(this), 0, context)); 219 } else { 222 } 226 } 227 contentList.addAll(returnedList); 228 if (returnedList.size() == 0) { 229 continue; 231 } 232 if (((ListElement)returnedList.getLast()).isForcedBreak()) { 233 if (curLM.isFinished()) { 235 setFinished(true); 238 } 239 240 returnedList = new LinkedList (); 241 wrapPositionElements(contentList, returnList); 242 243 SpaceResolver.resolveElementList(returnList); 245 246 return returnList; 247 } 248 } 249 if (childLC.isKeepWithNextPending()) { 250 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 (); 258 wrapPositionElements(contentList, returnList); 259 260 SpaceResolver.resolveElementList(returnList); 262 263 getPSLM().notifyEndOfLayout(((TableCell)getFObj()).getId()); 264 265 setFinished(true); 266 return returnList; 267 } 268 269 275 public void setYOffset(int off) { 276 yoffset = off; 277 } 278 279 285 public void setXOffset(int off) { 286 xoffset = off; 287 } 288 289 294 public void setInRowIPDOffset(int off) { 295 this.inRowIPDOffset = off; 296 } 297 298 304 public void setContentHeight(int h) { 305 usedBPD = h; 306 } 307 308 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 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 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 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 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 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 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 int borderAdjust = 0; 478 if (!isSeparateBorderModel()) { 479 if (gridUnit.hasSpanning()) { 480 borderAdjust -= gridUnit.getHalfMaxBeforeBorderWidth(); 481 } else { 482 borderAdjust += gridUnit.getHalfMaxBeforeBorderWidth(); 483 } 484 } else { 485 } 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 495 parentLM.getParentArea(curBlockArea); 497 setCurrentArea(curBlockArea); } 500 return curBlockArea; 501 } 502 503 508 public void addChildArea(Area childArea) { 509 if (curBlockArea != null) { 510 curBlockArea.addBlock((Block) childArea); 511 } 512 } 513 514 519 public void resetPosition(Position resetPos) { 520 if (resetPos == null) { 521 reset(null); 522 } 523 } 524 525 528 public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) { 529 return 0; 531 } 532 533 536 public void discardSpace(KnuthGlue spaceGlue) { 537 } 539 540 543 public boolean mustKeepTogether() { 544 boolean keep = ((BlockLevelLayoutManager)getParent()).mustKeepTogether(); 546 if (gridUnit.getRow() != null) { 547 keep |= gridUnit.getRow().mustKeepTogether(); 548 } 549 return keep; 550 } 551 552 555 public boolean mustKeepWithPrevious() { 556 return false; 561 } 562 563 566 public boolean mustKeepWithNext() { 567 return false; 572 } 573 574 576 580 public int getContentAreaIPD() { 581 return cellIPD; 582 } 583 584 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 600 public boolean getGeneratesReferenceArea() { 601 return true; 602 } 603 604 607 public boolean getGeneratesBlockArea() { 608 return true; 609 } 610 611 } 612 613 | Popular Tags |