KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > ColumnText


1 /*
2  * $Id: ColumnText.java 2742 2007-05-08 13:04:56Z blowagie $
3  * $Name$
4  *
5  * Copyright 2001, 2002 by Paulo Soares.
6  *
7  * The contents of this file are subject to the Mozilla Public License Version 1.1
8  * (the "License"); you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the License.
14  *
15  * The Original Code is 'iText, a free JAVA-PDF library'.
16  *
17  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
18  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
19  * All Rights Reserved.
20  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
21  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
22  *
23  * Contributor(s): all the names of the contributors are added in the source code
24  * where applicable.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
28  * provisions of LGPL are applicable instead of those above. If you wish to
29  * allow use of your version of this file only under the terms of the LGPL
30  * License and not to allow others to use your version of this file under
31  * the MPL, indicate your decision by deleting the provisions above and
32  * replace them with the notice and other provisions required by the LGPL.
33  * If you do not delete the provisions above, a recipient may use your version
34  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Library General Public License as published by the Free Software Foundation;
39  * either version 2 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
44  * details.
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */

50
51 package com.lowagie.text.pdf;
52 import java.util.ArrayList JavaDoc;
53 import java.util.Iterator JavaDoc;
54 import java.util.LinkedList JavaDoc;
55 import java.util.Stack JavaDoc;
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 /**
68  * Formats text in a columnwise form. The text is bound
69  * on the left and on the right by a sequence of lines. This allows the column
70  * to have any shape, not only rectangular.
71  * <P>
72  * Several parameters can be set like the first paragraph line indent and
73  * extra space between paragraphs.
74  * <P>
75  * A call to the method <CODE>go</CODE> will return one of the following
76  * situations: the column ended or the text ended.
77  * <P>
78  * I the column ended, a new column definition can be loaded with the method
79  * <CODE>setColumns</CODE> and the method <CODE>go</CODE> can be called again.
80  * <P>
81  * If the text ended, more text can be loaded with <CODE>addText</CODE>
82  * and the method <CODE>go</CODE> can be called again.<BR>
83  * The only limitation is that one or more complete paragraphs must be loaded
84  * each time.
85  * <P>
86  * Full bidirectional reordering is supported. If the run direction is
87  * <CODE>PdfWriter.RUN_DIRECTION_RTL</CODE> the meaning of the horizontal
88  * alignments and margins is mirrored.
89  * @author Paulo Soares (psoares@consiste.pt)
90  */

