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: * Series.java 29: * ----------- 30: * (C) Copyright 2001-2007, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * Changes 36: * ------- 37: * 15-Nov-2001 : Version 1 (DG); 38: * 29-Nov-2001 : Added cloning and property change support (DG); 39: * 30-Jan-2002 : Added a description attribute and changed the constructors to 40: * protected (DG); 41: * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 42: * 13-Mar-2003 : Implemented Serializable (DG); 43: * 01-May-2003 : Added equals() method (DG); 44: * 26-Jun-2003 : Changed listener list to use EventListenerList - see bug 45: * 757027 (DG); 46: * 15-Oct-2003 : Added a flag to control whether or not change events are sent 47: * to registered listeners (DG); 48: * 19-May-2005 : Made abstract (DG); 49: * ------------- JFREECHART 1.0.x --------------------------------------------- 50: * 04-May-2006 : Updated API docs (DG); 51: * 26-Sep-2007 : Added isEmpty() and getItemCount() methods (DG); 52: * 53: */ 54: 55: package org.jfree.data.general; 56: 57: import java.beans.PropertyChangeListener; 58: import java.beans.PropertyChangeSupport; 59: import java.io.Serializable; 60: 61: import javax.swing.event.EventListenerList; 62: 63: import org.jfree.util.ObjectUtilities; 64: 65: /** 66: * Base class representing a data series. Subclasses are left to implement the 67: * actual data structures. 68: * <P> 69: * The series has two properties ("Key" and "Description") for which you can 70: * register a <code>PropertyChangeListener</code>. 71: * <P> 72: * You can also register a {@link SeriesChangeListener} to receive notification 73: * of changes to the series data. 74: */ 75: public abstract class Series implements Cloneable, Serializable { 76: 77: /** For serialization. */ 78: private static final long serialVersionUID = -6906561437538683581L; 79: 80: /** The key for the series. */ 81: private Comparable key; 82: 83: /** A description of the series. */ 84: private String description; 85: 86: /** Storage for registered change listeners. */ 87: private EventListenerList listeners; 88: 89: /** Object to support property change notification. */ 90: private PropertyChangeSupport propertyChangeSupport; 91: 92: /** A flag that controls whether or not changes are notified. */ 93: private boolean notify; 94: 95: /** 96: * Creates a new series with the specified key. 97: * 98: * @param key the series key (<code>null</code> not permitted). 99: */ 100: protected Series(Comparable key) { 101: this(key, null); 102: } 103: 104: /** 105: * Creates a new series with the specified key and description. 106: * 107: * @param key the series key (<code>null</code> NOT permitted). 108: * @param description the series description (<code>null</code> permitted). 109: */ 110: protected Series(Comparable key, String description) { 111: if (key == null) { 112: throw new IllegalArgumentException("Null 'key' argument."); 113: } 114: this.key = key; 115: this.description = description; 116: this.listeners = new EventListenerList(); 117: this.propertyChangeSupport = new PropertyChangeSupport(this); 118: this.notify = true; 119: } 120: 121: /** 122: * Returns the key for the series. 123: * 124: * @return The series key (never <code>null</code>). 125: * 126: * @see #setKey(Comparable) 127: */ 128: public Comparable getKey() { 129: return this.key; 130: } 131: 132: /** 133: * Sets the key for the series and sends a <code>PropertyChangeEvent</code> 134: * (with the property name "Key") to all registered listeners. 135: * 136: * @param key the key (<code>null</code> not permitted). 137: * 138: * @see #getKey() 139: */ 140: public void setKey(Comparable key) { 141: if (key == null) { 142: throw new IllegalArgumentException("Null 'key' argument."); 143: } 144: Comparable old = this.key; 145: this.key = key; 146: this.propertyChangeSupport.firePropertyChange("Key", old, key); 147: } 148: 149: /** 150: * Returns a description of the series. 151: * 152: * @return The series description (possibly <code>null</code>). 153: * 154: * @see #setDescription(String) 155: */ 156: public String getDescription() { 157: return this.description; 158: } 159: 160: /** 161: * Sets the description of the series and sends a 162: * <code>PropertyChangeEvent</code> to all registered listeners. 163: * 164: * @param description the description (<code>null</code> permitted). 165: * 166: * @see #getDescription() 167: */ 168: public void setDescription(String description) { 169: String old = this.description; 170: this.description = description; 171: this.propertyChangeSupport.firePropertyChange("Description", old, 172: description); 173: } 174: 175: /** 176: * Returns the flag that controls whether or not change events are sent to 177: * registered listeners. 178: * 179: * @return A boolean. 180: * 181: * @see #setNotify(boolean) 182: */ 183: public boolean getNotify() { 184: return this.notify; 185: } 186: 187: /** 188: * Sets the flag that controls whether or not change events are sent to 189: * registered listeners. 190: * 191: * @param notify the new value of the flag. 192: * 193: * @see #getNotify() 194: */ 195: public void setNotify(boolean notify) { 196: if (this.notify != notify) { 197: this.notify = notify; 198: fireSeriesChanged(); 199: } 200: } 201: 202: /** 203: * Returns <code>true</code> if the series contains no data items, and 204: * <code>false</code> otherwise. 205: * 206: * @return A boolean. 207: * 208: * @since 1.0.7 209: */ 210: public boolean isEmpty() { 211: return (getItemCount() == 0); 212: } 213: 214: /** 215: * Returns the number of data items in the series. 216: * 217: * @return The number of data items in the series. 218: */ 219: public abstract int getItemCount(); 220: 221: /** 222: * Returns a clone of the series. 223: * <P> 224: * Notes: 225: * <ul> 226: * <li>No need to clone the name or description, since String object is 227: * immutable.</li> 228: * <li>We set the listener list to empty, since the listeners did not 229: * register with the clone.</li> 230: * <li>Same applies to the PropertyChangeSupport instance.</li> 231: * </ul> 232: * 233: * @return A clone of the series. 234: * 235: * @throws CloneNotSupportedException not thrown by this class, but 236: * subclasses may differ. 237: */ 238: public Object clone() throws CloneNotSupportedException { 239: 240: Series clone = (Series) super.clone(); 241: clone.listeners = new EventListenerList(); 242: clone.propertyChangeSupport = new PropertyChangeSupport(clone); 243: return clone; 244: 245: } 246: 247: /** 248: * Tests the series for equality with another object. 249: * 250: * @param obj the object (<code>null</code> permitted). 251: * 252: * @return <code>true</code> or <code>false</code>. 253: */ 254: public boolean equals(Object obj) { 255: if (obj == this) { 256: return true; 257: } 258: if (!(obj instanceof Series)) { 259: return false; 260: } 261: Series that = (Series) obj; 262: if (!getKey().equals(that.getKey())) { 263: return false; 264: } 265: if (!ObjectUtilities.equal(getDescription(), that.getDescription())) { 266: return false; 267: } 268: return true; 269: } 270: 271: /** 272: * Returns a hash code. 273: * 274: * @return A hash code. 275: */ 276: public int hashCode() { 277: int result; 278: result = this.key.hashCode(); 279: result = 29 * result + (this.description != null 280: ? this.description.hashCode() : 0); 281: return result; 282: } 283: 284: /** 285: * Registers an object with this series, to receive notification whenever 286: * the series changes. 287: * <P> 288: * Objects being registered must implement the {@link SeriesChangeListener} 289: * interface. 290: * 291: * @param listener the listener to register. 292: */ 293: public void addChangeListener(SeriesChangeListener listener) { 294: this.listeners.add(SeriesChangeListener.class, listener); 295: } 296: 297: /** 298: * Deregisters an object, so that it not longer receives notification 299: * whenever the series changes. 300: * 301: * @param listener the listener to deregister. 302: */ 303: public void removeChangeListener(SeriesChangeListener listener) { 304: this.listeners.remove(SeriesChangeListener.class, listener); 305: } 306: 307: /** 308: * General method for signalling to registered listeners that the series 309: * has been changed. 310: */ 311: public void fireSeriesChanged() { 312: if (this.notify) { 313: notifyListeners(new SeriesChangeEvent(this)); 314: } 315: } 316: 317: /** 318: * Sends a change event to all registered listeners. 319: * 320: * @param event contains information about the event that triggered the 321: * notification. 322: */ 323: protected void notifyListeners(SeriesChangeEvent event) { 324: 325: Object[] listenerList = this.listeners.getListenerList(); 326: for (int i = listenerList.length - 2; i >= 0; i -= 2) { 327: if (listenerList[i] == SeriesChangeListener.class) { 328: ((SeriesChangeListener) listenerList[i + 1]).seriesChanged( 329: event); 330: } 331: } 332: 333: } 334: 335: /** 336: * Adds a property change listener to the series. 337: * 338: * @param listener the listener. 339: */ 340: public void addPropertyChangeListener(PropertyChangeListener listener) { 341: this.propertyChangeSupport.addPropertyChangeListener(listener); 342: } 343: 344: /** 345: * Removes a property change listener from the series. 346: * 347: * @param listener The listener. 348: */ 349: public void removePropertyChangeListener(PropertyChangeListener listener) { 350: this.propertyChangeSupport.removePropertyChangeListener(listener); 351: } 352: 353: /** 354: * Fires a property change event. 355: * 356: * @param property the property key. 357: * @param oldValue the old value. 358: * @param newValue the new value. 359: */ 360: protected void firePropertyChange(String property, Object oldValue, 361: Object newValue) { 362: this.propertyChangeSupport.firePropertyChange(property, oldValue, 363: newValue); 364: } 365: 366: }