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.4 2007/06/14 13:20:19 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: * 14-Jun-2007 : Use double primitive in PaintItem (DG);
043: *
044: */
045:
046: package org.jfree.chart.renderer;
047:
048: import java.awt.Color;
049: import java.awt.Paint;
050: import java.io.IOException;
051: import java.io.ObjectInputStream;
052: import java.io.ObjectOutputStream;
053: import java.io.Serializable;
054: import java.util.Collections;
055: import java.util.List;
056:
057: import org.jfree.io.SerialUtilities;
058: import org.jfree.util.PaintUtilities;
059: import org.jfree.util.PublicCloneable;
060:
061: /**
062: * A paint scale that uses a lookup table to associate paint instances
063: * with data value ranges.
064: *
065: * @since 1.0.4
066: */
067: public class LookupPaintScale implements PaintScale, PublicCloneable,
068: Serializable {
069:
070: /**
071: * Stores the paint for a value.
072: */
073: class PaintItem implements Comparable, Serializable {
074:
075: /** The value. */
076: double value;
077:
078: /** The paint. */
079: transient Paint paint;
080:
081: /**
082: * Creates a new instance.
083: *
084: * @param value the value.
085: * @param paint the paint.
086: */
087: public PaintItem(double value, Paint paint) {
088: this .value = value;
089: this .paint = paint;
090: }
091:
092: /* (non-Javadoc)
093: * @see java.lang.Comparable#compareTo(java.lang.Object)
094: */
095: public int compareTo(Object obj) {
096: PaintItem that = (PaintItem) obj;
097: double d1 = this .value;
098: double d2 = that.value;
099: if (d1 > d2) {
100: return 1;
101: }
102: if (d1 < d2) {
103: return -1;
104: }
105: return 0;
106: }
107:
108: /**
109: * Tests this item for equality with an arbitrary object.
110: *
111: * @param obj the object (<code>null</code> permitted).
112: *
113: * @return A boolean.
114: */
115: public boolean equals(Object obj) {
116: if (obj == this ) {
117: return true;
118: }
119: if (!(obj instanceof PaintItem)) {
120: return false;
121: }
122: PaintItem that = (PaintItem) obj;
123: if (this .value != that.value) {
124: return false;
125: }
126: if (!PaintUtilities.equal(this .paint, that.paint)) {
127: return false;
128: }
129: return true;
130: }
131:
132: /**
133: * Provides serialization support.
134: *
135: * @param stream the output stream.
136: *
137: * @throws IOException if there is an I/O error.
138: */
139: private void writeObject(ObjectOutputStream stream)
140: 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: /** The lower bound. */
162: private double lowerBound;
163:
164: /** The upper bound. */
165: private double upperBound;
166:
167: /** The default paint. */
168: private transient Paint defaultPaint;
169:
170: /** The lookup table. */
171: private List lookupTable;
172:
173: /**
174: * Creates a new paint scale.
175: */
176: public LookupPaintScale() {
177: this (0.0, 1.0, Color.lightGray);
178: }
179:
180: /**
181: * Creates a new paint scale with the specified default paint.
182: *
183: * @param lowerBound the lower bound.
184: * @param upperBound the upper bound.
185: * @param defaultPaint the default paint (<code>null</code> not
186: * permitted).
187: */
188: public LookupPaintScale(double lowerBound, double upperBound,
189: Paint defaultPaint) {
190: if (lowerBound >= upperBound) {
191: throw new IllegalArgumentException(
192: "Requires lowerBound < upperBound.");
193: }
194: if (defaultPaint == null) {
195: throw new IllegalArgumentException("Null 'paint' argument.");
196: }
197: this .lowerBound = lowerBound;
198: this .upperBound = upperBound;
199: this .defaultPaint = defaultPaint;
200: this .lookupTable = new java.util.ArrayList();
201: }
202:
203: /**
204: * Returns the default paint (never <code>null</code>).
205: *
206: * @return The default paint.
207: */
208: public Paint getDefaultPaint() {
209: return this .defaultPaint;
210: }
211:
212: /**
213: * Returns the lower bound.
214: *
215: * @return The lower bound.
216: *
217: * @see #getUpperBound()
218: */
219: public double getLowerBound() {
220: return this .lowerBound;
221: }
222:
223: /**
224: * Returns the upper bound.
225: *
226: * @return The upper bound.
227: *
228: * @see #getLowerBound()
229: */
230: public double getUpperBound() {
231: return this .upperBound;
232: }
233:
234: /**
235: * Adds an entry to the lookup table. Any values from <code>n</code> up
236: * to but not including the next value in the table take on the specified
237: * <code>paint</code>.
238: *
239: * @param value the data value (<code>null</code> not permitted).
240: * @param paint the paint.
241: *
242: * @deprecated Use {@link #add(double, Paint)}.
243: */
244: public void add(Number value, Paint paint) {
245: add(value.doubleValue(), paint);
246: }
247:
248: /**
249: * Adds an entry to the lookup table. Any values from <code>n</code> up
250: * to but not including the next value in the table take on the specified
251: * <code>paint</code>.
252: *
253: * @param value the data value.
254: * @param paint the paint.
255: *
256: * @since 1.0.6
257: */
258: public void add(double value, Paint paint) {
259: PaintItem item = new PaintItem(value, paint);
260: int index = Collections.binarySearch(this .lookupTable, item);
261: if (index >= 0) {
262: this .lookupTable.set(index, item);
263: } else {
264: this .lookupTable.add(-(index + 1), item);
265: }
266: }
267:
268: /**
269: * Returns the paint associated with the specified value.
270: *
271: * @param value the value.
272: *
273: * @return The paint.
274: *
275: * @see #getDefaultPaint()
276: */
277: public Paint getPaint(double value) {
278:
279: // handle value outside bounds...
280: if (value < this .lowerBound) {
281: return this .defaultPaint;
282: }
283: if (value > this .upperBound) {
284: return this .defaultPaint;
285: }
286:
287: int count = this .lookupTable.size();
288: if (count == 0) {
289: return this .defaultPaint;
290: }
291:
292: // handle special case where value is less that item zero
293: PaintItem item = (PaintItem) this .lookupTable.get(0);
294: if (value < item.value) {
295: return this .defaultPaint;
296: }
297:
298: // for value in bounds, do the lookup...
299: int low = 0;
300: int high = this .lookupTable.size() - 1;
301: while (high - low > 1) {
302: int current = (low + high) / 2;
303: item = (PaintItem) this .lookupTable.get(current);
304: if (value >= item.value) {
305: low = current;
306: } else {
307: high = current;
308: }
309: }
310: if (high > low) {
311: item = (PaintItem) this .lookupTable.get(high);
312: if (value < item.value) {
313: item = (PaintItem) this .lookupTable.get(low);
314: }
315: }
316: return (item != null ? item.paint : this .defaultPaint);
317: }
318:
319: /**
320: * Tests this instance for equality with an arbitrary object.
321: *
322: * @param obj the object (<code>null</code> permitted).
323: *
324: * @return A boolean.
325: */
326: public boolean equals(Object obj) {
327: if (obj == this ) {
328: return true;
329: }
330: if (!(obj instanceof LookupPaintScale)) {
331: return false;
332: }
333: LookupPaintScale that = (LookupPaintScale) obj;
334: if (this .lowerBound != that.lowerBound) {
335: return false;
336: }
337: if (this .upperBound != that.upperBound) {
338: return false;
339: }
340: if (!PaintUtilities.equal(this .defaultPaint, that.defaultPaint)) {
341: return false;
342: }
343: if (!this .lookupTable.equals(that.lookupTable)) {
344: return false;
345: }
346: return true;
347: }
348:
349: /**
350: * Returns a clone of the instance.
351: *
352: * @return A clone.
353: *
354: * @throws CloneNotSupportedException if there is a problem cloning the
355: * instance.
356: */
357: public Object clone() throws CloneNotSupportedException {
358: LookupPaintScale clone = (LookupPaintScale) super .clone();
359: clone.lookupTable = new java.util.ArrayList(this .lookupTable);
360: return clone;
361: }
362:
363: /**
364: * Provides serialization support.
365: *
366: * @param stream the output stream.
367: *
368: * @throws IOException if there is an I/O error.
369: */
370: private void writeObject(ObjectOutputStream stream)
371: throws IOException {
372: stream.defaultWriteObject();
373: SerialUtilities.writePaint(this .defaultPaint, stream);
374: }
375:
376: /**
377: * Provides serialization support.
378: *
379: * @param stream the input stream.
380: *
381: * @throws IOException if there is an I/O error.
382: * @throws ClassNotFoundException if there is a classpath problem.
383: */
384: private void readObject(ObjectInputStream stream)
385: throws IOException, ClassNotFoundException {
386: stream.defaultReadObject();
387: this.defaultPaint = SerialUtilities.readPaint(stream);
388: }
389:
390: }
|