net.sf.jasperreports.customizers.shape.AbstractShapeCustomizer.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jasperreports.customizers.shape.AbstractShapeCustomizer.java

Source

/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports 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 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports 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 JasperReports. If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.jasperreports.customizers.shape;

import java.awt.Dimension;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Dimension2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.List;

import org.jfree.chart.plot.XYPlot;

import net.sf.jasperreports.customizers.util.ItemsCounter;
import net.sf.jasperreports.customizers.util.SeriesNameProvider;
import net.sf.jasperreports.engine.JRAbstractChartCustomizer;

/**
 * Abstract customizer that provide the utility methods to work with shapes.
 * 
 * @author Marco Orlandin (dejawho2@users.sourceforge.net)
 */
public abstract class AbstractShapeCustomizer extends JRAbstractChartCustomizer {
    public static final String PROPERTY_SHAPE_WIDTH = "shapeWidth";
    public static final String PROPERTY_SHAPE_HEIGHT = "shapeHeight";
    public static final String PROPERTY_SHAPE_TYPE = "shapeType";
    public static final String PROPERTY_SHAPE_POINTS = "shapePoints";

    protected interface ShapeSetter {
        public void setShape(int seriesIndex, Shape shape);
    }

    class XYPlotSeriesNameProvider implements SeriesNameProvider {
        private final XYPlot xyPlot;

        public XYPlotSeriesNameProvider(XYPlot xyPlot) {
            this.xyPlot = xyPlot;
        }

        @Override
        public String getSeriesName(int index) {
            Comparable<?> key = xyPlot.getDataset().getSeriesKey(index);
            return key == null ? null : String.valueOf(key);
        }
    }

    /**
     * Returns the width of the shape.
     * 
     * @return the width of the shape or null if it is not specified
     */
    protected Integer getWidth() {
        return getIntegerProperty(PROPERTY_SHAPE_WIDTH);
    }

    /**
     * Returns the height of the shape. 
     * 
     * @return the height of the shape or null if it is not specified
     */
    protected Integer getHeight() {
        return getIntegerProperty(PROPERTY_SHAPE_HEIGHT);
    }

    /**
     * Builds the shape from the type and the points read from the respective configuration properties.
     * 
     * @return the Shape or null if the configuration properties are not valid
     */
    protected Shape buildShape() {
        Shape shape = null;

        ShapeTypeEnum shapeType = ShapeTypeEnum.getByName(getProperty(PROPERTY_SHAPE_TYPE));
        if (shapeType != null) {
            switch (shapeType) {
            case ELLIPSE: {
                shape = buildEllipse();
                break;
            }
            case RECTANGLE: {
                shape = buildRectangle();
                break;
            }
            case POLYLINE: {
                String shapePoints = getProperty(PROPERTY_SHAPE_POINTS);
                if (shapePoints != null) {
                    shape = buildPolyline(ShapePoints.decode(shapePoints));
                }
                break;
            }
            case POLYGON: {
                String shapePoints = getProperty(PROPERTY_SHAPE_POINTS);
                if (shapePoints != null) {
                    shape = buildPolygon(ShapePoints.decode(shapePoints));
                }
                break;
            }
            }
        }

        return shape;
    }

    /**
     * Returns the width and height properties defined, if only one is defined it value will be used 
     * also for the other, if they are both undefined it will return null.
     * 
     * @return a size or null if it is undefined
     */
    protected Dimension2D getSize() {
        Integer width = getWidth();
        Integer height = getHeight();
        if (width == null && height == null) {
            return null;
        } else if (width == null) {
            width = height;
        } else if (height == null) {
            height = width;
        }
        return new Dimension(width, height);
    }

    /**
     *
     */
    protected Rectangle2D getBounds(ShapePoints shape) {
        Rectangle2D bounds = null;

        List<Point> points = shape.getPoints();
        if (points != null && !points.isEmpty()) {
            Integer top = null;
            Integer bottom = null;
            Integer left = null;
            Integer right = null;

            for (int i = 0; i < points.size(); i++) {
                Point point = points.get(i);

                if (top == null || point.getY() < top) {
                    top = point.getY();
                }

                if (bottom == null || point.getY() > bottom) {
                    bottom = point.getY();
                }

                if (left == null || point.getX() < left) {
                    left = point.getX();
                }

                if (right == null || point.getX() > right) {
                    right = point.getX();
                }
            }

            bounds = new Rectangle(left, top, right - left, bottom - top);
        }

        return bounds;
    }

