Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » [javadoc | source]
    1   /*
    2    * $Id: Phrase.java 3373 2008-05-12 16:21:24Z 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.util.ArrayList;
   53   import java.util.Collection;
   54   import java.util.Iterator;
   55   
   56   import com.lowagie.text.pdf.HyphenationEvent;
   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 (explicitly 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 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;
   96       
   97       /** Null, unless the Phrase has to be hyphenated.
   98        * @since	2.1.2
   99        */
  100       protected HyphenationEvent hyphenation = null;
  101       
  102       // constructors
  103       
  104       /**
  105        * Constructs a <CODE>Phrase</CODE> without specifying a leading.
  106        */
  107       public Phrase() {
  108           this(16);
  109       }
  110       
  111       /**
  112        * Copy constructor for <CODE>Phrase</CODE>.
  113        */
  114       public Phrase(Phrase phrase) {
  115           super();
  116           this.addAll(phrase);
  117           leading = phrase.getLeading();
  118           font = phrase.getFont();
  119           setHyphenation(phrase.getHyphenation());
  120       }
  121   
  122   	/**
  123        * Constructs a <CODE>Phrase</CODE> with a certain leading.
  124        *
  125        * @param	leading		the leading
  126        */
  127       public Phrase(float leading) {
  128           this.leading = leading;
  129           font = new Font();
  130       }
  131       
  132       /**
  133        * Constructs a <CODE>Phrase</CODE> with a certain <CODE>Chunk</CODE>.
  134        *
  135        * @param	chunk		a <CODE>Chunk</CODE>
  136        */
  137       public Phrase(Chunk chunk) {
  138           super.add(chunk);
  139           font = chunk.getFont();
  140           setHyphenation(chunk.getHyphenation());
  141       }
  142   
  143   	/**
  144        * Constructs a <CODE>Phrase</CODE> with a certain <CODE>Chunk</CODE>
  145        * and a certain leading.
  146        *
  147        * @param	leading	the leading
  148        * @param	chunk		a <CODE>Chunk</CODE>
  149        */
  150       public Phrase(float leading, Chunk chunk) {
  151           this.leading = leading;
  152           super.add(chunk);
  153           font = chunk.getFont();
  154           setHyphenation(chunk.getHyphenation());
  155       }
  156       
  157       /**
  158        * Constructs a <CODE>Phrase</CODE> with a certain <CODE>String</CODE>.
  159        *
  160        * @param	string		a <CODE>String</CODE>
  161        */
  162       public Phrase(String string) {
  163           this(Float.NaN, string, new Font());
  164       }
  165       
  166       /**
  167        * Constructs a <CODE>Phrase</CODE> with a certain <CODE>String</CODE> and a certain <CODE>Font</CODE>.
  168        *
  169        * @param	string		a <CODE>String</CODE>
  170        * @param	font		a <CODE>Font</CODE>
  171        */
  172       public Phrase(String string, Font font) {
  173           this(Float.NaN, string, font);
  174       }
  175       
  176       /**
  177        * Constructs a <CODE>Phrase</CODE> with a certain leading and a certain <CODE>String</CODE>.
  178        *
  179        * @param	leading	the leading
  180        * @param	string		a <CODE>String</CODE>
  181        */
  182       public Phrase(float leading, String string) {
  183           this(leading, string, new Font());
  184       }
  185       
  186       /**
  187        * Constructs a <CODE>Phrase</CODE> with a certain leading, a certain <CODE>String</CODE>
  188        * and a certain <CODE>Font</CODE>.
  189        *
  190        * @param	leading	the leading
  191        * @param	string		a <CODE>String</CODE>
  192        * @param	font		a <CODE>Font</CODE>
  193        */
  194       public Phrase(float leading, String string, Font font) {
  195           this.leading = leading;
  196           this.font = font;
  197       	/* bugfix by August Detlefsen */
  198           if (string != null && string.length() != 0) {
  199               super.add(new Chunk(string, font));
  200           }
  201       }
  202       
  203       // implementation of the Element-methods
  204       
  205       /**
  206        * Processes the element by adding it (or the different parts) to an
  207        * <CODE>ElementListener</CODE>.
  208        *
  209        * @param	listener	an <CODE>ElementListener</CODE>
  210        * @return	<CODE>true</CODE> if the element was processed successfully
  211        */
  212       public boolean process(ElementListener listener) {
  213           try {
  214               for (Iterator i = iterator(); i.hasNext(); ) {
  215                   listener.add((Element) i.next());
  216               }
  217               return true;
  218           }
  219           catch(DocumentException de) {
  220               return false;
  221           }
  222       }
  223       
  224       /**
  225        * Gets the type of the text element.
  226        *
  227        * @return	a type
  228        */    
  229       public int type() {
  230           return Element.PHRASE;
  231       }
  232       
  233       /**
  234        * Gets all the chunks in this element.
  235        *
  236        * @return	an <CODE>ArrayList</CODE>
  237        */ 
  238       public ArrayList getChunks() {
  239           ArrayList tmp = new ArrayList();
  240           for (Iterator i = iterator(); i.hasNext(); ) {
  241               tmp.addAll(((Element) i.next()).getChunks());
  242           }
  243           return tmp;
  244       }
  245   	
  246   	/**
  247   	 * @see com.lowagie.text.Element#isContent()
  248   	 * @since	iText 2.0.8
  249   	 */
  250   	public boolean isContent() {
  251   		return true;
  252   	}
  253   
  254   	/**
  255   	 * @see com.lowagie.text.Element#isNestable()
  256   	 * @since	iText 2.0.8
  257   	 */
  258   	public boolean isNestable() {
  259   		return true;
  260   	}
  261       
  262       // overriding some of the ArrayList-methods
  263       
  264       /**
  265        * Adds a <CODE>Chunk</CODE>, an <CODE>Anchor</CODE> or another <CODE>Phrase</CODE>
  266        * to this <CODE>Phrase</CODE>.
  267        *
  268        * @param	index	index at which the specified element is to be inserted
  269        * @param	o   	an object of type <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
  270        * @throws	ClassCastException	when you try to add something that isn't a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
  271        */
  272       public void add(int index, Object o) {
  273       	if (o == null) return;
  274           try {
  275               Element element = (Element) o;
  276               if (element.type() == Element.CHUNK) {
  277                   Chunk chunk = (Chunk) element;
  278                   if (!font.isStandardFont()) {
  279                       chunk.setFont(font.difference(chunk.getFont()));
  280                   }
  281                   if (hyphenation != null) {
  282                   	chunk.setHyphenation(hyphenation);
  283                   }
  284                   super.add(index, chunk);
  285               }
  286               else if (element.type() == Element.PHRASE ||
  287               element.type() == Element.ANCHOR ||
  288               element.type() == Element.ANNOTATION ||
  289               element.type() == Element.TABLE || // line added by David Freels
  290               element.type() == Element.YMARK || 
  291               element.type() == Element.MARKED) {
  292                   super.add(index, element);
  293               }
  294               else {
  295                   throw new ClassCastException(String.valueOf(element.type()));
  296               }
  297           }
  298           catch(ClassCastException cce) {
  299               throw new ClassCastException("Insertion of illegal Element: " + cce.getMessage());
  300           }
  301       }
  302       
  303       /**
  304        * Adds a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or another <CODE>Phrase</CODE>
  305        * to this <CODE>Phrase</CODE>.
  306        *
  307        * @param	o	an object of type <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
  308        * @return	a boolean
  309        * @throws	ClassCastException	when you try to add something that isn't a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
  310        */
  311       public boolean add(Object o) {
  312       	if (o == null) return false;
  313           if (o instanceof String) {
  314               return super.add(new Chunk((String) o, font));
  315           }
  316           if (o instanceof RtfElementInterface) {
  317           	return super.add(o);
  318           }
  319           try {
  320               Element element = (Element) o;
  321               switch(element.type()) {
  322                   case Element.CHUNK:
  323                       return addChunk((Chunk) o);
  324                   case Element.PHRASE:
  325                   case Element.PARAGRAPH:
  326                       Phrase phrase = (Phrase) o;
  327                       boolean success = true;
  328                       Element e;
  329                       for (Iterator i = phrase.iterator(); i.hasNext(); ) {
  330                           e = (Element) i.next();
  331                           if (e instanceof Chunk) {
  332                               success &= addChunk((Chunk)e);
  333                           }
  334                           else {
  335                               success &= this.add(e);
  336                           }
  337                       }
  338                       return success;
  339                   case Element.MARKED:
  340                   case Element.ANCHOR:
  341                   case Element.ANNOTATION:
  342                   case Element.TABLE: // case added by David Freels
  343                   case Element.PTABLE: // case added by mr. Karen Vardanyan
  344                   	// This will only work for PDF!!! Not for RTF/HTML
  345                   case Element.LIST:
  346                   case Element.YMARK:
  347                   	return super.add(o);
  348                       default:
  349                           throw new ClassCastException(String.valueOf(element.type()));
  350               }
  351           }
  352           catch(ClassCastException cce) {
  353               throw new ClassCastException("Insertion of illegal Element: " + cce.getMessage());
  354           }
  355       }
  356       
  357       /**
  358        * Adds a collection of <CODE>Chunk</CODE>s
  359        * to this <CODE>Phrase</CODE>.
  360        *
  361        * @param	collection	a collection of <CODE>Chunk</CODE>s, <CODE>Anchor</CODE>s and <CODE>Phrase</CODE>s.
  362        * @return	<CODE>true</CODE> if the action succeeded, <CODE>false</CODE> if not.
  363        * @throws	ClassCastException	when you try to add something that isn't a <CODE>Chunk</CODE>, <CODE>Anchor</CODE> or <CODE>Phrase</CODE>
  364        */
  365       public boolean addAll(Collection collection) {
  366           for (Iterator iterator = collection.iterator(); iterator.hasNext(); ) {
  367               this.add(iterator.next());
  368           }
  369           return true;
  370       }
  371       
  372       /**
  373        * Adds a Chunk.
  374        * <p>
  375        * This method is a hack to solve a problem I had with phrases that were split between chunks
  376        * in the wrong place.
  377        * @param chunk a Chunk to add to the Phrase
  378        * @return true if adding the Chunk succeeded
  379        */
  380       protected boolean addChunk(Chunk chunk) {
  381       	Font f = chunk.getFont();
  382       	String c = chunk.getContent();
  383           if (font != null && !font.isStandardFont()) {
  384               f = font.difference(chunk.getFont());
  385           }
  386           if (size() > 0 && !chunk.hasAttributes()) {
  387               try {
  388                   Chunk previous = (Chunk) get(size() - 1);
  389                   if (!previous.hasAttributes()
  390                   		&& (f == null
  391                   		|| f.compareTo(previous.getFont()) == 0)
  392                   		&& !"".equals(previous.getContent().trim())
  393                   		&& !"".equals(c.trim())) {
  394                       previous.append(c);
  395                       return true;
  396                   }
  397               }
  398               catch(ClassCastException cce) {
  399               }
  400           }
  401           Chunk newChunk = new Chunk(c, f);
  402           newChunk.setAttributes(chunk.getAttributes());
  403           if (newChunk.getHyphenation() == null) {
  404           	newChunk.setHyphenation(hyphenation);
  405           }
  406           return super.add(newChunk);
  407       }
  408       
  409       /**
  410        * Adds a <CODE>Object</CODE> to the <CODE>Paragraph</CODE>.
  411        *
  412        * @param	object		the object to add.
  413        */
  414       protected void addSpecial(Object object) {
  415           super.add(object);
  416       }
  417       
  418       // other methods that change the member variables
  419       
  420       /**
  421        * Sets the leading of this phrase.
  422        *
  423        * @param	leading		the new leading
  424        */
  425       
  426       public void setLeading(float leading) {
  427           this.leading = leading;
  428       }
  429       
  430       /**
  431        * Sets the main font of this phrase.
  432        * @param font	the new font
  433        */
  434       public void setFont(Font font) {
  435       	this.font = font;
  436       }
  437       
  438       // methods to retrieve information
  439   
  440   	/**
  441        * Gets the leading of this phrase.
  442        *
  443        * @return	the linespacing
  444        */
  445       public float getLeading() {
  446           if (Float.isNaN(leading) && font != null) {
  447               return font.getCalculatedLeading(1.5f);
  448           }
  449           return leading;
  450       }
  451   
  452       /**
  453        * Checks you if the leading of this phrase is defined.
  454        *
  455        * @return	true if the leading is defined
  456        */ 
  457       public boolean hasLeading() {
  458           if (Float.isNaN(leading)) {
  459               return false;
  460           }
  461           return true;
  462       }
  463   
  464   	/**
  465        * Gets the font of the first <CODE>Chunk</CODE> that appears in this <CODE>Phrase</CODE>.
  466        *
  467        * @return	a <CODE>Font</CODE>
  468        */  
  469       public Font getFont() {
  470           return font;
  471       }
  472   
  473   	/**
  474        * Returns the content as a String object.
  475        * This method differs from toString because toString will return an ArrayList with the toString value of the Chunks in this Phrase.
  476        */
  477       public String getContent() {
  478       	StringBuffer buf = new StringBuffer();
  479       	for (Iterator i = getChunks().iterator(); i.hasNext(); ) {
  480       		buf.append(i.next().toString());
  481       	}
  482       	return buf.toString();
  483       }
  484       
  485       /**
  486        * Checks is this <CODE>Phrase</CODE> contains no or 1 empty <CODE>Chunk</CODE>.
  487        *
  488        * @return	<CODE>false</CODE> if the <CODE>Phrase</CODE>
  489        * contains more than one or more non-empty<CODE>Chunk</CODE>s.
  490        */
  491       public boolean isEmpty() {
  492           switch(size()) {
  493               case 0:
  494                   return true;
  495               case 1:
  496                   Element element = (Element) get(0);
  497                   if (element.type() == Element.CHUNK && ((Chunk) element).isEmpty()) {
  498                       return true;
  499                   }
  500                   return false;
  501                   default:
  502                       return false;
  503           }
  504       }
  505       
  506       /**
  507        * Getter for the hyphenation settings.
  508        * @return	a HyphenationEvent
  509        * @since	2.1.2
  510        */
  511       public HyphenationEvent getHyphenation() {
  512   		return hyphenation;
  513   	}
  514   
  515       /**
  516        * Setter for the hyphenation.
  517        * @param	hyphenation	a HyphenationEvent instance
  518        * @since	2.1.2
  519        */
  520   	public void setHyphenation(HyphenationEvent hyphenation) {
  521   		this.hyphenation = hyphenation;
  522   	}
  523   	
  524       // kept for historical reasons; people should use FontSelector
  525       // eligible for deprecation, but the methods are mentioned in the book p277.
  526       
  527       /**
  528        * Constructs a Phrase that can be used in the static getInstance() method.
  529        * @param	dummy	a dummy parameter
  530        */
  531       private Phrase(boolean dummy) {
  532       }
  533       
  534       /**
  535        * Gets a special kind of Phrase that changes some characters into corresponding symbols.
  536        * @param string
  537        * @return a newly constructed Phrase
  538        */
  539       public static final Phrase getInstance(String string) {
  540       	return getInstance(16, string, new Font());
  541       }
  542       
  543       /**
  544        * Gets a special kind of Phrase that changes some characters into corresponding symbols.
  545        * @param leading
  546        * @param string
  547        * @return a newly constructed Phrase
  548        */
  549       public static final Phrase getInstance(int leading, String string) {
  550       	return getInstance(leading, string, new Font());
  551       }
  552       
  553       /**
  554        * Gets a special kind of Phrase that changes some characters into corresponding symbols.
  555        * @param leading
  556        * @param string
  557        * @param font
  558        * @return a newly constructed Phrase
  559        */
  560       public static final Phrase getInstance(int leading, String string, Font font) {
  561       	Phrase p = new Phrase(true);
  562       	p.setLeading(leading);
  563       	p.font = font;
  564       	if (font.getFamily() != Font.SYMBOL && font.getFamily() != Font.ZAPFDINGBATS && font.getBaseFont() == null) {
  565               int index;
  566               while((index = SpecialSymbol.index(string)) > -1) {
  567                   if (index > 0) {
  568                       String firstPart = string.substring(0, index);
  569                       ((ArrayList)p).add(new Chunk(firstPart, font));
  570                       string = string.substring(index);
  571                   }
  572                   Font symbol = new Font(Font.SYMBOL, font.getSize(), font.getStyle(), font.getColor());
  573                   StringBuffer buf = new StringBuffer();
  574                   buf.append(SpecialSymbol.getCorrespondingSymbol(string.charAt(0)));
  575                   string = string.substring(1);
  576                   while (SpecialSymbol.index(string) == 0) {
  577                       buf.append(SpecialSymbol.getCorrespondingSymbol(string.charAt(0)));
  578                       string = string.substring(1);
  579                   }
  580                   ((ArrayList)p).add(new Chunk(buf.toString(), symbol));
  581               }
  582           }
  583           if (string != null && string.length() != 0) {
  584           	((ArrayList)p).add(new Chunk(string, font));
  585           }
  586       	return p;
  587       }
  588   
  589   }

Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » [javadoc | source]