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",
173: old, 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
248: .getDescription())) {
249: return false;
250: }
251: return true;
252: }
253:
254: /**
255: * Returns a hash code.
256: *
257: * @return A hash code.
258: */
259: public int hashCode() {
260: int result;
261: result = this .key.hashCode();
262: result = 29
263: * result
264: + (this .description != null ? this .description
265: .hashCode() : 0);
266: return result;
267: }
268:
269: /**
270: * Registers an object with this series, to receive notification whenever
271: * the series changes.
272: * <P>
273: * Objects being registered must implement the {@link SeriesChangeListener}
274: * interface.
275: *
276: * @param listener the listener to register.
277: */
278: public void addChangeListener(SeriesChangeListener listener) {
279: this .listeners.add(SeriesChangeListener.class, listener);
280: }
281:
282: /**
283: * Deregisters an object, so that it not longer receives notification
284: * whenever the series changes.
285: *
286: * @param listener the listener to deregister.
287: */
288: public void removeChangeListener(SeriesChangeListener listener) {
289: this .listeners.remove(SeriesChangeListener.class, listener);
290: }
291:
292: /**
293: * General method for signalling to registered listeners that the series
294: * has been changed.
295: */
296: public void fireSeriesChanged() {
297: if (this .notify) {
298: notifyListeners(new SeriesChangeEvent(this ));
299: }
300: }
301:
302: /**
303: * Sends a change event to all registered listeners.
304: *
305: * @param event contains information about the event that triggered the
306: * notification.
307: */
308: protected void notifyListeners(SeriesChangeEvent event) {
309:
310: Object[] listenerList = this .listeners.getListenerList();
311: for (int i = listenerList.length - 2; i >= 0; i -= 2) {
312: if (listenerList[i] == SeriesChangeListener.class) {
313: ((SeriesChangeListener) listenerList[i + 1])
314: .seriesChanged(event);
315: }
316: }
317:
318: }
319:
320: /**
321: * Adds a property change listener to the series.
322: *
323: * @param listener the listener.
324: */
325: public void addPropertyChangeListener(
326: PropertyChangeListener listener) {
327: this .propertyChangeSupport.addPropertyChangeListener(listener);
328: }
329:
330: /**
331: * Removes a property change listener from the series.
332: *
333: * @param listener The listener.
334: */
335: public void removePropertyChangeListener(
336: PropertyChangeListener listener) {
337: this .propertyChangeSupport
338: .removePropertyChangeListener(listener);
339: }
340:
341: /**
342: * Fires a property change event.
343: *
344: * @param property the property key.
345: * @param oldValue the old value.
346: * @param newValue the new value.
347: */
348: protected void firePropertyChange(String property, Object oldValue,
349: Object newValue) {
350: this.propertyChangeSupport.firePropertyChange(property,
351: oldValue, newValue);
352: }
353:
354: }
|