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