1 /* =========================================================== 2 * JFreeChart : a free chart library for the Java(tm) platform 3 * =========================================================== 4 * 5 * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors. 6 * 7 * Project Info: http://www.jfree.org/jfreechart/index.html 8 * 9 * This library is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU Lesser General Public License as published by 11 * the Free Software Foundation; either version 2.1 of the License, or 12 * (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17 * License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 22 * USA. 23 * 24 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 25 * Other names may be trademarks of their respective owners.] 26 * 27 * ------------ 28 * DialCap.java 29 * ------------ 30 * (C) Copyright 2006-2013, by Object Refinery Limited. 31 * 32 * Original Author: David Gilbert (for Object Refinery Limited); 33 * Contributor(s): -; 34 * 35 * Changes 36 * ------- 37 * 03-Nov-2006 : Version 1 (DG); 38 * 17-Oct-2007 : Updated equals() method (DG); 39 * 40 */ 41 42 package org.jfree.chart.plot.dial; 43 44 import java.awt.BasicStroke; 45 import java.awt.Color; 46 import java.awt.Graphics2D; 47 import java.awt.Paint; 48 import java.awt.Stroke; 49 import java.awt.geom.Ellipse2D; 50 import java.awt.geom.Rectangle2D; 51 import java.io.IOException; 52 import java.io.ObjectInputStream; 53 import java.io.ObjectOutputStream; 54 import java.io.Serializable; 55 56 import org.jfree.chart.HashUtilities; 57 import org.jfree.chart.util.ParamChecks; 58 import org.jfree.io.SerialUtilities; 59 import org.jfree.util.PaintUtilities; 60 import org.jfree.util.PublicCloneable; 61 62 /** 63 * A regular dial layer that can be used to draw a cap over the center of 64 * the dial (the base of the dial pointer(s)). 65 * 66 * @since 1.0.7 67 */ 68 public class DialCap extends AbstractDialLayer implements DialLayer, Cloneable, 69 PublicCloneable, Serializable { 70 71 /** For serialization. */ 72 static final long serialVersionUID = -2929484264982524463L; 73 74 /** 75 * The radius of the cap, as a percentage of the framing rectangle. 76 */ 77 private double radius; 78 79 /** 80 * The fill paint. This field is transient because it requires special 81 * handling for serialization. 82 */ 83 private transient Paint fillPaint; 84 85 /** 86 * The paint used to draw the cap outline (this should never be 87 * <code>null</code>). This field is transient because it requires 88 * special handling for serialization. 89 */ 90 private transient Paint outlinePaint; 91 92 /** 93 * The stroke used to draw the cap outline (this should never be 94 * <code>null</code>). This field is transient because it requires 95 * special handling for serialization. 96 */ 97 private transient Stroke outlineStroke; 98 99 /** 100 * Creates a new instance of <code>StandardDialBackground</code>. The 101 * default background paint is <code>Color.white</code>. 102 */ DialCap()103 public DialCap() { 104 this.radius = 0.05; 105 this.fillPaint = Color.white; 106 this.outlinePaint = Color.black; 107 this.outlineStroke = new BasicStroke(2.0f); 108 } 109 110 /** 111 * Returns the radius of the cap, as a percentage of the dial's framing 112 * rectangle. 113 * 114 * @return The radius. 115 * 116 * @see #setRadius(double) 117 */ getRadius()118 public double getRadius() { 119 return this.radius; 120 } 121 122 /** 123 * Sets the radius of the cap, as a percentage of the dial's framing 124 * rectangle, and sends a {@link DialLayerChangeEvent} to all registered 125 * listeners. 126 * 127 * @param radius the radius (must be greater than zero). 128 * 129 * @see #getRadius() 130 */ setRadius(double radius)131 public void setRadius(double radius) { 132 if (radius <= 0.0) { 133 throw new IllegalArgumentException("Requires radius > 0.0."); 134 } 135 this.radius = radius; 136 notifyListeners(new DialLayerChangeEvent(this)); 137 } 138 139 /** 140 * Returns the paint used to fill the cap. 141 * 142 * @return The paint (never <code>null</code>). 143 * 144 * @see #setFillPaint(Paint) 145 */ getFillPaint()146 public Paint getFillPaint() { 147 return this.fillPaint; 148 } 149 150 /** 151 * Sets the paint for the cap background and sends a 152 * {@link DialLayerChangeEvent} to all registered listeners. 153 * 154 * @param paint the paint (<code>null</code> not permitted). 155 * 156 * @see #getFillPaint() 157 */ setFillPaint(Paint paint)158 public void setFillPaint(Paint paint) { 159 ParamChecks.nullNotPermitted(paint, "paint"); 160 this.fillPaint = paint; 161 notifyListeners(new DialLayerChangeEvent(this)); 162 } 163 164 /** 165 * Returns the paint used to draw the outline of the cap. 166 * 167 * @return The paint (never <code>null</code>). 168 * 169 * @see #setOutlinePaint(Paint) 170 */ getOutlinePaint()171 public Paint getOutlinePaint() { 172 return this.outlinePaint; 173 } 174 175 /** 176 * Sets the paint used to draw the outline of the cap and sends a 177 * {@link DialLayerChangeEvent} to all registered listeners. 178 * 179 * @param paint the paint (<code>null</code> not permitted). 180 * 181 * @see #getOutlinePaint() 182 */ setOutlinePaint(Paint paint)183 public void setOutlinePaint(Paint paint) { 184 ParamChecks.nullNotPermitted(paint, "paint"); 185 this.outlinePaint = paint; 186 notifyListeners(new DialLayerChangeEvent(this)); 187 } 188 189 /** 190 * Returns the stroke used to draw the outline of the cap. 191 * 192 * @return The stroke (never <code>null</code>). 193 * 194 * @see #setOutlineStroke(Stroke) 195 */ getOutlineStroke()196 public Stroke getOutlineStroke() { 197 return this.outlineStroke; 198 } 199 200 /** 201 * Sets the stroke used to draw the outline of the cap and sends a 202 * {@link DialLayerChangeEvent} to all registered listeners. 203 * 204 * @param stroke the stroke (<code>null</code> not permitted). 205 * 206 * @see #getOutlineStroke() 207 */ setOutlineStroke(Stroke stroke)208 public void setOutlineStroke(Stroke stroke) { 209 ParamChecks.nullNotPermitted(stroke, "stroke"); 210 this.outlineStroke = stroke; 211 notifyListeners(new DialLayerChangeEvent(this)); 212 } 213 214 /** 215 * Returns <code>true</code> to indicate that this layer should be 216 * clipped within the dial window. 217 * 218 * @return <code>true</code>. 219 */ 220 @Override isClippedToWindow()221 public boolean isClippedToWindow() { 222 return true; 223 } 224 225 /** 226 * Draws the background to the specified graphics device. If the dial 227 * frame specifies a window, the clipping region will already have been 228 * set to this window before this method is called. 229 * 230 * @param g2 the graphics device (<code>null</code> not permitted). 231 * @param plot the plot (ignored here). 232 * @param frame the dial frame (ignored here). 233 * @param view the view rectangle (<code>null</code> not permitted). 234 */ 235 @Override draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, Rectangle2D view)236 public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, 237 Rectangle2D view) { 238 239 g2.setPaint(this.fillPaint); 240 241 Rectangle2D f = DialPlot.rectangleByRadius(frame, this.radius, 242 this.radius); 243 Ellipse2D e = new Ellipse2D.Double(f.getX(), f.getY(), f.getWidth(), 244 f.getHeight()); 245 g2.fill(e); 246 g2.setPaint(this.outlinePaint); 247 g2.setStroke(this.outlineStroke); 248 g2.draw(e); 249 250 } 251 252 /** 253 * Tests this instance for equality with an arbitrary object. 254 * 255 * @param obj the object (<code>null</code> permitted). 256 * 257 * @return A boolean. 258 */ 259 @Override equals(Object obj)260 public boolean equals(Object obj) { 261 if (obj == this) { 262 return true; 263 } 264 if (!(obj instanceof DialCap)) { 265 return false; 266 } 267 DialCap that = (DialCap) obj; 268 if (this.radius != that.radius) { 269 return false; 270 } 271 if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) { 272 return false; 273 } 274 if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) { 275 return false; 276 } 277 if (!this.outlineStroke.equals(that.outlineStroke)) { 278 return false; 279 } 280 return super.equals(obj); 281 } 282 283 /** 284 * Returns a hash code for this instance. 285 * 286 * @return The hash code. 287 */ 288 @Override hashCode()289 public int hashCode() { 290 int result = 193; 291 result = 37 * result + HashUtilities.hashCodeForPaint(this.fillPaint); 292 result = 37 * result + HashUtilities.hashCodeForPaint( 293 this.outlinePaint); 294 result = 37 * result + this.outlineStroke.hashCode(); 295 return result; 296 } 297 298 /** 299 * Returns a clone of this instance. 300 * 301 * @return A clone. 302 * 303 * @throws CloneNotSupportedException if some attribute of the cap cannot 304 * be cloned. 305 */ 306 @Override clone()307 public Object clone() throws CloneNotSupportedException { 308 return super.clone(); 309 } 310 311 /** 312 * Provides serialization support. 313 * 314 * @param stream the output stream. 315 * 316 * @throws IOException if there is an I/O error. 317 */ writeObject(ObjectOutputStream stream)318 private void writeObject(ObjectOutputStream stream) throws IOException { 319 stream.defaultWriteObject(); 320 SerialUtilities.writePaint(this.fillPaint, stream); 321 SerialUtilities.writePaint(this.outlinePaint, stream); 322 SerialUtilities.writeStroke(this.outlineStroke, stream); 323 } 324 325 /** 326 * Provides serialization support. 327 * 328 * @param stream the input stream. 329 * 330 * @throws IOException if there is an I/O error. 331 * @throws ClassNotFoundException if there is a classpath problem. 332 */ readObject(ObjectInputStream stream)333 private void readObject(ObjectInputStream stream) 334 throws IOException, ClassNotFoundException { 335 stream.defaultReadObject(); 336 this.fillPaint = SerialUtilities.readPaint(stream); 337 this.outlinePaint = SerialUtilities.readPaint(stream); 338 this.outlineStroke = SerialUtilities.readStroke(stream); 339 } 340 341 } 342 343