001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2007, 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * --------------------- 028 * LookupPaintScale.java 029 * --------------------- 030 * (C) Copyright 2006, 2007, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: LookupPaintScale.java,v 1.1.2.3 2007/03/09 15:59:21 mungady Exp $ 036 * 037 * Changes 038 * ------- 039 * 05-Jul-2006 : Version 1 (DG); 040 * 31-Jan-2007 : Fixed serialization support (DG); 041 * 09-Mar-2007 : Fixed cloning (DG); 042 * 043 */ 044 045 package org.jfree.chart.renderer; 046 047 import java.awt.Color; 048 import java.awt.Paint; 049 import java.io.IOException; 050 import java.io.ObjectInputStream; 051 import java.io.ObjectOutputStream; 052 import java.io.Serializable; 053 import java.util.Collections; 054 import java.util.List; 055 056 import org.jfree.io.SerialUtilities; 057 import org.jfree.util.PaintUtilities; 058 import org.jfree.util.PublicCloneable; 059 060 /** 061 * A paint scale that uses a lookup table to associate paint instances 062 * with data value ranges. 063 * 064 * @since 1.0.4 065 */ 066 public class LookupPaintScale 067 implements PaintScale, PublicCloneable, Serializable { 068 069 /** 070 * Stores the paint for a value. 071 */ 072 class PaintItem implements Comparable, Serializable { 073 074 /** The value. */ 075 Number value; 076 077 /** The paint. */ 078 transient Paint paint; 079 080 /** 081 * Creates a new instance. 082 * 083 * @param value the value. 084 * @param paint the paint. 085 */ 086 public PaintItem(Number value, Paint paint) { 087 this.value = value; 088 this.paint = paint; 089 } 090 091 /* (non-Javadoc) 092 * @see java.lang.Comparable#compareTo(java.lang.Object) 093 */ 094 public int compareTo(Object obj) { 095 PaintItem that = (PaintItem) obj; 096 double d1 = this.value.doubleValue(); 097 double d2 = that.value.doubleValue(); 098 if (d1 > d2) { 099 return 1; 100 } 101 if (d1 < d2) { 102 return -1; 103 } 104 return 0; 105 } 106 107 /** 108 * Tests this item for equality with an arbitrary object. 109 * 110 * @param obj the object (<code>null</code> permitted). 111 * 112 * @return A boolean. 113 */ 114 public boolean equals(Object obj) { 115 if (obj == this) { 116 return true; 117 } 118 if (!(obj instanceof PaintItem)) { 119 return false; 120 } 121 PaintItem that = (PaintItem) obj; 122 if (!this.value.equals(that.value)) { 123 return false; 124 } 125 if (!PaintUtilities.equal(this.paint, that.paint)) { 126 return false; 127 } 128 return true; 129 } 130 131 /** 132 * Provides serialization support. 133 * 134 * @param stream the output stream. 135 * 136 * @throws IOException if there is an I/O error. 137 */ 138 private void writeObject(ObjectOutputStream stream) throws IOException { 139 stream.defaultWriteObject(); 140 SerialUtilities.writePaint(this.paint, stream); 141 } 142 143 /** 144 * Provides serialization support. 145 * 146 * @param stream the input stream. 147 * 148 * @throws IOException if there is an I/O error. 149 * @throws ClassNotFoundException if there is a classpath problem. 150 */ 151 private void readObject(ObjectInputStream stream) 152 throws IOException, ClassNotFoundException { 153 stream.defaultReadObject(); 154 this.paint = SerialUtilities.readPaint(stream); 155 } 156 157 } 158 159 /** The lower bound. */ 160 private double lowerBound; 161 162 /** The upper bound. */ 163 private double upperBound; 164 165 /** The default paint. */ 166 private transient Paint defaultPaint; 167 168 /** The lookup table. */ 169 private List lookupTable; 170 171 /** 172 * Creates a new paint scale. 173 */ 174 public LookupPaintScale() { 175 this(0.0, 1.0, Color.lightGray); 176 } 177 178 /** 179 * Creates a new paint scale with the specified default paint. 180 * 181 * @param lowerBound the lower bound. 182 * @param upperBound the upper bound. 183 * @param defaultPaint the default paint (<code>null</code> not 184 * permitted). 185 */ 186 public LookupPaintScale(double lowerBound, double upperBound, 187 Paint defaultPaint) { 188 if (lowerBound >= upperBound) { 189 throw new IllegalArgumentException( 190 "Requires lowerBound < upperBound."); 191 } 192 if (defaultPaint == null) { 193 throw new IllegalArgumentException("Null 'paint' argument."); 194 } 195 this.lowerBound = lowerBound; 196 this.upperBound = upperBound; 197 this.defaultPaint = defaultPaint; 198 this.lookupTable = new java.util.ArrayList(); 199 } 200 201 /** 202 * Returns the default paint (never <code>null</code>). 203 * 204 * @return The default paint. 205 */ 206 public Paint getDefaultPaint() { 207 return this.defaultPaint; 208 } 209 210 /** 211 * Returns the lower bound. 212 * 213 * @return The lower bound. 214 * 215 * @see #getUpperBound() 216 */ 217 public double getLowerBound() { 218 return this.lowerBound; 219 } 220 221 /** 222 * Returns the upper bound. 223 * 224 * @return The upper bound. 225 * 226 * @see #getLowerBound() 227 */ 228 public double getUpperBound() { 229 return this.upperBound; 230 } 231 232 /** 233 * Adds an entry to the lookup table. Any values from <code>n</code> up 234 * to but not including the next value in the table take on the specified 235 * <code>paint</code>. 236 * 237 * @param value the data value. 238 * @param paint the paint. 239 */ 240 public void add(Number value, Paint paint) { 241 PaintItem item = new PaintItem(value, paint); 242 int index = Collections.binarySearch(this.lookupTable, item); 243 if (index >= 0) { 244 this.lookupTable.set(index, item); 245 } 246 else { 247 this.lookupTable.add(-(index + 1), item); 248 } 249 } 250 251 /** 252 * Returns the paint associated with the specified value. 253 * 254 * @param value the value. 255 * 256 * @return The paint. 257 * 258 * @see #getDefaultPaint() 259 */ 260 public Paint getPaint(double value) { 261 262 // handle value outside bounds... 263 if (value < this.lowerBound) { 264 return this.defaultPaint; 265 } 266 if (value > this.upperBound) { 267 return this.defaultPaint; 268 } 269 270 // for value in bounds, do the lookup... 271 Paint result = this.defaultPaint; 272 int index = this.lookupTable.size(); 273 boolean done = false; 274 while (index > 0 && !done) { 275 PaintItem item = (PaintItem) this.lookupTable.get(--index); 276 if (value >= item.value.doubleValue()) { 277 result = item.paint; 278 done = true; 279 } 280 } 281 return result; 282 } 283 284 /** 285 * Tests this instance for equality with an arbitrary object. 286 * 287 * @param obj the object (<code>null</code> permitted). 288 * 289 * @return A boolean. 290 */ 291 public boolean equals(Object obj) { 292 if (obj == this) { 293 return true; 294 } 295 if (!(obj instanceof LookupPaintScale)) { 296 return false; 297 } 298 LookupPaintScale that = (LookupPaintScale) obj; 299 if (this.lowerBound != that.lowerBound) { 300 return false; 301 } 302 if (this.upperBound != that.upperBound) { 303 return false; 304 } 305 if (!PaintUtilities.equal(this.defaultPaint, that.defaultPaint)) { 306 return false; 307 } 308 if (!this.lookupTable.equals(that.lookupTable)) { 309 return false; 310 } 311 return true; 312 } 313 314 /** 315 * Returns a clone of the instance. 316 * 317 * @return A clone. 318 * 319 * @throws CloneNotSupportedException if there is a problem cloning the 320 * instance. 321 */ 322 public Object clone() throws CloneNotSupportedException { 323 LookupPaintScale clone = (LookupPaintScale) super.clone(); 324 clone.lookupTable = new java.util.ArrayList(this.lookupTable); 325 return clone; 326 } 327 328 /** 329 * Provides serialization support. 330 * 331 * @param stream the output stream. 332 * 333 * @throws IOException if there is an I/O error. 334 */ 335 private void writeObject(ObjectOutputStream stream) throws IOException { 336 stream.defaultWriteObject(); 337 SerialUtilities.writePaint(this.defaultPaint, stream); 338 } 339 340 /** 341 * Provides serialization support. 342 * 343 * @param stream the input stream. 344 * 345 * @throws IOException if there is an I/O error. 346 * @throws ClassNotFoundException if there is a classpath problem. 347 */ 348 private void readObject(ObjectInputStream stream) 349 throws IOException, ClassNotFoundException { 350 stream.defaultReadObject(); 351 this.defaultPaint = SerialUtilities.readPaint(stream); 352 } 353 354 }