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     * PaintMap.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: PaintMap.java,v 1.1.2.2 2007/01/17 10:08:19 mungady Exp $
036     *
037     * Changes:
038     * --------
039     * 27-Sep-2006 : Version 1 (DG);
040     * 17-Jan-2007 : Changed TreeMap to HashMap, so that different classes that
041     *               implement Comparable can be used as keys (DG);
042     *
043     */
044    
045    package org.jfree.chart;
046    
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.HashMap;
053    import java.util.Iterator;
054    import java.util.Map;
055    import java.util.Set;
056    
057    import org.jfree.io.SerialUtilities;
058    import org.jfree.util.PaintUtilities;
059    
060    /**
061     * A storage structure that maps <code>Comparable</code> instances with
062     * <code>Paint</code> instances.  
063     * <br><br>
064     * To support cloning and serialization, you should only use keys that are 
065     * cloneable and serializable.  Special handling for the <code>Paint</code>
066     * instances is included in this class.
067     * 
068     * @since 1.0.3
069     */
070    public class PaintMap implements Cloneable, Serializable {
071    
072        /** Storage for the keys and values. */
073        private transient Map store;
074        
075        /**
076         * Creates a new (empty) map.
077         */
078        public PaintMap() {
079            this.store = new HashMap();    
080        }
081        
082        /**
083         * Returns the paint associated with the specified key, or 
084         * <code>null</code>.
085         * 
086         * @param key  the key (<code>null</code> not permitted).
087         * 
088         * @return The paint, or <code>null</code>.
089         * 
090         * @throws IllegalArgumentException if <code>key</code> is 
091         *     <code>null</code>.
092         */
093        public Paint getPaint(Comparable key) {
094            if (key == null) {
095                throw new IllegalArgumentException("Null 'key' argument.");
096            }
097            return (Paint) this.store.get(key);
098        }
099        
100        /**
101         * Returns <code>true</code> if the map contains the specified key, and
102         * <code>false</code> otherwise.
103         * 
104         * @param key  the key.
105         * 
106         * @return <code>true</code> if the map contains the specified key, and
107         * <code>false</code> otherwise.
108         */
109        public boolean containsKey(Comparable key) {
110            return this.store.containsKey(key);
111        }
112        
113        /**
114         * Adds a mapping between the specified <code>key</code> and 
115         * <code>paint</code> values.
116         * 
117         * @param key  the key (<code>null</code> not permitted).
118         * @param paint  the paint.
119         * 
120         * @throws IllegalArgumentException if <code>key</code> is 
121         *     <code>null</code>.
122         */
123        public void put(Comparable key, Paint paint) {
124            if (key == null) {
125                throw new IllegalArgumentException("Null 'key' argument.");
126            }
127            this.store.put(key, paint);
128        }
129        
130        /**
131         * Resets the map to empty.
132         */
133        public void clear() {
134            this.store.clear();
135        }
136        
137        /**
138         * Tests this map for equality with an arbitrary object.
139         * 
140         * @param obj  the object (<code>null</code> permitted).
141         * 
142         * @return A boolean.
143         */
144        public boolean equals(Object obj) {
145            if (obj == this) {
146                return true;
147            }
148            if (!(obj instanceof PaintMap)) {
149                return false;
150            }
151            PaintMap that = (PaintMap) obj;
152            if (this.store.size() != that.store.size()) {
153                return false;
154            }
155            Set keys = this.store.keySet();
156            Iterator iterator = keys.iterator();
157            while (iterator.hasNext()) {
158                Comparable key = (Comparable) iterator.next();
159                Paint p1 = getPaint(key);
160                Paint p2 = that.getPaint(key);
161                if (!PaintUtilities.equal(p1, p2)) {
162                    return false;
163                }
164            }
165            return true;
166        }
167        
168        /**
169         * Returns a clone of this <code>PaintMap</code>.
170         * 
171         * @return A clone of this instance.
172         * 
173         * @throws CloneNotSupportedException if any key is not cloneable.
174         */
175        public Object clone() throws CloneNotSupportedException {
176            // TODO: I think we need to make sure the keys are actually cloned,
177            // whereas the paint instances are always immutable so they're OK
178            return super.clone();
179        }
180        
181        /**
182         * Provides serialization support.
183         *
184         * @param stream  the output stream.
185         *
186         * @throws IOException  if there is an I/O error.
187         */
188        private void writeObject(ObjectOutputStream stream) throws IOException {
189            stream.defaultWriteObject();
190            stream.writeInt(this.store.size());
191            Set keys = this.store.keySet();
192            Iterator iterator = keys.iterator();
193            while (iterator.hasNext()) {
194                Comparable key = (Comparable) iterator.next();
195                stream.writeObject(key);
196                Paint paint = getPaint(key);
197                SerialUtilities.writePaint(paint, stream);
198            }
199        }
200    
201        /**
202         * Provides serialization support.
203         *
204         * @param stream  the input stream.
205         *
206         * @throws IOException  if there is an I/O error.
207         * @throws ClassNotFoundException  if there is a classpath problem.
208         */
209        private void readObject(ObjectInputStream stream) 
210                throws IOException, ClassNotFoundException {
211            stream.defaultReadObject();
212            this.store = new HashMap();
213            int keyCount = stream.readInt();
214            for (int i = 0; i < keyCount; i++) {
215                Comparable key = (Comparable) stream.readObject();
216                Paint paint = SerialUtilities.readPaint(stream);
217                this.store.put(key, paint);
218            }
219        }
220        
221    }