Source for org.jfree.data.category.CategoryToPieDataset

   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: }