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 * StrokeMap.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 * 02-Jul-2013 : Use ParamChecks (DG);
039 *
040 */
041
042package org.jfree.chart;
043
044import java.awt.Stroke;
045import java.io.IOException;
046import java.io.ObjectInputStream;
047import java.io.ObjectOutputStream;
048import java.io.Serializable;
049import java.util.Iterator;
050import java.util.Map;
051import java.util.Set;
052import java.util.TreeMap;
053import org.jfree.chart.util.ParamChecks;
054
055import org.jfree.io.SerialUtilities;
056import org.jfree.util.ObjectUtilities;
057
058/**
059 * A storage structure that maps <code>Comparable</code> instances with
060 * <code>Stroke</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>Stroke</code>
064 * instances is included in this class.
065 *
066 * @since 1.0.3
067 */
068public class StrokeMap implements Cloneable, Serializable {
069
070    /** For serialization. */
071    static final long serialVersionUID = -8148916785963525169L;
072
073    /** Storage for the keys and values. */
074    private transient Map store;
075
076    /**
077     * Creates a new (empty) map.
078     */
079    public StrokeMap() {
080        this.store = new TreeMap();
081    }
082
083    /**
084     * Returns the stroke 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 stroke, or <code>null</code>.
090     *
091     * @throws IllegalArgumentException if <code>key</code> is
092     *     <code>null</code>.
093     */
094    public Stroke getStroke(Comparable key) {
095        ParamChecks.nullNotPermitted(key, "key");
096        return (Stroke) this.store.get(key);
097    }
098
099    /**
100     * Returns <code>true</code> if the map contains the specified key, and
101     * <code>false</code> otherwise.
102     *
103     * @param key  the key.
104     *
105     * @return <code>true</code> if the map contains the specified key, and
106     * <code>false</code> otherwise.
107     */
108    public boolean containsKey(Comparable key) {
109        return this.store.containsKey(key);
110    }
111
112    /**
113     * Adds a mapping between the specified <code>key</code> and
114     * <code>stroke</code> values.
115     *
116     * @param key  the key (<code>null</code> not permitted).
117     * @param stroke  the stroke.
118     */
119    public void put(Comparable key, Stroke stroke) {
120        ParamChecks.nullNotPermitted(key, "key");
121        this.store.put(key, stroke);
122    }
123
124    /**
125     * Resets the map to empty.
126     */
127    public void clear() {
128        this.store.clear();
129    }
130
131    /**
132     * Tests this map for equality with an arbitrary object.
133     *
134     * @param obj  the object (<code>null</code> permitted).
135     *
136     * @return A boolean.
137     */
138    @Override
139    public boolean equals(Object obj) {
140        if (obj == this) {
141            return true;
142        }
143        if (!(obj instanceof StrokeMap)) {
144            return false;
145        }
146        StrokeMap that = (StrokeMap) obj;
147        if (this.store.size() != that.store.size()) {
148            return false;
149        }
150        Set keys = this.store.keySet();
151        Iterator iterator = keys.iterator();
152        while (iterator.hasNext()) {
153            Comparable key = (Comparable) iterator.next();
154            Stroke s1 = getStroke(key);
155            Stroke s2 = that.getStroke(key);
156            if (!ObjectUtilities.equal(s1, s2)) {
157                return false;
158            }
159        }
160        return true;
161    }
162
163    /**
164     * Returns a clone of this <code>StrokeMap</code>.
165     *
166     * @return A clone of this instance.
167     *
168     * @throws CloneNotSupportedException if any key is not cloneable.
169     */
170    @Override
171    public Object clone() throws CloneNotSupportedException {
172        StrokeMap clone = (StrokeMap) super.clone();
173        clone.store = new TreeMap();
174        clone.store.putAll(this.store);
175        // TODO: I think we need to make sure the keys are actually cloned,
176        // whereas the stroke instances are always immutable so they're OK
177        return clone;
178    }
179
180    /**
181     * Provides serialization support.
182     *
183     * @param stream  the output stream.
184     *
185     * @throws IOException  if there is an I/O error.
186     */
187    private void writeObject(ObjectOutputStream stream) throws IOException {
188        stream.defaultWriteObject();
189        stream.writeInt(this.store.size());
190        Set keys = this.store.keySet();
191        Iterator iterator = keys.iterator();
192        while (iterator.hasNext()) {
193            Comparable key = (Comparable) iterator.next();
194            stream.writeObject(key);
195            Stroke stroke = getStroke(key);
196            SerialUtilities.writeStroke(stroke, stream);
197        }
198    }
199
200    /**
201     * Provides serialization support.
202     *
203     * @param stream  the input stream.
204     *
205     * @throws IOException  if there is an I/O error.
206     * @throws ClassNotFoundException  if there is a classpath problem.
207     */
208    private void readObject(ObjectInputStream stream)
209            throws IOException, ClassNotFoundException {
210        stream.defaultReadObject();
211        this.store = new TreeMap();
212        int keyCount = stream.readInt();
213        for (int i = 0; i < keyCount; i++) {
214            Comparable key = (Comparable) stream.readObject();
215            Stroke stroke = SerialUtilities.readStroke(stream);
216            this.store.put(key, stroke);
217        }
218    }
219
220}