Frames | No Frames |
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: * LookupPaintScale.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: * 05-Jul-2006 : Version 1 (DG); 38: * 31-Jan-2007 : Fixed serialization support (DG); 39: * 09-Mar-2007 : Fixed cloning (DG); 40: * 14-Jun-2007 : Use double primitive in PaintItem (DG); 41: * 42: */ 43: 44: package org.jfree.chart.renderer; 45: 46: import java.awt.Color; 47: import java.awt.Paint; 48: import java.io.IOException; 49: import java.io.ObjectInputStream; 50: import java.io.ObjectOutputStream; 51: import java.io.Serializable; 52: import java.util.Collections; 53: import java.util.List; 54: 55: import org.jfree.io.SerialUtilities; 56: import org.jfree.util.PaintUtilities; 57: import org.jfree.util.PublicCloneable; 58: 59: /** 60: * A paint scale that uses a lookup table to associate paint instances 61: * with data value ranges. 62: * 63: * @since 1.0.4 64: */ 65: public class LookupPaintScale 66: implements PaintScale, PublicCloneable, Serializable { 67: 68: /** 69: * Stores the paint for a value. 70: */ 71: class PaintItem implements Comparable, Serializable { 72: 73: /** For serialization. */ 74: static final long serialVersionUID = 698920578512361570L; 75: 76: /** The value. */ 77: double value; 78: 79: /** The paint. */ 80: transient Paint paint; 81: 82: /** 83: * Creates a new instance. 84: * 85: * @param value the value. 86: * @param paint the paint. 87: */ 88: public PaintItem(double value, Paint paint) { 89: this.value = value; 90: this.paint = paint; 91: } 92: 93: /* (non-Javadoc) 94: * @see java.lang.Comparable#compareTo(java.lang.Object) 95: */ 96: public int compareTo(Object obj) { 97: PaintItem that = (PaintItem) obj; 98: double d1 = this.value; 99: double d2 = that.value; 100: if (d1 > d2) { 101: return 1; 102: } 103: if (d1 < d2) { 104: return -1; 105: } 106: return 0; 107: } 108: 109: /** 110: * Tests this item for equality with an arbitrary object. 111: * 112: * @param obj the object (<code>null</code> permitted). 113: * 114: * @return A boolean. 115: */ 116: public boolean equals(Object obj) { 117: if (obj == this) { 118: return true; 119: } 120: if (!(obj instanceof PaintItem)) { 121: return false; 122: } 123: PaintItem that = (PaintItem) obj; 124: if (this.value != that.value) { 125: return false; 126: } 127: if (!PaintUtilities.equal(this.paint, that.paint)) { 128: return false; 129: } 130: return true; 131: } 132: 133: /** 134: * Provides serialization support. 135: * 136: * @param stream the output stream. 137: * 138: * @throws IOException if there is an I/O error. 139: */ 140: private void writeObject(ObjectOutputStream stream) throws IOException { 141: stream.defaultWriteObject(); 142: SerialUtilities.writePaint(this.paint, stream); 143: } 144: 145: /** 146: * Provides serialization support. 147: * 148: * @param stream the input stream. 149: * 150: * @throws IOException if there is an I/O error. 151: * @throws ClassNotFoundException if there is a classpath problem. 152: */ 153: private void readObject(ObjectInputStream stream) 154: throws IOException, ClassNotFoundException { 155: stream.defaultReadObject(); 156: this.paint = SerialUtilities.readPaint(stream); 157: } 158: 159: } 160: 161: /** For serialization. */ 162: static final long serialVersionUID = -5239384246251042006L; 163: 164: /** The lower bound. */ 165: private double lowerBound; 166: 167: /** The upper bound. */ 168: private double upperBound; 169: 170: /** The default paint. */ 171: private transient Paint defaultPaint; 172: 173: /** The lookup table. */ 174: private List lookupTable; 175: 176: /** 177: * Creates a new paint scale. 178: */ 179: public LookupPaintScale() { 180: this(0.0, 1.0, Color.lightGray); 181: } 182: 183: /** 184: * Creates a new paint scale with the specified default paint. 185: * 186: * @param lowerBound the lower bound. 187: * @param upperBound the upper bound. 188: * @param defaultPaint the default paint (<code>null</code> not 189: * permitted). 190: */ 191: public LookupPaintScale(double lowerBound, double upperBound, 192: Paint defaultPaint) { 193: if (lowerBound >= upperBound) { 194: throw new IllegalArgumentException( 195: "Requires lowerBound < upperBound."); 196: } 197: if (defaultPaint == null) { 198: throw new IllegalArgumentException("Null 'paint' argument."); 199: } 200: this.lowerBound = lowerBound; 201: this.upperBound = upperBound; 202: this.defaultPaint = defaultPaint; 203: this.lookupTable = new java.util.ArrayList(); 204: } 205: 206: /** 207: * Returns the default paint (never <code>null</code>). 208: * 209: * @return The default paint. 210: */ 211: public Paint getDefaultPaint() { 212: return this.defaultPaint; 213: } 214: 215: /** 216: * Returns the lower bound. 217: * 218: * @return The lower bound. 219: * 220: * @see #getUpperBound() 221: */ 222: public double getLowerBound() { 223: return this.lowerBound; 224: } 225: 226: /** 227: * Returns the upper bound. 228: * 229: * @return The upper bound. 230: * 231: * @see #getLowerBound() 232: */ 233: public double getUpperBound() { 234: return this.upperBound; 235: } 236: 237: /** 238: * Adds an entry to the lookup table. Any values from <code>n</code> up 239: * to but not including the next value in the table take on the specified 240: * <code>paint</code>. 241: * 242: * @param value the data value (<code>null</code> not permitted). 243: * @param paint the paint. 244: * 245: * @deprecated Use {@link #add(double, Paint)}. 246: */ 247: public void add(Number value, Paint paint) { 248: add(value.doubleValue(), paint); 249: } 250: 251: /** 252: * Adds an entry to the lookup table. Any values from <code>n</code> up 253: * to but not including the next value in the table take on the specified 254: * <code>paint</code>. 255: * 256: * @param value the data value. 257: * @param paint the paint. 258: * 259: * @since 1.0.6 260: */ 261: public void add(double value, Paint paint) { 262: PaintItem item = new PaintItem(value, paint); 263: int index = Collections.binarySearch(this.lookupTable, item); 264: if (index >= 0) { 265: this.lookupTable.set(index, item); 266: } 267: else { 268: this.lookupTable.add(-(index + 1), item); 269: } 270: } 271: 272: /** 273: * Returns the paint associated with the specified value. 274: * 275: * @param value the value. 276: * 277: * @return The paint. 278: * 279: * @see #getDefaultPaint() 280: */ 281: public Paint getPaint(double value) { 282: 283: // handle value outside bounds... 284: if (value < this.lowerBound) { 285: return this.defaultPaint; 286: } 287: if (value > this.upperBound) { 288: return this.defaultPaint; 289: } 290: 291: int count = this.lookupTable.size(); 292: if (count == 0) { 293: return this.defaultPaint; 294: } 295: 296: // handle special case where value is less that item zero 297: PaintItem item = (PaintItem) this.lookupTable.get(0); 298: if (value < item.value) { 299: return this.defaultPaint; 300: } 301: 302: // for value in bounds, do the lookup... 303: int low = 0; 304: int high = this.lookupTable.size() - 1; 305: while (high - low > 1) { 306: int current = (low + high) / 2; 307: item = (PaintItem) this.lookupTable.get(current); 308: if (value >= item.value) { 309: low = current; 310: } 311: else { 312: high = current; 313: } 314: } 315: if (high > low) { 316: item = (PaintItem) this.lookupTable.get(high); 317: if (value < item.value) { 318: item = (PaintItem) this.lookupTable.get(low); 319: } 320: } 321: return (item != null ? item.paint : this.defaultPaint); 322: } 323: 324: 325: /** 326: * Tests this instance for equality with an arbitrary object. 327: * 328: * @param obj the object (<code>null</code> permitted). 329: * 330: * @return A boolean. 331: */ 332: public boolean equals(Object obj) { 333: if (obj == this) { 334: return true; 335: } 336: if (!(obj instanceof LookupPaintScale)) { 337: return false; 338: } 339: LookupPaintScale that = (LookupPaintScale) obj; 340: if (this.lowerBound != that.lowerBound) { 341: return false; 342: } 343: if (this.upperBound != that.upperBound) { 344: return false; 345: } 346: if (!PaintUtilities.equal(this.defaultPaint, that.defaultPaint)) { 347: return false; 348: } 349: if (!this.lookupTable.equals(that.lookupTable)) { 350: return false; 351: } 352: return true; 353: } 354: 355: /** 356: * Returns a clone of the instance. 357: * 358: * @return A clone. 359: * 360: * @throws CloneNotSupportedException if there is a problem cloning the 361: * instance. 362: */ 363: public Object clone() throws CloneNotSupportedException { 364: LookupPaintScale clone = (LookupPaintScale) super.clone(); 365: clone.lookupTable = new java.util.ArrayList(this.lookupTable); 366: return clone; 367: } 368: 369: /** 370: * Provides serialization support. 371: * 372: * @param stream the output stream. 373: * 374: * @throws IOException if there is an I/O error. 375: */ 376: private void writeObject(ObjectOutputStream stream) throws IOException { 377: stream.defaultWriteObject(); 378: SerialUtilities.writePaint(this.defaultPaint, stream); 379: } 380: 381: /** 382: * Provides serialization support. 383: * 384: * @param stream the input stream. 385: * 386: * @throws IOException if there is an I/O error. 387: * @throws ClassNotFoundException if there is a classpath problem. 388: */ 389: private void readObject(ObjectInputStream stream) 390: throws IOException, ClassNotFoundException { 391: stream.defaultReadObject(); 392: this.defaultPaint = SerialUtilities.readPaint(stream); 393: } 394: 395: }