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
043package org.jfree.chart;
044
045import java.awt.Paint;
046import java.io.IOException;
047import java.io.ObjectInputStream;
048import java.io.ObjectOutputStream;
049import java.io.Serializable;
050import java.util.HashMap;
051import java.util.Iterator;
052import java.util.Map;
053import java.util.Set;
054
055import org.jfree.io.SerialUtilities;
056import 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 */
068public 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}