Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2006, 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: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 25: * in the United States and other countries.] 26: * 27: * ------------------------- 28: * CategoryToPieDataset.java 29: * ------------------------- 30: * (C) Copyright 2003-2006, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): Christian W. Zuckschwerdt; 34: * 35: * $Id: CategoryToPieDataset.java,v 1.4.2.2 2006/07/26 10:28:00 mungady Exp $ 36: * 37: * Changes 38: * ------- 39: * 23-Jan-2003 : Version 1 (DG); 40: * 30-Jul-2003 : Pass through DatasetChangeEvent (CZ); 41: * 29-Jan-2004 : Replaced 'extract' int with TableOrder (DG); 42: * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0 43: * release (DG); 44: * ------------- JFREECHART 1.0.0 RELEASED ------------------------------------ 45: * 26-Jul-2006 : Added serialVersionUID, changed constructor to allow null 46: * for source, and added getSource(), getExtractType() and 47: * getExtractIndex() methods - see feature request 1477915 (DG); 48: * 49: */ 50: 51: package org.jfree.data.category; 52: 53: import java.util.Collections; 54: import java.util.List; 55: 56: import org.jfree.data.general.AbstractDataset; 57: import org.jfree.data.general.DatasetChangeEvent; 58: import org.jfree.data.general.DatasetChangeListener; 59: import org.jfree.data.general.PieDataset; 60: import org.jfree.util.TableOrder; 61: 62: /** 63: * A {@link PieDataset} implementation that obtains its data from one row or 64: * column of a {@link CategoryDataset}. 65: */ 66: public class CategoryToPieDataset extends AbstractDataset 67: implements PieDataset, DatasetChangeListener { 68: 69: static final long serialVersionUID = 5516396319762189617L; 70: 71: /** The source. */ 72: private CategoryDataset source; 73: 74: /** The extract type. */ 75: private TableOrder extract; 76: 77: /** The row or column index. */ 78: private int index; 79: 80: /** 81: * An adaptor class that converts any {@link CategoryDataset} into a 82: * {@link PieDataset}, by taking the values from a single row or column. 83: * <p> 84: * If <code>source</code> is <code>null</code>, the created dataset will 85: * be empty. 86: * 87: * @param source the source dataset (<code>null</code> permitted). 88: * @param extract extract data from rows or columns? (<code>null</code> 89: * not permitted). 90: * @param index the row or column index. 91: */ 92: public CategoryToPieDataset(CategoryDataset source, 93: TableOrder extract, 94: int index) { 95: if (extract == null) { 96: throw new IllegalArgumentException("Null 'extract' argument."); 97: } 98: this.source = source; 99: if (this.source != null) { 100: this.source.addChangeListener(this); 101: } 102: this.extract = extract; 103: this.index = index; 104: } 105: 106: /** 107: * Returns the underlying dataset. 108: * 109: * @return The underlying dataset (possibly <code>null</code>). 110: * 111: * @since 1.0.2 112: */ 113: public CategoryDataset getUnderlyingDataset() { 114: return this.source; 115: } 116: 117: /** 118: * Returns the extract type, which determines whether data is read from 119: * one row or one column of the underlying dataset. 120: * 121: * @return The extract type. 122: * 123: * @since 1.0.2 124: */ 125: public TableOrder getExtractType() { 126: return this.extract; 127: } 128: 129: /** 130: * Returns the index of the row or column from which to extract the data. 131: * 132: * @return The extract index. 133: * 134: * @since 1.0.2 135: */ 136: public int getExtractIndex() { 137: return this.index; 138: } 139: 140: /** 141: * Returns the number of items (values) in the collection. If the 142: * underlying dataset is <code>null</code>, this method returns zero. 143: * 144: * @return The item count. 145: */ 146: public int getItemCount() { 147: int result = 0; 148: if (this.source != null) { 149: if (this.extract == TableOrder.BY_ROW) { 150: result = this.source.getColumnCount(); 151: } 152: else if (this.extract == TableOrder.BY_COLUMN) { 153: result = this.source.getRowCount(); 154: } 155: } 156: return result; 157: } 158: 159: /** 160: * Returns a value from the dataset. 161: * 162: * @param item the item index (zero-based). 163: * 164: * @return The value (possibly <code>null</code>). 165: * 166: * @throws IndexOutOfBoundsException if <code>item</code> is not in the 167: * range <code>0</code> to <code>getItemCount() - 1</code>. 168: */ 169: public Number getValue(int item) { 170: Number result = null; 171: if (item < 0 || item >= getItemCount()) { 172: // this will include the case where the underlying dataset is null 173: throw new IndexOutOfBoundsException( 174: "The 'item' index is out of bounds."); 175: } 176: if (this.extract == TableOrder.BY_ROW) { 177: result = this.source.getValue(this.index, item); 178: } 179: else if (this.extract == TableOrder.BY_COLUMN) { 180: result = this.source.getValue(item, this.index); 181: } 182: return result; 183: } 184: 185: /** 186: * Returns the key at the specified index. 187: * 188: * @param index the item index (in the range <code>0</code> to 189: * <code>getItemCount() - 1</code>). 190: * 191: * @return The key. 192: * 193: * @throws IndexOutOfBoundsException if <code>index</code> is not in the 194: * specified range. 195: */ 196: public Comparable getKey(int index) { 197: Comparable result = null; 198: if (index < 0 || index >= getItemCount()) { 199: // this includes the case where the underlying dataset is null 200: throw new IndexOutOfBoundsException("Invalid 'index': " + index); 201: } 202: if (this.extract == TableOrder.BY_ROW) { 203: result = this.source.getColumnKey(index); 204: } 205: else if (this.extract == TableOrder.BY_COLUMN) { 206: result = this.source.getRowKey(index); 207: } 208: return result; 209: } 210: 211: /** 212: * Returns the index for a given key, or <code>-1</code> if there is no 213: * such key. 214: * 215: * @param key the key. 216: * 217: * @return The index for the key, or <code>-1</code>. 218: */ 219: public int getIndex(Comparable key) { 220: int result = -1; 221: if (this.source != null) { 222: if (this.extract == TableOrder.BY_ROW) { 223: result = this.source.getColumnIndex(key); 224: } 225: else if (this.extract == TableOrder.BY_COLUMN) { 226: result = this.source.getRowIndex(key); 227: } 228: } 229: return result; 230: } 231: 232: /** 233: * Returns the keys for the dataset. 234: * <p> 235: * If the underlying dataset is <code>null</code>, this method returns an 236: * empty list. 237: * 238: * @return The keys. 239: */ 240: public List getKeys() { 241: List result = Collections.EMPTY_LIST; 242: if (this.source != null) { 243: if (this.extract == TableOrder.BY_ROW) { 244: result = this.source.getColumnKeys(); 245: } 246: else if (this.extract == TableOrder.BY_COLUMN) { 247: result = this.source.getRowKeys(); 248: } 249: } 250: return result; 251: } 252: 253: /** 254: * Returns the value for a given key. If the key is not recognised, the 255: * method should return <code>null</code> (but note that <code>null</code> 256: * can be associated with a valid key also). 257: * 258: * @param key the key. 259: * 260: * @return The value (possibly <code>null</code>). 261: */ 262: public Number getValue(Comparable key) { 263: Number result = null; 264: int keyIndex = getIndex(key); 265: if (keyIndex != -1) { 266: if (this.extract == TableOrder.BY_ROW) { 267: result = this.source.getValue(this.index, keyIndex); 268: } 269: else if (this.extract == TableOrder.BY_COLUMN) { 270: result = this.source.getValue(keyIndex, this.index); 271: } 272: } 273: return result; 274: } 275: 276: /** 277: * Sends a {@link DatasetChangeEvent} to all registered listeners, with 278: * this (not the underlying) dataset as the source. 279: * 280: * @param event the event (ignored, a new event with this dataset as the 281: * source is sent to the listeners). 282: */ 283: public void datasetChanged(DatasetChangeEvent event) { 284: fireDatasetChanged(); 285: } 286: 287: /** 288: * Tests this dataset for equality with an arbitrary object, returning 289: * <code>true</code> if <code>obj</code> is a dataset containing the same 290: * keys and values in the same order as this dataset. 291: * 292: * @param obj the object to test (<code>null</code> permitted). 293: * 294: * @return A boolean. 295: */ 296: public boolean equals(Object obj) { 297: if (obj == this) { 298: return true; 299: } 300: if (!(obj instanceof PieDataset)) { 301: return false; 302: } 303: PieDataset that = (PieDataset) obj; 304: int count = getItemCount(); 305: if (that.getItemCount() != count) { 306: return false; 307: } 308: for (int i = 0; i < count; i++) { 309: Comparable k1 = getKey(i); 310: Comparable k2 = that.getKey(i); 311: if (!k1.equals(k2)) { 312: return false; 313: } 314: 315: Number v1 = getValue(i); 316: Number v2 = that.getValue(i); 317: if (v1 == null) { 318: if (v2 != null) { 319: return false; 320: } 321: } 322: else { 323: if (!v1.equals(v2)) { 324: return false; 325: } 326: } 327: } 328: return true; 329: } 330: 331: }