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 * DefaultPieDataset.java
029 * ----------------------
030 * (C) Copyright 2001-2008, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): Sam (oldman);
034 *
035 * Changes
036 * -------
037 * 17-Nov-2001 : Version 1 (DG);
038 * 22-Jan-2002 : Removed legend methods from dataset implementations (DG);
039 * 07-Apr-2002 : Modified implementation to guarantee data sequence to remain
040 * in the order categories are added (oldman);
041 * 23-Oct-2002 : Added getCategory(int) method and getItemCount() method, in
042 * line with changes to the PieDataset interface (DG);
043 * 04-Feb-2003 : Changed underlying data storage to DefaultKeyedValues (DG);
044 * 04-Mar-2003 : Inserted DefaultKeyedValuesDataset class into hierarchy (DG);
045 * 24-Apr-2003 : Switched places with DefaultKeyedValuesDataset (DG);
046 * 18-Aug-2003 : Implemented Cloneable (DG);
047 * 03-Mar-2005 : Implemented PublicCloneable (DG);
048 * 29-Jun-2005 : Added remove() method (DG);
049 * ------------- JFREECHART 1.0.0 ---------------------------------------------
050 * 31-Jul-2006 : Added a clear() method to clear all values from the
051 * dataset (DG);
052 * 28-Sep-2006 : Added sortByKeys() and sortByValues() methods (DG);
053 * 30-Apr-2007 : Added new insertValues() methods (DG);
054 *
055 */
056
057 package org.jfree.data.general;
058
059 import java.io.Serializable;
060 import java.util.Collections;
061 import java.util.List;
062
063 import org.jfree.data.DefaultKeyedValues;
064 import org.jfree.data.KeyedValues;
065 import org.jfree.data.UnknownKeyException;
066 import org.jfree.util.PublicCloneable;
067 import org.jfree.util.SortOrder;
068
069 /**
070 * A default implementation of the {@link PieDataset} interface.
071 */
072 public class DefaultPieDataset extends AbstractDataset
073 implements PieDataset, Cloneable, PublicCloneable, Serializable {
074
075 /** For serialization. */
076 private static final long serialVersionUID = 2904745139106540618L;
077
078 /** Storage for the data. */
079 private DefaultKeyedValues data;
080
081 /**
082 * Constructs a new dataset, initially empty.
083 */
084 public DefaultPieDataset() {
085 this.data = new DefaultKeyedValues();
086 }
087
088 /**
089 * Creates a new dataset by copying data from a {@link KeyedValues}
090 * instance.
091 *
092 * @param data the data (<code>null</code> not permitted).
093 */
094 public DefaultPieDataset(KeyedValues data) {
095 if (data == null) {
096 throw new IllegalArgumentException("Null 'data' argument.");
097 }
098 this.data = new DefaultKeyedValues();
099 for (int i = 0; i < data.getItemCount(); i++) {
100 this.data.addValue(data.getKey(i), data.getValue(i));
101 }
102 }
103
104 /**
105 * Returns the number of items in the dataset.
106 *
107 * @return The item count.
108 */
109 public int getItemCount() {
110 return this.data.getItemCount();
111 }
112
113 /**
114 * Returns the categories in the dataset. The returned list is
115 * unmodifiable.
116 *
117 * @return The categories in the dataset.
118 */
119 public List getKeys() {
120 return Collections.unmodifiableList(this.data.getKeys());
121 }
122
123 /**
124 * Returns the key for the specified item, or <code>null</code>.
125 *
126 * @param item the item index (in the range <code>0</code> to
127 * <code>getItemCount() - 1</code>).
128 *
129 * @return The key, or <code>null</code>.
130 *
131 * @throws IndexOutOfBoundsException if <code>item</code> is not in the
132 * specified range.
133 */
134 public Comparable getKey(int item) {
135 return this.data.getKey(item);
136 }
137
138 /**
139 * Returns the index for a key, or -1 if the key is not recognised.
140 *
141 * @param key the key (<code>null</code> not permitted).
142 *
143 * @return The index, or <code>-1</code> if the key is unrecognised.
144 *
145 * @throws IllegalArgumentException if <code>key</code> is
146 * <code>null</code>.
147 */
148 public int getIndex(Comparable key) {
149 return this.data.getIndex(key);
150 }
151
152 /**
153 * Returns a value.
154 *
155 * @param item the value index.
156 *
157 * @return The value (possibly <code>null</code>).
158 */
159 public Number getValue(int item) {
160
161 Number result = null;
162 if (getItemCount() > item) {
163 result = this.data.getValue(item);
164 }
165 return result;
166
167 }
168
169 /**
170 * Returns the data value associated with a key.
171 *
172 * @param key the key (<code>null</code> not permitted).
173 *
174 * @return The value (possibly <code>null</code>).
175 *
176 * @throws UnknownKeyException if the key is not recognised.
177 */
178 public Number getValue(Comparable key) {
179 if (key == null) {
180 throw new IllegalArgumentException("Null 'key' argument.");
181 }
182 return this.data.getValue(key);
183 }
184
185 /**
186 * Sets the data value for a key and sends a {@link DatasetChangeEvent} to
187 * all registered listeners.
188 *
189 * @param key the key (<code>null</code> not permitted).
190 * @param value the value.
191 *
192 * @throws IllegalArgumentException if <code>key</code> is
193 * <code>null</code>.
194 */
195 public void setValue(Comparable key, Number value) {
196 this.data.setValue(key, value);
197 fireDatasetChanged();
198 }
199
200 /**
201 * Sets the data value for a key and sends a {@link DatasetChangeEvent} to
202 * all registered listeners.
203 *
204 * @param key the key (<code>null</code> not permitted).
205 * @param value the value.
206 *
207 * @throws IllegalArgumentException if <code>key</code> is
208 * <code>null</code>.
209 */
210 public void setValue(Comparable key, double value) {
211 setValue(key, new Double(value));
212 }
213
214 /**
215 * Inserts a new value at the specified position in the dataset or, if
216 * there is an existing item with the specified key, updates the value
217 * for that item and moves it to the specified position. After the change
218 * is made, this methods sends a {@link DatasetChangeEvent} to all
219 * registered listeners.
220 *
221 * @param position the position (in the range 0 to getItemCount()).
222 * @param key the key (<code>null</code> not permitted).
223 * @param value the value (<code>null</code> permitted).
224 *
225 * @since 1.0.6
226 */
227 public void insertValue(int position, Comparable key, double value) {
228 insertValue(position, key, new Double(value));
229 }
230
231 /**
232 * Inserts a new value at the specified position in the dataset or, if
233 * there is an existing item with the specified key, updates the value
234 * for that item and moves it to the specified position. After the change
235 * is made, this methods sends a {@link DatasetChangeEvent} to all
236 * registered listeners.
237 *
238 * @param position the position (in the range 0 to getItemCount()).
239 * @param key the key (<code>null</code> not permitted).
240 * @param value the value (<code>null</code> permitted).
241 *
242 * @since 1.0.6
243 */
244 public void insertValue(int position, Comparable key, Number value) {
245 this.data.insertValue(position, key, value);
246 fireDatasetChanged();
247 }
248
249 /**
250 * Removes an item from the dataset and sends a {@link DatasetChangeEvent}
251 * to all registered listeners.
252 *
253 * @param key the key (<code>null</code> not permitted).
254 *
255 * @throws IllegalArgumentException if <code>key</code> is
256 * <code>null</code>.
257 */
258 public void remove(Comparable key) {
259 this.data.removeValue(key);
260 fireDatasetChanged();
261 }
262
263 /**
264 * Clears all data from this dataset and sends a {@link DatasetChangeEvent}
265 * to all registered listeners (unless the dataset was already empty).
266 *
267 * @since 1.0.2
268 */
269 public void clear() {
270 if (getItemCount() > 0) {
271 this.data.clear();
272 fireDatasetChanged();
273 }
274 }
275
276 /**
277 * Sorts the dataset's items by key and sends a {@link DatasetChangeEvent}
278 * to all registered listeners.
279 *
280 * @param order the sort order (<code>null</code> not permitted).
281 *
282 * @since 1.0.3
283 */
284 public void sortByKeys(SortOrder order) {
285 this.data.sortByKeys(order);
286 fireDatasetChanged();
287 }
288
289 /**
290 * Sorts the dataset's items by value and sends a {@link DatasetChangeEvent}
291 * to all registered listeners.
292 *
293 * @param order the sort order (<code>null</code> not permitted).
294 *
295 * @since 1.0.3
296 */
297 public void sortByValues(SortOrder order) {
298 this.data.sortByValues(order);
299 fireDatasetChanged();
300 }
301
302 /**
303 * Tests if this object is equal to another.
304 *
305 * @param obj the other object.
306 *
307 * @return A boolean.
308 */
309 public boolean equals(Object obj) {
310 if (obj == this) {
311 return true;
312 }
313
314 if (!(obj instanceof PieDataset)) {
315 return false;
316 }
317 PieDataset that = (PieDataset) obj;
318 int count = getItemCount();
319 if (that.getItemCount() != count) {
320 return false;
321 }
322
323 for (int i = 0; i < count; i++) {
324 Comparable k1 = getKey(i);
325 Comparable k2 = that.getKey(i);
326 if (!k1.equals(k2)) {
327 return false;
328 }
329
330 Number v1 = getValue(i);
331 Number v2 = that.getValue(i);
332 if (v1 == null) {
333 if (v2 != null) {
334 return false;
335 }
336 }
337 else {
338 if (!v1.equals(v2)) {
339 return false;
340 }
341 }
342 }
343 return true;
344
345 }
346
347 /**
348 * Returns a hash code.
349 *
350 * @return A hash code.
351 */
352 public int hashCode() {
353 return this.data.hashCode();
354 }
355
356 /**
357 * Returns a clone of the dataset.
358 *
359 * @return A clone.
360 *
361 * @throws CloneNotSupportedException This class will not throw this
362 * exception, but subclasses (if any) might.
363 */
364 public Object clone() throws CloneNotSupportedException {
365 DefaultPieDataset clone = (DefaultPieDataset) super.clone();
366 clone.data = (DefaultKeyedValues) this.data.clone();
367 return clone;
368 }
369
370 }