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