001/*
002 * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003 *
004 * Redistribution and use in source and binary forms, with or without
005 * modification, are permitted provided that the following conditions are met:
006 *
007 *  o Redistributions of source code must retain the above copyright notice,
008 *    this list of conditions and the following disclaimer.
009 *
010 *  o Redistributions in binary form must reproduce the above copyright notice,
011 *    this list of conditions and the following disclaimer in the documentation
012 *    and/or other materials provided with the distribution.
013 *
014 *  o Neither the name of JGoodies Karsten Lentzsch nor the names of
015 *    its contributors may be used to endorse or promote products derived
016 *    from this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030
031package com.jgoodies.forms.layout;
032
033import java.awt.Component;
034import java.awt.Container;
035import java.io.Serializable;
036import java.util.Iterator;
037import java.util.List;
038
039import com.jgoodies.forms.util.DefaultUnitConverter;
040import com.jgoodies.forms.util.UnitConverter;
041
042/**
043 * Consists only of static methods that create and convert sizes
044 * as required by the FormLayout. The conversion of sizes
045 * that are not based on pixel is delegated to an implementation
046 * of {@link UnitConverter}. The conversion methods require the
047 * layout container as parameter to read its current font and resolution.
048 *
049 * @author  Karsten Lentzsch
050 * @version $Revision$
051 *
052 * @see     Size
053 * @see     UnitConverter
054 * @see     DefaultUnitConverter
055 */
056public final class Sizes {
057
058    // Common Constant Sizes ************************************************
059
060    public static final ConstantSize ZERO = pixel(0);
061
062    public static final ConstantSize DLUX1 = dluX(1);
063    public static final ConstantSize DLUX2 = dluX(2);
064    public static final ConstantSize DLUX3 = dluX(3);
065    public static final ConstantSize DLUX4 = dluX(4);
066    public static final ConstantSize DLUX5 = dluX(5);
067    public static final ConstantSize DLUX6 = dluX(6);
068    public static final ConstantSize DLUX7 = dluX(7);
069    public static final ConstantSize DLUX8 = dluX(8);
070    public static final ConstantSize DLUX9 = dluX(9);
071    public static final ConstantSize DLUX11 = dluX(11);
072    public static final ConstantSize DLUX14 = dluX(14);
073
074    public static final ConstantSize DLUY1 = dluY(1);
075    public static final ConstantSize DLUY2 = dluY(2);
076    public static final ConstantSize DLUY3 = dluY(3);
077    public static final ConstantSize DLUY4 = dluY(4);
078    public static final ConstantSize DLUY5 = dluY(5);
079    public static final ConstantSize DLUY6 = dluY(6);
080    public static final ConstantSize DLUY7 = dluY(7);
081    public static final ConstantSize DLUY8 = dluY(8);
082    public static final ConstantSize DLUY9 = dluY(9);
083    public static final ConstantSize DLUY11 = dluY(11);
084    public static final ConstantSize DLUY14 = dluY(14);
085
086    // Static Component Sizes ***********************************************
087
088    /**
089     * Use the maximum of all component minimum sizes as column or row size.
090     */
091    public static final ComponentSize MINIMUM = new ComponentSize("minimum");
092
093    /**
094     * Use the maximum of all component preferred sizes as column or row size.
095     */
096    public static final ComponentSize PREFERRED = new ComponentSize(
097            "preferred");
098
099    /**
100     * Use the maximum of all component sizes as column or row size;
101     * measures preferred sizes when asked for the preferred size
102     * and minimum sizes when asked for the minimum size.
103     */
104    public static final ComponentSize DEFAULT = new ComponentSize("default");
105
106    /**
107     * An array of all enumeration values used to canonicalize
108     * deserialized component sizes.
109     */
110    private static final ComponentSize[] VALUES = { MINIMUM, PREFERRED,
111            DEFAULT };
112
113    // Singleton State *******************************************************
114
115    /**
116     * Holds the current converter that maps non-pixel sizes to pixels.
117     */
118    private static UnitConverter unitConverter;
119
120    // Instance Creation ******************************************************
121
122    private Sizes() {
123        // Suppresses default constructor, ensuring non-instantiability.
124    }
125
126    // Creation of Size Instances *********************************************
127
128    /**
129     * Creates and returns an instance of <code>ConstantSize</code> from the
130     * given encoded size and unit description.
131     *
132     * @param encodedValueAndUnit  value and unit in string representation
133     * @param horizontal                        true for horizontal, false for vertical
134     * @return a <code>ConstantSize</code> for the given value and unit
135     */
136    public static ConstantSize constant(String encodedValueAndUnit,
137            boolean horizontal) {
138        return ConstantSize.valueOf(encodedValueAndUnit, horizontal);
139    }
140
141    /**
142     * Creates and returns a ConstantSize for the specified value
143     * in horizontal dialog units.
144     *
145     * @param value        size value in horizontal dialog units
146     * @return the associated <code>ConstantSize</code>
147     */
148    public static ConstantSize dluX(int value) {
149        return ConstantSize.dluX(value);
150    }
151
152    /**
153     * Creates and returns a ConstantSize for the specified value
154     * in vertical dialog units.
155     *
156     * @param value         size value in vertical dialog units
157     * @return the associated <code>ConstantSize</code>
158     */
159    public static ConstantSize dluY(int value) {
160        return ConstantSize.dluY(value);
161    }
162
163    /**
164     * Creates and returns a ConstantSize
165     * for the specified pixel value.
166     *
167     * @param value  value in pixel
168     * @return the associated <code>ConstantSize</code>
169     */
170    public static ConstantSize pixel(int value) {
171        return new ConstantSize(value, ConstantSize.PIXEL);
172    }
173
174    /**
175     * Creates and returns a BoundedSize for the given basis
176     * using the specified lower and upper bounds.
177     *
178     * @param basis                  the base size
179     * @param lowerBound          the lower bound size
180     * @param upperBound          the upper bound size
181     * @return a <code>BoundedSize</code> for the given basis and bounds
182     * @exception NullPointerException if basis is null
183     */
184    public static Size bounded(Size basis, Size lowerBound, Size upperBound) {
185        return new BoundedSize(basis, lowerBound, upperBound);
186    }
187
188    // Unit Conversion ******************************************************
189
190    /**
191     * Converts Inches and returns pixels using the specified resolution.
192     *
193     * @param in           the Inches
194     * @param component    the component that provides the graphics object
195     * @return the given Inches as pixels
196     */
197    public static int inchAsPixel(double in, Component component) {
198        return in == 0d ? 0 : getUnitConverter().inchAsPixel(in, component);
199    }
200
201    /**
202     * Converts Millimeters and returns pixels using the resolution of the
203     * given component's graphics object.
204     *
205     * @param mm                Millimeters
206     * @param component    the component that provides the graphics object
207     * @return the given Millimeters as pixels
208     */
209    public static int millimeterAsPixel(double mm, Component component) {
210        return mm == 0d ? 0
211                : getUnitConverter().millimeterAsPixel(mm, component);
212    }
213
214    /**
215     * Converts Centimeters and returns pixels using the resolution of the
216     * given component's graphics object.
217     *
218     * @param cm                Centimeters
219     * @param component    the component that provides the graphics object
220     * @return the given Centimeters as pixels
221     */
222    public static int centimeterAsPixel(double cm, Component component) {
223        return cm == 0d ? 0
224                : getUnitConverter().centimeterAsPixel(cm, component);
225    }
226
227    /**
228     * Converts DTP Points and returns pixels using the resolution of the
229     * given component's graphics object.
230     *
231     * @param pt                DTP Points
232     * @param component    the component that provides the graphics object
233     * @return the given Points as pixels
234     */
235    public static int pointAsPixel(int pt, Component component) {
236        return pt == 0 ? 0 : getUnitConverter().pointAsPixel(pt, component);
237    }
238
239    /**
240     * Converts horizontal dialog units and returns pixels.
241     * Honors the resolution, dialog font size, platform, and l&amp;f.
242     *
243     * @param dluX         the horizontal dialog units
244     * @param component    the component that provides the graphics object
245     * @return the given horizontal dialog units as pixels
246     */
247    public static int dialogUnitXAsPixel(int dluX, Component component) {
248        return dluX == 0 ? 0
249                : getUnitConverter().dialogUnitXAsPixel(dluX, component);
250    }
251
252    /**
253     * Converts vertical dialog units and returns pixels.
254     * Honors the resolution, dialog font size, platform, and l&amp;f.
255     *
256     * @param dluY         the vertical dialog units
257     * @param component    the component that provides the graphics object
258     * @return the given vertical dialog units as pixels
259     */
260    public static int dialogUnitYAsPixel(int dluY, Component component) {
261        return dluY == 0 ? 0
262                : getUnitConverter().dialogUnitYAsPixel(dluY, component);
263    }
264
265    // Accessing the Unit Converter *******************************************
266
267    /**
268     * Returns the current {@link UnitConverter}. If it has not been initialized
269     * before it will get an instance of {@link DefaultUnitConverter}.
270     *
271     * @return the current <code>UnitConverter</code>
272     */
273    public static UnitConverter getUnitConverter() {
274        if (unitConverter == null) {
275            unitConverter = DefaultUnitConverter.getInstance();
276        }
277        return unitConverter;
278    }
279
280    /**
281     * Sets a new UnitConverter that will be used to convert
282     * font-dependent sizes to pixel sizes.
283     *
284     * @param newUnitConverter  the unit converter to be set
285     */
286    public static void setUnitConverter(UnitConverter newUnitConverter) {
287        unitConverter = newUnitConverter;
288    }
289
290    // Helper Class *********************************************************
291
292    /**
293     * An ordinal-based serializable typesafe enumeration that implements
294     * the {@link Size} interface for the component sizes:
295     * <em>min, pref, default</em>.
296     */
297    @SuppressWarnings("serial")
298    static final class ComponentSize implements Size, Serializable {
299
300        private final transient String name;
301
302        private ComponentSize(String name) {
303            this.name = name;
304        }
305
306        /**
307         * Returns an instance of <code>ComponentSize</code> that corresponds
308         * to the specified string.
309         * @param str                   the encoded component size
310         * @return the corresponding ComponentSize or null if none matches
311         */
312        static ComponentSize valueOf(String str) {
313            if (str.equals("m") || str.equals("min")) {
314                return MINIMUM;
315            }
316            if (str.equals("p") || str.equals("pref")) {
317                return PREFERRED;
318            }
319            if (str.equals("d") || str.equals("default")) {
320                return DEFAULT;
321            }
322            return null;
323        }
324
325        /**
326         * Computes the maximum size for the given list of components, using
327         * this form spec and the specified measure.
328         * <p>
329         * Invoked by FormLayout to determine the size of one of my elements
330         *
331         * @param container       the layout container
332         * @param components      the list of components to measure
333         * @param minMeasure      the measure used to determine the minimum size
334         * @param prefMeasure     the measure used to determine the preferred size
335         * @param defaultMeasure  the measure used to determine the default size
336         * @return the maximum size in pixels for the given list of components
337         */
338        @Override
339        public int maximumSize(Container container, List components,
340                FormLayout.Measure minMeasure, FormLayout.Measure prefMeasure,
341                FormLayout.Measure defaultMeasure) {
342
343            FormLayout.Measure measure = this == MINIMUM ? minMeasure
344                    : this == PREFERRED ? prefMeasure : defaultMeasure;
345            int maximum = 0;
346            for (Iterator i = components.iterator(); i.hasNext();) {
347                Component c = (Component) i.next();
348                maximum = Math.max(maximum, measure.sizeOf(c));
349            }
350            return maximum;
351        }
352
353        @Override
354        public String toString() {
355            return name.substring(0, 1);
356        }
357
358        // Serialization *****************************************************
359
360        private static int nextOrdinal = 0;
361
362        private final int ordinal = nextOrdinal++;
363
364        private Object readResolve() {
365            return VALUES[ordinal]; // Canonicalize
366        }
367
368    }
369
370}