001/* ===========================================================
002 * Orson Charts : a 3D chart library for the Java(tm) platform
003 * ===========================================================
004 * 
005 * (C)opyright 2013-2022, by David Gilbert.  All rights reserved.
006 * 
007 * https://github.com/jfree/orson-charts
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 org.jfree.chart3d.table;
034
035import java.awt.Dimension;
036import java.awt.Image;
037import java.awt.Graphics2D;
038import java.awt.Paint;
039import java.awt.geom.Rectangle2D;
040import java.io.Serializable;
041import java.io.IOException;
042import java.io.ObjectInputStream;
043import java.io.ObjectOutputStream;
044
045import org.jfree.chart3d.graphics2d.Anchor2D;
046import org.jfree.chart3d.graphics2d.Fit2D;
047import org.jfree.chart3d.graphics2d.Scale2D;
048import org.jfree.chart3d.internal.Args;
049import org.jfree.chart3d.internal.ObjectUtils;
050import org.jfree.chart3d.internal.SerialUtils;
051
052
053/**
054 * A {@link RectanglePainter} that fills the rectangle with a 
055 * color or image.  Instances of this class are immutable.
056 * <br><br>
057 * Note that it is possible to use gradient paint with this painter, but it is
058 * usually better to use {@link GradientRectanglePainter} since it provides
059 * options to transform the gradient to fit the chart background size.
060 * <br><br>
061 * NOTE: This class is serializable, but the serialization format is subject 
062 * to change in future releases and should not be relied upon for persisting 
063 * instances of this class.
064 */
065@SuppressWarnings("serial")
066public class StandardRectanglePainter implements RectanglePainter, 
067        Serializable {
068    
069    /** The paint (never {@code null}). */
070    private transient Paint paint;
071    
072    /** A background image for the chart, if any. */
073    private transient Image image;
074    
075    private Fit2D imageFit;
076    
077    /**
078     * Creates a new painter that will fill a rectangle with the specified
079     * paint.
080     * 
081     * @param paint  the fill paint ({@code null} not permitted).
082     */
083    public StandardRectanglePainter(Paint paint) {
084        this(paint, null, null);
085    }
086    
087    /**
088     * Creates a new painter that will draw an image within the specified
089     * rectangle.
090     * 
091     * @param paint  the background paint ({@code null} not permitted).
092     * @param image  the image ({@code null} permitted).
093     * @param imageFit  the fit ({@code null} permitted).
094     */
095    public StandardRectanglePainter(Paint paint, Image image, Fit2D imageFit) {
096        Args.nullNotPermitted(paint, "paint");
097        this.paint = paint;
098        this.image = image;
099        this.imageFit = new Fit2D(Anchor2D.TOP_CENTER, Scale2D.SCALE_BOTH);
100        if (imageFit != null) {
101            this.imageFit = imageFit;
102        }
103    }
104
105    /**
106     * Returns the paint that will be used to fill rectangles.
107     * 
108     * @return The paint (never {@code null}).
109     */
110    public Paint getPaint() {
111        return this.paint;
112    }
113    
114    /**
115     * Returns the image.
116     * 
117     * @return The image (possibly {@code null}). 
118     */
119    public Image getImage() {
120        return this.image;
121    }
122    
123    /**
124     * Returns the image fit specification.
125     * 
126     * @return The image fit specification. 
127     */
128    public Fit2D getImageFit() {
129        return this.imageFit;
130    }
131    
132    /**
133     * Fills the rectangle with the paint specified in the constructor.
134     * 
135     * @param g2  the graphics target ({@code null} not permitted).
136     * @param bounds  the rectangle ({@code null} not permitted).
137     */
138    @Override
139    public void fill(Graphics2D g2, Rectangle2D bounds) {
140        Paint saved = g2.getPaint();
141        g2.setPaint(this.paint);
142        g2.fill(bounds);
143        if (this.image != null) {
144            int w = this.image.getWidth(null);
145            int h = this.image.getHeight(null);
146            Rectangle2D imageBounds = this.imageFit.fit(new Dimension(w, h), 
147                    bounds);
148            g2.drawImage(this.image, (int) imageBounds.getX(), 
149                    (int) imageBounds.getY(), (int) imageBounds.getWidth(),
150                    (int) imageBounds.getHeight(), null);
151        }
152        g2.setPaint(saved);
153    }
154
155    /**
156     * Tests this painter for equality with an arbitrary object.
157     * 
158     * @param obj  the object ({@code null} permitted).
159     * 
160     * @return A boolean. 
161     */
162    @Override
163    public boolean equals(Object obj) {
164        if (obj == this) {
165            return true;
166        }
167        if (!(obj instanceof StandardRectanglePainter)) {
168            return false;
169        }
170        StandardRectanglePainter that = (StandardRectanglePainter) obj;
171        if (!ObjectUtils.equalsPaint(this.paint, that.paint)) {
172            return false;
173        }
174        return true;
175    }
176    
177    /**
178     * Provides serialization support.
179     *
180     * @param stream  the output stream.
181     *
182     * @throws IOException  if there is an I/O error.
183     */
184    private void writeObject(ObjectOutputStream stream) throws IOException {
185        stream.defaultWriteObject();
186        SerialUtils.writePaint(this.paint, stream);
187        // TODO : serialize the image 
188    }
189
190    /**
191     * Provides serialization support.
192     *
193     * @param stream  the input stream.
194     *
195     * @throws IOException  if there is an I/O error.
196     * @throws ClassNotFoundException  if there is a classpath problem.
197     */
198    private void readObject(ObjectInputStream stream)
199        throws IOException, ClassNotFoundException {
200        stream.defaultReadObject();
201        this.paint = SerialUtils.readPaint(stream);
202        // deserialize the image
203    }
204}