91
92 public class ColumnText {
93     /** Eliminate the arabic vowels */
94     public static final int AR_NOVOWEL = ArabicLigaturizer.ar_novowel;
95     /** Compose the tashkeel in the ligatures. */
96     public static final int AR_COMPOSEDTASHKEEL = ArabicLigaturizer.ar_composedtashkeel;
97     /** Do some extra double ligatures. */
98     public static final int AR_LIG = ArabicLigaturizer.ar_lig;
99     /**
100      * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits.
101      */

102     public static final int DIGITS_EN2AN = ArabicLigaturizer.DIGITS_EN2AN;
103     
104     /**
105      * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039).
106      */

107     public static final int DIGITS_AN2EN = ArabicLigaturizer.DIGITS_AN2EN;
108     
109     /**
110      * Digit shaping option:
111      * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
112      * if the most recent strongly directional character
113      * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
114      * The initial state at the start of the text is assumed to be not an Arabic,
115      * letter, so European digits at the start of the text will not change.
116      * Compare to DIGITS_ALEN2AN_INIT_AL.
117      */

118     public static final int DIGITS_EN2AN_INIT_LR = ArabicLigaturizer.DIGITS_EN2AN_INIT_LR;
119     
120     /**
121      * Digit shaping option:
122      * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
123      * if the most recent strongly directional character
124      * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
125      * The initial state at the start of the text is assumed to be an Arabic,
126      * letter, so European digits at the start of the text will change.
127      * Compare to DIGITS_ALEN2AN_INT_LR.
128      */

129     public static final int DIGITS_EN2AN_INIT_AL = ArabicLigaturizer.DIGITS_EN2AN_INIT_AL;
130     
131     /**
132      * Digit type option: Use Arabic-Indic digits (U+0660...U+0669).
133      */

134     public static final int DIGIT_TYPE_AN = ArabicLigaturizer.DIGIT_TYPE_AN;
135     
136     /**
137      * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9).
138      */

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     /** the space char ratio */
144     public static final float GLOBAL_SPACE_CHAR_RATIO = 0;
145     
146     /** Initial value of the status. */
147     public static final int START_COLUMN = 0;
148     
149     /** Signals that there is no more text available. */
150     public static final int NO_MORE_TEXT = 1;
151     
152     /** Signals that there is no more column. */
153     public static final int NO_MORE_COLUMN = 2;
154     
155     /** The column is valid. */
156     protected static final int LINE_STATUS_OK = 0;
157     
158     /** The line is out the column limits. */
159     protected static final int LINE_STATUS_OFFLIMITS = 1;
160     
161     /** The line cannot fit this column position. */
162     protected static final int LINE_STATUS_NOLINE = 2;
163     
164     /** Upper bound of the column. */
165     protected float maxY;
166     
167     /** Lower bound of the column. */
168     protected float minY;
169     
170     protected float leftX;
171     
172     protected float rightX;
173     
174     /** The column alignment. Default is left alignment. */
175     protected int alignment = Element.ALIGN_LEFT;
176     
177     /** The left column bound. */
178     protected ArrayList JavaDoc leftWall;
179     
180     /** The right column bound. */
181     protected ArrayList JavaDoc rightWall;
182     
183     /** The chunks that form the text. */
184 // protected ArrayList chunks = new ArrayList();
185
protected BidiLine bidiLine;
186     
187     /** The current y line location. Text will be written at this line minus the leading. */
188     protected float yLine;
189     
190     /** The leading for the current line. */
191     protected float currentLeading = 16;
192     
193     /** The fixed text leading. */
194     protected float fixedLeading = 16;
195     
196     /** The text leading that is multiplied by the biggest font size in the line. */
197     protected float multipliedLeading = 0;
198     
199     /** The <CODE>PdfContent</CODE> where the text will be written to. */
200     protected PdfContentByte canvas;
201     
202     protected PdfContentByte[] canvases;
203     
204     /** The line status when trying to fit a line to a column. */
205     protected int lineStatus;
206     
207     /** The first paragraph line indent. */
208     protected float indent = 0;
209     
210     /** The following paragraph lines indent. */
211     protected float followingIndent = 0;
212     
213     /** The right paragraph lines indent. */
214     protected float rightIndent = 0;
215     
216     /** The extra space between paragraphs. */
217     protected float extraParagraphSpace = 0;
218     
219     /** The width of the line when the column is defined as a simple rectangle. */
220     protected float rectangularWidth = -1;
221     
222     protected boolean rectangularMode = false;
223     /** Holds value of property spaceCharRatio. */
224     private float spaceCharRatio = GLOBAL_SPACE_CHAR_RATIO;
225
226     private boolean lastWasNewline = true;
227     
228     /** Holds value of property linesWritten. */
229     private int linesWritten;
230     
231     private float firstLineY;
232     private boolean firstLineYDone = false;
233     
234     /** Holds value of property arabicOptions. */
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 JavaDoc compositeElements;
244     
245     protected int listIdx = 0;
246     
247     private boolean splittedRow;
248     
249     protected Phrase waitPhrase;
250     
251     /** if true, first line height is adjusted so that the max ascender touches the top */
252     private boolean useAscender = false;
253
254     /**
255      * Creates a <CODE>ColumnText</CODE>.
256      * @param canvas the place where the text will be written to. Can
257      * be a template.
258      */

259     public ColumnText(PdfContentByte canvas) {
260         this.canvas = canvas;
261     }
262     
263     /** Creates an independent duplicated of the instance <CODE>org</CODE>.
264      * @param org the original <CODE>ColumnText</CODE>
265      * @return the duplicated
266      */

267     public static ColumnText duplicate(ColumnText org) {
268         ColumnText ct = new ColumnText(null);
269         ct.setACopy(org);
270         return ct;
271     }
272     
273     /** Makes this instance an independent copy of <CODE>org</CODE>.
274      * @param org the original <CODE>ColumnText</CODE>
275      * @return itself
276      */

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 JavaDoc(org.leftWall);
291         rightWall = null;
292         if (org.rightWall != null)
293             rightWall = new ArrayList JavaDoc(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 JavaDoc(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 JavaDoc j = waitPhrase.getChunks().iterator(); j.hasNext();) {
338                 bidiLine.addChunk(new PdfChunk((Chunk)j.next(), null));
339             }
340             waitPhrase = null;
341         }
342     }
343     
344     /**
345      * Adds a <CODE>Phrase</CODE> to the current text array.
346      * Will not have any effect if addElement() was called before.
347      * @param phrase the text
348      */

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 JavaDoc j = phrase.getChunks().iterator(); j.hasNext();) {
358             bidiLine.addChunk(new PdfChunk((Chunk)j.next(), null));
359         }
360     }
361     
362     /**
363      * Replaces the current text array with this <CODE>Phrase</CODE>.
364      * Anything added previously with addElement() is lost.
365      * @param phrase the text
366      */

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     /**
378      * Adds a <CODE>Chunk</CODE> to the current text array.
379      * Will not have any effect if addElement() was called before.
380      * @param chunk the text
381      */

