1. /* ===========================================================
  2. * JFreeChart : a free chart library for the Java(tm) platform
  3. * ===========================================================
  4. *
  5. * (C) Copyright 2000-2005, 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 under the terms
  10. * of the GNU Lesser General Public License as published by the Free Software Foundation;
  11. * either version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  14. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License along with this
  18. * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. *
  21. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  22. * in the United States and other countries.]
  23. *
  24. * -----------
  25. * Series.java
  26. * -----------
  27. * (C) Copyright 2001-2005, by Object Refinery Limited.
  28. *
  29. * Original Author: David Gilbert (for Object Refinery Limited);
  30. * Contributor(s): -;
  31. *
  32. * $Id: Series.java,v 1.5 2005/01/14 17:31:43 mungady Exp $
  33. *
  34. * Changes
  35. * -------
  36. * 15-Nov-2001 : Version 1 (DG);
  37. * 29-Nov-2001 : Added cloning and property change support (DG);
  38. * 30-Jan-2002 : Added a description attribute and changed the constructors to protected (DG);
  39. * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  40. * 13-Mar-2003 : Implemented Serializable (DG);
  41. * 01-May-2003 : Added equals() method (DG);
  42. * 26-Jun-2003 : Changed listener list to use EventListenerList - see bug 757027 (DG);
  43. * 15-Oct-2003 : Added a flag to control whether or not change events are sent to registered
  44. * listeners (DG);
  45. *
  46. */
  47. package org.jfree.data.general;
  48. import java.beans.PropertyChangeListener;
  49. import java.beans.PropertyChangeSupport;
  50. import java.io.Serializable;
  51. import javax.swing.event.EventListenerList;
  52. import org.jfree.util.ObjectUtilities;
  53. /**
  54. * Base class representing a data series. Subclasses are left to implement the
  55. * actual data structures.
  56. * <P>
  57. * The series has two properties ("Name" and "Description") for which you can
  58. * register a {@link PropertyChangeListener}.
  59. * <P>
  60. * You can also register a {@link SeriesChangeListener} to receive notification of
  61. * changes to the series data.
  62. *
  63. */
  64. public class Series implements Cloneable, Serializable {
  65. /** The name of the series. */
  66. private String name;
  67. /** A description of the series. */
  68. private String description;
  69. /** Storage for registered change listeners. */
  70. private EventListenerList listeners;
  71. /** Object to support property change notification. */
  72. private PropertyChangeSupport propertyChangeSupport;
  73. /** A flag that controls whether or not changes are notified. */
  74. private boolean notify;
  75. /**
  76. * Creates a new series.
  77. *
  78. * @param name the series name (<code>null</code> not permitted).
  79. */
  80. protected Series(String name) {
  81. this(name, null);
  82. }
  83. /**
  84. * Constructs a series.
  85. *
  86. * @param name the series name (<code>null</code> NOT permitted).
  87. * @param description the series description (<code>null</code> permitted).
  88. */
  89. protected Series(String name, String description) {
  90. if (name == null) {
  91. throw new IllegalArgumentException("Null 'name' argument.");
  92. }
  93. this.name = name;
  94. this.description = description;
  95. this.listeners = new EventListenerList();
  96. this.propertyChangeSupport = new PropertyChangeSupport(this);
  97. this.notify = true;
  98. }
  99. /**
  100. * Returns the name of the series.
  101. *
  102. * @return the series name (never <code>null</code>).
  103. */
  104. public String getName() {
  105. return this.name;
  106. }
  107. /**
  108. * Sets the name of the series.
  109. *
  110. * @param name the name (<code>null</code> not permitted).
  111. */
  112. public void setName(String name) {
  113. if (name == null) {
  114. throw new IllegalArgumentException("Null 'name' argument.");
  115. }
  116. String old = this.name;
  117. this.name = name;
  118. this.propertyChangeSupport.firePropertyChange("Name", old, name);
  119. }
  120. /**
  121. * Returns a description of the series.
  122. *
  123. * @return the series description (possibly <code>null</code>).
  124. */
  125. public String getDescription() {
  126. return this.description;
  127. }
  128. /**
  129. * Sets the description of the series.
  130. *
  131. * @param description the description (<code>null</code> permitted).
  132. */
  133. public void setDescription(String description) {
  134. String old = this.description;
  135. this.description = description;
  136. this.propertyChangeSupport.firePropertyChange("Description", old, description);
  137. }
  138. /**
  139. * Returns the flag that controls whether or not change events are sent to registered
  140. * listeners.
  141. *
  142. * @return a boolean.
  143. */
  144. public boolean getNotify() {
  145. return this.notify;
  146. }
  147. /**
  148. * Sets the flag that controls whether or not change events are sent to registered
  149. * listeners.
  150. *
  151. * @param notify the new value of the flag.
  152. */
  153. public void setNotify(boolean notify) {
  154. if (this.notify != notify) {
  155. this.notify = notify;
  156. fireSeriesChanged();
  157. }
  158. }
  159. /**
  160. * Returns a clone of the series.
  161. * <P>
  162. * Notes:
  163. * 1. No need to clone the name or description, since String object is immutable.
  164. * 2. We set the listener list to empty, since the listeners did not register with the clone.
  165. * 3. Same applies to the PropertyChangeSupport instance.
  166. *
  167. * @return a clone of the series.
  168. *
  169. * @throws CloneNotSupportedException not thrown by this class, but subclasses may differ.
  170. */
  171. public Object clone() throws CloneNotSupportedException {
  172. try {
  173. Series clone = (Series) super.clone();
  174. clone.listeners = new EventListenerList();
  175. clone.propertyChangeSupport = new PropertyChangeSupport(clone);
  176. return clone;
  177. }
  178. catch (CloneNotSupportedException e) { // won't get here...
  179. throw new CloneNotSupportedException("Series.clone(): unexpected exception.");
  180. }
  181. }
  182. /**
  183. * Tests the series for equality with another object.
  184. *
  185. * @param obj the object.
  186. *
  187. * @return <code>true</code> or <code>false</code>.
  188. */
  189. public boolean equals(Object obj) {
  190. if (obj == this) {
  191. return true;
  192. }
  193. if (!(obj instanceof Series)) {
  194. return false;
  195. }
  196. Series that = (Series) obj;
  197. if (!getName().equals(that.getName())) {
  198. return false;
  199. }
  200. if (!ObjectUtilities.equal(getDescription(), that.getDescription())) {
  201. return false;
  202. }
  203. return true;
  204. }
  205. /**
  206. * Returns a hash code.
  207. *
  208. * @return a hash code.
  209. */
  210. public int hashCode() {
  211. int result;
  212. result = this.name.hashCode();
  213. result = 29 * result + (this.description != null ? this.description.hashCode() : 0);
  214. return result;
  215. }
  216. /**
  217. * Registers an object with this series, to receive notification whenever the series changes.
  218. * <P>
  219. * Objects being registered must implement the {@link SeriesChangeListener} interface.
  220. *
  221. * @param listener the listener to register.
  222. */
  223. public void addChangeListener(SeriesChangeListener listener) {
  224. this.listeners.add(SeriesChangeListener.class, listener);
  225. }
  226. /**
  227. * Deregisters an object, so that it not longer receives notification whenever the series
  228. * changes.
  229. *
  230. * @param listener the listener to deregister.
  231. */
  232. public void removeChangeListener(SeriesChangeListener listener) {
  233. this.listeners.remove(SeriesChangeListener.class, listener);
  234. }
  235. /**
  236. * General method for signalling to registered listeners that the series
  237. * has been changed.
  238. */
  239. public void fireSeriesChanged() {
  240. if (this.notify) {
  241. notifyListeners(new SeriesChangeEvent(this));
  242. }
  243. }
  244. /**
  245. * Sends a change event to all registered listeners.
  246. *
  247. * @param event Contains information about the event that triggered the notification.
  248. */
  249. protected void notifyListeners(SeriesChangeEvent event) {
  250. Object[] listenerList = this.listeners.getListenerList();
  251. for (int i = listenerList.length - 2; i >= 0; i -= 2) {
  252. if (listenerList[i] == SeriesChangeListener.class) {
  253. ((SeriesChangeListener) listenerList[i + 1]).seriesChanged(event);
  254. }
  255. }
  256. }
  257. /**
  258. * Adds a property change listener to the series.
  259. *
  260. * @param listener The listener.
  261. */
  262. public void addPropertyChangeListener(PropertyChangeListener listener) {
  263. this.propertyChangeSupport.addPropertyChangeListener(listener);
  264. }
  265. /**
  266. * Removes a property change listener from the series.
  267. *
  268. * @param listener The listener.
  269. */
  270. public void removePropertyChangeListener(PropertyChangeListener listener) {
  271. this.propertyChangeSupport.removePropertyChangeListener(listener);
  272. }
  273. /**
  274. * Fires a property change event.
  275. *
  276. * @param property the property key.
  277. * @param oldValue the old value.
  278. * @param newValue the new value.
  279. */
  280. protected void firePropertyChange(String property,
  281. Object oldValue,
  282. Object newValue) {
  283. this.propertyChangeSupport.firePropertyChange(property, oldValue, newValue);
  284. }
  285. }