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.1 2007/01/31 14:15:16 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 05-Jul-2006 : Version 1 (DG);
040     * 31-Jan-2007 : Fixed serialization support (DG);
041     * 
042     */
043    
044    package org.jfree.chart.renderer;
045    
046    import java.awt.Color;
047    import java.awt.Paint;
048    import java.io.IOException;
049    import java.io.ObjectInputStream;
050    import java.io.ObjectOutputStream;
051    import java.io.Serializable;
052    import java.util.List;
053    
054    import org.jfree.io.SerialUtilities;
055    import org.jfree.util.PaintUtilities;
056    import org.jfree.util.PublicCloneable;
057    
058    /**
059     * A paint scale that uses a lookup table to associate paint instances
060     * with data value ranges.
061     * 
062     * @since 1.0.4
063     */
064    public class LookupPaintScale 
065            implements PaintScale, PublicCloneable, Serializable {
066    
067        /**
068         * Stores the paint for a value.
069         */
070        class PaintItem implements Serializable {
071            
072            /** The value. */
073            Number value;
074            
075            /** The paint. */
076            transient Paint paint;
077            
078            /**
079             * Creates a new instance.
080             * 
081             * @param value  the value.
082             * @param paint  the paint.
083             */
084            public PaintItem(Number value, Paint paint) {
085                this.value = value;
086                this.paint = paint;
087            }
088            
089            /**
090             * Tests this item for equality with an arbitrary object.
091             * 
092             * @param obj  the object (<code>null</code> permitted).
093             * 
094             * @return A boolean.
095             */
096            public boolean equals(Object obj) {
097                if (obj == this) {
098                    return true;
099                }
100                if (!(obj instanceof PaintItem)) {
101                    return false;
102                }
103                PaintItem that = (PaintItem) obj;
104                if (!this.value.equals(that.value)) {
105                    return false;
106                }
107                if (!PaintUtilities.equal(this.paint, that.paint)) {
108                    return false;
109                }
110                return true;
111            }
112            
113            /**
114             * Provides serialization support.
115             *
116             * @param stream  the output stream.
117             *
118             * @throws IOException  if there is an I/O error.
119             */
120            private void writeObject(ObjectOutputStream stream) throws IOException {
121                stream.defaultWriteObject();
122                SerialUtilities.writePaint(this.paint, stream);
123            }
124    
125            /**
126             * Provides serialization support.
127             *
128             * @param stream  the input stream.
129             *
130             * @throws IOException  if there is an I/O error.
131             * @throws ClassNotFoundException  if there is a classpath problem.
132             */
133            private void readObject(ObjectInputStream stream) 
134                    throws IOException, ClassNotFoundException {
135                stream.defaultReadObject();
136                this.paint = SerialUtilities.readPaint(stream);
137            }
138            
139        }
140        
141        /** The lower bound. */
142        private double lowerBound;
143        
144        /** The upper bound. */
145        private double upperBound;
146        
147        /** The default paint. */
148        private transient Paint defaultPaint; 
149        
150        /** The lookup table. */
151        private List lookupTable;
152        
153        /**
154         * Creates a new paint scale.
155         */
156        public LookupPaintScale() {
157            this(0.0, 1.0, Color.lightGray);    
158        }
159        
160        /**
161         * Creates a new paint scale with the specified default paint.
162         * 
163         * @param lowerBound  the lower bound.
164         * @param upperBound  the upper bound.
165         * @param defaultPaint  the default paint (<code>null</code> not 
166         *     permitted).
167         */
168        public LookupPaintScale(double lowerBound, double upperBound, 
169                Paint defaultPaint) {
170            if (lowerBound >= upperBound) {
171                throw new IllegalArgumentException(
172                        "Requires lowerBound < upperBound.");
173            }
174            if (defaultPaint == null) {
175                throw new IllegalArgumentException("Null 'paint' argument.");
176            }
177            this.defaultPaint = defaultPaint;
178            this.lookupTable = new java.util.ArrayList();
179        }
180        
181        /**
182         * Returns the default paint (never <code>null</code>).
183         * 
184         * @return The default paint.
185         */
186        public Paint getDefaultPaint() {
187            return this.defaultPaint;
188        }
189        
190        /**
191         * Returns the lower bound.
192         * 
193         * @return The lower bound.
194         */
195        public double getLowerBound() {
196            return this.lowerBound;
197        }
198    
199        /**
200         * Returns the upper bound.
201         * 
202         * @return The upper bound.
203         */
204        public double getUpperBound() {
205            return this.upperBound;
206        }
207    
208        /**
209         * Adds an entry to the lookup table.
210         * 
211         * @param n  the data value.
212         * @param p  the paint.
213         */
214        public void add(Number n, Paint p) {
215            this.lookupTable.add(new PaintItem(n, p));
216        }
217        
218        /**
219         * Returns the paint associated with the specified value.
220         * 
221         * @param value  the value.
222         * 
223         * @return The paint.
224         */
225        public Paint getPaint(double value) {
226            Paint result = defaultPaint;
227            int index = this.lookupTable.size();
228            boolean done = false;
229            while (index > 0 && !done) {
230                PaintItem item = (PaintItem) lookupTable.get(--index);
231                if (value >= item.value.doubleValue()) {
232                    result = item.paint;
233                    done = true;
234                }
235            }
236            return result;
237        }
238        
239        /**
240         * Tests this instance for equality with an arbitrary object.
241         * 
242         * @param obj  the object (<code>null</code> permitted).
243         * 
244         * @return A boolean.
245         */
246        public boolean equals(Object obj) {
247            if (obj == this) {
248                return true;
249            }
250            if (!(obj instanceof LookupPaintScale)) {
251                return false;
252            }
253            LookupPaintScale that = (LookupPaintScale) obj;
254            if (this.lowerBound != that.lowerBound) {
255                return false;
256            }
257            if (this.upperBound != that.upperBound) {
258                return false;
259            }
260            if (!PaintUtilities.equal(this.defaultPaint, that.defaultPaint)) {
261                return false;
262            }
263            if (!this.lookupTable.equals(that.lookupTable)) {
264                return false;
265            }
266            return true;
267        }
268        
269        /**
270         * Returns a clone of the instance.
271         * 
272         * @return A clone.
273         * 
274         * @throws CloneNotSupportedException if there is a problem cloning the
275         *     instance.
276         */
277        public Object clone() throws CloneNotSupportedException {
278            return super.clone();
279        }
280    
281        /**
282         * Provides serialization support.
283         *
284         * @param stream  the output stream.
285         *
286         * @throws IOException  if there is an I/O error.
287         */
288        private void writeObject(ObjectOutputStream stream) throws IOException {
289            stream.defaultWriteObject();
290            SerialUtilities.writePaint(this.defaultPaint, stream);
291        }
292    
293        /**
294         * Provides serialization support.
295         *
296         * @param stream  the input stream.
297         *
298         * @throws IOException  if there is an I/O error.
299         * @throws ClassNotFoundException  if there is a classpath problem.
300         */
301        private void readObject(ObjectInputStream stream) 
302                throws IOException, ClassNotFoundException {
303            stream.defaultReadObject();
304            this.defaultPaint = SerialUtilities.readPaint(stream);
305        }
306    
307    }