Package com.positive.charts.renderer.category

Source Code of com.positive.charts.renderer.category.AbstractCategoryItemRenderer

/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2006, 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. 
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------------------------
* AbstractCategoryItemRenderer.java
* ---------------------------------
* (C) Copyright 2002-2006, by Object Refinery Limited.
*
* Original Author:  David Gilbert (for Object Refinery Limited);
* Contributor(s):   Richard Atkinson;
*
* $Id: AbstractCategoryItemRenderer.java,v 1.1 2007/08/24 12:43:41 slapukhov Exp $
*
* Changes:
* --------
* 29-May-2002 : Version 1 (DG);
* 06-Jun-2002 : Added accessor methods for the tool tip generator (DG);
* 11-Jun-2002 : Made constructors protected (DG);
* 26-Jun-2002 : Added axis to initialise method (DG);
* 05-Aug-2002 : Added urlGenerator member variable plus accessors (RA);
* 22-Aug-2002 : Added categoriesPaint attribute, based on code submitted by
*               Janet Banks.  This can be used when there is only one series,
*               and you want each category item to have a different color (DG);
* 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 29-Oct-2002 : Fixed bug where background image for plot was not being
*               drawn (DG);
* 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG);
* 26-Nov 2002 : Replaced the isStacked() method with getRangeType() (DG);
* 09-Jan-2003 : Renamed grid-line methods (DG);
* 17-Jan-2003 : Moved plot classes into separate package (DG);
* 25-Mar-2003 : Implemented Serializable (DG);
* 12-May-2003 : Modified to take into account the plot orientation (DG);
* 12-Aug-2003 : Very minor javadoc corrections (DB)
* 13-Aug-2003 : Implemented Cloneable (DG);
* 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
* 05-Nov-2003 : Fixed marker rendering bug (833623) (DG);
* 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
* 11-Feb-2004 : Modified labelling for markers (DG);
* 12-Feb-2004 : Updated clone() method (DG);
* 15-Apr-2004 : Created a new CategoryToolTipGenerator interface (DG);
* 05-May-2004 : Fixed bug (948310) where interval markers extend outside axis
*               range (DG);
* 14-Jun-2004 : Fixed bug in drawRangeMarker() method - now uses 'paint' and
*               'stroke' rather than 'outlinePaint' and 'outlineStroke' (DG);
* 15-Jun-2004 : Interval markers can now use GradientPaint (DG);
* 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities
*               --> TextUtilities (DG);
* 01-Oct-2004 : Fixed bug 1029697, problem with label alignment in
*               drawRangeMarker() method (DG);
* 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds() (DG);
* 21-Jan-2005 : Modified return type of calculateRangeMarkerTextAnchorPoint()
*               method (DG);
* 08-Mar-2005 : Fixed positioning of marker labels (DG);
* 20-Apr-2005 : Added legend label, tooltip and URL generators (DG);
* 01-Jun-2005 : Handle one dimension of the marker label adjustment
*               automatically (DG);
* 09-Jun-2005 : Added utility method for adding an item entity (DG);
* ------------- JFREECHART 1.0.x ---------------------------------------------
* 01-Mar-2006 : Updated getLegendItems() to check seriesVisibleInLegend
*               flags (DG);
* 20-Jul-2006 : Set dataset and series indices in LegendItem (DG);
* 23-Oct-2006 : Draw outlines for interval markers (DG);
* 24-Oct-2006 : Respect alpha setting in markers, as suggested by Sergei
*               Ivanov in patch 1567843 (DG);
*              
*/

package com.positive.charts.renderer.category;

import java.io.Serializable;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;

import com.positive.charts.axis.CategoryAxis;
import com.positive.charts.axis.ValueAxis;
import com.positive.charts.block.RectangleInsets;
import com.positive.charts.data.Range;
import com.positive.charts.data.category.CategoryDataset;
import com.positive.charts.data.util.DatasetUtilities;
import com.positive.charts.data.util.ObjectList;
import com.positive.charts.data.util.ObjectUtilities;
import com.positive.charts.data.util.PublicCloneable;
import com.positive.charts.data.util.RectangleAnchor;
import com.positive.charts.entity.CategoryItemEntity;
import com.positive.charts.entity.EntityCollection;
import com.positive.charts.event.RendererChangeEvent;
import com.positive.charts.labels.CategoryItemLabelGenerator;
import com.positive.charts.labels.CategorySeriesLabelGenerator;
import com.positive.charts.labels.CategoryToolTipGenerator;
import com.positive.charts.labels.ItemLabelPosition;
import com.positive.charts.labels.StandardCategorySeriesLabelGenerator;
import com.positive.charts.legend.LegendItem;
import com.positive.charts.legend.LegendItemCollection;
import com.positive.charts.plot.CategoryMarker;
import com.positive.charts.plot.CategoryPlot;
import com.positive.charts.plot.DrawingSupplier;
import com.positive.charts.plot.IntervalMarker;
import com.positive.charts.plot.Marker;
import com.positive.charts.plot.Plot;
import com.positive.charts.plot.PlotOrientation;
import com.positive.charts.plot.PlotRenderingInfo;
import com.positive.charts.plot.ValueMarker;
import com.positive.charts.renderer.AbstractRenderer;
import com.positive.charts.urls.CategoryURLGenerator;
import com.positive.charts.util.GCUtilities;
import com.positive.charts.util.LengthAdjustmentType;
import com.positive.charts.util.Line;
import com.positive.charts.util.RectangleAdapter;
import com.positive.charts.util.RectangleUtil;
import com.positive.charts.util.Stroke;
import com.positive.charts.util.TextUtilities;

