001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2008, 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
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
041 package org.jfree.chart;
042
043 import java.awt.Stroke;
044 import java.io.IOException;
045 import java.io.ObjectInputStream;
046 import java.io.ObjectOutputStream;
047 import java.io.Serializable;
048 import java.util.Iterator;
049 import java.util.Map;
050 import java.util.Set;
051 import java.util.TreeMap;
052
053 import org.jfree.io.SerialUtilities;
054 import 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 */
066 public 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 }