1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
6  *
7  * Project Info:  http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
22  * USA.
23  *
24  * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
25  * Other names may be trademarks of their respective owners.]
26  *
27  * --------------
28  * StrokeMap.java
29  * --------------
30  * (C) Copyright 2006-2013, by Object Refinery Limited.
31  *
32  * Original Author:  David Gilbert (for Object Refinery Limited);
33  * Contributor(s):   -;
34  *
35  * Changes:
36  * --------
37  * 27-Sep-2006 : Version 1 (DG);
38  * 02-Jul-2013 : Use ParamChecks (DG);
39  *
40  */
41 
42 package org.jfree.chart;
43 
44 import java.awt.Stroke;
45 import java.io.IOException;
46 import java.io.ObjectInputStream;
47 import java.io.ObjectOutputStream;
48 import java.io.Serializable;
49 import java.util.Iterator;
50 import java.util.Map;
51 import java.util.Set;
52 import java.util.TreeMap;
53 import org.jfree.chart.util.ParamChecks;
54 
55 import org.jfree.io.SerialUtilities;
56 import org.jfree.util.ObjectUtilities;
57 
58 /**
59  * A storage structure that maps <code>Comparable</code> instances with
60  * <code>Stroke</code> instances.
61  * <br><br>
62  * To support cloning and serialization, you should only use keys that are
63  * cloneable and serializable.  Special handling for the <code>Stroke</code>
64  * instances is included in this class.
65  *
66  * @since 1.0.3
67  */
68 public class StrokeMap implements Cloneable, Serializable {
69 
70     /** For serialization. */
71     static final long serialVersionUID = -8148916785963525169L;
72 
73     /** Storage for the keys and values. */
74     private transient Map store;
75 
76     /**
77      * Creates a new (empty) map.
78      */
StrokeMap()79     public StrokeMap() {
80         this.store = new TreeMap();
81     }
82 
83     /**
84      * Returns the stroke associated with the specified key, or
85      * <code>null</code>.
86      *
87      * @param key  the key (<code>null</code> not permitted).
88      *
89      * @return The stroke, or <code>null</code>.
90      *
91      * @throws IllegalArgumentException if <code>key</code> is
92      *     <code>null</code>.
93      */
getStroke(Comparable key)94     public Stroke getStroke(Comparable key) {
95         ParamChecks.nullNotPermitted(key, "key");
96         return (Stroke) this.store.get(key);
97     }
98 
99     /**
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      */
containsKey(Comparable key)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      */
put(Comparable key, Stroke stroke)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      */
clear()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
equals(Object obj)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
clone()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      */
writeObject(ObjectOutputStream stream)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      */
readObject(ObjectInputStream stream)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 }
218