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