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: * AbstractDataset.java 29: * -------------------- 30: * (C)opyright 2000-2007, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): Nicolas Brodu (for Astrium and EADS Corporate Research 34: * Center); 35: * 36: * Changes (from 21-Aug-2001) 37: * -------------------------- 38: * 21-Aug-2001 : Added standard header. Fixed DOS encoding problem (DG); 39: * 18-Sep-2001 : Updated e-mail address in header (DG); 40: * 15-Oct-2001 : Moved to new package (com.jrefinery.data.*) (DG); 41: * 22-Oct-2001 : Renamed DataSource.java --> Dataset.java etc. (DG); 42: * 17-Nov-2001 : Changed constructor from public to protected, created new 43: * AbstractSeriesDataset class and transferred series-related 44: * methods, updated Javadoc comments (DG); 45: * 04-Mar-2002 : Updated import statements (DG); 46: * 11-Jun-2002 : Updated for change in the event constructor (DG); 47: * 07-Aug-2002 : Changed listener list to use 48: * javax.swing.event.EventListenerList (DG); 49: * 04-Oct-2002 : Fixed errors reported by Checkstyle (DG); 50: * 27-Mar-2003 : Implemented Serializable (DG); 51: * 18-Aug-2003 : Implemented Cloneable (DG); 52: * 08-Sep-2003 : Serialization fixes (NB); 53: * 11-Sep-2003 : Cloning Fixes (NB); 54: * 01-Jun-2005 : Added hasListener() method for unit testing (DG); 55: * 56: */ 57: 58: package org.jfree.data.general; 59: 60: import java.io.IOException; 61: import java.io.InvalidObjectException; 62: import java.io.ObjectInputStream; 63: import java.io.ObjectInputValidation; 64: import java.io.ObjectOutputStream; 65: import java.io.Serializable; 66: import java.util.Arrays; 67: import java.util.EventListener; 68: import java.util.List; 69: 70: import javax.swing.event.EventListenerList; 71: 72: /** 73: * An abstract implementation of the {@link Dataset} interface, containing a 74: * mechanism for registering change listeners. 75: */ 76: public abstract class AbstractDataset implements Dataset, 77: Cloneable, 78: Serializable, 79: ObjectInputValidation { 80: 81: /** For serialization. */ 82: private static final long serialVersionUID = 1918768939869230744L; 83: 84: /** The group that the dataset belongs to. */ 85: private DatasetGroup group; 86: 87: /** Storage for registered change listeners. */ 88: private transient EventListenerList listenerList; 89: 90: /** 91: * Constructs a dataset. By default, the dataset is assigned to its own 92: * group. 93: */ 94: protected AbstractDataset() { 95: this.group = new DatasetGroup(); 96: this.listenerList = new EventListenerList(); 97: } 98: 99: /** 100: * Returns the dataset group for the dataset. 101: * 102: * @return The group. 103: */ 104: public DatasetGroup getGroup() { 105: return this.group; 106: } 107: 108: /** 109: * Sets the dataset group for the dataset. 110: * 111: * @param group the group (<code>null</code> not permitted). 112: */ 113: public void setGroup(DatasetGroup group) { 114: if (group == null) { 115: throw new IllegalArgumentException("Null 'group' argument."); 116: } 117: this.group = group; 118: } 119: 120: /** 121: * Registers an object to receive notification of changes to the dataset. 122: * 123: * @param listener the object to register. 124: */ 125: public void addChangeListener(DatasetChangeListener listener) { 126: this.listenerList.add(DatasetChangeListener.class, listener); 127: } 128: 129: /** 130: * Deregisters an object so that it no longer receives notification of 131: * changes to the dataset. 132: * 133: * @param listener the object to deregister. 134: */ 135: public void removeChangeListener(DatasetChangeListener listener) { 136: this.listenerList.remove(DatasetChangeListener.class, listener); 137: } 138: 139: /** 140: * Returns <code>true</code> if the specified object is registered with 141: * the dataset as a listener. Most applications won't need to call this 142: * method, it exists mainly for use by unit testing code. 143: * 144: * @param listener the listener. 145: * 146: * @return A boolean. 147: */ 148: public boolean hasListener(EventListener listener) { 149: List list = Arrays.asList(this.listenerList.getListenerList()); 150: return list.contains(listener); 151: } 152: 153: /** 154: * Notifies all registered listeners that the dataset has changed. 155: */ 156: protected void fireDatasetChanged() { 157: notifyListeners(new DatasetChangeEvent(this, this)); 158: } 159: 160: /** 161: * Notifies all registered listeners that the dataset has changed. 162: * 163: * @param event contains information about the event that triggered the 164: * notification. 165: */ 166: protected void notifyListeners(DatasetChangeEvent event) { 167: 168: Object[] listeners = this.listenerList.getListenerList(); 169: for (int i = listeners.length - 2; i >= 0; i -= 2) { 170: if (listeners[i] == DatasetChangeListener.class) { 171: ((DatasetChangeListener) listeners[i + 1]).datasetChanged( 172: event 173: ); 174: } 175: } 176: 177: } 178: 179: /** 180: * Returns a clone of the dataset. The cloned dataset will NOT include the 181: * {@link DatasetChangeListener} references that have been registered with 182: * this dataset. 183: * 184: * @return A clone. 185: * 186: * @throws CloneNotSupportedException if the dataset does not support 187: * cloning. 188: */ 189: public Object clone() throws CloneNotSupportedException { 190: AbstractDataset clone = (AbstractDataset) super.clone(); 191: clone.listenerList = new EventListenerList(); 192: return clone; 193: } 194: 195: /** 196: * Handles serialization. 197: * 198: * @param stream the output stream. 199: * 200: * @throws IOException if there is an I/O problem. 201: */ 202: private void writeObject(ObjectOutputStream stream) throws IOException { 203: stream.defaultWriteObject(); 204: } 205: 206: /** 207: * Restores a serialized object. 208: * 209: * @param stream the input stream. 210: * 211: * @throws IOException if there is an I/O problem. 212: * @throws ClassNotFoundException if there is a problem loading a class. 213: */ 214: private void readObject(ObjectInputStream stream) 215: throws IOException, ClassNotFoundException { 216: stream.defaultReadObject(); 217: this.listenerList = new EventListenerList(); 218: stream.registerValidation(this, 10); // see comments about priority of 219: // 10 in validateObject() 220: } 221: 222: /** 223: * Validates the object. We use this opportunity to call listeners who have 224: * registered during the deserialization process, as listeners are not 225: * serialized. This method is called by the serialization system after the 226: * entire graph is read. 227: * 228: * This object has registered itself to the system with a priority of 10. 229: * Other callbacks may register with a higher priority number to be called 230: * before this object, or with a lower priority number to be called after 231: * the listeners were notified. 232: * 233: * All listeners are supposed to have register by now, either in their 234: * readObject or validateObject methods. Notify them that this dataset has 235: * changed. 236: * 237: * @exception InvalidObjectException If the object cannot validate itself. 238: */ 239: public void validateObject() throws InvalidObjectException { 240: fireDatasetChanged(); 241: } 242: 243: }