001: /* ===========================================================
002: * JFreeChart : a free chart 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/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: * DialTextAnnotation.java
029: * -----------------------
030: * (C) Copyright 2006, 2007, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: DialTextAnnotation.java,v 1.1.2.3 2007/03/08 16:51:07 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 03-Nov-2006 : Version 1 (DG);
040: * 08-Mar-2007 : Fix in hashCode() (DG);
041: *
042: */
043:
044: package org.jfree.experimental.chart.plot.dial;
045:
046: import java.awt.Color;
047: import java.awt.Font;
048: import java.awt.Graphics2D;
049: import java.awt.Paint;
050: import java.awt.geom.Arc2D;
051: import java.awt.geom.Point2D;
052: import java.awt.geom.Rectangle2D;
053: import java.io.IOException;
054: import java.io.ObjectInputStream;
055: import java.io.ObjectOutputStream;
056: import java.io.Serializable;
057:
058: import org.jfree.chart.HashUtilities;
059: import org.jfree.io.SerialUtilities;
060: import org.jfree.text.TextUtilities;
061: import org.jfree.ui.TextAnchor;
062: import org.jfree.util.PaintUtilities;
063: import org.jfree.util.PublicCloneable;
064:
065: /**
066: * A text annotation for a {@link DialPlot}.
067: */
068: public class DialTextAnnotation extends AbstractDialLayer implements
069: DialLayer, Cloneable, PublicCloneable, Serializable {
070:
071: /** The angle that defines the anchor point for the annotation. */
072: private double angle;
073:
074: /** The radius that defines the anchor point for the annotation. */
075: private double radius;
076:
077: /** The font. */
078: private Font font;
079:
080: /**
081: * The paint for the label. This field is transient because it requires
082: * special handling for serialization.
083: */
084: private transient Paint paint;
085:
086: /** The label text. */
087: private String label;
088:
089: /** The text anchor to be aligned to the annotation's anchor point. */
090: private TextAnchor anchor;
091:
092: /**
093: * Creates a new instance of <code>DialTextAnnotation</code>.
094: *
095: * @param label the label (<code>null</code> not permitted).
096: */
097: public DialTextAnnotation(String label) {
098: if (label == null) {
099: throw new IllegalArgumentException("Null 'label' argument.");
100: }
101: this .angle = -90.0;
102: this .radius = 0.3;
103: this .font = new Font("Dialog", Font.BOLD, 14);
104: this .paint = Color.black;
105: this .label = label;
106: this .anchor = TextAnchor.TOP_CENTER;
107: }
108:
109: /**
110: * Returns the angle used to calculate the anchor point.
111: *
112: * @return The angle used to calculate the anchor point.
113: *
114: * @see #setAngle(double)
115: * @see #getRadius()
116: */
117: public double getAngle() {
118: return this .angle;
119: }
120:
121: /**
122: * Sets the angle used to calculate the anchor point.
123: *
124: * @param angle the angle.
125: *
126: * @see #getAngle()
127: * @see #setRadius(double)
128: */
129: public void setAngle(double angle) {
130: this .angle = angle;
131: notifyListeners(new DialLayerChangeEvent(this ));
132: }
133:
134: /**
135: * Returns the radius used to calculate the anchor point.
136: *
137: * @return The radius.
138: *
139: * @see #setRadius(double)
140: * @see #getAngle()
141: */
142: public double getRadius() {
143: return this .radius;
144: }
145:
146: /**
147: * Sets the radius used to calculate the anchor point.
148: *
149: * @param radius the radius.
150: *
151: * @see #getRadius()
152: * @see #setAngle(double)
153: */
154: public void setRadius(double radius) {
155: // TODO: validation
156: this .radius = radius;
157: notifyListeners(new DialLayerChangeEvent(this ));
158: }
159:
160: /**
161: * Returns the font used to display the label.
162: *
163: * @return The font (never <code>null</code>).
164: *
165: * @see #setFont(Font)
166: */
167: public Font getFont() {
168: return this .font;
169: }
170:
171: /**
172: * Sets the font used to display the label.
173: *
174: * @param font the font (<code>null</code> not permitted).
175: *
176: * @see #getFont()
177: */
178: public void setFont(Font font) {
179: if (font == null) {
180: throw new IllegalArgumentException("Null 'font' argument.");
181: }
182: this .font = font;
183: notifyListeners(new DialLayerChangeEvent(this ));
184: }
185:
186: /**
187: * Returns the paint used to display the label.
188: *
189: * @return The paint (never <code>null</code>).
190: *
191: * @see #setPaint(Paint)
192: */
193: public Paint getPaint() {
194: return this .paint;
195: }
196:
197: /**
198: * Sets the paint used to display the label.
199: *
200: * @param paint the paint (<code>null</code> not permitted).
201: *
202: * @see #getPaint()
203: */
204: public void setPaint(Paint paint) {
205: if (paint == null) {
206: throw new IllegalArgumentException("Null 'paint' argument.");
207: }
208: this .paint = paint;
209: notifyListeners(new DialLayerChangeEvent(this ));
210: }
211:
212: /**
213: * Returns the label text.
214: *
215: * @return The label text (never <code>null</code).
216: *
217: * @see #setLabel(String)
218: */
219: public String getLabel() {
220: return this .label;
221: }
222:
223: /**
224: * Sets the label.
225: *
226: * @param label the label (<code>null</code> not permitted).
227: *
228: * @see #getLabel()
229: */
230: public void setLabel(String label) {
231: if (label == null) {
232: throw new IllegalArgumentException("Null 'label' argument.");
233: }
234: this .label = label;
235: notifyListeners(new DialLayerChangeEvent(this ));
236: }
237:
238: /**
239: * Returns <code>true</code> to indicate that this layer should be
240: * clipped within the dial window.
241: *
242: * @return <code>true</code>.
243: */
244: public boolean isClippedToWindow() {
245: return true;
246: }
247:
248: /**
249: * Draws the background to the specified graphics device. If the dial
250: * frame specifies a window, the clipping region will already have been
251: * set to this window before this method is called.
252: *
253: * @param g2 the graphics device (<code>null</code> not permitted).
254: * @param plot the plot (ignored here).
255: * @param frame the dial frame (ignored here).
256: * @param view the view rectangle (<code>null</code> not permitted).
257: */
258: public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame,
259: Rectangle2D view) {
260:
261: // work out the anchor point
262: Rectangle2D f = DialPlot.rectangleByRadius(frame, this .radius,
263: this .radius);
264: Arc2D arc = new Arc2D.Double(f, this .angle, 0.0, Arc2D.OPEN);
265: Point2D pt = arc.getStartPoint();
266: g2.setPaint(this .paint);
267: g2.setFont(this .font);
268: TextUtilities.drawAlignedString(this .label, g2, (float) pt
269: .getX(), (float) pt.getY(), this .anchor);
270:
271: }
272:
273: /**
274: * Tests this instance for equality with an arbitrary object.
275: *
276: * @param obj the object (<code>null</code> permitted).
277: *
278: * @return A boolean.
279: */
280: public boolean equals(Object obj) {
281: if (obj == this ) {
282: return true;
283: }
284: if (!(obj instanceof DialTextAnnotation)) {
285: return false;
286: }
287: DialTextAnnotation that = (DialTextAnnotation) obj;
288: if (!this .label.equals(that.label)) {
289: return false;
290: }
291: if (!this .font.equals(that.font)) {
292: return false;
293: }
294: if (!PaintUtilities.equal(this .paint, that.paint)) {
295: return false;
296: }
297: if (this .radius != that.radius) {
298: return false;
299: }
300: if (this .angle != that.angle) {
301: return false;
302: }
303: if (!this .anchor.equals(that.anchor)) {
304: return false;
305: }
306: return true;
307: }
308:
309: /**
310: * Returns a hash code for this instance.
311: *
312: * @return The hash code.
313: */
314: public int hashCode() {
315: int result = 193;
316: result = 37 * result
317: + HashUtilities.hashCodeForPaint(this .paint);
318: result = 37 * result + this .font.hashCode();
319: result = 37 * result + this .label.hashCode();
320: result = 37 * result + this .anchor.hashCode();
321: long temp = Double.doubleToLongBits(this .angle);
322: result = 37 * result + (int) (temp ^ (temp >>> 32));
323: temp = Double.doubleToLongBits(this .radius);
324: result = 37 * result + (int) (temp ^ (temp >>> 32));
325: return result;
326: }
327:
328: /**
329: * Returns a clone of this instance.
330: *
331: * @return The clone.
332: *
333: * @throws CloneNotSupportedException if some attribute of this instance
334: * cannot be cloned.
335: */
336: public Object clone() throws CloneNotSupportedException {
337: return super .clone();
338: }
339:
340: /**
341: * Provides serialization support.
342: *
343: * @param stream the output stream.
344: *
345: * @throws IOException if there is an I/O error.
346: */
347: private void writeObject(ObjectOutputStream stream)
348: throws IOException {
349: stream.defaultWriteObject();
350: SerialUtilities.writePaint(this .paint, stream);
351: }
352:
353: /**
354: * Provides serialization support.
355: *
356: * @param stream the input stream.
357: *
358: * @throws IOException if there is an I/O error.
359: * @throws ClassNotFoundException if there is a classpath problem.
360: */
361: private void readObject(ObjectInputStream stream)
362: throws IOException, ClassNotFoundException {
363: stream.defaultReadObject();
364: this.paint = SerialUtilities.readPaint(stream);
365: }
366:
367: }
|