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