All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.privatejgoodies.forms.layout.CellConstraints Maven / Gradle / Ivy

/*
 * Copyright (c) 2002-2013 JGoodies Software GmbH. 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 Software GmbH 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.privatejgoodies.forms.layout;

import static com.privatejgoodies.common.base.Preconditions.checkArgument;
import static com.privatejgoodies.common.base.Preconditions.checkNotNull;

import java.awt.Component;
import java.awt.Insets;
import java.awt.Rectangle;
import java.io.Serializable;
import java.util.Locale;
import java.util.StringTokenizer;

import com.privatejgoodies.forms.factories.CC;

/**
 * Defines constraints for components that are laid out with the FormLayout. Defines the components
 * display area: grid x, grid y, grid width (column span), grid height (row span),
 * horizontal alignment and vertical alignment.

* * Most methods return this object to enable method chaining.

* * You can set optional insets in a constructor. This is useful if you need to use a pixel-size * insets to align perceived component bounds with pixel data, for example an icon. Anyway, this is * rarely used. The insets don't affect the size computation for columns and rows. I consider * renaming the insets to offsets to better indicate the motivation for this option.

* * Examples:
* The following cell constraints locate a component in the third column of the fifth row; column * and row span are 1; the component will be aligned with the column's right-hand side and the row's * bottom. *

 * CellConstraints cc = new CellConstraints();
 * cc.xy  (3, 5);
 * cc.xy  (3, 5, CellConstraints.RIGHT, CellConstraints.BOTTOM);
 * cc.xy  (3, 5, "right, bottom");
 *
 * cc.xyw (3, 5, 1);
 * cc.xyw (3, 5, 1, CellConstraints.RIGHT, CellConstraints.BOTTOM);
 * cc.xyw (3, 5, 1, "right, bottom");
 *
 * cc.xywh(3, 5, 1, 1);
 * cc.xywh(3, 5, 1, 1, CellConstraints.RIGHT, CellConstraints.BOTTOM);
 * cc.xywh(3, 5, 1, 1, "right, bottom");
 * 
See also the examples in the {@link FormLayout} class comment.

* * TODO: Explain in the JavaDocs that the insets are actually offsets. And describe that these * offsets are not taken into account when FormLayout computes the column and row sizes.

* * TODO: Rename the inset to offsets. * * @author Karsten Lentzsch * @version $Revision: 1.15 $ * * @see CC */ public final class CellConstraints implements Cloneable, Serializable { // Alignment Constants ************************************************* /* * Implementation Note: Do not change the order of the following constants. * The serialization of class Alignment is ordinal-based and relies on it. */ /** * Use the column's or row's default alignment. */ public static final Alignment DEFAULT = new Alignment("default", Alignment.BOTH); /** * Fill the cell either horizontally or vertically. */ public static final Alignment FILL = new Alignment("fill", Alignment.BOTH); /** * Put the component in the left. */ public static final Alignment LEFT = new Alignment("left", Alignment.HORIZONTAL); /** * Put the component in the right. */ public static final Alignment RIGHT = new Alignment("right", Alignment.HORIZONTAL); /** * Put the component in the center. */ public static final Alignment CENTER = new Alignment("center", Alignment.BOTH); /** * Put the component in the top. */ public static final Alignment TOP = new Alignment("top", Alignment.VERTICAL); /** * Put the component in the bottom. */ public static final Alignment BOTTOM = new Alignment("bottom", Alignment.VERTICAL); /** * An array of all enumeration values used to canonicalize deserialized alignments. */ private static final Alignment[] VALUES = {DEFAULT, FILL, LEFT, RIGHT, CENTER, TOP, BOTTOM}; /** * A reusable {@code Insets} object to reduce object instantiation. */ private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0); // Fields *************************************************************** /** * Describes the component's horizontal grid origin (starts at 1). */ public int gridX; /** * Describes the component's vertical grid origin (starts at 1). */ public int gridY; /** * Describes the component's horizontal grid extend (number of cells). */ public int gridWidth; /** * Describes the component's vertical grid extent (number of cells). */ public int gridHeight; /** * Describes the component's horizontal alignment. */ public Alignment hAlign; /** * Describes the component's vertical alignment. */ public Alignment vAlign; /** * Describes the component's {@code Insets} in it's display area. */ public Insets insets; /** * Describes whether individual components shall be taken into account by the FormLayout if 1) * they are invisible and 2) the FormLayout does not honor the visibility. * * See {@link FormLayout#setHonorsVisibility(boolean)} and * {@link FormLayout#setHonorsVisibility(Component, Boolean)} for a full description of this * feature. */ public Boolean honorsVisibility; // Instance Creation **************************************************** /** * Constructs a default instance of {@code CellConstraints}. */ public CellConstraints() { this(1, 1); } /** * Constructs an instance of {@code CellConstraints} for the given cell position.

* * Examples:

     * new CellConstraints(1, 3);
     * new CellConstraints(1, 3);
     * 
* * @param gridX the component's horizontal grid origin * @param gridY the component's vertical grid origin */ public CellConstraints(int gridX, int gridY) { this(gridX, gridY, 1, 1); } /** * Constructs an instance of {@code CellConstraints} for the given cell position, anchor, and * fill.

* * Examples:

     * new CellConstraints(1, 3, CellConstraints.LEFT,   CellConstraints.BOTTOM);
     * new CellConstraints(1, 3, CellConstraints.CENTER, CellConstraints.FILL);
     * 
* * @param gridX the component's horizontal grid origin * @param gridY the component's vertical grid origin * @param hAlign the component's horizontal alignment * @param vAlign the component's vertical alignment */ public CellConstraints(int gridX, int gridY, Alignment hAlign, Alignment vAlign) { this(gridX, gridY, 1, 1, hAlign, vAlign, EMPTY_INSETS); } /** * Constructs an instance of {@code CellConstraints} for the given cell position and size.

* * Examples:

     * new CellConstraints(1, 3, 2, 1);
     * new CellConstraints(1, 3, 7, 3);
     * 
* * @param gridX the component's horizontal grid origin * @param gridY the component's vertical grid origin * @param gridWidth the component's horizontal extent * @param gridHeight the component's vertical extent */ public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight) { this(gridX, gridY, gridWidth, gridHeight, DEFAULT, DEFAULT); } /** * Constructs an instance of {@code CellConstraints} for the given cell position and size, * anchor, and fill.

* * Examples:

     * new CellConstraints(1, 3, 2, 1, CellConstraints.LEFT,   CellConstraints.BOTTOM);
     * new CellConstraints(1, 3, 7, 3, CellConstraints.CENTER, CellConstraints.FILL);
     * 
* * @param gridX the component's horizontal grid origin * @param gridY the component's vertical grid origin * @param gridWidth the component's horizontal extent * @param gridHeight the component's vertical extent * @param hAlign the component's horizontal alignment * @param vAlign the component's vertical alignment */ public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight, Alignment hAlign, Alignment vAlign) { this(gridX, gridY, gridWidth, gridHeight, hAlign, vAlign, EMPTY_INSETS); } /** * Constructs an instance of {@code CellConstraints} for the complete set of available * properties.

* * Examples:

     * new CellConstraints(1, 3, 2, 1, CellConstraints.LEFT,   CellConstraints.BOTTOM, new Insets(0, 1, 0, 3));
     * new CellConstraints(1, 3, 7, 3, CellConstraints.CENTER, CellConstraints.FILL,   new Insets(0, 1, 0, 0));
     * 
* * @param gridX the component's horizontal grid origin * @param gridY the component's vertical grid origin * @param gridWidth the component's horizontal extent * @param gridHeight the component's vertical extent * @param hAlign the component's horizontal alignment * @param vAlign the component's vertical alignment * @param insets the component's display area {@code Insets} * @throws IndexOutOfBoundsException if the grid origin or extent is negative * @throws NullPointerException if the horizontal or vertical alignment is null * @throws IllegalArgumentException if an alignment orientation is invalid */ public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight, Alignment hAlign, Alignment vAlign, Insets insets) { this.gridX = gridX; this.gridY = gridY; this.gridWidth = gridWidth; this.gridHeight = gridHeight; this.hAlign = hAlign; this.vAlign = vAlign; this.insets = insets; if (gridX <= 0) { throw new IndexOutOfBoundsException("The grid x must be a positive number."); } if (gridY <= 0) { throw new IndexOutOfBoundsException("The grid y must be a positive number."); } if (gridWidth <= 0) { throw new IndexOutOfBoundsException("The grid width must be a positive number."); } if (gridHeight <= 0) { throw new IndexOutOfBoundsException("The grid height must be a positive number."); } checkNotNull(hAlign, "The horizontal alignment must not be null."); checkNotNull(vAlign, "The vertical alignment must not be null."); ensureValidOrientations(hAlign, vAlign); } /** * Constructs an instance of {@code CellConstraints} from the given encoded string * properties.

* * Examples:

     * new CellConstraints("1, 3");
     * new CellConstraints("1, 3, left, bottom");
     * new CellConstraints("1, 3, 2, 1, left, bottom");
     * new CellConstraints("1, 3, 2, 1, l, b");
     * 
* * @param encodedConstraints the constraints encoded as string */ public CellConstraints(String encodedConstraints) { this(); initFromConstraints(encodedConstraints); } // Setters with Column-Row Order ****************************************** /** * Sets column and row origins; sets width and height to 1; uses the default alignments.

