001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, 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-2005, 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.1 2005/10/25 21:32:29 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 * 052 */ 053 054 package org.jfree.data.general; 055 056 import java.beans.PropertyChangeListener; 057 import java.beans.PropertyChangeSupport; 058 import java.io.Serializable; 059 060 import javax.swing.event.EventListenerList; 061 062 import org.jfree.util.ObjectUtilities; 063 064 /** 065 * Base class representing a data series. Subclasses are left to implement the 066 * actual data structures. 067 * <P> 068 * The series has two properties ("Name" and "Description") for which you can 069 * register a {@link PropertyChangeListener}. 070 * <P> 071 * You can also register a {@link SeriesChangeListener} to receive notification 072 * of changes to the series data. 073 */ 074 public abstract class Series implements Cloneable, Serializable { 075 076 /** For serialization. */ 077 private static final long serialVersionUID = -6906561437538683581L; 078 079 /** The key for the series. */ 080 private Comparable key; 081 082 /** A description of the series. */ 083 private String description; 084 085 /** Storage for registered change listeners. */ 086 private EventListenerList listeners; 087 088 /** Object to support property change notification. */ 089 private PropertyChangeSupport propertyChangeSupport; 090 091 /** A flag that controls whether or not changes are notified. */ 092 private boolean notify; 093 094 /** 095 * Creates a new series. 096 * 097 * @param key the series key (<code>null</code> not permitted). 098 */ 099 protected Series(Comparable key) { 100 this(key, null); 101 } 102 103 /** 104 * Constructs a series. 105 * 106 * @param key the series key (<code>null</code> NOT permitted). 107 * @param description the series description (<code>null</code> permitted). 108 */ 109 protected Series(Comparable key, String description) { 110 if (key == null) { 111 throw new IllegalArgumentException("Null 'key' argument."); 112 } 113 this.key = key; 114 this.description = description; 115 this.listeners = new EventListenerList(); 116 this.propertyChangeSupport = new PropertyChangeSupport(this); 117 this.notify = true; 118 119 } 120 121 /** 122 * Returns the key for the series. 123 * 124 * @return The series key (never <code>null</code>). 125 */ 126 public Comparable getKey() { 127 return this.key; 128 } 129 130 /** 131 * Sets the key for the series. 132 * 133 * @param key the key (<code>null</code> not permitted). 134 */ 135 public void setKey(Comparable key) { 136 if (key == null) { 137 throw new IllegalArgumentException("Null 'key' argument."); 138 } 139 Comparable old = this.key; 140 this.key = key; 141 this.propertyChangeSupport.firePropertyChange("Key", old, key); 142 } 143 144 /** 145 * Returns a description of the series. 146 * 147 * @return The series description (possibly <code>null</code>). 148 */ 149 public String getDescription() { 150 return this.description; 151 } 152 153 /** 154 * Sets the description of the series. 155 * 156 * @param description the description (<code>null</code> permitted). 157 */ 158 public void setDescription(String description) { 159 String old = this.description; 160 this.description = description; 161 this.propertyChangeSupport.firePropertyChange( 162 "Description", old, description 163 ); 164 } 165 166 /** 167 * Returns the flag that controls whether or not change events are sent to 168 * registered listeners. 169 * 170 * @return A boolean. 171 */ 172 public boolean getNotify() { 173 return this.notify; 174 } 175 176 /** 177 * Sets the flag that controls whether or not change events are sent to 178 * registered listeners. 179 * 180 * @param notify the new value of the flag. 181 */ 182 public void setNotify(boolean notify) { 183 if (this.notify != notify) { 184 this.notify = notify; 185 fireSeriesChanged(); 186 } 187 } 188 189 /** 190 * Returns a clone of the series. 191 * <P> 192 * Notes: 193 * <ul> 194 * <li>No need to clone the name or description, since String object is 195 * immutable.</li> 196 * <li>We set the listener list to empty, since the listeners did not 197 * register with the clone.</li> 198 * <li>Same applies to the PropertyChangeSupport instance.</li> 199 * </ul> 200 * 201 * @return A clone of the series. 202 * 203 * @throws CloneNotSupportedException not thrown by this class, but 204 * subclasses may differ. 205 */ 206 public Object clone() throws CloneNotSupportedException { 207 208 Series clone = (Series) super.clone(); 209 clone.listeners = new EventListenerList(); 210 clone.propertyChangeSupport = new PropertyChangeSupport(clone); 211 return clone; 212 213 } 214 215 /** 216 * Tests the series for equality with another object. 217 * 218 * @param obj the object. 219 * 220 * @return <code>true</code> or <code>false</code>. 221 */ 222 public boolean equals(Object obj) { 223 224 if (obj == this) { 225 return true; 226 } 227 228 if (!(obj instanceof Series)) { 229 return false; 230 } 231 Series that = (Series) obj; 232 if (!getKey().equals(that.getKey())) { 233 return false; 234 } 235 236 if (!ObjectUtilities.equal(getDescription(), that.getDescription())) { 237 return false; 238 } 239 240 return true; 241 } 242 243 /** 244 * Returns a hash code. 245 * 246 * @return A hash code. 247 */ 248 public int hashCode() { 249 int result; 250 result = this.key.hashCode(); 251 result = 29 * result + (this.description != null 252 ? this.description.hashCode() : 0); 253 return result; 254 } 255 256 /** 257 * Registers an object with this series, to receive notification whenever 258 * the series changes. 259 * <P> 260 * Objects being registered must implement the {@link SeriesChangeListener} 261 * interface. 262 * 263 * @param listener the listener to register. 264 */ 265 public void addChangeListener(SeriesChangeListener listener) { 266 this.listeners.add(SeriesChangeListener.class, listener); 267 } 268 269 /** 270 * Deregisters an object, so that it not longer receives notification 271 * whenever the series changes. 272 * 273 * @param listener the listener to deregister. 274 */ 275 public void removeChangeListener(SeriesChangeListener listener) { 276 this.listeners.remove(SeriesChangeListener.class, listener); 277 } 278 279 /** 280 * General method for signalling to registered listeners that the series 281 * has been changed. 282 */ 283 public void fireSeriesChanged() { 284 if (this.notify) { 285 notifyListeners(new SeriesChangeEvent(this)); 286 } 287 } 288 289 /** 290 * Sends a change event to all registered listeners. 291 * 292 * @param event contains information about the event that triggered the 293 * notification. 294 */ 295 protected void notifyListeners(SeriesChangeEvent event) { 296 297 Object[] listenerList = this.listeners.getListenerList(); 298 for (int i = listenerList.length - 2; i >= 0; i -= 2) { 299 if (listenerList[i] == SeriesChangeListener.class) { 300 ((SeriesChangeListener) listenerList[i + 1]).seriesChanged( 301 event 302 ); 303 } 304 } 305 306 } 307 308 /** 309 * Adds a property change listener to the series. 310 * 311 * @param listener the listener. 312 */ 313 public void addPropertyChangeListener(PropertyChangeListener listener) { 314 this.propertyChangeSupport.addPropertyChangeListener(listener); 315 } 316 317 /** 318 * Removes a property change listener from the series. 319 * 320 * @param listener The listener. 321 */ 322 public void removePropertyChangeListener(PropertyChangeListener listener) { 323 this.propertyChangeSupport.removePropertyChangeListener(listener); 324 } 325 326 /** 327 * Fires a property change event. 328 * 329 * @param property the property key. 330 * @param oldValue the old value. 331 * @param newValue the new value. 332 */ 333 protected void firePropertyChange(String property, 334 Object oldValue, 335 Object newValue) { 336 this.propertyChangeSupport.firePropertyChange( 337 property, oldValue, newValue 338 ); 339 } 340 341 }