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: public class DialCap extends AbstractDialLayer implements DialLayer, Cloneable, 
  66:         PublicCloneable, Serializable {
  67:     
  68:     /** For serialization. */
  69:     static final long serialVersionUID = -2929484264982524463L;
  70: 
  71:     /**
  72:      * The radius of the cap, as a percentage of the framing rectangle.
  73:      */
  74:     private double radius;
  75:     
  76:     /** 
  77:      * The fill paint.  This field is transient because it requires special
  78:      * handling for serialization.
  79:      */
  80:     private transient Paint fillPaint;
  81:     
  82:     /** 
  83:      * The paint used to draw the cap outline (this should never be 
  84:      * <code>null</code>).  This field is transient because it requires
  85:      * special handling for serialization.
  86:      */
  87:     private transient Paint outlinePaint;
  88:     
  89:     /** 
  90:      * The stroke used to draw the cap outline (this should never be 
  91:      * <code>null</code>).   This field is transient because it requires
  92:      * special handling for serialization.
  93:      */
  94:     private transient Stroke outlineStroke;
  95:     
  96:     /** 
  97:      * Creates a new instance of <code>StandardDialBackground</code>.  The 
  98:      * default background paint is <code>Color.white</code>.
  99:      */
 100:     public DialCap() {
 101:         this.radius = 0.05;
 102:         this.fillPaint = Color.white;
 103:         this.outlinePaint = Color.black;
 104:         this.outlineStroke = new BasicStroke(2.0f);
 105:     }
 106:     
 107:     /**
 108:      * Returns the radius of the cap, as a percentage of the dial's framing
 109:      * rectangle.
 110:      *
 111:      * @return The radius.
 112:      *
 113:      * @see #setRadius(double)
 114:      */
 115:     public double getRadius() {
 116:         return this.radius;
 117:     }
 118:     
 119:     /**
 120:      * Sets the radius of the cap, as a percentage of the dial's framing
 121:      * rectangle, and sends a {@link DialLayerChangeEvent} to all registered
 122:      * listeners.
 123:      *
 124:      * @param radius  the radius (must be greater than zero).
 125:      *
 126:      * @see #getRadius()
 127:      */
 128:     public void setRadius(double radius) {
 129:         if (radius <= 0.0) {
 130:             throw new IllegalArgumentException("Requires radius > 0.0.");
 131:         }
 132:         this.radius = radius;
 133:         notifyListeners(new DialLayerChangeEvent(this));
 134:     }
 135:     
 136:     /**
 137:      * Returns the paint used to fill the cap. 
 138:      *
 139:      * @return The paint (never <code>null</code>).
 140:      *
 141:      * @see #setFillPaint(Paint)
 142:      */
 143:     public Paint getFillPaint() {
 144:         return this.fillPaint;
 145:     }
 146:     
 147:     /**
 148:      * Sets the paint for the cap background and sends a 
 149:      * {@link DialLayerChangeEvent} to all registered listeners.
 150:      *
 151:      * @param paint  the paint (<code>null</code> not permitted).
 152:      *
 153:      * @see #getFillPaint()
 154:      */
 155:     public void setFillPaint(Paint paint) {
 156:         if (paint == null) {
 157:             throw new IllegalArgumentException("Null 'paint' argument.");
 158:         }
 159:         this.fillPaint = paint;
 160:         notifyListeners(new DialLayerChangeEvent(this));
 161:     }
 162:         
 163:     /**
 164:      * Returns the paint used to draw the outline of the cap. 
 165:      *
 166:      * @return The paint (never <code>null</code>).
 167:      *
 168:      * @see #setOutlinePaint(Paint)
 169:      */
 170:     public Paint getOutlinePaint() {
 171:         return this.outlinePaint;
 172:     }
 173:     
 174:     /**
 175:      * Sets the paint used to draw the outline of the cap and sends a 
 176:      * {@link DialLayerChangeEvent} to all registered listeners.
 177:      *
 178:      * @param paint  the paint (<code>null</code> not permitted).
 179:      *
 180:      * @see #getOutlinePaint()
 181:      */
 182:     public void setOutlinePaint(Paint paint) {
 183:         if (paint == null) {
 184:             throw new IllegalArgumentException("Null 'paint' argument.");
 185:         }
 186:         this.outlinePaint = paint;
 187:         notifyListeners(new DialLayerChangeEvent(this));
 188:     }
 189:         
 190:     /**
 191:      * Returns the stroke used to draw the outline of the cap. 
 192:      *
 193:      * @return The stroke (never <code>null</code>).
 194:      *
 195:      * @see #setOutlineStroke(Stroke)
 196:      */
 197:     public Stroke getOutlineStroke() {
 198:         return this.outlineStroke;
 199:     }
 200:     
 201:     /**
 202:      * Sets the stroke used to draw the outline of the cap and sends a 
 203:      * {@link DialLayerChangeEvent} to all registered listeners.
 204:      *
 205:      * @param stroke  the stroke (<code>null</code> not permitted).
 206:      *
 207:      * @see #getOutlineStroke()
 208:      */
 209:     public void setOutlineStroke(Stroke stroke) {
 210:         if (stroke == null) {
 211:             throw new IllegalArgumentException("Null 'stroke' argument.");
 212:         }
 213:         this.outlineStroke = stroke;
 214:         notifyListeners(new DialLayerChangeEvent(this));
 215:     }
 216:     
 217:     /**
 218:      * Returns <code>true</code> to indicate that this layer should be 
 219:      * clipped within the dial window. 
 220:      *
 221:      * @return <code>true</code>.
 222:      */
 223:     public boolean isClippedToWindow() {
 224:         return true;
 225:     }
 226:     
 227:     /**
 228:      * Draws the background to the specified graphics device.  If the dial
 229:      * frame specifies a window, the clipping region will already have been 
 230:      * set to this window before this method is called.
 231:      *
 232:      * @param g2  the graphics device (<code>null</code> not permitted).
 233:      * @param plot  the plot (ignored here).
 234:      * @param frame  the dial frame (ignored here).
 235:      * @param view  the view rectangle (<code>null</code> not permitted). 
 236:      */
 237:     public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, 
 238:             Rectangle2D view) {
 239: 
 240:         g2.setPaint(this.fillPaint);
 241:         
 242:         Rectangle2D f = DialPlot.rectangleByRadius(frame, this.radius, 
 243:                 this.radius);
 244:         Ellipse2D e = new Ellipse2D.Double(f.getX(), f.getY(), f.getWidth(), 
 245:                 f.getHeight());
 246:         g2.fill(e);
 247:         g2.setPaint(this.outlinePaint);
 248:         g2.setStroke(this.outlineStroke);
 249:         g2.draw(e);
 250:         
 251:     }
 252:     
 253:     /**
 254:      * Tests this instance for equality with an arbitrary object.
 255:      *
 256:      * @param obj  the object (<code>null</code> permitted).
 257:      *
 258:      * @return A boolean.
 259:      */
 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:     public int hashCode() {
 289:         int result = 193;
 290:         result = 37 * result + HashUtilities.hashCodeForPaint(this.fillPaint);
 291:         result = 37 * result + HashUtilities.hashCodeForPaint(
 292:                 this.outlinePaint);
 293:         result = 37 * result + this.outlineStroke.hashCode();
 294:         return result;
 295:     }
 296:     
 297:     /**
 298:      * Returns a clone of this instance.
 299:      *
 300:      * @return A clone.
 301:      * 
 302:      * @throws CloneNotSupportedException if some attribute of the cap cannot
 303:      *     be cloned.
 304:      */
 305:     public Object clone() throws CloneNotSupportedException {
 306:         return super.clone();
 307:     }
 308:     
 309:     /**
 310:      * Provides serialization support.
 311:      *
 312:      * @param stream  the output stream.
 313:      *
 314:      * @throws IOException  if there is an I/O error.
 315:      */
 316:     private void writeObject(ObjectOutputStream stream) throws IOException {
 317:         stream.defaultWriteObject();
 318:         SerialUtilities.writePaint(this.fillPaint, stream);
 319:         SerialUtilities.writePaint(this.outlinePaint, stream);
 320:         SerialUtilities.writeStroke(this.outlineStroke, stream);
 321:     }
 322: 
 323:     /**
 324:      * Provides serialization support.
 325:      *
 326:      * @param stream  the input stream.
 327:      *
 328:      * @throws IOException  if there is an I/O error.
 329:      * @throws ClassNotFoundException  if there is a classpath problem.
 330:      */
 331:     private void readObject(ObjectInputStream stream) 
 332:             throws IOException, ClassNotFoundException {
 333:         stream.defaultReadObject();
 334:         this.fillPaint = SerialUtilities.readPaint(stream);
 335:         this.outlinePaint = SerialUtilities.readPaint(stream);
 336:         this.outlineStroke = SerialUtilities.readStroke(stream);
 337:     }
 338:     
 339: }
 340: