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