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