001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/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 * TextAnnotation.java
029 * -------------------
030 * (C) Copyright 2002-2008, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * Changes:
036 * --------
037 * 28-Aug-2002 : Version 1 (DG);
038 * 07-Nov-2002 : Fixed errors reported by Checkstyle, added accessor
039 *               methods (DG);
040 * 13-Jan-2003 : Reviewed Javadocs (DG);
041 * 26-Mar-2003 : Implemented Serializable (DG);
042 * 02-Jun-2003 : Added anchor and rotation settings (DG);
043 * 19-Aug-2003 : Added equals() method and implemented Cloneable (DG);
044 * 29-Sep-2004 : Updated equals() method (DG);
045 * 06-Jun-2005 : Fixed equals() method to work with GradientPaint (DG);
046 * ------------- JFREECHART 1.0.x ---------------------------------------------
047 * 16-Jan-2007 : Added argument checks, fixed hashCode() method and updated
048 *               API docs (DG);
049 *
050 */
051
052package org.jfree.chart.annotations;
053
054import java.awt.Color;
055import java.awt.Font;
056import java.awt.Paint;
057import java.io.IOException;
058import java.io.ObjectInputStream;
059import java.io.ObjectOutputStream;
060import java.io.Serializable;
061
062import org.jfree.chart.HashUtilities;
063import org.jfree.io.SerialUtilities;
064import org.jfree.ui.TextAnchor;
065import org.jfree.util.ObjectUtilities;
066import org.jfree.util.PaintUtilities;
067
068/**
069 * A base class for text annotations.  This class records the content but not
070 * the location of the annotation.
071 */
072public class TextAnnotation implements Serializable {
073
074    /** For serialization. */
075    private static final long serialVersionUID = 7008912287533127432L;
076
077    /** The default font. */
078    public static final Font DEFAULT_FONT
079            = new Font("SansSerif", Font.PLAIN, 10);
080
081    /** The default paint. */
082    public static final Paint DEFAULT_PAINT = Color.black;
083
084    /** The default text anchor. */
085    public static final TextAnchor DEFAULT_TEXT_ANCHOR = TextAnchor.CENTER;
086
087    /** The default rotation anchor. */
088    public static final TextAnchor DEFAULT_ROTATION_ANCHOR = TextAnchor.CENTER;
089
090    /** The default rotation angle. */
091    public static final double DEFAULT_ROTATION_ANGLE = 0.0;
092
093    /** The text. */
094    private String text;
095
096    /** The font. */
097    private Font font;
098
099    /** The paint. */
100    private transient Paint paint;
101
102    /** The text anchor. */
103    private TextAnchor textAnchor;
104
105    /** The rotation anchor. */
106    private TextAnchor rotationAnchor;
107
108    /** The rotation angle. */
109    private double rotationAngle;
110
111    /**
112     * Creates a text annotation with default settings.
113     *
114     * @param text  the text (<code>null</code> not permitted).
115     */
116    protected TextAnnotation(String text) {
117        if (text == null) {
118            throw new IllegalArgumentException("Null 'text' argument.");
119        }
120        this.text = text;
121        this.font = DEFAULT_FONT;
122        this.paint = DEFAULT_PAINT;
123        this.textAnchor = DEFAULT_TEXT_ANCHOR;
124        this.rotationAnchor = DEFAULT_ROTATION_ANCHOR;
125        this.rotationAngle = DEFAULT_ROTATION_ANGLE;
126    }
127
128    /**
129     * Returns the text for the annotation.
130     *
131     * @return The text (never <code>null</code>).
132     *
133     * @see #setText(String)
134     */
135    public String getText() {
136        return this.text;
137    }
138
139    /**
140     * Sets the text for the annotation.
141     *
142     * @param text  the text (<code>null</code> not permitted).
143     *
144     * @see #getText()
145     */
146    public void setText(String text) {
147        if (text == null) {
148            throw new IllegalArgumentException("Null 'text' argument.");
149        }
150        this.text = text;
151    }
152
153    /**
154     * Returns the font for the annotation.
155     *
156     * @return The font (never <code>null</code>).
157     *
158     * @see #setFont(Font)
159     */
160    public Font getFont() {
161        return this.font;
162    }
163
164    /**
165     * Sets the font for the annotation.
166     *
167     * @param font  the font (<code>null</code> not permitted).
168     *
169     * @see #getFont()
170     */
171    public void setFont(Font font) {
172        if (font == null) {
173            throw new IllegalArgumentException("Null 'font' argument.");
174        }
175        this.font = font;
176    }
177
178    /**
179     * Returns the paint for the annotation.
180     *
181     * @return The paint (never <code>null</code>).
182     *
183     * @see #setPaint(Paint)
184     */
185    public Paint getPaint() {
186        return this.paint;
187    }
188
189    /**
190     * Sets the paint for the annotation.
191     *
192     * @param paint  the paint (<code>null</code> not permitted).
193     *
194     * @see #getPaint()
195     */
196    public void setPaint(Paint paint) {
197        if (paint == null) {
198            throw new IllegalArgumentException("Null 'paint' argument.");
199        }
200        this.paint = paint;
201    }
202
203    /**
204     * Returns the text anchor.
205     *
206     * @return The text anchor.
207     *
208     * @see #setTextAnchor(TextAnchor)
209     */
210    public TextAnchor getTextAnchor() {
211        return this.textAnchor;
212    }
213
214    /**
215     * Sets the text anchor (the point on the text bounding rectangle that is
216     * aligned to the (x, y) coordinate of the annotation).
217     *
218     * @param anchor  the anchor point (<code>null</code> not permitted).
219     *
220     * @see #getTextAnchor()
221     */
222    public void setTextAnchor(TextAnchor anchor) {
223        if (anchor == null) {
224            throw new IllegalArgumentException("Null 'anchor' argument.");
225        }
226        this.textAnchor = anchor;
227    }
228
229    /**
230     * Returns the rotation anchor.
231     *
232     * @return The rotation anchor point (never <code>null</code>).
233     *
234     * @see #setRotationAnchor(TextAnchor)
235     */
236    public TextAnchor getRotationAnchor() {
237        return this.rotationAnchor;
238    }
239
240    /**
241     * Sets the rotation anchor point.
242     *
243     * @param anchor  the anchor (<code>null</code> not permitted).
244     *
245     * @see #getRotationAnchor()
246     */
247    public void setRotationAnchor(TextAnchor anchor) {
248        this.rotationAnchor = anchor;
249    }
250
251    /**
252     * Returns the rotation angle in radians.
253     *
254     * @return The rotation angle.
255     *
256     * @see #setRotationAngle(double)
257     */
258    public double getRotationAngle() {
259        return this.rotationAngle;
260    }
261
262    /**
263     * Sets the rotation angle.  The angle is measured clockwise in radians.
264     *
265     * @param angle  the angle (in radians).
266     *
267     * @see #getRotationAngle()
268     */
269    public void setRotationAngle(double angle) {
270        this.rotationAngle = angle;
271    }
272
273    /**
274     * Tests this object for equality with an arbitrary object.
275     *
276     * @param obj  the object (<code>null</code> permitted).
277     *
278     * @return <code>true</code> or <code>false</code>.
279     */
280    public boolean equals(Object obj) {
281        if (obj == this) {
282            return true;
283        }
284        // now try to reject equality...
285        if (!(obj instanceof TextAnnotation)) {
286            return false;
287        }
288        TextAnnotation that = (TextAnnotation) obj;
289        if (!ObjectUtilities.equal(this.text, that.getText())) {
290            return false;
291        }
292        if (!ObjectUtilities.equal(this.font, that.getFont())) {
293            return false;
294        }
295        if (!PaintUtilities.equal(this.paint, that.getPaint())) {
296            return false;
297        }
298        if (!ObjectUtilities.equal(this.textAnchor, that.getTextAnchor())) {
299            return false;
300        }
301        if (!ObjectUtilities.equal(this.rotationAnchor,
302                that.getRotationAnchor())) {
303            return false;
304        }
305        if (this.rotationAngle != that.getRotationAngle()) {
306            return false;
307        }
308
309        // seem to be the same...
310        return true;
311
312    }
313
314    /**
315     * Returns a hash code for this instance.
316     *
317     * @return A hash code.
318     */
319    public int hashCode() {
320        int result = 193;
321        result = 37 * result + this.font.hashCode();
322        result = 37 * result + HashUtilities.hashCodeForPaint(this.paint);
323        result = 37 * result + this.rotationAnchor.hashCode();
324        long temp = Double.doubleToLongBits(this.rotationAngle);
325        result = 37 * result + (int) (temp ^ (temp >>> 32));
326        result = 37 * result + this.text.hashCode();
327        result = 37 * result + this.textAnchor.hashCode();
328        return result;
329    }
330
331    /**
332     * Provides serialization support.
333     *
334     * @param stream  the output stream.
335     *
336     * @throws IOException if there is an I/O error.
337     */
338    private void writeObject(ObjectOutputStream stream) throws IOException {
339        stream.defaultWriteObject();
340        SerialUtilities.writePaint(this.paint, stream);
341    }
342
343    /**
344     * Provides serialization support.
345     *
346     * @param stream  the input stream.
347     *
348     * @throws IOException  if there is an I/O error.
349     * @throws ClassNotFoundException  if there is a classpath problem.
350     */
351    private void readObject(ObjectInputStream stream)
352        throws IOException, ClassNotFoundException {
353        stream.defaultReadObject();
354        this.paint = SerialUtilities.readPaint(stream);
355    }
356
357}