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 * AbstractDialLayer.java
029 * ----------------------
030 * (C) Copyright 2006-2008, 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
043package org.jfree.chart.plot.dial;
044
045import java.io.IOException;
046import java.io.ObjectInputStream;
047import java.util.Arrays;
048import java.util.EventListener;
049import java.util.List;
050
051import javax.swing.event.EventListenerList;
052
053import 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 */
061public 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    @Override
086    public boolean isVisible() {
087        return this.visible;
088    }
089
090    /**
091     * Sets the flag that determines whether or not this layer is drawn by
092     * the plot, and sends a {@link DialLayerChangeEvent} to all registered
093     * listeners.
094     *
095     * @param visible  the flag.
096     *
097     * @see #isVisible()
098     */
099    public void setVisible(boolean visible) {
100        this.visible = visible;
101        notifyListeners(new DialLayerChangeEvent(this));
102    }
103
104    /**
105     * Tests this instance for equality with an arbitrary object.
106     *
107     * @param obj  the object (<code>null</code> permitted).
108     *
109     * @return A boolean.
110     */
111    @Override
112    public boolean equals(Object obj) {
113        if (obj == this) {
114            return true;
115        }
116        if (!(obj instanceof AbstractDialLayer)) {
117            return false;
118        }
119        AbstractDialLayer that = (AbstractDialLayer) obj;
120        return this.visible == that.visible;
121    }
122
123    /**
124     * Returns a hash code for this instance.
125     *
126     * @return A hash code.
127     */
128    @Override
129    public int hashCode() {
130        int result = 23;
131        result = HashUtilities.hashCode(result, this.visible);
132        return result;
133    }
134
135    /**
136     * Returns a clone of this instance.
137     *
138     * @return A clone.
139     *
140     * @throws CloneNotSupportedException if there is a problem cloning this
141     *     instance.
142     */
143    @Override
144    public Object clone() throws CloneNotSupportedException {
145        AbstractDialLayer clone = (AbstractDialLayer) super.clone();
146        // we don't clone the listeners
147        clone.listenerList = new EventListenerList();
148        return clone;
149    }
150
151    /**
152     * Registers an object for notification of changes to the dial layer.
153     *
154     * @param listener  the object that is being registered.
155     *
156     * @see #removeChangeListener(DialLayerChangeListener)
157     */
158    @Override
159    public void addChangeListener(DialLayerChangeListener listener) {
160        this.listenerList.add(DialLayerChangeListener.class, listener);
161    }
162
163    /**
164     * Deregisters an object for notification of changes to the dial layer.
165     *
166     * @param listener  the object to deregister.
167     *
168     * @see #addChangeListener(DialLayerChangeListener)
169     */
170    @Override
171    public void removeChangeListener(DialLayerChangeListener listener) {
172        this.listenerList.remove(DialLayerChangeListener.class, listener);
173    }
174
175    /**
176     * Returns <code>true</code> if the specified object is registered with
177     * the dataset as a listener.  Most applications won't need to call this
178     * method, it exists mainly for use by unit testing code.
179     *
180     * @param listener  the listener.
181     *
182     * @return A boolean.
183     */
184    @Override
185    public boolean hasListener(EventListener listener) {
186        List list = Arrays.asList(this.listenerList.getListenerList());
187        return list.contains(listener);
188    }
189
190    /**
191     * Notifies all registered listeners that the dial layer has changed.
192     * The {@link DialLayerChangeEvent} provides information about the change.
193     *
194     * @param event  information about the change to the axis.
195     */
196    protected void notifyListeners(DialLayerChangeEvent event) {
197        Object[] listeners = this.listenerList.getListenerList();
198        for (int i = listeners.length - 2; i >= 0; i -= 2) {
199            if (listeners[i] == DialLayerChangeListener.class) {
200                ((DialLayerChangeListener) listeners[i + 1]).dialLayerChanged(
201                        event);
202            }
203        }
204    }
205
206    /**
207     * Provides serialization support.
208     *
209     * @param stream  the input stream.
210     *
211     * @throws IOException  if there is an I/O error.
212     * @throws ClassNotFoundException  if there is a classpath problem.
213     */
214    private void readObject(ObjectInputStream stream)
215        throws IOException, ClassNotFoundException {
216        stream.defaultReadObject();
217        this.listenerList = new EventListenerList();
218    }
219
220}