* * Examples:

     * cc.xy(1, 1);
     * cc.xy(1, 3);
     * 
* * @param col the new column index * @param row the new row index * @return this */ public CellConstraints xy(int col, int row) { return xywh(col, row, 1, 1); } /** * Sets column and row origins; sets width and height to 1; decodes horizontal and vertical * alignments from the given string.

* * Examples:

     * cc.xy(1, 3, "left, bottom");
     * cc.xy(1, 3, "l, b");
     * cc.xy(1, 3, "center, fill");
     * cc.xy(1, 3, "c, f");
     * 
* * @param col the new column index * @param row the new row index * @param encodedAlignments describes the horizontal and vertical alignments * @return this * * @throws IllegalArgumentException if an alignment orientation is invalid */ public CellConstraints xy(int col, int row, String encodedAlignments) { return xywh(col, row, 1, 1, encodedAlignments); } /** * Sets the column and row origins; sets width and height to 1; set horizontal and vertical * alignment using the specified objects.

* * Examples:

     * cc.xy(1, 3, CellConstraints.LEFT,   CellConstraints.BOTTOM);
     * cc.xy(1, 3, CellConstraints.CENTER, CellConstraints.FILL);
     * 
* * @param col the new column index * @param row the new row index * @param colAlign horizontal component alignment * @param rowAlign vertical component alignment * @return this */ public CellConstraints xy(int col, int row, Alignment colAlign, Alignment rowAlign) { return xywh(col, row, 1, 1, colAlign, rowAlign); } /** * Sets the column, row, width, and height; uses a height (row span) of 1 and the horizontal and * vertical default alignments.

* * Examples:

     * cc.xyw(1, 3, 7);
     * cc.xyw(1, 3, 2);
     * 
* * @param col the new column index * @param row the new row index * @param colSpan the column span or grid width * @return this */ public CellConstraints xyw(int col, int row, int colSpan) { return xywh(col, row, colSpan, 1, DEFAULT, DEFAULT); } /** * Sets the column, row, width, and height; decodes the horizontal and vertical alignments from * the given string. The row span (height) is set to 1 * .

* * Examples:

     * cc.xyw(1, 3, 7, "left, bottom");
     * cc.xyw(1, 3, 7, "l, b");
     * cc.xyw(1, 3, 2, "center, fill");
     * cc.xyw(1, 3, 2, "c, f");
     * 
* * @param col the new column index * @param row the new row index * @param colSpan the column span or grid width * @param encodedAlignments describes the horizontal and vertical alignments * @return this * @throws IllegalArgumentException if an alignment orientation is invalid */ public CellConstraints xyw(int col, int row, int colSpan, String encodedAlignments) { return xywh(col, row, colSpan, 1, encodedAlignments); } /** * Sets the column, row, width, and height; sets the horizontal and vertical alignment using the * specified alignment objects. The row span (height) is set to 1 * .

* * Examples:

     * cc.xyw(1, 3, 2, CellConstraints.LEFT,   CellConstraints.BOTTOM);
     * cc.xyw(1, 3, 7, CellConstraints.CENTER, CellConstraints.FILL);
     * 
* * @param col the new column index * @param row the new row index * @param colSpan the column span or grid width * @param colAlign horizontal component alignment * @param rowAlign vertical component alignment * @return this * @throws IllegalArgumentException if an alignment orientation is invalid */ public CellConstraints xyw(int col, int row, int colSpan, Alignment colAlign, Alignment rowAlign) { return xywh(col, row, colSpan, 1, colAlign, rowAlign); } /** * Sets the column, row, width, and height; uses default alignments.

* * Examples:

     * cc.xywh(1, 3, 2, 1);
     * cc.xywh(1, 3, 7, 3);
     * 
* * @param col the new column index * @param row the new row index * @param colSpan the column span or grid width * @param rowSpan the row span or grid height * @return this */ public CellConstraints xywh(int col, int row, int colSpan, int rowSpan) { return xywh(col, row, colSpan, rowSpan, DEFAULT, DEFAULT); } /** * Sets the column, row, width, and height; decodes the horizontal and vertical alignments from * the given string.

* * Examples:

     * cc.xywh(1, 3, 2, 1, "left, bottom");
     * cc.xywh(1, 3, 2, 1, "l, b");
     * cc.xywh(1, 3, 7, 3, "center, fill");
     * cc.xywh(1, 3, 7, 3, "c, f");
     * 
* * @param col the new column index * @param row the new row index * @param colSpan the column span or grid width * @param rowSpan the row span or grid height * @param encodedAlignments describes the horizontal and vertical alignments * @return this * @throws IllegalArgumentException if an alignment orientation is invalid */ public CellConstraints xywh(int col, int row, int colSpan, int rowSpan, String encodedAlignments) { CellConstraints result = xywh(col, row, colSpan, rowSpan); result.setAlignments(encodedAlignments, true); return result; } /** * Sets the column, row, width, and height; sets the horizontal and vertical alignment using the * specified alignment objects.

* * Examples:

     * cc.xywh(1, 3, 2, 1, CellConstraints.LEFT,   CellConstraints.BOTTOM);
     * cc.xywh(1, 3, 7, 3, CellConstraints.CENTER, CellConstraints.FILL);
     * 
* * @param col the new column index * @param row the new row index * @param colSpan the column span or grid width * @param rowSpan the row span or grid height * @param colAlign horizontal component alignment * @param rowAlign vertical component alignment * @return this * @throws IllegalArgumentException if an alignment orientation is invalid */ public CellConstraints xywh(int col, int row, int colSpan, int rowSpan, Alignment colAlign, Alignment rowAlign) { this.gridX = col; this.gridY = row; this.gridWidth = colSpan; this.gridHeight = rowSpan; this.hAlign = colAlign; this.vAlign = rowAlign; ensureValidOrientations(hAlign, vAlign); return this; } // Setters with Row-Column Order ****************************************** /** * Sets row and column origins; sets height and width to 1; uses the default alignments.

