/* * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of JGoodies Karsten Lentzsch nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jgoodies.forms.layout; import java.awt.Component; import java.awt.Container; import java.io.Serializable; import java.util.List; import java.util.Locale; /** * An implementation of the {@link Size} interface that represents constant * sizes described by a value and unit, for example: * 10 pixel, 15 point or 4 dialog units. * You can get instances of <code>ConstantSize</code> using * the factory methods and constants in the {@link Sizes} class. * Logical constant sizes that vary with the current layout style * are delivered by the {@link com.jgoodies.forms.util.LayoutStyle} class.<p> * * This class supports different size units: * <table> * <tr><td><b>Unit</b>  * </td><td> <b>Abbreviation</b> </td><td>  * <b>Size</b></td></tr> * <tr><td>Millimeter</td><td>mm</td><td>0.1 cm</td></tr> * <tr><td>Centimeter</td><td>cm</td><td>10.0 mm</td></tr> * <tr><td>Inch</td><td>in</td><td>25.4 mm</td></tr> * <tr><td>DTP Point</td><td>pt</td><td>1/72 in</td></tr> * <tr><td>Pixel</td><td>px</td><td>1/(resolution in dpi) in</td></tr> * <tr><td>Dialog Unit</td><td>dlu</td><td>honors l&f, resolution, and * dialog font size</td></tr> * </table><p> * * <strong>Examples:</strong><pre> * Sizes.ZERO; * Sizes.DLUX9; * Sizes.dluX(42); * Sizes.pixel(99); * </pre> * * @author Karsten Lentzsch * @version $Revision$ * * @see Size * @see Sizes */ public final class ConstantSize implements Size, Serializable { // Public Units ********************************************************* public static final Unit PIXEL = new Unit("Pixel", "px", true); public static final Unit POINT = new Unit("Point", "pt", true); public static final Unit DIALOG_UNITS_X = new Unit("Dialog units X", "dluX", true); public static final Unit DLUX = DIALOG_UNITS_X; public static final Unit DIALOG_UNITS_Y = new Unit("Dialog units Y", "dluY", true); public static final Unit DLUY = DIALOG_UNITS_Y; public static final Unit MILLIMETER = new Unit("Millimeter", "mm", false); public static final Unit MM = MILLIMETER; public static final Unit CENTIMETER = new Unit("Centimeter", "cm", false); public static final Unit CM = CENTIMETER; public static final Unit INCH = new Unit("Inch", "in", false); public static final Unit IN = INCH; /** * An array of all enumeration values used to canonicalize * deserialized units. */ private static final Unit[] VALUES = { PIXEL, POINT, DIALOG_UNITS_X, DIALOG_UNITS_Y, MILLIMETER, CENTIMETER, INCH }; // Fields *************************************************************** private final double value; private final Unit unit; // Instance Creation **************************************************** /** * Constructs an instance of <code>ConstantSize</code> from the given * encoded size and unit description. * * @param value the size value interpreted in the given units * @param unit the size's unit */ ConstantSize(int value, Unit unit) { this.value = value; this.unit = unit; } /** * Constructs an instance of <code>ConstantSize</code> from the given * encoded size and unit description. * * @param value the size value interpreted in the given units * @param unit the size's unit */ ConstantSize(double value, Unit unit) { this.value = value; this.unit = unit; } /** * Constructs an instance of <code>ConstantSize</code> from the given * encoded size and unit description. * * @param encodedValueAndUnit the size's value and unit as string * @param horizontal true for horizontal, false for vertical * @return a constant size for the given encoding and unit description * @exception IllegalArgumentException if the unit requires integer * but the value is not an integer */ static ConstantSize valueOf(String encodedValueAndUnit, boolean horizontal) { String split[] = ConstantSize.splitValueAndUnit(encodedValueAndUnit); String encodedValue = split[0]; String encodedUnit = split[1]; Unit unit = Unit.valueOf(encodedUnit, horizontal); double value = Double.parseDouble(encodedValue); if (unit.requiresIntegers) { if (value != (int) value) { throw new IllegalArgumentException(unit.toString() + " value " + encodedValue + " must be an integer."); } } return new ConstantSize(value, unit); } /** * Returns an instance of <code>Size</code> for the specified value * in horizontal dialog units. * * @param value size value in horizontal dialog units * @return the associated Size instance */ static ConstantSize dluX(int value) { return new ConstantSize(value, DLUX); } /** * Returns an instance of <code>Size</code> for the specified value * in vertical dialog units. * * @param value size value in vertical dialog units * @return the associated Size instance */ static ConstantSize dluY(int value) { return new ConstantSize(value, DLUY); } // Accessing the Value ************************************************** /** * Converts the size if necessary and returns the value in pixels. * * @param component the associated component * @return the size in pixels */ public int getPixelSize(Component component) { if (unit == PIXEL) { return intValue(); } else if (unit == POINT) { return Sizes.pointAsPixel(intValue(), component); } else if (unit == INCH) { return Sizes.inchAsPixel(value, component); } else if (unit == MILLIMETER) { return Sizes.millimeterAsPixel(value, component); } else if (unit == CENTIMETER) { return Sizes.centimeterAsPixel(value, component); } else if (unit == DIALOG_UNITS_X) { return Sizes.dialogUnitXAsPixel(intValue(), component); } else if (unit == DIALOG_UNITS_Y) { return Sizes.dialogUnitYAsPixel(intValue(), component); } else { throw new IllegalStateException("Invalid unit " + unit); } } // Implementing the Size Interface ************************************** /** * Returns this size as pixel size. Neither requires the component * list nor the specified measures.<p> * * Invoked by {@link com.jgoodies.forms.layout.FormSpec} to determine * the size of a column or row. * * @param container the layout container * @param components the list of components used to compute the size * @param minMeasure the measure that determines the minimum sizes * @param prefMeasure the measure that determines the preferred sizes * @param defaultMeasure the measure that determines the default sizes * @return the computed maximum size in pixel */ public int maximumSize(Container container, List components, FormLayout.Measure minMeasure, FormLayout.Measure prefMeasure, FormLayout.Measure defaultMeasure) { return getPixelSize(container); } // Overriding Object Behavior ******************************************* /** * Indicates whether some other ConstantSize is "equal to" this one. * * @param o the Object with which to compare * @return <code>true</code> if this object is the same as the obj * argument; <code>false</code> otherwise. * @see java.lang.Object#hashCode() * @see java.util.Hashtable */ public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof ConstantSize)) { return false; } ConstantSize size = (ConstantSize) o; return this.value == size.value && this.unit == size.unit; } /** * Returns a hash code value for the object. This method is * supported for the benefit of hashtables such as those provided by * <code>java.util.Hashtable</code>. * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.util.Hashtable */ public int hashCode() { return Double.valueOf(value).hashCode() + 37 * unit.hashCode(); } /** * Returns a string representation of this size object. * * <strong>Note:</strong> The string representation may change * at any time. It is strongly recommended to not use this string * for parsing purposes. * * @return a string representation of the constant size */ public String toString() { return (value == intValue()) ? Integer.toString(intValue()) + unit.abbreviation() : Double.toString(value) + unit.abbreviation(); } // Helper Code ********************************************************** private int intValue() { return (int) Math.round(value); } /** * Splits a string that encodes size with unit into the size and unit * substrings. Returns an array of two strings. * * @param encodedValueAndUnit a strings that represents a size with unit * @return the first element is size, the second is unit */ static String[] splitValueAndUnit(String encodedValueAndUnit) { String[] result = new String[2]; int len = encodedValueAndUnit.length(); int firstLetterIndex = len; while (firstLetterIndex > 0 && Character.isLetter(encodedValueAndUnit .charAt(firstLetterIndex - 1))) { firstLetterIndex--; } result[0] = encodedValueAndUnit.substring(0, firstLetterIndex); result[1] = encodedValueAndUnit.substring(firstLetterIndex); return result; } // Helper Class ********************************************************* /** * An ordinal-based serializable typesafe enumeration for units * as used in instances of {@link ConstantSize}. */ public static final class Unit implements Serializable { private final transient String name; private final transient String abbreviation; final transient boolean requiresIntegers; private Unit(String name, String abbreviation, boolean requiresIntegers) { this.name = name; this.abbreviation = abbreviation; this.requiresIntegers = requiresIntegers; } /** * Returns an instance of <code>Unit</code> that corresponds to the * specified string. * * @param str the encoded unit * @param horizontal true for a horizontal unit, false for vertical * @return the corresponding Unit * @exception IllegalArgumentException if no Unit exists for the string */ static Unit valueOf(String str, boolean horizontal) { String lowerCase = str.toLowerCase(Locale.ENGLISH); if (lowerCase.equals("px") || lowerCase.length() == 0) { return PIXEL; } else if (lowerCase.equals("dlu")) { return horizontal ? DIALOG_UNITS_X : DIALOG_UNITS_Y; } else if (lowerCase.equals("pt")) { return POINT; } else if (lowerCase.equals("in")) { return INCH; } else if (lowerCase.equals("mm")) { return MILLIMETER; } else if (lowerCase.equals("cm")) { return CENTIMETER; } else { throw new IllegalArgumentException("Invalid unit name '" + str + "'. Must be one of: " + "px, dlu, pt, mm, cm, in"); } } public String toString() { return name; } /** * Returns the first character of this Unit's name. * Used to identify it in short format strings. * * @return the first character of this Unit's name. */ public String abbreviation() { return abbreviation; } // Serialization ***************************************************** private static int nextOrdinal = 0; private final int ordinal = nextOrdinal++; private Object readResolve() { return VALUES[ordinal]; // Canonicalize } } }