AnchorLayoutManager.java

package edu.hawaii.ics.yucheng;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;

/**
 * A layout manager that supports anchored components. Each component added can
 * be anchored to the left, top, right, bottom, or a combination of these
 * locations. When the container is resized, the components will stretch or move
 * accordingly.
 */
class AnchorLayoutManager implements LayoutManager {

    /** An anchor associated with a component. */
    final class Anchor {

        /** The pixels anchored to the left. */
        private final boolean   myAnchorX1;

        /** The pixels anchored to the right. */
        private final boolean   myAnchorX2;

        /** The pixels anchored to the top. */
        private final boolean   myAnchorY1;

        /** The pixels anchored to the bottom. */
        private final boolean   myAnchorY2;

        /** The component that is anchored. */
        private final Component myComponent;

        /** The initially specified width of the component. */
        private final int       myCX;

        /** The initially specified height of the component. */
        private final int       myCY;

        /** The amount of inset from the left. */
        private final int       myInsetX1;

        /** The amount of inset from the right. */
        private final int       myInsetX2;

        /** The amount of inset from the top. */
        private final int       myInsetY1;

        /** The amount of inset from the bottom. */
        private final int       myInsetY2;

        /** The percent from the left. */
        private final float     myPercentX1;

        /** The percent from the right. */
        private final float     myPercentX2;

        /** The percent from the top. */
        private final float     myPercentY1;

        /** The percent from the bottom. */
        private final float     myPercentY2;


        /**
         * Initializes a new instance of the class.
         * 
         * @param flags The anchor flags.
         * 
         * @param component The component.
         */
        public Anchor(final String flags, final Component component) {
            assert null != flags;
            assert null != component;

            myComponent = component;

            myAnchorX1 = flags.contains(ANCHOR_LEFT);
            myAnchorY1 = flags.contains(ANCHOR_TOP);
            myAnchorX2 = flags.contains(ANCHOR_RIGHT);
            myAnchorY2 = flags.contains(ANCHOR_BOTTOM);

            myCX = component.getWidth();
            myCY = component.getHeight();

            myInsetX1 = component.getX();
            myInsetY1 = component.getY();
            myInsetX2 = myMinimumCX - (myInsetX1 + myCX);
            myInsetY2 = myMinimumCY - (myInsetY1 + myCY);

            myPercentX1 = (float) myInsetX1 / myMinimumCX;
            myPercentY1 = (float) myInsetY1 / myMinimumCY;
            myPercentX2 = (float) myInsetX2 / myMinimumCX;
            myPercentY2 = (float) myInsetY2 / myMinimumCY;
        }


        /**
         * Sets the bounds on the assigned component based on the size of the
         * container.
         * 
         * @param containerCX The width of the container.
         * 
         * @param containerCY The height of the container.
         */
        public void setBounds(final int containerCX, final int containerCY) {

            int x1, x2;
            if (myAnchorX1) {
                x1 = myInsetX1;
                x2 = myAnchorX2 ? containerCX - myInsetX2 : x1 + myCX;
            } else if (myAnchorX2) {
                x2 = containerCX - myInsetX2;
                x1 = x2 - myCX;
            } else {
                x1 = (int) (myPercentX1 * containerCX);
                x2 = containerCX - (int) (myPercentX2 * containerCX);
            }

            int y1, y2;
            if (myAnchorY1) {
                y1 = myInsetY1;
                y2 = myAnchorY2 ? containerCY - myInsetY2 : y1 + myCY;
            } else if (myAnchorY2) {
                y2 = containerCY - myInsetY2;
                y1 = y2 - myCY;
            } else {
                y1 = (int) (myPercentY1 * containerCY);
                y2 = containerCY - (int) (myPercentY2 * containerCY);
            }

            final Rectangle bounds = new Rectangle(x1, y1, x2 - x1, y2 - y1);
            myComponent.setBounds(bounds);
        }
    }

    /** An flag that indicates the component should anchor to the bottom. */
    public static final String       ANCHOR_BOTTOM = "B";

    /** An flag that indicates the component should anchor to the left. */
    public static final String       ANCHOR_LEFT   = "L";

    /** An flag that indicates the component should anchor to the right. */
    public static final String       ANCHOR_RIGHT  = "R";

    /** An flag that indicates the component should anchor to the top. */
    public static final String       ANCHOR_TOP    = "T";

    /** The anchored components. */
    private final Collection<Anchor> myAnchors     = new ArrayList<Anchor>();

    /** The minimum width of the container. */
    final int                        myMinimumCX;

    /** The minimum height of the container. */
    final int                        myMinimumCY;


    /**
     * Initializes a new instance of the class. The minimum width and height must
     * be at least one.
     * 
     * @param minimumCX The minimum and initial width of the container.
     * 
     * @param minimumCY The minimum and initial height of the container.
     * 
     * @throws IllegalArgumentException Thrown if either of the minimum sizes are
     *           less than one.
     */
    public AnchorLayoutManager(final int minimumCX, final int minimumCY) {

        if (minimumCX < 1)
            throw new IllegalArgumentException("minimumCX");

        if (minimumCY < 1)
            throw new IllegalArgumentException("minimumCY");

        myMinimumCX = minimumCX;
        myMinimumCY = minimumCY;
    }


    /**
     * Adds a component to the layout manager.
     * 
     * @param flags The layout flags.
     * 
     * @param component The component to add.
     * 
     * @throws NullPointerException Thrown if either of the arguments are null.
     */
    public void addLayoutComponent(final String flags, final Component component) {

        if (null == flags)
            throw new NullPointerException("flags");

        if (null == component)
            throw new NullPointerException("component");

        myAnchors.add(new Anchor(flags, component));
    }


    /**
     * Positions each component added to the layout based on the size of the
     * specified container.
     * 
     * @param container The container.
     * 
     * @throws NullPointerException Thrown if the container is null.
     */
    public void layoutContainer(final Container container) {

        if (null == container)
            throw new NullPointerException("container");

        final int cx = Math.max(myMinimumCX, container.getWidth());
        final int cy = Math.max(myMinimumCY, container.getHeight());
        for (final Anchor anchor : myAnchors)
            anchor.setBounds(cx, cy);
    }


    /**
     * Returns the minimum layout size. This is the size specified in the
     * constructor.
     * 
     * @param container The container (not used).
     * 
     * @return The minimum size.
     * 
     * @throws NullPointerException Thrown if the container is null.
     */
    public Dimension minimumLayoutSize(final Container container) {

        if (null == container)
            throw new NullPointerException("container");

        return new Dimension(myMinimumCX, myMinimumCY);
    }


    /**
     * Returns the preferred layout size. This is the maximum of the minimum size
     * and the current size of the container.
     * 
     * @param container The container.
     * 
     * @return The preferred size.
     * 
     * @throws NullPointerException Thrown if the container is null.
     */
    public Dimension preferredLayoutSize(final Container container) {

        if (null == container)
            throw new NullPointerException("container");

        final int cx = Math.max(myMinimumCX, container.getWidth());
        final int cy = Math.max(myMinimumCY, container.getHeight());
        return new Dimension(cx, cy);
    }


    /**
     * Removes a component from the layout.
     * 
     * @param component The component to remove.
     * 
     * @throws NullPointerException Thrown if the component is null.
     */
    public void removeLayoutComponent(final Component component) {

        if (null == component)
            throw new NullPointerException("component");

        myAnchors.remove(component);
    }
}
Valid HTML 4.01 Valid CSS