    /**
     *
     */
    protected abstract Point getOffset(Dimension2D size);

    /**
     *
     */
    protected abstract Point getOffset(Rectangle2D bounds);

    /**
     * Builds an ellipse shape.
     * 
     * @return the ellipse or null if its size is not specified
     */
    protected Shape buildEllipse() {
        Ellipse2D ellipse = null;
        Dimension2D size = getSize();
        if (size != null) {
            Point offset = getOffset(size);
            ellipse = new Ellipse2D.Float(-offset.getX(), -offset.getY(), (float) size.getWidth(),
                    (float) size.getHeight());
        }
        return ellipse;
    }

    /**
     * Builds a rectangle shape.
     * 
     * @return the rectangle or null if its size is not specified
     */
    protected Shape buildRectangle() {
        Rectangle2D rectangle = null;
        Dimension2D size = getSize();
        if (size != null) {
            Point offset = getOffset(size);
            rectangle = new Rectangle2D.Float(-offset.getX(), -offset.getY(), (float) size.getWidth(),
                    (float) size.getHeight());
        }
        return rectangle;
    }

    /**
     * Builds a polygon shape.
     * 
     * @param shapePoints the points of the polygon
     * @return the polygon or null if it can't be build from the current configuration
     */
    protected Shape buildPolygon(ShapePoints shapePoints) {
        Polygon polygon = null;
        List<Point> points = shapePoints.getPoints();
        if (points != null && !points.isEmpty()) {
            float scaleFactorX = 1.0f;
            float scaleFactorY = 1.0f;

            Rectangle2D bounds = getBounds(shapePoints);
            Integer width = getWidth();
            Integer height = getHeight();
            if (width != null) {
                scaleFactorX = (float) width / (float) bounds.getWidth();
            }
            if (height != null) {
                scaleFactorY = (float) height / (float) bounds.getHeight();
            }

            Point offset = getOffset(bounds);

            int[] pointsX = new int[points.size()];
            int[] pointsY = new int[points.size()];

            for (int i = 0; i < points.size(); i++) {
                Point point = points.get(i);
                pointsX[i] = Math.round((point.getX() - offset.getX()) * scaleFactorX);
                pointsY[i] = Math.round((point.getY() - offset.getY()) * scaleFactorY);
            }

            polygon = new Polygon(pointsX, pointsY, points.size());
        }
        return polygon;
    }

    /**
     * Uses the points to build a polyline
     * 
     * @param baseShape the points of the polyline
     * @return a polyline shape or null if it can't be build from the current configuration
     */
    protected Shape buildPolyline(ShapePoints baseShape) {
        Path2D path = null;
        List<Point> points = baseShape.getPoints();
        if (points != null && !points.isEmpty()) {
            float scaleFactorX = 1.0f;
            float scaleFactorY = 1.0f;

            Rectangle2D bounds = getBounds(baseShape);
            Integer width = getWidth();
            Integer height = getHeight();
            if (width != null) {
                scaleFactorX = (float) (width / bounds.getWidth());
            }
            if (height != null) {
                scaleFactorY = (float) (height / bounds.getHeight());
            }

            path = new Path2D.Double();

            if (points.size() > 1) {
                Point offset = getOffset(bounds);
                Point point = points.get(0);

                path.moveTo((point.getX() - offset.getX()) * scaleFactorX,
                        (point.getY() - offset.getY()) * scaleFactorY);
                for (int i = 1; i < points.size(); i++) {
                    point = points.get(i);
                    path.lineTo((point.getX() - offset.getX()) * scaleFactorX,
                            (point.getY() - offset.getY()) * scaleFactorY);
                }
            }
        }
        return path;
    }

    /**
     * Apply the shaped defined in the configuration to the ShapeSetter in the specified
     * index of the passed parameter
     */
    protected void updateItem(ItemsCounter itemsCounter, ShapeSetter shapeSetter, int index) {
        if (index >= 0 && index < itemsCounter.getCount()) {
            Shape shape = buildShape();
            if (shape != null) {
                shapeSetter.setShape(index, shape);
            }
        }
    }

    /**
     * Update all the items in the collection
     */
    protected void updateItems(ItemsCounter itemsCounter, ShapeSetter shapeSetter) {
        Shape shape = buildShape();
        if (shape != null) {
            for (int i = 0; i < itemsCounter.getCount(); i++) {
                shapeSetter.setShape(i, shape);
            }
        }
    }
}