/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2014, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * --------------------- * AbstractRenderer.java * --------------------- * (C) Copyright 2002-2014, by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited); * Contributor(s): Nicolas Brodu; * Michael Zinsmaier; * * Changes: * -------- * 22-Aug-2002 : Version 1, draws code out of AbstractXYItemRenderer to share * with AbstractCategoryItemRenderer (DG); * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG); * 06-Nov-2002 : Moved to the com.jrefinery.chart.renderer package (DG); * 21-Nov-2002 : Added a paint table for the renderer to use (DG); * 17-Jan-2003 : Moved plot classes into a separate package (DG); * 25-Mar-2003 : Implemented Serializable (DG); * 29-Apr-2003 : Added valueLabelFont and valueLabelPaint attributes, based on * code from Arnaud Lelievre (DG); * 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG); * 13-Aug-2003 : Implemented Cloneable (DG); * 15-Sep-2003 : Fixed serialization (NB); * 17-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); * 07-Oct-2003 : Moved PlotRenderingInfo into RendererState to allow for * multiple threads using a single renderer (DG); * 20-Oct-2003 : Added missing setOutlinePaint() method (DG); * 23-Oct-2003 : Split item label attributes into 'positive' and 'negative' * values (DG); * 26-Nov-2003 : Added methods to get the positive and negative item label * positions (DG); * 01-Mar-2004 : Modified readObject() method to prevent null pointer exceptions * after deserialization (DG); * 19-Jul-2004 : Fixed bug in getItemLabelFont(int, int) method (DG); * 04-Oct-2004 : Updated equals() method, eliminated use of NumberUtils, * renamed BooleanUtils --> BooleanUtilities, ShapeUtils --> * ShapeUtilities (DG); * 15-Mar-2005 : Fixed serialization of baseFillPaint (DG); * 16-May-2005 : Base outline stroke should never be null (DG); * 01-Jun-2005 : Added hasListener() method for unit testing (DG); * 08-Jun-2005 : Fixed equals() method to handle GradientPaint (DG); * ------------- JFREECHART 1.0.x --------------------------------------------- * 02-Feb-2007 : Minor API doc update (DG); * 19-Feb-2007 : Fixes for clone() method (DG); * 28-Feb-2007 : Use cached event to signal changes (DG); * 19-Apr-2007 : Deprecated seriesVisible and seriesVisibleInLegend flags (DG); * 20-Apr-2007 : Deprecated paint, fillPaint, outlinePaint, stroke, * outlineStroke, shape, itemLabelsVisible, itemLabelFont, * itemLabelPaint, positiveItemLabelPosition, * negativeItemLabelPosition and createEntities override * fields (DG); * 13-Jun-2007 : Added new autoPopulate flags for core series attributes (DG); * 23-Oct-2007 : Updated lookup methods to better handle overridden * methods (DG); * 04-Dec-2007 : Modified hashCode() implementation (DG); * 29-Apr-2008 : Minor API doc update (DG); * 17-Jun-2008 : Added legendShape, legendTextFont and legendTextPaint * attributes (DG); * 18-Aug-2008 : Added clearSeriesPaints() and clearSeriesStrokes() (DG); * 28-Jan-2009 : Equals method doesn't test Shape equality correctly (DG); * 27-Mar-2009 : Added dataBoundsIncludesVisibleSeriesOnly attribute, and * updated renderer events for series visibility changes (DG); * 01-Apr-2009 : Factored up the defaultEntityRadius field from the * AbstractXYItemRenderer class (DG); * 28-Apr-2009 : Added flag to allow a renderer to treat the legend shape as * a line (DG); * */ package org.jfree.chart.renderer; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; import java.util.EventListener; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.event.EventListenerList; import org.jfree.chart.util.HashUtils; import org.jfree.chart.ui.TextAnchor; import org.jfree.chart.util.BooleanList; import org.jfree.chart.util.ObjectUtils; import org.jfree.chart.util.PaintUtils; import org.jfree.chart.util.ShapeList; import org.jfree.chart.util.ShapeUtils; import org.jfree.chart.util.StrokeList; import org.jfree.chart.event.RendererChangeEvent; import org.jfree.chart.event.RendererChangeListener; import org.jfree.chart.labels.ItemLabelAnchor; import org.jfree.chart.labels.ItemLabelPosition; import org.jfree.chart.plot.DrawingSupplier; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.item.DefaultLabelIRS; import org.jfree.chart.renderer.item.DefaultPaintIRS; import org.jfree.chart.renderer.item.DefaultShapeIRS; import org.jfree.chart.renderer.item.DefaultStrokeIRS; import org.jfree.chart.renderer.item.DefaultVisibilityIRS; import org.jfree.chart.renderer.item.LabelIRS; import org.jfree.chart.renderer.item.PaintIRS; import org.jfree.chart.renderer.item.ShapeIRS; import org.jfree.chart.renderer.item.StrokeIRS; import org.jfree.chart.renderer.item.VisibilityIRS; import org.jfree.chart.title.LegendTitle; import org.jfree.chart.util.ParamChecks; import org.jfree.chart.util.SerialUtils; /** * Base class providing common services for renderers. Most methods that update * attributes of the renderer will fire a {@link RendererChangeEvent}, which * normally means the plot that owns the renderer will receive notification that * the renderer has been changed (the plot will, in turn, notify the chart). */ public abstract class AbstractRenderer implements Cloneable, Serializable { /** For serialization. */ private static final long serialVersionUID = -828267569428206075L; /** Zero represented as a <code>Double</code>. */ public static final Double ZERO = 0.0; /** The default paint. */ public static final Paint DEFAULT_PAINT = Color.BLUE; /** The default outline paint. */ public static final Paint DEFAULT_OUTLINE_PAINT = Color.GRAY; /** The default stroke. */ public static final Stroke DEFAULT_STROKE = new BasicStroke(1.0f); /** The default outline stroke. */ public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke(1.0f); /** The default shape. */ public static final Shape DEFAULT_SHAPE = new Rectangle2D.Double(-3.0, -3.0, 6.0, 6.0); /** The default value label font. */ public static final Font DEFAULT_VALUE_LABEL_FONT = new Font("SansSerif", Font.PLAIN, 10); /** The default value label paint. */ public static final Paint DEFAULT_VALUE_LABEL_PAINT = Color.BLACK; /** * A hook that allows to control the rendering of individual item labels * (if the renderer uses {@link #getItemLabelFont(int, int)} ... ) */ private LabelIRS labelIRS = new DefaultLabelIRS(this); /** * A hook that allows to control the painting of individual items (if the * renderer uses {@link #getItemPaint(int, int)} ... ) */ private PaintIRS paintIRS = new DefaultPaintIRS(this); /** * A hook that allows to control the shape of individual items * (if the renderer uses {@link #getItemShape(int, int)} ... ) */ private ShapeIRS shapeIRS = new DefaultShapeIRS(this); /** * A hook that allows to use individual strokes for each item * (if the renderer uses {@link #getItemStroke(int, int)} ... ) */ private StrokeIRS strokeIRS = new DefaultStrokeIRS(this); /** * A hook that allows to control the visibility of individual items * (if the renderer uses {@link #getItemVisible(int, int)} ... ) */ private VisibilityIRS visibilityIRS = new DefaultVisibilityIRS(this); /** A list of flags that controls whether or not each series is visible. */ private BooleanList seriesVisibleList; /** The default visibility for all series. */ private boolean defaultSeriesVisible; /** * A list of flags that controls whether or not each series is visible in * the legend. */ private BooleanList seriesVisibleInLegendList; /** The default visibility for each series in the legend. */ private boolean defaultSeriesVisibleInLegend; /** * Storage for the paint assigned to each series (never <code>null</code>). */ private transient Map<Integer, Paint> paintMap; /** * A flag that controls whether or not the paintList is auto-populated * in the {@link #lookupSeriesPaint(int)} method. * * @since 1.0.6 */ private boolean autoPopulateSeriesPaint; /** The default paint, used when there is no paint assigned for a series. */ private transient Paint defaultPaint; /** Storage for the fill paint assigned to each series. */ private transient Map<Integer, Paint> fillPaintMap; /** * A flag that controls whether or not the fillPaintList is auto-populated * in the {@link #lookupSeriesFillPaint(int)} method. * * @since 1.0.6 */ private boolean autoPopulateSeriesFillPaint; /** The base fill paint. */ private transient Paint defaultFillPaint; /** Storage for the outline paint assigned to each series. */ private transient Map<Integer, Paint> outlinePaintMap; /** * A flag that controls whether or not the outlinePaintList is * auto-populated in the {@link #lookupSeriesOutlinePaint(int)} method. * * @since 1.0.6 */ private boolean autoPopulateSeriesOutlinePaint; /** The base outline paint. */ private transient Paint defaultOutlinePaint; /** The stroke list. */ private StrokeList strokeList; /** * A flag that controls whether or not the strokeList is auto-populated * in the {@link #lookupSeriesStroke(int)} method. * * @since 1.0.6 */ private boolean autoPopulateSeriesStroke; /** The base stroke. */ private transient Stroke defaultStroke; /** The outline stroke list. */ private StrokeList outlineStrokeList; /** The base outline stroke. */ private transient Stroke defaultOutlineStroke; /** * A flag that controls whether or not the outlineStrokeList is * auto-populated in the {@link #lookupSeriesOutlineStroke(int)} method. * * @since 1.0.6 */ private boolean autoPopulateSeriesOutlineStroke; /** A shape list. */ private ShapeList shapeList; /** * A flag that controls whether or not the shapeList is auto-populated * in the {@link #lookupSeriesShape(int)} method. * * @since 1.0.6 */ private boolean autoPopulateSeriesShape; /** The base shape. */ private transient Shape defaultShape; /** Visibility of the item labels PER series. */ private BooleanList itemLabelsVisibleList; /** The base item labels visible. */ private Boolean defaultItemLabelsVisible; /** The item label font list (one font per series). */ private Map<Integer, Font> itemLabelFontMap; /** The base item label font. */ private Font defaultItemLabelFont; /** The item label paint list (one paint per series). */ private transient Map<Integer, Paint> itemLabelPaintMap; /** The base item label paint. */ private transient Paint defaultItemLabelPaint; /** The positive item label position (per series). */ private Map<Integer, ItemLabelPosition> positiveItemLabelPositionMap; /** The fallback positive item label position. */ private ItemLabelPosition defaultPositiveItemLabelPosition; /** The negative item label position (per series). */ private Map<Integer, ItemLabelPosition> negativeItemLabelPositionMap; /** The fallback negative item label position. */ private ItemLabelPosition defaultNegativeItemLabelPosition; /** The item label anchor offset. */ private double itemLabelAnchorOffset = 2.0; /** * Flags that control whether or not entities are generated for each * series. This will be overridden by 'createEntities'. */ private BooleanList createEntitiesList; /** * The default flag that controls whether or not entities are generated. * This flag is used when both the above flags return null. */ private boolean defaultCreateEntities; /** * The per-series legend shape settings. * * @since 1.0.11 */ private ShapeList legendShapeList; /** * The base shape for legend items. If this is <code>null</code>, the * series shape will be used. * * @since 1.0.11 */ private transient Shape defaultLegendShape; /** * A special flag that, if true, will cause the getLegendItem() method * to configure the legend shape as if it were a line. * * @since 1.0.14 */ private boolean treatLegendShapeAsLine; /** * The per-series legend text font. * * @since 1.0.11 */ private Map<Integer, Font> legendTextFontMap; /** * The base legend font. * * @since 1.0.11 */ private Font defaultLegendTextFont; /** * The per series legend text paint settings. * * @since 1.0.11 */ private transient Map<Integer, Paint> legendTextPaintMap; /** * The default paint for the legend text items (if this is * <code>null</code>, the {@link LegendTitle} class will determine the * text paint to use. * * @since 1.0.11 */ private transient Paint defaultLegendTextPaint; /** * A flag that controls whether or not the renderer will include the * non-visible series when calculating the data bounds. * * @since 1.0.13 */ private boolean dataBoundsIncludesVisibleSeriesOnly = true; /** The default radius for the entity 'hotspot' */ private int defaultEntityRadius; /** Storage for registered change listeners. */ private transient EventListenerList listenerList; /** An event for re-use. */ private transient RendererChangeEvent event; /** * Default constructor. */ public AbstractRenderer() { this.seriesVisibleList = new BooleanList(); this.defaultSeriesVisible = true; this.seriesVisibleInLegendList = new BooleanList(); this.defaultSeriesVisibleInLegend = true; this.paintMap = new HashMap<Integer, Paint>(); this.defaultPaint = DEFAULT_PAINT; this.autoPopulateSeriesPaint = true; this.fillPaintMap = new HashMap<Integer, Paint>(); this.defaultFillPaint = Color.WHITE; this.autoPopulateSeriesFillPaint = false; this.outlinePaintMap = new HashMap<Integer, Paint>(); this.defaultOutlinePaint = DEFAULT_OUTLINE_PAINT; this.autoPopulateSeriesOutlinePaint = false; this.strokeList = new StrokeList(); this.defaultStroke = DEFAULT_STROKE; this.autoPopulateSeriesStroke = true; this.outlineStrokeList = new StrokeList(); this.defaultOutlineStroke = DEFAULT_OUTLINE_STROKE; this.autoPopulateSeriesOutlineStroke = false; this.shapeList = new ShapeList(); this.defaultShape = DEFAULT_SHAPE; this.autoPopulateSeriesShape = true; this.itemLabelsVisibleList = new BooleanList(); this.defaultItemLabelsVisible = Boolean.FALSE; this.itemLabelFontMap = new HashMap<Integer, Font>(); this.defaultItemLabelFont = new Font("SansSerif", Font.PLAIN, 10); this.itemLabelPaintMap = new HashMap<Integer, Paint>(); this.defaultItemLabelPaint = Color.BLACK; this.positiveItemLabelPositionMap = new HashMap<Integer, ItemLabelPosition>(); this.defaultPositiveItemLabelPosition = new ItemLabelPosition( ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER); this.negativeItemLabelPositionMap = new HashMap<Integer, ItemLabelPosition>(); this.defaultNegativeItemLabelPosition = new ItemLabelPosition( ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER); this.createEntitiesList = new BooleanList(); this.defaultCreateEntities = true; this.defaultEntityRadius = 3; this.legendShapeList = new ShapeList(); this.defaultLegendShape = null; this.treatLegendShapeAsLine = false; this.legendTextFontMap = new HashMap<Integer, Font>(); this.defaultLegendTextFont = new Font("Dialog", Font.PLAIN, 12); this.legendTextPaintMap = new HashMap<Integer, Paint>(); this.defaultLegendTextPaint = null; this.listenerList = new EventListenerList(); } /** * Returns the drawing supplier from the plot. * * @return The drawing supplier. */ public abstract DrawingSupplier getDrawingSupplier(); // SETTER FOR ITEM RENDERING STRATEGIES /** * @param labelIRS {@link #labelIRS} (<code>null</code> not permitted) */ public void setLabelIRS(LabelIRS labelIRS) { ParamChecks.nullNotPermitted(labelIRS, "labelIRS"); this.labelIRS = labelIRS; } /** * @param paintIRS {@link #paintIRS} (<code>null</code> not permitted) */ public void setPaintIRS(PaintIRS paintIRS) { ParamChecks.nullNotPermitted(paintIRS, "paintIRS"); this.paintIRS = paintIRS; } /** * @param shapeIRS {@link #shapeIRS} (<code>null</code> not permitted) */ public void setShapeIRS(ShapeIRS shapeIRS) { ParamChecks.nullNotPermitted(shapeIRS, "shapeIRS"); this.shapeIRS = shapeIRS; } /** * @param strokeIRS {@link #strokeIRS} (<code>null</code> not permitted) */ public void setStrokeIRS(StrokeIRS strokeIRS) { ParamChecks.nullNotPermitted(strokeIRS, "strokeIRS"); this.strokeIRS = strokeIRS; } /** * @param visibilityIRS {@link #visibilityIRS} (<code>null</code> not * permitted) */ public void setVisibilityIRS(VisibilityIRS visibilityIRS) { ParamChecks.nullNotPermitted(visibilityIRS, null); this.visibilityIRS = visibilityIRS; } // SERIES VISIBLE (not yet respected by all renderers) /** * Returns a boolean that indicates whether or not the specified item * should be drawn (this is typically used to hide an entire series). * <p> * The default implementation passes control to the * {@link DefaultVisibilityIRS} which uses the * <code>isSeriesVisible(series)</code> method. You can implement your * own {@link VisibilityIRS} or override this method if you require * different behavior. * * @param series the series index. * @param item the column (or category) index (zero-based). * * @return The item visibility */ public boolean getItemVisible(int series, int item) { return visibilityIRS.getItemVisible(series, item); } /** * Returns a boolean that indicates whether or not the specified series * should be drawn. * * @param series the series index. * * @return A boolean. */ public boolean isSeriesVisible(int series) { boolean result = this.defaultSeriesVisible; Boolean b = this.seriesVisibleList.getBoolean(series); if (b != null) { result = b; } return result; } /** * Returns the flag that controls whether a series is visible. * * @param series the series index (zero-based). * * @return The flag (possibly <code>null</code>). * * @see #setSeriesVisible(int, Boolean) */ public Boolean getSeriesVisible(int series) { return this.seriesVisibleList.getBoolean(series); } /** * Sets the flag that controls whether a series is visible and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param visible the flag (<code>null</code> permitted). * * @see #getSeriesVisible(int) */ public void setSeriesVisible(int series, Boolean visible) { setSeriesVisible(series, visible, true); } /** * Sets the flag that controls whether a series is visible and, if * requested, sends a {@link RendererChangeEvent} to all registered * listeners. * * @param series the series index. * @param visible the flag (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesVisible(int) */ public void setSeriesVisible(int series, Boolean visible, boolean notify) { this.seriesVisibleList.setBoolean(series, visible); if (notify) { // we create an event with a special flag set...the purpose of // this is to communicate to the plot (the default receiver of // the event) that series visibility has changed so the axis // ranges might need updating... RendererChangeEvent e = new RendererChangeEvent(this, true); notifyListeners(e); } } /** * Returns the default visibility for all series. * * @return The default visibility. * * @see #setDefaultSeriesVisible(boolean) */ public boolean getDefaultSeriesVisible() { return this.defaultSeriesVisible; } /** * Sets the default series visibility and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param visible the flag. * * @see #getDefaultSeriesVisible() */ public void setDefaultSeriesVisible(boolean visible) { // defer argument checking... setDefaultSeriesVisible(visible, true); } /** * Sets the default series visibility and, if requested, sends * a {@link RendererChangeEvent} to all registered listeners. * * @param visible the visibility. * @param notify notify listeners? * * @see #getDefaultSeriesVisible() */ public void setDefaultSeriesVisible(boolean visible, boolean notify) { this.defaultSeriesVisible = visible; if (notify) { // we create an event with a special flag set...the purpose of // this is to communicate to the plot (the default receiver of // the event) that series visibility has changed so the axis // ranges might need updating... RendererChangeEvent e = new RendererChangeEvent(this, true); notifyListeners(e); } } // SERIES VISIBLE IN LEGEND (not yet respected by all renderers) /** * Returns <code>true</code> if the series should be shown in the legend, * and <code>false</code> otherwise. * * @param series the series index. * * @return A boolean. */ public boolean isSeriesVisibleInLegend(int series) { boolean result = this.defaultSeriesVisibleInLegend; Boolean b = this.seriesVisibleInLegendList.getBoolean(series); if (b != null) { result = b; } return result; } /** * Returns the flag that controls whether a series is visible in the * legend. This method returns only the "per series" settings - to * incorporate the default settings as well, you need to use the * {@link #isSeriesVisibleInLegend(int)} method. * * @param series the series index (zero-based). * * @return The flag (possibly <code>null</code>). * * @see #setSeriesVisibleInLegend(int, Boolean) */ public Boolean getSeriesVisibleInLegend(int series) { return this.seriesVisibleInLegendList.getBoolean(series); } /** * Sets the flag that controls whether a series is visible in the legend * and sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param visible the flag (<code>null</code> permitted). * * @see #getSeriesVisibleInLegend(int) */ public void setSeriesVisibleInLegend(int series, Boolean visible) { setSeriesVisibleInLegend(series, visible, true); } /** * Sets the flag that controls whether a series is visible in the legend * and, if requested, sends a {@link RendererChangeEvent} to all registered * listeners. * * @param series the series index. * @param visible the flag (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesVisibleInLegend(int) */ public void setSeriesVisibleInLegend(int series, Boolean visible, boolean notify) { this.seriesVisibleInLegendList.setBoolean(series, visible); if (notify) { fireChangeEvent(); } } /** * Returns the default visibility in the legend for all series. * * @return The default visibility. * * @see #setDefaultSeriesVisibleInLegend(boolean) */ public boolean getDefaultSeriesVisibleInLegend() { return this.defaultSeriesVisibleInLegend; } /** * Sets the default visibility in the legend and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param visible the flag. * * @see #getDefaultSeriesVisibleInLegend() */ public void setDefaultSeriesVisibleInLegend(boolean visible) { // defer argument checking... setDefaultSeriesVisibleInLegend(visible, true); } /** * Sets the default visibility in the legend and, if requested, sends * a {@link RendererChangeEvent} to all registered listeners. * * @param visible the visibility. * @param notify notify listeners? * * @see #getDefaultSeriesVisibleInLegend() */ public void setDefaultSeriesVisibleInLegend(boolean visible, boolean notify) { this.defaultSeriesVisibleInLegend = visible; if (notify) { fireChangeEvent(); } } // PAINT /** * Returns the paint used to fill data items as they are drawn. * (this is typically the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultPaintIRS} * which uses the <code>lookupSeriesPaint(row)</code> method. You can * implement your own {@link PaintIRS} or override this method if you * require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The paint (never <code>null</code>). */ public Paint getItemPaint(int row, int column) { return paintIRS.getItemPaint(row, column); } /** * Returns the paint used to fill an item drawn by the renderer. * * @param series the series index (zero-based). * * @return The paint (never <code>null</code>). * * @since 1.0.6 */ public Paint lookupSeriesPaint(int series) { Paint seriesPaint = getSeriesPaint(series); if (seriesPaint == null && this.autoPopulateSeriesPaint) { DrawingSupplier supplier = getDrawingSupplier(); if (supplier != null) { seriesPaint = supplier.getNextPaint(); setSeriesPaint(series, seriesPaint, false); } } if (seriesPaint == null) { seriesPaint = this.defaultPaint; } return seriesPaint; } /** * Returns the paint used to fill an item drawn by the renderer. * * @param series the series index (zero-based). * * @return The paint (possibly <code>null</code>). * * @see #setSeriesPaint(int, Paint) */ public Paint getSeriesPaint(int series) { return this.paintMap.get(series); } /** * Sets the paint used for a series and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param series the series index (zero-based). * @param paint the paint (<code>null</code> permitted). * * @see #getSeriesPaint(int) */ public void setSeriesPaint(int series, Paint paint) { setSeriesPaint(series, paint, true); } /** * Sets the paint used for a series and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index. * @param paint the paint (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesPaint(int) */ public void setSeriesPaint(int series, Paint paint, boolean notify) { this.paintMap.put(series, paint); if (notify) { fireChangeEvent(); } } /** * Clears the series paint settings for this renderer and, if requested, * sends a {@link RendererChangeEvent} to all registered listeners. * * @param notify notify listeners? * * @since 1.0.11 */ public void clearSeriesPaints(boolean notify) { this.paintMap.clear(); if (notify) { fireChangeEvent(); } } /** * Returns the default paint. * * @return The default paint (never <code>null</code>). * * @see #setDefaultPaint(Paint) */ public Paint getDefaultPaint() { return this.defaultPaint; } /** * Sets the default paint and sends a {@link RendererChangeEvent} to all * registered listeners. * * @param paint the paint (<code>null</code> not permitted). * * @see #getDefaultPaint() */ public void setDefaultPaint(Paint paint) { // defer argument checking... setDefaultPaint(paint, true); } /** * Sets the default paint and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param paint the paint (<code>null</code> not permitted). * @param notify notify listeners? * * @see #getDefaultPaint() */ public void setDefaultPaint(Paint paint, boolean notify) { this.defaultPaint = paint; if (notify) { fireChangeEvent(); } } /** * Returns the flag that controls whether or not the series paint list is * automatically populated when {@link #lookupSeriesPaint(int)} is called. * * @return A boolean. * * @since 1.0.6 * * @see #setAutoPopulateSeriesPaint(boolean) */ public boolean getAutoPopulateSeriesPaint() { return this.autoPopulateSeriesPaint; } /** * Sets the flag that controls whether or not the series paint list is * automatically populated when {@link #lookupSeriesPaint(int)} is called. * * @param auto the new flag value. * * @since 1.0.6 * * @see #getAutoPopulateSeriesPaint() */ public void setAutoPopulateSeriesPaint(boolean auto) { this.autoPopulateSeriesPaint = auto; } //// FILL PAINT ////////////////////////////////////////////////////////// /** * Returns the paint used to fill data items as they are drawn. * (this is typically the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultPaintIRS} * which uses the <code>lookupSeriesFillPaint(row)</code> method. You can * implement your own {@link PaintIRS} or override this method if you * require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The paint (never <code>null</code>). */ public Paint getItemFillPaint(int row, int column) { return paintIRS.getItemFillPaint(row, column); } /** * Returns the paint used to fill an item drawn by the renderer. * * @param series the series (zero-based index). * * @return The paint (never <code>null</code>). * * @since 1.0.6 */ public Paint lookupSeriesFillPaint(int series) { Paint seriesFillPaint = getSeriesFillPaint(series); if (seriesFillPaint == null && this.autoPopulateSeriesFillPaint) { DrawingSupplier supplier = getDrawingSupplier(); if (supplier != null) { seriesFillPaint = supplier.getNextFillPaint(); setSeriesFillPaint(series, seriesFillPaint, false); } } if (seriesFillPaint == null) { seriesFillPaint = this.defaultFillPaint; } return seriesFillPaint; } /** * Returns the paint used to fill an item drawn by the renderer. * * @param series the series (zero-based index). * * @return The paint (never <code>null</code>). * * @see #setSeriesFillPaint(int, Paint) */ public Paint getSeriesFillPaint(int series) { return this.fillPaintMap.get(series); } /** * Sets the paint used for a series fill and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param paint the paint (<code>null</code> permitted). * * @see #getSeriesFillPaint(int) */ public void setSeriesFillPaint(int series, Paint paint) { setSeriesFillPaint(series, paint, true); } /** * Sets the paint used to fill a series and, if requested, * sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param paint the paint (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesFillPaint(int) */ public void setSeriesFillPaint(int series, Paint paint, boolean notify) { this.fillPaintMap.put(series, paint); if (notify) { fireChangeEvent(); } } /** * Returns the default fill paint. * * @return The paint (never <code>null</code>). * * @see #setDefaultFillPaint(Paint) */ public Paint getDefaultFillPaint() { return this.defaultFillPaint; } /** * Sets the default fill paint and sends a {@link RendererChangeEvent} to * all registered listeners. * * @param paint the paint (<code>null</code> not permitted). * * @see #getDefaultFillPaint() */ public void setDefaultFillPaint(Paint paint) { // defer argument checking... setDefaultFillPaint(paint, true); } /** * Sets the default fill paint and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param paint the paint (<code>null</code> not permitted). * @param notify notify listeners? * * @see #getDefaultFillPaint() */ public void setDefaultFillPaint(Paint paint, boolean notify) { ParamChecks.nullNotPermitted(paint, "paint"); this.defaultFillPaint = paint; if (notify) { fireChangeEvent(); } } /** * Returns the flag that controls whether or not the series fill paint list * is automatically populated when {@link #lookupSeriesFillPaint(int)} is * called. * * @return A boolean. * * @since 1.0.6 * * @see #setAutoPopulateSeriesFillPaint(boolean) */ public boolean getAutoPopulateSeriesFillPaint() { return this.autoPopulateSeriesFillPaint; } /** * Sets the flag that controls whether or not the series fill paint list is * automatically populated when {@link #lookupSeriesFillPaint(int)} is * called. * * @param auto the new flag value. * * @since 1.0.6 * * @see #getAutoPopulateSeriesFillPaint() */ public void setAutoPopulateSeriesFillPaint(boolean auto) { this.autoPopulateSeriesFillPaint = auto; } // OUTLINE PAINT ////////////////////////////////////////////////////////// /** * Returns the paint used to outline data items as they are drawn. * (this is typically the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultPaintIRS} * which uses the <code>return lookupSeriesOutlinePaint(row)</code> method. * You can implement your own {@link PaintIRS} or override this method if * you require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The paint (never <code>null</code>). */ public Paint getItemOutlinePaint(int row, int column) { return paintIRS.getItemOutlinePaint(row, column); } /** * Returns the paint used to outline an item drawn by the renderer. * * @param series the series (zero-based index). * * @return The paint (never <code>null</code>). * * @since 1.0.6 */ public Paint lookupSeriesOutlinePaint(int series) { Paint seriesOutlinePaint = getSeriesOutlinePaint(series); if (seriesOutlinePaint == null && this.autoPopulateSeriesOutlinePaint) { DrawingSupplier supplier = getDrawingSupplier(); if (supplier != null) { seriesOutlinePaint = supplier.getNextOutlinePaint(); setSeriesOutlinePaint(series, seriesOutlinePaint, false); } } if (seriesOutlinePaint == null) { seriesOutlinePaint = this.defaultOutlinePaint; } return seriesOutlinePaint; } /** * Returns the paint used to outline an item drawn by the renderer. * * @param series the series (zero-based index). * * @return The paint (possibly <code>null</code>). * * @see #setSeriesOutlinePaint(int, Paint) */ public Paint getSeriesOutlinePaint(int series) { return this.outlinePaintMap.get(series); } /** * Sets the paint used for a series outline and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param paint the paint (<code>null</code> permitted). * * @see #getSeriesOutlinePaint(int) */ public void setSeriesOutlinePaint(int series, Paint paint) { setSeriesOutlinePaint(series, paint, true); } /** * Sets the paint used to draw the outline for a series and, if requested, * sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param paint the paint (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesOutlinePaint(int) */ public void setSeriesOutlinePaint(int series, Paint paint, boolean notify) { this.outlinePaintMap.put(series, paint); if (notify) { fireChangeEvent(); } } /** * Returns the default outline paint. * * @return The paint (never <code>null</code>). * * @see #setDefaultOutlinePaint(Paint) */ public Paint getDefaultOutlinePaint() { return this.defaultOutlinePaint; } /** * Sets the default outline paint and sends a {@link RendererChangeEvent} to * all registered listeners. * * @param paint the paint (<code>null</code> not permitted). * * @see #getDefaultOutlinePaint() */ public void setDefaultOutlinePaint(Paint paint) { // defer argument checking... setDefaultOutlinePaint(paint, true); } /** * Sets the default outline paint and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param paint the paint (<code>null</code> not permitted). * @param notify notify listeners? * * @see #getDefaultOutlinePaint() */ public void setDefaultOutlinePaint(Paint paint, boolean notify) { ParamChecks.nullNotPermitted(paint, "paint"); this.defaultOutlinePaint = paint; if (notify) { fireChangeEvent(); } } /** * Returns the flag that controls whether or not the series outline paint * list is automatically populated when * {@link #lookupSeriesOutlinePaint(int)} is called. * * @return A boolean. * * @since 1.0.6 * * @see #setAutoPopulateSeriesOutlinePaint(boolean) */ public boolean getAutoPopulateSeriesOutlinePaint() { return this.autoPopulateSeriesOutlinePaint; } /** * Sets the flag that controls whether or not the series outline paint list * is automatically populated when {@link #lookupSeriesOutlinePaint(int)} * is called. * * @param auto the new flag value. * * @since 1.0.6 * * @see #getAutoPopulateSeriesOutlinePaint() */ public void setAutoPopulateSeriesOutlinePaint(boolean auto) { this.autoPopulateSeriesOutlinePaint = auto; } // STROKE /** * Returns the stroke used to draw data items. * (this is typically the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultStrokeIRS} * which uses the <code>lookupSeriesStroke(row)</code> method. You can * implement your own {@link StrokeIRS} or override this method if you * require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The stroke (never <code>null</code>). */ public Stroke getItemStroke(int row, int column) { return strokeIRS.getItemStroke(row, column); } /** * Returns the stroke used to draw the items in a series. * * @param series the series (zero-based index). * * @return The stroke (never <code>null</code>). * * @since 1.0.6 */ public Stroke lookupSeriesStroke(int series) { Stroke result = getSeriesStroke(series); if (result == null && this.autoPopulateSeriesStroke) { DrawingSupplier supplier = getDrawingSupplier(); if (supplier != null) { result = supplier.getNextStroke(); setSeriesStroke(series, result, false); } } if (result == null) { result = this.defaultStroke; } return result; } /** * Returns the stroke used to draw the items in a series. * * @param series the series (zero-based index). * * @return The stroke (possibly <code>null</code>). * * @see #setSeriesStroke(int, Stroke) */ public Stroke getSeriesStroke(int series) { return this.strokeList.getStroke(series); } /** * Sets the stroke used for a series and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param series the series index (zero-based). * @param stroke the stroke (<code>null</code> permitted). * * @see #getSeriesStroke(int) */ public void setSeriesStroke(int series, Stroke stroke) { setSeriesStroke(series, stroke, true); } /** * Sets the stroke for a series and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param stroke the stroke (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesStroke(int) */ public void setSeriesStroke(int series, Stroke stroke, boolean notify) { this.strokeList.setStroke(series, stroke); if (notify) { fireChangeEvent(); } } /** * Clears the series stroke settings for this renderer and, if requested, * sends a {@link RendererChangeEvent} to all registered listeners. * * @param notify notify listeners? * * @since 1.0.11 */ public void clearSeriesStrokes(boolean notify) { this.strokeList.clear(); if (notify) { fireChangeEvent(); } } /** * Returns the default stroke. * * @return The default stroke (never <code>null</code>). * * @see #setDefaultStroke(Stroke) */ public Stroke getDefaultStroke() { return this.defaultStroke; } /** * Sets the default stroke and sends a {@link RendererChangeEvent} to all * registered listeners. * * @param stroke the stroke (<code>null</code> not permitted). * * @see #getDefaultStroke() */ public void setDefaultStroke(Stroke stroke) { // defer argument checking... setDefaultStroke(stroke, true); } /** * Sets the default stroke and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param stroke the stroke (<code>null</code> not permitted). * @param notify notify listeners? * * @see #getDefaultStroke() */ public void setDefaultStroke(Stroke stroke, boolean notify) { ParamChecks.nullNotPermitted(stroke, "stroke"); this.defaultStroke = stroke; if (notify) { fireChangeEvent(); } } /** * Returns the flag that controls whether or not the series stroke list is * automatically populated when {@link #lookupSeriesStroke(int)} is called. * * @return A boolean. * * @since 1.0.6 * * @see #setAutoPopulateSeriesStroke(boolean) */ public boolean getAutoPopulateSeriesStroke() { return this.autoPopulateSeriesStroke; } /** * Sets the flag that controls whether or not the series stroke list is * automatically populated when {@link #lookupSeriesStroke(int)} is called. * * @param auto the new flag value. * * @since 1.0.6 * * @see #getAutoPopulateSeriesStroke() */ public void setAutoPopulateSeriesStroke(boolean auto) { this.autoPopulateSeriesStroke = auto; } // OUTLINE STROKE /** * Returns the stroke used to outline data items * (this is typically the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultStrokeIRS} * which uses the <code>lookupSeriesOutlineStroke(row)</code> method. You * can implement your own {@link StrokeIRS} or override this method if you * require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The stroke (never <code>null</code>). */ public Stroke getItemOutlineStroke(int row, int column) { return strokeIRS.getItemOutlineStroke(row, column); } /** * Returns the stroke used to outline the items in a series. * * @param series the series (zero-based index). * * @return The stroke (never <code>null</code>). * * @since 1.0.6 */ public Stroke lookupSeriesOutlineStroke(int series) { Stroke result = getSeriesOutlineStroke(series); if (result == null && this.autoPopulateSeriesOutlineStroke) { DrawingSupplier supplier = getDrawingSupplier(); if (supplier != null) { result = supplier.getNextOutlineStroke(); setSeriesOutlineStroke(series, result, false); } } if (result == null) { result = this.defaultOutlineStroke; } return result; } /** * Returns the stroke used to outline the items in a series. * * @param series the series (zero-based index). * * @return The stroke (possibly <code>null</code>). * * @see #setSeriesOutlineStroke(int, Stroke) */ public Stroke getSeriesOutlineStroke(int series) { return this.outlineStrokeList.getStroke(series); } /** * Sets the outline stroke used for a series and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param stroke the stroke (<code>null</code> permitted). * * @see #getSeriesOutlineStroke(int) */ public void setSeriesOutlineStroke(int series, Stroke stroke) { setSeriesOutlineStroke(series, stroke, true); } /** * Sets the outline stroke for a series and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index. * @param stroke the stroke (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesOutlineStroke(int) */ public void setSeriesOutlineStroke(int series, Stroke stroke, boolean notify) { this.outlineStrokeList.setStroke(series, stroke); if (notify) { fireChangeEvent(); } } /** * Returns the default outline stroke. * * @return The stroke (never <code>null</code>). * * @see #setDefaultOutlineStroke(Stroke) */ public Stroke getDefaultOutlineStroke() { return this.defaultOutlineStroke; } /** * Sets the default outline stroke and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param stroke the stroke (<code>null</code> not permitted). * * @see #getDefaultOutlineStroke() */ public void setDefaultOutlineStroke(Stroke stroke) { setDefaultOutlineStroke(stroke, true); } /** * Sets the default outline stroke and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param stroke the stroke (<code>null</code> not permitted). * @param notify a flag that controls whether or not listeners are * notified. * * @see #getDefaultOutlineStroke() */ public void setDefaultOutlineStroke(Stroke stroke, boolean notify) { ParamChecks.nullNotPermitted(stroke, "stroke"); this.defaultOutlineStroke = stroke; if (notify) { fireChangeEvent(); } } /** * Returns the flag that controls whether or not the series outline stroke * list is automatically populated when * {@link #lookupSeriesOutlineStroke(int)} is called. * * @return A boolean. * * @since 1.0.6 * * @see #setAutoPopulateSeriesOutlineStroke(boolean) */ public boolean getAutoPopulateSeriesOutlineStroke() { return this.autoPopulateSeriesOutlineStroke; } /** * Sets the flag that controls whether or not the series outline stroke list * is automatically populated when {@link #lookupSeriesOutlineStroke(int)} * is called. * * @param auto the new flag value. * * @since 1.0.6 * * @see #getAutoPopulateSeriesOutlineStroke() */ public void setAutoPopulateSeriesOutlineStroke(boolean auto) { this.autoPopulateSeriesOutlineStroke = auto; } // SHAPE /** * Returns a shape used to represent a data item. * (this is typically the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultShapeIRS} * which uses the <code>lookupSeriesShape(row)</code> method. You can * implement your own {@link ShapeIRS} or override this method if you * require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The shape (never <code>null</code>). */ public Shape getItemShape(int row, int column) { return shapeIRS.getItemShape(row, column); } /** * Returns a shape used to represent the items in a series. * * @param series the series (zero-based index). * * @return The shape (never <code>null</code>). * * @since 1.0.6 */ public Shape lookupSeriesShape(int series) { Shape result = getSeriesShape(series); if (result == null && this.autoPopulateSeriesShape) { DrawingSupplier supplier = getDrawingSupplier(); if (supplier != null) { result = supplier.getNextShape(); setSeriesShape(series, result, false); } } if (result == null) { result = this.defaultShape; } return result; } /** * Returns a shape used to represent the items in a series. * * @param series the series (zero-based index). * * @return The shape (possibly <code>null</code>). * * @see #setSeriesShape(int, Shape) */ public Shape getSeriesShape(int series) { return this.shapeList.getShape(series); } /** * Sets the shape used for a series and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param series the series index (zero-based). * @param shape the shape (<code>null</code> permitted). * * @see #getSeriesShape(int) */ public void setSeriesShape(int series, Shape shape) { setSeriesShape(series, shape, true); } /** * Sets the shape for a series and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero based). * @param shape the shape (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesShape(int) */ public void setSeriesShape(int series, Shape shape, boolean notify) { this.shapeList.setShape(series, shape); if (notify) { fireChangeEvent(); } } /** * Returns the default shape. * * @return The shape (never <code>null</code>). * * @see #setDefaultShape(Shape) */ public Shape getDefaultShape() { return this.defaultShape; } /** * Sets the default shape and sends a {@link RendererChangeEvent} to all * registered listeners. * * @param shape the shape (<code>null</code> not permitted). * * @see #getDefaultShape() */ public void setDefaultShape(Shape shape) { // defer argument checking... setDefaultShape(shape, true); } /** * Sets the default shape and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param shape the shape (<code>null</code> not permitted). * @param notify notify listeners? * * @see #getDefaultShape() */ public void setDefaultShape(Shape shape, boolean notify) { ParamChecks.nullNotPermitted(shape, "shape"); this.defaultShape = shape; if (notify) { fireChangeEvent(); } } /** * Returns the flag that controls whether or not the series shape list is * automatically populated when {@link #lookupSeriesShape(int)} is called. * * @return A boolean. * * @since 1.0.6 * * @see #setAutoPopulateSeriesShape(boolean) */ public boolean getAutoPopulateSeriesShape() { return this.autoPopulateSeriesShape; } /** * Sets the flag that controls whether or not the series shape list is * automatically populated when {@link #lookupSeriesShape(int)} is called. * * @param auto the new flag value. * * @since 1.0.6 * * @see #getAutoPopulateSeriesShape() */ public void setAutoPopulateSeriesShape(boolean auto) { this.autoPopulateSeriesShape = auto; } // ITEM LABEL VISIBILITY... /** * Returns <code>true</code> if an item label is visible, and * <code>false</code> otherwise (this is typically the same for an entire * series). * <p> * The default implementation passes control to the * {@link DefaultVisibilityIRS} which uses the * <code>isSeriesItemLabelsVisible(row)</code> method. You can implement * your own {@link VisibilityIRS} or override this method if you require * different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return true if the item label is visible */ public boolean isItemLabelVisible(int row, int column) { return labelIRS.isItemLabelVisible(row, column); } /** * Returns <code>true</code> if the item labels for a series are visible, * and <code>false</code> otherwise. * * @param series the series index (zero-based). * * @return A boolean. */ public boolean isSeriesItemLabelsVisible(int series) { Boolean b = this.itemLabelsVisibleList.getBoolean(series); if (b == null) { b = this.defaultItemLabelsVisible; } if (b == null) { b = Boolean.FALSE; } return b; } /** * Sets a flag that controls the visibility of the item labels for a series, * and sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param visible the flag. */ public void setSeriesItemLabelsVisible(int series, boolean visible) { setSeriesItemLabelsVisible(series, Boolean.valueOf(visible)); } /** * Sets the visibility of the item labels for a series and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param visible the flag (<code>null</code> permitted). */ public void setSeriesItemLabelsVisible(int series, Boolean visible) { setSeriesItemLabelsVisible(series, visible, true); } /** * Sets the visibility of item labels for a series and, if requested, sends * a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param visible the visible flag. * @param notify a flag that controls whether or not listeners are * notified. */ public void setSeriesItemLabelsVisible(int series, Boolean visible, boolean notify) { this.itemLabelsVisibleList.setBoolean(series, visible); if (notify) { fireChangeEvent(); } } /** * Returns the default setting for item label visibility. * * @return A flag (possibly <code>null</code>). * * @see #setDefaultItemLabelsVisible(boolean) */ public boolean getDefaultItemLabelsVisible() { return this.defaultItemLabelsVisible; } /** * Sets the default flag that controls whether or not item labels are * visible, and sends a {@link RendererChangeEvent} to all registered * listeners. * * @param visible the flag. * * @see #getDefaultItemLabelsVisible() */ public void setDefaultItemLabelsVisible(boolean visible) { setDefaultItemLabelsVisible(visible, true); } /** * Sets the base visibility for item labels and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param visible the flag (<code>null</code> is permitted, and viewed * as equivalent to <code>Boolean.FALSE</code>). * @param notify a flag that controls whether or not listeners are * notified. * * @see #getDefaultItemLabelsVisible() */ public void setDefaultItemLabelsVisible(boolean visible, boolean notify) { this.defaultItemLabelsVisible = visible; if (notify) { fireChangeEvent(); } } //// ITEM LABEL FONT ////////////////////////////////////////////////////// /** * Returns the font for an item label (this is typically the same for an * entire series). * <p> * The default implementation passes control to the {@link DefaultLabelIRS} * You can implement your own {@link LabelIRS} or override this method if * you require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The font (never <code>null</code>). */ public Font getItemLabelFont(int row, int column) { return labelIRS.getItemLabelFont(row, column); } /** * Returns the font for all the item labels in a series. * * @param series the series index (zero-based). * * @return The font (possibly <code>null</code>). * * @see #setSeriesItemLabelFont(int, Font) */ public Font getSeriesItemLabelFont(int series) { return this.itemLabelFontMap.get(series); } /** * Sets the item label font for a series and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param font the font (<code>null</code> permitted). * * @see #getSeriesItemLabelFont(int) */ public void setSeriesItemLabelFont(int series, Font font) { setSeriesItemLabelFont(series, font, true); } /** * Sets the item label font for a series and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero based). * @param font the font (<code>null</code> permitted). * @param notify a flag that controls whether or not listeners are * notified. * * @see #getSeriesItemLabelFont(int) */ public void setSeriesItemLabelFont(int series, Font font, boolean notify) { this.itemLabelFontMap.put(series, font); if (notify) { fireChangeEvent(); } } /** * Returns the default item label font (this is used when no other font * setting is available). * * @return The font (<code>never</code> null). * * @see #setDefaultItemLabelFont(Font) */ public Font getDefaultItemLabelFont() { return this.defaultItemLabelFont; } /** * Sets the default item label font and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param font the font (<code>null</code> not permitted). * * @see #getDefaultItemLabelFont() */ public void setDefaultItemLabelFont(Font font) { ParamChecks.nullNotPermitted(font, "font"); setDefaultItemLabelFont(font, true); } /** * Sets the default item label font and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param font the font (<code>null</code> not permitted). * @param notify a flag that controls whether or not listeners are * notified. * * @see #getDefaultItemLabelFont() */ public void setDefaultItemLabelFont(Font font, boolean notify) { this.defaultItemLabelFont = font; if (notify) { fireChangeEvent(); } } //// ITEM LABEL PAINT //////////////////////////////////////////////////// /** * Returns the paint used to draw an item label. * * @param row the row index (zero based). * @param column the column index (zero based). * * @return The paint (never <code>null</code>). */ public Paint getItemLabelPaint(int row, int column) { Paint result = getSeriesItemLabelPaint(row); if (result == null) { result = this.defaultItemLabelPaint; } return result; } /** * Returns the paint used to draw the item labels for a series. * * @param series the series index (zero based). * * @return The paint (possibly <code>null</code>). * * @see #setSeriesItemLabelPaint(int, Paint) */ public Paint getSeriesItemLabelPaint(int series) { return this.itemLabelPaintMap.get(series); } /** * Sets the item label paint for a series and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series (zero based index). * @param paint the paint (<code>null</code> permitted). * * @see #getSeriesItemLabelPaint(int) */ public void setSeriesItemLabelPaint(int series, Paint paint) { setSeriesItemLabelPaint(series, paint, true); } /** * Sets the item label paint for a series and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero based). * @param paint the paint (<code>null</code> permitted). * @param notify a flag that controls whether or not listeners are * notified. * * @see #getSeriesItemLabelPaint(int) */ public void setSeriesItemLabelPaint(int series, Paint paint, boolean notify) { this.itemLabelPaintMap.put(series, paint); if (notify) { fireChangeEvent(); } } /** * Returns the default item label paint. * * @return The paint (never <code>null</code>). * * @see #setDefaultItemLabelPaint(Paint) */ public Paint getDefaultItemLabelPaint() { return this.defaultItemLabelPaint; } /** * Sets the default item label paint and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param paint the paint (<code>null</code> not permitted). * * @see #getDefaultItemLabelPaint() */ public void setDefaultItemLabelPaint(Paint paint) { // defer argument checking... setDefaultItemLabelPaint(paint, true); } /** * Sets the default item label paint and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners.. * * @param paint the paint (<code>null</code> not permitted). * @param notify a flag that controls whether or not listeners are * notified. * * @see #getDefaultItemLabelPaint() */ public void setDefaultItemLabelPaint(Paint paint, boolean notify) { ParamChecks.nullNotPermitted(paint, "paint"); this.defaultItemLabelPaint = paint; if (notify) { fireChangeEvent(); } } // POSITIVE ITEM LABEL POSITION... /** * Returns the item label position for positive values (this is typically * the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultLabelIRS} * You can implement your own {@link LabelIRS} or override this method if * you require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The item label position (never <code>null</code>). * * @see #getNegativeItemLabelPosition(int, int) */ public ItemLabelPosition getPositiveItemLabelPosition(int row, int column) { return labelIRS.getPositiveItemLabelPosition(row, column); } /** * Returns the item label position for all positive values in a series. * * @param series the series index (zero-based). * * @return The item label position (never <code>null</code>). * * @see #setSeriesPositiveItemLabelPosition(int, ItemLabelPosition) */ public ItemLabelPosition getSeriesPositiveItemLabelPosition(int series) { ItemLabelPosition position = this.positiveItemLabelPositionMap.get(series); if (position == null) { position = this.defaultPositiveItemLabelPosition; } return position; } /** * Sets the item label position for all positive values in a series and * sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param position the position (<code>null</code> permitted). * * @see #getSeriesPositiveItemLabelPosition(int) */ public void setSeriesPositiveItemLabelPosition(int series, ItemLabelPosition position) { setSeriesPositiveItemLabelPosition(series, position, true); } /** * Sets the item label position for all positive values in a series and (if * requested) sends a {@link RendererChangeEvent} to all registered * listeners. * * @param series the series index (zero-based). * @param position the position (<code>null</code> permitted). * @param notify notify registered listeners? * * @see #getSeriesPositiveItemLabelPosition(int) */ public void setSeriesPositiveItemLabelPosition(int series, ItemLabelPosition position, boolean notify) { this.positiveItemLabelPositionMap.put(series, position); if (notify) { fireChangeEvent(); } } /** * Returns the default positive item label position. * * @return The position (never <code>null</code>). * * @see #setDefaultPositiveItemLabelPosition(ItemLabelPosition) */ public ItemLabelPosition getDefaultPositiveItemLabelPosition() { return this.defaultPositiveItemLabelPosition; } /** * Sets the default positive item label position. * * @param position the position (<code>null</code> not permitted). * * @see #getDefaultPositiveItemLabelPosition() */ public void setDefaultPositiveItemLabelPosition( ItemLabelPosition position) { // defer argument checking... setDefaultPositiveItemLabelPosition(position, true); } /** * Sets the default positive item label position and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param position the position (<code>null</code> not permitted). * @param notify notify registered listeners? * * @see #getDefaultPositiveItemLabelPosition() */ public void setDefaultPositiveItemLabelPosition(ItemLabelPosition position, boolean notify) { ParamChecks.nullNotPermitted(position, "positions"); this.defaultPositiveItemLabelPosition = position; if (notify) { fireChangeEvent(); } } // NEGATIVE ITEM LABEL POSITION... /** * Returns the item label position for negative values (this is typically * the same for an entire series). * <p> * The default implementation passes control to the {@link DefaultLabelIRS} * You can implement your own {@link LabelIRS} or override this method if * you require different behavior. * * @param row the row (or series) index (zero-based). * @param column the column (or category) index (zero-based). * * @return The item label position (never <code>null</code>). * * @see #getPositiveItemLabelPosition(int, int) */ public ItemLabelPosition getNegativeItemLabelPosition(int row, int column) { return labelIRS.getNegativeItemLabelPosition(row, column); } /** * Returns the item label position for all negative values in a series. * * @param series the series index (zero-based). * * @return The item label position (never <code>null</code>). * * @see #setSeriesNegativeItemLabelPosition(int, ItemLabelPosition) */ public ItemLabelPosition getSeriesNegativeItemLabelPosition(int series) { ItemLabelPosition position = this.negativeItemLabelPositionMap.get( series); if (position == null) { position = this.defaultNegativeItemLabelPosition; } return position; } /** * Sets the item label position for negative values in a series and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param position the position (<code>null</code> permitted). * * @see #getSeriesNegativeItemLabelPosition(int) */ public void setSeriesNegativeItemLabelPosition(int series, ItemLabelPosition position) { setSeriesNegativeItemLabelPosition(series, position, true); } /** * Sets the item label position for negative values in a series and (if * requested) sends a {@link RendererChangeEvent} to all registered * listeners. * * @param series the series index (zero-based). * @param position the position (<code>null</code> permitted). * @param notify notify registered listeners? * * @see #getSeriesNegativeItemLabelPosition(int) */ public void setSeriesNegativeItemLabelPosition(int series, ItemLabelPosition position, boolean notify) { this.negativeItemLabelPositionMap.put(series, position); if (notify) { fireChangeEvent(); } } /** * Returns the default item label position for negative values. * * @return The position (never <code>null</code>). * * @see #setDefaultNegativeItemLabelPosition(ItemLabelPosition) */ public ItemLabelPosition getDefaultNegativeItemLabelPosition() { return this.defaultNegativeItemLabelPosition; } /** * Sets the default item label position for negative values and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param position the position (<code>null</code> not permitted). * * @see #getDefaultNegativeItemLabelPosition() */ public void setDefaultNegativeItemLabelPosition( ItemLabelPosition position) { setDefaultNegativeItemLabelPosition(position, true); } /** * Sets the default negative item label position and, if requested, sends a * {@link RendererChangeEvent} to all registered listeners. * * @param position the position (<code>null</code> not permitted). * @param notify notify registered listeners? * * @see #getDefaultNegativeItemLabelPosition() */ public void setDefaultNegativeItemLabelPosition(ItemLabelPosition position, boolean notify) { ParamChecks.nullNotPermitted(position, "positions"); this.defaultNegativeItemLabelPosition = position; if (notify) { fireChangeEvent(); } } /** * Returns the item label anchor offset. * * @return The offset. * * @see #setItemLabelAnchorOffset(double) */ public double getItemLabelAnchorOffset() { return this.itemLabelAnchorOffset; } /** * Sets the item label anchor offset. * * @param offset the offset. * * @see #getItemLabelAnchorOffset() */ public void setItemLabelAnchorOffset(double offset) { this.itemLabelAnchorOffset = offset; fireChangeEvent(); } /** * Returns a boolean that indicates whether or not the specified item * should have a chart entity created for it. * * @param series the series index. * @param item the item index. * * @return A boolean. */ public boolean getItemCreateEntity(int series, int item) { Boolean b = getSeriesCreateEntities(series); if (b != null) { return b; } // otherwise... return this.defaultCreateEntities; } /** * Returns the flag that controls whether entities are created for a * series. * * @param series the series index (zero-based). * * @return The flag (possibly <code>null</code>). * * @see #setSeriesCreateEntities(int, Boolean) */ public Boolean getSeriesCreateEntities(int series) { return this.createEntitiesList.getBoolean(series); } /** * Sets the flag that controls whether entities are created for a series, * and sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index (zero-based). * @param create the flag (<code>null</code> permitted). * * @see #getSeriesCreateEntities(int) */ public void setSeriesCreateEntities(int series, Boolean create) { setSeriesCreateEntities(series, create, true); } /** * Sets the flag that controls whether entities are created for a series * and, if requested, sends a {@link RendererChangeEvent} to all registered * listeners. * * @param series the series index. * @param create the flag (<code>null</code> permitted). * @param notify notify listeners? * * @see #getSeriesCreateEntities(int) */ public void setSeriesCreateEntities(int series, Boolean create, boolean notify) { this.createEntitiesList.setBoolean(series, create); if (notify) { fireChangeEvent(); } } /** * Returns the default flag for creating entities. * * @return The default flag for creating entities. * * @see #setDefaultCreateEntities(boolean) */ public boolean getDefaultCreateEntities() { return this.defaultCreateEntities; } /** * Sets the default flag that controls whether entities are created * for a series, and sends a {@link RendererChangeEvent} * to all registered listeners. * * @param create the flag. * * @see #getDefaultCreateEntities() */ public void setDefaultCreateEntities(boolean create) { // defer argument checking... setDefaultCreateEntities(create, true); } /** * Sets the default flag that controls whether entities are created and, * if requested, sends a {@link RendererChangeEvent} to all registered * listeners. * * @param create the visibility. * @param notify notify listeners? * * @see #getDefaultCreateEntities() */ public void setDefaultCreateEntities(boolean create, boolean notify) { this.defaultCreateEntities = create; if (notify) { fireChangeEvent(); } } /** * Returns the radius of the circle used for the default entity area * when no area is specified. * * @return A radius. * * @see #setDefaultEntityRadius(int) */ public int getDefaultEntityRadius() { return this.defaultEntityRadius; } /** * Sets the radius of the circle used for the default entity area * when no area is specified. * * @param radius the radius. * * @see #getDefaultEntityRadius() */ public void setDefaultEntityRadius(int radius) { this.defaultEntityRadius = radius; } /** * Performs a lookup for the legend shape. * * @param series the series index. * * @return The shape (possibly <code>null</code>). * * @since 1.0.11 */ public Shape lookupLegendShape(int series) { Shape result = getLegendShape(series); if (result == null) { result = this.defaultLegendShape; } if (result == null) { result = lookupSeriesShape(series); } return result; } /** * Returns the legend shape defined for the specified series (possibly * <code>null</code>). * * @param series the series index. * * @return The shape (possibly <code>null</code>). * * @see #lookupLegendShape(int) * * @since 1.0.11 */ public Shape getLegendShape(int series) { return this.legendShapeList.getShape(series); } /** * Sets the shape used for the legend item for the specified series, and * sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index. * @param shape the shape (<code>null</code> permitted). * * @since 1.0.11 */ public void setLegendShape(int series, Shape shape) { this.legendShapeList.setShape(series, shape); fireChangeEvent(); } /** * Returns the default legend shape, which may be <code>null</code>. * * @return The default legend shape. * * @since 1.0.11 */ public Shape getDefaultLegendShape() { return this.defaultLegendShape; } /** * Sets the default legend shape and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param shape the shape (<code>null</code> permitted). * * @since 1.0.11 */ public void setDefaultLegendShape(Shape shape) { this.defaultLegendShape = shape; fireChangeEvent(); } /** * Returns the flag that controls whether or not the legend shape is * treated as a line when creating legend items. * * @return A boolean. * * @since 1.0.14 */ protected boolean getTreatLegendShapeAsLine() { return this.treatLegendShapeAsLine; } /** * Sets the flag that controls whether or not the legend shape is * treated as a line when creating legend items. * * @param treatAsLine the new flag value. * * @since 1.0.14 */ protected void setTreatLegendShapeAsLine(boolean treatAsLine) { if (this.treatLegendShapeAsLine != treatAsLine) { this.treatLegendShapeAsLine = treatAsLine; fireChangeEvent(); } } /** * Performs a lookup for the legend text font. * * @param series the series index. * * @return The font. * * @since 1.0.11 */ public Font lookupLegendTextFont(int series) { Font result = getLegendTextFont(series); if (result == null) { result = this.defaultLegendTextFont; } return result; } /** * Returns the legend text font defined for the specified series (possibly * <code>null</code>). * * @param series the series index. * * @return The font (possibly <code>null</code>). * * @see #lookupLegendTextFont(int) * * @since 1.0.11 */ public Font getLegendTextFont(int series) { return this.legendTextFontMap.get(series); } /** * Sets the font used for the legend text for the specified series, and * sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index. * @param font the font (<code>null</code> permitted). * * @since 1.0.11 */ public void setLegendTextFont(int series, Font font) { this.legendTextFontMap.put(series, font); fireChangeEvent(); } /** * Returns the default legend text font. * * @return The default legend text font. * * @since 1.0.11 */ public Font getDefaultLegendTextFont() { return this.defaultLegendTextFont; } /** * Sets the default legend text font and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param font the font (<code>null</code> not permitted). * * @since 1.0.11 */ public void setDefaultLegendTextFont(Font font) { ParamChecks.nullNotPermitted(font, "font"); this.defaultLegendTextFont = font; fireChangeEvent(); } /** * Performs a lookup for the legend text paint. * * @param series the series index. * * @return The paint (possibly <code>null</code>). * * @since 1.0.11 */ public Paint lookupLegendTextPaint(int series) { Paint result = getLegendTextPaint(series); if (result == null) { result = this.defaultLegendTextPaint; } return result; } /** * Returns the legend text paint defined for the specified series (possibly * <code>null</code>). * * @param series the series index. * * @return The paint (possibly <code>null</code>). * * @see #lookupLegendTextPaint(int) * * @since 1.0.11 */ public Paint getLegendTextPaint(int series) { return this.legendTextPaintMap.get(series); } /** * Sets the paint used for the legend text for the specified series, and * sends a {@link RendererChangeEvent} to all registered listeners. * * @param series the series index. * @param paint the paint (<code>null</code> permitted). * * @since 1.0.11 */ public void setLegendTextPaint(int series, Paint paint) { this.legendTextPaintMap.put(series, paint); fireChangeEvent(); } /** * Returns the default legend text paint, which may be <code>null</code>. * * @return The default legend text paint. * * @since 1.0.11 */ public Paint getDefaultLegendTextPaint() { return this.defaultLegendTextPaint; } /** * Sets the default legend text paint and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param paint the paint (<code>null</code> permitted). * * @since 1.0.11 */ public void setDefaultLegendTextPaint(Paint paint) { this.defaultLegendTextPaint = paint; fireChangeEvent(); } /** * Returns the flag that controls whether or not the data bounds reported * by this renderer will exclude non-visible series. * * @return A boolean. * * @since 1.0.13 */ public boolean getDataBoundsIncludesVisibleSeriesOnly() { return this.dataBoundsIncludesVisibleSeriesOnly; } /** * Sets the flag that controls whether or not the data bounds reported * by this renderer will exclude non-visible series and sends a * {@link RendererChangeEvent} to all registered listeners. * * @param visibleOnly include only visible series. * * @since 1.0.13 */ public void setDataBoundsIncludesVisibleSeriesOnly(boolean visibleOnly) { this.dataBoundsIncludesVisibleSeriesOnly = visibleOnly; notifyListeners(new RendererChangeEvent(this, true)); } /** The adjacent offset. */ private static final double ADJ = Math.cos(Math.PI / 6.0); /** The opposite offset. */ private static final double OPP = Math.sin(Math.PI / 6.0); /** * Calculates the item label anchor point. * * @param anchor the anchor. * @param x the x coordinate. * @param y the y coordinate. * @param orientation the plot orientation. * * @return The anchor point (never <code>null</code>). */ protected Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor, double x, double y, PlotOrientation orientation) { Point2D result = null; if (anchor == ItemLabelAnchor.CENTER) { result = new Point2D.Double(x, y); } else if (anchor == ItemLabelAnchor.INSIDE1) { result = new Point2D.Double(x + OPP * this.itemLabelAnchorOffset, y - ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE2) { result = new Point2D.Double(x + ADJ * this.itemLabelAnchorOffset, y - OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE3) { result = new Point2D.Double(x + this.itemLabelAnchorOffset, y); } else if (anchor == ItemLabelAnchor.INSIDE4) { result = new Point2D.Double(x + ADJ * this.itemLabelAnchorOffset, y + OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE5) { result = new Point2D.Double(x + OPP * this.itemLabelAnchorOffset, y + ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE6) { result = new Point2D.Double(x, y + this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE7) { result = new Point2D.Double(x - OPP * this.itemLabelAnchorOffset, y + ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE8) { result = new Point2D.Double(x - ADJ * this.itemLabelAnchorOffset, y + OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE9) { result = new Point2D.Double(x - this.itemLabelAnchorOffset, y); } else if (anchor == ItemLabelAnchor.INSIDE10) { result = new Point2D.Double(x - ADJ * this.itemLabelAnchorOffset, y - OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE11) { result = new Point2D.Double(x - OPP * this.itemLabelAnchorOffset, y - ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.INSIDE12) { result = new Point2D.Double(x, y - this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE1) { result = new Point2D.Double( x + 2.0 * OPP * this.itemLabelAnchorOffset, y - 2.0 * ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE2) { result = new Point2D.Double( x + 2.0 * ADJ * this.itemLabelAnchorOffset, y - 2.0 * OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE3) { result = new Point2D.Double(x + 2.0 * this.itemLabelAnchorOffset, y); } else if (anchor == ItemLabelAnchor.OUTSIDE4) { result = new Point2D.Double( x + 2.0 * ADJ * this.itemLabelAnchorOffset, y + 2.0 * OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE5) { result = new Point2D.Double( x + 2.0 * OPP * this.itemLabelAnchorOffset, y + 2.0 * ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE6) { result = new Point2D.Double(x, y + 2.0 * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE7) { result = new Point2D.Double( x - 2.0 * OPP * this.itemLabelAnchorOffset, y + 2.0 * ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE8) { result = new Point2D.Double( x - 2.0 * ADJ * this.itemLabelAnchorOffset, y + 2.0 * OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE9) { result = new Point2D.Double(x - 2.0 * this.itemLabelAnchorOffset, y); } else if (anchor == ItemLabelAnchor.OUTSIDE10) { result = new Point2D.Double( x - 2.0 * ADJ * this.itemLabelAnchorOffset, y - 2.0 * OPP * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE11) { result = new Point2D.Double( x - 2.0 * OPP * this.itemLabelAnchorOffset, y - 2.0 * ADJ * this.itemLabelAnchorOffset); } else if (anchor == ItemLabelAnchor.OUTSIDE12) { result = new Point2D.Double(x, y - 2.0 * this.itemLabelAnchorOffset); } return result; } /** * Registers an object to receive notification of changes to the renderer. * * @param listener the listener (<code>null</code> not permitted). * * @see #removeChangeListener(RendererChangeListener) */ public void addChangeListener(RendererChangeListener listener) { ParamChecks.nullNotPermitted(listener, "listener"); this.listenerList.add(RendererChangeListener.class, listener); } /** * Deregisters an object so that it no longer receives * notification of changes to the renderer. * * @param listener the object (<code>null</code> not permitted). * * @see #addChangeListener(RendererChangeListener) */ public void removeChangeListener(RendererChangeListener listener) { ParamChecks.nullNotPermitted(listener, "listener"); this.listenerList.remove(RendererChangeListener.class, listener); } /** * Returns <code>true</code> if the specified object is registered with * the dataset as a listener. Most applications won't need to call this * method, it exists mainly for use by unit testing code. * * @param listener the listener. * * @return A boolean. */ public boolean hasListener(EventListener listener) { List<Object> list = Arrays.asList(this.listenerList.getListenerList()); return list.contains(listener); } /** * Sends a {@link RendererChangeEvent} to all registered listeners. * * @since 1.0.5 */ protected void fireChangeEvent() { // the commented out code would be better, but only if // RendererChangeEvent is immutable, which it isn't. See if there is // a way to fix this... //if (this.event == null) { // this.event = new RendererChangeEvent(this); //} //notifyListeners(this.event); notifyListeners(new RendererChangeEvent(this)); } /** * Notifies all registered listeners that the renderer has been modified. * * @param event information about the change event. */ public void notifyListeners(RendererChangeEvent event) { Object[] ls = this.listenerList.getListenerList(); for (int i = ls.length - 2; i >= 0; i -= 2) { if (ls[i] == RendererChangeListener.class) { ((RendererChangeListener) ls[i + 1]).rendererChanged(event); } } } /** * Tests this renderer for equality with another object. * * @param obj the object (<code>null</code> permitted). * * @return <code>true</code> or <code>false</code>. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof AbstractRenderer)) { return false; } AbstractRenderer that = (AbstractRenderer) obj; if (this.dataBoundsIncludesVisibleSeriesOnly != that.dataBoundsIncludesVisibleSeriesOnly) { return false; } if (this.treatLegendShapeAsLine != that.treatLegendShapeAsLine) { return false; } if (this.defaultEntityRadius != that.defaultEntityRadius) { return false; } if (!this.seriesVisibleList.equals(that.seriesVisibleList)) { return false; } if (this.defaultSeriesVisible != that.defaultSeriesVisible) { return false; } if (!this.seriesVisibleInLegendList.equals( that.seriesVisibleInLegendList)) { return false; } if (this.defaultSeriesVisibleInLegend != that.defaultSeriesVisibleInLegend) { return false; } if (!PaintUtils.equalMaps(this.paintMap, that.paintMap)) { return false; } if (!PaintUtils.equal(this.defaultPaint, that.defaultPaint)) { return false; } if (!PaintUtils.equalMaps(this.fillPaintMap, that.fillPaintMap)) { return false; } if (!PaintUtils.equal(this.defaultFillPaint, that.defaultFillPaint)) { return false; } if (!PaintUtils.equalMaps(this.outlinePaintMap, that.outlinePaintMap)) { return false; } if (!PaintUtils.equal(this.defaultOutlinePaint, that.defaultOutlinePaint)) { return false; } if (!ObjectUtils.equal(this.strokeList, that.strokeList)) { return false; } if (!ObjectUtils.equal(this.defaultStroke, that.defaultStroke)) { return false; } if (!ObjectUtils.equal(this.outlineStrokeList, that.outlineStrokeList)) { return false; } if (!ObjectUtils.equal(this.defaultOutlineStroke, that.defaultOutlineStroke)) { return false; } if (!ObjectUtils.equal(this.shapeList, that.shapeList)) { return false; } if (!ShapeUtils.equal(this.defaultShape, that.defaultShape)) { return false; } if (!ObjectUtils.equal(this.itemLabelsVisibleList, that.itemLabelsVisibleList)) { return false; } if (!ObjectUtils.equal(this.defaultItemLabelsVisible, that.defaultItemLabelsVisible)) { return false; } if (!ObjectUtils.equal(this.itemLabelFontMap, that.itemLabelFontMap)) { return false; } if (!ObjectUtils.equal(this.defaultItemLabelFont, that.defaultItemLabelFont)) { return false; } if (!PaintUtils.equalMaps(this.itemLabelPaintMap, that.itemLabelPaintMap)) { return false; } if (!PaintUtils.equal(this.defaultItemLabelPaint, that.defaultItemLabelPaint)) { return false; } if (!ObjectUtils.equal(this.positiveItemLabelPositionMap, that.positiveItemLabelPositionMap)) { return false; } if (!ObjectUtils.equal(this.defaultPositiveItemLabelPosition, that.defaultPositiveItemLabelPosition)) { return false; } if (!ObjectUtils.equal(this.negativeItemLabelPositionMap, that.negativeItemLabelPositionMap)) { return false; } if (!ObjectUtils.equal(this.defaultNegativeItemLabelPosition, that.defaultNegativeItemLabelPosition)) { return false; } if (this.itemLabelAnchorOffset != that.itemLabelAnchorOffset) { return false; } if (!ObjectUtils.equal(this.createEntitiesList, that.createEntitiesList)) { return false; } if (this.defaultCreateEntities != that.defaultCreateEntities) { return false; } if (!ObjectUtils.equal(this.legendShapeList, that.legendShapeList)) { return false; } if (!ShapeUtils.equal(this.defaultLegendShape, that.defaultLegendShape)) { return false; } if (!ObjectUtils.equal(this.legendTextFontMap, that.legendTextFontMap)) { return false; } if (!ObjectUtils.equal(this.defaultLegendTextFont, that.defaultLegendTextFont)) { return false; } if (!PaintUtils.equalMaps(this.legendTextPaintMap, that.legendTextPaintMap)) { return false; } if (!PaintUtils.equal(this.defaultLegendTextPaint, that.defaultLegendTextPaint)) { return false; } return true; } /** * Returns a hashcode for the renderer. * * @return The hashcode. */ @Override public int hashCode() { int result = 193; result = HashUtils.hashCode(result, this.seriesVisibleList); result = HashUtils.hashCode(result, this.defaultSeriesVisible); result = HashUtils.hashCode(result, this.seriesVisibleInLegendList); result = HashUtils.hashCode(result, this.defaultSeriesVisibleInLegend); result = HashUtils.hashCode(result, this.paintMap); result = HashUtils.hashCode(result, this.defaultPaint); result = HashUtils.hashCode(result, this.fillPaintMap); result = HashUtils.hashCode(result, this.defaultFillPaint); result = HashUtils.hashCode(result, this.outlinePaintMap); result = HashUtils.hashCode(result, this.defaultOutlinePaint); result = HashUtils.hashCode(result, this.strokeList); result = HashUtils.hashCode(result, this.defaultStroke); result = HashUtils.hashCode(result, this.outlineStrokeList); result = HashUtils.hashCode(result, this.defaultOutlineStroke); // shapeList // baseShape result = HashUtils.hashCode(result, this.itemLabelsVisibleList); result = HashUtils.hashCode(result, this.defaultItemLabelsVisible); // itemLabelFontList // baseItemLabelFont // itemLabelPaintList // baseItemLabelPaint // positiveItemLabelPositionList // basePositiveItemLabelPosition // negativeItemLabelPositionList // baseNegativeItemLabelPosition // itemLabelAnchorOffset // createEntityList // baseCreateEntities return result; } /** * Returns an independent copy of the renderer. * * @return A clone. * * @throws CloneNotSupportedException if some component of the renderer * does not support cloning. */ @Override protected Object clone() throws CloneNotSupportedException { AbstractRenderer clone = (AbstractRenderer) super.clone(); if (this.seriesVisibleList != null) { clone.seriesVisibleList = (BooleanList) this.seriesVisibleList.clone(); } if (this.seriesVisibleInLegendList != null) { clone.seriesVisibleInLegendList = (BooleanList) this.seriesVisibleInLegendList.clone(); } // 'paint' : immutable, no need to clone reference clone.paintMap = new HashMap<Integer, Paint>(this.paintMap); // 'basePaint' : immutable, no need to clone reference clone.fillPaintMap = new HashMap<Integer, Paint>(this.fillPaintMap); // 'outlinePaint' : immutable, no need to clone reference clone.outlinePaintMap = new HashMap<Integer, Paint>(this.outlinePaintMap); // 'baseOutlinePaint' : immutable, no need to clone reference // 'stroke' : immutable, no need to clone reference if (this.strokeList != null) { clone.strokeList = (StrokeList) this.strokeList.clone(); } // 'baseStroke' : immutable, no need to clone reference // 'outlineStroke' : immutable, no need to clone reference if (this.outlineStrokeList != null) { clone.outlineStrokeList = (StrokeList) this.outlineStrokeList.clone(); } // 'baseOutlineStroke' : immutable, no need to clone reference if (this.shapeList != null) { clone.shapeList = (ShapeList) this.shapeList.clone(); } if (this.defaultShape != null) { clone.defaultShape = ShapeUtils.clone(this.defaultShape); } // 'itemLabelsVisible' : immutable, no need to clone reference if (this.itemLabelsVisibleList != null) { clone.itemLabelsVisibleList = (BooleanList) this.itemLabelsVisibleList.clone(); } // 'basePaint' : immutable, no need to clone reference // 'itemLabelFont' : immutable, no need to clone reference if (this.itemLabelFontMap != null) { clone.itemLabelFontMap = new HashMap<Integer, Font>(this.itemLabelFontMap); } // 'baseItemLabelFont' : immutable, no need to clone reference // 'itemLabelPaint' : immutable, no need to clone reference if (this.itemLabelPaintMap != null) { clone.itemLabelPaintMap = new HashMap<Integer, Paint>(this.itemLabelPaintMap); } // 'baseItemLabelPaint' : immutable, no need to clone reference if (this.positiveItemLabelPositionMap != null) { clone.positiveItemLabelPositionMap = new HashMap<Integer, ItemLabelPosition>( this.positiveItemLabelPositionMap); } if (this.negativeItemLabelPositionMap != null) { clone.negativeItemLabelPositionMap = new HashMap<Integer, ItemLabelPosition>( this.negativeItemLabelPositionMap); } if (this.createEntitiesList != null) { clone.createEntitiesList = (BooleanList) this.createEntitiesList.clone(); } if (this.legendShapeList != null) { clone.legendShapeList = (ShapeList) this.legendShapeList.clone(); } if (this.legendTextFontMap != null) { clone.legendTextFontMap = new HashMap<Integer, Font>(this.legendTextFontMap); } if (this.legendTextPaintMap != null) { clone.legendTextPaintMap = new HashMap<Integer, Paint>(this.legendTextPaintMap); } clone.listenerList = new EventListenerList(); clone.event = null; return clone; } /** * Provides serialization support. * * @param stream the output stream. * * @throws IOException if there is an I/O error. */ private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); SerialUtils.writePaint(this.defaultPaint, stream); SerialUtils.writePaintMap(this.paintMap, stream); SerialUtils.writePaint(this.defaultFillPaint, stream); SerialUtils.writePaintMap(this.fillPaintMap, stream); SerialUtils.writePaint(this.defaultOutlinePaint, stream); SerialUtils.writePaintMap(this.outlinePaintMap, stream); SerialUtils.writeStroke(this.defaultStroke, stream); SerialUtils.writeStroke(this.defaultOutlineStroke, stream); SerialUtils.writeShape(this.defaultShape, stream); SerialUtils.writePaint(this.defaultItemLabelPaint, stream); SerialUtils.writePaintMap(this.itemLabelPaintMap, stream); SerialUtils.writeShape(this.defaultLegendShape, stream); SerialUtils.writePaint(this.defaultLegendTextPaint, stream); SerialUtils.writePaintMap(this.legendTextPaintMap, stream); } /** * Provides serialization support. * * @param stream the input stream. * * @throws IOException if there is an I/O error. * @throws ClassNotFoundException if there is a classpath problem. */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); this.defaultPaint = SerialUtils.readPaint(stream); this.paintMap = SerialUtils.readPaintMap(stream); this.defaultFillPaint = SerialUtils.readPaint(stream); this.fillPaintMap = SerialUtils.readPaintMap(stream); this.defaultOutlinePaint = SerialUtils.readPaint(stream); this.outlinePaintMap = SerialUtils.readPaintMap(stream); this.defaultStroke = SerialUtils.readStroke(stream); this.defaultOutlineStroke = SerialUtils.readStroke(stream); this.defaultShape = SerialUtils.readShape(stream); this.defaultItemLabelPaint = SerialUtils.readPaint(stream); this.itemLabelPaintMap = SerialUtils.readPaintMap(stream); this.defaultLegendShape = SerialUtils.readShape(stream); this.defaultLegendTextPaint = SerialUtils.readPaint(stream); this.legendTextPaintMap = SerialUtils.readPaintMap(stream); // listeners are not restored automatically, but storage must be // provided... this.listenerList = new EventListenerList(); } }