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