001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2022, by David Gilbert 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 * PlotRenderingInfo.java
029 * ----------------------
030 * (C) Copyright 2003-2022, by David Gilbert.
031 *
032 * Original Author:  David Gilbert;
033 * Contributor(s):   -;
034 *
035 */
036
037package org.jfree.chart.plot;
038
039import java.awt.geom.Point2D;
040import java.awt.geom.Rectangle2D;
041import java.io.IOException;
042import java.io.ObjectInputStream;
043import java.io.ObjectOutputStream;
044import java.io.Serializable;
045import java.util.ArrayList;
046import java.util.List;
047import java.util.Objects;
048
049import org.jfree.chart.ChartRenderingInfo;
050import org.jfree.chart.internal.Args;
051import org.jfree.chart.internal.CloneUtils;
052import org.jfree.chart.internal.SerialUtils;
053
054/**
055 * Stores information about the dimensions of a plot and its subplots.
056 */
057public class PlotRenderingInfo implements Cloneable, Serializable {
058
059    /** For serialization. */
060    private static final long serialVersionUID = 8446720134379617220L;
061
062    /** The owner of this info. */
063    private final ChartRenderingInfo owner;
064
065    /** The plot area. */
066    private transient Rectangle2D plotArea;
067
068    /** The data area. */
069    private transient Rectangle2D dataArea;
070
071    /**
072     * Storage for the plot rendering info objects belonging to the subplots.
073     */
074    private List<PlotRenderingInfo> subplotInfo;
075
076    /**
077     * Creates a new instance.
078     *
079     * @param owner  the owner ({@code null} permitted).
080     */
081    public PlotRenderingInfo(ChartRenderingInfo owner) {
082        this.owner = owner;
083        this.dataArea = new Rectangle2D.Double();
084        this.subplotInfo = new ArrayList<>();
085    }
086
087    /**
088     * Returns the owner (as specified in the constructor).
089     *
090     * @return The owner (possibly {@code null}).
091     */
092    public ChartRenderingInfo getOwner() {
093        return this.owner;
094    }
095
096    /**
097     * Returns the plot area (in Java2D space).
098     *
099     * @return The plot area (possibly {@code null}).
100     *
101     * @see #setPlotArea(Rectangle2D)
102     */
103    public Rectangle2D getPlotArea() {
104        return this.plotArea;
105    }
106
107    /**
108     * Sets the plot area.
109     *
110     * @param area  the plot area (in Java2D space, {@code null}
111     *     permitted but discouraged)
112     *
113     * @see #getPlotArea()
114     */
115    public void setPlotArea(Rectangle2D area) {
116        this.plotArea = area;
117    }
118
119    /**
120     * Returns the plot's data area (in Java2D space).
121     *
122     * @return The data area (possibly {@code null}).
123     *
124     * @see #setDataArea(Rectangle2D)
125     */
126    public Rectangle2D getDataArea() {
127        return this.dataArea;
128    }
129
130    /**
131     * Sets the data area.
132     *
133     * @param area  the data area (in Java2D space, {@code null} permitted
134     *     but discouraged).
135     *
136     * @see #getDataArea()
137     */
138    public void setDataArea(Rectangle2D area) {
139        this.dataArea = area;
140    }
141
142    /**
143     * Returns the number of subplots (possibly zero).
144     *
145     * @return The subplot count.
146     */
147    public int getSubplotCount() {
148        return this.subplotInfo.size();
149    }
150
151    /**
152     * Adds the info for a subplot.
153     *
154     * @param info  the subplot info.
155     *
156     * @see #getSubplotInfo(int)
157     */
158    public void addSubplotInfo(PlotRenderingInfo info) {
159        this.subplotInfo.add(info);
160    }
161
162    /**
163     * Returns the info for a subplot.
164     *
165     * @param index  the subplot index.
166     *
167     * @return The info.
168     *
169     * @see #addSubplotInfo(PlotRenderingInfo)
170     */
171    public PlotRenderingInfo getSubplotInfo(int index) {
172        return this.subplotInfo.get(index);
173    }
174
175    /**
176     * Returns the index of the subplot that contains the specified
177     * (x, y) point (the "source" point).  The source point will usually
178     * come from a mouse click on a {@link org.jfree.chart.swing.ChartPanel},
179     * and this method is then used to determine the subplot that
180     * contains the source point.
181     *
182     * @param source  the source point (in Java2D space, {@code null} not
183     * permitted).
184     *
185     * @return The subplot index (or -1 if no subplot contains {@code source}).
186     */
187    public int getSubplotIndex(Point2D source) {
188        Args.nullNotPermitted(source, "source");
189        int subplotCount = getSubplotCount();
190        for (int i = 0; i < subplotCount; i++) {
191            PlotRenderingInfo info = getSubplotInfo(i);
192            Rectangle2D area = info.getDataArea();
193            if (area.contains(source)) {
194                return i;
195            }
196        }
197        return -1;
198    }
199
200    /**
201     * Tests this instance for equality against an arbitrary object.
202     *
203     * @param obj  the object ({@code null} permitted).
204     *
205     * @return A boolean.
206     */
207    @Override
208    public boolean equals(Object obj) {
209        if (this == obj) {
210            return true;
211        }
212        if (!(obj instanceof PlotRenderingInfo)) {
213            return false;
214        }
215        PlotRenderingInfo that = (PlotRenderingInfo) obj;
216        if (!Objects.equals(this.dataArea, that.dataArea)) {
217            return false;
218        }
219        if (!Objects.equals(this.plotArea, that.plotArea)) {
220            return false;
221        }
222        if (!Objects.equals(this.subplotInfo, that.subplotInfo)) {
223            return false;
224        }
225        return true;
226    }
227
228    @Override
229    public int hashCode()
230    {
231        int hash = 5;
232        hash = 53 * hash + Objects.hashCode(this.plotArea);
233        hash = 53 * hash + Objects.hashCode(this.dataArea);
234        hash = 53 * hash + Objects.hashCode(this.subplotInfo);
235        return hash;
236    }
237
238    /**
239     * Returns a clone of this object.
240     *
241     * @return A clone.
242     *
243     * @throws CloneNotSupportedException if there is a problem cloning.
244     */
245    @Override
246    public Object clone() throws CloneNotSupportedException {
247        PlotRenderingInfo clone = (PlotRenderingInfo) super.clone();
248        if (this.plotArea != null) {
249            clone.plotArea = (Rectangle2D) this.plotArea.clone();
250        }
251        if (this.dataArea != null) {
252            clone.dataArea = (Rectangle2D) this.dataArea.clone();
253        }
254        clone.subplotInfo = new ArrayList<>(this.subplotInfo.size());
255        for (int i = 0; i < this.subplotInfo.size(); i++) {
256            clone.subplotInfo.add(CloneUtils.clone(this.subplotInfo.get(i)));
257        }
258        return clone;
259    }
260
261    /**
262     * Provides serialization support.
263     *
264     * @param stream  the output stream.
265     *
266     * @throws IOException  if there is an I/O error.
267     */
268    private void writeObject(ObjectOutputStream stream) throws IOException {
269        stream.defaultWriteObject();
270        SerialUtils.writeShape(this.dataArea, stream);
271        SerialUtils.writeShape(this.plotArea, stream);
272    }
273
274    /**
275     * Provides serialization support.
276     *
277     * @param stream  the input stream.
278     *
279     * @throws IOException  if there is an I/O error.
280     * @throws ClassNotFoundException  if there is a classpath problem.
281     */
282    private void readObject(ObjectInputStream stream)
283            throws IOException, ClassNotFoundException {
284        stream.defaultReadObject();
285        this.dataArea = (Rectangle2D) SerialUtils.readShape(stream);
286        this.plotArea = (Rectangle2D) SerialUtils.readShape(stream);
287    }
288
289}