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 * RectangleConstraint.java
029 * ------------------------
030 * (C) Copyright 2004-2008, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * Changes:
036 * --------
037 * 22-Oct-2004 : Version 1 (DG);
038 * 02-Feb-2005 : Added toString() method (DG);
039 * 08-Feb-2005 : Separated height and width constraints (DG);
040 * 13-May-2005 : Added convenience constructor and new methods for
041 *               transforming constraints (DG);
042 *
043 */
044
045package org.jfree.chart.block;
046
047import org.jfree.data.Range;
048import org.jfree.ui.Size2D;
049
050/**
051 * A description of a constraint for resizing a rectangle.  Constraints are
052 * immutable.
053 */
054public class RectangleConstraint {
055
056    /**
057     * An instance representing no constraint.
058     */
059    public static final RectangleConstraint NONE = new RectangleConstraint(
060            0.0, null, LengthConstraintType.NONE,
061            0.0, null, LengthConstraintType.NONE);
062
063    /** The width. */
064    private double width;
065
066    /** The width range. */
067    private Range widthRange;
068
069    /** The width constraint type. */
070    private LengthConstraintType widthConstraintType;
071
072    /** The fixed or maximum height. */
073    private double height;
074
075    private Range heightRange;
076
077    /** The constraint type. */
078    private LengthConstraintType heightConstraintType;
079
080    /**
081     * Creates a new "fixed width and height" instance.
082     *
083     * @param w  the fixed width.
084     * @param h  the fixed height.
085     */
086    public RectangleConstraint(double w, double h) {
087        this(w, null, LengthConstraintType.FIXED,
088                h, null, LengthConstraintType.FIXED);
089    }
090
091    /**
092     * Creates a new "range width and height" instance.
093     *
094     * @param w  the width range.
095     * @param h  the height range.
096     */
097    public RectangleConstraint(Range w, Range h) {
098        this(0.0, w, LengthConstraintType.RANGE,
099                0.0, h, LengthConstraintType.RANGE);
100    }
101
102    /**
103     * Creates a new constraint with a range for the width and a
104     * fixed height.
105     *
106     * @param w  the width range.
107     * @param h  the fixed height.
108     */
109    public RectangleConstraint(Range w, double h) {
110        this(0.0, w, LengthConstraintType.RANGE,
111                h, null, LengthConstraintType.FIXED);
112    }
113
114    /**
115     * Creates a new constraint with a fixed width and a range for
116     * the height.
117     *
118     * @param w  the fixed width.
119     * @param h  the height range.
120     */
121    public RectangleConstraint(double w, Range h) {
122        this(w, null, LengthConstraintType.FIXED,
123                0.0, h, LengthConstraintType.RANGE);
124    }
125
126    /**
127     * Creates a new constraint.
128     *
129     * @param w  the fixed or maximum width.
130     * @param widthRange  the width range.
131     * @param widthConstraintType  the width type.
132     * @param h  the fixed or maximum height.
133     * @param heightRange  the height range.
134     * @param heightConstraintType  the height type.
135     */
136    public RectangleConstraint(double w, Range widthRange,
137                               LengthConstraintType widthConstraintType,
138                               double h, Range heightRange,
139                               LengthConstraintType heightConstraintType) {
140        if (widthConstraintType == null) {
141            throw new IllegalArgumentException("Null 'widthType' argument.");
142        }
143        if (heightConstraintType == null) {
144            throw new IllegalArgumentException("Null 'heightType' argument.");
145        }
146        this.width = w;
147        this.widthRange = widthRange;
148        this.widthConstraintType = widthConstraintType;
149        this.height = h;
150        this.heightRange = heightRange;
151        this.heightConstraintType = heightConstraintType;
152    }
153
154    /**
155     * Returns the fixed width.
156     *
157     * @return The width.
158     */
159    public double getWidth() {
160        return this.width;
161    }
162
163    /**
164     * Returns the width range.
165     *
166     * @return The range (possibly <code>null</code>).
167     */
168    public Range getWidthRange() {
169        return this.widthRange;
170    }
171
172    /**
173     * Returns the constraint type.
174     *
175     * @return The constraint type (never <code>null</code>).
176     */
177    public LengthConstraintType getWidthConstraintType() {
178        return this.widthConstraintType;
179    }
180
181    /**
182     * Returns the fixed height.
183     *
184     * @return The height.
185     */
186    public double getHeight() {
187        return this.height;
188    }
189
190    /**
191     * Returns the width range.
192     *
193     * @return The range (possibly <code>null</code>).
194     */
195    public Range getHeightRange() {
196        return this.heightRange;
197    }
198
199    /**
200     * Returns the constraint type.
201     *
202     * @return The constraint type (never <code>null</code>).
203     */
204    public LengthConstraintType getHeightConstraintType() {
205        return this.heightConstraintType;
206    }
207
208    /**
209     * Returns a constraint that matches this one on the height attributes,
210     * but has no width constraint.
211     *
212     * @return A new constraint.
213     */
214    public RectangleConstraint toUnconstrainedWidth() {
215        if (this.widthConstraintType == LengthConstraintType.NONE) {
216            return this;
217        }
218        else {
219            return new RectangleConstraint(this.width, this.widthRange,
220                    LengthConstraintType.NONE, this.height, this.heightRange,
221                    this.heightConstraintType);
222        }
223    }
224
225    /**
226     * Returns a constraint that matches this one on the width attributes,
227     * but has no height constraint.
228     *
229     * @return A new constraint.
230     */
231    public RectangleConstraint toUnconstrainedHeight() {
232        if (this.heightConstraintType == LengthConstraintType.NONE) {
233            return this;
234        }
235        else {
236            return new RectangleConstraint(this.width, this.widthRange,
237                    this.widthConstraintType, 0.0, this.heightRange,
238                    LengthConstraintType.NONE);
239        }
240    }
241
242    /**
243     * Returns a constraint that matches this one on the height attributes,
244     * but has a fixed width constraint.
245     *
246     * @param width  the fixed width.
247     *
248     * @return A new constraint.
249     */
250    public RectangleConstraint toFixedWidth(double width) {
251        return new RectangleConstraint(width, this.widthRange,
252                LengthConstraintType.FIXED, this.height, this.heightRange,
253                this.heightConstraintType);
254    }
255
256    /**
257     * Returns a constraint that matches this one on the width attributes,
258     * but has a fixed height constraint.
259     *
260     * @param height  the fixed height.
261     *
262     * @return A new constraint.
263     */
264    public RectangleConstraint toFixedHeight(double height) {
265        return new RectangleConstraint(this.width, this.widthRange,
266                this.widthConstraintType, height, this.heightRange,
267                LengthConstraintType.FIXED);
268    }
269
270    /**
271     * Returns a constraint that matches this one on the height attributes,
272     * but has a range width constraint.
273     *
274     * @param range  the width range (<code>null</code> not permitted).
275     *
276     * @return A new constraint.
277     */
278    public RectangleConstraint toRangeWidth(Range range) {
279        if (range == null) {
280            throw new IllegalArgumentException("Null 'range' argument.");
281        }
282        return new RectangleConstraint(range.getUpperBound(), range,
283                LengthConstraintType.RANGE, this.height, this.heightRange,
284                this.heightConstraintType);
285    }
286
287    /**
288     * Returns a constraint that matches this one on the width attributes,
289     * but has a range height constraint.
290     *
291     * @param range  the height range (<code>null</code> not permitted).
292     *
293     * @return A new constraint.
294     */
295    public RectangleConstraint toRangeHeight(Range range) {
296        if (range == null) {
297            throw new IllegalArgumentException("Null 'range' argument.");
298        }
299        return new RectangleConstraint(this.width, this.widthRange,
300                this.widthConstraintType, range.getUpperBound(), range,
301                LengthConstraintType.RANGE);
302    }
303
304    /**
305     * Returns a string representation of this instance, mostly used for
306     * debugging purposes.
307     *
308     * @return A string.
309     */
310    public String toString() {
311        return "RectangleConstraint["
312                + this.widthConstraintType.toString() + ": width="
313                + this.width + ", height=" + this.height + "]";
314    }
315
316    /**
317     * Returns the new size that reflects the constraints defined by this
318     * instance.
319     *
320     * @param base  the base size.
321     *
322     * @return The constrained size.
323     */
324    public Size2D calculateConstrainedSize(Size2D base) {
325        Size2D result = new Size2D();
326        if (this.widthConstraintType == LengthConstraintType.NONE) {
327            result.width = base.width;
328            if (this.heightConstraintType == LengthConstraintType.NONE) {
329               result.height = base.height;
330            }
331            else if (this.heightConstraintType == LengthConstraintType.RANGE) {
332               result.height = this.heightRange.constrain(base.height);
333            }
334            else if (this.heightConstraintType == LengthConstraintType.FIXED) {
335               result.height = this.height;
336            }
337        }
338        else if (this.widthConstraintType == LengthConstraintType.RANGE) {
339            result.width = this.widthRange.constrain(base.width);
340            if (this.heightConstraintType == LengthConstraintType.NONE) {
341                result.height = base.height;
342            }
343            else if (this.heightConstraintType == LengthConstraintType.RANGE) {
344                result.height = this.heightRange.constrain(base.height);
345            }
346            else if (this.heightConstraintType == LengthConstraintType.FIXED) {
347                result.height = this.height;
348            }
349        }
350        else if (this.widthConstraintType == LengthConstraintType.FIXED) {
351            result.width = this.width;
352            if (this.heightConstraintType == LengthConstraintType.NONE) {
353                result.height = base.height;
354            }
355            else if (this.heightConstraintType == LengthConstraintType.RANGE) {
356                result.height = this.heightRange.constrain(base.height);
357            }
358            else if (this.heightConstraintType == LengthConstraintType.FIXED) {
359                result.height = this.height;
360            }
361        }
362        return result;
363    }
364
365}