1 51 package org.apache.fop.fo.flow; 52 53 import org.apache.fop.fo.*; 55 import org.apache.fop.fo.properties.*; 56 import org.apache.fop.layout.*; 57 import org.apache.fop.datatypes.*; 58 import org.apache.fop.apps.FOPException; 59 60 import java.util.ArrayList ; 62 63 public class Table extends FObj { 64 65 public static class Maker extends FObj.Maker { 66 public FObj make(FObj parent, PropertyList propertyList, 67 String systemId, int line, int column) 68 throws FOPException { 69 return new Table(parent, propertyList, systemId, line, column); 70 } 71 72 } 73 74 public static FObj.Maker maker() { 75 return new Table.Maker(); 76 } 77 78 private static final int MINCOLWIDTH = 10000; int breakBefore; 80 int breakAfter; 81 int spaceBefore; 82 int spaceAfter; 83 LengthRange ipd; 84 int height; 85 String id; 86 TableHeader tableHeader = null; 87 TableFooter tableFooter = null; 88 boolean omitHeaderAtBreak = false; 89 boolean omitFooterAtBreak = false; 90 91 ArrayList columns = new ArrayList (); 92 int bodyCount = 0; 93 private boolean bAutoLayout=false; 94 private int contentWidth = 0; 96 private int optIPD; 97 98 private int minIPD; 99 100 private int maxIPD; 101 102 AreaContainer areaContainer; 103 104 public Table(FObj parent, PropertyList propertyList, 105 String systemId, int line, int column) { 106 super(parent, propertyList, systemId, line, column); 107 } 108 109 public String getName() { 110 return "fo:table"; 111 } 112 113 public int layout(Area area) throws FOPException { 114 if (this.marker == BREAK_AFTER) { 115 return Status.OK; 116 } 117 118 if (this.marker == START) { 119 AccessibilityProps mAccProps = propMgr.getAccessibilityProps(); 121 122 AuralProps mAurProps = propMgr.getAuralProps(); 124 125 BorderAndPadding bap = propMgr.getBorderAndPadding(); 127 BackgroundProps bProps = propMgr.getBackgroundProps(); 128 129 MarginProps mProps = propMgr.getMarginProps(); 131 132 RelativePositionProps mRelProps = propMgr.getRelativePositionProps(); 134 135 156 this.breakBefore = this.properties.get("break-before").getEnum(); 157 this.breakAfter = this.properties.get("break-after").getEnum(); 158 this.spaceBefore = 159 this.properties.get("space-before.optimum").getLength().mvalue(); 160 this.spaceAfter = 161 this.properties.get("space-after.optimum").getLength().mvalue(); 162 this.ipd = 163 this.properties.get("inline-progression-dimension"). 164 getLengthRange(); 165 this.height = this.properties.get("height").getLength().mvalue(); 166 this.bAutoLayout = (this.properties.get("table-layout").getEnum() == 167 TableLayout.AUTO); 168 169 this.id = this.properties.get("id").getString(); 170 171 this.omitHeaderAtBreak = 172 this.properties.get("table-omit-header-at-break").getEnum() 173 == TableOmitHeaderAtBreak.TRUE; 174 this.omitFooterAtBreak = 175 this.properties.get("table-omit-footer-at-break").getEnum() 176 == TableOmitFooterAtBreak.TRUE; 177 178 if (area instanceof BlockArea) { 179 area.end(); 180 } 181 if (this.areaContainer == null) { 183 try { 184 area.getIDReferences().createID(id); 185 } 186 catch(FOPException e) { 187 if (!e.isLocationSet()) { 188 e.setLocation(systemId, line, column); 189 } 190 throw e; 191 } 192 } 193 194 195 this.marker = 0; 196 197 if (breakBefore == BreakBefore.PAGE) { 198 return Status.FORCE_PAGE_BREAK; 199 } 200 201 if (breakBefore == BreakBefore.ODD_PAGE) { 202 return Status.FORCE_PAGE_BREAK_ODD; 203 } 204 205 if (breakBefore == BreakBefore.EVEN_PAGE) { 206 return Status.FORCE_PAGE_BREAK_EVEN; 207 } 208 209 } 210 211 if ((spaceBefore != 0) && (this.marker == 0)) { 212 area.addDisplaySpace(spaceBefore); 213 } 214 215 if (marker == 0 && areaContainer == null) { 216 area.getIDReferences().configureID(id, area); 218 } 219 220 int spaceLeft = area.spaceLeft(); 221 this.areaContainer = 222 new AreaContainer(propMgr.getFontState(area.getFontInfo()), 0, 0, 223 area.getAllocationWidth(), area.spaceLeft(), 224 Position.STATIC); 225 226 areaContainer.foCreator = this; areaContainer.setPage(area.getPage()); 228 areaContainer.setParent(area); 229 areaContainer.setBackground(propMgr.getBackgroundProps()); 230 areaContainer.setBorderAndPadding(propMgr.getBorderAndPadding()); 231 areaContainer.start(); 232 233 areaContainer.setAbsoluteHeight(area.getAbsoluteHeight()); 234 areaContainer.setIDReferences(area.getIDReferences()); 235 236 boolean addedHeader = false; 237 boolean addedFooter = false; 238 int numChildren = this.children.size(); 239 240 if (columns.size()==0) { 243 findColumns(areaContainer); 244 if (this.bAutoLayout) { 245 log.warn("table-layout=auto is not supported, using fixed!"); 246 } 247 this.contentWidth = 249 calcFixedColumnWidths(areaContainer.getAllocationWidth()); 250 } 251 areaContainer.setAllocationWidth(this.contentWidth); 252 layoutColumns(areaContainer); 253 254 for (int i = this.marker; i < numChildren; i++) { 255 FONode fo = (FONode)children.get(i); 256 if (fo instanceof Marker) { 257 ((Marker)fo).layout(area); 258 continue; 259 } 260 if (fo instanceof TableHeader) { 261 if (columns.size() == 0) { 262 log.warn("current implementation of tables requires a table-column for each column, indicating column-width"); 263 return Status.OK; 264 } 265 tableHeader = (TableHeader)fo; 266 tableHeader.setColumns(columns); 267 } else if (fo instanceof TableFooter) { 268 if (columns.size() == 0) { 269 log.warn("current implementation of tables requires a table-column for each column, indicating column-width"); 270 return Status.OK; 271 } 272 tableFooter = (TableFooter)fo; 273 tableFooter.setColumns(columns); 274 } else if (fo instanceof TableBody) { 275 if (columns.size() == 0) { 276 log.warn("current implementation of tables requires a table-column for each column, indicating column-width"); 277 return Status.OK; 278 } 279 int status; 280 if (tableHeader != null &&!addedHeader) { 281 if (Status.isIncomplete((status = 282 tableHeader.layout(areaContainer)))) { 283 tableHeader.resetMarker(); 284 return Status.AREA_FULL_NONE; 285 } 286 addedHeader = true; 287 tableHeader.resetMarker(); 288 area.setMaxHeight(area.getMaxHeight() - spaceLeft 289 + this.areaContainer.getMaxHeight()); 290 } 291 if (tableFooter != null &&!this.omitFooterAtBreak 292 &&!addedFooter) { 293 if (Status.isIncomplete((status = 294 tableFooter.layout(areaContainer)))) { 295 return Status.AREA_FULL_NONE; 296 } 297 addedFooter = true; 298 tableFooter.resetMarker(); 299 } 300 ((TableBody)fo).setColumns(columns); 301 302 if (Status.isIncomplete((status = fo.layout(areaContainer)))) { 303 this.marker = i; 304 if (bodyCount == 0 305 && status == Status.AREA_FULL_NONE) { 306 if (tableHeader != null) 307 tableHeader.removeLayout(areaContainer); 308 if (tableFooter != null) 309 tableFooter.removeLayout(areaContainer); 310 resetMarker(); 311 } 313 if (areaContainer.getContentHeight() > 0) { 315 area.addChild(areaContainer); 316 area.increaseHeight(areaContainer.getHeight()); 317 if (this.omitHeaderAtBreak) { 318 tableHeader = null; 320 } 321 if (tableFooter != null &&!this.omitFooterAtBreak) { 322 ((TableBody)fo).setYPosition(tableFooter.getYPosition()); 324 tableFooter.setYPosition(tableFooter.getYPosition() 325 + ((TableBody)fo).getHeight()); 326 } 327 setupColumnHeights(); 328 status = Status.AREA_FULL_SOME; 329 this.areasGenerated++; 330 } 331 return status; 332 } else { 333 bodyCount++; 334 } 335 area.setMaxHeight(area.getMaxHeight() - spaceLeft 336 + this.areaContainer.getMaxHeight()); 337 if (tableFooter != null &&!this.omitFooterAtBreak) { 338 ((TableBody)fo).setYPosition(tableFooter.getYPosition()); 341 tableFooter.setYPosition(tableFooter.getYPosition() 342 + ((TableBody)fo).getHeight()); 343 } 344 } 345 } 346 this.areasGenerated++; 347 348 if (tableFooter != null && this.omitFooterAtBreak) { 349 if (Status.isIncomplete(tableFooter.layout(areaContainer))) { 350 log.warn("footer could not fit on page, moving last body row to next page"); 355 area.addChild(areaContainer); 356 area.increaseHeight(areaContainer.getHeight()); 357 if (this.omitHeaderAtBreak) { 358 tableHeader = null; 360 } 361 tableFooter.removeLayout(areaContainer); 362 tableFooter.resetMarker(); 363 return Status.AREA_FULL_SOME; 364 } 365 } 366 367 if (height != 0) 368 areaContainer.setHeight(height); 369 370 setupColumnHeights(); 371 372 areaContainer.end(); 373 area.addChild(areaContainer); 374 375 376 area.increaseHeight(areaContainer.getHeight()); 377 378 if (spaceAfter != 0) { 379 area.addDisplaySpace(spaceAfter); 380 } 381 382 if (area instanceof BlockArea) { 383 area.start(); 384 } 385 386 if (breakAfter == BreakAfter.PAGE) { 387 this.marker = BREAK_AFTER; 388 return Status.FORCE_PAGE_BREAK; 389 } 390 391 if (breakAfter == BreakAfter.ODD_PAGE) { 392 this.marker = BREAK_AFTER; 393 return Status.FORCE_PAGE_BREAK_ODD; 394 } 395 396 if (breakAfter == BreakAfter.EVEN_PAGE) { 397 this.marker = BREAK_AFTER; 398 return Status.FORCE_PAGE_BREAK_EVEN; 399 } 400 401 return Status.OK; 402 } 403 404 protected void setupColumnHeights() { 405 for (int i = 0; i < columns.size(); i++) { 406 TableColumn c = (TableColumn)columns.get(i); 407 if ( c != null) { 408 c.setHeight(areaContainer.getContentHeight()); 409 } 410 } 411 } 412 413 private void findColumns(Area areaContainer) throws FOPException { 414 int nextColumnNumber = 1; 415 for (int i = 0; i < children.size(); i++) { 416 FONode fo = (FONode)children.get(i); 417 if (fo instanceof TableColumn) { 418 TableColumn c = (TableColumn)fo; 419 c.doSetup(areaContainer); 420 int numColumnsRepeated = c.getNumColumnsRepeated(); 421 int currentColumnNumber = c.getColumnNumber(); 422 if (currentColumnNumber == 0) { 423 currentColumnNumber = nextColumnNumber; 424 } 425 if (currentColumnNumber + numColumnsRepeated > columns.size()) { 426 columns.ensureCapacity(currentColumnNumber + numColumnsRepeated); 427 } 428 for (int j = 0; j < numColumnsRepeated; j++) { 429 if (currentColumnNumber <= columns.size()) { 430 if (columns.get(currentColumnNumber - 1) != null) { 431 log.warn("More than one column object assigned " + 432 "to column " + 433 currentColumnNumber); 434 } 435 columns.set(currentColumnNumber - 1, c); 436 } else { 437 columns.add(currentColumnNumber - 1, c); 438 } 439 currentColumnNumber++; 440 } 441 nextColumnNumber = currentColumnNumber; 442 } 443 } 444 } 445 446 447 448 private int calcFixedColumnWidths(int maxAllocationWidth) { 449 int nextColumnNumber=1; 450 int iEmptyCols=0; 451 double dTblUnits=0.0; 452 int iFixedWidth=0; 453 double dWidthFactor = 0.0; 454 double dUnitLength = 0.0; 455 double tuMin = 100000.0 ; for (int i = 0; i < columns.size(); i++) { 457 TableColumn c = (TableColumn)columns.get(i); 458 if (c == null) { 459 log.warn("No table-column specification for column " + 460 nextColumnNumber); 461 iEmptyCols++; 463 } 464 else { 465 Length colLength = c.getColumnWidthAsLength(); 466 double tu = colLength.getTableUnits(); 467 if (tu > 0 && tu < tuMin && colLength.mvalue()==0) { 468 471 tuMin = tu; 472 } 473 dTblUnits += tu; 474 iFixedWidth += colLength.mvalue(); 475 } 476 nextColumnNumber++; 477 } 478 479 setIPD((dTblUnits > 0.0), maxAllocationWidth); 480 if (dTblUnits > 0.0) { 481 int iProportionalWidth = 0; 482 if (this.optIPD > iFixedWidth) { 483 iProportionalWidth = this.optIPD - iFixedWidth; 484 } 485 else if (this.maxIPD > iFixedWidth) { 486 iProportionalWidth = this.maxIPD - iFixedWidth; 487 } 488 else { 489 iProportionalWidth = maxAllocationWidth - iFixedWidth; 490 } 491 if (iProportionalWidth > 0) { 492 dUnitLength = ((double)iProportionalWidth)/dTblUnits; 493 } 494 else { 495 log.error("Sum of fixed column widths " + iFixedWidth + 496 " greater than maximum available IPD " + 497 maxAllocationWidth + "; no space for " + 498 dTblUnits + " proportional units."); 499 502 dUnitLength = MINCOLWIDTH/tuMin; 503 } 505 } 507 else { 508 511 int iTableWidth = iFixedWidth; 512 if (this.minIPD > iFixedWidth) { 513 iTableWidth = this.minIPD; 514 dWidthFactor = (double)this.minIPD/(double)iFixedWidth; 516 } 517 else if (this.maxIPD < iFixedWidth) { 518 log.warn("Sum of fixed column widths " + iFixedWidth + 520 " greater than maximum specified IPD " + this.maxIPD); 521 } 522 else if (this.optIPD != -1 && iFixedWidth != this.optIPD) { 523 log.warn("Sum of fixed column widths " + iFixedWidth + 524 " differs from specified optimum IPD " + this.optIPD); 525 } 526 } 527 int offset = 0; 529 for (int i = 0; i < columns.size(); i++) { 530 TableColumn c = (TableColumn)columns.get(i); 531 if (c != null) { 532 c.setColumnOffset(offset); 533 Length l = c.getColumnWidthAsLength(); 534 if (dUnitLength > 0) { 535 l.resolveTableUnit(dUnitLength); 536 } 537 int colWidth = l.mvalue(); 539 if (colWidth <= 0) { 540 log.warn("Zero-width table column!"); 541 } 542 if (dWidthFactor > 0.0) { 543 colWidth *= dWidthFactor; 545 } 546 c.setColumnWidth(colWidth); 547 offset += colWidth; 548 } 549 } 550 return offset; 551 } 552 553 private void layoutColumns(Area tableArea) throws FOPException { 554 for (int i = 0; i < columns.size(); i++) { 555 TableColumn c = (TableColumn)columns.get(i); 556 if (c != null) { 557 c.layout(tableArea); 558 } 559 } 560 } 561 562 563 public int getAreaHeight() { 564 return areaContainer.getHeight(); 565 } 566 567 570 public int getContentWidth() { 571 if (areaContainer != null) 572 return areaContainer.getContentWidth(); else 574 return 0; } 576 577 580 private void setIPD(boolean bHasProportionalUnits, int maxAllocIPD) { 581 boolean bMaxIsSpecified = !this.ipd.getMaximum().getLength().isAuto(); 582 if (bMaxIsSpecified) { 583 this.maxIPD = ipd.getMaximum().getLength().mvalue(); 584 } 585 else { 586 this.maxIPD = maxAllocIPD; 587 } 588 589 if (ipd.getOptimum().getLength().isAuto()) { 590 this.optIPD = -1; 591 } 592 else { 593 this.optIPD = ipd.getMaximum().getLength().mvalue(); 594 } 595 if (ipd.getMinimum().getLength().isAuto()) { 596 this.minIPD = -1; 597 } 598 else { 599 this.minIPD = ipd.getMinimum().getLength().mvalue(); 600 } 601 if (bHasProportionalUnits && this.optIPD < 0) { 602 if (this.minIPD > 0) { 603 if (bMaxIsSpecified) { 604 this.optIPD = (minIPD + maxIPD)/2; 605 } 606 else { 607 this.optIPD = this.minIPD; 608 } 609 } 610 else if (bMaxIsSpecified) { 611 this.optIPD = this.maxIPD; 612 } 613 else { 614 log.error("At least one of minimum, optimum, or maximum " + 615 "IPD must be specified on table."); 616 this.optIPD = this.maxIPD; 617 } 618 } 619 } 620 621 622 638 653 654 } 664 | Popular Tags |