382     public void addText(Chunk chunk) {
383         if (chunk == null || composite)
384             return;
385         addText(new Phrase(chunk));
386     }
387     
388     /**
389      * Adds an element. Elements supported are <CODE>Paragraph</CODE>,
390      * <CODE>List</CODE>, <CODE>PdfPTable</CODE>, <CODE>Image</CODE> and
391      * <CODE>Graphic</CODE>.
392      * <p>
393      * It removes all the text placed with <CODE>addText()</CODE>.
394      * @param element the <CODE>Element</CODE>
395      */

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 JavaDoc("Element not allowed.");
442             }
443         }
444         else if (element.type() != Element.PARAGRAPH && element.type() != Element.LIST && element.type() != Element.PTABLE)
445             throw new IllegalArgumentException JavaDoc("Element not allowed.");
446         if (!composite) {
447             composite = true;
448             compositeElements = new LinkedList JavaDoc();
449             bidiLine = null;
450             waitPhrase = null;
451         }
452         compositeElements.add(element);
453     }
454     
455     /**
456      * Converts a sequence of lines representing one of the column bounds into
457      * an internal format.
458      * <p>
459      * Each array element will contain a <CODE>float[4]</CODE> representing
460      * the line x = ax + b.
461      * @param cLine the column array
462      * @return the converted array
463      */

464     protected ArrayList JavaDoc convertColumn(float cLine[]) {
465         if (cLine.length < 4)
466             throw new RuntimeException JavaDoc("No valid column line found.");
467         ArrayList JavaDoc cc = new ArrayList JavaDoc();
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             // x = ay + b
476
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 JavaDoc("No valid column line found.");
489         return cc;
490     }
491     
492     /**
493      * Finds the intersection between the <CODE>yLine</CODE> and the column. It will
494      * set the <CODE>lineStatus</CODE> apropriatly.
495      * @param wall the column to intersect
496      * @return the x coordinate of the intersection
497      */

