1 50 51 package com.lowagie.text.pdf; 52 53 import java.util.ArrayList ; 54 55 import com.lowagie.text.Chunk; 56 import com.lowagie.text.DocumentException; 57 import com.lowagie.text.Element; 58 import com.lowagie.text.ElementListener; 59 import com.lowagie.text.Phrase; 60 import com.lowagie.text.Rectangle; 61 62 70 public class MultiColumnText implements Element { 71 72 73 public static final float AUTOMATIC = -1f; 74 75 79 private float desiredHeight; 80 81 84 private float totalHeight; 85 86 89 private boolean overflow; 90 91 95 private float top; 96 97 100 private float pageBottom; 101 102 105 private ColumnText columnText; 106 107 110 private ArrayList columnDefs; 111 112 115 private boolean simple = true; 116 117 private int currentColumn = 0; 118 119 private float nextY = AUTOMATIC; 120 121 private boolean columnsRightToLeft = false; 122 123 private PdfDocument document; 124 128 public MultiColumnText() { 129 this(AUTOMATIC); 130 } 131 132 139 public MultiColumnText(float height) { 140 columnDefs = new ArrayList (); 141 desiredHeight = height; 142 top = AUTOMATIC; 143 columnText = new ColumnText(null); 145 totalHeight = 0f; 146 } 147 148 155 public MultiColumnText(float top, float height) { 156 columnDefs = new ArrayList (); 157 desiredHeight = height; 158 this.top = top; 159 nextY = top; 160 columnText = new ColumnText(null); 162 totalHeight = 0f; 163 } 164 165 174 public boolean isOverflow() { 175 return overflow; 176 } 177 178 185 public void useColumnParams(ColumnText sourceColumn) { 186 columnText.setSimpleVars(sourceColumn); 188 } 189 190 197 public void addColumn(float[] left, float[] right) { 198 ColumnDef nextDef = new ColumnDef(left, right); 199 simple = nextDef.isSimple(); 200 columnDefs.add(nextDef); 201 } 202 203 210 public void addSimpleColumn(float left, float right) { 211 ColumnDef newCol = new ColumnDef(left, right); 212 columnDefs.add(newCol); 213 } 214 215 224 public void addRegularColumns(float left, float right, float gutterWidth, int numColumns) { 225 float currX = left; 226 float width = right - left; 227 float colWidth = (width - (gutterWidth * (numColumns - 1))) / numColumns; 228 for (int i = 0; i < numColumns; i++) { 229 addSimpleColumn(currX, currX + colWidth); 230 currX += colWidth + gutterWidth; 231 } 232 } 233 234 244 public void addElement(Element element) throws DocumentException { 245 if (simple) { 246 columnText.addElement(element); 247 } else if (element instanceof Phrase) { 248 columnText.addText((Phrase) element); 249 } else if (element instanceof Chunk) { 250 columnText.addText((Chunk) element); 251 } else { 252 throw new DocumentException("Can't add " + element.getClass() + " to MultiColumnText with complex columns"); 253 } 254 } 255 256 257 266 public float write(PdfContentByte canvas, PdfDocument document, float documentY) throws DocumentException { 267 this.document = document; 268 columnText.setCanvas(canvas); 269 if (columnDefs.isEmpty()) { 270 throw new DocumentException("MultiColumnText has no columns"); 271 } 272 overflow = false; 273 pageBottom = document.bottom(); 274 float currentHeight = 0; 275 boolean done = false; 276 try { 277 while (!done) { 278 if (nextY == AUTOMATIC) { 279 nextY = document.getVerticalPosition(true); } 281 if (top == AUTOMATIC) { 282 top = document.getVerticalPosition(true); } 284 285 ColumnDef currentDef = (ColumnDef) columnDefs.get(getCurrentColumn()); 286 columnText.setYLine(top); 287 288 float[] left = currentDef.resolvePositions(Rectangle.LEFT); 289 float[] right = currentDef.resolvePositions(Rectangle.RIGHT); 290 if (document.isMarginMirroring() && document.getPageNumber() % 2 == 0){ 291 float delta = document.rightMargin() - document.left(); 292 left = (float[])left.clone(); 293 right = (float[])right.clone(); 294 for (int i = 0; i < left.length; i += 2) { 295 left[i] -= delta; 296 } 297 for (int i = 0; i < right.length; i += 2) { 298 right[i] -= delta; 299 } 300 } 301 302 currentHeight = Math.max(currentHeight, getHeight(left, right)); 303 304 if (currentDef.isSimple()) { 305 columnText.setSimpleColumn(left[2], left[3], right[0], right[1]); 306 } else { 307 columnText.setColumns(left, right); 308 } 309 310 int result = columnText.go(); 311 if ((result & ColumnText.NO_MORE_TEXT) != 0) { 312 done = true; 313 top = columnText.getYLine(); 314 } else if (shiftCurrentColumn()) { 315 top = nextY; 316 } else { totalHeight += currentHeight; 318 if ((desiredHeight != AUTOMATIC) && (totalHeight >= desiredHeight)) { 319 overflow = true; 320 break; 321 } else { documentY = nextY; 323 newPage(); 324 currentHeight = 0; 325 } 326 } 327 } 328 } catch (DocumentException ex) { 329 ex.printStackTrace(); 330 throw ex; 331 } 332 if (desiredHeight == AUTOMATIC && columnDefs.size() == 1) { 333 currentHeight = documentY - columnText.getYLine(); 334 } 335 return currentHeight; 336 } 337 338 private void newPage() throws DocumentException { 339 resetCurrentColumn(); 340 if (desiredHeight == AUTOMATIC) { 341 top = nextY = AUTOMATIC; 342 } 343 else { 344 top = nextY; 345 } 346 totalHeight = 0; 347 if (document != null) { 348 document.newPage(); 349 } 350 } 351 352 359 private float getHeight(float[] left, float[] right) { 360 float max = Float.MIN_VALUE; 361 float min = Float.MAX_VALUE; 362 for (int i = 0; i < left.length; i += 2) { 363 min = Math.min(min, left[i + 1]); 364 max = Math.max(max, left[i + 1]); 365 } 366 for (int i = 0; i < right.length; i += 2) { 367 min = Math.min(min, right[i + 1]); 368 max = Math.max(max, right[i + 1]); 369 } 370 return max - min; 371 } 372 373 374 381 public boolean process(ElementListener listener) { 382 try { 383 return listener.add(this); 384 } catch (DocumentException de) { 385 return false; 386 } 387 } 388 389 394 395 public int type() { 396 return Element.MULTI_COLUMN_TEXT; 397 } 398 399 404 405 public ArrayList getChunks() { 406 return null; 407 } 408 409 415 private float getColumnBottom() { 416 if (desiredHeight == AUTOMATIC) { 417 return pageBottom; 418 } else { 419 return Math.max(top - (desiredHeight - totalHeight), pageBottom); 420 } 421 } 422 423 428 public void nextColumn() throws DocumentException { 429 currentColumn = (currentColumn + 1) % columnDefs.size(); 430 top = nextY; 431 if (currentColumn == 0) { 432 newPage(); 433 } 434 } 435 436 440 public int getCurrentColumn() { 441 if (columnsRightToLeft) { 442 return (columnDefs.size() - currentColumn - 1); 443 } 444 return currentColumn; 445 } 446 447 450 public void resetCurrentColumn() { 451 currentColumn = 0; 452 } 453 454 458 public boolean shiftCurrentColumn() { 459 if (currentColumn + 1 < columnDefs.size()) { 460 currentColumn++; 461 return true; 462 } 463 return false; 464 } 465 466 470 public void setColumnsRightToLeft(boolean direction) { 471 columnsRightToLeft = direction; 472 } 473 474 481 public void setSpaceCharRatio(float spaceCharRatio) { 482 columnText.setSpaceCharRatio(spaceCharRatio); 483 } 484 485 488 public void setRunDirection(int runDirection) { 489 columnText.setRunDirection(runDirection); 490 } 491 492 496 public void setArabicOptions(int arabicOptions) { 497 columnText.setArabicOptions(arabicOptions); 498 } 499 500 503 public void setAlignment(int alignment) { 504 columnText.setAlignment(alignment); 505 } 506 507 510 private class ColumnDef { 511 private float[] left; 512 private float[] right; 513 514 ColumnDef(float[] newLeft, float[] newRight) { 515 left = newLeft; 516 right = newRight; 517 } 518 519 ColumnDef(float leftPosition, float rightPosition) { 520 left = new float[4]; 521 left[0] = leftPosition; left[1] = top; left[2] = leftPosition; if (desiredHeight == AUTOMATIC || top == AUTOMATIC) { 525 left[3] = AUTOMATIC; 526 } else { 527 left[3] = top - desiredHeight; 528 } 529 530 right = new float[4]; 531 right[0] = rightPosition; right[1] = top; right[2] = rightPosition; if (desiredHeight == AUTOMATIC || top == AUTOMATIC) { 535 right[3] = AUTOMATIC; 536 } else { 537 right[3] = top - desiredHeight; 538 } 539 } 540 541 549 float[] resolvePositions(int side) { 550 if (side == Rectangle.LEFT) { 551 return resolvePositions(left); 552 } else { 553 return resolvePositions(right); 554 } 555 } 556 557 private float[] resolvePositions(float[] positions) { 558 if (!isSimple()) { 559 return positions; 560 } 561 if (top == AUTOMATIC) { 562 throw new RuntimeException ("resolvePositions called with top=AUTOMATIC (-1). " + 564 "Top position must be set befure lines can be resolved"); 565 } 566 positions[1] = top; 567 positions[3] = getColumnBottom(); 568 return positions; 569 } 570 571 575 private boolean isSimple() { 576 return (left.length == 4 && right.length == 4) && (left[0] == left[2] && right[0] == right[2]); 577 } 578 579 } 580 } 581 | Popular Tags |