KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > Phrase


1 /*
2  * $Id: Phrase.java 2748 2007-05-12 15:11:48Z blowagie $
3  * $Name$
4  *
5  * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
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;
52
53 import java.util.ArrayList JavaDoc;
54 import java.util.Collection JavaDoc;
55 import java.util.Iterator JavaDoc;
56 import java.util.Properties JavaDoc;
57
58 /**
59  * A <CODE>Phrase</CODE> is a series of <CODE>Chunk</CODE>s.
60  * <P>
61  * A <CODE>Phrase</CODE> has a main <CODE>Font</CODE>, but some chunks
62  * within the phrase can have a <CODE>Font</CODE> that differs from the
63  * main <CODE>Font</CODE>. All the <CODE>Chunk</CODE>s in a <CODE>Phrase</CODE>
64  * have the same <CODE>leading</CODE>.
65  * <P>
66  * Example:
67  * <BLOCKQUOTE><PRE>
68  * // When no parameters are passed, the default leading = 16
69  * <STRONG>Phrase phrase0 = new Phrase();</STRONG>
70  * <STRONG>Phrase phrase1 = new Phrase("this is a phrase");</STRONG>
71  * // In this example the leading is passed as a parameter
72  * <STRONG>Phrase phrase2 = new Phrase(16, "this is a phrase with leading 16");</STRONG>
73  * // When a Font is passed (explicitely or embedded in a chunk), the default leading = 1.5 * size of the font
74  * <STRONG>Phrase phrase3 = new Phrase("this is a phrase with a red, normal font Courier, size 12", FontFactory.getFont(FontFactory.COURIER, 12, Font.NORMAL, new Color(255, 0, 0)));</STRONG>
75  * <STRONG>Phrase phrase4 = new Phrase(new Chunk("this is a phrase"));</STRONG>
76  * <STRONG>Phrase phrase5 = new Phrase(18, new Chunk("this is a phrase", FontFactory.getFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0)));</STRONG>
77  * </PRE></BLOCKQUOTE>
78  *
79  * @see Element
80  * @see Chunk
81  * @see Paragraph
82  * @see Anchor
83  */

