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

49
50 package com.lowagie.text;
51
52 import java.awt.Color;
53 import java.net.URL;
54 import java.util.ArrayList;
55 import java.util.HashMap;
56
57 import com.lowagie.text.pdf.HyphenationEvent;
58 import com.lowagie.text.pdf.PdfAction;
59 import com.lowagie.text.pdf.PdfAnnotation;
60 import com.lowagie.text.pdf.PdfContentByte;
61 import com.lowagie.text.pdf.draw.DrawInterface;
62
63 /**
64  * This is the smallest significant part of text that can be added to a
65  * document.
66  * <P>
67  * Most elements can be divided in one or more <CODE>Chunk</CODE>s. A chunk
68  * is a <CODE>String</CODE> with a certain <CODE>Font</CODE>. All other
69  * layout parameters should be defined in the object to which this chunk of text
70  * is added.
71  * <P>
72  * Example: <BLOCKQUOTE>
73  * 
74  * <PRE>
75  * 
76  * <STRONG>Chunk chunk = new Chunk("Hello world",
77  * FontFactory.getFont(FontFactory.COURIER, 20, Font.ITALIC, new Color(255, 0,
78  * 0))); </STRONG> document.add(chunk);
79  * 
80  * </PRE>
81  * 
82  * </BLOCKQUOTE>
83  */

