001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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 * AbstractDialLayer.java
029 * ----------------------
030 * (C) Copyright 2006-2007, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * Changes
036 * -------
037 * 06-Nov-2006 : Version 1 (DG);
038 * 17-Nov-2006 : Added visible flag (DG);
039 * 16-Oct-2007 : Implemented equals() and clone() (DG);
040 *
041 */
042
043 package org.jfree.chart.plot.dial;
044
045 import java.io.IOException;
046 import java.io.ObjectInputStream;
047 import java.util.Arrays;
048 import java.util.EventListener;
049 import java.util.List;
050
051 import javax.swing.event.EventListenerList;
052
053 import org.jfree.chart.HashUtilities;
054
055 /**
056 * A base class that can be used to implement a {@link DialLayer}. It includes
057 * an event notification mechanism.
058 *
059 * @since 1.0.7
060 */
061 public abstract class AbstractDialLayer implements DialLayer {
062
063 /** A flag that controls whether or not the layer is visible. */
064 private boolean visible;
065
066 /** Storage for registered listeners. */
067 private transient EventListenerList listenerList;
068
069 /**
070 * Creates a new instance.
071 */
072 protected AbstractDialLayer() {
073 this.visible = true;
074 this.listenerList = new EventListenerList();
075 }
076
077 /**
078 * Returns <code>true</code> if this layer is visible (should be displayed),
079 * and <code>false</code> otherwise.
080 *
081 * @return A boolean.
082 *
083 * @see #setVisible(boolean)
084 */
085 public boolean isVisible() {
086 return this.visible;
087 }
088
089 /**
090 * Sets the flag that determines whether or not this layer is drawn by
091 * the plot, and sends a {@link DialLayerChangeEvent} to all registered
092 * listeners.
093 *
094 * @param visible the flag.
095 *
096 * @see #isVisible()
097 */
098 public void setVisible(boolean visible) {
099 this.visible = visible;
100 notifyListeners(new DialLayerChangeEvent(this));
101 }
102
103 /**
104 * Tests this instance for equality with an arbitrary object.
105 *
106 * @param obj the object (<code>null</code> permitted).
107 *
108 * @return A boolean.
109 */
110 public boolean equals(Object obj) {
111 if (obj == this) {
112 return true;
113 }
114 if (!(obj instanceof AbstractDialLayer)) {
115 return false;
116 }
117 AbstractDialLayer that = (AbstractDialLayer) obj;
118 return this.visible == that.visible;
119 }
120
121 /**
122 * Returns a hash code for this instance.
123 *
124 * @return A hash code.
125 */
126 public int hashCode() {
127 int result = 23;
128 result = HashUtilities.hashCode(result, this.visible);
129 return result;
130 }
131
132 /**
133 * Returns a clone of this instance.
134 *
135 * @return A clone.
136 *
137 * @throws CloneNotSupportedException if there is a problem cloning this
138 * instance.
139 */
140 public Object clone() throws CloneNotSupportedException {
141 AbstractDialLayer clone = (AbstractDialLayer) super.clone();
142 // we don't clone the listeners
143 clone.listenerList = new EventListenerList();
144 return clone;
145 }
146
147 /**
148 * Registers an object for notification of changes to the dial layer.
149 *
150 * @param listener the object that is being registered.
151 *
152 * @see #removeChangeListener(DialLayerChangeListener)
153 */
154 public void addChangeListener(DialLayerChangeListener listener) {
155 this.listenerList.add(DialLayerChangeListener.class, listener);
156 }
157
158 /**
159 * Deregisters an object for notification of changes to the dial layer.
160 *
161 * @param listener the object to deregister.
162 *
163 * @see #addChangeListener(DialLayerChangeListener)
164 */
165 public void removeChangeListener(DialLayerChangeListener listener) {
166 this.listenerList.remove(DialLayerChangeListener.class, listener);
167 }
168
169 /**
170 * Returns <code>true</code> if the specified object is registered with
171 * the dataset as a listener. Most applications won't need to call this
172 * method, it exists mainly for use by unit testing code.
173 *
174 * @param listener the listener.
175 *
176 * @return A boolean.
177 */
178 public boolean hasListener(EventListener listener) {
179 List list = Arrays.asList(this.listenerList.getListenerList());
180 return list.contains(listener);
181 }
182
183 /**
184 * Notifies all registered listeners that the dial layer has changed.
185 * The {@link DialLayerChangeEvent} provides information about the change.
186 *
187 * @param event information about the change to the axis.
188 */
189 protected void notifyListeners(DialLayerChangeEvent event) {
190 Object[] listeners = this.listenerList.getListenerList();
191 for (int i = listeners.length - 2; i >= 0; i -= 2) {
192 if (listeners[i] == DialLayerChangeListener.class) {
193 ((DialLayerChangeListener) listeners[i + 1]).dialLayerChanged(
194 event);
195 }
196 }
197 }
198
199 /**
200 * Provides serialization support.
201 *
202 * @param stream the input stream.
203 */
204 private void readObject(ObjectInputStream stream)
205 throws IOException, ClassNotFoundException {
206 stream.defaultReadObject();
207 this.listenerList = new EventListenerList();
208 }
209
210 }