84
85 public class Phrase extends ArrayList JavaDoc implements TextElementArray {
86     
87     // constants
88
private static final long serialVersionUID = 2643594602455068231L;
89
90     // membervariables
91
/** This is the leading of this phrase. */
92     protected float leading = Float.NaN;
93     
94     /** This is the font of this phrase. */
95     protected Font font = new Font();
96     
97     // constructors
98

99     /**
100      * Constructs a <CODE>Phrase</CODE> without specifying a leading.
101      */

102     public Phrase() {
103         this(16);
104     }
105     
106     /**
107      * Copy constructor for <CODE>Phrase</CODE>.
108      */

109     public Phrase(Phrase phrase) {
110         super(phrase);
111         leading = phrase.getLeading();
112         font = phrase.getFont();
113     }
114     
115     /**
116      * Constructs a <CODE>Phrase</CODE> with a certain leading.
117      *
118      * @param leading the leading
119      */

120     public Phrase(float leading) {
121         this.leading = leading;
122     }
123     
124     /**
125      * Constructs a <CODE>Phrase</CODE> with a certain <CODE>Chunk</CODE>.
126      *
127      * @param chunk a <CODE>Chunk</CODE>
128      */

129     public Phrase(Chunk chunk) {
130         super.add(chunk);
131         font = chunk.getFont();
132     }
133     
134     /**
135      * Constructs a <CODE>Phrase</CODE> with a certain <CODE>Chunk</CODE>
136      * and a certain leading.
137      *
138      * @param leading the leading
139      * @param chunk a <CODE>Chunk</CODE>
140      */

141     public Phrase(float leading, Chunk chunk) {
142         this(leading);
143         super.add(chunk);
144         font = chunk.getFont();
145     }
146     
147     /**
148      * Constructs a <CODE>Phrase</CODE> with a certain <CODE>String</CODE>.
149      *
150      * @param string a <CODE>String</CODE>
151      */

152     public Phrase(String JavaDoc string) {
153         this(Float.NaN, string, new Font());
154     }
155     
156     /**
157      * Constructs a <CODE>Phrase</CODE> with a certain <CODE>String</CODE> and a certain <CODE>Font</CODE>.
158      *
159      * @param string a <CODE>String</CODE>
160      * @param font a <CODE>Font</CODE>
161      */

162     public Phrase(String JavaDoc string, Font font) {
163         this(Float.NaN, string, font);
164         this.font = font;
165     }
166     
167     /**
168      * Constructs a <CODE>Phrase</CODE> with a certain leading and a certain <CODE>String</CODE>.
169      *
170      * @param leading the leading
171      * @param string a <CODE>String</CODE>
172      */

173     public Phrase(float leading, String JavaDoc string) {
174         this(leading, string, new Font());
175     }
176     
177     /**
178      * Constructs a <CODE>Phrase</CODE> with a certain leading, a certain <CODE>String</CODE>
179      * and a certain <CODE>Font</CODE>.
180      *
181      * @param leading the leading
182      * @param string a <CODE>String</CODE>
183      * @param font a <CODE>Font</CODE>
184      */

185     public Phrase(float leading, String JavaDoc string, Font font) {
186         this(leading);
187         this.font = font;
188         /* bugfix by August Detlefsen */
189         if (string != null && string.length() != 0) {
190             super.add(new Chunk(string, font));
191         }
192     }
193     
194     // implementation of the Element-methods
195

196     /**
197      * Processes the element by adding it (or the different parts) to an
198      * <CODE>ElementListener</CODE>.
199      *
200      * @param listener an <CODE>ElementListener</CODE>
201      * @return <CODE>true</CODE> if the element was processed successfully
202      */

203     public boolean process(ElementListener listener) {
204         try {
205             for (Iterator JavaDoc i = iterator(); i.hasNext(); ) {
206                 listener.add((Element) i.next());
207             }
208             return true;
209         }
210         catch(DocumentException de) {
211             return false;
212         }
213     }
214     
215     /**
216      * Gets the type of the text element.
217      *
218      * @return a type
219      */

220     public int type() {
221         return Element.PHRASE;
222     }
223     
224     /**
225      * Gets all the chunks in this element.
226      *
227      * @return an <CODE>ArrayList</CODE>
228      */

229     public ArrayList JavaDoc getChunks() {
230         ArrayList JavaDoc tmp = new ArrayList JavaDoc();
231         for (Iterator JavaDoc i = iterator(); i.hasNext(); ) {
232             tmp.addAll(((Element) i.next()).getChunks());
233         }
234         return tmp;
235     }
236     
237     // overriding some of the ArrayList-methods
238

239     /**
240      * Adds a <CODE>Chunk</CODE>, an <CODE>Anchor</CODE> or another <CODE>Phrase</CODE>
241      * to this <CODE>Phrase</CODE>.
242      *
243      * @param index index at which the specified element is to be inserted
244      * @param o an object of type <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
245      * @throws ClassCastException when you try to add something that isn't a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
246      */

247     public void add(int index, Object JavaDoc o) {
248         if (o == null) return;
249         try {
250             Element element = (Element) o;
251             if (element.type() == Element.CHUNK) {
252                 Chunk chunk = (Chunk) element;
253                 if (!font.isStandardFont()) {
254                     chunk.setFont(font.difference(chunk.getFont()));
255                 }
256                 super.add(index, chunk);
257             }
258             else if (element.type() == Element.PHRASE ||
259             element.type() == Element.ANCHOR ||
260             element.type() == Element.ANNOTATION ||
261             element.type() == Element.TABLE || // line added by David Freels
262
element.type() == Element.MARKED) {
263                 super.add(index, element);
264             }
265             else {
266                 throw new ClassCastException JavaDoc(String.valueOf(element.type()));
267             }
268         }
269         catch(ClassCastException JavaDoc cce) {
270             throw new ClassCastException JavaDoc("Insertion of illegal Element: " + cce.getMessage());
271         }
272     }
273     
274     /**
275      * Adds a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or another <CODE>Phrase</CODE>
276      * to this <CODE>Phrase</CODE>.
277      *
278      * @param o an object of type <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
279      * @return a boolean
280      * @throws ClassCastException when you try to add something that isn't a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
281      */

282     public boolean add(Object JavaDoc o) {
283         if (o == null) return false;
284         if (o instanceof String JavaDoc) {
285             return super.add(new Chunk((String JavaDoc) o, font));
286         }
287         try {
288             Element element = (Element) o;
289             switch(element.type()) {
290                 case Element.CHUNK:
291                     return addChunk((Chunk) o);
292                 case Element.PHRASE:
293                 case Element.PARAGRAPH:
294                     Phrase phrase = (Phrase) o;
295                     boolean success = true;
296                     Element e;
297                     for (Iterator JavaDoc i = phrase.iterator(); i.hasNext(); ) {
298                         e = (Element) i.next();
299                         if (e instanceof Chunk) {
300                             success &= addChunk((Chunk)e);
301                         }
302                         else {
303                             success &= this.add(e);
304                         }
305                     }
306                     return success;
307                 case Element.MARKED:
308                 case Element.ANCHOR:
309                 case Element.ANNOTATION:
310                 case Element.TABLE: // case added by David Freels
311
case Element.PTABLE: // case added by mr. Karen Vardanyan
312
// This will only work for PDF!!! Not for RTF/HTML
313
case Element.LIST:
314                     return super.add(o);
315                     default:
316                         throw new ClassCastException JavaDoc(String.valueOf(element.type()));
317             }
318         }
319         catch(ClassCastException JavaDoc cce) {
320             throw new ClassCastException JavaDoc("Insertion of illegal Element: " + cce.getMessage());
321         }
322     }
323     
324     /**
325      * Adds a collection of <CODE>Chunk</CODE>s
326      * to this <CODE>Phrase</CODE>.
327      *
328      * @param collection a collection of <CODE>Chunk</CODE>s, <CODE>Anchor</CODE>s and <CODE>Phrase</CODE>s.
329      * @return <CODE>true</CODE> if the action succeeded, <CODE>false</CODE> if not.
330      * @throws ClassCastException when you try to add something that isn't a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
331      */

332     public boolean addAll(Collection JavaDoc collection) {
333         for (Iterator JavaDoc iterator = collection.iterator(); iterator.hasNext(); ) {
334             this.add(iterator.next());
335         }
336         return true;
337     }
338     
339     /**
340      * Adds a Chunk.
341      * <p>
342      * This method is a hack to solve a problem I had with phrases that were split between chunks
343      * in the wrong place.
344      * @param chunk a Chunk to add to the Phrase
345      * @return true if adding the Chunk succeeded
346      */

347     protected synchronized boolean addChunk(Chunk chunk) {
348         if (!font.isStandardFont()) {
349             chunk.setFont(font.difference(chunk.getFont()));
350         }
351         if (size() > 0 && !chunk.hasAttributes()) {
352             try {
353                 Chunk previous = (Chunk) get(size() - 1);
354                 if (!previous.hasAttributes() && previous.getFont().compareTo(chunk.getFont()) == 0 && !"".equals(previous.getContent().trim()) && !"".equals(chunk.getContent().trim())) {
355                     previous.append(chunk.getContent());
356                     return true;
357                 }
358             }
359             catch(ClassCastException JavaDoc cce) {
360             }
361         }
362         return super.add(chunk);
363     }
364     
365     /**
366      * Adds a <CODE>Object</CODE> to the <CODE>Paragraph</CODE>.
367      *
368      * @param object the object to add.
369      */

370     protected void addSpecial(Object JavaDoc object) {
371         super.add(object);
372     }
373     
374     // other methods that change the member variables
375

376     /**
377      * Sets the leading of this phrase.
378      *
379      * @param leading the new leading
380      */

381     
382     public void setLeading(float leading) {
383         this.leading = leading;
384     }
385     
386     /**
387      * Sets the main font of this phrase.
388      * @param font the new font
389      */

390     public void setFont(Font font) {
391         this.font = font;
392     }
393     
394     // methods to retrieve information
395

396     /**
397      * Gets the leading of this phrase.
398      *
399      * @return the linespacing
400      */

401     public float getLeading() {
402         if (Float.isNaN(leading)) {
403             return font.getCalculatedLeading(1.5f);
404         }
405         return leading;
406     }
407
408     /**
409      * Checks you if the leading of this phrase is defined.
410      *
411      * @return true if the leading is defined
412      */

413     public boolean hasLeading() {
414         if (Float.isNaN(leading)) {
415             return false;
416         }
417         return true;
418     }
419
420     /**
421      * Gets the font of the first <CODE>Chunk</CODE> that appears in this <CODE>Phrase</CODE>.
422      *
423      * @return a <CODE>Font</CODE>
424      */

425     public Font getFont() {
426         return font;
427     }
428
429     /**
430      * Returns the content as a String object.
431      * This method differs from toString because toString will return an ArrayList with the toString value of the Chunks in this Phrase.
432      */

433     public String JavaDoc getContent() {
434         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
435         for (Iterator JavaDoc i = getChunks().iterator(); i.hasNext(); ) {
436             buf.append(i.next().toString());
437         }
438         return buf.toString();
439     }
440     
441     /**
442      * Checks is this <CODE>Phrase</CODE> contains no or 1 empty <CODE>Chunk</CODE>.
443      *
444      * @return <CODE>false</CODE> if the <CODE>Phrase</CODE>
445      * contains more than one or more non-empty<CODE>Chunk</CODE>s.
446      */

447     public boolean isEmpty() {
448         switch(size()) {
449             case 0:
450                 return true;
451             case 1:
452                 Element element = (Element) get(0);
453                 if (element.type() == Element.CHUNK && ((Chunk) element).isEmpty()) {
454                     return true;
455                 }
456                 return false;
457                 default:
458                     return false;
459         }
460     }
461     
462     // kept for historical reasons; people should use FontSelector
463
// eligible for deprecation, but the methods are mentioned in the book p277.
464

465     /**
466      * Constructs a Phrase that can be used in the static getInstance() method.
467      * @param dummy a dummy parameter
468      */

469     private Phrase(boolean dummy) {
470     }
471     
472     /**
473      * Gets a special kind of Phrase that changes some characters into corresponding symbols.
474      * @param string
475      * @return a newly constructed Phrase
476      */

477     public static final Phrase getInstance(String JavaDoc string) {
478         return getInstance(16, string, new Font());
479     }
480     
481     /**
482      * Gets a special kind of Phrase that changes some characters into corresponding symbols.
483      * @param leading
484      * @param string
485      * @return a newly constructed Phrase
486      */

487     public static final Phrase getInstance(int leading, String JavaDoc string) {
488         return getInstance(leading, string, new Font());
489     }
490     
491     /**
492      * Gets a special kind of Phrase that changes some characters into corresponding symbols.
493      * @param leading
494      * @param string
495      * @param font
496      * @return a newly constructed Phrase
497      */

498     public static final Phrase getInstance(int leading, String JavaDoc string, Font font) {
499         Phrase p = new Phrase(true);
500         p.setLeading(leading);
501         p.font = font;
502         if (font.getFamily() != Font.SYMBOL && font.getFamily() != Font.ZAPFDINGBATS && font.getBaseFont() == null) {
503             int index;
504             while((index = SpecialSymbol.index(string)) > -1) {
505                 if (index > 0) {
506                     String JavaDoc firstPart = string.substring(0, index);
507                     ((ArrayList JavaDoc)p).add(new Chunk(firstPart, font));
508                     string = string.substring(index);
509                 }
510                 Font symbol = new Font(Font.SYMBOL, font.getSize(), font.getStyle(), font.getColor());
511                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
512                 buf.append(SpecialSymbol.getCorrespondingSymbol(string.charAt(0)));
513                 string = string.substring(1);
514                 while (SpecialSymbol.index(string) == 0) {
515                     buf.append(SpecialSymbol.getCorrespondingSymbol(string.charAt(0)));
516                     string = string.substring(1);
517                 }
518                 ((ArrayList JavaDoc)p).add(new Chunk(buf.toString(), symbol));
519             }
520         }
521         if (string != null && string.length() != 0) {
522             ((ArrayList JavaDoc)p).add(new Chunk(string, font));
523         }
524         return p;
525     }
526     
527     // deprecated constructor and methods
528

529     /**
530      * Returns a <CODE>Phrase</CODE> that has been constructed taking in account
531      * the value of some <VAR>attributes</VAR>.
532      *
533      * @param attributes Some attributes
534      */

535     public Phrase(Properties JavaDoc attributes) {
536         this(com.lowagie.text.factories.ElementFactory.getPhrase(attributes));
537     }
538     /**
539      * Gets the font of the first <CODE>Chunk</CODE> that appears in this <CODE>Phrase</CODE>.
540      *
541      * @return a <CODE>Font</CODE>
542      * @deprecated Use {@link #getFont()} instead
543      */

544     public Font font() {
545         return getFont();
546     }
547     /**
548      * Gets the leading of this phrase.
549      *
550      * @return the linespacing
551      * @deprecated Use {@link #getLeading()} instead
552      */

553     public float leading() {
554         return getLeading();
555     }
556     /**
557      * Checks you if the leading of this phrase is defined.
558      *
559      * @return true if the leading is defined
560      * @deprecated Use {@link #hasLeading()} instead
561      */

562     public boolean leadingDefined() {
563         return hasLeading();
564     }
565     
566     /**
567      * Returns the content as a String object.
568      * This method differs from toString because toString will return an ArrayList with the toString value of the Chunks in this Phrase.
569      * @deprecated Use {@link #getContent()} instead
570      */

571     public String JavaDoc content() {
572         return getContent();
573     }
574 }
Popular Tags