001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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-2007, 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}