001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025     * in the United States and other countries.]
026     *
027     * --------------
028     * AxisSpace.java
029     * --------------
030     * (C) Copyright 2003-2008, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 03-Jul-2003 : Version 1 (DG);
038     * 14-Aug-2003 : Implemented Cloneable (DG);
039     * 18-Aug-2003 : Implemented Serializable (DG);
040     * 17-Mar-2004 : Added a toString() method for debugging (DG);
041     * 07-Jan-2005 : Updated equals() method (DG);
042     * 11-Jan-2005 : Removed deprecated methods in preparation for 1.0.0
043     *               release (DG);
044     *
045     */
046    
047    package org.jfree.chart.axis;
048    
049    import java.awt.geom.Rectangle2D;
050    import java.io.Serializable;
051    
052    import org.jfree.ui.RectangleEdge;
053    import org.jfree.util.PublicCloneable;
054    
055    /**
056     * A record that contains the space required at each edge of a plot.
057     */
058    public class AxisSpace implements Cloneable, PublicCloneable, Serializable {
059    
060        /** For serialization. */
061        private static final long serialVersionUID = -2490732595134766305L;
062    
063        /** The top space. */
064        private double top;
065    
066        /** The bottom space. */
067        private double bottom;
068    
069        /** The left space. */
070        private double left;
071    
072        /** The right space. */
073        private double right;
074    
075        /**
076         * Creates a new axis space record.
077         */
078        public AxisSpace() {
079            this.top = 0.0;
080            this.bottom = 0.0;
081            this.left = 0.0;
082            this.right = 0.0;
083        }
084    
085        /**
086         * Returns the space reserved for axes at the top of the plot area.
087         *
088         * @return The space (in Java2D units).
089         */
090        public double getTop() {
091            return this.top;
092        }
093    
094        /**
095         * Sets the space reserved for axes at the top of the plot area.
096         *
097         * @param space  the space (in Java2D units).
098         */
099        public void setTop(double space) {
100            this.top = space;
101        }
102    
103        /**
104         * Returns the space reserved for axes at the bottom of the plot area.
105         *
106         * @return The space (in Java2D units).
107         */
108        public double getBottom() {
109            return this.bottom;
110        }
111    
112        /**
113         * Sets the space reserved for axes at the bottom of the plot area.
114         *
115         * @param space  the space (in Java2D units).
116         */
117        public void setBottom(double space) {
118            this.bottom = space;
119        }
120    
121        /**
122         * Returns the space reserved for axes at the left of the plot area.
123         *
124         * @return The space (in Java2D units).
125         */
126        public double getLeft() {
127            return this.left;
128        }
129    
130        /**
131         * Sets the space reserved for axes at the left of the plot area.
132         *
133         * @param space  the space (in Java2D units).
134         */
135        public void setLeft(double space) {
136            this.left = space;
137        }
138    
139        /**
140         * Returns the space reserved for axes at the right of the plot area.
141         *
142         * @return The space (in Java2D units).
143         */
144        public double getRight() {
145            return this.right;
146        }
147    
148        /**
149         * Sets the space reserved for axes at the right of the plot area.
150         *
151         * @param space  the space (in Java2D units).
152         */
153        public void setRight(double space) {
154            this.right = space;
155        }
156    
157        /**
158         * Adds space to the top, bottom, left or right edge of the plot area.
159         *
160         * @param space  the space (in Java2D units).
161         * @param edge  the edge (<code>null</code> not permitted).
162         */
163        public void add(double space, RectangleEdge edge) {
164            if (edge == null) {
165                throw new IllegalArgumentException("Null 'edge' argument.");
166            }
167            if (edge == RectangleEdge.TOP) {
168                this.top += space;
169            }
170            else if (edge == RectangleEdge.BOTTOM) {
171                this.bottom += space;
172            }
173            else if (edge == RectangleEdge.LEFT) {
174                this.left += space;
175            }
176            else if (edge == RectangleEdge.RIGHT) {
177                this.right += space;
178            }
179            else {
180                throw new IllegalStateException("Unrecognised 'edge' argument.");
181            }
182        }
183    
184        /**
185         * Ensures that this object reserves at least as much space as another.
186         *
187         * @param space  the other space.
188         */
189        public void ensureAtLeast(AxisSpace space) {
190            this.top = Math.max(this.top, space.top);
191            this.bottom = Math.max(this.bottom, space.bottom);
192            this.left = Math.max(this.left, space.left);
193            this.right = Math.max(this.right, space.right);
194        }
195    
196        /**
197         * Ensures there is a minimum amount of space at the edge corresponding to
198         * the specified axis location.
199         *
200         * @param space  the space.
201         * @param edge  the location.
202         */
203        public void ensureAtLeast(double space, RectangleEdge edge) {
204            if (edge == RectangleEdge.TOP) {
205                if (this.top < space) {
206                    this.top = space;
207                }
208            }
209            else if (edge == RectangleEdge.BOTTOM) {
210                if (this.bottom < space) {
211                    this.bottom = space;
212                }
213            }
214            else if (edge == RectangleEdge.LEFT) {
215                if (this.left < space) {
216                    this.left = space;
217                }
218            }
219            else if (edge == RectangleEdge.RIGHT) {
220                if (this.right < space) {
221                    this.right = space;
222                }
223            }
224            else {
225                throw new IllegalStateException(
226                    "AxisSpace.ensureAtLeast(): unrecognised AxisLocation."
227                );
228            }
229        }
230    
231        /**
232         * Shrinks an area by the space attributes.
233         *
234         * @param area  the area to shrink.
235         * @param result  an optional carrier for the result.
236         *
237         * @return The result.
238         */
239        public Rectangle2D shrink(Rectangle2D area, Rectangle2D result) {
240            if (result == null) {
241                result = new Rectangle2D.Double();
242            }
243            result.setRect(
244                area.getX() + this.left,
245                area.getY() + this.top,
246                area.getWidth() - this.left - this.right,
247                area.getHeight() - this.top - this.bottom
248            );
249            return result;
250        }
251    
252        /**
253         * Expands an area by the amount of space represented by this object.
254         *
255         * @param area  the area to expand.
256         * @param result  an optional carrier for the result.
257         *
258         * @return The result.
259         */
260        public Rectangle2D expand(Rectangle2D area, Rectangle2D result) {
261            if (result == null) {
262                result = new Rectangle2D.Double();
263            }
264            result.setRect(
265                area.getX() - this.left,
266                area.getY() - this.top,
267                area.getWidth() + this.left + this.right,
268                area.getHeight() + this.top + this.bottom
269            );
270            return result;
271        }
272    
273        /**
274         * Calculates the reserved area.
275         *
276         * @param area  the area.
277         * @param edge  the edge.
278         *
279         * @return The reserved area.
280         */
281        public Rectangle2D reserved(Rectangle2D area, RectangleEdge edge) {
282            Rectangle2D result = null;
283            if (edge == RectangleEdge.TOP) {
284                result = new Rectangle2D.Double(
285                    area.getX(), area.getY(), area.getWidth(), this.top
286                );
287            }
288            else if (edge == RectangleEdge.BOTTOM) {
289                result = new Rectangle2D.Double(
290                    area.getX(), area.getMaxY() - this.top,
291                    area.getWidth(), this.bottom
292                );
293            }
294            else if (edge == RectangleEdge.LEFT) {
295                result = new Rectangle2D.Double(
296                    area.getX(), area.getY(), this.left, area.getHeight()
297                );
298            }
299            else if (edge == RectangleEdge.RIGHT) {
300                result = new Rectangle2D.Double(
301                    area.getMaxX() - this.right, area.getY(),
302                    this.right, area.getHeight()
303                );
304            }
305            return result;
306        }
307    
308        /**
309         * Returns a clone of the object.
310         *
311         * @return A clone.
312         *
313         * @throws CloneNotSupportedException This class won't throw this exception,
314         *         but subclasses (if any) might.
315         */
316        public Object clone() throws CloneNotSupportedException {
317            return super.clone();
318        }
319    
320        /**
321         * Tests this object for equality with another object.
322         *
323         * @param obj  the object to compare against.
324         *
325         * @return <code>true</code> or <code>false</code>.
326         */
327        public boolean equals(Object obj) {
328            if (obj == this) {
329                return true;
330            }
331            if (!(obj instanceof AxisSpace)) {
332                return false;
333            }
334            AxisSpace that = (AxisSpace) obj;
335            if (this.top != that.top) {
336                return false;
337            }
338            if (this.bottom != that.bottom) {
339                return false;
340            }
341            if (this.left != that.left) {
342                return false;
343            }
344            if (this.right != that.right) {
345                return false;
346            }
347            return true;
348        }
349    
350        /**
351         * Returns a hash code for this object.
352         *
353         * @return A hash code.
354         */
355        public int hashCode() {
356            int result = 23;
357            long l = Double.doubleToLongBits(this.top);
358            result = 37 * result + (int) (l ^ (l >>> 32));
359            l = Double.doubleToLongBits(this.bottom);
360            result = 37 * result + (int) (l ^ (l >>> 32));
361            l = Double.doubleToLongBits(this.left);
362            result = 37 * result + (int) (l ^ (l >>> 32));
363            l = Double.doubleToLongBits(this.right);
364            result = 37 * result + (int) (l ^ (l >>> 32));
365            return result;
366        }
367    
368        /**
369         * Returns a string representing the object (for debugging purposes).
370         *
371         * @return A string.
372         */
373        public String toString() {
374            return super.toString() + "[left=" + this.left + ",right=" + this.right
375                        + ",top=" + this.top + ",bottom=" + this.bottom + "]";
376        }
377    
378    }