Source for org.jfree.chart.plot.dial.DialCap

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, 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:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * ------------
  28:  * DialCap.java
  29:  * ------------
  30:  * (C) Copyright 2006, 2007, 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.io.SerialUtilities;
  58: import org.jfree.util.PaintUtilities;
  59: import org.jfree.util.PublicCloneable;
  60: 
  61: /**
  62:  * A regular dial layer that can be used to draw a cap over the center of 
  63:  * the dial (the base of the dial pointer(s)).
  64:  * 
  65:  * @since 1.0.7
  66:  */
  67: public class DialCap extends AbstractDialLayer implements DialLayer, Cloneable, 
  68:         PublicCloneable, Serializable {
  69:     
  70:     /** For serialization. */
  71:     static final long serialVersionUID = -2929484264982524463L;
  72: 
  73:     /**
  74:      * The radius of the cap, as a percentage of the framing rectangle.
  75:      */
  76:     private double radius;
  77:     
  78:     /** 
  79:      * The fill paint.  This field is transient because it requires special
  80:      * handling for serialization.
  81:      */
  82:     private transient Paint fillPaint;
  83:     
  84:     /** 
  85:      * The paint used to draw the cap outline (this should never be 
  86:      * <code>null</code>).  This field is transient because it requires
  87:      * special handling for serialization.
  88:      */
  89:     private transient Paint outlinePaint;
  90:     
  91:     /** 
  92:      * The stroke used to draw the cap outline (this should never be 
  93:      * <code>null</code>).   This field is transient because it requires
  94:      * special handling for serialization.
  95:      */
  96:     private transient Stroke outlineStroke;
  97:     
  98:     /** 
  99:      * Creates a new instance of <code>StandardDialBackground</code>.  The 
 100:      * default background paint is <code>Color.white</code>.
 101:      */
 102:     public DialCap() {
 103:         this.radius = 0.05;
 104:         this.fillPaint = Color.white;
 105:         this.outlinePaint = Color.black;
 106:         this.outlineStroke = new BasicStroke(2.0f);
 107:     }
 108:     
 109:     /**
 110:      * Returns the radius of the cap, as a percentage of the dial's framing
 111:      * rectangle.
 112:      *
 113:      * @return The radius.
 114:      *
 115:      * @see #setRadius(double)
 116:      */
 117:     public double getRadius() {
 118:         return this.radius;
 119:     }
 120:     
 121:     /**
 122:      * Sets the radius of the cap, as a percentage of the dial's framing
 123:      * rectangle, and sends a {@link DialLayerChangeEvent} to all registered
 124:      * listeners.
 125:      *
 126:      * @param radius  the radius (must be greater than zero).
 127:      *
 128:      * @see #getRadius()
 129:      */
 130:     public void setRadius(double radius) {
 131:         if (radius <= 0.0) {
 132:             throw new IllegalArgumentException("Requires radius > 0.0.");
 133:         }
 134:         this.radius = radius;
 135:         notifyListeners(new DialLayerChangeEvent(this));
 136:     }
 137:     
 138:     /**
 139:      * Returns the paint used to fill the cap. 
 140:      *
 141:      * @return The paint (never <code>null</code>).
 142:      *
 143:      * @see #setFillPaint(Paint)
 144:      */
 145:     public Paint getFillPaint() {
 146:         return this.fillPaint;
 147:     }
 148:     
 149:     /**
 150:      * Sets the paint for the cap background and sends a 
 151:      * {@link DialLayerChangeEvent} to all registered listeners.
 152:      *
 153:      * @param paint  the paint (<code>null</code> not permitted).
 154:      *
 155:      * @see #getFillPaint()
 156:      */
 157:     public void setFillPaint(Paint paint) {
 158:         if (paint == null) {
 159:             throw new IllegalArgumentException("Null 'paint' argument.");
 160:         }
 161:         this.fillPaint = paint;
 162:         notifyListeners(new DialLayerChangeEvent(this));
 163:     }
 164:         
 165:     /**
 166:      * Returns the paint used to draw the outline of the cap. 
 167:      *
 168:      * @return The paint (never <code>null</code>).
 169:      *
 170:      * @see #setOutlinePaint(Paint)
 171:      */
 172:     public Paint getOutlinePaint() {
 173:         return this.outlinePaint;
 174:     }
 175:     
 176:     /**
 177:      * Sets the paint used to draw the outline of the cap and sends a 
 178:      * {@link DialLayerChangeEvent} to all registered listeners.
 179:      *
 180:      * @param paint  the paint (<code>null</code> not permitted).
 181:      *
 182:      * @see #getOutlinePaint()
 183:      */
 184:     public void setOutlinePaint(Paint paint) {
 185:         if (paint == null) {
 186:             throw new IllegalArgumentException("Null 'paint' argument.");
 187:         }
 188:         this.outlinePaint = paint;
 189:         notifyListeners(new DialLayerChangeEvent(this));
 190:     }
 191:         
 192:     /**
 193:      * Returns the stroke used to draw the outline of the cap. 
 194:      *
 195:      * @return The stroke (never <code>null</code>).
 196:      *
 197:      * @see #setOutlineStroke(Stroke)
 198:      */
 199:     public Stroke getOutlineStroke() {
 200:         return this.outlineStroke;
 201:     }
 202:     
 203:     /**
 204:      * Sets the stroke used to draw the outline of the cap and sends a 
 205:      * {@link DialLayerChangeEvent} to all registered listeners.
 206:      *
 207:      * @param stroke  the stroke (<code>null</code> not permitted).
 208:      *
 209:      * @see #getOutlineStroke()
 210:      */
 211:     public void setOutlineStroke(Stroke stroke) {
 212:         if (stroke == null) {
 213:             throw new IllegalArgumentException("Null 'stroke' argument.");
 214:         }
 215:         this.outlineStroke = stroke;
 216:         notifyListeners(new DialLayerChangeEvent(this));
 217:     }
 218:     
 219:     /**
 220:      * Returns <code>true</code> to indicate that this layer should be 
 221:      * clipped within the dial window. 
 222:      *
 223:      * @return <code>true</code>.
 224:      */
 225:     public boolean isClippedToWindow() {
 226:         return true;
 227:     }
 228:     
 229:     /**
 230:      * Draws the background to the specified graphics device.  If the dial
 231:      * frame specifies a window, the clipping region will already have been 
 232:      * set to this window before this method is called.
 233:      *
 234:      * @param g2  the graphics device (<code>null</code> not permitted).
 235:      * @param plot  the plot (ignored here).
 236:      * @param frame  the dial frame (ignored here).
 237:      * @param view  the view rectangle (<code>null</code> not permitted). 
 238:      */
 239:     public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, 
 240:             Rectangle2D view) {
 241: 
 242:         g2.setPaint(this.fillPaint);
 243:         
 244:         Rectangle2D f = DialPlot.rectangleByRadius(frame, this.radius, 
 245:                 this.radius);
 246:         Ellipse2D e = new Ellipse2D.Double(f.getX(), f.getY(), f.getWidth(), 
 247:                 f.getHeight());
 248:         g2.fill(e);
 249:         g2.setPaint(this.outlinePaint);
 250:         g2.setStroke(this.outlineStroke);
 251:         g2.draw(e);
 252:         
 253:     }
 254:     
 255:     /**
 256:      * Tests this instance for equality with an arbitrary object.
 257:      *
 258:      * @param obj  the object (<code>null</code> permitted).
 259:      *
 260:      * @return A boolean.
 261:      */
 262:     public boolean equals(Object obj) {
 263:         if (obj == this) {
 264:             return true;
 265:         }
 266:         if (!(obj instanceof DialCap)) {
 267:             return false;
 268:         }
 269:         DialCap that = (DialCap) obj;
 270:         if (this.radius != that.radius) {
 271:             return false;
 272:         }
 273:         if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) {
 274:             return false;
 275:         }
 276:         if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
 277:             return false;
 278:         }
 279:         if (!this.outlineStroke.equals(that.outlineStroke)) {
 280:             return false;
 281:         }
 282:         return super.equals(obj);
 283:     }
 284:     
 285:     /**
 286:      * Returns a hash code for this instance.
 287:      * 
 288:      * @return The hash code.
 289:      */
 290:     public int hashCode() {
 291:         int result = 193;
 292:         result = 37 * result + HashUtilities.hashCodeForPaint(this.fillPaint);
 293:         result = 37 * result + HashUtilities.hashCodeForPaint(
 294:                 this.outlinePaint);
 295:         result = 37 * result + this.outlineStroke.hashCode();
 296:         return result;
 297:     }
 298:     
 299:     /**
 300:      * Returns a clone of this instance.
 301:      *
 302:      * @return A clone.
 303:      * 
 304:      * @throws CloneNotSupportedException if some attribute of the cap cannot
 305:      *     be cloned.
 306:      */
 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:      */
 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:      */
 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: