001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * -------------------- 028 * AbstractDataset.java 029 * -------------------- 030 * (C)opyright 2000-2013, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Nicolas Brodu (for Astrium and EADS Corporate Research 034 * Center); 035 * 036 * Changes (from 21-Aug-2001) 037 * -------------------------- 038 * 21-Aug-2001 : Added standard header. Fixed DOS encoding problem (DG); 039 * 18-Sep-2001 : Updated e-mail address in header (DG); 040 * 15-Oct-2001 : Moved to new package (com.jrefinery.data.*) (DG); 041 * 22-Oct-2001 : Renamed DataSource.java --> Dataset.java etc. (DG); 042 * 17-Nov-2001 : Changed constructor from public to protected, created new 043 * AbstractSeriesDataset class and transferred series-related 044 * methods, updated Javadoc comments (DG); 045 * 04-Mar-2002 : Updated import statements (DG); 046 * 11-Jun-2002 : Updated for change in the event constructor (DG); 047 * 07-Aug-2002 : Changed listener list to use 048 * javax.swing.event.EventListenerList (DG); 049 * 04-Oct-2002 : Fixed errors reported by Checkstyle (DG); 050 * 27-Mar-2003 : Implemented Serializable (DG); 051 * 18-Aug-2003 : Implemented Cloneable (DG); 052 * 08-Sep-2003 : Serialization fixes (NB); 053 * 11-Sep-2003 : Cloning Fixes (NB); 054 * 01-Jun-2005 : Added hasListener() method for unit testing (DG); 055 * 03-Jul-2013 : Use ParamChecks (DG); 056 * 21-Nov-2013 : Added notify flag to allow suppressing change events 057 * temporarily (DG); 058 * 059 */ 060 061package org.jfree.data.general; 062 063import java.io.IOException; 064import java.io.InvalidObjectException; 065import java.io.ObjectInputStream; 066import java.io.ObjectInputValidation; 067import java.io.ObjectOutputStream; 068import java.io.Serializable; 069import java.util.Arrays; 070import java.util.EventListener; 071import java.util.List; 072 073import javax.swing.event.EventListenerList; 074import org.jfree.chart.util.ParamChecks; 075 076/** 077 * An abstract implementation of the {@link Dataset} interface, containing a 078 * mechanism for registering change listeners. 079 */ 080public abstract class AbstractDataset implements Dataset, Cloneable, 081 Serializable, ObjectInputValidation { 082 083 /** For serialization. */ 084 private static final long serialVersionUID = 1918768939869230744L; 085 086 /** The group that the dataset belongs to. */ 087 private DatasetGroup group; 088 089 /** Storage for registered change listeners. */ 090 private transient EventListenerList listenerList; 091 092 /** 093 * A flag that can be used to temporarily suppress dataset change event 094 * notifications. 095 */ 096 private boolean notify; 097 098 /** 099 * Constructs a dataset. By default, the dataset is assigned to its own 100 * group. 101 */ 102 protected AbstractDataset() { 103 this.group = new DatasetGroup(); 104 this.listenerList = new EventListenerList(); 105 this.notify = true; 106 } 107 108 /** 109 * Returns the dataset group for the dataset. 110 * 111 * @return The group (never <code>null</code>). 112 * 113 * @see #setGroup(DatasetGroup) 114 */ 115 @Override 116 public DatasetGroup getGroup() { 117 return this.group; 118 } 119 120 /** 121 * Sets the dataset group for the dataset. 122 * 123 * @param group the group (<code>null</code> not permitted). 124 * 125 * @see #getGroup() 126 */ 127 @Override 128 public void setGroup(DatasetGroup group) { 129 ParamChecks.nullNotPermitted(group, "group"); 130 this.group = group; 131 } 132 133 /** 134 * Returns the value of the notify flag. The default value is 135 * <code>true</code>. If this is <code>false</code>, calls to the 136 * {@link #fireDatasetChanged()} method will NOT trigger a dataset 137 * change event. 138 * 139 * @return A boolean. 140 * 141 * @since 1.0.17 142 */ 143 public boolean getNotify() { 144 return this.notify; 145 } 146 147 /** 148 * Sets the notify flag, which controls whether or not the {@link #fireDatasetChanged()} 149 * method notifies listeners. Setting this flag to <code>true</code> will 150 * trigger a <code>DatasetChangeEvent</code> because there may be 151 * queued up changes. 152 * 153 * @param notify the new flag value. 154 * 155 * @since 1.0.17 156 */ 157 public void setNotify(boolean notify) { 158 this.notify = notify; 159 if (notify) { 160 fireDatasetChanged(); 161 } 162 } 163 164 /** 165 * Registers an object to receive notification of changes to the dataset. 166 * 167 * @param listener the object to register. 168 * 169 * @see #removeChangeListener(DatasetChangeListener) 170 */ 171 @Override 172 public void addChangeListener(DatasetChangeListener listener) { 173 this.listenerList.add(DatasetChangeListener.class, listener); 174 } 175 176 /** 177 * Deregisters an object so that it no longer receives notification of 178 * changes to the dataset. 179 * 180 * @param listener the object to deregister. 181 * 182 * @see #addChangeListener(DatasetChangeListener) 183 */ 184 @Override 185 public void removeChangeListener(DatasetChangeListener listener) { 186 this.listenerList.remove(DatasetChangeListener.class, listener); 187 } 188 189 /** 190 * Returns <code>true</code> if the specified object is registered with 191 * the dataset as a listener. Most applications won't need to call this 192 * method, it exists mainly for use by unit testing code. 193 * 194 * @param listener the listener. 195 * 196 * @return A boolean. 197 * 198 * @see #addChangeListener(DatasetChangeListener) 199 * @see #removeChangeListener(DatasetChangeListener) 200 */ 201 public boolean hasListener(EventListener listener) { 202 List list = Arrays.asList(this.listenerList.getListenerList()); 203 return list.contains(listener); 204 } 205 206 /** 207 * Notifies all registered listeners that the dataset has changed, 208 * provided that the <code>notify</code> flag has not been set to 209 * <code>false</code>. 210 * 211 * @see #addChangeListener(DatasetChangeListener) 212 */ 213 protected void fireDatasetChanged() { 214 if (this.notify) { 215 notifyListeners(new DatasetChangeEvent(this, this)); 216 } 217 } 218 219 /** 220 * Notifies all registered listeners that the dataset has changed. 221 * 222 * @param event contains information about the event that triggered the 223 * notification. 224 * 225 * @see #addChangeListener(DatasetChangeListener) 226 * @see #removeChangeListener(DatasetChangeListener) 227 */ 228 protected void notifyListeners(DatasetChangeEvent event) { 229 Object[] listeners = this.listenerList.getListenerList(); 230 for (int i = listeners.length - 2; i >= 0; i -= 2) { 231 if (listeners[i] == DatasetChangeListener.class) { 232 ((DatasetChangeListener) listeners[i + 1]).datasetChanged( 233 event); 234 } 235 } 236 } 237 238 /** 239 * Returns a clone of the dataset. The cloned dataset will NOT include the 240 * {@link DatasetChangeListener} references that have been registered with 241 * this dataset. 242 * 243 * @return A clone. 244 * 245 * @throws CloneNotSupportedException if the dataset does not support 246 * cloning. 247 */ 248 @Override 249 public Object clone() throws CloneNotSupportedException { 250 AbstractDataset clone = (AbstractDataset) super.clone(); 251 clone.listenerList = new EventListenerList(); 252 return clone; 253 } 254 255 /** 256 * Handles serialization. 257 * 258 * @param stream the output stream. 259 * 260 * @throws IOException if there is an I/O problem. 261 */ 262 private void writeObject(ObjectOutputStream stream) throws IOException { 263 stream.defaultWriteObject(); 264 } 265 266 /** 267 * Restores a serialized object. 268 * 269 * @param stream the input stream. 270 * 271 * @throws IOException if there is an I/O problem. 272 * @throws ClassNotFoundException if there is a problem loading a class. 273 */ 274 private void readObject(ObjectInputStream stream) 275 throws IOException, ClassNotFoundException { 276 stream.defaultReadObject(); 277 this.listenerList = new EventListenerList(); 278 stream.registerValidation(this, 10); // see comments about priority of 279 // 10 in validateObject() 280 } 281 282 /** 283 * Validates the object. We use this opportunity to call listeners who have 284 * registered during the deserialization process, as listeners are not 285 * serialized. This method is called by the serialization system after the 286 * entire graph is read. 287 * 288 * This object has registered itself to the system with a priority of 10. 289 * Other callbacks may register with a higher priority number to be called 290 * before this object, or with a lower priority number to be called after 291 * the listeners were notified. 292 * 293 * All listeners are supposed to have register by now, either in their 294 * readObject or validateObject methods. Notify them that this dataset has 295 * changed. 296 * 297 * @exception InvalidObjectException If the object cannot validate itself. 298 */ 299 @Override 300 public void validateObject() throws InvalidObjectException { 301 fireDatasetChanged(); 302 } 303 304}