001/*
002 * $Id: PdfPCell.java 4923 2011-07-05 15:13:19Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf;
045
046import java.util.List;
047
048import com.itextpdf.text.Chunk;
049import com.itextpdf.text.DocumentException;
050import com.itextpdf.text.Element;
051import com.itextpdf.text.ExceptionConverter;
052import com.itextpdf.text.Image;
053import com.itextpdf.text.Phrase;
054import com.itextpdf.text.Rectangle;
055import com.itextpdf.text.error_messages.MessageLocalization;
056import com.itextpdf.text.pdf.events.PdfPCellEventForwarder;
057
058/**
059 * A cell in a PdfPTable.
060 */
061
062public class PdfPCell extends Rectangle{
063
064    private ColumnText column = new ColumnText(null);
065
066    /** Vertical alignment of the cell. */
067    private int verticalAlignment = Element.ALIGN_TOP;
068
069    /** Left padding of the cell. */
070    private float paddingLeft = 2;
071
072    /** Right padding of the cell. */
073    private float paddingRight = 2;
074
075    /** Top padding of the cell. */
076    private float paddingTop = 2;
077
078    /** Bottom padding of the cell. */
079    private float paddingBottom = 2;
080
081    /** Fixed height of the cell. */
082    private float fixedHeight = 0;
083
084    /** Minimum height of the cell. */
085    private float minimumHeight;
086
087    /** Holds value of property noWrap. */
088    private boolean noWrap = false;
089
090    /** Holds value of property table. */
091    private PdfPTable table;
092
093    /** Holds value of property colspan. */
094    private int colspan = 1;
095
096    /**
097     * Holds value of property rowspan.
098     * @since   2.1.6
099     */
100    private int rowspan = 1;
101
102    /** Holds value of property image. */
103    private Image image;
104
105    /** Holds value of property cellEvent. */
106    private PdfPCellEvent cellEvent;
107
108    /** Holds value of property useDescender. */
109    private boolean useDescender = true;
110
111    /** Increases padding to include border if true */
112    private boolean useBorderPadding = false;
113
114    /** The text in the cell. */
115    protected Phrase phrase;
116
117    /**
118     * The rotation of the cell. Possible values are
119     * 0, 90, 180 and 270.
120     */
121    private int rotation;
122
123    /**
124     * Constructs an empty <CODE>PdfPCell</CODE>.
125     * The default padding is 2.
126     */
127    public PdfPCell() {
128        super(0, 0, 0, 0);
129        borderWidth = 0.5f;
130        border = BOX;
131        column.setLeading(0, 1);
132        column.setUseAscender(true);
133    }
134
135    /**
136     * Constructs a <CODE>PdfPCell</CODE> with a <CODE>Phrase</CODE>.
137     * The default padding is 2.
138     *
139     * @param phrase the text
140     */
141    public PdfPCell(Phrase phrase) {
142        super(0, 0, 0, 0);
143        borderWidth = 0.5f;
144        border = BOX;
145        column.addText(this.phrase = phrase);
146        column.setLeading(0, 1);
147        column.setUseAscender(true);
148    }
149
150    /**
151     * Constructs a <CODE>PdfPCell</CODE> with an <CODE>Image</CODE>.
152     * The default padding is 0.
153     *
154     * @param image the <CODE>Image</CODE>
155     */
156    public PdfPCell(Image image) {
157        this(image, false);
158    }
159
160    /**
161     * Constructs a <CODE>PdfPCell</CODE> with an <CODE>Image</CODE>.
162     * The default padding is 0.25 for a border width of 0.5.
163     *
164     * @param image the <CODE>Image</CODE>
165     * @param fit <CODE>true</CODE> to fit the image to the cell
166     */
167    public PdfPCell(Image image, boolean fit) {
168        super(0, 0, 0, 0);
169        borderWidth = 0.5f;
170        border = BOX;
171        if (fit) {
172            this.image = image;
173            column.setLeading(0, 1);
174            setPadding(borderWidth / 2);
175        }
176        else {
177            column.addText(this.phrase = new Phrase(new Chunk(image, 0, 0, true)));
178            column.setLeading(0, 1);
179            setPadding(0);
180        }
181    }
182
183    /**
184     * Constructs a <CODE>PdfPCell</CODE> with a <CODE>PdfPtable</CODE>.
185     * This constructor allows nested tables.
186     * The default padding is 0.
187     *
188     * @param table The <CODE>PdfPTable</CODE>
189     */
190    public PdfPCell(PdfPTable table) {
191        this(table, null);
192    }
193
194    /**
195     * Constructs a <CODE>PdfPCell</CODE> with a <CODE>PdfPtable</CODE>.
196     * This constructor allows nested tables.
197     *
198     * @param table The <CODE>PdfPTable</CODE>
199     * @param style     The style to apply to the cell (you could use getDefaultCell())
200     * @since 2.1.0
201     */
202    public PdfPCell(PdfPTable table, PdfPCell style) {
203        super(0, 0, 0, 0);
204        borderWidth = 0.5f;
205        border = BOX;
206        column.setLeading(0, 1);
207        this.table = table;
208        table.setWidthPercentage(100);
209        table.setExtendLastRow(true);
210        column.addElement(table);
211        if (style != null) {
212                cloneNonPositionParameters(style);
213                verticalAlignment = style.verticalAlignment;
214                paddingLeft = style.paddingLeft;
215                paddingRight = style.paddingRight;
216                paddingTop = style.paddingTop;
217                paddingBottom = style.paddingBottom;
218                colspan = style.colspan;
219                rowspan = style.rowspan;
220                cellEvent = style.cellEvent;
221                useDescender = style.useDescender;
222                useBorderPadding = style.useBorderPadding;
223                rotation = style.rotation;
224        }
225        else
226                setPadding(0);
227    }
228
229    /**
230     * Constructs a deep copy of a <CODE>PdfPCell</CODE>.
231     *
232     * @param cell the <CODE>PdfPCell</CODE> to duplicate
233     */
234    public PdfPCell(PdfPCell cell) {
235        super(cell.llx, cell.lly, cell.urx, cell.ury);
236        cloneNonPositionParameters(cell);
237        verticalAlignment = cell.verticalAlignment;
238        paddingLeft = cell.paddingLeft;
239        paddingRight = cell.paddingRight;
240        paddingTop = cell.paddingTop;
241        paddingBottom = cell.paddingBottom;
242        phrase = cell.phrase;
243        fixedHeight = cell.fixedHeight;
244        minimumHeight = cell.minimumHeight;
245        noWrap = cell.noWrap;
246        colspan = cell.colspan;
247        rowspan = cell.rowspan;
248        if (cell.table != null)
249            table = new PdfPTable(cell.table);
250        image = Image.getInstance(cell.image);
251        cellEvent = cell.cellEvent;
252        useDescender = cell.useDescender;
253        column = ColumnText.duplicate(cell.column);
254        useBorderPadding = cell.useBorderPadding;
255        rotation = cell.rotation;
256    }
257
258    /**
259     * Adds an iText element to the cell.
260     *
261     * @param element
262     */
263    public void addElement(Element element) {
264        if (table != null) {
265            table = null;
266            column.setText(null);
267        }
268        column.addElement(element);
269    }
270
271    /**
272     * Gets the <CODE>Phrase</CODE> from this cell.
273     *
274     * @return the <CODE>Phrase</CODE>
275     */
276    public Phrase getPhrase() {
277        return phrase;
278    }
279
280    /**
281     * Sets the <CODE>Phrase</CODE> for this cell.
282     *
283     * @param phrase the <CODE>Phrase</CODE>
284     */
285    public void setPhrase(Phrase phrase) {
286        table = null;
287        image = null;
288        column.setText(this.phrase = phrase);
289    }
290
291    /**
292     * Gets the horizontal alignment for the cell.
293     *
294     * @return the horizontal alignment for the cell
295     */
296    public int getHorizontalAlignment() {
297        return column.getAlignment();
298    }
299
300    /**
301     * Sets the horizontal alignment for the cell. It could be
302     * <CODE>Element.ALIGN_CENTER</CODE> for example.
303     *
304     * @param horizontalAlignment The horizontal alignment
305     */
306    public void setHorizontalAlignment(int horizontalAlignment) {
307        column.setAlignment(horizontalAlignment);
308    }
309
310    /**
311     * Gets the vertical alignment for the cell.
312     *
313     * @return the vertical alignment for the cell
314     */
315    public int getVerticalAlignment() {
316        return verticalAlignment;
317    }
318
319    /**
320     * Sets the vertical alignment for the cell. It could be
321     * <CODE>Element.ALIGN_MIDDLE</CODE> for example.
322     *
323     * @param verticalAlignment The vertical alignment
324     */
325    public void setVerticalAlignment(int verticalAlignment) {
326        if (table != null)
327            table.setExtendLastRow(verticalAlignment == Element.ALIGN_TOP);
328        this.verticalAlignment = verticalAlignment;
329    }
330
331    /**
332     * Gets the effective left padding.
333     * This will include the left border width if
334     * {@link #isUseBorderPadding()} is true.
335     *
336     * @return effective value of property paddingLeft.
337     */
338    public float getEffectivePaddingLeft() {
339        if (isUseBorderPadding()) {
340                float border = getBorderWidthLeft() / (isUseVariableBorders() ? 1f : 2f);
341            return paddingLeft + border;
342        }
343        return paddingLeft;
344    }
345
346    /**
347     * @return Value of property paddingLeft.
348     */
349    public float getPaddingLeft() {
350        return paddingLeft;
351    }
352
353    /**
354     * Setter for property paddingLeft.
355     *
356     * @param paddingLeft New value of property paddingLeft.
357     */
358    public void setPaddingLeft(float paddingLeft) {
359        this.paddingLeft = paddingLeft;
360    }
361
362    /**
363     * Gets the effective right padding.  This will include
364     * the right border width if {@link #isUseBorderPadding()} is true.
365     *
366     * @return effective value of property paddingRight.
367     */
368    public float getEffectivePaddingRight() {
369        if (isUseBorderPadding()) {
370                float border = getBorderWidthRight() / (isUseVariableBorders() ? 1f : 2f);
371                return paddingRight + border;
372        }
373        return paddingRight;
374    }
375
376    /**
377     * Getter for property paddingRight.
378     *
379     * @return Value of property paddingRight.
380     */
381    public float getPaddingRight() {
382        return paddingRight;
383    }
384
385    /**
386     * Setter for property paddingRight.
387     *
388     * @param paddingRight New value of property paddingRight.
389     */
390    public void setPaddingRight(float paddingRight) {
391        this.paddingRight = paddingRight;
392    }
393
394    /**
395     * Gets the effective top padding.  This will include
396     * the top border width if {@link #isUseBorderPadding()} is true.
397     *
398     * @return effective value of property paddingTop.
399     */
400    public float getEffectivePaddingTop() {
401        if (isUseBorderPadding()) {
402                float border = getBorderWidthTop()/(isUseVariableBorders()?1f:2f);
403                return paddingTop + border;
404        }
405        return paddingTop;
406    }
407
408    /**
409     * Getter for property paddingTop.
410     *
411     * @return Value of property paddingTop.
412     */
413    public float getPaddingTop() {
414        return paddingTop;
415    }
416
417    /**
418     * Setter for property paddingTop.
419     *
420     * @param paddingTop New value of property paddingTop.
421     */
422    public void setPaddingTop(float paddingTop) {
423        this.paddingTop = paddingTop;
424    }
425
426    /**
427     * Gets the effective bottom padding.
428     * This will include  the bottom border width if
429     * {@link #isUseBorderPadding()} is true.
430     *
431     * @return effective value of property paddingBottom.
432     */
433    public float getEffectivePaddingBottom() {
434        if (isUseBorderPadding()) {
435                float border = getBorderWidthBottom()/(isUseVariableBorders()?1f:2f);
436                return paddingBottom + border;
437        }
438        return paddingBottom;
439    }
440
441    /**
442     * Getter for property paddingBottom.
443     *
444     * @return Value of property paddingBottom.
445     */
446    public float getPaddingBottom() {
447        return paddingBottom;
448    }
449
450    /**
451     * Setter for property paddingBottom.
452     *
453     * @param paddingBottom New value of property paddingBottom.
454     */
455    public void setPaddingBottom(float paddingBottom) {
456        this.paddingBottom = paddingBottom;
457    }
458
459    /**
460     * Sets the padding of the contents in the cell (space between content and border).
461     *
462     * @param padding
463     */
464    public void setPadding(float padding) {
465        paddingBottom = padding;
466        paddingTop = padding;
467        paddingLeft = padding;
468        paddingRight = padding;
469    }
470
471    /**
472     * If true, then effective padding will include border widths
473     *
474     * @return true if effective padding includes border widths
475     */
476    public boolean isUseBorderPadding() {
477        return useBorderPadding;
478    }
479
480    /**
481     * Adjusts effective padding to include border widths.
482     *
483     * @param use adjust effective padding if true
484     */
485    public void setUseBorderPadding(boolean use) {
486        useBorderPadding = use;
487    }
488
489    /**
490     * Sets the leading fixed and variable.
491     * The resultant leading will be:
492     * fixedLeading+multipliedLeading*maxFontSize
493     * where maxFontSize is the size of the biggest font in the line.
494     *
495     * @param fixedLeading the fixed leading
496     * @param multipliedLeading the variable leading
497     */
498    public void setLeading(float fixedLeading, float multipliedLeading) {
499        column.setLeading(fixedLeading, multipliedLeading);
500    }
501
502    /**
503     * Gets the fixed leading.
504     *
505     * @return the leading
506     */
507    public float getLeading() {
508        return column.getLeading();
509    }
510
511    /**
512     * Gets the variable leading.
513     *
514     * @return the leading
515     */
516    public float getMultipliedLeading() {
517        return column.getMultipliedLeading();
518    }
519
520    /**
521     * Sets the first paragraph line indent.
522     *
523     * @param indent the indent
524     */
525    public void setIndent(float indent) {
526        column.setIndent(indent);
527    }
528
529    /**
530     * Gets the first paragraph line indent.
531     *
532     * @return the indent
533     */
534    public float getIndent() {
535        return column.getIndent();
536    }
537
538    /**
539     * Gets the extra space between paragraphs.
540     *
541     * @return the extra space between paragraphs
542     */
543    public float getExtraParagraphSpace() {
544        return column.getExtraParagraphSpace();
545    }
546
547    /**
548     * Sets the extra space between paragraphs.
549     *
550     * @param extraParagraphSpace the extra space between paragraphs
551     */
552    public void setExtraParagraphSpace(float extraParagraphSpace) {
553        column.setExtraParagraphSpace(extraParagraphSpace);
554    }
555
556    /**
557     * Set a fixed height for the cell.
558     * This will automatically unset minimumHeight, if set.
559     *
560     * @param fixedHeight New value of property fixedHeight.
561     */
562    public void setFixedHeight(float fixedHeight) {
563        this.fixedHeight = fixedHeight;
564        minimumHeight = 0;
565    }
566
567    /**
568     * Get the fixed height of the cell.
569     *
570     * @return Value of property fixedHeight.
571     */
572    public float getFixedHeight() {
573        return fixedHeight;
574    }
575
576    /**
577     * Tells you whether the cell has a fixed height.
578     *
579     * @return  true is a fixed height was set.
580     * @since 2.1.5
581     */
582    public boolean hasFixedHeight() {
583        return getFixedHeight() > 0;
584    }
585
586    /**
587     * Set a minimum height for the cell.
588     * This will automatically unset fixedHeight, if set.
589     *
590     * @param minimumHeight New value of property minimumHeight.
591     */
592    public void setMinimumHeight(float minimumHeight) {
593        this.minimumHeight = minimumHeight;
594        fixedHeight = 0;
595    }
596
597    /**
598     * Get the minimum height of the cell.
599     *
600     * @return Value of property minimumHeight.
601     */
602    public float getMinimumHeight() {
603        return minimumHeight;
604    }
605
606    /**
607     * Tells you whether the cell has a minimum height.
608     *
609     * @return  true if a minimum height was set.
610     * @since 2.1.5
611     */
612    public boolean hasMinimumHeight() {
613        return getMinimumHeight() > 0;
614    }
615
616    /**
617     * Getter for property noWrap.
618     *
619     * @return Value of property noWrap.
620     */
621    public boolean isNoWrap() {
622        return noWrap;
623    }
624
625    /**
626     * Setter for property noWrap.
627     *
628     * @param noWrap New value of property noWrap.
629     */
630    public void setNoWrap(boolean noWrap) {
631        this.noWrap = noWrap;
632    }
633
634    /**
635     * Getter for property table.
636     *
637     * @return Value of property table.
638     * @since 2.x
639     */
640    public PdfPTable getTable() {
641        return table;
642    }
643
644    void setTable(PdfPTable table) {
645        this.table = table;
646        column.setText(null);
647        image = null;
648        if (table != null) {
649            table.setExtendLastRow(verticalAlignment == Element.ALIGN_TOP);
650            column.addElement(table);
651            table.setWidthPercentage(100);
652        }
653    }
654
655    /**
656     * Getter for property colspan.
657     *
658     * @return Value of property colspan.
659     */
660    public int getColspan() {
661        return colspan;
662    }
663
664    /**
665     * Setter for property colspan.
666     *
667     * @param colspan New value of property colspan.
668     */
669    public void setColspan(int colspan) {
670        this.colspan = colspan;
671    }
672
673    /**
674     * Getter for property rowspan.
675     *
676     * @return Value of property rowspan.
677     * @since   2.1.6
678     */
679    public int getRowspan() {
680        return rowspan;
681    }
682
683    /**
684     * Setter for property rowspan.
685     *
686     * @param rowspan New value of property rowspan.
687     * @since   2.1.6
688     */
689    public void setRowspan(int rowspan) {
690        this.rowspan = rowspan;
691    }
692
693    /**
694     * Sets the following paragraph lines indent.
695     *
696     * @param indent the indent
697     */
698    public void setFollowingIndent(float indent) {
699        column.setFollowingIndent(indent);
700    }
701
702    /**
703     * Gets the following paragraph lines indent.
704     *
705     * @return the indent
706     */
707    public float getFollowingIndent() {
708        return column.getFollowingIndent();
709    }
710
711    /**
712     * Sets the right paragraph lines indent.
713     *
714     * @param indent the indent
715     */
716    public void setRightIndent(float indent) {
717        column.setRightIndent(indent);
718    }
719
720    /**
721     * Gets the right paragraph lines indent.
722     *
723     * @return the indent
724     */
725    public float getRightIndent() {
726        return column.getRightIndent();
727    }
728
729    /**
730     * Gets the space/character extra spacing ratio for fully justified text.
731     *
732     * @return the space/character extra spacing ratio
733     */
734    public float getSpaceCharRatio() {
735        return column.getSpaceCharRatio();
736    }
737
738    /** Sets the ratio between the extra word spacing and the
739     * extra character spacing when the text is fully justified.
740     * Extra word spacing will grow <CODE>spaceCharRatio</CODE> times more
741     * than extra character spacing.
742     * If the ratio is <CODE>PdfWriter.NO_SPACE_CHAR_RATIO</CODE> then the
743     * extra character spacing will be zero.
744     *
745     * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing
746     */
747    public void setSpaceCharRatio(float spaceCharRatio) {
748        column.setSpaceCharRatio(spaceCharRatio);
749    }
750
751    /**
752     * Sets the run direction of the text content in the cell.
753     * May be either of:
754     * PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI,
755     * PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL.
756     * @param runDirection
757     */
758    public void setRunDirection(int runDirection) {
759        column.setRunDirection(runDirection);
760    }
761
762    /**
763     * Gets the run direction of the text content in the cell
764     *
765     * @return One of the following values:
766     * PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI,
767     * PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL.
768     */
769    public int getRunDirection() {
770        return column.getRunDirection();
771    }
772
773    /**
774     * Getter for property image.
775     *
776     * @return Value of property image.
777     */
778    public Image getImage() {
779        return image;
780    }
781
782    /**
783     * Setter for property image.
784     *
785     * @param image New value of property image.
786     */
787    public void setImage(Image image) {
788        column.setText(null);
789        table = null;
790        this.image = image;
791    }
792
793    /**
794     * Gets the cell event for this cell.
795     *
796     * @return the cell event
797     */
798    public PdfPCellEvent getCellEvent() {
799        return cellEvent;
800    }
801
802    /**
803     * Sets the cell event for this cell.
804     *
805     * @param cellEvent the cell event
806     */
807    public void setCellEvent(PdfPCellEvent cellEvent) {
808        if (cellEvent == null)
809                this.cellEvent = null;
810        else if (this.cellEvent == null)
811                this.cellEvent = cellEvent;
812        else if (this.cellEvent instanceof PdfPCellEventForwarder)
813                ((PdfPCellEventForwarder)this.cellEvent).addCellEvent(cellEvent);
814        else {
815                PdfPCellEventForwarder forward = new PdfPCellEventForwarder();
816                forward.addCellEvent(this.cellEvent);
817                forward.addCellEvent(cellEvent);
818                this.cellEvent = forward;
819        }
820    }
821
822    /**
823     * Gets the arabic shaping options.
824     *
825     * @return the arabic shaping options
826     */
827    public int getArabicOptions() {
828        return column.getArabicOptions();
829    }
830
831    /**
832     * Sets the arabic shaping options.
833     * The option can be AR_NOVOWEL, AR_COMPOSEDTASHKEEL and AR_LIG.
834     *
835     * @param arabicOptions the arabic shaping options
836     */
837    public void setArabicOptions(int arabicOptions) {
838        column.setArabicOptions(arabicOptions);
839    }
840
841    /**
842     * Gets state of first line height based on max ascender
843     *
844     * @return true if an ascender is to be used.
845     */
846    public boolean isUseAscender() {
847        return column.isUseAscender();
848    }
849
850    /**
851     * Enables/ Disables adjustment of first line height based on max ascender.
852     *
853     * @param useAscender adjust height if true
854     */
855    public void setUseAscender(boolean useAscender) {
856        column.setUseAscender(useAscender);
857    }
858
859
860    /**
861     * Getter for property useDescender.
862     *
863     * @return Value of property useDescender.
864     */
865    public boolean isUseDescender() {
866        return useDescender;
867    }
868
869    /**
870     * Setter for property useDescender.
871     *
872     * @param useDescender New value of property useDescender.
873     */
874    public void setUseDescender(boolean useDescender) {
875        this.useDescender = useDescender;
876    }
877
878    /**
879     * Gets the ColumnText with the content of the cell.
880     *
881     * @return a columntext object
882     */
883    public ColumnText getColumn() {
884        return column;
885    }
886
887    /**
888     * Returns the list of composite elements of the column.
889     *
890     * @return  a List object.
891     * @since   2.1.1
892     */
893    public List<Element> getCompositeElements() {
894        return getColumn().compositeElements;
895    }
896
897    /**
898     * Sets the columntext in the cell.
899     *
900     * @param column
901     */
902    public void setColumn(ColumnText column) {
903        this.column = column;
904    }
905
906    /**
907     * Gets the rotation of the cell.
908     *
909     * @return the rotation of the cell.
910     */
911    @Override
912    public int getRotation() {
913        return rotation;
914    }
915
916    /**
917     * Sets the rotation of the cell.
918     * Possible values are 0, 90, 180 and 270.
919     *
920     * @param rotation the rotation of the cell
921     */
922    public void setRotation(int rotation) {
923        rotation %= 360;
924        if (rotation < 0)
925            rotation += 360;
926        if (rotation % 90 != 0)
927            throw new IllegalArgumentException(MessageLocalization.getComposedMessage("rotation.must.be.a.multiple.of.90"));
928        this.rotation = rotation;
929    }
930
931        /**
932         * Returns the height of the cell.
933         * @return      the height of the cell
934         * @since       3.0.0
935         */
936        public float getMaxHeight() {
937                boolean pivoted = getRotation() == 90 || getRotation() == 270;
938                Image img = getImage();
939                if (img != null) {
940                        img.scalePercent(100);
941                        float refWidth = pivoted ? img.getScaledHeight() : img.getScaledWidth();
942                        float scale = (getRight() - getEffectivePaddingRight()
943                    - getEffectivePaddingLeft() - getLeft()) / refWidth;
944                        img.scalePercent(scale * 100);
945                        float refHeight = pivoted ? img.getScaledWidth() : img.getScaledHeight();
946                        setBottom(getTop() - getEffectivePaddingTop() - getEffectivePaddingBottom() - refHeight);
947                }
948                else {
949                        if (pivoted && hasFixedHeight())
950                                setBottom(getTop() - getFixedHeight());
951                        else {
952                                ColumnText ct = ColumnText.duplicate(getColumn());
953                                float right, top, left, bottom;
954                                if (pivoted) {
955                                        right = PdfPRow.RIGHT_LIMIT;
956                                        top = getRight() - getEffectivePaddingRight();
957                                        left = 0;
958                                        bottom = getLeft() + getEffectivePaddingLeft();
959                                }
960                                else {
961                                        right = isNoWrap() ? PdfPRow.RIGHT_LIMIT : getRight() - getEffectivePaddingRight();
962                                        top = getTop() - getEffectivePaddingTop();
963                                        left = getLeft() + getEffectivePaddingLeft();
964                                        bottom = hasFixedHeight() ? getTop() + getEffectivePaddingBottom() - getFixedHeight() : PdfPRow.BOTTOM_LIMIT;
965                                }
966                                PdfPRow.setColumn(ct, left, bottom, right, top);
967                                try {
968                                        ct.go(true);
969                                } catch (DocumentException e) {
970                                        throw new ExceptionConverter(e);
971                                }
972                                if (pivoted)
973                                        setBottom(getTop() - getEffectivePaddingTop() - getEffectivePaddingBottom() - ct.getFilledWidth());
974                                else {
975                                        float yLine = ct.getYLine();
976                                        if (isUseDescender())
977                                                yLine += ct.getDescender();
978                                        setBottom(yLine - getEffectivePaddingBottom());
979                                }
980                        }
981                }
982                float height = getHeight();
983                if (hasFixedHeight())
984                        height = getFixedHeight();
985                else if (hasMinimumHeight() && height < getMinimumHeight())
986                        height = getMinimumHeight();
987                return height;
988        }
989}