001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2014, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * -------------
028 * PaintMap.java
029 * -------------
030 * (C) Copyright 2006-2014, 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 * 02-Jul-2013 : Use ParamChecks class (DG);
041 *
042 */
043
044package org.jfree.chart;
045
046import java.awt.Paint;
047import java.io.IOException;
048import java.io.ObjectInputStream;
049import java.io.ObjectOutputStream;
050import java.io.Serializable;
051import java.util.HashMap;
052import java.util.Iterator;
053import java.util.Map;
054import java.util.Set;
055import org.jfree.chart.util.ParamChecks;
056
057import org.jfree.io.SerialUtilities;
058import 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 */
070public class PaintMap implements Cloneable, Serializable {
071
072    /** For serialization. */
073    static final long serialVersionUID = -4639833772123069274L;
074
075    /** Storage for the keys and values. */
076    private transient Map store;
077
078    /**
079     * Creates a new (empty) map.
080     */
081    public PaintMap() {
082        this.store = new HashMap();
083    }
084
085    /**
086     * Returns the paint associated with the specified key, or
087     * <code>null</code>.
088     *
089     * @param key  the key (<code>null</code> not permitted).
090     *
091     * @return The paint, or <code>null</code>.
092     *
093     * @throws IllegalArgumentException if <code>key</code> is
094     *     <code>null</code>.
095     */
096    public Paint getPaint(Comparable key) {
097        ParamChecks.nullNotPermitted(key, "key");
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        ParamChecks.nullNotPermitted(key, "key");
126        this.store.put(key, paint);
127    }
128
129    /**
130     * Resets the map to empty.
131     */
132    public void clear() {
133        this.store.clear();
134    }
135
136    /**
137     * Tests this map for equality with an arbitrary object.
138     *
139     * @param obj  the object (<code>null</code> permitted).
140     *
141     * @return A boolean.
142     */
143    @Override
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    @Override
176    public Object clone() throws CloneNotSupportedException {
177        PaintMap clone = (PaintMap) super.clone();
178        clone.store = new HashMap();
179        clone.store.putAll(this.store);
180        // TODO: I think we need to make sure the keys are actually cloned,
181        // whereas the paint instances are always immutable so they're OK
182        return clone;
183    }
184
185    /**
186     * Provides serialization support.
187     *
188     * @param stream  the output stream.
189     *
190     * @throws IOException  if there is an I/O error.
191     */
192    private void writeObject(ObjectOutputStream stream) throws IOException {
193        stream.defaultWriteObject();
194        stream.writeInt(this.store.size());
195        Set keys = this.store.keySet();
196        Iterator iterator = keys.iterator();
197        while (iterator.hasNext()) {
198            Comparable key = (Comparable) iterator.next();
199            stream.writeObject(key);
200            Paint paint = getPaint(key);
201            SerialUtilities.writePaint(paint, stream);
202        }
203    }
204
205    /**
206     * Provides serialization support.
207     *
208     * @param stream  the input stream.
209     *
210     * @throws IOException  if there is an I/O error.
211     * @throws ClassNotFoundException  if there is a classpath problem.
212     */
213    private void readObject(ObjectInputStream stream)
214            throws IOException, ClassNotFoundException {
215        stream.defaultReadObject();
216        this.store = new HashMap();
217        int keyCount = stream.readInt();
218        for (int i = 0; i < keyCount; i++) {
219            Comparable key = (Comparable) stream.readObject();
220            Paint paint = SerialUtilities.readPaint(stream);
221            this.store.put(key, paint);
222        }
223    }
224
225}