498     protected float findLimitsPoint(ArrayList JavaDoc 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     /**
515      * Finds the intersection between the <CODE>yLine</CODE> and the two
516      * column bounds. It will set the <CODE>lineStatus</CODE> apropriatly.
517      * @return a <CODE>float[2]</CODE>with the x coordinates of the intersection
518      */

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     /**
530      * Finds the intersection between the <CODE>yLine</CODE>,
531      * the <CODE>yLine-leading</CODE>and the two
532      * column bounds. It will set the <CODE>lineStatus</CODE> apropriatly.
533      * @return a <CODE>float[4]</CODE>with the x coordinates of the intersection
534      */

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     /**
562      * Sets the columns bounds. Each column bound is described by a
563      * <CODE>float[]</CODE> with the line points [x1,y1,x2,y2,...].
564      * The array must have at least 4 elements.
565      * @param leftLine the left column bound
566      * @param rightLine the right column bound
567      */

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     /**
578      * Simplified method for rectangular columns.
579      * @param phrase a <CODE>Phrase</CODE>
580      * @param llx the lower left x corner
581      * @param lly the lower left y corner
582      * @param urx the upper right x corner
583      * @param ury the upper right y corner
584      * @param leading the leading
585      * @param alignment the column alignment
586      */

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     /**
593      * Simplified method for rectangular columns.
594      * @param llx the lower left x corner
595      * @param lly the lower left y corner
596      * @param urx the upper right x corner
597      * @param ury the upper right y corner
598      * @param leading the leading
599      * @param alignment the column alignment
600      */

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     /**
608      * Simplified method for rectangular columns.
609      * @param llx
610      * @param lly
611      * @param urx
612      * @param ury
613      */

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     /**
626      * Sets the leading to fixed
627      * @param leading the leading
628      */

629     public void setLeading(float leading) {
630         fixedLeading = leading;
631         multipliedLeading = 0;
632     }
633     
634     /**
635      * Sets the leading fixed and variable. The resultant leading will be
636      * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the
637      * size of the bigest font in the line.
638      * @param fixedLeading the fixed leading
639      * @param multipliedLeading the variable leading
640      */

641     public void setLeading(float fixedLeading, float multipliedLeading) {
642         this.fixedLeading = fixedLeading;
643         this.multipliedLeading = multipliedLeading;
644     }
645     
646     /**
647      * Gets the fixed leading
648      * @return the leading
649      */

650     public float getLeading() {
651         return fixedLeading;
652     }
653     
654     /**
655      * Gets the variable leading
656      * @return the leading
657      */

658     public float getMultipliedLeading() {
659         return multipliedLeading;
660     }
661     
662     /**
663      * Sets the yLine. The line will be written to yLine-leading.
664      * @param yLine the yLine
665      */

666     public void setYLine(float yLine) {
667         this.yLine = yLine;
668     }
669     
670     /**
671      * Gets the yLine.
672      * @return the yLine
673      */

674     public float getYLine() {
675         return yLine;
676     }
677     
678     /**
679      * Sets the alignment.
680      * @param alignment the alignment
681      */

682     public void setAlignment(int alignment) {
683         this.alignment = alignment;
684     }
685     
686     /**
687      * Gets the alignment.
688      * @return the alignment
689      */

690     public int getAlignment() {
691         return alignment;
692     }
693     
694     /**
695      * Sets the first paragraph line indent.
696      * @param indent the indent
697      */

698     public void setIndent(float indent) {
699         this.indent = indent;
700         lastWasNewline = true;
701     }
702     
703     /**
704      * Gets the first paragraph line indent.
705      * @return the indent
706      */

707     public float getIndent() {
708         return indent;
709     }
710     
711     /**
712      * Sets the following paragraph lines indent.
713      * @param indent the indent
714      */

715     public void setFollowingIndent(float indent) {
716         this.followingIndent = indent;
717         lastWasNewline = true;
718     }
719     
720     /**
721      * Gets the following paragraph lines indent.
722      * @return the indent
723      */

724     public float getFollowingIndent() {
725         return followingIndent;
726     }
727     
728     /**
729      * Sets the right paragraph lines indent.
730      * @param indent the indent
731      */

732     public void setRightIndent(float indent) {
733         this.rightIndent = indent;
734         lastWasNewline = true;
735     }
736     
737     /**
738      * Gets the right paragraph lines indent.
739      * @return the indent
740      */

741     public float getRightIndent() {
742         return rightIndent;
743     }
744     
745     /**
746      * Outputs the lines to the document. It is equivalent to <CODE>go(false)</CODE>.
747      * @return returns the result of the operation. It can be <CODE>NO_MORE_TEXT</CODE>
748      * and/or <CODE>NO_MORE_COLUMN</CODE>
749      * @throws DocumentException on error
750      */

751     public int go() throws DocumentException {
752         return go(false);
753     }
754     
755     /**
756      * Outputs the lines to the document. The output can be simulated.
757      * @param simulate <CODE>true</CODE> to simulate the writting to the document
758      * @return returns the result of the operation. It can be <CODE>NO_MORE_TEXT</CODE>
759      * and/or <CODE>NO_MORE_COLUMN</CODE>
760      * @throws DocumentException on error
761      */

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 JavaDoc currentValues[] = new Object JavaDoc[2];
773         PdfFont currentFont = null;
774         Float JavaDoc lastBaseFactor = new Float JavaDoc(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 JavaDoc("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     /**
902      * Sets the extra space between paragraphs.
903      * @return the extra space between paragraphs
904      */

905     public float getExtraParagraphSpace() {
906         return extraParagraphSpace;
907     }
908     
909     /**
910      * Sets the extra space between paragraphs.
911      * @param extraParagraphSpace the extra space between paragraphs
912      */

913     public void setExtraParagraphSpace(float extraParagraphSpace) {
914         this.extraParagraphSpace = extraParagraphSpace;
915     }
916     
917     /**
918      * Clears the chunk array. A call to <CODE>go()</CODE> will always return
919      * NO_MORE_TEXT.
920      */

921     public void clearChunks() {
922         if (bidiLine != null)
923             bidiLine.clearChunks();
924     }
925     
926     /** Gets the space/character extra spacing ratio for
927      * fully justified text.
928      * @return the space/character extra spacing ratio
929      */

930     public float getSpaceCharRatio() {
931         return spaceCharRatio;
932     }
933     
934     /** Sets the ratio between the extra word spacing and the extra character spacing
935      * when the text is fully justified.
936      * Extra word spacing will grow <CODE>spaceCharRatio</CODE> times more than extra character spacing.
937      * If the ratio is <CODE>PdfWriter.NO_SPACE_CHAR_RATIO</CODE> then the extra character spacing
938      * will be zero.
939      * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing
940      */

941     public void setSpaceCharRatio(float spaceCharRatio) {
942         this.spaceCharRatio = spaceCharRatio;
943     }
944
945     /** Sets the run direction.
946      * @param runDirection the run direction
947      */

948     public void setRunDirection(int runDirection) {
949         if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT || runDirection > PdfWriter.RUN_DIRECTION_RTL)
950             throw new RuntimeException JavaDoc("Invalid run direction: " + runDirection);
951         this.runDirection = runDirection;
952     }
953     
954     /** Gets the run direction.
955      * @return the run direction
956      */

957     public int getRunDirection() {
958         return runDirection;
959     }
960     
961     /** Gets the number of lines written.
962      * @return the number of lines written
963      */

964     public int getLinesWritten() {
965         return this.linesWritten;
966     }
967     
968     /** Gets the arabic shaping options.
969      * @return the arabic shaping options
970      */

971     public int getArabicOptions() {
972         return this.arabicOptions;
973     }
974     
975     /** Sets the arabic shaping options. The option can be AR_NOVOWEL,
976      * AR_COMPOSEDTASHKEEL and AR_LIG.
977      * @param arabicOptions the arabic shaping options
978      */

979     public void setArabicOptions(int arabicOptions) {
980         this.arabicOptions = arabicOptions;
981     }
982     
983     /** Gets the biggest descender value of the last line written.
984      * @return the biggest descender value of the last line written
985      */

986     public float getDescender() {
987         return descender;
988     }
989     
990     /** Gets the width that the line will occupy after writing.
991      * Only the width of the first line is returned.
992      * @param phrase the <CODE>Phrase</CODE> containing the line
993      * @param runDirection the run direction
994      * @param arabicOptions the options for the arabic shaping
995      * @return the width of the line
996      */

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    /** Gets the width that the line will occupy after writing.
1009     * Only the width of the first line is returned.
1010     * @param phrase the <CODE>Phrase</CODE> containing the line
1011     * @return the width of the line
1012     */

1013    public static float getWidth(Phrase phrase) {
1014        return getWidth(phrase, PdfWriter.RUN_DIRECTION_NO_BIDI, 0);
1015    }
1016    
1017    /** Shows a line of text. Only the first line is written.
1018     * @param canvas where the text is to be written to
1019     * @param alignment the alignment. It is not influenced by the run direction
1020     * @param phrase the <CODE>Phrase</CODE> with the text
1021     * @param x the x reference position
1022     * @param y the y reference position
1023     * @param rotation the rotation to be applied in degrees counterclockwise
1024     * @param runDirection the run direction
1025     * @param arabicOptions the options for the arabic shaping
1026     */

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    /** Shows a line of text. Only the first line is written.
1072     * @param canvas where the text is to be written to
1073     * @param alignment the alignment
1074     * @param phrase the <CODE>Phrase</CODE> with the text
1075     * @param x the x reference position
1076     * @param y the y reference position
1077     * @param rotation the rotation to be applied in degrees counterclockwise
1078     */

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 JavaDoc items = list.getItems();
1156                ListItem item = null;
1157                float listIndentation = list.getIndentationLeft();
1158                int count = 0;
1159                Stack JavaDoc stack = new Stack JavaDoc();
1160                for (int k = 0; k < items.size(); ++k) {
1161                    Object JavaDoc 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 JavaDoc[]{list, new Integer JavaDoc(k), new Float JavaDoc(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 JavaDoc objs[] = (Object JavaDoc[])stack.pop();
1180                            list = (com.lowagie.text.List)objs[0];
1181                            items = list.getItems();
1182                            k = ((Integer JavaDoc)objs[1]).intValue();
1183                            listIndentation = ((Float JavaDoc)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 JavaDoc 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 JavaDoc rows = table.getRows();
1349                    ArrayList JavaDoc 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 JavaDoc 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    /**
1401     * Gets the canvas.
1402     * @return a PdfContentByte.
1403     */

1404    public PdfContentByte getCanvas() {
1405        return canvas;
1406    }
1407    
1408    /**
1409     * Sets the canvas.
1410     * @param canvas
1411     */

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    /**
1420     * Sets the canvases.
1421     * @param canvases
1422     */

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    /**
1431     * Gets the canvases.
1432     * @return an array of PdfContentByte
1433     */

1434    public PdfContentByte[] getCanvases() {
1435        return canvases;
1436    }
1437    
1438    /**
1439     * Checks if UseAscender is enabled/disabled.
1440     * @return true is the adjustment of the first line height is based on max ascender.
1441     */

1442    public boolean isUseAscender() {
1443        return useAscender;
1444    }
1445
1446    /**
1447     * Enables/Disables adjustment of first line height based on max ascender.
1448     * @param use enable adjustment if true
1449     */

1450    public void setUseAscender(boolean use) {
1451        useAscender = use;
1452    }
1453    
1454    /**
1455     * Checks the status variable and looks if there's still some text.
1456     */

1457    public static boolean hasMoreText(int status) {
1458        return (status & ColumnText.NO_MORE_TEXT) == 0;
1459    }
1460
1461    /**
1462     * Holds value of property filledWidth.
1463     */

1464    private float filledWidth;
1465
1466    /**
1467     * Gets the real width used by the largest line.
1468     * @return the real width used by the largest line
1469     */

1470    public float getFilledWidth() {
1471
1472        return this.filledWidth;
1473    }
1474
1475    /**
1476     * Sets the real width used by the largest line. Only used to set it
1477     * to zero to start another measurement.
1478     * @param filledWidth the real width used by the largest line
1479     */

1480    public void setFilledWidth(float filledWidth) {
1481
1482        this.filledWidth = filledWidth;
1483    }
1484    
1485    /**
1486     * Replaces the <CODE>filledWidth</CODE> if greater than the existing one.
1487     * @param w the new <CODE>filledWidth</CODE> if greater than the existing one
1488     */

1489    public void updateFilledWidth(float w) {
1490        if (w > filledWidth)
1491            filledWidth = w;
1492    }
1493}
1494
Popular Tags