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