001: /* ========================================================================
002: * JCommon : a free general purpose class library for the Java(tm) platform
003: * ========================================================================
004: *
005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jcommon/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * -----------------
028: * TextFragment.java
029: * -----------------
030: * (C) Copyright 2003-2007, by Object Refinery Limited and Contributors.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: TextFragment.java,v 1.13 2007/03/16 10:25:58 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 07-Nov-2003 : Version 1 (DG);
040: * 25-Nov-2003 : Fixed bug in the dimension calculation (DG);
041: * 22-Dec-2003 : Added workaround for Java bug 4245442 (DG);
042: * 29-Jan-2004 : Added paint attribute (DG);
043: * 22-Mar-2004 : Added equals() method and implemented Serializable (DG);
044: * 01-Apr-2004 : Changed java.awt.geom.Dimension2D to org.jfree.ui.Size2D
045: * because of JDK bug 4976448 which persists on JDK 1.3.1 (DG);
046: * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities
047: * --> TextUtilities (DG);
048: * 16-Mar-2007 : Fixed serialization for GradientPaint (DG);
049: *
050: */
051:
052: package org.jfree.text;
053:
054: import java.awt.Color;
055: import java.awt.Font;
056: import java.awt.FontMetrics;
057: import java.awt.Graphics2D;
058: import java.awt.Paint;
059: import java.awt.font.LineMetrics;
060: import java.awt.geom.Rectangle2D;
061: import java.io.IOException;
062: import java.io.ObjectInputStream;
063: import java.io.ObjectOutputStream;
064: import java.io.Serializable;
065:
066: import org.jfree.io.SerialUtilities;
067: import org.jfree.ui.Size2D;
068: import org.jfree.ui.TextAnchor;
069: import org.jfree.util.Log;
070: import org.jfree.util.LogContext;
071:
072: /**
073: * A text item, with an associated font, that fits on a single line (see
074: * {@link TextLine}). Instances of the class are immutable.
075: */
076: public class TextFragment implements Serializable {
077:
078: /** For serialization. */
079: private static final long serialVersionUID = 4465945952903143262L;
080:
081: /** The default font. */
082: public static final Font DEFAULT_FONT = new Font("Serif",
083: Font.PLAIN, 12);
084:
085: /** The default text color. */
086: public static final Paint DEFAULT_PAINT = Color.black;
087:
088: /** The text. */
089: private String text;
090:
091: /** The font. */
092: private Font font;
093:
094: /** The text color. */
095: private transient Paint paint;
096:
097: /**
098: * The baseline offset (can be used to simulate subscripts and
099: * superscripts).
100: */
101: private float baselineOffset;
102:
103: /** Access to logging facilities. */
104: protected static final LogContext logger = Log
105: .createContext(TextFragment.class);
106:
107: /**
108: * Creates a new text fragment.
109: *
110: * @param text the text (<code>null</code> not permitted).
111: */
112: public TextFragment(final String text) {
113: this (text, DEFAULT_FONT, DEFAULT_PAINT);
114: }
115:
116: /**
117: * Creates a new text fragment.
118: *
119: * @param text the text (<code>null</code> not permitted).
120: * @param font the font (<code>null</code> not permitted).
121: */
122: public TextFragment(final String text, final Font font) {
123: this (text, font, DEFAULT_PAINT);
124: }
125:
126: /**
127: * Creates a new text fragment.
128: *
129: * @param text the text (<code>null</code> not permitted).
130: * @param font the font (<code>null</code> not permitted).
131: * @param paint the text color (<code>null</code> not permitted).
132: */
133: public TextFragment(final String text, final Font font,
134: final Paint paint) {
135: this (text, font, paint, 0.0f);
136: }
137:
138: /**
139: * Creates a new text fragment.
140: *
141: * @param text the text (<code>null</code> not permitted).
142: * @param font the font (<code>null</code> not permitted).
143: * @param paint the text color (<code>null</code> not permitted).
144: * @param baselineOffset the baseline offset.
145: */
146: public TextFragment(final String text, final Font font,
147: final Paint paint, final float baselineOffset) {
148: if (text == null) {
149: throw new IllegalArgumentException("Null 'text' argument.");
150: }
151: if (font == null) {
152: throw new IllegalArgumentException("Null 'font' argument.");
153: }
154: if (paint == null) {
155: throw new IllegalArgumentException("Null 'paint' argument.");
156: }
157: this .text = text;
158: this .font = font;
159: this .paint = paint;
160: this .baselineOffset = baselineOffset;
161: }
162:
163: /**
164: * Returns the text.
165: *
166: * @return The text (possibly <code>null</code>).
167: */
168: public String getText() {
169: return this .text;
170: }
171:
172: /**
173: * Returns the font.
174: *
175: * @return The font (never <code>null</code>).
176: */
177: public Font getFont() {
178: return this .font;
179: }
180:
181: /**
182: * Returns the text paint.
183: *
184: * @return The text paint (never <code>null</code>).
185: */
186: public Paint getPaint() {
187: return this .paint;
188: }
189:
190: /**
191: * Returns the baseline offset.
192: *
193: * @return The baseline offset.
194: */
195: public float getBaselineOffset() {
196: return this .baselineOffset;
197: }
198:
199: /**
200: * Draws the text fragment.
201: *
202: * @param g2 the graphics device.
203: * @param anchorX the x-coordinate of the anchor point.
204: * @param anchorY the y-coordinate of the anchor point.
205: * @param anchor the location of the text that is aligned to the anchor
206: * point.
207: * @param rotateX the x-coordinate of the rotation point.
208: * @param rotateY the y-coordinate of the rotation point.
209: * @param angle the angle.
210: */
211: public void draw(final Graphics2D g2, final float anchorX,
212: final float anchorY, final TextAnchor anchor,
213: final float rotateX, final float rotateY, final double angle) {
214:
215: g2.setFont(this .font);
216: g2.setPaint(this .paint);
217: TextUtilities.drawRotatedString(this .text, g2, anchorX, anchorY
218: + this .baselineOffset, anchor, angle, rotateX, rotateY);
219:
220: }
221:
222: /**
223: * Calculates the dimensions of the text fragment.
224: *
225: * @param g2 the graphics device.
226: *
227: * @return The width and height of the text.
228: */
229: public Size2D calculateDimensions(final Graphics2D g2) {
230: final FontMetrics fm = g2.getFontMetrics(this .font);
231: final Rectangle2D bounds = TextUtilities.getTextBounds(
232: this .text, g2, fm);
233: final Size2D result = new Size2D(bounds.getWidth(), bounds
234: .getHeight());
235: return result;
236: }
237:
238: /**
239: * Calculates the vertical offset between the baseline and the specified
240: * text anchor.
241: *
242: * @param g2 the graphics device.
243: * @param anchor the anchor.
244: *
245: * @return the offset.
246: */
247: public float calculateBaselineOffset(final Graphics2D g2,
248: final TextAnchor anchor) {
249: float result = 0.0f;
250: final FontMetrics fm = g2.getFontMetrics(this .font);
251: final LineMetrics lm = fm.getLineMetrics("ABCxyz", g2);
252: if (anchor == TextAnchor.TOP_LEFT
253: || anchor == TextAnchor.TOP_CENTER
254: || anchor == TextAnchor.TOP_RIGHT) {
255: result = lm.getAscent();
256: } else if (anchor == TextAnchor.BOTTOM_LEFT
257: || anchor == TextAnchor.BOTTOM_CENTER
258: || anchor == TextAnchor.BOTTOM_RIGHT) {
259: result = -lm.getDescent() - lm.getLeading();
260: }
261: return result;
262: }
263:
264: /**
265: * Tests this instance for equality with an arbitrary object.
266: *
267: * @param obj the object to test against (<code>null</code> permitted).
268: *
269: * @return A boolean.
270: */
271: public boolean equals(final Object obj) {
272: if (obj == null) {
273: return false;
274: }
275: if (obj == this ) {
276: return true;
277: }
278: if (obj instanceof TextFragment) {
279: final TextFragment tf = (TextFragment) obj;
280: if (!this .text.equals(tf.text)) {
281: return false;
282: }
283: if (!this .font.equals(tf.font)) {
284: return false;
285: }
286: if (!this .paint.equals(tf.paint)) {
287: return false;
288: }
289: return true;
290: }
291: return false;
292: }
293:
294: /**
295: * Returns a hash code for this object.
296: *
297: * @return A hash code.
298: */
299: public int hashCode() {
300: int result;
301: result = (this .text != null ? this .text.hashCode() : 0);
302: result = 29 * result
303: + (this .font != null ? this .font.hashCode() : 0);
304: result = 29 * result
305: + (this .paint != null ? this .paint.hashCode() : 0);
306: return result;
307: }
308:
309: /**
310: * Provides serialization support.
311: *
312: * @param stream the output stream.
313: *
314: * @throws IOException if there is an I/O error.
315: */
316: private void writeObject(final ObjectOutputStream stream)
317: throws IOException {
318: stream.defaultWriteObject();
319: SerialUtilities.writePaint(this .paint, stream);
320: }
321:
322: /**
323: * Provides serialization support.
324: *
325: * @param stream the input stream.
326: *
327: * @throws IOException if there is an I/O error.
328: * @throws ClassNotFoundException if there is a classpath problem.
329: */
330: private void readObject(final ObjectInputStream stream)
331: throws IOException, ClassNotFoundException {
332: stream.defaultReadObject();
333: this.paint = SerialUtilities.readPaint(stream);
334: }
335:
336: }
|