* * Examples:

     * cc.rc(1, 1);
     * cc.rc(3, 1);
     * 
* * @param row the new row index * @param col the new column index * @return this * * @since 1.1 */ public CellConstraints rc(int row, int col) { return rchw(row, col, 1, 1); } /** * Sets row and column origins; sets height and width to 1; decodes vertical and horizontal * alignments from the given string.

* * Examples:

     * cc.rc(3, 1, "bottom, left");
     * cc.rc(3, 1, "b, l");
     * cc.rc(3, 1, "fill, center");
     * cc.rc(3, 1, "f, c");
     * 
* * @param row the new row index * @param col the new column index * @param encodedAlignments describes the vertical and horizontal alignments * @return this * * @throws IllegalArgumentException if an alignment orientation is invalid * * @since 1.1 */ public CellConstraints rc(int row, int col, String encodedAlignments) { return rchw(row, col, 1, 1, encodedAlignments); } /** * Sets the row and column origins; sets width and height to 1; set horizontal and vertical * alignment using the specified objects.

* * Examples:

     * cc.rc(3, 1, CellConstraints.BOTTOM, CellConstraints.LEFT);
     * cc.rc(3, 1, CellConstraints.FILL,   CellConstraints.CENTER);
     * 
* * @param row the new row index * @param col the new column index * @param rowAlign vertical component alignment * @param colAlign horizontal component alignment * @return this * * @since 1.1 */ public CellConstraints rc(int row, int col, Alignment rowAlign, Alignment colAlign) { return rchw(row, col, 1, 1, rowAlign, colAlign); } /** * Sets the row, column, height, and width; uses a height (row span) of 1 and the vertical and * horizontal default alignments.

* * Examples:

     * cc.rcw(3, 1, 7);
     * cc.rcw(3, 1, 2);
     * 
* * @param row the new row index * @param col the new column index * @param colSpan the column span or grid width * @return this * * @since 1.1 */ public CellConstraints rcw(int row, int col, int colSpan) { return rchw(row, col, 1, colSpan, DEFAULT, DEFAULT); } /** * Sets the row, column, height, and width; decodes the vertical and horizontal alignments from * the given string. The row span (height) is set to 1 * .

* * Examples:

     * cc.rcw(3, 1, 7, "bottom, left");
     * cc.rcw(3, 1, 7, "b, l");
     * cc.rcw(3, 1, 2, "fill, center");
     * cc.rcw(3, 1, 2, "f, c");
     * 
* * @param row the new row index * @param col the new column index * @param colSpan the column span or grid width * @param encodedAlignments describes the vertical and horizontal alignments * @return this * * @throws IllegalArgumentException if an alignment orientation is invalid * * @since 1.1 */ public CellConstraints rcw(int row, int col, int colSpan, String encodedAlignments) { return rchw(row, col, 1, colSpan, encodedAlignments); } /** * Sets the row, column, height, and width; sets the vertical and horizontal alignment using the * specified alignment objects. The row span (height) is set to 1 * .

* * Examples:

     * cc.rcw(3, 1, 2, CellConstraints.BOTTOM, CellConstraints.LEFT);
     * cc.rcw(3, 1, 7, CellConstraints.FILL,   CellConstraints.CENTER);
     * 
* * @param row the new row index * @param col the new column index * @param colSpan the column span or grid width * @param rowAlign vertical component alignment * @param colAlign horizontal component alignment * @return this * * @throws IllegalArgumentException if an alignment orientation is invalid * * @since 1.1 */ public CellConstraints rcw(int row, int col, int colSpan, Alignment rowAlign, Alignment colAlign) { return rchw(row, col, 1, colSpan, rowAlign, colAlign); } /** * Sets the row, column, height, and width; uses default alignments.

* * Examples:

     * cc.rchw(1, 3, 2, 1);
     * cc.rchw(1, 3, 7, 3);
     * 
* * @param row the new row index * @param col the new column index * @param rowSpan the row span or grid height * @param colSpan the column span or grid width * @return this * * @since 1.1 */ public CellConstraints rchw(int row, int col, int rowSpan, int colSpan) { return rchw(row, col, rowSpan, colSpan, DEFAULT, DEFAULT); } /** * Sets the row, column, height, and width; decodes the vertical and horizontal alignments from * the given string.

* * Examples:

     * cc.rchw(3, 1, 1, 2, "bottom, left");
     * cc.rchw(3, 1, 1, 2, "b, l");
     * cc.rchw(3, 1, 3, 7, "fill, center");
     * cc.rchw(3, 1, 3, 7, "f, c");
     * 
* * @param row the new row index * @param col the new column index * @param rowSpan the row span or grid height * @param colSpan the column span or grid width * @param encodedAlignments describes the vertical and horizontal alignments * @return this * @throws IllegalArgumentException if an alignment orientation is invalid * * @since 1.1 */ public CellConstraints rchw(int row, int col, int rowSpan, int colSpan, String encodedAlignments) { CellConstraints result = rchw(row, col, rowSpan, colSpan); result.setAlignments(encodedAlignments, false); return result; } /** * Sets the row, column, height, and width; sets the vertical and horizontal alignment using the * specified alignment objects.

* * Examples:

     * cc.rchw(3, 1, 1, 2, CellConstraints.BOTTOM, CellConstraints.LEFT);
     * cc.rchw(3, 1, 3, 7, CellConstraints.FILL,   CellConstraints.CENTER);
     * 
* * @param row the new row index * @param col the new column index * @param rowSpan the row span or grid height * @param colSpan the column span or grid width * @param rowAlign vertical component alignment * @param colAlign horizontal component alignment * @return this * * @throws IllegalArgumentException if an alignment orientation is invalid * * @since 1.1 */ public CellConstraints rchw(int row, int col, int rowSpan, int colSpan, Alignment rowAlign, Alignment colAlign) { return xywh(col, row, colSpan, rowSpan, colAlign, rowAlign); } // Parsing and Decoding String Descriptions ***************************** /** * Decodes and returns the grid bounds and alignments for this constraints as an array of six * integers. The string representation is a comma separated sequence, one of *
     * "x, y"
     * "x, y, w, h"
     * "x, y, hAlign, vAlign"
     * "x, y, w, h, hAlign, vAlign"
     * 
