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    
045    package org.jfree.chart.block;
046    
047    import org.jfree.data.Range;
048    import org.jfree.ui.Size2D;
049    
050    /**
051     * A description of a constraint for resizing a rectangle.  Constraints are
052     * immutable.
053     */
054    public 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    }