001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------- 028 * Series.java 029 * ----------- 030 * (C) Copyright 2001-2006, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: Series.java,v 1.9.2.3 2006/07/25 15:55:48 mungady Exp $ 036 * 037 * Changes 038 * ------- 039 * 15-Nov-2001 : Version 1 (DG); 040 * 29-Nov-2001 : Added cloning and property change support (DG); 041 * 30-Jan-2002 : Added a description attribute and changed the constructors to 042 * protected (DG); 043 * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 044 * 13-Mar-2003 : Implemented Serializable (DG); 045 * 01-May-2003 : Added equals() method (DG); 046 * 26-Jun-2003 : Changed listener list to use EventListenerList - see bug 047 * 757027 (DG); 048 * 15-Oct-2003 : Added a flag to control whether or not change events are sent 049 * to registered listeners (DG); 050 * 19-May-2005 : Made abstract (DG); 051 * ------------- JFREECHART 1.0.0 --------------------------------------------- 052 * 04-May-2006 : Updated API docs (DG); 053 * 054 */ 055 056 package org.jfree.data.general; 057 058 import java.beans.PropertyChangeListener; 059 import java.beans.PropertyChangeSupport; 060 import java.io.Serializable; 061 062 import javax.swing.event.EventListenerList; 063 064 import org.jfree.util.ObjectUtilities; 065 066 /** 067 * Base class representing a data series. Subclasses are left to implement the 068 * actual data structures. 069 * <P> 070 * The series has two properties ("Key" and "Description") for which you can 071 * register a <code>PropertyChangeListener</code>. 072 * <P> 073 * You can also register a {@link SeriesChangeListener} to receive notification 074 * of changes to the series data. 075 */ 076 public abstract class Series implements Cloneable, Serializable { 077 078 /** For serialization. */ 079 private static final long serialVersionUID = -6906561437538683581L; 080 081 /** The key for the series. */ 082 private Comparable key; 083 084 /** A description of the series. */ 085 private String description; 086 087 /** Storage for registered change listeners. */ 088 private EventListenerList listeners; 089 090 /** Object to support property change notification. */ 091 private PropertyChangeSupport propertyChangeSupport; 092 093 /** A flag that controls whether or not changes are notified. */ 094 private boolean notify; 095 096 /** 097 * Creates a new series with the specified key. 098 * 099 * @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 }