* * @param encodedConstraints represents horizontal and vertical alignment * * @throws IllegalArgumentException if the encoded constraints do not follow the constraint * syntax */ @SuppressWarnings("null") private void initFromConstraints(String encodedConstraints) { StringTokenizer tokenizer = new StringTokenizer(encodedConstraints, " ,"); int argCount = tokenizer.countTokens(); checkArgument(argCount == 2 || argCount == 4 || argCount == 6, "You must provide 2, 4 or 6 arguments."); Integer nextInt = decodeInt(tokenizer.nextToken()); checkArgument(nextInt != null, "First cell constraint element must be a number."); gridX = nextInt.intValue(); checkArgument(gridX > 0, "The grid x must be a positive number."); nextInt = decodeInt(tokenizer.nextToken()); checkArgument(nextInt != null, "Second cell constraint element must be a number."); gridY = nextInt.intValue(); checkArgument(gridY > 0, "The grid y must be a positive number."); if (!tokenizer.hasMoreTokens()) { return; } String token = tokenizer.nextToken(); nextInt = decodeInt(token); if (nextInt != null) { // Case: "x, y, w, h" or // "x, y, w, h, hAlign, vAlign" gridWidth = nextInt.intValue(); if (gridWidth <= 0) { throw new IndexOutOfBoundsException( "The grid width must be a positive number."); } nextInt = decodeInt(tokenizer.nextToken()); if (nextInt == null) { throw new IllegalArgumentException( "Fourth cell constraint element must be like third."); } gridHeight = nextInt.intValue(); if (gridHeight <= 0) { throw new IndexOutOfBoundsException( "The grid height must be a positive number."); } if (!tokenizer.hasMoreTokens()) { return; } token = tokenizer.nextToken(); } hAlign = decodeAlignment(token); vAlign = decodeAlignment(tokenizer.nextToken()); ensureValidOrientations(hAlign, vAlign); } /** * Decodes a string description for the horizontal and vertical alignment and sets this * CellConstraints' alignment values. If the boolean is {@code true} the horizontal alignment is * the first token, and the vertical alignment is the second token. if the boolean is * {@code false} the vertical alignment comes first. *

* * Valid horizontal alignments are: left, center, right, default, and fill. Valid vertical * alignments are: top, center, bottom, default, and fill. The anchor's string representation * abbreviates the alignment: l, c, r, d, f, t, and b.

* * Anchor examples: "c, c" is centered, "l, t" is northwest, "c, t" is north, "r, c" east. "c, * d" is horizontally centered and uses the row's default alignment. "d, t" is on top of the * cell and uses the column's default alignment.

* * @param encodedAlignments represents horizontal and vertical alignment * @throws IllegalArgumentException if an alignment orientation is invalid */ private void setAlignments(String encodedAlignments, boolean horizontalThenVertical) { StringTokenizer tokenizer = new StringTokenizer(encodedAlignments, " ,"); Alignment first = decodeAlignment(tokenizer.nextToken()); Alignment second = decodeAlignment(tokenizer.nextToken()); hAlign = horizontalThenVertical ? first : second; vAlign = horizontalThenVertical ? second : first; ensureValidOrientations(hAlign, vAlign); } /** * Decodes an integer string representation and returns the associated Integer or null in case * of an invalid number format. * * @param token the encoded integer * @return the decoded Integer or null */ private static Integer decodeInt(String token) { try { return Integer.decode(token); } catch (NumberFormatException e) { return null; } } /** * Parses an alignment string description and returns the corresponding alignment value. * * @param encodedAlignment the encoded alignment * @return the associated {@code Alignment} instance */ private static Alignment decodeAlignment(String encodedAlignment) { return Alignment.valueOf(encodedAlignment); } /** * Checks and verifies that this constraints object has valid grid index values, i. e. the * display area cells are inside the form's grid. * * @param colCount number of columns in the grid * @param rowCount number of rows in the grid * @throws IndexOutOfBoundsException if the display area described by this constraints object is * not inside the grid */ void ensureValidGridBounds(int colCount, int rowCount) { if (gridX <= 0) { throw new IndexOutOfBoundsException( "The column index " + gridX + " must be positive."); } if (gridX > colCount) { throw new IndexOutOfBoundsException( "The column index " + gridX + " must be less than or equal to " + colCount + "."); } if (gridX + gridWidth - 1 > colCount) { throw new IndexOutOfBoundsException( "The grid width " + gridWidth + " must be less than or equal to " + (colCount - gridX + 1) + "."); } if (gridY <= 0) { throw new IndexOutOfBoundsException( "The row index " + gridY + " must be positive."); } if (gridY > rowCount) { throw new IndexOutOfBoundsException( "The row index " + gridY + " must be less than or equal to " + rowCount + "."); } if (gridY + gridHeight - 1 > rowCount) { throw new IndexOutOfBoundsException( "The grid height " + gridHeight + " must be less than or equal to " + (rowCount - gridY + 1) + "."); } } /** * Checks and verifies that the horizontal alignment is a horizontal and the vertical alignment * is vertical. * * @param horizontalAlignment the horizontal alignment * @param verticalAlignment the vertical alignment * @throws IllegalArgumentException if an alignment is invalid */ private static void ensureValidOrientations(Alignment horizontalAlignment, Alignment verticalAlignment) { if (!horizontalAlignment.isHorizontal()) { throw new IllegalArgumentException("The horizontal alignment must be one of: left, center, right, fill, default."); } if (!verticalAlignment.isVertical()) { throw new IllegalArgumentException("The vertical alignment must be one of: top, center, bottom, fill, default."); } } // Settings Component Bounds ******************************************** /** * Sets the component's bounds using the given component and cell bounds. * * @param c the component to set bounds * @param layout the FormLayout instance that computes the bounds * @param cellBounds the cell's bounds * @param minWidthMeasure measures the minimum width * @param minHeightMeasure measures the minimum height * @param prefWidthMeasure measures the preferred width * @param prefHeightMeasure measures the preferred height */ void setBounds(Component c, FormLayout layout, Rectangle cellBounds, FormLayout.Measure minWidthMeasure, FormLayout.Measure minHeightMeasure, FormLayout.Measure prefWidthMeasure, FormLayout.Measure prefHeightMeasure) { ColumnSpec colSpec = gridWidth == 1 ? layout.getColumnSpec(gridX) : null; RowSpec rowSpec = gridHeight == 1 ? layout.getRowSpec(gridY) : null; Alignment concreteHAlign = concreteAlignment(this.hAlign, colSpec); Alignment concreteVAlign = concreteAlignment(this.vAlign, rowSpec); Insets concreteInsets = this.insets != null ? this.insets : EMPTY_INSETS; int cellX = cellBounds.x + concreteInsets.left; int cellY = cellBounds.y + concreteInsets.top; int cellW = cellBounds.width - concreteInsets.left - concreteInsets.right; int cellH = cellBounds.height - concreteInsets.top - concreteInsets.bottom; int compW = componentSize(c, colSpec, cellW, minWidthMeasure, prefWidthMeasure); int compH = componentSize(c, rowSpec, cellH, minHeightMeasure, prefHeightMeasure); int x = origin(concreteHAlign, cellX, cellW, compW); int y = origin(concreteVAlign, cellY, cellH, compH); int w = extent(concreteHAlign, cellW, compW); int h = extent(concreteVAlign, cellH, compH); c.setBounds(x, y, w, h); } /** * Computes and returns the concrete alignment. Takes into account the cell alignment and * the {@code FormSpec} if applicable.

* * If this constraints object doesn't belong to a single column or row, the {@code formSpec} * parameter is {@code null}. In this case the cell alignment is answered, but {@code DEFAULT} * is mapped to {@code FILL} * .

* * If the cell belongs to a single column or row, we use the cell alignment, unless it is * {@code DEFAULT}, where the alignment is inherited from the column or row resp. * * @param cellAlignment this cell's alignment * @param formSpec the associated column or row specification * @return the concrete alignment */ private static Alignment concreteAlignment(Alignment cellAlignment, FormSpec formSpec) { return formSpec == null ? cellAlignment == DEFAULT ? FILL : cellAlignment : usedAlignment(cellAlignment, formSpec); } /** * Returns the alignment used for a given form constraints object. The cell alignment overrides * the column or row default, unless it is {@code DEFAULT}. In the latter case, we use the * column or row alignment. * * @param cellAlignment this cell constraint's alignment * @param formSpec the associated column or row specification * @return the alignment used */ private static Alignment usedAlignment(Alignment cellAlignment, FormSpec formSpec) { if (cellAlignment != CellConstraints.DEFAULT) { // Cell alignments other than DEFAULT override col/row alignments return cellAlignment; } FormSpec.DefaultAlignment defaultAlignment = formSpec.getDefaultAlignment(); if (defaultAlignment == FormSpec.FILL_ALIGN) { return FILL; } if (defaultAlignment == ColumnSpec.LEFT) { return LEFT; } else if (defaultAlignment == FormSpec.CENTER_ALIGN) { return CENTER; } else if (defaultAlignment == ColumnSpec.RIGHT) { return RIGHT; } else if (defaultAlignment == RowSpec.TOP) { return TOP; } else { return BOTTOM; } } /** * Computes and returns the pixel size of the given component using the given form * specification, measures, and cell size. * * @param component the component to measure * @param formSpec the specification of the component's column/row * @param minMeasure the measure for the minimum size * @param prefMeasure the measure for the preferred size * @param cellSize the cell size * @return the component size as measured or a constant */ private static int componentSize(Component component, FormSpec formSpec, int cellSize, FormLayout.Measure minMeasure, FormLayout.Measure prefMeasure) { if (formSpec == null) { return prefMeasure.sizeOf(component); } else if (formSpec.getSize() == Sizes.MINIMUM) { return minMeasure.sizeOf(component); } else if (formSpec.getSize() == Sizes.PREFERRED) { return prefMeasure.sizeOf(component); } else { // default mode return Math.min(cellSize, prefMeasure.sizeOf(component)); } } /** * Computes and returns the component's pixel origin. * * @param alignment the component's alignment * @param cellOrigin the origin of the display area * @param cellSize the extent of the display area * @param componentSize the component's size * @return the component's pixel origin */ private static int origin(Alignment alignment, int cellOrigin, int cellSize, int componentSize) { if (alignment == RIGHT || alignment == BOTTOM) { return cellOrigin + cellSize - componentSize; } else if (alignment == CENTER) { return cellOrigin + (cellSize - componentSize) / 2; } else { // left, top, fill return cellOrigin; } } /** * Returns the component's pixel extent. * * @param alignment the component's alignment * @param cellSize the size of the display area * @param componentSize the component's size * @return the component's pixel extent */ private static int extent(Alignment alignment, int cellSize, int componentSize) { return alignment == FILL ? cellSize : componentSize; } // Misc ***************************************************************** /** * Creates a copy of this cell constraints object. * * @return a copy of this cell constraints object */ @Override public Object clone() { try { CellConstraints c = (CellConstraints) super.clone(); c.insets = (Insets) insets.clone(); return c; } catch (CloneNotSupportedException e) { // This shouldn't happen, since we are Cloneable. throw new InternalError(); } } /** * Constructs and returns a string representation of this constraints object. * * @return string representation of this constraints object */ @Override public String toString() { StringBuffer buffer = new StringBuffer("CellConstraints"); buffer.append("[x="); buffer.append(gridX); buffer.append("; y="); buffer.append(gridY); buffer.append("; w="); buffer.append(gridWidth); buffer.append("; h="); buffer.append(gridHeight); buffer.append("; hAlign="); buffer.append(hAlign); buffer.append("; vAlign="); buffer.append(vAlign); if (!EMPTY_INSETS.equals(insets)) { buffer.append("; insets="); buffer.append(insets); } buffer.append("; honorsVisibility="); buffer.append(honorsVisibility); buffer.append(']'); return buffer.toString(); } /** * Returns a short string representation of this constraints object. * * @return a short string representation of this constraints object */ public String toShortString() { return toShortString(null); } /** * Returns a short string representation of this constraints object. This method can use the * given {@code FormLayout} to display extra information how default alignments are mapped to * concrete alignments. Therefore it asks the related column and row as specified by this * constraints object. * * @param layout the layout to be presented as a string * @return a short string representation of this constraints object */ public String toShortString(FormLayout layout) { StringBuffer buffer = new StringBuffer("("); buffer.append(formatInt(gridX)); buffer.append(", "); buffer.append(formatInt(gridY)); buffer.append(", "); buffer.append(formatInt(gridWidth)); buffer.append(", "); buffer.append(formatInt(gridHeight)); buffer.append(", \""); buffer.append(hAlign.abbreviation()); if (hAlign == DEFAULT && layout != null) { buffer.append('='); ColumnSpec colSpec = gridWidth == 1 ? layout.getColumnSpec(gridX) : null; buffer.append(concreteAlignment(hAlign, colSpec).abbreviation()); } buffer.append(", "); buffer.append(vAlign.abbreviation()); if (vAlign == DEFAULT && layout != null) { buffer.append('='); RowSpec rowSpec = gridHeight == 1 ? layout.getRowSpec(gridY) : null; buffer.append(concreteAlignment(vAlign, rowSpec).abbreviation()); } buffer.append("\""); if (!EMPTY_INSETS.equals(insets)) { buffer.append(", "); buffer.append(insets); } if (honorsVisibility != null) { buffer.append(honorsVisibility.booleanValue() ? "honors visibility" : "ignores visibility"); } buffer.append(')'); return buffer.toString(); } // Helper Class ********************************************************* /** * An ordinal-based serializable typesafe enumeration for component alignment types as used by * the {@link FormLayout}. */ public static final class Alignment implements Serializable { private static final int HORIZONTAL = 0; private static final int VERTICAL = 1; private static final int BOTH = 2; private final transient String name; private final transient int orientation; private Alignment(String name, int orientation) { this.name = name; this.orientation = orientation; } static Alignment valueOf(String nameOrAbbreviation) { String str = nameOrAbbreviation.toLowerCase(Locale.ENGLISH); if (str.equals("d") || str.equals("default")) { return DEFAULT; } else if (str.equals("f") || str.equals("fill")) { return FILL; } else if (str.equals("c") || str.equals("center")) { return CENTER; } else if (str.equals("l") || str.equals("left")) { return LEFT; } else if (str.equals("r") || str.equals("right")) { return RIGHT; } else if (str.equals("t") || str.equals("top")) { return TOP; } else if (str.equals("b") || str.equals("bottom")) { return BOTTOM; } else { throw new IllegalArgumentException( "Invalid alignment " + nameOrAbbreviation + ". Must be one of: left, center, right, top, bottom, " + "fill, default, l, c, r, t, b, f, d."); } } /** * Returns this Alignment's name. * * @return this alignment's name. */ @Override public String toString() { return name; } /** * Returns the first character of this Alignment's name. Used to identify it in short format * strings. * * @return the name's first character. */ public char abbreviation() { return name.charAt(0); } private boolean isHorizontal() { return orientation != VERTICAL; } private boolean isVertical() { return orientation != HORIZONTAL; } // Serialization ********************************************************* private static int nextOrdinal = 0; private final int ordinal = nextOrdinal++; private Object readResolve() { return VALUES[ordinal]; // Canonicalize } } /** * Returns an integer that has a minimum of two characters. * * @param number the number to format * @return a string representation for a number with a minimum of two chars */ private static String formatInt(int number) { String str = Integer.toString(number); return number < 10 ? " " + str : str; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy