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: * CategoryLineAnnotation.java
029: * ---------------------------
030: * (C) Copyright 2005-2007, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: CategoryLineAnnotation.java,v 1.1.2.4 2007/03/06 16:12:18 mungady Exp $
036: *
037: * Changes:
038: * --------
039: * 29-Jul-2005 : Version 1, based on CategoryTextAnnotation (DG);
040: * ------------- JFREECHART 1.0.x ---------------------------------------------
041: * 06-Mar-2007 : Reimplemented hashCode() (DG);
042: *
043: */
044:
045: package org.jfree.chart.annotations;
046:
047: import java.awt.BasicStroke;
048: import java.awt.Color;
049: import java.awt.Graphics2D;
050: import java.awt.Paint;
051: import java.awt.Stroke;
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.chart.axis.CategoryAnchor;
060: import org.jfree.chart.axis.CategoryAxis;
061: import org.jfree.chart.axis.ValueAxis;
062: import org.jfree.chart.plot.CategoryPlot;
063: import org.jfree.chart.plot.Plot;
064: import org.jfree.chart.plot.PlotOrientation;
065: import org.jfree.data.category.CategoryDataset;
066: import org.jfree.io.SerialUtilities;
067: import org.jfree.ui.RectangleEdge;
068: import org.jfree.util.ObjectUtilities;
069: import org.jfree.util.PaintUtilities;
070:
071: /**
072: * A line annotation that can be placed on a {@link CategoryPlot}.
073: */
074: public class CategoryLineAnnotation implements CategoryAnnotation,
075: Cloneable, Serializable {
076:
077: /** The category for the start of the line. */
078: private Comparable category1;
079:
080: /** The value for the start of the line. */
081: private double value1;
082:
083: /** The category for the end of the line. */
084: private Comparable category2;
085:
086: /** The value for the end of the line. */
087: private double value2;
088:
089: /** The line color. */
090: private transient Paint paint = Color.black;
091:
092: /** The line stroke. */
093: private transient Stroke stroke = new BasicStroke(1.0f);
094:
095: /**
096: * Creates a new annotation that draws a line between (category1, value1)
097: * and (category2, value2).
098: *
099: * @param category1 the category (<code>null</code> not permitted).
100: * @param value1 the value.
101: * @param category2 the category (<code>null</code> not permitted).
102: * @param value2 the value.
103: * @param paint the line color (<code>null</code> not permitted).
104: * @param stroke the line stroke (<code>null</code> not permitted).
105: */
106: public CategoryLineAnnotation(Comparable category1, double value1,
107: Comparable category2, double value2, Paint paint,
108: Stroke stroke) {
109: if (category1 == null) {
110: throw new IllegalArgumentException(
111: "Null 'category1' argument.");
112: }
113: if (category2 == null) {
114: throw new IllegalArgumentException(
115: "Null 'category2' argument.");
116: }
117: if (paint == null) {
118: throw new IllegalArgumentException("Null 'paint' argument.");
119: }
120: if (stroke == null) {
121: throw new IllegalArgumentException(
122: "Null 'stroke' argument.");
123: }
124: this .category1 = category1;
125: this .value1 = value1;
126: this .category2 = category2;
127: this .value2 = value2;
128: this .paint = paint;
129: this .stroke = stroke;
130: }
131:
132: /**
133: * Returns the category for the start of the line.
134: *
135: * @return The category for the start of the line (never <code>null</code>).
136: *
137: * @see #setCategory1(Comparable)
138: */
139: public Comparable getCategory1() {
140: return this .category1;
141: }
142:
143: /**
144: * Sets the category for the start of the line.
145: *
146: * @param category the category (<code>null</code> not permitted).
147: *
148: * @see #getCategory1()
149: */
150: public void setCategory1(Comparable category) {
151: if (category == null) {
152: throw new IllegalArgumentException(
153: "Null 'category' argument.");
154: }
155: this .category1 = category;
156: }
157:
158: /**
159: * Returns the y-value for the start of the line.
160: *
161: * @return The y-value for the start of the line.
162: *
163: * @see #setValue1(double)
164: */
165: public double getValue1() {
166: return this .value1;
167: }
168:
169: /**
170: * Sets the y-value for the start of the line.
171: *
172: * @param value the value.
173: *
174: * @see #getValue1()
175: */
176: public void setValue1(double value) {
177: this .value1 = value;
178: }
179:
180: /**
181: * Returns the category for the end of the line.
182: *
183: * @return The category for the end of the line (never <code>null</code>).
184: *
185: * @see #setCategory2(Comparable)
186: */
187: public Comparable getCategory2() {
188: return this .category2;
189: }
190:
191: /**
192: * Sets the category for the end of the line.
193: *
194: * @param category the category (<code>null</code> not permitted).
195: *
196: * @see #getCategory2()
197: */
198: public void setCategory2(Comparable category) {
199: if (category == null) {
200: throw new IllegalArgumentException(
201: "Null 'category' argument.");
202: }
203: this .category2 = category;
204: }
205:
206: /**
207: * Returns the y-value for the end of the line.
208: *
209: * @return The y-value for the end of the line.
210: *
211: * @see #setValue2(double)
212: */
213: public double getValue2() {
214: return this .value2;
215: }
216:
217: /**
218: * Sets the y-value for the end of the line.
219: *
220: * @param value the value.
221: *
222: * @see #getValue2()
223: */
224: public void setValue2(double value) {
225: this .value2 = value;
226: }
227:
228: /**
229: * Returns the paint used to draw the connecting line.
230: *
231: * @return The paint (never <code>null</code>).
232: *
233: * @see #setPaint(Paint)
234: */
235: public Paint getPaint() {
236: return this .paint;
237: }
238:
239: /**
240: * Sets the paint used to draw the connecting line.
241: *
242: * @param paint the paint (<code>null</code> not permitted).
243: *
244: * @see #getPaint()
245: */
246: public void setPaint(Paint paint) {
247: if (paint == null) {
248: throw new IllegalArgumentException("Null 'paint' argument.");
249: }
250: this .paint = paint;
251: }
252:
253: /**
254: * Returns the stroke used to draw the connecting line.
255: *
256: * @return The stroke (never <code>null</code>).
257: *
258: * @see #setStroke(Stroke)
259: */
260: public Stroke getStroke() {
261: return this .stroke;
262: }
263:
264: /**
265: * Sets the stroke used to draw the connecting line.
266: *
267: * @param stroke the stroke (<code>null</code> not permitted).
268: *
269: * @see #getStroke()
270: */
271: public void setStroke(Stroke stroke) {
272: if (stroke == null) {
273: throw new IllegalArgumentException(
274: "Null 'stroke' argument.");
275: }
276: this .stroke = stroke;
277: }
278:
279: /**
280: * Draws the annotation.
281: *
282: * @param g2 the graphics device.
283: * @param plot the plot.
284: * @param dataArea the data area.
285: * @param domainAxis the domain axis.
286: * @param rangeAxis the range axis.
287: */
288: public void draw(Graphics2D g2, CategoryPlot plot,
289: Rectangle2D dataArea, CategoryAxis domainAxis,
290: ValueAxis rangeAxis) {
291:
292: CategoryDataset dataset = plot.getDataset();
293: int catIndex1 = dataset.getColumnIndex(this .category1);
294: int catIndex2 = dataset.getColumnIndex(this .category2);
295: int catCount = dataset.getColumnCount();
296:
297: double lineX1 = 0.0f;
298: double lineY1 = 0.0f;
299: double lineX2 = 0.0f;
300: double lineY2 = 0.0f;
301: PlotOrientation orientation = plot.getOrientation();
302: RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(plot
303: .getDomainAxisLocation(), orientation);
304: RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(plot
305: .getRangeAxisLocation(), orientation);
306:
307: if (orientation == PlotOrientation.HORIZONTAL) {
308: lineY1 = domainAxis.getCategoryJava2DCoordinate(
309: CategoryAnchor.MIDDLE, catIndex1, catCount,
310: dataArea, domainEdge);
311: lineX1 = rangeAxis.valueToJava2D(this .value1, dataArea,
312: rangeEdge);
313: lineY2 = domainAxis.getCategoryJava2DCoordinate(
314: CategoryAnchor.MIDDLE, catIndex2, catCount,
315: dataArea, domainEdge);
316: lineX2 = rangeAxis.valueToJava2D(this .value2, dataArea,
317: rangeEdge);
318: } else if (orientation == PlotOrientation.VERTICAL) {
319: lineX1 = domainAxis.getCategoryJava2DCoordinate(
320: CategoryAnchor.MIDDLE, catIndex1, catCount,
321: dataArea, domainEdge);
322: lineY1 = rangeAxis.valueToJava2D(this .value1, dataArea,
323: rangeEdge);
324: lineX2 = domainAxis.getCategoryJava2DCoordinate(
325: CategoryAnchor.MIDDLE, catIndex2, catCount,
326: dataArea, domainEdge);
327: lineY2 = rangeAxis.valueToJava2D(this .value2, dataArea,
328: rangeEdge);
329: }
330: g2.setPaint(this .paint);
331: g2.setStroke(this .stroke);
332: g2.drawLine((int) lineX1, (int) lineY1, (int) lineX2,
333: (int) lineY2);
334: }
335:
336: /**
337: * Tests this object for equality with another.
338: *
339: * @param obj the object (<code>null</code> permitted).
340: *
341: * @return <code>true</code> or <code>false</code>.
342: */
343: public boolean equals(Object obj) {
344: if (obj == this ) {
345: return true;
346: }
347: if (!(obj instanceof CategoryLineAnnotation)) {
348: return false;
349: }
350: CategoryLineAnnotation that = (CategoryLineAnnotation) obj;
351: if (!this .category1.equals(that.getCategory1())) {
352: return false;
353: }
354: if (this .value1 != that.getValue1()) {
355: return false;
356: }
357: if (!this .category2.equals(that.getCategory2())) {
358: return false;
359: }
360: if (this .value2 != that.getValue2()) {
361: return false;
362: }
363: if (!PaintUtilities.equal(this .paint, that.paint)) {
364: return false;
365: }
366: if (!ObjectUtilities.equal(this .stroke, that.stroke)) {
367: return false;
368: }
369: return true;
370: }
371:
372: /**
373: * Returns a hash code for this instance.
374: *
375: * @return A hash code.
376: */
377: public int hashCode() {
378: int result = 193;
379: result = 37 * result + this .category1.hashCode();
380: long temp = Double.doubleToLongBits(this .value1);
381: result = 37 * result + (int) (temp ^ (temp >>> 32));
382: result = 37 * result + this .category2.hashCode();
383: temp = Double.doubleToLongBits(this .value2);
384: result = 37 * result + (int) (temp ^ (temp >>> 32));
385: result = 37 * result
386: + HashUtilities.hashCodeForPaint(this .paint);
387: result = 37 * result + this .stroke.hashCode();
388: return result;
389: }
390:
391: /**
392: * Returns a clone of the annotation.
393: *
394: * @return A clone.
395: *
396: * @throws CloneNotSupportedException this class will not throw this
397: * exception, but subclasses (if any) might.
398: */
399: public Object clone() throws CloneNotSupportedException {
400: return super .clone();
401: }
402:
403: /**
404: * Provides serialization support.
405: *
406: * @param stream the output stream.
407: *
408: * @throws IOException if there is an I/O error.
409: */
410: private void writeObject(ObjectOutputStream stream)
411: throws IOException {
412: stream.defaultWriteObject();
413: SerialUtilities.writePaint(this .paint, stream);
414: SerialUtilities.writeStroke(this .stroke, stream);
415: }
416:
417: /**
418: * Provides serialization support.
419: *
420: * @param stream the input stream.
421: *
422: * @throws IOException if there is an I/O error.
423: * @throws ClassNotFoundException if there is a classpath problem.
424: */
425: private void readObject(ObjectInputStream stream)
426: throws IOException, ClassNotFoundException {
427: stream.defaultReadObject();
428: this.paint = SerialUtilities.readPaint(stream);
429: this.stroke = SerialUtilities.readStroke(stream);
430: }
431:
432: }
|