001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2011, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * --------------------------- 028 * CategoryTextAnnotation.java 029 * --------------------------- 030 * (C) Copyright 2003-2011, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Peter Kolb (patch 2809117); 034 * 035 * Changes: 036 * -------- 037 * 02-Apr-2003 : Version 1 (DG); 038 * 02-Jul-2003 : Added new text alignment and rotation options (DG); 039 * 04-Jul-2003 : Added a category anchor option (DG); 040 * 19-Aug-2003 : Added equals() method and implemented Cloneable (DG); 041 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 042 * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities 043 * --> TextUtilities (DG); 044 * ------------- JFREECHART 1.0.x ------------------------------------------- 045 * 06-Mar-2007 : Implemented hashCode() (DG); 046 * 23-Apr-2008 : Implemented PublicCloneable (DG); 047 * 24-Jun-2009 : Fire change events (see patch 2809117 by PK) (DG); 048 * 049 */ 050 051package org.jfree.chart.annotations; 052 053import java.awt.Graphics2D; 054import java.awt.geom.Rectangle2D; 055import java.io.Serializable; 056 057import org.jfree.chart.axis.CategoryAnchor; 058import org.jfree.chart.axis.CategoryAxis; 059import org.jfree.chart.axis.ValueAxis; 060import org.jfree.chart.event.AnnotationChangeEvent; 061import org.jfree.chart.plot.CategoryPlot; 062import org.jfree.chart.plot.Plot; 063import org.jfree.chart.plot.PlotOrientation; 064import org.jfree.data.category.CategoryDataset; 065import org.jfree.text.TextUtilities; 066import org.jfree.ui.RectangleEdge; 067import org.jfree.util.PublicCloneable; 068 069/** 070 * A text annotation that can be placed on a {@link CategoryPlot}. 071 */ 072public class CategoryTextAnnotation extends TextAnnotation 073 implements CategoryAnnotation, Cloneable, PublicCloneable, 074 Serializable { 075 076 /** For serialization. */ 077 private static final long serialVersionUID = 3333360090781320147L; 078 079 /** The category. */ 080 private Comparable category; 081 082 /** The category anchor (START, MIDDLE, or END). */ 083 private CategoryAnchor categoryAnchor; 084 085 /** The value. */ 086 private double value; 087 088 /** 089 * Creates a new annotation to be displayed at the given location. 090 * 091 * @param text the text (<code>null</code> not permitted). 092 * @param category the category (<code>null</code> not permitted). 093 * @param value the value. 094 */ 095 public CategoryTextAnnotation(String text, Comparable category, 096 double value) { 097 super(text); 098 if (category == null) { 099 throw new IllegalArgumentException("Null 'category' argument."); 100 } 101 this.category = category; 102 this.value = value; 103 this.categoryAnchor = CategoryAnchor.MIDDLE; 104 } 105 106 /** 107 * Returns the category. 108 * 109 * @return The category (never <code>null</code>). 110 * 111 * @see #setCategory(Comparable) 112 */ 113 public Comparable getCategory() { 114 return this.category; 115 } 116 117 /** 118 * Sets the category that the annotation attaches to and sends an 119 * {@link AnnotationChangeEvent} to all registered listeners. 120 * 121 * @param category the category (<code>null</code> not permitted). 122 * 123 * @see #getCategory() 124 */ 125 public void setCategory(Comparable category) { 126 if (category == null) { 127 throw new IllegalArgumentException("Null 'category' argument."); 128 } 129 this.category = category; 130 fireAnnotationChanged(); 131 } 132 133 /** 134 * Returns the category anchor point. 135 * 136 * @return The category anchor point. 137 * 138 * @see #setCategoryAnchor(CategoryAnchor) 139 */ 140 public CategoryAnchor getCategoryAnchor() { 141 return this.categoryAnchor; 142 } 143 144 /** 145 * Sets the category anchor point and sends an 146 * {@link AnnotationChangeEvent} to all registered listeners. 147 * 148 * @param anchor the anchor point (<code>null</code> not permitted). 149 * 150 * @see #getCategoryAnchor() 151 */ 152 public void setCategoryAnchor(CategoryAnchor anchor) { 153 if (anchor == null) { 154 throw new IllegalArgumentException("Null 'anchor' argument."); 155 } 156 this.categoryAnchor = anchor; 157 fireAnnotationChanged(); 158 } 159 160 /** 161 * Returns the value that the annotation attaches to. 162 * 163 * @return The value. 164 * 165 * @see #setValue(double) 166 */ 167 public double getValue() { 168 return this.value; 169 } 170 171 /** 172 * Sets the value and sends an 173 * {@link AnnotationChangeEvent} to all registered listeners. 174 * 175 * @param value the value. 176 * 177 * @see #getValue() 178 */ 179 public void setValue(double value) { 180 this.value = value; 181 fireAnnotationChanged(); 182 } 183 184 /** 185 * Draws the annotation. 186 * 187 * @param g2 the graphics device. 188 * @param plot the plot. 189 * @param dataArea the data area. 190 * @param domainAxis the domain axis. 191 * @param rangeAxis the range axis. 192 */ 193 public void draw(Graphics2D g2, CategoryPlot plot, Rectangle2D dataArea, 194 CategoryAxis domainAxis, ValueAxis rangeAxis) { 195 196 CategoryDataset dataset = plot.getDataset(); 197 int catIndex = dataset.getColumnIndex(this.category); 198 int catCount = dataset.getColumnCount(); 199 200 float anchorX = 0.0f; 201 float anchorY = 0.0f; 202 PlotOrientation orientation = plot.getOrientation(); 203 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( 204 plot.getDomainAxisLocation(), orientation); 205 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( 206 plot.getRangeAxisLocation(), orientation); 207 208 if (orientation == PlotOrientation.HORIZONTAL) { 209 anchorY = (float) domainAxis.getCategoryJava2DCoordinate( 210 this.categoryAnchor, catIndex, catCount, dataArea, 211 domainEdge); 212 anchorX = (float) rangeAxis.valueToJava2D(this.value, dataArea, 213 rangeEdge); 214 } 215 else if (orientation == PlotOrientation.VERTICAL) { 216 anchorX = (float) domainAxis.getCategoryJava2DCoordinate( 217 this.categoryAnchor, catIndex, catCount, dataArea, 218 domainEdge); 219 anchorY = (float) rangeAxis.valueToJava2D(this.value, dataArea, 220 rangeEdge); 221 } 222 g2.setFont(getFont()); 223 g2.setPaint(getPaint()); 224 TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY, 225 getTextAnchor(), getRotationAngle(), getRotationAnchor()); 226 227 } 228 229 /** 230 * Tests this object for equality with another. 231 * 232 * @param obj the object (<code>null</code> permitted). 233 * 234 * @return <code>true</code> or <code>false</code>. 235 */ 236 public boolean equals(Object obj) { 237 if (obj == this) { 238 return true; 239 } 240 if (!(obj instanceof CategoryTextAnnotation)) { 241 return false; 242 } 243 CategoryTextAnnotation that = (CategoryTextAnnotation) obj; 244 if (!super.equals(obj)) { 245 return false; 246 } 247 if (!this.category.equals(that.getCategory())) { 248 return false; 249 } 250 if (!this.categoryAnchor.equals(that.getCategoryAnchor())) { 251 return false; 252 } 253 if (this.value != that.getValue()) { 254 return false; 255 } 256 return true; 257 } 258 259 /** 260 * Returns a hash code for this instance. 261 * 262 * @return A hash code. 263 */ 264 public int hashCode() { 265 int result = super.hashCode(); 266 result = 37 * result + this.category.hashCode(); 267 result = 37 * result + this.categoryAnchor.hashCode(); 268 long temp = Double.doubleToLongBits(this.value); 269 result = 37 * result + (int) (temp ^ (temp >>> 32)); 270 return result; 271 } 272 273 /** 274 * Returns a clone of the annotation. 275 * 276 * @return A clone. 277 * 278 * @throws CloneNotSupportedException this class will not throw this 279 * exception, but subclasses (if any) might. 280 */ 281 public Object clone() throws CloneNotSupportedException { 282 return super.clone(); 283 } 284 285}