1 50 51 package com.lowagie.text.pdf; 52 import java.util.ArrayList ; 53 import java.util.Iterator ; 54 import java.util.LinkedList ; 55 import java.util.Stack ; 56 57 import com.lowagie.text.Chunk; 58 import com.lowagie.text.DocumentException; 59 import com.lowagie.text.Element; 60 import com.lowagie.text.ExceptionConverter; 61 import com.lowagie.text.Image; 62 import com.lowagie.text.ListItem; 63 import com.lowagie.text.Paragraph; 64 import com.lowagie.text.Phrase; 65 import com.lowagie.text.SimpleTable; 66 67 91 92 public class ColumnText { 93 94 public static final int AR_NOVOWEL = ArabicLigaturizer.ar_novowel; 95 96 public static final int AR_COMPOSEDTASHKEEL = ArabicLigaturizer.ar_composedtashkeel; 97 98 public static final int AR_LIG = ArabicLigaturizer.ar_lig; 99 102 public static final int DIGITS_EN2AN = ArabicLigaturizer.DIGITS_EN2AN; 103 104 107 public static final int DIGITS_AN2EN = ArabicLigaturizer.DIGITS_AN2EN; 108 109 118 public static final int DIGITS_EN2AN_INIT_LR = ArabicLigaturizer.DIGITS_EN2AN_INIT_LR; 119 120 129 public static final int DIGITS_EN2AN_INIT_AL = ArabicLigaturizer.DIGITS_EN2AN_INIT_AL; 130 131 134 public static final int DIGIT_TYPE_AN = ArabicLigaturizer.DIGIT_TYPE_AN; 135 136 139 public static final int DIGIT_TYPE_AN_EXTENDED = ArabicLigaturizer.DIGIT_TYPE_AN_EXTENDED; 140 141 protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT; 142 143 144 public static final float GLOBAL_SPACE_CHAR_RATIO = 0; 145 146 147 public static final int START_COLUMN = 0; 148 149 150 public static final int NO_MORE_TEXT = 1; 151 152 153 public static final int NO_MORE_COLUMN = 2; 154 155 156 protected static final int LINE_STATUS_OK = 0; 157 158 159 protected static final int LINE_STATUS_OFFLIMITS = 1; 160 161 162 protected static final int LINE_STATUS_NOLINE = 2; 163 164 165 protected float maxY; 166 167 168 protected float minY; 169 170 protected float leftX; 171 172 protected float rightX; 173 174 175 protected int alignment = Element.ALIGN_LEFT; 176 177 178 protected ArrayList leftWall; 179 180 181 protected ArrayList rightWall; 182 183 184 protected BidiLine bidiLine; 186 187 188 protected float yLine; 189 190 191 protected float currentLeading = 16; 192 193 194 protected float fixedLeading = 16; 195 196 197 protected float multipliedLeading = 0; 198 199 200 protected PdfContentByte canvas; 201 202 protected PdfContentByte[] canvases; 203 204 205 protected int lineStatus; 206 207 208 protected float indent = 0; 209 210 211 protected float followingIndent = 0; 212 213 214 protected float rightIndent = 0; 215 216 217 protected float extraParagraphSpace = 0; 218 219 220 protected float rectangularWidth = -1; 221 222 protected boolean rectangularMode = false; 223 224 private float spaceCharRatio = GLOBAL_SPACE_CHAR_RATIO; 225 226 private boolean lastWasNewline = true; 227 228 229 private int linesWritten; 230 231 private float firstLineY; 232 private boolean firstLineYDone = false; 233 234 235 private int arabicOptions = 0; 236 237 protected float descender; 238 239 protected boolean composite = false; 240 241 protected ColumnText compositeColumn; 242 243 protected LinkedList compositeElements; 244 245 protected int listIdx = 0; 246 247 private boolean splittedRow; 248 249 protected Phrase waitPhrase; 250 251 252 private boolean useAscender = false; 253 254 259 public ColumnText(PdfContentByte canvas) { 260 this.canvas = canvas; 261 } 262 263 267 public static ColumnText duplicate(ColumnText org) { 268 ColumnText ct = new ColumnText(null); 269 ct.setACopy(org); 270 return ct; 271 } 272 273 277 public ColumnText setACopy(ColumnText org) { 278 setSimpleVars(org); 279 if (org.bidiLine != null) 280 bidiLine = new BidiLine(org.bidiLine); 281 return this; 282 } 283 284 protected void setSimpleVars(ColumnText org) { 285 maxY = org.maxY; 286 minY = org.minY; 287 alignment = org.alignment; 288 leftWall = null; 289 if (org.leftWall != null) 290 leftWall = new ArrayList (org.leftWall); 291 rightWall = null; 292 if (org.rightWall != null) 293 rightWall = new ArrayList (org.rightWall); 294 yLine = org.yLine; 295 currentLeading = org.currentLeading; 296 fixedLeading = org.fixedLeading; 297 multipliedLeading = org.multipliedLeading; 298 canvas = org.canvas; 299 canvases = org.canvases; 300 lineStatus = org.lineStatus; 301 indent = org.indent; 302 followingIndent = org.followingIndent; 303 rightIndent = org.rightIndent; 304 extraParagraphSpace = org.extraParagraphSpace; 305 rectangularWidth = org.rectangularWidth; 306 rectangularMode = org.rectangularMode; 307 spaceCharRatio = org.spaceCharRatio; 308 lastWasNewline = org.lastWasNewline; 309 linesWritten = org.linesWritten; 310 arabicOptions = org.arabicOptions; 311 runDirection = org.runDirection; 312 descender = org.descender; 313 composite = org.composite; 314 splittedRow = org.splittedRow; 315 if (org.composite) { 316 compositeElements = new LinkedList (org.compositeElements); 317 if (splittedRow) { 318 PdfPTable table = (PdfPTable)compositeElements.getFirst(); 319 compositeElements.set(0, new PdfPTable(table)); 320 } 321 if (org.compositeColumn != null) 322 compositeColumn = duplicate(org.compositeColumn); 323 } 324 listIdx = org.listIdx; 325 firstLineY = org.firstLineY; 326 leftX = org.leftX; 327 rightX = org.rightX; 328 firstLineYDone = org.firstLineYDone; 329 waitPhrase = org.waitPhrase; 330 useAscender = org.useAscender; 331 filledWidth = org.filledWidth; 332 } 333 334 private void addWaitingPhrase() { 335 if (bidiLine == null && waitPhrase != null) { 336 bidiLine = new BidiLine(); 337 for (Iterator j = waitPhrase.getChunks().iterator(); j.hasNext();) { 338 bidiLine.addChunk(new PdfChunk((Chunk)j.next(), null)); 339 } 340 waitPhrase = null; 341 } 342 } 343 344 349 public void addText(Phrase phrase) { 350 if (phrase == null || composite) 351 return; 352 addWaitingPhrase(); 353 if (bidiLine == null) { 354 waitPhrase = phrase; 355 return; 356 } 357 for (Iterator j = phrase.getChunks().iterator(); j.hasNext();) { 358 bidiLine.addChunk(new PdfChunk((Chunk)j.next(), null)); 359 } 360 } 361 362 367 public void setText(Phrase phrase) { 368 bidiLine = null; 369 composite = false; 370 compositeColumn = null; 371 compositeElements = null; 372 listIdx = 0; 373 splittedRow = false; 374 waitPhrase = phrase; 375 } 376 377 382 public void addText(Chunk chunk) { 383 if (chunk == null || composite) 384 return; 385 addText(new Phrase(chunk)); 386 } 387 388 396 public void addElement(Element element) { 397 if (element == null) 398 return; 399 if (element instanceof Image) { 400 Image img = (Image)element; 401 PdfPTable t = new PdfPTable(1); 402 float w = img.getWidthPercentage(); 403 if (w == 0) { 404 t.setTotalWidth(img.getScaledWidth()); 405 t.setLockedWidth(true); 406 } 407 else 408 t.setWidthPercentage(w); 409 t.setSpacingAfter(img.getSpacingAfter()); 410 t.setSpacingBefore(img.getSpacingBefore()); 411 switch (img.getAlignment()) { 412 case Image.LEFT: 413 t.setHorizontalAlignment(Element.ALIGN_LEFT); 414 break; 415 case Image.RIGHT: 416 t.setHorizontalAlignment(Element.ALIGN_RIGHT); 417 break; 418 default: 419 t.setHorizontalAlignment(Element.ALIGN_CENTER); 420 break; 421 } 422 PdfPCell c = new PdfPCell(img, true); 423 c.setPadding(0); 424 c.setBorder(img.getBorder()); 425 c.setBorderColor(img.getBorderColor()); 426 c.setBorderWidth(img.getBorderWidth()); 427 c.setBackgroundColor(img.getBackgroundColor()); 428 t.addCell(c); 429 element = t; 430 } 431 if (element.type() == Element.CHUNK) { 432 element = new Paragraph((Chunk)element); 433 } 434 else if (element.type() == Element.PHRASE) { 435 element = new Paragraph((Phrase)element); 436 } 437 if (element instanceof SimpleTable) { 438 try { 439 element = ((SimpleTable)element).createPdfPTable(); 440 } catch (DocumentException e) { 441 throw new IllegalArgumentException ("Element not allowed."); 442 } 443 } 444 else if (element.type() != Element.PARAGRAPH && element.type() != Element.LIST && element.type() != Element.PTABLE) 445 throw new IllegalArgumentException ("Element not allowed."); 446 if (!composite) { 447 composite = true; 448 compositeElements = new LinkedList (); 449 bidiLine = null; 450 waitPhrase = null; 451 } 452 compositeElements.add(element); 453 } 454 455 464 protected ArrayList convertColumn(float cLine[]) { 465 if (cLine.length < 4) 466 throw new RuntimeException ("No valid column line found."); 467 ArrayList cc = new ArrayList (); 468 for (int k = 0; k < cLine.length - 2; k += 2) { 469 float x1 = cLine[k]; 470 float y1 = cLine[k + 1]; 471 float x2 = cLine[k + 2]; 472 float y2 = cLine[k + 3]; 473 if (y1 == y2) 474 continue; 475 float a = (x1 - x2) / (y1 - y2); 477 float b = x1 - a * y1; 478 float r[] = new float[4]; 479 r[0] = Math.min(y1, y2); 480 r[1] = Math.max(y1, y2); 481 r[2] = a; 482 r[3] = b; 483 cc.add(r); 484 maxY = Math.max(maxY, r[1]); 485 minY = Math.min(minY, r[0]); 486 } 487 if (cc.isEmpty()) 488 throw new RuntimeException ("No valid column line found."); 489 return cc; 490 } 491 492 498 protected float findLimitsPoint(ArrayList wall) { 499 lineStatus = LINE_STATUS_OK; 500 if (yLine < minY || yLine > maxY) { 501 lineStatus = LINE_STATUS_OFFLIMITS; 502 return 0; 503 } 504 for (int k = 0; k < wall.size(); ++k) { 505 float r[] = (float[])wall.get(k); 506 if (yLine < r[0] || yLine > r[1]) 507 continue; 508 return r[2] * yLine + r[3]; 509 } 510 lineStatus = LINE_STATUS_NOLINE; 511 return 0; 512 } 513 514 519 protected float[] findLimitsOneLine() { 520 float x1 = findLimitsPoint(leftWall); 521 if (lineStatus == LINE_STATUS_OFFLIMITS || lineStatus == LINE_STATUS_NOLINE) 522 return null; 523 float x2 = findLimitsPoint(rightWall); 524 if (lineStatus == LINE_STATUS_NOLINE) 525 return null; 526 return new float[]{x1, x2}; 527 } 528 529 535 protected float[] findLimitsTwoLines() { 536 boolean repeat = false; 537 for (;;) { 538 if (repeat && currentLeading == 0) 539 return null; 540 repeat = true; 541 float x1[] = findLimitsOneLine(); 542 if (lineStatus == LINE_STATUS_OFFLIMITS) 543 return null; 544 yLine -= currentLeading; 545 if (lineStatus == LINE_STATUS_NOLINE) { 546 continue; 547 } 548 float x2[] = findLimitsOneLine(); 549 if (lineStatus == LINE_STATUS_OFFLIMITS) 550 return null; 551 if (lineStatus == LINE_STATUS_NOLINE) { 552 yLine -= currentLeading; 553 continue; 554 } 555 if (x1[0] >= x2[1] || x2[0] >= x1[1]) 556 continue; 557 return new float[]{x1[0], x1[1], x2[0], x2[1]}; 558 } 559 } 560 561 568 public void setColumns(float leftLine[], float rightLine[]) { 569 maxY = -10e20f; 570 minY = 10e20f; 571 rightWall = convertColumn(rightLine); 572 leftWall = convertColumn(leftLine); 573 rectangularWidth = -1; 574 rectangularMode = false; 575 } 576 577 587 public void setSimpleColumn(Phrase phrase, float llx, float lly, float urx, float ury, float leading, int alignment) { 588 addText(phrase); 589 setSimpleColumn(llx, lly, urx, ury, leading, alignment); 590 } 591 592 601 public void setSimpleColumn(float llx, float lly, float urx, float ury, float leading, int alignment) { 602 setLeading(leading); 603 this.alignment = alignment; 604 setSimpleColumn(llx, lly, urx, ury); 605 } 606 607 614 public void setSimpleColumn(float llx, float lly, float urx, float ury) { 615 leftX = Math.min(llx, urx); 616 maxY = Math.max(lly, ury); 617 minY = Math.min(lly, ury); 618 rightX = Math.max(llx, urx); 619 yLine = maxY; 620 rectangularWidth = rightX - leftX; 621 if (rectangularWidth < 0) 622 rectangularWidth = 0; 623 rectangularMode = true; 624 } 625 629 public void setLeading(float leading) { 630 fixedLeading = leading; 631 multipliedLeading = 0; 632 } 633 634 641 public void setLeading(float fixedLeading, float multipliedLeading) { 642 this.fixedLeading = fixedLeading; 643 this.multipliedLeading = multipliedLeading; 644 } 645 646 650 public float getLeading() { 651 return fixedLeading; 652 } 653 654 658 public float getMultipliedLeading() { 659 return multipliedLeading; 660 } 661 662 666 public void setYLine(float yLine) { 667 this.yLine = yLine; 668 } 669 670 674 public float getYLine() { 675 return yLine; 676 } 677 678 682 public void setAlignment(int alignment) { 683 this.alignment = alignment; 684 } 685 686 690 public int getAlignment() { 691 return alignment; 692 } 693 694 698 public void setIndent(float indent) { 699 this.indent = indent; 700 lastWasNewline = true; 701 } 702 703 707 public float getIndent() { 708 return indent; 709 } 710 711 715 public void setFollowingIndent(float indent) { 716 this.followingIndent = indent; 717 lastWasNewline = true; 718 } 719 720 724 public float getFollowingIndent() { 725 return followingIndent; 726 } 727 728 732 public void setRightIndent(float indent) { 733 this.rightIndent = indent; 734 lastWasNewline = true; 735 } 736 737 741 public float getRightIndent() { 742 return rightIndent; 743 } 744 745 751 public int go() throws DocumentException { 752 return go(false); 753 } 754 755 762 public int go(boolean simulate) throws DocumentException { 763 if (composite) 764 return goComposite(simulate); 765 addWaitingPhrase(); 766 if (bidiLine == null) 767 return NO_MORE_TEXT; 768 descender = 0; 769 linesWritten = 0; 770 boolean dirty = false; 771 float ratio = spaceCharRatio; 772 Object currentValues[] = new Object [2]; 773 PdfFont currentFont = null; 774 Float lastBaseFactor = new Float (0); 775 currentValues[1] = lastBaseFactor; 776 PdfDocument pdf = null; 777 PdfContentByte graphics = null; 778 PdfContentByte text = null; 779 firstLineY = Float.NaN; 780 int localRunDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; 781 if (runDirection != PdfWriter.RUN_DIRECTION_DEFAULT) 782 localRunDirection = runDirection; 783 if (canvas != null) { 784 graphics = canvas; 785 pdf = canvas.getPdfDocument(); 786 text = canvas.getDuplicate(); 787 } 788 else if (!simulate) 789 throw new NullPointerException ("ColumnText.go with simulate==false and text==null."); 790 if (!simulate) { 791 if (ratio == GLOBAL_SPACE_CHAR_RATIO) 792 ratio = text.getPdfWriter().getSpaceCharRatio(); 793 else if (ratio < 0.001f) 794 ratio = 0.001f; 795 } 796 float firstIndent = 0; 797 798 int status = 0; 799 if (rectangularMode) { 800 for (;;) { 801 firstIndent = (lastWasNewline ? indent : followingIndent); 802 if (rectangularWidth <= firstIndent + rightIndent) { 803 status = NO_MORE_COLUMN; 804 if (bidiLine.isEmpty()) 805 status |= NO_MORE_TEXT; 806 break; 807 } 808 if (bidiLine.isEmpty()) { 809 status = NO_MORE_TEXT; 810 break; 811 } 812 PdfLine line = bidiLine.processLine(rectangularWidth - firstIndent - rightIndent, alignment, localRunDirection, arabicOptions); 813 if (line == null) { 814 status = NO_MORE_TEXT; 815 break; 816 } 817 float maxSize = line.getMaxSizeSimple(); 818 if (isUseAscender() && Float.isNaN(firstLineY)) { 819 currentLeading = line.getAscender(); 820 } 821 else { 822 currentLeading = fixedLeading + maxSize * multipliedLeading; 823 } 824 if (yLine > maxY || yLine - currentLeading < minY ) { 825 status = NO_MORE_COLUMN; 826 bidiLine.restore(); 827 break; 828 } 829 yLine -= currentLeading; 830 if (!simulate && !dirty) { 831 text.beginText(); 832 dirty = true; 833 } 834 if (Float.isNaN(firstLineY)) { 835 firstLineY = yLine; 836 } 837 updateFilledWidth(rectangularWidth - line.widthLeft()); 838 if (!simulate) { 839 currentValues[0] = currentFont; 840 text.setTextMatrix(leftX + (line.isRTL() ? rightIndent : firstIndent) + line.indentLeft(), yLine); 841 pdf.writeLineToContent(line, text, graphics, currentValues, ratio); 842 currentFont = (PdfFont)currentValues[0]; 843 } 844 lastWasNewline = line.isNewlineSplit(); 845 yLine -= line.isNewlineSplit() ? extraParagraphSpace : 0; 846 ++linesWritten; 847 descender = line.getDescender(); 848 } 849 } 850 else { 851 currentLeading = fixedLeading; 852 for (;;) { 853 firstIndent = (lastWasNewline ? indent : followingIndent); 854 float yTemp = yLine; 855 float xx[] = findLimitsTwoLines(); 856 if (xx == null) { 857 status = NO_MORE_COLUMN; 858 if (bidiLine.isEmpty()) 859 status |= NO_MORE_TEXT; 860 yLine = yTemp; 861 break; 862 } 863 if (bidiLine.isEmpty()) { 864 status = NO_MORE_TEXT; 865 yLine = yTemp; 866 break; 867 } 868 float x1 = Math.max(xx[0], xx[2]); 869 float x2 = Math.min(xx[1], xx[3]); 870 if (x2 - x1 <= firstIndent + rightIndent) 871 continue; 872 if (!simulate && !dirty) { 873 text.beginText(); 874 dirty = true; 875 } 876 PdfLine line = bidiLine.processLine(x2 - x1 - firstIndent - rightIndent, alignment, localRunDirection, arabicOptions); 877 if (line == null) { 878 status = NO_MORE_TEXT; 879 yLine = yTemp; 880 break; 881 } 882 if (!simulate) { 883 currentValues[0] = currentFont; 884 text.setTextMatrix(x1 + (line.isRTL() ? rightIndent : firstIndent) + line.indentLeft(), yLine); 885 pdf.writeLineToContent(line, text, graphics, currentValues, ratio); 886 currentFont = (PdfFont)currentValues[0]; 887 } 888 lastWasNewline = line.isNewlineSplit(); 889 yLine -= line.isNewlineSplit() ? extraParagraphSpace : 0; 890 ++linesWritten; 891 descender = line.getDescender(); 892 } 893 } 894 if (dirty) { 895 text.endText(); 896 canvas.add(text); 897 } 898 return status; 899 } 900 901 905 public float getExtraParagraphSpace() { 906 return extraParagraphSpace; 907 } 908 909 913 public void setExtraParagraphSpace(float extraParagraphSpace) { 914 this.extraParagraphSpace = extraParagraphSpace; 915 } 916 917 921 public void clearChunks() { 922 if (bidiLine != null) 923 bidiLine.clearChunks(); 924 } 925 926 930 public float getSpaceCharRatio() { 931 return spaceCharRatio; 932 } 933 934 941 public void setSpaceCharRatio(float spaceCharRatio) { 942 this.spaceCharRatio = spaceCharRatio; 943 } 944 945 948 public void setRunDirection(int runDirection) { 949 if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT || runDirection > PdfWriter.RUN_DIRECTION_RTL) 950 throw new RuntimeException ("Invalid run direction: " + runDirection); 951 this.runDirection = runDirection; 952 } 953 954 957 public int getRunDirection() { 958 return runDirection; 959 } 960 961 964 public int getLinesWritten() { 965 return this.linesWritten; 966 } 967 968 971 public int getArabicOptions() { 972 return this.arabicOptions; 973 } 974 975 979 public void setArabicOptions(int arabicOptions) { 980 this.arabicOptions = arabicOptions; 981 } 982 983 986 public float getDescender() { 987 return descender; 988 } 989 990 997 public static float getWidth(Phrase phrase, int runDirection, int arabicOptions) { 998 ColumnText ct = new ColumnText(null); 999 ct.addText(phrase); 1000 ct.addWaitingPhrase(); 1001 PdfLine line = ct.bidiLine.processLine(20000, Element.ALIGN_LEFT, runDirection, arabicOptions); 1002 if (line == null) 1003 return 0; 1004 else 1005 return 20000 - line.widthLeft(); 1006 } 1007 1008 1013 public static float getWidth(Phrase phrase) { 1014 return getWidth(phrase, PdfWriter.RUN_DIRECTION_NO_BIDI, 0); 1015 } 1016 1017 1027 public static void showTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation, int runDirection, int arabicOptions) { 1028 if (alignment != Element.ALIGN_LEFT && alignment != Element.ALIGN_CENTER 1029 && alignment != Element.ALIGN_RIGHT) 1030 alignment = Element.ALIGN_LEFT; 1031 canvas.saveState(); 1032 ColumnText ct = new ColumnText(canvas); 1033 if (rotation == 0) { 1034 if (alignment == Element.ALIGN_LEFT) 1035 ct.setSimpleColumn(phrase, x, y - 1, 20000 + x, y + 2, 2, alignment); 1036 else if (alignment == Element.ALIGN_RIGHT) 1037 ct.setSimpleColumn(phrase, x-20000, y-1, x, y+2, 2, alignment); 1038 else 1039 ct.setSimpleColumn(phrase, x-20000, y-1, x+20000, y+2, 2, alignment); 1040 } 1041 else { 1042 double alpha = rotation * Math.PI / 180.0; 1043 float cos = (float)Math.cos(alpha); 1044 float sin = (float)Math.sin(alpha); 1045 canvas.concatCTM(cos, sin, -sin, cos, x, y); 1046 if (alignment == Element.ALIGN_LEFT) 1047 ct.setSimpleColumn(phrase, 0, -1, 20000, 2, 2, alignment); 1048 else if (alignment == Element.ALIGN_RIGHT) 1049 ct.setSimpleColumn(phrase, -20000, -1, 0, 2, 2, alignment); 1050 else 1051 ct.setSimpleColumn(phrase, -20000, -1, 20000, 2, 2, alignment); 1052 } 1053 if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { 1054 if (alignment == Element.ALIGN_LEFT) 1055 alignment = Element.ALIGN_RIGHT; 1056 else if (alignment == Element.ALIGN_RIGHT) 1057 alignment = Element.ALIGN_LEFT; 1058 } 1059 ct.setAlignment(alignment); 1060 ct.setArabicOptions(arabicOptions); 1061 ct.setRunDirection(runDirection); 1062 try { 1063 ct.go(); 1064 } 1065 catch (DocumentException e) { 1066 throw new ExceptionConverter(e); 1067 } 1068 canvas.restoreState(); 1069 } 1070 1071 1079 public static void showTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation) { 1080 showTextAligned(canvas, alignment, phrase, x, y, rotation, PdfWriter.RUN_DIRECTION_NO_BIDI, 0); 1081 } 1082 1083 protected int goComposite(boolean simulate) throws DocumentException { 1084 if (!rectangularMode) 1085 throw new DocumentException("Irregular columns are not supported in composite mode."); 1086 linesWritten = 0; 1087 descender = 0; 1088 boolean firstPass = true; 1089 main_loop: 1090 while (true) { 1091 if (compositeElements.isEmpty()) 1092 return NO_MORE_TEXT; 1093 Element element = (Element)compositeElements.getFirst(); 1094 if (element.type() == Element.PARAGRAPH) { 1095 Paragraph para = (Paragraph)element; 1096 int status = 0; 1097 for (int keep = 0; keep < 2; ++keep) { 1098 float lastY = yLine; 1099 boolean createHere = false; 1100 if (compositeColumn == null) { 1101 compositeColumn = new ColumnText(canvas); 1102 compositeColumn.setUseAscender(firstPass ? useAscender : false); 1103 compositeColumn.setAlignment(para.getAlignment()); 1104 compositeColumn.setIndent(para.getIndentationLeft() + para.getFirstLineIndent()); 1105 compositeColumn.setExtraParagraphSpace(para.getExtraParagraphSpace()); 1106 compositeColumn.setFollowingIndent(para.getIndentationLeft()); 1107 compositeColumn.setRightIndent(para.getIndentationRight()); 1108 compositeColumn.setLeading(para.getLeading(), para.getMultipliedLeading()); 1109 compositeColumn.setRunDirection(runDirection); 1110 compositeColumn.setArabicOptions(arabicOptions); 1111 compositeColumn.setSpaceCharRatio(spaceCharRatio); 1112 compositeColumn.addText(para); 1113 if (!firstPass) { 1114 yLine -= para.spacingBefore(); 1115 } 1116 createHere = true; 1117 } 1118 compositeColumn.leftX = leftX; 1119 compositeColumn.rightX = rightX; 1120 compositeColumn.yLine = yLine; 1121 compositeColumn.rectangularWidth = rectangularWidth; 1122 compositeColumn.rectangularMode = rectangularMode; 1123 compositeColumn.minY = minY; 1124 compositeColumn.maxY = maxY; 1125 boolean keepCandidate = (para.getKeepTogether() && createHere && !firstPass); 1126 status = compositeColumn.go(simulate || (keepCandidate && keep == 0)); 1127 updateFilledWidth(compositeColumn.filledWidth); 1128 if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { 1129 compositeColumn = null; 1130 yLine = lastY; 1131 return NO_MORE_COLUMN; 1132 } 1133 if (simulate || !keepCandidate) 1134 break; 1135 if (keep == 0) { 1136 compositeColumn = null; 1137 yLine = lastY; 1138 } 1139 } 1140 firstPass = false; 1141 yLine = compositeColumn.yLine; 1142 linesWritten += compositeColumn.linesWritten; 1143 descender = compositeColumn.descender; 1144 if ((status & NO_MORE_TEXT) != 0) { 1145 compositeColumn = null; 1146 compositeElements.removeFirst(); 1147 yLine -= para.spacingAfter(); 1148 } 1149 if ((status & NO_MORE_COLUMN) != 0) { 1150 return NO_MORE_COLUMN; 1151 } 1152 } 1153 else if (element.type() == Element.LIST) { 1154 com.lowagie.text.List list = (com.lowagie.text.List)element; 1155 ArrayList items = list.getItems(); 1156 ListItem item = null; 1157 float listIndentation = list.getIndentationLeft(); 1158 int count = 0; 1159 Stack stack = new Stack (); 1160 for (int k = 0; k < items.size(); ++k) { 1161 Object obj = items.get(k); 1162 if (obj instanceof ListItem) { 1163 if (count == listIdx) { 1164 item = (ListItem)obj; 1165 break; 1166 } 1167 else ++count; 1168 } 1169 else if (obj instanceof com.lowagie.text.List) { 1170 stack.push(new Object []{list, new Integer (k), new Float (listIndentation)}); 1171 list = (com.lowagie.text.List)obj; 1172 items = list.getItems(); 1173 listIndentation += list.getIndentationLeft(); 1174 k = -1; 1175 continue; 1176 } 1177 if (k == items.size() - 1) { 1178 if (!stack.isEmpty()) { 1179 Object objs[] = (Object [])stack.pop(); 1180 list = (com.lowagie.text.List)objs[0]; 1181 items = list.getItems(); 1182 k = ((Integer )objs[1]).intValue(); 1183 listIndentation = ((Float )objs[2]).floatValue(); 1184 } 1185 } 1186 } 1187 int status = 0; 1188 for (int keep = 0; keep < 2; ++keep) { 1189 float lastY = yLine; 1190 boolean createHere = false; 1191 if (compositeColumn == null) { 1192 if (item == null) { 1193 listIdx = 0; 1194 compositeElements.removeFirst(); 1195 continue main_loop; 1196 } 1197 compositeColumn = new ColumnText(canvas); 1198 compositeColumn.setUseAscender(firstPass ? useAscender : false); 1199 compositeColumn.setAlignment(item.getAlignment()); 1200 compositeColumn.setIndent(item.getIndentationLeft() + listIndentation + item.getFirstLineIndent()); 1201 compositeColumn.setExtraParagraphSpace(item.getExtraParagraphSpace()); 1202 compositeColumn.setFollowingIndent(compositeColumn.getIndent()); 1203 compositeColumn.setRightIndent(item.getIndentationRight() + list.getIndentationRight()); 1204 compositeColumn.setLeading(item.getLeading(), item.getMultipliedLeading()); 1205 compositeColumn.setRunDirection(runDirection); 1206 compositeColumn.setArabicOptions(arabicOptions); 1207 compositeColumn.setSpaceCharRatio(spaceCharRatio); 1208 compositeColumn.addText(item); 1209 if (!firstPass) { 1210 yLine -= item.spacingBefore(); 1211 } 1212 createHere = true; 1213 } 1214 compositeColumn.leftX = leftX; 1215 compositeColumn.rightX = rightX; 1216 compositeColumn.yLine = yLine; 1217 compositeColumn.rectangularWidth = rectangularWidth; 1218 compositeColumn.rectangularMode = rectangularMode; 1219 compositeColumn.minY = minY; 1220 compositeColumn.maxY = maxY; 1221 boolean keepCandidate = (item.getKeepTogether() && createHere && !firstPass); 1222 status = compositeColumn.go(simulate || (keepCandidate && keep == 0)); 1223 updateFilledWidth(compositeColumn.filledWidth); 1224 if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { 1225 compositeColumn = null; 1226 yLine = lastY; 1227 return NO_MORE_COLUMN; 1228 } 1229 if (simulate || !keepCandidate) 1230 break; 1231 if (keep == 0) { 1232 compositeColumn = null; 1233 yLine = lastY; 1234 } 1235 } 1236 firstPass = false; 1237 yLine = compositeColumn.yLine; 1238 linesWritten += compositeColumn.linesWritten; 1239 descender = compositeColumn.descender; 1240 if (!Float.isNaN(compositeColumn.firstLineY) && !compositeColumn.firstLineYDone) { 1241 if (!simulate) 1242 showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(item.getListSymbol()), compositeColumn.leftX + listIndentation, compositeColumn.firstLineY, 0); 1243 compositeColumn.firstLineYDone = true; 1244 } 1245 if ((status & NO_MORE_TEXT) != 0) { 1246 compositeColumn = null; 1247 ++listIdx; 1248 yLine -= item.spacingAfter(); 1249 } 1250 if ((status & NO_MORE_COLUMN) != 0) { 1251 return NO_MORE_COLUMN; 1252 } 1253 } 1254 else if (element.type() == Element.PTABLE) { 1255 if (yLine < minY || yLine > maxY) 1256 return NO_MORE_COLUMN; 1257 PdfPTable table = (PdfPTable)element; 1258 if (table.size() <= table.getHeaderRows()) { 1259 compositeElements.removeFirst(); 1260 continue; 1261 } 1262 float yTemp = yLine; 1263 float yLineWrite = yLine; 1264 if (!firstPass && listIdx == 0) { 1265 yTemp -= table.spacingBefore(); 1266 yLineWrite = yTemp; 1267 } 1268 currentLeading = 0; 1269 if (yTemp < minY || yTemp > maxY) 1270 return NO_MORE_COLUMN; 1271 float x1 = leftX; 1272 float tableWidth; 1273 if (table.isLockedWidth()) { 1274 tableWidth = table.getTotalWidth(); 1275 updateFilledWidth(tableWidth); 1276 } 1277 else { 1278 tableWidth = rectangularWidth * table.getWidthPercentage() / 100f; 1279 table.setTotalWidth(tableWidth); 1280 } 1281 int k; 1282 boolean skipHeader = (!firstPass && table.isSkipFirstHeader() && listIdx <= table.getHeaderRows()); 1283 if (!skipHeader) { 1284 yTemp -= table.getHeaderHeight(); 1285 if (yTemp < minY || yTemp > maxY) { 1286 if (firstPass) { 1287 compositeElements.removeFirst(); 1288 continue; 1289 } 1290 return NO_MORE_COLUMN; 1291 } 1292 } 1293 if (listIdx < table.getHeaderRows()) 1294 listIdx = table.getHeaderRows(); 1295 for (k = listIdx; k < table.size(); ++k) { 1296 float rowHeight = table.getRowHeight(k); 1297 if (yTemp - rowHeight < minY) 1298 break; 1299 yTemp -= rowHeight; 1300 } 1301 if (k < table.size()) { 1302 if (table.isSplitRows() && (!table.isSplitLate() || (k == listIdx && firstPass))) { 1303 if (!splittedRow) { 1304 splittedRow = true; 1305 table = new PdfPTable(table); 1306 compositeElements.set(0, table); 1307 ArrayList rows = table.getRows(); 1308 for (int i = table.getHeaderRows(); i < listIdx; ++i) 1309 rows.set(i, null); 1310 } 1311 float h = yTemp - minY; 1312 PdfPRow newRow = table.getRow(k).splitRow(h); 1313 if (newRow == null) { 1314 if (k == listIdx) 1315 return NO_MORE_COLUMN; 1316 } 1317 else { 1318 yTemp = minY; 1319 table.getRows().add(++k, newRow); 1320 } 1321 } 1322 else if (!table.isSplitRows() && k == listIdx && firstPass) { 1323 compositeElements.removeFirst(); 1324 splittedRow = false; 1325 continue; 1326 } 1327 else if (k == listIdx && !firstPass && (!table.isSplitRows() || table.isSplitLate())) { 1328 return NO_MORE_COLUMN; 1329 } 1330 } 1331 firstPass = false; 1332 if (!simulate) { 1333 switch (table.getHorizontalAlignment()) { 1334 case Element.ALIGN_LEFT: 1335 break; 1336 case Element.ALIGN_RIGHT: 1337 x1 += rectangularWidth - tableWidth; 1338 break; 1339 default: 1340 x1 += (rectangularWidth - tableWidth) / 2f; 1341 } 1342 int realHeaderRows = table.getHeaderRows(); 1343 int footerRows = table.getFooterRows(); 1344 if (footerRows > realHeaderRows) 1345 footerRows = realHeaderRows; 1346 realHeaderRows -= footerRows; 1347 PdfPTable nt = PdfPTable.shallowCopy(table); 1348 ArrayList rows = table.getRows(); 1349 ArrayList sub = nt.getRows(); 1350 if (!skipHeader) { 1351 for (int j = 0; j < realHeaderRows; ++j) 1352 sub.add(rows.get(j)); 1353 } 1354 else 1355 nt.setHeaderRows(footerRows); 1356 for (int j = listIdx; j < k; ++j) 1357 sub.add(rows.get(j)); 1358 for (int j = 0; j < footerRows; ++j) 1359 sub.add(rows.get(j + realHeaderRows)); 1360 float rowHeight = 0; 1361 if (table.isExtendLastRow()) { 1362 PdfPRow last = (PdfPRow)sub.get(sub.size() - 1 - footerRows); 1363 rowHeight = last.getMaxHeights(); 1364 last.setMaxHeights(yTemp - minY + rowHeight); 1365 yTemp = minY; 1366 } 1367 if (canvases != null) 1368 nt.writeSelectedRows(0, -1, x1, yLineWrite, canvases); 1369 else 1370 nt.writeSelectedRows(0, -1, x1, yLineWrite, canvas); 1371 if (table.isExtendLastRow()) { 1372 PdfPRow last = (PdfPRow)sub.get(sub.size() - 1 - footerRows); 1373 last.setMaxHeights(rowHeight); 1374 } 1375 } 1376 else if (table.isExtendLastRow() && minY > PdfPRow.BOTTOM_LIMIT) 1377 yTemp = minY; 1378 yLine = yTemp; 1379 if (k >= table.size()) { 1380 yLine -= table.spacingAfter(); 1381 compositeElements.removeFirst(); 1382 splittedRow = false; 1383 listIdx = 0; 1384 } 1385 else { 1386 if (splittedRow) { 1387 ArrayList rows = table.getRows(); 1388 for (int i = listIdx; i < k; ++i) 1389 rows.set(i, null); 1390 } 1391 listIdx = k; 1392 return NO_MORE_COLUMN; 1393 } 1394 } 1395 else 1396 compositeElements.removeFirst(); 1397 } 1398 } 1399 1400 1404 public PdfContentByte getCanvas() { 1405 return canvas; 1406 } 1407 1408 1412 public void setCanvas(PdfContentByte canvas) { 1413 this.canvas = canvas; 1414 this.canvases = null; 1415 if (compositeColumn != null) 1416 compositeColumn.setCanvas(canvas); 1417 } 1418 1419 1423 public void setCanvases(PdfContentByte[] canvases) { 1424 this.canvases = canvases; 1425 this.canvas = canvases[PdfPTable.TEXTCANVAS]; 1426 if (compositeColumn != null) 1427 compositeColumn.setCanvases(canvases); 1428 } 1429 1430 1434 public PdfContentByte[] getCanvases() { 1435 return canvases; 1436 } 1437 1438 1442 public boolean isUseAscender() { 1443 return useAscender; 1444 } 1445 1446 1450 public void setUseAscender(boolean use) { 1451 useAscender = use; 1452 } 1453 1454 1457 public static boolean hasMoreText(int status) { 1458 return (status & ColumnText.NO_MORE_TEXT) == 0; 1459 } 1460 1461 1464 private float filledWidth; 1465 1466 1470 public float getFilledWidth() { 1471 1472 return this.filledWidth; 1473 } 1474 1475 1480 public void setFilledWidth(float filledWidth) { 1481 1482 this.filledWidth = filledWidth; 1483 } 1484 1485 1489 public void updateFilledWidth(float w) { 1490 if (w > filledWidth) 1491 filledWidth = w; 1492 } 1493} 1494 | Popular Tags |