001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2021, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * ----------------
028 * BlockBorder.java
029 * ----------------
030 * (C) Copyright 2004-2021, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 */
036
037package org.jfree.chart.block;
038
039import java.awt.Color;
040import java.awt.Graphics2D;
041import java.awt.Paint;
042import java.awt.geom.Rectangle2D;
043import java.io.IOException;
044import java.io.ObjectInputStream;
045import java.io.ObjectOutputStream;
046import java.io.Serializable;
047import org.jfree.chart.ui.RectangleInsets;
048import org.jfree.chart.util.PaintUtils;
049import org.jfree.chart.util.Args;
050import org.jfree.chart.util.SerialUtils;
051
052/**
053 * A border for a block.  This class is immutable.
054 */
055public class BlockBorder implements BlockFrame, Serializable {
056
057    /** For serialization. */
058    private static final long serialVersionUID = 4961579220410228283L;
059
060    /** An empty border. */
061    public static final BlockBorder NONE = new BlockBorder(
062            RectangleInsets.ZERO_INSETS, Color.WHITE);
063
064    /** The space reserved for the border. */
065    private RectangleInsets insets;
066
067    /** The border color. */
068    private transient Paint paint;
069
070    /**
071     * Creates a default border.
072     */
073    public BlockBorder() {
074        this(Color.BLACK);
075    }
076
077    /**
078     * Creates a new border with the specified color.
079     *
080     * @param paint  the color ({@code null} not permitted).
081     */
082    public BlockBorder(Paint paint) {
083        this(new RectangleInsets(1, 1, 1, 1), paint);
084    }
085
086    /**
087     * Creates a new border with the specified line widths (in black).
088     *
089     * @param top  the width of the top border.
090     * @param left  the width of the left border.
091     * @param bottom  the width of the bottom border.
092     * @param right  the width of the right border.
093     */
094    public BlockBorder(double top, double left, double bottom, double right) {
095        this(new RectangleInsets(top, left, bottom, right), Color.BLACK);
096    }
097
098    /**
099     * Creates a new border with the specified line widths (in black).
100     *
101     * @param top  the width of the top border.
102     * @param left  the width of the left border.
103     * @param bottom  the width of the bottom border.
104     * @param right  the width of the right border.
105     * @param paint  the border paint ({@code null} not permitted).
106     */
107    public BlockBorder(double top, double left, double bottom, double right,
108                       Paint paint) {
109        this(new RectangleInsets(top, left, bottom, right), paint);
110    }
111
112    /**
113     * Creates a new border.
114     *
115     * @param insets  the border insets ({@code null} not permitted).
116     * @param paint  the paint ({@code null} not permitted).
117     */
118    public BlockBorder(RectangleInsets insets, Paint paint) {
119        Args.nullNotPermitted(insets, "insets");
120        Args.nullNotPermitted(paint, "paint");
121        this.insets = insets;
122        this.paint = paint;
123    }
124
125    /**
126     * Returns the space reserved for the border.
127     *
128     * @return The space (never {@code null}).
129     */
130    @Override
131    public RectangleInsets getInsets() {
132        return this.insets;
133    }
134
135    /**
136     * Returns the paint used to draw the border.
137     *
138     * @return The paint (never {@code null}).
139     */
140    public Paint getPaint() {
141        return this.paint;
142    }
143
144    /**
145     * Draws the border by filling in the reserved space.
146     *
147     * @param g2  the graphics device.
148     * @param area  the area.
149     */
150    @Override
151    public void draw(Graphics2D g2, Rectangle2D area) {
152        // this default implementation will just fill the available
153        // border space with a single color
154        double t = this.insets.calculateTopInset(area.getHeight());
155        double b = this.insets.calculateBottomInset(area.getHeight());
156        double l = this.insets.calculateLeftInset(area.getWidth());
157        double r = this.insets.calculateRightInset(area.getWidth());
158        double x = area.getX();
159        double y = area.getY();
160        double w = area.getWidth();
161        double h = area.getHeight();
162        g2.setPaint(this.paint);
163        Rectangle2D rect = new Rectangle2D.Double();
164        if (t > 0.0) {
165            rect.setRect(x, y, w, t);
166            g2.fill(rect);
167        }
168        if (b > 0.0) {
169            rect.setRect(x, y + h - b, w, b);
170            g2.fill(rect);
171        }
172        if (l > 0.0) {
173            rect.setRect(x, y, l, h);
174            g2.fill(rect);
175        }
176        if (r > 0.0) {
177            rect.setRect(x + w - r, y, r, h);
178            g2.fill(rect);
179        }
180    }
181
182    /**
183     * Tests this border for equality with an arbitrary instance.
184     *
185     * @param obj  the object ({@code null} permitted).
186     *
187     * @return A boolean.
188     */
189    @Override
190    public boolean equals(Object obj) {
191        if (obj == this) {
192            return true;
193        }
194        if (!(obj instanceof BlockBorder)) {
195            return false;
196        }
197        BlockBorder that = (BlockBorder) obj;
198        if (!this.insets.equals(that.insets)) {
199            return false;
200        }
201        if (!PaintUtils.equal(this.paint, that.paint)) {
202            return false;
203        }
204        return true;
205    }
206
207    /**
208     * Provides serialization support.
209     *
210     * @param stream  the output stream.
211     *
212     * @throws IOException  if there is an I/O error.
213     */
214    private void writeObject(ObjectOutputStream stream) throws IOException {
215        stream.defaultWriteObject();
216        SerialUtils.writePaint(this.paint, stream);
217    }
218
219    /**
220     * Provides serialization support.
221     *
222     * @param stream  the input stream.
223     *
224     * @throws IOException  if there is an I/O error.
225     * @throws ClassNotFoundException  if there is a classpath problem.
226     */
227    private void readObject(ObjectInputStream stream)
228        throws IOException, ClassNotFoundException {
229        stream.defaultReadObject();
230        this.paint = SerialUtils.readPaint(stream);
231    }
232
233}