/**
* An abstract base class that you can use to implement a new
* {@link CategoryItemRenderer}. When you create a new
* {@link CategoryItemRenderer} you are not required to extend this class, but
* it makes the job easier.
*/
public abstract class AbstractCategoryItemRenderer extends AbstractRenderer
    implements CategoryItemRenderer, Cloneable, PublicCloneable,
    Serializable {

  /** For serialization. */
  private static final long serialVersionUID = 1247553218442497391L;

  /** The plot that the renderer is assigned to. */
  private CategoryPlot plot;

  /** The item label generator for ALL series. */
  private CategoryItemLabelGenerator itemLabelGenerator;

  /** A list of item label generators (one per series). */
  private ObjectList itemLabelGeneratorList;

  /** The base item label generator. */
  private CategoryItemLabelGenerator baseItemLabelGenerator;

  /** The tool tip generator for ALL series. */
  private CategoryToolTipGenerator toolTipGenerator;

  /** A list of tool tip generators (one per series). */
  private ObjectList toolTipGeneratorList;

  /** The base tool tip generator. */
  private CategoryToolTipGenerator baseToolTipGenerator;

  /** The URL generator. */
  private CategoryURLGenerator itemURLGenerator;

  /** A list of item label generators (one per series). */
  private ObjectList itemURLGeneratorList;

  /** The base item label generator. */
  private CategoryURLGenerator baseItemURLGenerator;

  /** The legend item label generator. */
  private CategorySeriesLabelGenerator legendItemLabelGenerator;

  /** The legend item tool tip generator. */
  private CategorySeriesLabelGenerator legendItemToolTipGenerator;

  /** The legend item URL generator. */
  private CategorySeriesLabelGenerator legendItemURLGenerator;

  /** The number of rows in the dataset (temporary record). */
  private transient int rowCount;

  /** The number of columns in the dataset (temporary record). */
  private transient int columnCount;

  /**
   * Creates a new renderer with no tool tip generator and no URL generator.
   * The defaults (no tool tip or URL generators) have been chosen to minimise
   * the processing required to generate a default chart. If you require tool
   * tips or URLs, then you can easily add the required generators.
   */
  protected AbstractCategoryItemRenderer() {
    this.itemLabelGenerator = null;
    this.itemLabelGeneratorList = new ObjectList();
    this.toolTipGenerator = null;
    this.toolTipGeneratorList = new ObjectList();
    this.itemURLGenerator = null;
    this.itemURLGeneratorList = new ObjectList();
    this.legendItemLabelGenerator = new StandardCategorySeriesLabelGenerator();
  }

  /**
   * Adds an entity with the specified hotspot, but only if an entity
   * collection is accessible via the renderer state.
   *
   * @param entities
   *            the entity collection.
   * @param dataset
   *            the dataset.
   * @param row
   *            the row index.
   * @param column
   *            the column index.
   * @param hotspot
   *            the hotspot.
   */
  protected void addItemEntity(final EntityCollection entities,
      final CategoryDataset dataset, final int row, final int column,
      final Region hotspot) {

    String tip = null;
    final CategoryToolTipGenerator tipster = this.getToolTipGenerator(row,
        column);
    if (tipster != null) {
      tip = tipster.generateToolTip(dataset, row, column);
    }
    String url = null;
    final CategoryURLGenerator urlster = this.getItemURLGenerator(row,
        column);
    if (urlster != null) {
      url = urlster.generateURL(dataset, row, column);
    }
    final CategoryItemEntity entity = new CategoryItemEntity(hotspot, tip,
        url, dataset, row, dataset.getColumnKey(column), column);
    entities.add(entity);

  }

  /**
   * Calculates the (x, y) coordinates for drawing the label for a marker on
   * the range axis.
   *
   * @param g2
   *            the graphics device.
   * @param orientation
   *            the plot orientation.
   * @param dataArea
   *            the data area.
   * @param markerArea
   *            the rectangle surrounding the marker.
   * @param markerOffset
   *            the marker offset.
   * @param labelOffsetType
   *            the label offset type.
   * @param anchor
   *            the label anchor.
   *
   * @return The coordinates for drawing the marker label.
   */
  protected Point calculateDomainMarkerTextAnchorPoint(final GC g2,
      final PlotOrientation orientation, final Rectangle dataArea,
      final Rectangle markerArea, final RectangleInsets markerOffset,
      final LengthAdjustmentType labelOffsetType,
      final RectangleAnchor anchor) {

    Rectangle anchorRect = null;
    if (orientation == PlotOrientation.HORIZONTAL) {
      anchorRect = markerOffset.createAdjustedRectangle(markerArea,
          LengthAdjustmentType.CONTRACT, labelOffsetType);
    } else if (orientation == PlotOrientation.VERTICAL) {
      anchorRect = markerOffset.createAdjustedRectangle(markerArea,
          labelOffsetType, LengthAdjustmentType.CONTRACT);
    }
    return RectangleAnchor.coordinates(anchorRect, anchor);

  }

  /**
   * Calculates the (x, y) coordinates for drawing a marker label.
   *
   * @param g2
   *            the graphics device.
   * @param orientation
   *            the plot orientation.
   * @param dataArea
   *            the data area.
   * @param markerArea
   *            the rectangle surrounding the marker.
   * @param markerOffset
   *            the marker offset.
   * @param labelOffsetType
   *            the label offset type.
   * @param anchor
   *            the label anchor.
   *
   * @return The coordinates for drawing the marker label.
   */
  protected Point calculateRangeMarkerTextAnchorPoint(final GC g2,
      final PlotOrientation orientation, final Rectangle dataArea,
      final Rectangle markerArea, final RectangleInsets markerOffset,
      final LengthAdjustmentType labelOffsetType,
      final RectangleAnchor anchor) {

    Rectangle anchorRect = null;
    if (orientation == PlotOrientation.HORIZONTAL) {
      anchorRect = markerOffset.createAdjustedRectangle(markerArea,
          labelOffsetType, LengthAdjustmentType.CONTRACT);
    } else if (orientation == PlotOrientation.VERTICAL) {
      anchorRect = markerOffset.createAdjustedRectangle(markerArea,
          LengthAdjustmentType.CONTRACT, labelOffsetType);
    }
    return RectangleAnchor.coordinates(anchorRect, anchor);

  }

  // ITEM LABEL GENERATOR

  /**
   * Returns an independent copy of the renderer. The <code>plot</code>
   * reference is shallow copied.
   *
   * @return A clone.
   *
   * @throws CloneNotSupportedException
   *             can be thrown if one of the objects belonging to the renderer
   *             does not support cloning (for example, an item label
   *             generator).
   */
  public Object clone() throws CloneNotSupportedException {

    final AbstractCategoryItemRenderer clone = (AbstractCategoryItemRenderer) super
        .clone();

    if (this.itemLabelGenerator != null) {
      if (this.itemLabelGenerator instanceof PublicCloneable) {
        final PublicCloneable pc = (PublicCloneable) this.itemLabelGenerator;
        clone.itemLabelGenerator = (CategoryItemLabelGenerator) pc
            .clone();
      } else {
        throw new CloneNotSupportedException(
            "ItemLabelGenerator not cloneable.");
      }
    }

    if (this.itemLabelGeneratorList != null) {
      clone.itemLabelGeneratorList = (ObjectList) this.itemLabelGeneratorList
          .clone();
    }

    if (this.baseItemLabelGenerator != null) {
      if (this.baseItemLabelGenerator instanceof PublicCloneable) {
        final PublicCloneable pc = (PublicCloneable) this.baseItemLabelGenerator;
        clone.baseItemLabelGenerator = (CategoryItemLabelGenerator) pc
            .clone();
      } else {
        throw new CloneNotSupportedException(
            "ItemLabelGenerator not cloneable.");
      }
    }

    if (this.toolTipGenerator != null) {
      if (this.toolTipGenerator instanceof PublicCloneable) {
        final PublicCloneable pc = (PublicCloneable) this.toolTipGenerator;
        clone.toolTipGenerator = (CategoryToolTipGenerator) pc.clone();
      } else {
        throw new CloneNotSupportedException(
            "Tool tip generator not cloneable.");
      }
    }

    if (this.toolTipGeneratorList != null) {
      clone.toolTipGeneratorList = (ObjectList) this.toolTipGeneratorList
          .clone();
    }

    if (this.baseToolTipGenerator != null) {
      if (this.baseToolTipGenerator instanceof PublicCloneable) {
        final PublicCloneable pc = (PublicCloneable) this.baseToolTipGenerator;
        clone.baseToolTipGenerator = (CategoryToolTipGenerator) pc
            .clone();
      } else {
        throw new CloneNotSupportedException(
            "Base tool tip generator not cloneable.");
      }
    }

    if (this.itemURLGenerator != null) {
      if (this.itemURLGenerator instanceof PublicCloneable) {
        final PublicCloneable pc = (PublicCloneable) this.itemURLGenerator;
        clone.itemURLGenerator = (CategoryURLGenerator) pc.clone();
      } else {
        throw new CloneNotSupportedException(
            "Item URL generator not cloneable.");
      }
    }

    if (this.itemURLGeneratorList != null) {
      clone.itemURLGeneratorList = (ObjectList) this.itemURLGeneratorList
          .clone();
    }

    if (this.baseItemURLGenerator != null) {
      if (this.baseItemURLGenerator instanceof PublicCloneable) {
        final PublicCloneable pc = (PublicCloneable) this.baseItemURLGenerator;
        clone.baseItemURLGenerator = (CategoryURLGenerator) pc.clone();
      } else {
        throw new CloneNotSupportedException(
            "Base item URL generator not cloneable.");
      }
    }

    return clone;
  }

  /**
   * Draws a background for the data area. The default implementation just
   * gets the plot to draw the outline, but some renderers will override this
   * behaviour.
   *
   * @param g2
   *            the graphics device.
   * @param plot
   *            the plot.
   * @param dataArea
   *            the data area.
   */
  public void drawBackground(final GC g2, final CategoryPlot plot,
      final Rectangle dataArea) {

    plot.drawBackground(g2, dataArea);

  }

  /**
   * Draws a grid line against the domain axis.
   * <P>
   * Note that this default implementation assumes that the horizontal axis is
   * the domain axis. If this is not the case, you will need to override this
   * method.
   *
   * @param gc
   *            the graphics device.
   * @param plot
   *            the plot.
   * @param dataArea
   *            the area for plotting data (not yet adjusted for any 3D
   *            effect).
   * @param value
   *            the Java2D value at which the grid line should be drawn.
   */
  public void drawDomainGridline(final GC gc, final CategoryPlot plot,
      final Rectangle dataArea, final double value) {

    Line line = null;
    final PlotOrientation orientation = plot.getOrientation();

    if (orientation == PlotOrientation.HORIZONTAL) {
      line = Line.Double(RectangleUtil.getMinX(dataArea), value,
          RectangleUtil.getMaxX(dataArea), value);
    } else if (orientation == PlotOrientation.VERTICAL) {
      line = Line.Double(value, RectangleUtil.getMinY(dataArea), value,
          RectangleUtil.getMaxY(dataArea));
    }

    Color paint = plot.getDomainGridlinePaint();
    if (paint == null) {
      paint = this.getPlot().getDrawingAssets().getColor(
          CategoryPlot.COLOR_GRIDLINE_PAINT);
    }
    gc.setForeground(paint);

    Stroke stroke = plot.getDomainGridlineStroke();
    if (stroke == null) {
      stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE;
    }
    stroke.set(gc);
    GCUtilities.draw(gc, line);
  }

  /**
   * Draws a marker for the domain axis.
   *
   * @param gc
   *            the graphics device (not <code>null</code>).
   * @param plot
   *            the plot (not <code>null</code>).
   * @param axis
   *            the range axis (not <code>null</code>).
   * @param marker
   *            the marker to be drawn (not <code>null</code>).
   * @param dataArea
   *            the area inside the axes (not <code>null</code>).
   */
  public void drawDomainMarker(final GC gc, final CategoryPlot plot,
      final CategoryAxis axis, final CategoryMarker marker,
      final Rectangle dataArea) {

    final Comparable category = marker.getKey();
    final CategoryDataset dataset = plot.getDataset(plot.getIndexOf(this));
    final int columnIndex = dataset.getColumnIndex(category);
    if (columnIndex < 0) {
      return;
    }

    final int oldAlpha = gc.getAlpha();
    // transparency
    gc.setAlpha(marker.getAlpha());

    final PlotOrientation orientation = plot.getOrientation();
    Rectangle bounds = null;
    if (marker.getDrawAsLine()) {
      final double v = axis.getCategoryMiddle(columnIndex, dataset
          .getColumnCount(), dataArea, plot.getDomainAxisEdge());
      Line line = null;
      if (orientation == PlotOrientation.HORIZONTAL) {

        line = Line.Double(RectangleUtil.getMinX(dataArea), v,
            RectangleUtil.getMaxX(dataArea), v);
      } else if (orientation == PlotOrientation.VERTICAL) {
        line = Line.Double(v, RectangleUtil.getMinY(dataArea), v,
            RectangleUtil.getMaxY(dataArea));
      }
      gc.setForeground(marker.getPaint());
      marker.getStroke().set(gc);
      GCUtilities.draw(gc, line);
      bounds = line.getBounds();
    } else {
      final double v0 = axis.getCategoryStart(columnIndex, dataset
          .getColumnCount(), dataArea, plot.getDomainAxisEdge());
      final double v1 = axis.getCategoryEnd(columnIndex, dataset
          .getColumnCount(), dataArea, plot.getDomainAxisEdge());
      Rectangle area = null;
      if (orientation == PlotOrientation.HORIZONTAL) {
        area = RectangleUtil.Double(RectangleUtil.getMinX(dataArea),
            v0, dataArea.width, (v1 - v0));
      } else if (orientation == PlotOrientation.VERTICAL) {
        area = RectangleUtil.Double(v0,
            RectangleUtil.getMinY(dataArea), (v1 - v0),
            dataArea.height);
      }
      gc.setBackground(marker.getPaint());
      gc.fillRectangle(area);
      bounds = area;
    }

    final String label = marker.getLabel();
    final RectangleAnchor anchor = marker.getLabelAnchor();
    if (label != null) {
      final Font labelFont = marker.getLabelFont();
      gc.setFont(labelFont);
      gc.setForeground(marker.getLabelPaint());
      final Point coordinates = this
          .calculateDomainMarkerTextAnchorPoint(gc, orientation,
              dataArea, bounds, marker.getLabelOffset(), marker
                  .getLabelOffsetType(), anchor);
      TextUtilities.drawAlignedString(label, gc, coordinates.x,
          coordinates.y, marker.getLabelTextAnchor());
    }
    gc.setAlpha(oldAlpha);
  }

  /**
   * Draws an item label.
   *
   * @param g2
   *            the graphics device.
   * @param orientation
   *            the orientation.
   * @param dataset
   *            the dataset.
   * @param row
   *            the row.
   * @param column
   *            the column.
   * @param x
   *            the x coordinate (in Java2D space).
   * @param y
   *            the y coordinate (in Java2D space).
   * @param negative
   *            indicates a negative value (which affects the item label
   *            position).
   */
  protected void drawItemLabel(final GC g2,
      final PlotOrientation orientation, final CategoryDataset dataset,
      final int row, final int column, final double x, final double y,
      final boolean negative) {

    final CategoryItemLabelGenerator generator = this
        .getItemLabelGenerator(row, column);
    if (generator != null) {
      final Font labelFont = this.getItemLabelFont(row, column);
      final Color paint = this.getItemLabelPaint(row, column);
      g2.setFont(labelFont);
      g2.setForeground(paint);
      final String label = generator.generateLabel(dataset, row, column);
      ItemLabelPosition position = null;
      if (!negative) {
        position = this.getPositiveItemLabelPosition(row, column);
      } else {
        position = this.getNegativeItemLabelPosition(row, column);
      }
      final Point anchorPoint = this.calculateLabelAnchorPoint(position
          .getItemLabelAnchor(), (int) (x + 0.5), (int) (y + 0.5),
          orientation);
      TextUtilities.drawRotatedString(label, g2, anchorPoint.x,
          anchorPoint.y, position.getTextAnchor(), position
              .getAngle(), position.getRotationAnchor());
    }

  }

  /**
   * Draws an outline for the data area. The default implementation just gets
   * the plot to draw the outline, but some renderers will override this
   * behaviour.
   *
   * @param g2
   *            the graphics device.
   * @param plot
   *            the plot.
   * @param dataArea
   *            the data area.
   */
  public void drawOutline(final GC g2, final CategoryPlot plot,
      final Rectangle dataArea) {

    plot.drawOutline(g2, dataArea);

  }

  // TOOL TIP GENERATOR

  /**
   * Draws a grid line against the range axis.
   *
   * @param gc
   *            the graphics device.
   * @param plot
   *            the plot.
   * @param axis
   *            the value axis.
   * @param dataArea
   *            the area for plotting data (not yet adjusted for any 3D
   *            effect).
   * @param value
   *            the value at which the grid line should be drawn.
   *
   */
  public void drawRangeGridline(final GC gc, final CategoryPlot plot,
      final ValueAxis axis, final Rectangle dataArea, final double value) {

    final Range range = axis.getRange();
    if (!range.contains(value)) {
      return;
    }

    final PlotOrientation orientation = plot.getOrientation();
    final double v = axis.valueToJava2D(value, dataArea, plot
        .getRangeAxisEdge());
    Line line = null;
    if (orientation == PlotOrientation.HORIZONTAL) {

      line = Line.Double(v, RectangleUtil.getMinY(dataArea), v,
          RectangleUtil.getMaxY(dataArea));
    } else if (orientation == PlotOrientation.VERTICAL) {
      line = Line.Double(RectangleUtil.getMinX(dataArea), v,
          RectangleUtil.getMaxX(dataArea), v);
    }

    Color paint = plot.getRangeGridlinePaint();
    if (paint == null) {
      paint = this.getPlot().getDrawingAssets().getColor(
          CategoryPlot.COLOR_GRIDLINE_PAINT);
    }
    gc.setForeground(paint);

    Stroke stroke = plot.getRangeGridlineStroke();
    if (stroke == null) {
      stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE;
    }
    stroke.set(gc);
    GCUtilities.draw(gc, line);
  }

  /**
   * Draws a marker for the range axis.
   *
   * @param gc
   *            the graphics device (not <code>null</code>).
   * @param plot
   *            the plot (not <code>null</code>).
   * @param axis
   *            the range axis (not <code>null</code>).
   * @param marker
   *            the marker to be drawn (not <code>null</code>).
   * @param dataArea
   *            the area inside the axes (not <code>null</code>).
   */
  public void drawRangeMarker(final GC gc, final CategoryPlot plot,
      final ValueAxis axis, final Marker marker,
      final Rectangle dataAreaRect) {

    final RectangleAdapter dataArea = new RectangleAdapter(dataAreaRect);

    if (marker instanceof ValueMarker) {
      final ValueMarker vm = (ValueMarker) marker;
      final double value = vm.getValue();
      final Range range = axis.getRange();

      if (!range.contains(value)) {
        return;
      }

      // set alpha
      final int oldAlpha = gc.getAlpha();
      gc.setAlpha(marker.getAlpha());

      final PlotOrientation orientation = plot.getOrientation();
      final double v = axis.valueToJava2D(value, dataArea.getRectangle(),
          plot.getRangeAxisEdge());
      Line line = null;
      if (orientation == PlotOrientation.HORIZONTAL) {
        line = Line
            .Double(v, dataArea.getMinY(), v, dataArea.getMaxY());
      } else if (orientation == PlotOrientation.VERTICAL) {
        line = Line
            .Double(dataArea.getMinX(), v, dataArea.getMaxX(), v);
      }

      gc.setForeground(marker.getPaint());
      marker.getStroke().set(gc);
      GCUtilities.draw(gc, line);

      final String label = marker.getLabel();
      final RectangleAnchor anchor = marker.getLabelAnchor();
      if (label != null) {
        final Font labelFont = marker.getLabelFont();
        gc.setFont(labelFont);
        gc.setForeground(marker.getLabelPaint());
        final Point coordinates = this
            .calculateRangeMarkerTextAnchorPoint(gc, orientation,
                dataArea.getRectangle(), line.getBounds(),
                marker.getLabelOffset(),
                LengthAdjustmentType.EXPAND, anchor);
        TextUtilities.drawAlignedString(label, gc, coordinates.x,
            coordinates.y, marker.getLabelTextAnchor());
      }

      gc.setAlpha(oldAlpha);
    } else if (marker instanceof IntervalMarker) {

      final IntervalMarker im = (IntervalMarker) marker;
      final double start = im.getStartValue();
      final double end = im.getEndValue();
      final Range range = axis.getRange();
      if (!(range.intersects(start, end))) {
        return;
      }

      final int oldAlpha = gc.getAlpha();
      gc.setAlpha(marker.getAlpha());

      final double start2d = axis.valueToJava2D(start, dataArea
          .getRectangle(), plot.getRangeAxisEdge());
      final double end2d = axis.valueToJava2D(end, dataArea
          .getRectangle(), plot.getRangeAxisEdge());

      final PlotOrientation orientation = plot.getOrientation();
      Rectangle rect = null;
      if (orientation == PlotOrientation.HORIZONTAL) {
        rect = RectangleUtil.Double(Math.min(start2d, end2d), dataArea
            .getMinY(), Math.abs(end2d - start2d), dataArea
            .getHeight());
      } else if (orientation == PlotOrientation.VERTICAL) {
        rect = RectangleUtil.Double(dataArea.getMinX(), Math.min(
            start2d, end2d), dataArea.getWidth(), Math.abs(end2d
            - start2d));
      }
      final Color p = marker.getPaint();
      gc.setBackground(p);
      gc.fillRectangle(rect);

      // now draw the outlines, if visible...
      if ((im.getOutlinePaint() != null)
          && (im.getOutlineStroke() != null)) {
        final int x0 = RectangleUtil.getMinX(rect);
        final int x1 = RectangleUtil.getMaxX(rect);
        final int y0 = RectangleUtil.getMinY(rect);
        final int y1 = RectangleUtil.getMaxY(rect);
        if (orientation == PlotOrientation.VERTICAL) {
          final Line line = Line.Double(x0, y0, x1, y0);
          gc.setForeground(im.getOutlinePaint());
          im.getOutlineStroke().set(gc);
          GCUtilities.draw(gc, line);
          line.setLine(x0, y1, x1, y1);
          GCUtilities.draw(gc, line);
        } else { // PlotOrientation.HORIZONTAL
          final Line line = Line.Double(x0, y0, x0, y1);
          gc.setForeground(im.getOutlinePaint());
          im.getOutlineStroke().set(gc);
          GCUtilities.draw(gc, line);
          line.setLine(x1, y0, x1, y1);
          GCUtilities.draw(gc, line);
        }
      }

      final String label = marker.getLabel();
      final RectangleAnchor anchor = marker.getLabelAnchor();
      if (label != null) {
        final Font labelFont = marker.getLabelFont();
        gc.setFont(labelFont);
        gc.setForeground(marker.getLabelPaint());
        final Point coordinates = this
            .calculateRangeMarkerTextAnchorPoint(gc, orientation,
                dataArea.getRectangle(), rect, marker
                    .getLabelOffset(), marker
                    .getLabelOffsetType(), anchor);
        TextUtilities.drawAlignedString(label, gc, coordinates.x,
            coordinates.y, marker.getLabelTextAnchor());
      }
      gc.setAlpha(oldAlpha);
    }
  }

  /**
   * Tests this renderer for equality with another object.
   *
   * @param obj
   *            the object.
   *
   * @return <code>true</code> or <code>false</code>.
   */
  public boolean equals(final Object obj) {

    if (obj == this) {
      return true;
    }
    if (!(obj instanceof AbstractCategoryItemRenderer)) {
      return false;
    }
    if (!super.equals(obj)) {
      return false;
    }

    final AbstractCategoryItemRenderer that = (AbstractCategoryItemRenderer) obj;

    if (!ObjectUtilities.equal(this.itemLabelGenerator,
        that.itemLabelGenerator)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.itemLabelGeneratorList,
        that.itemLabelGeneratorList)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.baseItemLabelGenerator,
        that.baseItemLabelGenerator)) {
      return false;
    }
    if (!ObjectUtilities
        .equal(this.toolTipGenerator, that.toolTipGenerator)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.toolTipGeneratorList,
        that.toolTipGeneratorList)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.baseToolTipGenerator,
        that.baseToolTipGenerator)) {
      return false;
    }
    if (!ObjectUtilities
        .equal(this.itemURLGenerator, that.itemURLGenerator)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.itemURLGeneratorList,
        that.itemURLGeneratorList)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.baseItemURLGenerator,
        that.baseItemURLGenerator)) {
      return false;
    }

    return true;

  }

  /**
   * Returns the range of values the renderer requires to display all the
   * items from the specified dataset.
   *
   * @param dataset
   *            the dataset (<code>null</code> permitted).
   *
   * @return The range (or <code>null</code> if the dataset is
   *         <code>null</code> or empty).
   */
  public Range findRangeBounds(final CategoryDataset dataset) {
    return DatasetUtilities.findRangeBounds(dataset);
  }

  /**
   * Returns the base item label generator.
   *
   * @return The generator (possibly <code>null</code>).
   */
  public CategoryItemLabelGenerator getBaseItemLabelGenerator() {
    return this.baseItemLabelGenerator;
  }

  /**
   * Returns the base item URL generator.
   *
   * @return The item URL generator.
   */
  public CategoryURLGenerator getBaseItemURLGenerator() {
    return this.baseItemURLGenerator;
  }

  /**
   * Returns the base tool tip generator (the "layer 2" generator).
   *
   * @return The tool tip generator (possibly <code>null</code>).
   */
  public CategoryToolTipGenerator getBaseToolTipGenerator() {
    return this.baseToolTipGenerator;
  }

  // URL GENERATOR

  /**
   * Returns the number of columns in the dataset. This value is updated in
   * the {@link AbstractCategoryItemRenderer#initialise} method.
   *
   * @return The column count.
   */
  public int getColumnCount() {
    return this.columnCount;
  }

  /**
   * Returns a domain axis for a plot.
   *
   * @param plot
   *            the plot.
   * @param index
   *            the axis index.
   *
   * @return A domain axis.
   */
  protected CategoryAxis getDomainAxis(final CategoryPlot plot,
      final int index) {
    CategoryAxis result = plot.getDomainAxis(index);
    if (result == null) {
      result = plot.getDomainAxis();
    }
    return result;
  }

  /**
   * Returns the drawing supplier from the plot.
   *
   * @return The drawing supplier (possibly <code>null</code>).
   */
  public DrawingSupplier getDrawingSupplier() {
    DrawingSupplier result = null;
    final CategoryPlot cp = this.getPlot();
    if (cp != null) {
      result = cp.getDrawingSupplier();
    }
    return result;
  }

  /**
   * Returns the item label generator for a data item. This implementation
   * simply passes control to the {@link #getSeriesItemLabelGenerator(int)}
   * method. If, for some reason, you want a different generator for
   * individual items, you can override this method.
   *
   * @param row
   *            the row index (zero based).
   * @param column
   *            the column index (zero based).
   *
   * @return The generator (possibly <code>null</code>).
   */
  public CategoryItemLabelGenerator getItemLabelGenerator(final int row,
      final int column) {
    return this.getSeriesItemLabelGenerator(row);
  }

  /**
   * Returns the URL generator for a data item. This method just calls the
   * getSeriesItemURLGenerator method, but you can override this behaviour if
   * you want to.
   *
   * @param row
   *            the row index (zero based).
   * @param column
   *            the column index (zero based).
   *
   * @return The URL generator.
   */
  public CategoryURLGenerator getItemURLGenerator(final int row,
      final int column) {
    return this.getSeriesItemURLGenerator(row);
  }

  /**
   * Returns a legend item for a series.
   *
   * @param datasetIndex
   *            the dataset index (zero-based).
   * @param series
   *            the series index (zero-based).
   *
   * @return The legend item.
   */
  public LegendItem getLegendItem(final int datasetIndex, final int series) {

    final CategoryPlot p = this.getPlot();
    if (p == null) {
      return null;
    }

    CategoryDataset dataset;
    dataset = p.getDataset(datasetIndex);
    final String label = this.legendItemLabelGenerator.generateLabel(
        dataset, series);
    final String description = label;
    String toolTipText = null;
    if (this.legendItemToolTipGenerator != null) {
      toolTipText = this.legendItemToolTipGenerator.generateLabel(
          dataset, series);
    }
    String urlText = null;
    if (this.legendItemURLGenerator != null) {
      urlText = this.legendItemURLGenerator
          .generateLabel(dataset, series);
    }
    final Rectangle shape = this.getSeriesShape(series);
    final Color paint = this.getSeriesPaint(series);
    final Color outlinePaint = this.getSeriesOutlinePaint(series);
    final Stroke outlineStroke = this.getSeriesOutlineStroke(series);

    // this(label, description, toolTipText, urlText,
    // /* shape visible = */ true, shape,

    // /* shape filled = */ true, fillPaint,
    // /* shape outlined = */ true, outlinePaint, outlineStroke,
    // /* line visible */ false, UNUSED_SHAPE, UNUSED_STROKE,
    // Color.black);

    final Color legentItemLinePaint = this.getPlot().getDrawingAssets()
        .getColor(Plot.DEFAULT_LEGEND_ITEM_LINE_COLOR);

    final LegendItem item = new LegendItem(label, description, toolTipText,
        urlText, true, shape, true, paint, true, outlinePaint,
        outlineStroke, false, LegendItem.UNUSED_SHAPE,
        LegendItem.UNUSED_STROKE, legentItemLinePaint);

    item.setSeriesIndex(series);
    item.setDatasetIndex(datasetIndex);
    return item;
  }

  /**
   * Returns the legend item label generator.
   *
   * @return The label generator (never <code>null</code>).
   */
  public CategorySeriesLabelGenerator getLegendItemLabelGenerator() {
    return this.legendItemLabelGenerator;
  }

  /**
   * Returns a (possibly empty) collection of legend items for the series that
   * this renderer is responsible for drawing.
   *
   * @return The legend item collection (never <code>null</code>).
   */
  public LegendItemCollection getLegendItems() {
    if (this.plot == null) {
      return new LegendItemCollection();
    }
    final LegendItemCollection result = new LegendItemCollection();
    final int index = this.plot.getIndexOf(this);
    final CategoryDataset dataset = this.plot.getDataset(index);
    if (dataset != null) {
      final int seriesCount = dataset.getRowCount();
      for (int i = 0; i < seriesCount; i++) {
        if (this.isSeriesVisibleInLegend(i)) {
          final LegendItem item = this.getLegendItem(index, i);
          if (item != null) {
            result.add(item);
          }
        }
      }

    }
    return result;
  }

  /**
   * Returns the legend item tool tip generator.
   *
   * @return The tool tip generator (possibly <code>null</code>).
   */
  public CategorySeriesLabelGenerator getLegendItemToolTipGenerator() {
    return this.legendItemToolTipGenerator;
  }

  /**
   * Returns the legend item URL generator.
   *
   * @return The URL generator (possibly <code>null</code>).
   */
  public CategorySeriesLabelGenerator getLegendItemURLGenerator() {
    return this.legendItemURLGenerator;
  }

  /**
   * Returns the number of passes through the dataset required by the
   * renderer. This method returns <code>1</code>, subclasses should override
   * if they need more passes.
   *
   * @return The pass count.
   */
  public int getPassCount() {
    return 1;
  }

  /**
   * Returns the plot that the renderer has been assigned to (where
   * <code>null</code> indicates that the renderer is not currently assigned
   * to a plot).
   *
   * @return The plot (possibly <code>null</code>).
   */
  public CategoryPlot getPlot() {
    return this.plot;
  }

  /**
   * Returns a range axis for a plot.
   *
   * @param plot
   *            the plot.
   * @param index
   *            the axis index (<code>null</code> for the primary axis).
   *
   * @return A range axis.
   */
  protected ValueAxis getRangeAxis(final CategoryPlot plot, final int index) {
    ValueAxis result = plot.getRangeAxis(index);
    if (result == null) {
      result = plot.getRangeAxis();
    }
    return result;
  }

  /**
   * Returns the number of rows in the dataset. This value is updated in the
   * {@link AbstractCategoryItemRenderer#initialise} method.
   *
   * @return The row count.
   */
  public int getRowCount() {
    return this.rowCount;
  }

  /**
   * Returns the item label generator for a series.
   *
   * @param series
   *            the series index (zero based).
   *
   * @return The generator (possibly <code>null</code>).
   */
  public CategoryItemLabelGenerator getSeriesItemLabelGenerator(
      final int series) {

    // return the generator for ALL series, if there is one...
    if (this.itemLabelGenerator != null) {
      return this.itemLabelGenerator;
    }

    // otherwise look up the generator table
    CategoryItemLabelGenerator generator = (CategoryItemLabelGenerator) this.itemLabelGeneratorList
        .get(series);
    if (generator == null) {
      generator = this.baseItemLabelGenerator;
    }
    return generator;

  }

  /**
   * Returns the URL generator for a series.
   *
   * @param series
   *            the series index (zero based).
   *
   * @return The URL generator for the series.
   */
  public CategoryURLGenerator getSeriesItemURLGenerator(final int series) {

    // return the generator for ALL series, if there is one...
    if (this.itemURLGenerator != null) {
      return this.itemURLGenerator;
    }

    // otherwise look up the generator table
    CategoryURLGenerator generator = (CategoryURLGenerator) this.itemURLGeneratorList
        .get(series);
    if (generator == null) {
      generator = this.baseItemURLGenerator;
    }
    return generator;

  }

  /**
   * Returns the tool tip generator for the specified series (a "layer 1"
   * generator).
   *
   * @param series
   *            the series index (zero-based).
   *
   * @return The tool tip generator (possibly <code>null</code>).
   */
  public CategoryToolTipGenerator getSeriesToolTipGenerator(final int series) {
    return (CategoryToolTipGenerator) this.toolTipGeneratorList.get(series);
  }

  /**
   * Returns the tool tip generator that will be used for ALL items in the
   * dataset (the "layer 0" generator).
   *
   * @return A tool tip generator (possibly <code>null</code>).
   */
  public CategoryToolTipGenerator getToolTipGenerator() {
    return this.toolTipGenerator;
  }

  /**
   * Returns the tool tip generator that should be used for the specified
   * item. This method looks up the generator using the "three-layer" approach
   * outlined in the general description of this interface. You can override
   * this method if you want to return a different generator per item.
   *
   * @param row
   *            the row index (zero-based).
   * @param column
   *            the column index (zero-based).
   *
   * @return The generator (possibly <code>null</code>).
   */
  public CategoryToolTipGenerator getToolTipGenerator(final int row,
      final int column) {

    CategoryToolTipGenerator result = null;
    if (this.toolTipGenerator != null) {
      result = this.toolTipGenerator;
    } else {
      result = this.getSeriesToolTipGenerator(row);
      if (result == null) {
        result = this.baseToolTipGenerator;
      }
    }
    return result;
  }

  /**
   * Returns a hash code for the renderer.
   *
   * @return The hash code.
   */
  public int hashCode() {
    final int result = super.hashCode();
    return result;
  }

  /**
   * Initialises the renderer and returns a state object that will be used for
   * the remainder of the drawing process for a single chart. The state object
   * allows for the fact that the renderer may be used simultaneously by
   * multiple threads (each thread will work with a separate state object).
   * <P>
   * Stores a reference to the {@link PlotRenderingInfo} object (which might
   * be <code>null</code>), and then sets the useCategoriesPaint flag
   * according to the special case conditions a) there is only one series and
   * b) the categoriesPaint array is not null.
   *
   * @param g2
   *            the graphics device.
   * @param dataArea
   *            the data area.
   * @param plot
   *            the plot.
   * @param rendererIndex
   *            the renderer index.
   * @param info
   *            an object for returning information about the structure of the
   *            plot (<code>null</code> permitted).
   *
   * @return The renderer state.
   *
   */
  public CategoryItemRendererState initialise(final GC g2,
      final Rectangle dataArea, final CategoryPlot plot,
      final int rendererIndex, final PlotRenderingInfo info) {

    this.setPlot(plot);
    final CategoryDataset data = plot.getDataset(rendererIndex);
    if (data != null) {
      this.rowCount = data.getRowCount();
      this.columnCount = data.getColumnCount();
    } else {
      this.rowCount = 0;
      this.columnCount = 0;
    }
    return new CategoryItemRendererState(info);

  }

  /**
   * Sets the base item label generator and sends a
   * {@link RendererChangeEvent} to all registered listeners.
   *
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setBaseItemLabelGenerator(
      final CategoryItemLabelGenerator generator) {
    this.baseItemLabelGenerator = generator;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the base item URL generator.
   *
   * @param generator
   *            the item URL generator.
   */
  public void setBaseItemURLGenerator(final CategoryURLGenerator generator) {
    this.baseItemURLGenerator = generator;
  }

  /**
   * Sets the base tool tip generator and sends a
   * {@link org.jfree.chart.event.RendererChangeEvent} to all registered
   * listeners.
   *
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setBaseToolTipGenerator(final CategoryToolTipGenerator generator) {
    this.baseToolTipGenerator = generator;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the item label generator for ALL series and sends a
   * {@link RendererChangeEvent} to all registered listeners.
   *
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setItemLabelGenerator(final CategoryItemLabelGenerator generator) {
    this.itemLabelGenerator = generator;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the item URL generator for ALL series.
   *
   * @param generator
   *            the generator.
   */
  public void setItemURLGenerator(final CategoryURLGenerator generator) {
    this.itemURLGenerator = generator;
  }

  /**
   * Sets the legend item label generator.
   *
   * @param generator
   *            the generator (<code>null</code> not permitted).
   */
  public void setLegendItemLabelGenerator(
      final CategorySeriesLabelGenerator generator) {
    if (generator == null) {
      throw new IllegalArgumentException("Null 'generator' argument.");
    }
    this.legendItemLabelGenerator = generator;
  }

  /**
   * Sets the legend item tool tip generator.
   *
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setLegendItemToolTipGenerator(
      final CategorySeriesLabelGenerator generator) {
    this.legendItemToolTipGenerator = generator;
  }

  /**
   * Sets the legend item URL generator.
   *
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setLegendItemURLGenerator(
      final CategorySeriesLabelGenerator generator) {
    this.legendItemURLGenerator = generator;
  }

  /**
   * Sets the plot that the renderer has been assigned to. This method is
   * usually called by the {@link CategoryPlot}, in normal usage you shouldn't
   * need to call this method directly.
   *
   * @param plot
   *            the plot (<code>null</code> not permitted).
   */
  public void setPlot(final CategoryPlot plot) {
    if (plot == null) {
      throw new IllegalArgumentException("Null 'plot' argument.");
    }
    this.plot = plot;
  }

  /**
   * Sets the item label generator for a series and sends a
   * {@link RendererChangeEvent} to all registered listeners.
   *
   * @param series
   *            the series index (zero based).
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setSeriesItemLabelGenerator(final int series,
      final CategoryItemLabelGenerator generator) {
    this.itemLabelGeneratorList.set(series, generator);
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the URL generator for a series.
   *
   * @param series
   *            the series index (zero based).
   * @param generator
   *            the generator.
   */
  public void setSeriesItemURLGenerator(final int series,
      final CategoryURLGenerator generator) {
    this.itemURLGeneratorList.set(series, generator);
  }

  /**
   * Sets the tool tip generator for a series and sends a
   * {@link org.jfree.chart.event.RendererChangeEvent} to all registered
   * listeners.
   *
   * @param series
   *            the series index (zero-based).
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setSeriesToolTipGenerator(final int series,
      final CategoryToolTipGenerator generator) {
    this.toolTipGeneratorList.set(series, generator);
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the tool tip generator for ALL series and sends a
   * {@link org.jfree.chart.event.RendererChangeEvent} to all registered
   * listeners.
   *
   * @param generator
   *            the generator (<code>null</code> permitted).
   */
  public void setToolTipGenerator(final CategoryToolTipGenerator generator) {
    this.toolTipGenerator = generator;
    this.notifyListeners(new RendererChangeEvent(this));
  }

}
TOP

Related Classes of com.positive.charts.renderer.category.AbstractCategoryItemRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.