Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » renderer » category » [javadoc | source]
    1   /* ===========================================================
    2    * JFreeChart : a free chart library for the Java(tm) platform
    3    * ===========================================================
    4    *
    5    * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
    6    *
    7    * Project Info:  http://www.jfree.org/jfreechart/index.html
    8    *
    9    * This library is free software; you can redistribute it and/or modify it
   10    * under the terms of the GNU Lesser General Public License as published by
   11    * the Free Software Foundation; either version 2.1 of the License, or
   12    * (at your option) any later version.
   13    *
   14    * This library is distributed in the hope that it will be useful, but
   15    * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   16    * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
   17    * License for more details.
   18    *
   19    * You should have received a copy of the GNU Lesser General Public
   20    * License along with this library; if not, write to the Free Software
   21    * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
   22    * USA.
   23    *
   24    * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
   25    * in the United States and other countries.]
   26    *
   27    * ---------------------------------
   28    * AbstractCategoryItemRenderer.java
   29    * ---------------------------------
   30    * (C) Copyright 2002-2008, by Object Refinery Limited.
   31    *
   32    * Original Author:  David Gilbert (for Object Refinery Limited);
   33    * Contributor(s):   Richard Atkinson;
   34    *
   35    * Changes:
   36    * --------
   37    * 29-May-2002 : Version 1 (DG);
   38    * 06-Jun-2002 : Added accessor methods for the tool tip generator (DG);
   39    * 11-Jun-2002 : Made constructors protected (DG);
   40    * 26-Jun-2002 : Added axis to initialise method (DG);
   41    * 05-Aug-2002 : Added urlGenerator member variable plus accessors (RA);
   42    * 22-Aug-2002 : Added categoriesPaint attribute, based on code submitted by
   43    *               Janet Banks.  This can be used when there is only one series,
   44    *               and you want each category item to have a different color (DG);
   45    * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
   46    * 29-Oct-2002 : Fixed bug where background image for plot was not being
   47    *               drawn (DG);
   48    * 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG);
   49    * 26-Nov 2002 : Replaced the isStacked() method with getRangeType() (DG);
   50    * 09-Jan-2003 : Renamed grid-line methods (DG);
   51    * 17-Jan-2003 : Moved plot classes into separate package (DG);
   52    * 25-Mar-2003 : Implemented Serializable (DG);
   53    * 12-May-2003 : Modified to take into account the plot orientation (DG);
   54    * 12-Aug-2003 : Very minor javadoc corrections (DB)
   55    * 13-Aug-2003 : Implemented Cloneable (DG);
   56    * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
   57    * 05-Nov-2003 : Fixed marker rendering bug (833623) (DG);
   58    * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
   59    * 11-Feb-2004 : Modified labelling for markers (DG);
   60    * 12-Feb-2004 : Updated clone() method (DG);
   61    * 15-Apr-2004 : Created a new CategoryToolTipGenerator interface (DG);
   62    * 05-May-2004 : Fixed bug (948310) where interval markers extend outside axis
   63    *               range (DG);
   64    * 14-Jun-2004 : Fixed bug in drawRangeMarker() method - now uses 'paint' and
   65    *               'stroke' rather than 'outlinePaint' and 'outlineStroke' (DG);
   66    * 15-Jun-2004 : Interval markers can now use GradientPaint (DG);
   67    * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities
   68    *               --> TextUtilities (DG);
   69    * 01-Oct-2004 : Fixed bug 1029697, problem with label alignment in
   70    *               drawRangeMarker() method (DG);
   71    * 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds() (DG);
   72    * 21-Jan-2005 : Modified return type of calculateRangeMarkerTextAnchorPoint()
   73    *               method (DG);
   74    * 08-Mar-2005 : Fixed positioning of marker labels (DG);
   75    * 20-Apr-2005 : Added legend label, tooltip and URL generators (DG);
   76    * 01-Jun-2005 : Handle one dimension of the marker label adjustment
   77    *               automatically (DG);
   78    * 09-Jun-2005 : Added utility method for adding an item entity (DG);
   79    * ------------- JFREECHART 1.0.x ---------------------------------------------
   80    * 01-Mar-2006 : Updated getLegendItems() to check seriesVisibleInLegend
   81    *               flags (DG);
   82    * 20-Jul-2006 : Set dataset and series indices in LegendItem (DG);
   83    * 23-Oct-2006 : Draw outlines for interval markers (DG);
   84    * 24-Oct-2006 : Respect alpha setting in markers, as suggested by Sergei
   85    *               Ivanov in patch 1567843 (DG);
   86    * 30-Nov-2006 : Added a check for series visibility in the getLegendItem()
   87    *               method (DG);
   88    * 07-Dec-2006 : Fix for equals() method (DG);
   89    * 22-Feb-2007 : Added createState() method (DG);
   90    * 01-Mar-2007 : Fixed interval marker drawing (patch 1670686 thanks to
   91    *               Sergei Ivanov) (DG);
   92    * 20-Apr-2007 : Updated getLegendItem() for renderer change, and deprecated
   93    *               itemLabelGenerator, toolTipGenerator and itemURLGenerator
   94    *               override fields (DG);
   95    * 18-May-2007 : Set dataset and seriesKey for LegendItem (DG);
   96    *
   97    */
   98   
   99   package org.jfree.chart.renderer.category;
  100   
  101   import java.awt.AlphaComposite;
  102   import java.awt.Composite;
  103   import java.awt.Font;
  104   import java.awt.GradientPaint;
  105   import java.awt.Graphics2D;
  106   import java.awt.Paint;
  107   import java.awt.Shape;
  108   import java.awt.Stroke;
  109   import java.awt.geom.Line2D;
  110   import java.awt.geom.Point2D;
  111   import java.awt.geom.Rectangle2D;
  112   import java.io.Serializable;
  113   
  114   import org.jfree.chart.LegendItem;
  115   import org.jfree.chart.LegendItemCollection;
  116   import org.jfree.chart.axis.CategoryAxis;
  117   import org.jfree.chart.axis.ValueAxis;
  118   import org.jfree.chart.entity.CategoryItemEntity;
  119   import org.jfree.chart.entity.EntityCollection;
  120   import org.jfree.chart.event.RendererChangeEvent;
  121   import org.jfree.chart.labels.CategoryItemLabelGenerator;
  122   import org.jfree.chart.labels.CategorySeriesLabelGenerator;
  123   import org.jfree.chart.labels.CategoryToolTipGenerator;
  124   import org.jfree.chart.labels.ItemLabelPosition;
  125   import org.jfree.chart.labels.StandardCategorySeriesLabelGenerator;
  126   import org.jfree.chart.plot.CategoryMarker;
  127   import org.jfree.chart.plot.CategoryPlot;
  128   import org.jfree.chart.plot.DrawingSupplier;
  129   import org.jfree.chart.plot.IntervalMarker;
  130   import org.jfree.chart.plot.Marker;
  131   import org.jfree.chart.plot.PlotOrientation;
  132   import org.jfree.chart.plot.PlotRenderingInfo;
  133   import org.jfree.chart.plot.ValueMarker;
  134   import org.jfree.chart.renderer.AbstractRenderer;
  135   import org.jfree.chart.urls.CategoryURLGenerator;
  136   import org.jfree.data.Range;
  137   import org.jfree.data.category.CategoryDataset;
  138   import org.jfree.data.general.DatasetUtilities;
  139   import org.jfree.text.TextUtilities;
  140   import org.jfree.ui.GradientPaintTransformer;
  141   import org.jfree.ui.LengthAdjustmentType;
  142   import org.jfree.ui.RectangleAnchor;
  143   import org.jfree.ui.RectangleInsets;
  144   import org.jfree.util.ObjectList;
  145   import org.jfree.util.ObjectUtilities;
  146   import org.jfree.util.PublicCloneable;
  147   
  148   /**
  149    * An abstract base class that you can use to implement a new
  150    * {@link CategoryItemRenderer}.  When you create a new
  151    * {@link CategoryItemRenderer} you are not required to extend this class,
  152    * but it makes the job easier.
  153    */
  154   public abstract class AbstractCategoryItemRenderer extends AbstractRenderer
  155           implements CategoryItemRenderer, Cloneable, PublicCloneable,
  156           Serializable {
  157   
  158       /** For serialization. */
  159       private static final long serialVersionUID = 1247553218442497391L;
  160   
  161       /** The plot that the renderer is assigned to. */
  162       private CategoryPlot plot;
  163   
  164       /**
  165        * The item label generator for ALL series.
  166        *
  167        * @deprecated This field is redundant and deprecated as of version 1.0.6.
  168        */
  169       private CategoryItemLabelGenerator itemLabelGenerator;
  170   
  171       /** A list of item label generators (one per series). */
  172       private ObjectList itemLabelGeneratorList;
  173   
  174       /** The base item label generator. */
  175       private CategoryItemLabelGenerator baseItemLabelGenerator;
  176   
  177       /**
  178        * The tool tip generator for ALL series.
  179        *
  180        * @deprecated This field is redundant and deprecated as of version 1.0.6.
  181        */
  182       private CategoryToolTipGenerator toolTipGenerator;
  183   
  184       /** A list of tool tip generators (one per series). */
  185       private ObjectList toolTipGeneratorList;
  186   
  187       /** The base tool tip generator. */
  188       private CategoryToolTipGenerator baseToolTipGenerator;
  189   
  190       /**
  191        * The URL generator.
  192        *
  193        * @deprecated This field is redundant and deprecated as of version 1.0.6.
  194        */
  195       private CategoryURLGenerator itemURLGenerator;
  196   
  197       /** A list of item label generators (one per series). */
  198       private ObjectList itemURLGeneratorList;
  199   
  200       /** The base item label generator. */
  201       private CategoryURLGenerator baseItemURLGenerator;
  202   
  203       /** The legend item label generator. */
  204       private CategorySeriesLabelGenerator legendItemLabelGenerator;
  205   
  206       /** The legend item tool tip generator. */
  207       private CategorySeriesLabelGenerator legendItemToolTipGenerator;
  208   
  209       /** The legend item URL generator. */
  210       private CategorySeriesLabelGenerator legendItemURLGenerator;
  211   
  212       /** The number of rows in the dataset (temporary record). */
  213       private transient int rowCount;
  214   
  215       /** The number of columns in the dataset (temporary record). */
  216       private transient int columnCount;
  217   
  218       /**
  219        * Creates a new renderer with no tool tip generator and no URL generator.
  220        * The defaults (no tool tip or URL generators) have been chosen to
  221        * minimise the processing required to generate a default chart.  If you
  222        * require tool tips or URLs, then you can easily add the required
  223        * generators.
  224        */
  225       protected AbstractCategoryItemRenderer() {
  226           this.itemLabelGenerator = null;
  227           this.itemLabelGeneratorList = new ObjectList();
  228           this.toolTipGenerator = null;
  229           this.toolTipGeneratorList = new ObjectList();
  230           this.itemURLGenerator = null;
  231           this.itemURLGeneratorList = new ObjectList();
  232           this.legendItemLabelGenerator
  233               = new StandardCategorySeriesLabelGenerator();
  234       }
  235   
  236       /**
  237        * Returns the number of passes through the dataset required by the
  238        * renderer.  This method returns <code>1</code>, subclasses should
  239        * override if they need more passes.
  240        *
  241        * @return The pass count.
  242        */
  243       public int getPassCount() {
  244           return 1;
  245       }
  246   
  247       /**
  248        * Returns the plot that the renderer has been assigned to (where
  249        * <code>null</code> indicates that the renderer is not currently assigned
  250        * to a plot).
  251        *
  252        * @return The plot (possibly <code>null</code>).
  253        *
  254        * @see #setPlot(CategoryPlot)
  255        */
  256       public CategoryPlot getPlot() {
  257           return this.plot;
  258       }
  259   
  260       /**
  261        * Sets the plot that the renderer has been assigned to.  This method is
  262        * usually called by the {@link CategoryPlot}, in normal usage you
  263        * shouldn't need to call this method directly.
  264        *
  265        * @param plot  the plot (<code>null</code> not permitted).
  266        *
  267        * @see #getPlot()
  268        */
  269       public void setPlot(CategoryPlot plot) {
  270           if (plot == null) {
  271               throw new IllegalArgumentException("Null 'plot' argument.");
  272           }
  273           this.plot = plot;
  274       }
  275   
  276       // ITEM LABEL GENERATOR
  277   
  278       /**
  279        * Returns the item label generator for a data item.  This implementation
  280        * simply passes control to the {@link #getSeriesItemLabelGenerator(int)}
  281        * method.  If, for some reason, you want a different generator for
  282        * individual items, you can override this method.
  283        *
  284        * @param row  the row index (zero based).
  285        * @param column  the column index (zero based).
  286        *
  287        * @return The generator (possibly <code>null</code>).
  288        */
  289       public CategoryItemLabelGenerator getItemLabelGenerator(int row,
  290               int column) {
  291           return getSeriesItemLabelGenerator(row);
  292       }
  293   
  294       /**
  295        * Returns the item label generator for a series.
  296        *
  297        * @param series  the series index (zero based).
  298        *
  299        * @return The generator (possibly <code>null</code>).
  300        *
  301        * @see #setSeriesItemLabelGenerator(int, CategoryItemLabelGenerator)
  302        */
  303       public CategoryItemLabelGenerator getSeriesItemLabelGenerator(int series) {
  304   
  305           // return the generator for ALL series, if there is one...
  306           if (this.itemLabelGenerator != null) {
  307               return this.itemLabelGenerator;
  308           }
  309   
  310           // otherwise look up the generator table
  311           CategoryItemLabelGenerator generator = (CategoryItemLabelGenerator)
  312               this.itemLabelGeneratorList.get(series);
  313           if (generator == null) {
  314               generator = this.baseItemLabelGenerator;
  315           }
  316           return generator;
  317   
  318       }
  319   
  320       /**
  321        * Sets the item label generator for ALL series and sends a
  322        * {@link RendererChangeEvent} to all registered listeners.
  323        *
  324        * @param generator  the generator (<code>null</code> permitted).
  325        *
  326        * @deprecated This method should no longer be used (as of version 1.0.6).
  327        *     It is sufficient to rely on {@link #setSeriesItemLabelGenerator(int,
  328        *     CategoryItemLabelGenerator)} and
  329        *     {@link #setBaseItemLabelGenerator(CategoryItemLabelGenerator)}.
  330        */
  331       public void setItemLabelGenerator(CategoryItemLabelGenerator generator) {
  332           this.itemLabelGenerator = generator;
  333           fireChangeEvent();
  334       }
  335   
  336       /**
  337        * Sets the item label generator for a series and sends a
  338        * {@link RendererChangeEvent} to all registered listeners.
  339        *
  340        * @param series  the series index (zero based).
  341        * @param generator  the generator (<code>null</code> permitted).
  342        *
  343        * @see #getSeriesItemLabelGenerator(int)
  344        */
  345       public void setSeriesItemLabelGenerator(int series,
  346                                           CategoryItemLabelGenerator generator) {
  347           this.itemLabelGeneratorList.set(series, generator);
  348           fireChangeEvent();
  349       }
  350   
  351       /**
  352        * Returns the base item label generator.
  353        *
  354        * @return The generator (possibly <code>null</code>).
  355        *
  356        * @see #setBaseItemLabelGenerator(CategoryItemLabelGenerator)
  357        */
  358       public CategoryItemLabelGenerator getBaseItemLabelGenerator() {
  359           return this.baseItemLabelGenerator;
  360       }
  361   
  362       /**
  363        * Sets the base item label generator and sends a
  364        * {@link RendererChangeEvent} to all registered listeners.
  365        *
  366        * @param generator  the generator (<code>null</code> permitted).
  367        *
  368        * @see #getBaseItemLabelGenerator()
  369        */
  370       public void setBaseItemLabelGenerator(
  371               CategoryItemLabelGenerator generator) {
  372           this.baseItemLabelGenerator = generator;
  373           fireChangeEvent();
  374       }
  375   
  376       // TOOL TIP GENERATOR
  377   
  378       /**
  379        * Returns the tool tip generator that should be used for the specified
  380        * item.  This method looks up the generator using the "three-layer"
  381        * approach outlined in the general description of this interface.  You
  382        * can override this method if you want to return a different generator per
  383        * item.
  384        *
  385        * @param row  the row index (zero-based).
  386        * @param column  the column index (zero-based).
  387        *
  388        * @return The generator (possibly <code>null</code>).
  389        */
  390       public CategoryToolTipGenerator getToolTipGenerator(int row, int column) {
  391   
  392           CategoryToolTipGenerator result = null;
  393           if (this.toolTipGenerator != null) {
  394               result = this.toolTipGenerator;
  395           }
  396           else {
  397               result = getSeriesToolTipGenerator(row);
  398               if (result == null) {
  399                   result = this.baseToolTipGenerator;
  400               }
  401           }
  402           return result;
  403       }
  404   
  405       /**
  406        * Returns the tool tip generator that will be used for ALL items in the
  407        * dataset (the "layer 0" generator).
  408        *
  409        * @return A tool tip generator (possibly <code>null</code>).
  410        *
  411        * @see #setToolTipGenerator(CategoryToolTipGenerator)
  412        *
  413        * @deprecated This method should no longer be used (as of version 1.0.6).
  414        *     It is sufficient to rely on {@link #getSeriesToolTipGenerator(int)}
  415        *     and {@link #getBaseToolTipGenerator()}.
  416        */
  417       public CategoryToolTipGenerator getToolTipGenerator() {
  418           return this.toolTipGenerator;
  419       }
  420   
  421       /**
  422        * Sets the tool tip generator for ALL series and sends a
  423        * {@link org.jfree.chart.event.RendererChangeEvent} to all registered
  424        * listeners.
  425        *
  426        * @param generator  the generator (<code>null</code> permitted).
  427        *
  428        * @see #getToolTipGenerator()
  429        *
  430        * @deprecated This method should no longer be used (as of version 1.0.6).
  431        *     It is sufficient to rely on {@link #setSeriesToolTipGenerator(int,
  432        *     CategoryToolTipGenerator)} and
  433        *     {@link #setBaseToolTipGenerator(CategoryToolTipGenerator)}.
  434        */
  435       public void setToolTipGenerator(CategoryToolTipGenerator generator) {
  436           this.toolTipGenerator = generator;
  437           fireChangeEvent();
  438       }
  439   
  440       /**
  441        * Returns the tool tip generator for the specified series (a "layer 1"
  442        * generator).
  443        *
  444        * @param series  the series index (zero-based).
  445        *
  446        * @return The tool tip generator (possibly <code>null</code>).
  447        *
  448        * @see #setSeriesToolTipGenerator(int, CategoryToolTipGenerator)
  449        */
  450       public CategoryToolTipGenerator getSeriesToolTipGenerator(int series) {
  451           return (CategoryToolTipGenerator) this.toolTipGeneratorList.get(series);
  452       }
  453   
  454       /**
  455        * Sets the tool tip generator for a series and sends a
  456        * {@link RendererChangeEvent} to all registered listeners.
  457        *
  458        * @param series  the series index (zero-based).
  459        * @param generator  the generator (<code>null</code> permitted).
  460        *
  461        * @see #getSeriesToolTipGenerator(int)
  462        */
  463       public void setSeriesToolTipGenerator(int series,
  464                                             CategoryToolTipGenerator generator) {
  465           this.toolTipGeneratorList.set(series, generator);
  466           fireChangeEvent();
  467       }
  468   
  469       /**
  470        * Returns the base tool tip generator (the "layer 2" generator).
  471        *
  472        * @return The tool tip generator (possibly <code>null</code>).
  473        *
  474        * @see #setBaseToolTipGenerator(CategoryToolTipGenerator)
  475        */
  476       public CategoryToolTipGenerator getBaseToolTipGenerator() {
  477           return this.baseToolTipGenerator;
  478       }
  479   
  480       /**
  481        * Sets the base tool tip generator and sends a {@link RendererChangeEvent}
  482        * to all registered listeners.
  483        *
  484        * @param generator  the generator (<code>null</code> permitted).
  485        *
  486        * @see #getBaseToolTipGenerator()
  487        */
  488       public void setBaseToolTipGenerator(CategoryToolTipGenerator generator) {
  489           this.baseToolTipGenerator = generator;
  490           fireChangeEvent();
  491       }
  492   
  493       // URL GENERATOR
  494   
  495       /**
  496        * Returns the URL generator for a data item.  This method just calls the
  497        * getSeriesItemURLGenerator method, but you can override this behaviour if
  498        * you want to.
  499        *
  500        * @param row  the row index (zero based).
  501        * @param column  the column index (zero based).
  502        *
  503        * @return The URL generator.
  504        */
  505       public CategoryURLGenerator getItemURLGenerator(int row, int column) {
  506           return getSeriesItemURLGenerator(row);
  507       }
  508   
  509       /**
  510        * Returns the URL generator for a series.
  511        *
  512        * @param series  the series index (zero based).
  513        *
  514        * @return The URL generator for the series.
  515        *
  516        * @see #setSeriesItemURLGenerator(int, CategoryURLGenerator)
  517        */
  518       public CategoryURLGenerator getSeriesItemURLGenerator(int series) {
  519   
  520           // return the generator for ALL series, if there is one...
  521           if (this.itemURLGenerator != null) {
  522               return this.itemURLGenerator;
  523           }
  524   
  525           // otherwise look up the generator table
  526           CategoryURLGenerator generator
  527               = (CategoryURLGenerator) this.itemURLGeneratorList.get(series);
  528           if (generator == null) {
  529               generator = this.baseItemURLGenerator;
  530           }
  531           return generator;
  532   
  533       }
  534   
  535       /**
  536        * Sets the item URL generator for ALL series and sends a
  537        * {@link RendererChangeEvent} to all registered listeners.
  538        *
  539        * @param generator  the generator.
  540        *
  541        * @deprecated This method should no longer be used (as of version 1.0.6).
  542        *     It is sufficient to rely on {@link #setSeriesItemURLGenerator(int,
  543        *     CategoryURLGenerator)} and
  544        *     {@link #setBaseItemURLGenerator(CategoryURLGenerator)}.
  545        */
  546       public void setItemURLGenerator(CategoryURLGenerator generator) {
  547           this.itemURLGenerator = generator;
  548           fireChangeEvent();
  549       }
  550   
  551       /**
  552        * Sets the URL generator for a series and sends a
  553        * {@link RendererChangeEvent} to all registered listeners.
  554        *
  555        * @param series  the series index (zero based).
  556        * @param generator  the generator.
  557        *
  558        * @see #getSeriesItemURLGenerator(int)
  559        */
  560       public void setSeriesItemURLGenerator(int series,
  561                                             CategoryURLGenerator generator) {
  562           this.itemURLGeneratorList.set(series, generator);
  563           fireChangeEvent();
  564       }
  565   
  566       /**
  567        * Returns the base item URL generator.
  568        *
  569        * @return The item URL generator.
  570        *
  571        * @see #setBaseItemURLGenerator(CategoryURLGenerator)
  572        */
  573       public CategoryURLGenerator getBaseItemURLGenerator() {
  574           return this.baseItemURLGenerator;
  575       }
  576   
  577       /**
  578        * Sets the base item URL generator and sends a
  579        * {@link RendererChangeEvent} to all registered listeners.
  580        *
  581        * @param generator  the item URL generator (<code>null</code> permitted).
  582        *
  583        * @see #getBaseItemURLGenerator()
  584        */
  585       public void setBaseItemURLGenerator(CategoryURLGenerator generator) {
  586           this.baseItemURLGenerator = generator;
  587           fireChangeEvent();
  588       }
  589   
  590       /**
  591        * Returns the number of rows in the dataset.  This value is updated in the
  592        * {@link AbstractCategoryItemRenderer#initialise} method.
  593        *
  594        * @return The row count.
  595        */
  596       public int getRowCount() {
  597           return this.rowCount;
  598       }
  599   
  600       /**
  601        * Returns the number of columns in the dataset.  This value is updated in
  602        * the {@link AbstractCategoryItemRenderer#initialise} method.
  603        *
  604        * @return The column count.
  605        */
  606       public int getColumnCount() {
  607           return this.columnCount;
  608       }
  609   
  610       /**
  611        * Creates a new state instance---this method is called from the
  612        * {@link #initialise(Graphics2D, Rectangle2D, CategoryPlot, int,
  613        * PlotRenderingInfo)} method.  Subclasses can override this method if
  614        * they need to use a subclass of {@link CategoryItemRendererState}.
  615        *
  616        * @param info  collects plot rendering info (<code>null</code> permitted).
  617        *
  618        * @return The new state instance (never <code>null</code>).
  619        *
  620        * @since 1.0.5
  621        */
  622       protected CategoryItemRendererState createState(PlotRenderingInfo info) {
  623           return new CategoryItemRendererState(info);
  624       }
  625   
  626       /**
  627        * Initialises the renderer and returns a state object that will be used
  628        * for the remainder of the drawing process for a single chart.  The state
  629        * object allows for the fact that the renderer may be used simultaneously
  630        * by multiple threads (each thread will work with a separate state object).
  631        *
  632        * @param g2  the graphics device.
  633        * @param dataArea  the data area.
  634        * @param plot  the plot.
  635        * @param rendererIndex  the renderer index.
  636        * @param info  an object for returning information about the structure of
  637        *              the plot (<code>null</code> permitted).
  638        *
  639        * @return The renderer state.
  640        */
  641       public CategoryItemRendererState initialise(Graphics2D g2,
  642                                                   Rectangle2D dataArea,
  643                                                   CategoryPlot plot,
  644                                                   int rendererIndex,
  645                                                   PlotRenderingInfo info) {
  646   
  647           setPlot(plot);
  648           CategoryDataset data = plot.getDataset(rendererIndex);
  649           if (data != null) {
  650               this.rowCount = data.getRowCount();
  651               this.columnCount = data.getColumnCount();
  652           }
  653           else {
  654               this.rowCount = 0;
  655               this.columnCount = 0;
  656           }
  657           return createState(info);
  658   
  659       }
  660   
  661       /**
  662        * Returns the range of values the renderer requires to display all the
  663        * items from the specified dataset.
  664        *
  665        * @param dataset  the dataset (<code>null</code> permitted).
  666        *
  667        * @return The range (or <code>null</code> if the dataset is
  668        *         <code>null</code> or empty).
  669        */
  670       public Range findRangeBounds(CategoryDataset dataset) {
  671           return DatasetUtilities.findRangeBounds(dataset);
  672       }
  673   
  674       /**
  675        * Draws a background for the data area.  The default implementation just
  676        * gets the plot to draw the background, but some renderers will override
  677        * this behaviour.
  678        *
  679        * @param g2  the graphics device.
  680        * @param plot  the plot.
  681        * @param dataArea  the data area.
  682        */
  683       public void drawBackground(Graphics2D g2,
  684                                  CategoryPlot plot,
  685                                  Rectangle2D dataArea) {
  686   
  687           plot.drawBackground(g2, dataArea);
  688   
  689       }
  690   
  691       /**
  692        * Draws an outline for the data area.  The default implementation just
  693        * gets the plot to draw the outline, but some renderers will override this
  694        * behaviour.
  695        *
  696        * @param g2  the graphics device.
  697        * @param plot  the plot.
  698        * @param dataArea  the data area.
  699        */
  700       public void drawOutline(Graphics2D g2,
  701                               CategoryPlot plot,
  702                               Rectangle2D dataArea) {
  703   
  704           plot.drawOutline(g2, dataArea);
  705   
  706       }
  707   
  708       /**
  709        * Draws a grid line against the domain axis.
  710        * <P>
  711        * Note that this default implementation assumes that the horizontal axis
  712        * is the domain axis. If this is not the case, you will need to override
  713        * this method.
  714        *
  715        * @param g2  the graphics device.
  716        * @param plot  the plot.
  717        * @param dataArea  the area for plotting data (not yet adjusted for any
  718        *                  3D effect).
  719        * @param value  the Java2D value at which the grid line should be drawn.
  720        *
  721        * @see #drawRangeGridline(Graphics2D, CategoryPlot, ValueAxis,
  722        *     Rectangle2D, double)
  723        */
  724       public void drawDomainGridline(Graphics2D g2,
  725                                      CategoryPlot plot,
  726                                      Rectangle2D dataArea,
  727                                      double value) {
  728   
  729           Line2D line = null;
  730           PlotOrientation orientation = plot.getOrientation();
  731   
  732           if (orientation == PlotOrientation.HORIZONTAL) {
  733               line = new Line2D.Double(dataArea.getMinX(), value,
  734                       dataArea.getMaxX(), value);
  735           }
  736           else if (orientation == PlotOrientation.VERTICAL) {
  737               line = new Line2D.Double(value, dataArea.getMinY(), value,
  738                       dataArea.getMaxY());
  739           }
  740   
  741           Paint paint = plot.getDomainGridlinePaint();
  742           if (paint == null) {
  743               paint = CategoryPlot.DEFAULT_GRIDLINE_PAINT;
  744           }
  745           g2.setPaint(paint);
  746   
  747           Stroke stroke = plot.getDomainGridlineStroke();
  748           if (stroke == null) {
  749               stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE;
  750           }
  751           g2.setStroke(stroke);
  752   
  753           g2.draw(line);
  754   
  755       }
  756   
  757       /**
  758        * Draws a grid line against the range axis.
  759        *
  760        * @param g2  the graphics device.
  761        * @param plot  the plot.
  762        * @param axis  the value axis.
  763        * @param dataArea  the area for plotting data (not yet adjusted for any
  764        *                  3D effect).
  765        * @param value  the value at which the grid line should be drawn.
  766        *
  767        * @see #drawDomainGridline(Graphics2D, CategoryPlot, Rectangle2D, double)
  768        *
  769        */
  770       public void drawRangeGridline(Graphics2D g2,
  771                                     CategoryPlot plot,
  772                                     ValueAxis axis,
  773                                     Rectangle2D dataArea,
  774                                     double value) {
  775   
  776           Range range = axis.getRange();
  777           if (!range.contains(value)) {
  778               return;
  779           }
  780   
  781           PlotOrientation orientation = plot.getOrientation();
  782           double v = axis.valueToJava2D(value, dataArea, plot.getRangeAxisEdge());
  783           Line2D line = null;
  784           if (orientation == PlotOrientation.HORIZONTAL) {
  785               line = new Line2D.Double(v, dataArea.getMinY(), v,
  786                       dataArea.getMaxY());
  787           }
  788           else if (orientation == PlotOrientation.VERTICAL) {
  789               line = new Line2D.Double(dataArea.getMinX(), v,
  790                       dataArea.getMaxX(), v);
  791           }
  792   
  793           Paint paint = plot.getRangeGridlinePaint();
  794           if (paint == null) {
  795               paint = CategoryPlot.DEFAULT_GRIDLINE_PAINT;
  796           }
  797           g2.setPaint(paint);
  798   
  799           Stroke stroke = plot.getRangeGridlineStroke();
  800           if (stroke == null) {
  801               stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE;
  802           }
  803           g2.setStroke(stroke);
  804   
  805           g2.draw(line);
  806   
  807       }
  808   
  809       /**
  810        * Draws a marker for the domain axis.
  811        *
  812        * @param g2  the graphics device (not <code>null</code>).
  813        * @param plot  the plot (not <code>null</code>).
  814        * @param axis  the range axis (not <code>null</code>).
  815        * @param marker  the marker to be drawn (not <code>null</code>).
  816        * @param dataArea  the area inside the axes (not <code>null</code>).
  817        *
  818        * @see #drawRangeMarker(Graphics2D, CategoryPlot, ValueAxis, Marker,
  819        *     Rectangle2D)
  820        */
  821       public void drawDomainMarker(Graphics2D g2,
  822                                    CategoryPlot plot,
  823                                    CategoryAxis axis,
  824                                    CategoryMarker marker,
  825                                    Rectangle2D dataArea) {
  826   
  827           Comparable category = marker.getKey();
  828           CategoryDataset dataset = plot.getDataset(plot.getIndexOf(this));
  829           int columnIndex = dataset.getColumnIndex(category);
  830           if (columnIndex < 0) {
  831               return;
  832           }
  833   
  834           final Composite savedComposite = g2.getComposite();
  835           g2.setComposite(AlphaComposite.getInstance(
  836                   AlphaComposite.SRC_OVER, marker.getAlpha()));
  837   
  838           PlotOrientation orientation = plot.getOrientation();
  839           Rectangle2D bounds = null;
  840           if (marker.getDrawAsLine()) {
  841               double v = axis.getCategoryMiddle(columnIndex,
  842                       dataset.getColumnCount(), dataArea,
  843                       plot.getDomainAxisEdge());
  844               Line2D line = null;
  845               if (orientation == PlotOrientation.HORIZONTAL) {
  846                   line = new Line2D.Double(dataArea.getMinX(), v,
  847                           dataArea.getMaxX(), v);
  848               }
  849               else if (orientation == PlotOrientation.VERTICAL) {
  850                   line = new Line2D.Double(v, dataArea.getMinY(), v,
  851                           dataArea.getMaxY());
  852               }
  853               g2.setPaint(marker.getPaint());
  854               g2.setStroke(marker.getStroke());
  855               g2.draw(line);
  856               bounds = line.getBounds2D();
  857           }
  858           else {
  859               double v0 = axis.getCategoryStart(columnIndex,
  860                       dataset.getColumnCount(), dataArea,
  861                       plot.getDomainAxisEdge());
  862               double v1 = axis.getCategoryEnd(columnIndex,
  863                       dataset.getColumnCount(), dataArea,
  864                       plot.getDomainAxisEdge());
  865               Rectangle2D area = null;
  866               if (orientation == PlotOrientation.HORIZONTAL) {
  867                   area = new Rectangle2D.Double(dataArea.getMinX(), v0,
  868                           dataArea.getWidth(), (v1 - v0));
  869               }
  870               else if (orientation == PlotOrientation.VERTICAL) {
  871                   area = new Rectangle2D.Double(v0, dataArea.getMinY(),
  872                           (v1 - v0), dataArea.getHeight());
  873               }
  874               g2.setPaint(marker.getPaint());
  875               g2.fill(area);
  876               bounds = area;
  877           }
  878   
  879           String label = marker.getLabel();
  880           RectangleAnchor anchor = marker.getLabelAnchor();
  881           if (label != null) {
  882               Font labelFont = marker.getLabelFont();
  883               g2.setFont(labelFont);
  884               g2.setPaint(marker.getLabelPaint());
  885               Point2D coordinates = calculateDomainMarkerTextAnchorPoint(
  886                       g2, orientation, dataArea, bounds, marker.getLabelOffset(),
  887                       marker.getLabelOffsetType(), anchor);
  888               TextUtilities.drawAlignedString(label, g2,
  889                       (float) coordinates.getX(), (float) coordinates.getY(),
  890                       marker.getLabelTextAnchor());
  891           }
  892           g2.setComposite(savedComposite);
  893       }
  894   
  895       /**
  896        * Draws a marker for the range axis.
  897        *
  898        * @param g2  the graphics device (not <code>null</code>).
  899        * @param plot  the plot (not <code>null</code>).
  900        * @param axis  the range axis (not <code>null</code>).
  901        * @param marker  the marker to be drawn (not <code>null</code>).
  902        * @param dataArea  the area inside the axes (not <code>null</code>).
  903        *
  904        * @see #drawDomainMarker(Graphics2D, CategoryPlot, CategoryAxis,
  905        *     CategoryMarker, Rectangle2D)
  906        */
  907       public void drawRangeMarker(Graphics2D g2,
  908                                   CategoryPlot plot,
  909                                   ValueAxis axis,
  910                                   Marker marker,
  911                                   Rectangle2D dataArea) {
  912   
  913           if (marker instanceof ValueMarker) {
  914               ValueMarker vm = (ValueMarker) marker;
  915               double value = vm.getValue();
  916               Range range = axis.getRange();
  917   
  918               if (!range.contains(value)) {
  919                   return;
  920               }
  921   
  922               final Composite savedComposite = g2.getComposite();
  923               g2.setComposite(AlphaComposite.getInstance(
  924                       AlphaComposite.SRC_OVER, marker.getAlpha()));
  925   
  926               PlotOrientation orientation = plot.getOrientation();
  927               double v = axis.valueToJava2D(value, dataArea,
  928                       plot.getRangeAxisEdge());
  929               Line2D line = null;
  930               if (orientation == PlotOrientation.HORIZONTAL) {
  931                   line = new Line2D.Double(v, dataArea.getMinY(), v,
  932                           dataArea.getMaxY());
  933               }
  934               else if (orientation == PlotOrientation.VERTICAL) {
  935                   line = new Line2D.Double(dataArea.getMinX(), v,
  936                           dataArea.getMaxX(), v);
  937               }
  938   
  939               g2.setPaint(marker.getPaint());
  940               g2.setStroke(marker.getStroke());
  941               g2.draw(line);
  942   
  943               String label = marker.getLabel();
  944               RectangleAnchor anchor = marker.getLabelAnchor();
  945               if (label != null) {
  946                   Font labelFont = marker.getLabelFont();
  947                   g2.setFont(labelFont);
  948                   g2.setPaint(marker.getLabelPaint());
  949                   Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
  950                           g2, orientation, dataArea, line.getBounds2D(),
  951                           marker.getLabelOffset(), LengthAdjustmentType.EXPAND,
  952                           anchor);
  953                   TextUtilities.drawAlignedString(label, g2,
  954                           (float) coordinates.getX(), (float) coordinates.getY(),
  955                           marker.getLabelTextAnchor());
  956               }
  957               g2.setComposite(savedComposite);
  958           }
  959           else if (marker instanceof IntervalMarker) {
  960               IntervalMarker im = (IntervalMarker) marker;
  961               double start = im.getStartValue();
  962               double end = im.getEndValue();
  963               Range range = axis.getRange();
  964               if (!(range.intersects(start, end))) {
  965                   return;
  966               }
  967   
  968               final Composite savedComposite = g2.getComposite();
  969               g2.setComposite(AlphaComposite.getInstance(
  970                       AlphaComposite.SRC_OVER, marker.getAlpha()));
  971   
  972               double start2d = axis.valueToJava2D(start, dataArea,
  973                       plot.getRangeAxisEdge());
  974               double end2d = axis.valueToJava2D(end, dataArea,
  975                       plot.getRangeAxisEdge());
  976               double low = Math.min(start2d, end2d);
  977               double high = Math.max(start2d, end2d);
  978   
  979               PlotOrientation orientation = plot.getOrientation();
  980               Rectangle2D rect = null;
  981               if (orientation == PlotOrientation.HORIZONTAL) {
  982                   // clip left and right bounds to data area
  983                   low = Math.max(low, dataArea.getMinX());
  984                   high = Math.min(high, dataArea.getMaxX());
  985                   rect = new Rectangle2D.Double(low,
  986                           dataArea.getMinY(), high - low,
  987                           dataArea.getHeight());
  988               }
  989               else if (orientation == PlotOrientation.VERTICAL) {
  990                   // clip top and bottom bounds to data area
  991                   low = Math.max(low, dataArea.getMinY());
  992                   high = Math.min(high, dataArea.getMaxY());
  993                   rect = new Rectangle2D.Double(dataArea.getMinX(),
  994                           low, dataArea.getWidth(),
  995                           high - low);
  996               }
  997               Paint p = marker.getPaint();
  998               if (p instanceof GradientPaint) {
  999                   GradientPaint gp = (GradientPaint) p;
 1000                   GradientPaintTransformer t = im.getGradientPaintTransformer();
 1001                   if (t != null) {
 1002                       gp = t.transform(gp, rect);
 1003                   }
 1004                   g2.setPaint(gp);
 1005               }
 1006               else {
 1007                   g2.setPaint(p);
 1008               }
 1009               g2.fill(rect);
 1010   
 1011               // now draw the outlines, if visible...
 1012               if (im.getOutlinePaint() != null && im.getOutlineStroke() != null) {
 1013                   if (orientation == PlotOrientation.VERTICAL) {
 1014                       Line2D line = new Line2D.Double();
 1015                       double x0 = dataArea.getMinX();
 1016                       double x1 = dataArea.getMaxX();
 1017                       g2.setPaint(im.getOutlinePaint());
 1018                       g2.setStroke(im.getOutlineStroke());
 1019                       if (range.contains(start)) {
 1020                           line.setLine(x0, start2d, x1, start2d);
 1021                           g2.draw(line);
 1022                       }
 1023                       if (range.contains(end)) {
 1024                           line.setLine(x0, end2d, x1, end2d);
 1025                           g2.draw(line);
 1026                       }
 1027                   }
 1028                   else { // PlotOrientation.HORIZONTAL
 1029                       Line2D line = new Line2D.Double();
 1030                       double y0 = dataArea.getMinY();
 1031                       double y1 = dataArea.getMaxY();
 1032                       g2.setPaint(im.getOutlinePaint());
 1033                       g2.setStroke(im.getOutlineStroke());
 1034                       if (range.contains(start)) {
 1035                           line.setLine(start2d, y0, start2d, y1);
 1036                           g2.draw(line);
 1037                       }
 1038                       if (range.contains(end)) {
 1039                           line.setLine(end2d, y0, end2d, y1);
 1040                           g2.draw(line);
 1041                       }
 1042                   }
 1043               }
 1044   
 1045               String label = marker.getLabel();
 1046               RectangleAnchor anchor = marker.getLabelAnchor();
 1047               if (label != null) {
 1048                   Font labelFont = marker.getLabelFont();
 1049                   g2.setFont(labelFont);
 1050                   g2.setPaint(marker.getLabelPaint());
 1051                   Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
 1052                           g2, orientation, dataArea, rect,
 1053                           marker.getLabelOffset(), marker.getLabelOffsetType(),
 1054                           anchor);
 1055                   TextUtilities.drawAlignedString(label, g2,
 1056                           (float) coordinates.getX(), (float) coordinates.getY(),
 1057                           marker.getLabelTextAnchor());
 1058               }
 1059               g2.setComposite(savedComposite);
 1060           }
 1061       }
 1062   
 1063       /**
 1064        * Calculates the (x, y) coordinates for drawing the label for a marker on
 1065        * the range axis.
 1066        *
 1067        * @param g2  the graphics device.
 1068        * @param orientation  the plot orientation.
 1069        * @param dataArea  the data area.
 1070        * @param markerArea  the rectangle surrounding the marker.
 1071        * @param markerOffset  the marker offset.
 1072        * @param labelOffsetType  the label offset type.
 1073        * @param anchor  the label anchor.
 1074        *
 1075        * @return The coordinates for drawing the marker label.
 1076        */
 1077       protected Point2D calculateDomainMarkerTextAnchorPoint(Graphics2D g2,
 1078                                         PlotOrientation orientation,
 1079                                         Rectangle2D dataArea,
 1080                                         Rectangle2D markerArea,
 1081                                         RectangleInsets markerOffset,
 1082                                         LengthAdjustmentType labelOffsetType,
 1083                                         RectangleAnchor anchor) {
 1084   
 1085           Rectangle2D anchorRect = null;
 1086           if (orientation == PlotOrientation.HORIZONTAL) {
 1087               anchorRect = markerOffset.createAdjustedRectangle(markerArea,
 1088                       LengthAdjustmentType.CONTRACT, labelOffsetType);
 1089           }
 1090           else if (orientation == PlotOrientation.VERTICAL) {
 1091               anchorRect = markerOffset.createAdjustedRectangle(markerArea,
 1092                       labelOffsetType, LengthAdjustmentType.CONTRACT);
 1093           }
 1094           return RectangleAnchor.coordinates(anchorRect, anchor);
 1095   
 1096       }
 1097   
 1098       /**
 1099        * Calculates the (x, y) coordinates for drawing a marker label.
 1100        *
 1101        * @param g2  the graphics device.
 1102        * @param orientation  the plot orientation.
 1103        * @param dataArea  the data area.
 1104        * @param markerArea  the rectangle surrounding the marker.
 1105        * @param markerOffset  the marker offset.
 1106        * @param labelOffsetType  the label offset type.
 1107        * @param anchor  the label anchor.
 1108        *
 1109        * @return The coordinates for drawing the marker label.
 1110        */
 1111       protected Point2D calculateRangeMarkerTextAnchorPoint(Graphics2D g2,
 1112                                         PlotOrientation orientation,
 1113                                         Rectangle2D dataArea,
 1114                                         Rectangle2D markerArea,
 1115                                         RectangleInsets markerOffset,
 1116                                         LengthAdjustmentType labelOffsetType,
 1117                                         RectangleAnchor anchor) {
 1118   
 1119           Rectangle2D anchorRect = null;
 1120           if (orientation == PlotOrientation.HORIZONTAL) {
 1121               anchorRect = markerOffset.createAdjustedRectangle(markerArea,
 1122                       labelOffsetType, LengthAdjustmentType.CONTRACT);
 1123           }
 1124           else if (orientation == PlotOrientation.VERTICAL) {
 1125               anchorRect = markerOffset.createAdjustedRectangle(markerArea,
 1126                       LengthAdjustmentType.CONTRACT, labelOffsetType);
 1127           }
 1128           return RectangleAnchor.coordinates(anchorRect, anchor);
 1129   
 1130       }
 1131   
 1132       /**
 1133        * Returns a legend item for a series.  This default implementation will
 1134        * return <code>null</code> if {@link #isSeriesVisible(int)} or
 1135        * {@link #isSeriesVisibleInLegend(int)} returns <code>false</code>.
 1136        *
 1137        * @param datasetIndex  the dataset index (zero-based).
 1138        * @param series  the series index (zero-based).
 1139        *
 1140        * @return The legend item (possibly <code>null</code>).
 1141        *
 1142        * @see #getLegendItems()
 1143        */
 1144       public LegendItem getLegendItem(int datasetIndex, int series) {
 1145   
 1146           CategoryPlot p = getPlot();
 1147           if (p == null) {
 1148               return null;
 1149           }
 1150   
 1151           // check that a legend item needs to be displayed...
 1152           if (!isSeriesVisible(series) || !isSeriesVisibleInLegend(series)) {
 1153               return null;
 1154           }
 1155   
 1156           CategoryDataset dataset = p.getDataset(datasetIndex);
 1157           String label = this.legendItemLabelGenerator.generateLabel(dataset,
 1158                   series);
 1159           String description = label;
 1160           String toolTipText = null;
 1161           if (this.legendItemToolTipGenerator != null) {
 1162               toolTipText = this.legendItemToolTipGenerator.generateLabel(
 1163                       dataset, series);
 1164           }
 1165           String urlText = null;
 1166           if (this.legendItemURLGenerator != null) {
 1167               urlText = this.legendItemURLGenerator.generateLabel(dataset,
 1168                       series);
 1169           }
 1170           Shape shape = lookupSeriesShape(series);
 1171           Paint paint = lookupSeriesPaint(series);
 1172           Paint outlinePaint = lookupSeriesOutlinePaint(series);
 1173           Stroke outlineStroke = lookupSeriesOutlineStroke(series);
 1174   
 1175           LegendItem item = new LegendItem(label, description, toolTipText,
 1176                   urlText, shape, paint, outlineStroke, outlinePaint);
 1177           item.setSeriesKey(dataset.getRowKey(series));
 1178           item.setSeriesIndex(series);
 1179           item.setDataset(dataset);
 1180           item.setDatasetIndex(datasetIndex);
 1181           return item;
 1182       }
 1183   
 1184       /**
 1185        * Tests this renderer for equality with another object.
 1186        *
 1187        * @param obj  the object.
 1188        *
 1189        * @return <code>true</code> or <code>false</code>.
 1190        */
 1191       public boolean equals(Object obj) {
 1192   
 1193           if (obj == this) {
 1194               return true;
 1195           }
 1196           if (!(obj instanceof AbstractCategoryItemRenderer)) {
 1197               return false;
 1198           }
 1199           AbstractCategoryItemRenderer that = (AbstractCategoryItemRenderer) obj;
 1200   
 1201           if (!ObjectUtilities.equal(this.itemLabelGenerator,
 1202                   that.itemLabelGenerator)) {
 1203               return false;
 1204           }
 1205           if (!ObjectUtilities.equal(this.itemLabelGeneratorList,
 1206                   that.itemLabelGeneratorList)) {
 1207               return false;
 1208           }
 1209           if (!ObjectUtilities.equal(this.baseItemLabelGenerator,
 1210                   that.baseItemLabelGenerator)) {
 1211               return false;
 1212           }
 1213           if (!ObjectUtilities.equal(this.toolTipGenerator,
 1214                   that.toolTipGenerator)) {
 1215               return false;
 1216           }
 1217           if (!ObjectUtilities.equal(this.toolTipGeneratorList,
 1218                   that.toolTipGeneratorList)) {
 1219               return false;
 1220           }
 1221           if (!ObjectUtilities.equal(this.baseToolTipGenerator,
 1222                   that.baseToolTipGenerator)) {
 1223               return false;
 1224           }
 1225           if (!ObjectUtilities.equal(this.itemURLGenerator,
 1226                   that.itemURLGenerator)) {
 1227               return false;
 1228           }
 1229           if (!ObjectUtilities.equal(this.itemURLGeneratorList,
 1230                   that.itemURLGeneratorList)) {
 1231               return false;
 1232           }
 1233           if (!ObjectUtilities.equal(this.baseItemURLGenerator,
 1234                   that.baseItemURLGenerator)) {
 1235               return false;
 1236           }
 1237           if (!ObjectUtilities.equal(this.legendItemLabelGenerator,
 1238                   that.legendItemLabelGenerator)) {
 1239               return false;
 1240           }
 1241           if (!ObjectUtilities.equal(this.legendItemToolTipGenerator,
 1242                   that.legendItemToolTipGenerator)) {
 1243               return false;
 1244           }
 1245           if (!ObjectUtilities.equal(this.legendItemURLGenerator,
 1246                   that.legendItemURLGenerator)) {
 1247               return false;
 1248           }
 1249           return super.equals(obj);
 1250       }
 1251   
 1252       /**
 1253        * Returns a hash code for the renderer.
 1254        *
 1255        * @return The hash code.
 1256        */
 1257       public int hashCode() {
 1258           int result = super.hashCode();
 1259           return result;
 1260       }
 1261   
 1262       /**
 1263        * Returns the drawing supplier from the plot.
 1264        *
 1265        * @return The drawing supplier (possibly <code>null</code>).
 1266        */
 1267       public DrawingSupplier getDrawingSupplier() {
 1268           DrawingSupplier result = null;
 1269           CategoryPlot cp = getPlot();
 1270           if (cp != null) {
 1271               result = cp.getDrawingSupplier();
 1272           }
 1273           return result;
 1274       }
 1275   
 1276       /**
 1277        * Draws an item label.
 1278        *
 1279        * @param g2  the graphics device.
 1280        * @param orientation  the orientation.
 1281        * @param dataset  the dataset.
 1282        * @param row  the row.
 1283        * @param column  the column.
 1284        * @param x  the x coordinate (in Java2D space).
 1285        * @param y  the y coordinate (in Java2D space).
 1286        * @param negative  indicates a negative value (which affects the item
 1287        *                  label position).
 1288        */
 1289       protected void drawItemLabel(Graphics2D g2,
 1290                                    PlotOrientation orientation,
 1291                                    CategoryDataset dataset,
 1292                                    int row, int column,
 1293                                    double x, double y,
 1294                                    boolean negative) {
 1295   
 1296           CategoryItemLabelGenerator generator
 1297               = getItemLabelGenerator(row, column);
 1298           if (generator != null) {
 1299               Font labelFont = getItemLabelFont(row, column);
 1300               Paint paint = getItemLabelPaint(row, column);
 1301               g2.setFont(labelFont);
 1302               g2.setPaint(paint);
 1303               String label = generator.generateLabel(dataset, row, column);
 1304               ItemLabelPosition position = null;
 1305               if (!negative) {
 1306                   position = getPositiveItemLabelPosition(row, column);
 1307               }
 1308               else {
 1309                   position = getNegativeItemLabelPosition(row, column);
 1310               }
 1311               Point2D anchorPoint = calculateLabelAnchorPoint(
 1312                       position.getItemLabelAnchor(), x, y, orientation);
 1313               TextUtilities.drawRotatedString(label, g2,
 1314                       (float) anchorPoint.getX(), (float) anchorPoint.getY(),
 1315                       position.getTextAnchor(),
 1316                       position.getAngle(), position.getRotationAnchor());
 1317           }
 1318   
 1319       }
 1320   
 1321       /**
 1322        * Returns an independent copy of the renderer.  The <code>plot</code>
 1323        * reference is shallow copied.
 1324        *
 1325        * @return A clone.
 1326        *
 1327        * @throws CloneNotSupportedException  can be thrown if one of the objects
 1328        *         belonging to the renderer does not support cloning (for example,
 1329        *         an item label generator).
 1330        */
 1331       public Object clone() throws CloneNotSupportedException {
 1332   
 1333           AbstractCategoryItemRenderer clone
 1334               = (AbstractCategoryItemRenderer) super.clone();
 1335   
 1336           if (this.itemLabelGenerator != null) {
 1337               if (this.itemLabelGenerator instanceof PublicCloneable) {
 1338                   PublicCloneable pc = (PublicCloneable) this.itemLabelGenerator;
 1339                   clone.itemLabelGenerator
 1340                           = (CategoryItemLabelGenerator) pc.clone();
 1341               }
 1342               else {
 1343                   throw new CloneNotSupportedException(
 1344                           "ItemLabelGenerator not cloneable.");
 1345               }
 1346           }
 1347   
 1348           if (this.itemLabelGeneratorList != null) {
 1349               clone.itemLabelGeneratorList
 1350                       = (ObjectList) this.itemLabelGeneratorList.clone();
 1351           }
 1352   
 1353           if (this.baseItemLabelGenerator != null) {
 1354               if (this.baseItemLabelGenerator instanceof PublicCloneable) {
 1355                   PublicCloneable pc
 1356                           = (PublicCloneable) this.baseItemLabelGenerator;
 1357                   clone.baseItemLabelGenerator
 1358                           = (CategoryItemLabelGenerator) pc.clone();
 1359               }
 1360               else {
 1361                   throw new CloneNotSupportedException(
 1362                           "ItemLabelGenerator not cloneable.");
 1363               }
 1364           }
 1365   
 1366           if (this.toolTipGenerator != null) {
 1367               if (this.toolTipGenerator instanceof PublicCloneable) {
 1368                   PublicCloneable pc = (PublicCloneable) this.toolTipGenerator;
 1369                   clone.toolTipGenerator = (CategoryToolTipGenerator) pc.clone();
 1370               }
 1371               else {
 1372                   throw new CloneNotSupportedException(
 1373                           "Tool tip generator not cloneable.");
 1374               }
 1375           }
 1376   
 1377           if (this.toolTipGeneratorList != null) {
 1378               clone.toolTipGeneratorList
 1379                       = (ObjectList) this.toolTipGeneratorList.clone();
 1380           }
 1381   
 1382           if (this.baseToolTipGenerator != null) {
 1383               if (this.baseToolTipGenerator instanceof PublicCloneable) {
 1384                   PublicCloneable pc
 1385                           = (PublicCloneable) this.baseToolTipGenerator;
 1386                   clone.baseToolTipGenerator
 1387                           = (CategoryToolTipGenerator) pc.clone();
 1388               }
 1389               else {
 1390                   throw new CloneNotSupportedException(
 1391                           "Base tool tip generator not cloneable.");
 1392               }
 1393           }
 1394   
 1395           if (this.itemURLGenerator != null) {
 1396               if (this.itemURLGenerator instanceof PublicCloneable) {
 1397                   PublicCloneable pc = (PublicCloneable) this.itemURLGenerator;
 1398                   clone.itemURLGenerator = (CategoryURLGenerator) pc.clone();
 1399               }
 1400               else {
 1401                   throw new CloneNotSupportedException(
 1402                           "Item URL generator not cloneable.");
 1403               }
 1404           }
 1405   
 1406           if (this.itemURLGeneratorList != null) {
 1407               clone.itemURLGeneratorList
 1408                       = (ObjectList) this.itemURLGeneratorList.clone();
 1409           }
 1410   
 1411           if (this.baseItemURLGenerator != null) {
 1412               if (this.baseItemURLGenerator instanceof PublicCloneable) {
 1413                   PublicCloneable pc
 1414                           = (PublicCloneable) this.baseItemURLGenerator;
 1415                   clone.baseItemURLGenerator = (CategoryURLGenerator) pc.clone();
 1416               }
 1417               else {
 1418                   throw new CloneNotSupportedException(
 1419                           "Base item URL generator not cloneable.");
 1420               }
 1421           }
 1422   
 1423           if (this.legendItemLabelGenerator instanceof PublicCloneable) {
 1424               clone.legendItemLabelGenerator = (CategorySeriesLabelGenerator)
 1425                       ObjectUtilities.clone(this.legendItemLabelGenerator);
 1426           }
 1427           if (this.legendItemToolTipGenerator instanceof PublicCloneable) {
 1428               clone.legendItemToolTipGenerator = (CategorySeriesLabelGenerator)
 1429                       ObjectUtilities.clone(this.legendItemToolTipGenerator);
 1430           }
 1431           if (this.legendItemURLGenerator instanceof PublicCloneable) {
 1432               clone.legendItemURLGenerator = (CategorySeriesLabelGenerator)
 1433                       ObjectUtilities.clone(this.legendItemURLGenerator);
 1434           }
 1435           return clone;
 1436       }
 1437   
 1438       /**
 1439        * Returns a domain axis for a plot.
 1440        *
 1441        * @param plot  the plot.
 1442        * @param index  the axis index.
 1443        *
 1444        * @return A domain axis.
 1445        */
 1446       protected CategoryAxis getDomainAxis(CategoryPlot plot, int index) {
 1447           CategoryAxis result = plot.getDomainAxis(index);
 1448           if (result == null) {
 1449               result = plot.getDomainAxis();
 1450           }
 1451           return result;
 1452       }
 1453   
 1454       /**
 1455        * Returns a range axis for a plot.
 1456        *
 1457        * @param plot  the plot.
 1458        * @param index  the axis index.
 1459        *
 1460        * @return A range axis.
 1461        */
 1462       protected ValueAxis getRangeAxis(CategoryPlot plot, int index) {
 1463           ValueAxis result = plot.getRangeAxis(index);
 1464           if (result == null) {
 1465               result = plot.getRangeAxis();
 1466           }
 1467           return result;
 1468       }
 1469   
 1470       /**
 1471        * Returns a (possibly empty) collection of legend items for the series
 1472        * that this renderer is responsible for drawing.
 1473        *
 1474        * @return The legend item collection (never <code>null</code>).
 1475        *
 1476        * @see #getLegendItem(int, int)
 1477        */
 1478       public LegendItemCollection getLegendItems() {
 1479           if (this.plot == null) {
 1480               return new LegendItemCollection();
 1481           }
 1482           LegendItemCollection result = new LegendItemCollection();
 1483           int index = this.plot.getIndexOf(this);
 1484           CategoryDataset dataset = this.plot.getDataset(index);
 1485           if (dataset != null) {
 1486               int seriesCount = dataset.getRowCount();
 1487               for (int i = 0; i < seriesCount; i++) {
 1488                   if (isSeriesVisibleInLegend(i)) {
 1489                       LegendItem item = getLegendItem(index, i);
 1490                       if (item != null) {
 1491                           result.add(item);
 1492                       }
 1493                   }
 1494               }
 1495   
 1496           }
 1497           return result;
 1498       }
 1499   
 1500       /**
 1501        * Returns the legend item label generator.
 1502        *
 1503        * @return The label generator (never <code>null</code>).
 1504        *
 1505        * @see #setLegendItemLabelGenerator(CategorySeriesLabelGenerator)
 1506        */
 1507       public CategorySeriesLabelGenerator getLegendItemLabelGenerator() {
 1508           return this.legendItemLabelGenerator;
 1509       }
 1510   
 1511       /**
 1512        * Sets the legend item label generator and sends a
 1513        * {@link RendererChangeEvent} to all registered listeners.
 1514        *
 1515        * @param generator  the generator (<code>null</code> not permitted).
 1516        *
 1517        * @see #getLegendItemLabelGenerator()
 1518        */
 1519       public void setLegendItemLabelGenerator(
 1520               CategorySeriesLabelGenerator generator) {
 1521           if (generator == null) {
 1522               throw new IllegalArgumentException("Null 'generator' argument.");
 1523           }
 1524           this.legendItemLabelGenerator = generator;
 1525           fireChangeEvent();
 1526       }
 1527   
 1528       /**
 1529        * Returns the legend item tool tip generator.
 1530        *
 1531        * @return The tool tip generator (possibly <code>null</code>).
 1532        *
 1533        * @see #setLegendItemToolTipGenerator(CategorySeriesLabelGenerator)
 1534        */
 1535       public CategorySeriesLabelGenerator getLegendItemToolTipGenerator() {
 1536           return this.legendItemToolTipGenerator;
 1537       }
 1538   
 1539       /**
 1540        * Sets the legend item tool tip generator and sends a
 1541        * {@link RendererChangeEvent} to all registered listeners.
 1542        *
 1543        * @param generator  the generator (<code>null</code> permitted).
 1544        *
 1545        * @see #setLegendItemToolTipGenerator(CategorySeriesLabelGenerator)
 1546        */
 1547       public void setLegendItemToolTipGenerator(
 1548               CategorySeriesLabelGenerator generator) {
 1549           this.legendItemToolTipGenerator = generator;
 1550           fireChangeEvent();
 1551       }
 1552   
 1553       /**
 1554        * Returns the legend item URL generator.
 1555        *
 1556        * @return The URL generator (possibly <code>null</code>).
 1557        *
 1558        * @see #setLegendItemURLGenerator(CategorySeriesLabelGenerator)
 1559        */
 1560       public CategorySeriesLabelGenerator getLegendItemURLGenerator() {
 1561           return this.legendItemURLGenerator;
 1562       }
 1563   
 1564       /**
 1565        * Sets the legend item URL generator and sends a
 1566        * {@link RendererChangeEvent} to all registered listeners.
 1567        *
 1568        * @param generator  the generator (<code>null</code> permitted).
 1569        *
 1570        * @see #getLegendItemURLGenerator()
 1571        */
 1572       public void setLegendItemURLGenerator(
 1573               CategorySeriesLabelGenerator generator) {
 1574           this.legendItemURLGenerator = generator;
 1575           fireChangeEvent();
 1576       }
 1577   
 1578       /**
 1579        * Adds an entity with the specified hotspot.
 1580        *
 1581        * @param entities  the entity collection.
 1582        * @param dataset  the dataset.
 1583        * @param row  the row index.
 1584        * @param column  the column index.
 1585        * @param hotspot  the hotspot.
 1586        */
 1587       protected void addItemEntity(EntityCollection entities,
 1588                                    CategoryDataset dataset, int row, int column,
 1589                                    Shape hotspot) {
 1590   
 1591           String tip = null;
 1592           CategoryToolTipGenerator tipster = getToolTipGenerator(row, column);
 1593           if (tipster != null) {
 1594               tip = tipster.generateToolTip(dataset, row, column);
 1595           }
 1596           String url = null;
 1597           CategoryURLGenerator urlster = getItemURLGenerator(row, column);
 1598           if (urlster != null) {
 1599               url = urlster.generateURL(dataset, row, column);
 1600           }
 1601           CategoryItemEntity entity = new CategoryItemEntity(hotspot, tip, url,
 1602                   dataset, dataset.getRowKey(row), dataset.getColumnKey(column));
 1603           entities.add(entity);
 1604   
 1605       }
 1606   
 1607   
 1608   }

Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » renderer » category » [javadoc | source]