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     * XYDrawableAnnotation.java
029     * -------------------------
030     * (C) Copyright 2003-2007, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes:
036     * --------
037     * 21-May-2003 : Version 1 (DG);
038     * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
039     * 30-Sep-2004 : Added support for tool tips and URLs (DG);
040     *
041     */
042    
043    package org.jfree.chart.annotations;
044    
045    import java.awt.Graphics2D;
046    import java.awt.geom.Rectangle2D;
047    import java.io.Serializable;
048    
049    import org.jfree.chart.axis.ValueAxis;
050    import org.jfree.chart.plot.Plot;
051    import org.jfree.chart.plot.PlotOrientation;
052    import org.jfree.chart.plot.PlotRenderingInfo;
053    import org.jfree.chart.plot.XYPlot;
054    import org.jfree.ui.Drawable;
055    import org.jfree.ui.RectangleEdge;
056    import org.jfree.util.ObjectUtilities;
057    import org.jfree.util.PublicCloneable;
058    
059    /**
060     * A general annotation that can be placed on an {@link XYPlot}.
061     */
062    public class XYDrawableAnnotation extends AbstractXYAnnotation
063                                      implements Cloneable, PublicCloneable, 
064                                                 Serializable {
065    
066        /** For serialization. */
067        private static final long serialVersionUID = -6540812859722691020L;
068        
069        /** The x-coordinate. */
070        private double x;
071    
072        /** The y-coordinate. */
073        private double y;
074    
075        /** The width. */
076        private double width;
077    
078        /** The height. */
079        private double height;
080    
081        /** The drawable object. */
082        private Drawable drawable;
083    
084        /**
085         * Creates a new annotation to be displayed within the given area.
086         *
087         * @param x  the x-coordinate for the area.
088         * @param y  the y-coordinate for the area.
089         * @param width  the width of the area.
090         * @param height  the height of the area.
091         * @param drawable  the drawable object (<code>null</code> not permitted).
092         */
093        public XYDrawableAnnotation(double x, double y, double width, double height,
094                                    Drawable drawable) {
095    
096            if (drawable == null) {
097                throw new IllegalArgumentException("Null 'drawable' argument.");
098            }
099            this.x = x;
100            this.y = y;
101            this.width = width;
102            this.height = height;
103            this.drawable = drawable;
104    
105        }
106    
107        /**
108         * Draws the annotation.
109         *
110         * @param g2  the graphics device.
111         * @param plot  the plot.
112         * @param dataArea  the data area.
113         * @param domainAxis  the domain axis.
114         * @param rangeAxis  the range axis.
115         * @param rendererIndex  the renderer index.
116         * @param info  if supplied, this info object will be populated with
117         *              entity information.
118         */
119        public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea,
120                         ValueAxis domainAxis, ValueAxis rangeAxis, 
121                         int rendererIndex,
122                         PlotRenderingInfo info) {
123    
124            PlotOrientation orientation = plot.getOrientation();
125            RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
126                    plot.getDomainAxisLocation(), orientation);
127            RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
128                    plot.getRangeAxisLocation(), orientation);
129            float j2DX = (float) domainAxis.valueToJava2D(this.x, dataArea, 
130                    domainEdge);
131            float j2DY = (float) rangeAxis.valueToJava2D(this.y, dataArea, 
132                    rangeEdge);
133            Rectangle2D area = new Rectangle2D.Double(j2DX - this.width / 2.0, 
134                    j2DY - this.height / 2.0, this.width, this.height);
135            this.drawable.draw(g2, area);
136            String toolTip = getToolTipText();
137            String url = getURL();
138            if (toolTip != null || url != null) {
139                addEntity(info, area, rendererIndex, toolTip, url);
140            }
141            
142        }
143    
144        /**
145         * Tests this annotation for equality with an arbitrary object.
146         * 
147         * @param obj  the object to test against.
148         * 
149         * @return <code>true</code> or <code>false</code>.
150         */
151        public boolean equals(Object obj) {
152            
153            if (obj == this) { // simple case
154                return true;
155            }      
156            // now try to reject equality...
157            if (!super.equals(obj)) {
158                return false;
159            }
160            if (!(obj instanceof XYDrawableAnnotation)) {
161                return false;
162            }
163            XYDrawableAnnotation that = (XYDrawableAnnotation) obj;
164            if (this.x != that.x) {
165                return false;
166            }
167            if (this.y != that.y) {
168                return false;
169            }
170            if (this.width != that.width) {
171                return false;
172            }
173            if (this.height != that.height) {
174                return false;
175            }
176            if (!ObjectUtilities.equal(this.drawable, that.drawable)) {
177                return false;
178            }
179            // seem to be the same... 
180            return true;
181            
182        }
183        
184        /**
185         * Returns a hash code.
186         * 
187         * @return A hash code.
188         */
189        public int hashCode() {
190            int result;
191            long temp;
192            temp = Double.doubleToLongBits(this.x);
193            result = (int) (temp ^ (temp >>> 32));
194            temp = Double.doubleToLongBits(this.y);
195            result = 29 * result + (int) (temp ^ (temp >>> 32));
196            temp = Double.doubleToLongBits(this.width);
197            result = 29 * result + (int) (temp ^ (temp >>> 32));
198            temp = Double.doubleToLongBits(this.height);
199            result = 29 * result + (int) (temp ^ (temp >>> 32));
200            return result;
201        }
202        
203        /**
204         * Returns a clone of the annotation.
205         * 
206         * @return A clone.
207         * 
208         * @throws CloneNotSupportedException  if the annotation can't be cloned.
209         */
210        public Object clone() throws CloneNotSupportedException {
211            return super.clone();
212        }
213    
214    }