Source for org.jfree.data.general.Series

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