Source for org.jfree.text.TextLine

   1: /* ========================================================================
   2:  * JCommon : a free general purpose class library for the Java(tm) platform
   3:  * ========================================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  * 
   7:  * Project Info:  http://www.jfree.org/jcommon/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  * 
  27:  * -------------
  28:  * TextLine.java
  29:  * -------------
  30:  * (C) Copyright 2003-2005, by Object Refinery Limited and Contributors.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * $Id: TextLine.java,v 1.13 2007/11/02 17:50:35 taqua Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 07-Nov-2003 : Version 1 (DG);
  40:  * 22-Dec-2003 : Added workaround for Java bug 4245442 (DG);
  41:  * 29-Jan-2004 : Added new constructor (DG);
  42:  * 22-Mar-2004 : Added equals() method and implemented Serializable (DG);
  43:  * 01-Apr-2004 : Changed java.awt.geom.Dimension2D to org.jfree.ui.Size2D 
  44:  *               because of JDK bug 4976448 which persists on JDK 1.3.1 (DG);
  45:  * 03-Sep-2004 : Added a method to remove a fragment (DG);
  46:  * 08-Jul-2005 : Fixed bug in calculateBaselineOffset() (DG);
  47:  *
  48:  */
  49: 
  50: package org.jfree.text;
  51: 
  52: import java.awt.Font;
  53: import java.awt.Graphics2D;
  54: import java.awt.Paint;
  55: import java.io.Serializable;
  56: import java.util.Iterator;
  57: import java.util.List;
  58: 
  59: import org.jfree.ui.Size2D;
  60: import org.jfree.ui.TextAnchor;
  61: 
  62: /**
  63:  * A sequence of {@link TextFragment} objects that together form a line of 
  64:  * text.  A sequence of text lines is managed by the {@link TextBlock} class.
  65:  *
  66:  * @author David Gilbert
  67:  */
  68: public class TextLine implements Serializable {
  69: 
  70:     /** For serialization. */
  71:     private static final long serialVersionUID = 7100085690160465444L;
  72:     
  73:     /** Storage for the text fragments that make up the line. */
  74:     private List fragments;
  75: 
  76:     /**
  77:      * Creates a new empty line.
  78:      */
  79:     public TextLine() {
  80:         this.fragments = new java.util.ArrayList();
  81:     }
  82:     
  83:     /**
  84:      * Creates a new text line using the default font.
  85:      * 
  86:      * @param text  the text (<code>null</code> not permitted).
  87:      */
  88:     public TextLine(final String text) {
  89:         this(text, TextFragment.DEFAULT_FONT);   
  90:     }
  91:     
  92:     /**
  93:      * Creates a new text line.
  94:      * 
  95:      * @param text  the text (<code>null</code> not permitted).
  96:      * @param font  the text font (<code>null</code> not permitted).
  97:      */
  98:     public TextLine(final String text, final Font font) {
  99:         this.fragments = new java.util.ArrayList();
 100:         final TextFragment fragment = new TextFragment(text, font);
 101:         this.fragments.add(fragment);
 102:     }
 103:     
 104:     /**
 105:      * Creates a new text line.
 106:      * 
 107:      * @param text  the text (<code>null</code> not permitted).
 108:      * @param font  the text font (<code>null</code> not permitted).
 109:      * @param paint  the text color (<code>null</code> not permitted).
 110:      */
 111:     public TextLine(final String text, final Font font, final Paint paint) {
 112:         if (text == null) {
 113:             throw new IllegalArgumentException("Null 'text' argument.");   
 114:         }
 115:         if (font == null) {
 116:             throw new IllegalArgumentException("Null 'font' argument.");   
 117:         }
 118:         if (paint == null) {
 119:             throw new IllegalArgumentException("Null 'paint' argument.");   
 120:         }
 121:         this.fragments = new java.util.ArrayList();
 122:         final TextFragment fragment = new TextFragment(text, font, paint);
 123:         this.fragments.add(fragment);
 124:     }
 125:     
 126:     /**
 127:      * Adds a text fragment to the text line.
 128:      * 
 129:      * @param fragment  the text fragment (<code>null</code> not permitted).
 130:      */
 131:     public void addFragment(final TextFragment fragment) {
 132:         this.fragments.add(fragment);        
 133:     }
 134:     
 135:     /**
 136:      * Removes a fragment from the line.
 137:      * 
 138:      * @param fragment  the fragment to remove.
 139:      */
 140:     public void removeFragment(final TextFragment fragment) {
 141:         this.fragments.remove(fragment);
 142:     }
 143:     
 144:     /**
 145:      * Draws the text line.
 146:      * 
 147:      * @param g2  the graphics device.
 148:      * @param anchorX  the x-coordinate for the anchor point.
 149:      * @param anchorY  the y-coordinate for the anchor point.
 150:      * @param anchor  the point on the text line that is aligned to the anchor 
 151:      *                point.
 152:      * @param rotateX  the x-coordinate for the rotation point.
 153:      * @param rotateY  the y-coordinate for the rotation point.
 154:      * @param angle  the rotation angle (in radians).
 155:      */
 156:     public void draw(final Graphics2D g2,
 157:                      final float anchorX, final float anchorY, 
 158:                      final TextAnchor anchor,
 159:                      final float rotateX, final float rotateY, 
 160:                      final double angle) {
 161:     
 162:         float x = anchorX;
 163:         final float yOffset = calculateBaselineOffset(g2, anchor);
 164:         final Iterator iterator = this.fragments.iterator();
 165:         while (iterator.hasNext()) {
 166:             final TextFragment fragment = (TextFragment) iterator.next();
 167:             final Size2D d = fragment.calculateDimensions(g2);
 168:             fragment.draw(
 169:                 g2, x, anchorY + yOffset, TextAnchor.BASELINE_LEFT, 
 170:                 rotateX, rotateY, angle
 171:             );
 172:             x = x + (float) d.getWidth();
 173:         }
 174:     
 175:     }
 176:     
 177:     /**
 178:      * Calculates the width and height of the text line.
 179:      * 
 180:      * @param g2  the graphics device.
 181:      * 
 182:      * @return The width and height.
 183:      */
 184:     public Size2D calculateDimensions(final Graphics2D g2) {
 185:         double width = 0.0;
 186:         double height = 0.0;
 187:         final Iterator iterator = this.fragments.iterator();
 188:         while (iterator.hasNext()) {
 189:             final TextFragment fragment = (TextFragment) iterator.next();
 190:             final Size2D dimension = fragment.calculateDimensions(g2);
 191:             width = width + dimension.getWidth();
 192:             height = Math.max(height, dimension.getHeight());
 193:         }
 194:         return new Size2D(width, height);
 195:     }
 196:     
 197:     /**
 198:      * Returns the first text fragment in the line.
 199:      * 
 200:      * @return The first text fragment in the line.
 201:      */
 202:     public TextFragment getFirstTextFragment() {
 203:         TextFragment result = null;
 204:         if (this.fragments.size() > 0) {
 205:             result = (TextFragment) this.fragments.get(0);
 206:         }    
 207:         return result;
 208:     }
 209:     
 210:     /**
 211:      * Returns the last text fragment in the line.
 212:      * 
 213:      * @return The last text fragment in the line.
 214:      */
 215:     public TextFragment getLastTextFragment() {
 216:         TextFragment result = null;
 217:         if (this.fragments.size() > 0) {
 218:             result = (TextFragment) this.fragments.get(this.fragments.size() 
 219:                     - 1);
 220:         }    
 221:         return result;
 222:     }
 223:     
 224:     /**
 225:      * Calculate the offsets required to translate from the specified anchor 
 226:      * position to the left baseline position.
 227:      * 
 228:      * @param g2  the graphics device.
 229:      * @param anchor  the anchor position.
 230:      * 
 231:      * @return The offsets.
 232:      */
 233:     private float calculateBaselineOffset(final Graphics2D g2, 
 234:                                           final TextAnchor anchor) {
 235:         float result = 0.0f;
 236:         Iterator iterator = this.fragments.iterator();
 237:         while (iterator.hasNext()) {
 238:             TextFragment fragment = (TextFragment) iterator.next();
 239:             result = Math.max(result, 
 240:                     fragment.calculateBaselineOffset(g2, anchor));
 241:         }
 242:         return result;
 243:     }
 244:     
 245:     /**
 246:      * Tests this object for equality with an arbitrary object.
 247:      * 
 248:      * @param obj  the object to test against (<code>null</code> permitted).
 249:      * 
 250:      * @return A boolean.
 251:      */
 252:     public boolean equals(final Object obj) {
 253:         if (obj == null) {
 254:             return false;
 255:         }
 256:         if (obj == this) {
 257:             return true;   
 258:         }
 259:         if (obj instanceof TextLine) {
 260:             final TextLine line = (TextLine) obj;
 261:             return this.fragments.equals(line.fragments);
 262:         }
 263:         return false;
 264:     }
 265: 
 266:     /**
 267:      * Returns a hash code for this object.
 268:      * 
 269:      * @return A hash code.
 270:      */
 271:     public int hashCode() {
 272:         return (this.fragments != null ? this.fragments.hashCode() : 0);
 273:     }
 274: 
 275: }