    001/* ===========================================================
    002 * Orson Charts : a 3D chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C)opyright 2013-2016, by Object Refinery Limited.  All rights reserved.
    006 *
    007 * http://www.object-refinery.com/orsoncharts/index.html
    008 *
    009 * This program is free software: you can redistribute it and/or modify
    010 * it under the terms of the GNU General Public License as published by
    011 * the Free Software Foundation, either version 3 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This program is distributed in the hope that it will be useful,
    015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    017 * GNU General Public License for more details.
    018 *
    019 * You should have received a copy of the GNU General Public License
    020 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    021 *
    022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    023 * Other names may be trademarks of their respective owners.]
    024 *
    025 * If you do not wish to be bound by the terms of the GPL, an alternative
    026 * commercial license can be purchased.  For details, please see visit the
    027 * Orson Charts home page:
    028 *
    029 * http://www.object-refinery.com/orsoncharts/index.html
    030 *
    031 */
    032
    033package com.orsoncharts.table;
    034
    035import java.awt.Color;
    036import java.awt.Graphics2D;
    037import java.awt.Insets;
    038import java.awt.Shape;
    039import java.awt.geom.AffineTransform;
    040import java.awt.geom.Dimension2D;
    041import java.awt.geom.Rectangle2D;
    042import java.util.ArrayList;
    043import java.util.List;
    044import java.util.Map;
    045
    046import com.orsoncharts.util.ArgChecks;
    047
    048/**
    049 * A table element that displays a shape.
    050 * <br><br>
    051 * NOTE: This class is serializable, but the serialization format is subject
    052 * to change in future releases and should not be relied upon for persisting
    053 * instances of this class.
    054 */
    055@SuppressWarnings("serial")
    056public class ShapeElement extends AbstractTableElement
    057        implements TableElement {
    058
    059    /**
    060     * The shape (by convention, the shape should be centered on the point
    061     * (0, 0)).
    062     */
    063    private Shape shape;
    064
    065    private Color fillColor;
    066
    067    /**
    068     * Creates a new shape element.
    069     *
    070     * @param shape  the shape ({@code null} not permitted).
    071     * @param fillColor  the fill color ({@code null} not permitted).
    072     */
    073    public ShapeElement(Shape shape, Color fillColor) {
    074        super();
    075        ArgChecks.nullNotPermitted(shape, "shape");
    076        ArgChecks.nullNotPermitted(fillColor, "fillColor");
    077        this.shape = shape;
    078        this.fillColor = fillColor;
    079    }
    080
    081    /**
    082     * Returns the fill color.
    083     *
    084     * @return The fill color.
    085     *
    086     * @since 1.2
    087     */
    088    public Color getFillColor() {
    089        return this.fillColor;
    090    }
    091
    092    /**
    093     * Sets the fill color.
    094     *
    095     * @param color  the fill color ({@code null} not permitted).
    096     *
    097     * @since 1.2
    098     */
    099    public void setFillColor(Color color) {
    100        ArgChecks.nullNotPermitted(color, "color");
    101        this.fillColor = color;
    102    }
    103
    104    @Override
    105    public Dimension2D preferredSize(Graphics2D g2, Rectangle2D bounds,
    106            Map<String, Object> constraints) {
    107        Insets insets = getInsets();
    108        Rectangle2D shapeBounds = shape.getBounds2D();
    109        return new ElementDimension(Math.min(shapeBounds.getWidth()
    110                + insets.left + insets.right, bounds.getWidth()),
    111                Math.min(shapeBounds.getHeight() + insets.top + insets.bottom,
    112                bounds.getHeight()));
    113    }
    114
    115    @Override
    116    public List<Rectangle2D> layoutElements(Graphics2D g2, Rectangle2D bounds,
    117            Map<String, Object> constraints) {
    118        List<Rectangle2D> result = new ArrayList<Rectangle2D>(1);
    119        Insets insets = getInsets();
    120        Rectangle2D shapeBounds = this.shape.getBounds2D();
    121        double w = Math.min(shapeBounds.getWidth() + insets.left + insets.right,
    122                bounds.getWidth());
    123        double h = Math.min(shapeBounds.getHeight() + insets.top
    124                + insets.bottom, bounds.getHeight());
    125        Rectangle2D pos = new Rectangle2D.Double(bounds.getCenterX() - w / 2.0,
    126                bounds.getCenterY() - h / 2.0, w, h);
    127        result.add(pos);
    128        return result;
    129    }
    130
    131    /**
    132     * Draws the shape element within the specified bounds.
    133     *
    134     * @param g2  the graphics target ({@code null} not permitted).
    135     * @param bounds  the bounds ({@code null} not permitted).
    136     */
    137    @Override
    138    public void draw(Graphics2D g2, Rectangle2D bounds) {
    139        draw(g2, bounds, null);
    140    }
    141
    142    /**
    143     * Draws the element within the specified bounds.  If the
    144     * {@code recordBounds} flag is set, this element and each of its
    145     * children will have their {@code BOUNDS_2D} property updated with
    146     * the current bounds.
    147     *
    148     * @param g2  the graphics target ({@code null} not permitted).
    149     * @param bounds  the bounds ({@code null} not permitted).
    150     * @param onDrawHandler  an object that will receive notification before
    151     *     and after the element is drawn ({@code null} permitted).
    152     *
    153     * @since 1.3
    154     */
    155    @Override
    156    public void draw(Graphics2D g2, Rectangle2D bounds,
    157            TableElementOnDraw onDrawHandler) {
    158        if (onDrawHandler != null) {
    159            onDrawHandler.beforeDraw(this, g2, bounds);
    160        }
    161        AffineTransform saved = g2.getTransform();
    162        RectanglePainter background = getBackground();
    163        if (background != null) {
    164            background.fill(g2, bounds);
    165        }
    166        g2.translate(bounds.getCenterX(), bounds.getCenterY());
    167        g2.setPaint(this.fillColor);
    168        g2.fill(shape);
    169        g2.setTransform(saved);
    170        if (onDrawHandler != null) {
    171            onDrawHandler.afterDraw(this, g2, bounds);
    172        }
    173    }
    174
    175    /**
    176     * Receives a visitor.
    177     *
    178     * @param visitor  the visitor ({@code null} not permitted).
    179     *
    180     * @since 1.2
    181     */
    182    @Override
    183    public void receive(TableElementVisitor visitor) {
    184        visitor.visit(this);
    185    }
    186
    187    /**
    188     * Returns a string representation of this element, primarily for
    189     * debugging purposes.
    190     *
    191     * @return A string representation of this element.
    192     */
    193    @Override
    194    public String toString() {
    195        StringBuilder sb = new StringBuilder();
    196        sb.append("ShapeElement[shape=").append(this.shape).append("]");
    197        return sb.toString();
    198    }
    199
    200}