001/* ===========================================================
002 * Orson Charts : a 3D chart library for the Java(tm) platform
003 * ===========================================================
004 * 
005 * (C)opyright 2013-2022, by David Gilbert.  All rights reserved.
006 * 
007 * https://github.com/jfree/orson-charts
008 * 
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as published by
011 * the Free Software Foundation, either version 3 of the License, or
012 * (at your option) any later version.
013 *
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
021 * 
022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
023 * Other names may be trademarks of their respective owners.]
024 * 
025 * If you do not wish to be bound by the terms of the GPL, an alternative
026 * commercial license can be purchased.  For details, please see visit the
027 * Orson Charts home page:
028 * 
029 * http://www.object-refinery.com/orsoncharts/index.html
030 * 
031 */
032
033package org.jfree.chart3d.renderer;
034
035import java.awt.Color;
036import java.awt.Font;
037import java.io.Serializable;
038import javax.swing.event.EventListenerList;
039
040import org.jfree.chart3d.ChartElementVisitor;
041import org.jfree.chart3d.internal.Args;
042import org.jfree.chart3d.label.ItemLabelPositioning;
043
044/**
045 * A base class for 3D renderers.
046 */
047public abstract class AbstractRenderer3D implements Renderer3D, Serializable {
048    
049    /** The font used to draw item labels. */
050    private Font itemLabelFont;
051    
052    /** The foreground color for item labels. */
053    private Color itemLabelColor;
054    
055    /** The background color for item labels. */
056    private Color itemLabelBackgroundColor;
057    
058    /** The item label positioning. */
059    private ItemLabelPositioning itemLabelPositioning;
060
061    /** Storage for registered change listeners. */
062    private final transient EventListenerList listenerList;
063
064    /**
065     * A flag that controls whether or not the renderer will notify listeners
066     * of changes (defaults to {@code true}, but sometimes it is useful 
067     * to disable this).
068     */
069    private boolean notify;
070
071    /**
072     * Default constructor.
073     */
074    protected AbstractRenderer3D() {
075        this.itemLabelFont = new Font(Font.SERIF, Font.PLAIN, 12);
076        this.itemLabelColor = Color.WHITE;
077        this.itemLabelBackgroundColor = new Color(100, 100, 100, 100); //Renderer3D.TRANSPARENT_COLOR;
078        this.itemLabelPositioning = ItemLabelPositioning.CENTRAL;
079        this.listenerList = new EventListenerList();
080        this.notify = true;
081    }
082
083    /**
084     * Returns the font used to display item labels, if there are any.
085     * The default value is {@code Font(Font.SERIF, Font.PLAIN, 8)}.
086     * 
087     * @return The font (never {@code null}).
088     * 
089     * @since 1.3
090     */
091    public Font getItemLabelFont() {
092        return itemLabelFont;
093    }
094
095    /**
096     * Sets the font used to display item labels and sends a change event
097     * to all registered listeners.
098     * 
099     * @param itemLabelFont  the font ({@code null} not permitted).
100     * 
101     * @since 1.3
102     */
103    public void setItemLabelFont(Font itemLabelFont) {
104        Args.nullNotPermitted(itemLabelFont, "itemLabelFont");
105        this.itemLabelFont = itemLabelFont;
106        fireChangeEvent(true);
107    }
108
109    /**
110     * Returns the foreground color used to display item labels.  The default
111     * value is {@code Color.BLACK}.
112     * 
113     * @return The foreground color (never {@code null}).
114     * 
115     * @since 1.3
116     */
117    public Color getItemLabelColor() {
118        return itemLabelColor;
119    }
120
121    /**
122     * Sets the foreground color used to display item labels and sends a 
123     * change event to all registered listeners.
124     * 
125     * @param itemLabelColor  the new color ({@code null} not permitted).
126     * 
127     * @since 1.3
128     */
129    public void setItemLabelColor(Color itemLabelColor) {
130        Args.nullNotPermitted(itemLabelColor, "itemLabelColor");
131        this.itemLabelColor = itemLabelColor;
132        fireChangeEvent(true);
133    }
134
135    /**
136     * Returns the background color for item labels.
137     * 
138     * @return The background color (never {@code null}).
139     * 
140     * @since 1.3
141     */
142    public Color getItemLabelBackgroundColor() {
143        return itemLabelBackgroundColor;
144    }
145
146    /**
147     * Sets the background color and sends a change event to all registered
148     * listeners.
149     * 
150     * @param color  the new color ({@code null} not permitted).
151     * 
152     * @since 1.3
153     */
154    public void setItemLabelBackgroundColor(Color color) {
155        Args.nullNotPermitted(color, "color");
156        this.itemLabelBackgroundColor = color ;
157        fireChangeEvent(true);
158    }
159
160    /**
161     * Returns the item label positioning.  The default value is 
162     * {@link ItemLabelPositioning#CENTRAL}.
163     * 
164     * @return The item label positioning (never {@code null}).
165     * 
166     * @since 1.3
167     */
168    public ItemLabelPositioning getItemLabelPositioning() {
169        return itemLabelPositioning;
170    }
171
172    /**
173     * Sets the item label positioning and sends a change event to all 
174     * registered listeners.
175     * 
176     * @param positioning  the new positioning ({@code null} not 
177     *     permitted).
178     * 
179     * @since 1.3
180     */
181    public void setItemLabelPositioning(ItemLabelPositioning positioning) {
182        Args.nullNotPermitted(positioning, "positioning");
183        this.itemLabelPositioning = positioning;
184        fireChangeEvent(true);
185    }
186
187    /**
188     * Returns a flag that controls whether or not change events are sent to
189     * registered listeners.
190     *
191     * @return A boolean.
192     *
193     * @see #setNotify(boolean)
194     */
195    public boolean isNotify() {
196        return this.notify;
197    }
198
199    /**
200     * Sets a flag that controls whether or not listeners receive
201     * {@link Renderer3DChangeEvent} notifications.
202     *
203     * @param notify  a boolean.
204     *
205     * @see #isNotify()
206     */
207    public void setNotify(boolean notify) {
208        this.notify = notify;
209        // if the flag is being set to true, there may be queued up changes...
210        if (notify) {
211            fireChangeEvent(true);
212        }
213    }
214    
215    /**
216     * Receives a {@link ChartElementVisitor}.  This is part of a general 
217     * purpose mechanism for traversing the chart structure and performing 
218     * operations on the elements in the structure.  You won't normally call
219     * this method directly.
220     * 
221     * @param visitor  the visitor ({@code null} not permitted).
222     * 
223     * @since 1.2
224     */
225    @Override
226    public void receive(ChartElementVisitor visitor) {
227        visitor.visit(this);
228    }
229
230    /**
231     * Registers an object for notification of changes to the renderer.
232     *
233     * @param listener  the object to be registered.
234     *
235     * @see #removeChangeListener(Renderer3DChangeListener)
236     */
237    @Override
238    public void addChangeListener(Renderer3DChangeListener listener) {
239        this.listenerList.add(Renderer3DChangeListener.class, listener);
240    }
241
242    /**
243     * Unregisters an object for notification of changes to the renderer.
244     *
245     * @param listener  the object to be unregistered.
246     *
247     * @see #addChangeListener(Renderer3DChangeListener) 
248     */
249    @Override
250    public void removeChangeListener(Renderer3DChangeListener listener) {
251        this.listenerList.remove(Renderer3DChangeListener.class, listener);
252    }
253
254    /**
255     * Notifies all registered listeners that the plot has been modified.
256     *
257     * @param event  information about the change event.
258     */
259    public void notifyListeners(Renderer3DChangeEvent event) {
260        // if the 'notify' flag has been switched to false, we don't notify
261        // the listeners
262        if (!this.notify) {
263            return;
264        }
265        Object[] listeners = this.listenerList.getListenerList();
266        for (int i = listeners.length - 2; i >= 0; i -= 2) {
267            if (listeners[i] == Renderer3DChangeListener.class) { 
268                ((Renderer3DChangeListener) listeners[i + 1]).rendererChanged(
269                        event);
270            }
271        }
272    }
273
274    /**
275     * Sends a {@link Renderer3DChangeEvent} to all registered listeners.
276     * 
277     * @param requiresWorldUpdate  a flag indicating whether or not the change
278     *     requires the 3D world to be updated.
279     */
280    protected void fireChangeEvent(boolean requiresWorldUpdate) {
281        notifyListeners(new Renderer3DChangeEvent(this, requiresWorldUpdate));
282    }
283
284    /**
285     * Tests this renderer for equality with an arbitrary object.  The 
286     * change listeners are NOT considered in the test, but the 
287     * {@code notify} flag is taken into account.
288     * 
289     * @param obj  the object ({@code null} permitted).
290     * 
291     * @return A boolean. 
292     */
293    @Override
294    public boolean equals(Object obj) {
295        if (obj == this) {
296            return true;
297        }
298        if (!(obj instanceof AbstractRenderer3D)) {
299            return false;
300        }
301        AbstractRenderer3D that = (AbstractRenderer3D) obj;
302        if (this.notify != that.notify) {
303            return false;
304        }
305        if (!this.itemLabelFont.equals(that.itemLabelFont)) {
306            return false;
307        }
308        if (!this.itemLabelColor.equals(that.itemLabelColor)) {
309            return false;
310        }
311        if (!this.itemLabelBackgroundColor.equals(
312                that.itemLabelBackgroundColor)) {
313            return false;
314        }
315        if (this.itemLabelPositioning != that.itemLabelPositioning) {
316            return false;
317        }
318        return true;
319    }
320}