84
85 public class Chunk implements Element {
86
87     // public static membervariables
88
89     /** The character stand in for an image or a separator. */
90     public static final String OBJECT_REPLACEMENT_CHARACTER = "\ufffc";
91
92     /** This is a Chunk containing a newline. */
93     public static final Chunk NEWLINE = new Chunk("\n");
94
95     /** This is a Chunk containing a newpage. */
96     public static final Chunk NEXTPAGE = new Chunk("");
97     static {
98         NEXTPAGE.setNewPage();
99     }
100
101     // member variables
102
103     /** This is the content of this chunk of text. */
104     protected StringBuffer content = null;
105
106     /** This is the <CODE>Font</CODE> of this chunk of text. */
107     protected Font font = null;
108
109     /** Contains some of the attributes for this Chunk. */
110     protected HashMap attributes = null;
111
112     // constructors
113
114     /**
115      * Empty constructor.
116      */

117     public Chunk() {
118         this.content = new StringBuffer();
119         this.font = new Font();
120     }
121
122     /**
123      * A <CODE>Chunk</CODE> copy constructor.
124      * @param ck the <CODE>Chunk</CODE> to be copied
125      */
    
126     public Chunk(Chunk ck) {
127         if (ck.content != null) {
128             content = new StringBuffer(ck.content.toString());
129         }
130         if (ck.font != null) {
131             font = new Font(ck.font);
132         }
133         if (ck.attributes != null) {
134             attributes = new HashMap(ck.attributes);
135         }
136     }
137     
138     /**
139      * Constructs a chunk of text with a certain content and a certain <CODE>
140      * Font</CODE>.
141      * 
142      * @param content
143      *            the content
144      * @param font
145      *            the font
146      */

147     public Chunk(String content, Font font) {
148         this.content = new StringBuffer(content);
149         this.font = font;
150     }
151
152     /**
153      * Constructs a chunk of text with a certain content, without specifying a
154      * <CODE>Font</CODE>.
155      * 
156      * @param content
157      *            the content
158      */

159     public Chunk(String content) {
160         this(content, new Font());
161     }
162
163     /**
164      * Constructs a chunk of text with a char and a certain <CODE>Font</CODE>.
165      * 
166      * @param c
167      *            the content
168      * @param font
169      *            the font
170      */

171     public Chunk(char c, Font font) {
172         this.content = new StringBuffer();
173         this.content.append(c);
174         this.font = font;
175     }
176
177     /**
178      * Constructs a chunk of text with a char, without specifying a <CODE>Font
179      * </CODE>.
180      * 
181      * @param c
182      *            the content
183      */

184     public Chunk(char c) {
185         this(c, new Font());
186     }
187
188     /**
189      * Constructs a chunk containing an <CODE>Image</CODE>.
190      * 
191      * @param image
192      *            the image
193      * @param offsetX
194      *            the image offset in the x direction
195      * @param offsetY
196      *            the image offset in the y direction
197      */

198     public Chunk(Image image, float offsetX, float offsetY) {
199         this(OBJECT_REPLACEMENT_CHARACTER, new Font());
200         Image copyImage = Image.getInstance(image);
201         copyImage.setAbsolutePosition(Float.NaN, Float.NaN);
202         setAttribute(IMAGE, new Object[] { copyImage, new Float(offsetX),
203                 new Float(offsetY), Boolean.FALSE });
204     }
205
206     /**
207      * Key for drawInterface of the Separator.
208      * @since    2.1.2
209      */

210     public static final String SEPARATOR = "SEPARATOR";
211     
212     /**
213      * Creates a separator Chunk.
214      * Note that separator chunks can't be used in combination with tab chunks!
215      * @param    separator    the drawInterface to use to draw the separator.
216      * @since    2.1.2
217      */

218     public Chunk(DrawInterface separator) {
219         this(separator, false);
220     }    
221     
222     /**
223      * Creates a separator Chunk.
224      * Note that separator chunks can't be used in combination with tab chunks!
225      * @param    separator    the drawInterface to use to draw the separator.
226      * @param    vertical    true if this is a vertical separator
227      * @since    2.1.2
228      */

229     public Chunk(DrawInterface separator, boolean vertical) {
230         this(OBJECT_REPLACEMENT_CHARACTER, new Font());
231         setAttribute(SEPARATOR, new Object[] {separator, Boolean.valueOf(vertical)});
232     }
233
234     /**
235      * Key for drawInterface of the tab.
236      * @since    2.1.2
237      */

238     public static final String TAB = "TAB";
239     
240     /**
241      * Creates a tab Chunk.
242      * Note that separator chunks can't be used in combination with tab chunks!
243      * @param    separator    the drawInterface to use to draw the tab.
244      * @param    tabPosition    an X coordinate that will be used as start position for the next Chunk.
245      * @since    2.1.2
246      */

247     public Chunk(DrawInterface separator, float tabPosition) {
248         this(separator, tabPosition, false);
249     }
250     
251     /**
252      * Creates a tab Chunk.
253      * Note that separator chunks can't be used in combination with tab chunks!
254      * @param    separator    the drawInterface to use to draw the tab.
255      * @param    tabPosition    an X coordinate that will be used as start position for the next Chunk.
256      * @param    newline        if true, a newline will be added if the tabPosition has already been reached.
257      * @since    2.1.2
258      */

259     public Chunk(DrawInterface separator, float tabPosition, boolean newline) {
260         this(OBJECT_REPLACEMENT_CHARACTER, new Font());
261         if (tabPosition < 0) {
262             throw new IllegalArgumentException("A tab position may not be lower than 0; yours is " + tabPosition);
263         }
264         setAttribute(TAB, new Object[] {separator, new Float(tabPosition), Boolean.valueOf(newline), new Float(0)});
265     }
266
267     /**
268      * Constructs a chunk containing an <CODE>Image</CODE>.
269      * 
270      * @param image
271      *            the image
272      * @param offsetX
273      *            the image offset in the x direction
274      * @param offsetY
275      *            the image offset in the y direction
276      * @param changeLeading
277      *            true if the leading has to be adapted to the image
278      */

279     public Chunk(Image image, float offsetX, float offsetY,
280             boolean changeLeading) {
281         this(OBJECT_REPLACEMENT_CHARACTER, new Font());
282         setAttribute(IMAGE, new Object[] { image, new Float(offsetX),
283                 new Float(offsetY), Boolean.valueOf(changeLeading) });
284     }
285
286     // implementation of the Element-methods
287
288     /**
289      * Processes the element by adding it (or the different parts) to an <CODE>
290      * ElementListener</CODE>.
291      * 
292      * @param listener
293      *            an <CODE>ElementListener</CODE>
294      * @return <CODE>true</CODE> if the element was processed successfully
295      */

296     public boolean process(ElementListener listener) {
297         try {
298             return listener.add(this);
299         } catch (DocumentException de) {
300             return false;
301         }
302     }
303
304     /**
305      * Gets the type of the text element.
306      * 
307      * @return a type
308      */

309     public int type() {
310         return Element.CHUNK;
311     }
312
313     /**
314      * Gets all the chunks in this element.
315      * 
316      * @return an <CODE>ArrayList</CODE>
317      */

318     public ArrayList getChunks() {
319         ArrayList tmp = new ArrayList();
320         tmp.add(this);
321         return tmp;
322     }
323
324     // methods that change the member variables
325
326     /**
327      * appends some text to this <CODE>Chunk</CODE>.
328      * 
329      * @param string
330      *            <CODE>String</CODE>
331      * @return a <CODE>StringBuffer</CODE>
332      */

333     public StringBuffer append(String string) {
334         return content.append(string);
335     }
336
337     /**
338      * Sets the font of this <CODE>Chunk</CODE>.
339      * 
340      * @param font
341      *            a <CODE>Font</CODE>
342      */

343     public void setFont(Font font) {
344         this.font = font;
345     }
346
347     // methods to retrieve information
348
349     /**
350      * Gets the font of this <CODE>Chunk</CODE>.
351      * 
352      * @return a <CODE>Font</CODE>
353      */

354     public Font getFont() {
355         return font;
356     }
357
358     /**
359      * Returns the content of this <CODE>Chunk</CODE>.
360      * 
361      * @return a <CODE>String</CODE>
362      */

363     public String getContent() {
364         return content.toString();
365     }
366
367     /**
368      * Returns the content of this <CODE>Chunk</CODE>.
369      * 
370      * @return a <CODE>String</CODE>
371      */

372     public String toString() {
373         return getContent();
374     }
375
376     /**
377      * Checks is this <CODE>Chunk</CODE> is empty.
378      * 
379      * @return <CODE>false</CODE> if the Chunk contains other characters than
380      *         space.
381      */

382     public boolean isEmpty() {
383         return (content.toString().trim().length() == 0)
384                 && (content.toString().indexOf("\n") == -1)
385                 && (attributes == null);
386     }
387
388     /**
389      * Gets the width of the Chunk in points.
390      * 
391      * @return a width in points
392      */

393     public float getWidthPoint() {
394         if (getImage() != null) {
395             return getImage().getScaledWidth();
396         }
397         return font.getCalculatedBaseFont(true).getWidthPoint(getContent(),
398                 font.getCalculatedSize())
399                 * getHorizontalScaling();
400     }
401
402     // attributes
403
404     /**
405      * Checks the attributes of this <CODE>Chunk</CODE>.
406      * 
407      * @return false if there aren't any.
408      */

409
410     public boolean hasAttributes() {
411         return attributes != null;
412     }
413
414     /**
415      * Gets the attributes for this <CODE>Chunk</CODE>.
416      * <P>
417      * It may be null.
418      * 
419      * @return the attributes for this <CODE>Chunk</CODE>
420      */

421
422     public HashMap getAttributes() {
423         return attributes;
424     }
425
426     /**
427      * Sets the attributes all at once.
428      * @param    attributes    the attributes of a Chunk
429      */

430     public void setAttributes(HashMap attributes) {
431         this.attributes = attributes;
432     }
433
434     /**
435      * Sets an arbitrary attribute.
436      * 
437      * @param name
438      *            the key for the attribute
439      * @param obj
440      *            the value of the attribute
441      * @return this <CODE>Chunk</CODE>
442      */

443
444     private Chunk setAttribute(String name, Object obj) {
445         if (attributes == null)
446             attributes = new HashMap();
447         attributes.put(name, obj);
448         return this;
449     }
450
451     // the attributes are ordered as they appear in the book 'iText in Action'
452
453     /** Key for text horizontal scaling. */
454     public static final String HSCALE = "HSCALE";
455
456     /**
457      * Sets the text horizontal scaling. A value of 1 is normal and a value of
458      * 0.5f shrinks the text to half it's width.
459      * 
460      * @param scale
461      *            the horizontal scaling factor
462      * @return this <CODE>Chunk</CODE>
463      */

464     public Chunk setHorizontalScaling(float scale) {
465         return setAttribute(HSCALE, new Float(scale));
466     }
467
468     /**
469      * Gets the horizontal scaling.
470      * 
471      * @return a percentage in float
472      */

473     public float getHorizontalScaling() {
474         if (attributes == null)
475             return 1f;
476         Float f = (Float) attributes.get(HSCALE);
477         if (f == null)
478             return 1f;
479         return f.floatValue();
480     }
481
482     /** Key for underline. */
483     public static final String UNDERLINE = "UNDERLINE";
484
485     /**
486      * Sets an horizontal line that can be an underline or a strikethrough.
487      * Actually, the line can be anywhere vertically and has always the <CODE>
488      * Chunk</CODE> width. Multiple call to this method will produce multiple
489      * lines.
490      * 
491      * @param thickness
492      *            the absolute thickness of the line
493      * @param yPosition
494      *            the absolute y position relative to the baseline
495      * @return this <CODE>Chunk</CODE>
496      */

497     public Chunk setUnderline(float thickness, float yPosition) {
498         return setUnderline(null, thickness, 0f, yPosition, 0f,
499                 PdfContentByte.LINE_CAP_BUTT);
500     }
501
502     /**
503      * Sets an horizontal line that can be an underline or a strikethrough.
504      * Actually, the line can be anywhere vertically and has always the <CODE>
505      * Chunk</CODE> width. Multiple call to this method will produce multiple
506      * lines.
507      * 
508      * @param color
509      *            the color of the line or <CODE>null</CODE> to follow the
510      *            text color
511      * @param thickness
512      *            the absolute thickness of the line
513      * @param thicknessMul
514      *            the thickness multiplication factor with the font size
515      * @param yPosition
516      *            the absolute y position relative to the baseline
517      * @param yPositionMul
518      *            the position multiplication factor with the font size
519      * @param cap
520      *            the end line cap. Allowed values are
521      *            PdfContentByte.LINE_CAP_BUTT, PdfContentByte.LINE_CAP_ROUND
522      *            and PdfContentByte.LINE_CAP_PROJECTING_SQUARE
523      * @return this <CODE>Chunk</CODE>
524      */

525     public Chunk setUnderline(Color color, float thickness, float thicknessMul,
526             float yPosition, float yPositionMul, int cap) {
527         if (attributes == null)
528             attributes = new HashMap();
529         Object obj[] = {
530                 color,
531                 new float[] { thickness, thicknessMul, yPosition, yPositionMul, cap } };
532         Object unders[][] = Utilities.addToArray((Object[][]) attributes.get(UNDERLINE),
533                 obj);
534         return setAttribute(UNDERLINE, unders);
535     }
536     
537     /** Key for sub/superscript. */
538     public static final String SUBSUPSCRIPT = "SUBSUPSCRIPT";
539     
540     /**
541      * Sets the text displacement relative to the baseline. Positive values rise
542      * the text, negative values lower the text.
543      * <P>
544      * It can be used to implement sub/superscript.
545      * 
546      * @param rise
547      *            the displacement in points
548      * @return this <CODE>Chunk</CODE>
549      */

550
551     public Chunk setTextRise(float rise) {
552         return setAttribute(SUBSUPSCRIPT, new Float(rise));
553     }
554
555     /**
556      * Gets the text displacement relative to the baseline.
557      * 
558      * @return a displacement in points
559      */

560     public float getTextRise() {
561         if (attributes != null && attributes.containsKey(SUBSUPSCRIPT)) {
562             Float f = (Float) attributes.get(SUBSUPSCRIPT);
563             return f.floatValue();
564         }
565         return 0.0f;
566     }
567
568     /** Key for text skewing. */
569     public static final String SKEW = "SKEW";
570
571     /**
572      * Skews the text to simulate italic and other effects. Try <CODE>alpha=0
573      * </CODE> and <CODE>beta=12</CODE>.
574      * 
575      * @param alpha
576      *            the first angle in degrees
577      * @param beta
578      *            the second angle in degrees
579      * @return this <CODE>Chunk</CODE>
580      */

581     public Chunk setSkew(float alpha, float beta) {
582         alpha = (float) Math.tan(alpha * Math.PI / 180);
583         beta = (float) Math.tan(beta * Math.PI / 180);
584         return setAttribute(SKEW, new float[] { alpha, beta });
585     }
586
587     /** Key for background. */
588     public static final String BACKGROUND = "BACKGROUND";
589
590     /**
591      * Sets the color of the background <CODE>Chunk</CODE>.
592      * 
593      * @param color
594      *            the color of the background
595      * @return this <CODE>Chunk</CODE>
596      */

597     public Chunk setBackground(Color color) {
598         return setBackground(color, 0, 0, 0, 0);
599     }
600
601     /**
602      * Sets the color and the size of the background <CODE>Chunk</CODE>.
603      * 
604      * @param color
605      *            the color of the background
606      * @param extraLeft
607      *            increase the size of the rectangle in the left
608      * @param extraBottom
609      *            increase the size of the rectangle in the bottom
610      * @param extraRight
611      *            increase the size of the rectangle in the right
612      * @param extraTop
613      *            increase the size of the rectangle in the top
614      * @return this <CODE>Chunk</CODE>
615      */

616     public Chunk setBackground(Color color, float extraLeft, float extraBottom,
617             float extraRight, float extraTop) {
618         return setAttribute(BACKGROUND, new Object[] { color,
619                 new float[] { extraLeft, extraBottom, extraRight, extraTop } });
620     }
621
622     /** Key for text rendering mode. */
623     public static final String TEXTRENDERMODE = "TEXTRENDERMODE";
624
625     /**
626      * Sets the text rendering mode. It can outline text, simulate bold and make
627      * text invisible.
628      * 
629      * @param mode
630      *            the text rendering mode. It can be <CODE>
631      *            PdfContentByte.TEXT_RENDER_MODE_FILL</CODE>,<CODE>
632      *            PdfContentByte.TEXT_RENDER_MODE_STROKE</CODE>,<CODE>
633      *            PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE</CODE> and <CODE>
634      *            PdfContentByte.TEXT_RENDER_MODE_INVISIBLE</CODE>.
635      * @param strokeWidth
636      *            the stroke line width for the modes <CODE>
637      *            PdfContentByte.TEXT_RENDER_MODE_STROKE</CODE> and <CODE>
638      *            PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE</CODE>.
639      * @param strokeColor
640      *            the stroke color or <CODE>null</CODE> to follow the text
641      *            color
642      * @return this <CODE>Chunk</CODE>
643      */

644     public Chunk setTextRenderMode(int mode, float strokeWidth,
645             Color strokeColor) {
646         return setAttribute(TEXTRENDERMODE, new Object[] { new Integer(mode),
647                 new Float(strokeWidth), strokeColor });
648     }
649
650     /** Key for split character. */
651     public static final String SPLITCHARACTER = "SPLITCHARACTER";
652
653     /**
654      * Sets the split characters.
655      * 
656      * @param splitCharacter
657      *            the <CODE>SplitCharacter</CODE> interface
658      * @return this <CODE>Chunk</CODE>
659      */

660
661     public Chunk setSplitCharacter(SplitCharacter splitCharacter) {
662         return setAttribute(SPLITCHARACTER, splitCharacter);
663     }
664
665     /** Key for hyphenation. */
666     public static final String HYPHENATION = "HYPHENATION";
667     
668     /**
669      * sets the hyphenation engine to this <CODE>Chunk</CODE>.
670      * 
671      * @param hyphenation
672      *            the hyphenation engine
673      * @return this <CODE>Chunk</CODE>
674      */

675     public Chunk setHyphenation(HyphenationEvent hyphenation) {
676         return setAttribute(HYPHENATION, hyphenation);
677     }
678
679     /** Key for remote goto. */
680     public static final String REMOTEGOTO = "REMOTEGOTO";
681
682     /**
683      * Sets a goto for a remote destination for this <CODE>Chunk</CODE>.
684      * 
685      * @param filename
686      *            the file name of the destination document
687      * @param name
688      *            the name of the destination to go to
689      * @return this <CODE>Chunk</CODE>
690      */

691
692     public Chunk setRemoteGoto(String filename, String name) {
693         return setAttribute(REMOTEGOTO, new Object[] { filename, name });
694     }
695
696     /**
697      * Sets a goto for a remote destination for this <CODE>Chunk</CODE>.
698      * 
699      * @param filename
700      *            the file name of the destination document
701      * @param page
702      *            the page of the destination to go to. First page is 1
703      * @return this <CODE>Chunk</CODE>
704      */

705
706     public Chunk setRemoteGoto(String filename, int page) {
707         return setAttribute(REMOTEGOTO, new Object[] { filename,
708                 new Integer(page) });
709     }
710
711     /** Key for local goto. */
712     public static final String LOCALGOTO = "LOCALGOTO";
713     
714     /**
715      * Sets a local goto for this <CODE>Chunk</CODE>.
716      * <P>
717      * There must be a local destination matching the name.
718      * 
719      * @param name
720      *            the name of the destination to go to
721      * @return this <CODE>Chunk</CODE>
722      */

723
724     public Chunk setLocalGoto(String name) {
725         return setAttribute(LOCALGOTO, name);
726     }
727
728     /** Key for local destination. */
729     public static final String LOCALDESTINATION = "LOCALDESTINATION";
730
731     /**
732      * Sets a local destination for this <CODE>Chunk</CODE>.
733      * 
734      * @param name
735      *            the name for this destination
736      * @return this <CODE>Chunk</CODE>
737      */

738     public Chunk setLocalDestination(String name) {
739         return setAttribute(LOCALDESTINATION, name);
740     }
741
742     /** Key for generic tag. */
743     public static final String GENERICTAG = "GENERICTAG";
744
745     /**
746      * Sets the generic tag <CODE>Chunk</CODE>.
747      * <P>
748      * The text for this tag can be retrieved with <CODE>PdfPageEvent</CODE>.
749      * 
750      * @param text
751      *            the text for the tag
752      * @return this <CODE>Chunk</CODE>
753      */

754
755     public Chunk setGenericTag(String text) {
756         return setAttribute(GENERICTAG, text);
757     }
758     
759     /** Key for image. */
760     public static final String IMAGE = "IMAGE";
761
762     /**
763      * Returns the image.
764      * 
765      * @return the image
766      */

767
768     public Image getImage() {
769         if (attributes == null)
770             return null;
771         Object obj[] = (Object[]) attributes.get(Chunk.IMAGE);
772         if (obj == null)
773             return null;
774         else {
775             return (Image) obj[0];
776         }
777     }
778     
779     /** Key for Action. */
780     public static final String ACTION = "ACTION";
781
782     /**
783      * Sets an action for this <CODE>Chunk</CODE>.
784      * 
785      * @param action
786      *            the action
787      * @return this <CODE>Chunk</CODE>
788      */

789
790     public Chunk setAction(PdfAction action) {
791         return setAttribute(ACTION, action);
792     }
793
794     /**
795      * Sets an anchor for this <CODE>Chunk</CODE>.
796      * 
797      * @param url
798      *            the <CODE>URL</CODE> to link to
799      * @return this <CODE>Chunk</CODE>
800      */

801
802     public Chunk setAnchor(URL url) {
803         return setAttribute(ACTION, new PdfAction(url.toExternalForm()));
804     }
805
806     /**
807      * Sets an anchor for this <CODE>Chunk</CODE>.
808      * 
809      * @param url
810      *            the url to link to
811      * @return this <CODE>Chunk</CODE>
812      */

813
814     public Chunk setAnchor(String url) {
815         return setAttribute(ACTION, new PdfAction(url));
816     }
817     
818     /** Key for newpage. */
819     public static final String NEWPAGE = "NEWPAGE";
820
821     /**
822      * Sets a new page tag..
823      * 
824      * @return this <CODE>Chunk</CODE>
825      */

826
827     public Chunk setNewPage() {
828         return setAttribute(NEWPAGE, null);
829     }
830
831     /** Key for annotation. */
832     public static final String PDFANNOTATION = "PDFANNOTATION";
833
834     /**
835      * Sets a generic annotation to this <CODE>Chunk</CODE>.
836      * 
837      * @param annotation
838      *            the annotation
839      * @return this <CODE>Chunk</CODE>
840      */

841     public Chunk setAnnotation(PdfAnnotation annotation) {
842         return setAttribute(PDFANNOTATION, annotation);
843     }
844     
845     /**
846      * @see com.lowagie.text.Element#isContent()
847      * @since    iText 2.0.8
848      */

849     public boolean isContent() {
850         return true;
851     }
852
853     /**
854      * @see com.lowagie.text.Element#isNestable()
855      * @since    iText 2.0.8
856      */

857     public boolean isNestable() {
858         return true;
859     }
860
861     /**
862      * Returns the hyphenation (if present).
863      * @since    2.1.2
864      */

865     public HyphenationEvent getHyphenation() {
866         if (attributes == nullreturn null;
867         return (HyphenationEvent) attributes.get(Chunk.HYPHENATION);
868     }
869     
870     // keys used in PdfChunk
871     
872     /** Key for color. */
873     public static final String COLOR = "COLOR";
874
875     /** Key for encoding. */
876     public static final String ENCODING = "ENCODING";
877
878 }