/** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES (OR CONDITIONS), EXPRESS OR IMPLIED WITH RESPECT TO THE PROGRAM, INCLUDING THE IMPLIED WARRANTIES (OR CONDITIONS) OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE PROGRAM AND DOCUMENTATION REMAINS WITH THE USER. */ package de.uni_passau.fim.infosun.prophet.util; import java.awt.AWTError; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * A vertical layout manager similar to <code>FlowLayout</code>. * Like <code>FlowLayout</code> components do not expand to fill available space except when the horizontal alignment * is <code>STRETCH</code> in which case components are stretched horizontally. * <p> * Unlike <code>FlowLayout</code>, components will not wrap to form another column if there isn't enough space * vertically. <code>VerticalLayout</code> can optionally anchor components to the top or bottom of the display area * or center them between the top and bottom. * <p> * * Revision date 12th July 2001 * * @author Colin Mummery e-mail: colin_mummery@yahoo.com Homepage:www.kagi.com/equitysoft - * Based on 'FlexLayout' in Java class libraries Vol 2 Chan/Lee Addison-Wesley 1998 */ public class VerticalLayout implements LayoutManager { /** * The horizontal alignment constant that designates centering. Also used to designate center anchoring. */ public static final int CENTER = 0; /** * The horizontal alignment constant that designates right justification. */ public static final int RIGHT = 1; /** * The horizontal alignment constant that designates left justification. */ public static final int LEFT = 2; /** * The horizontal alignment constant that designates stretching the component horizontally. */ public static final int STRETCH = 3; /** * The anchoring constant that designates anchoring to the top of the display area */ public static final int TOP = 4; /** * The anchoring constant that designates anchoring to the bottom of the display area */ public static final int BOTTOM = 5; /** * A read-only map containing <code>String</code> representations of the magic constants used by this class. */ private static final Map<Integer, String> constantReps; static { Map<Integer, String> reps = new HashMap<>(); reps.put(CENTER, "CENTER"); reps.put(RIGHT, "RIGHT"); reps.put(LEFT, "LEFT"); reps.put(STRETCH, "STRETCH"); reps.put(TOP, "TOP"); reps.put(BOTTOM, "BOTTOM"); constantReps = Collections.unmodifiableMap(reps); } private final int vgap; // the vertical gap between components ... defaults to 5 private final int alignment; // LEFT, RIGHT, CENTER or STRETCH ... how the components are justified private final int anchor; // TOP, BOTTOM or CENTER ... where are the components positioned in an overlarge space /** * Constructs a new <code>VerticalLayout</code> with a vertical gap of 5 pixels and horizontal centering. Components * will be anchored to the top of the display area. */ public VerticalLayout() { this(5, CENTER, TOP); } /** * Constructs a new <code>VerticalLayout</code> with the specified vertical gap and horizontal centering. Components * will be anchored to the top of the display area. * * @param vgap * the vertical spacing between components in pixels */ public VerticalLayout(int vgap) { this(vgap, CENTER, TOP); } /** * Constructs a new <code>VerticalLayout</code> with the specified <code>vgap</code> and <code>alignment</code> * in which components will be anchored to the top of the display area. * * @param vgap * the vertical spacing between components in pixels * @param alignment * the horizontal alignment, must be one of {@link #LEFT}, {@link #RIGHT}, {@link #CENTER}, * {@link #STRETCH} */ public VerticalLayout(int vgap, int alignment) { this(vgap, alignment, TOP); } /** * Constructs a new <code>VerticalLayout</code> with the specified <code>vgap</code>, <code>alignment</code> and * <code>anchor</code>. * * @param vgap * the vertical spacing between components in pixels * @param alignment * the horizontal alignment, must be one of {@link #LEFT}, {@link #RIGHT}, {@link #CENTER} or * {@link #STRETCH} * @param anchor * the anchor for the laid out components, must be one of {@link #TOP}, {@link #BOTTOM} or {@link #CENTER} */ public VerticalLayout(int vgap, int alignment, int anchor) { if (!(alignment == LEFT || alignment == RIGHT || alignment == CENTER || alignment == STRETCH)) { throw new AWTError("Invalid alignment."); } if (!(anchor == TOP || anchor == BOTTOM || anchor == CENTER)) { throw new AWTError("Invalid anchor."); } this.vgap = vgap; this.alignment = alignment; this.anchor = anchor; } /** * Calculates the minimum or preferred size dimensions for the specified container, given the components it * contains. * * @param parent * the component to be laid out * @param minimum * true for minimum size, false for preferred size * * @see #preferredLayoutSize(java.awt.Container) * @see #minimumLayoutSize(java.awt.Container) */ private Dimension layoutSize(Container parent, boolean minimum) { Dimension size = new Dimension(); Dimension componentSize; Component[] components; Component component; synchronized (parent.getTreeLock()) { components = parent.getComponents(); for (int i = 0; i < components.length; i++) { component = components[i]; if (component.isVisible()) { componentSize = minimum ? component.getMinimumSize() : component.getPreferredSize(); size.width = Math.max(size.width, componentSize.width); size.height += componentSize.height; if (i < components.length - 1) { size.height += vgap; } } } } Insets parentInsets = parent.getInsets(); size.width += parentInsets.left + parentInsets.right; size.height += parentInsets.top + parentInsets.bottom + vgap + vgap; return size; } @Override public void layoutContainer(Container parent) { synchronized (parent.getTreeLock()) { Insets parentInsets = parent.getInsets(); Dimension parentDimension = parent.getSize(); Component[] components = parent.getComponents(); Dimension componentDimension; int y = 0; for (Component component : components) { componentDimension = component.getPreferredSize(); y += componentDimension.height + vgap; } y -= vgap; //otherwise there is a vgap too many // modify y to fit the chosen anchor if (anchor == TOP) { y = parentInsets.top; } else if (anchor == CENTER) { y = (parentDimension.height - y) / 2; } else { y = parentDimension.height - y - parentInsets.bottom; } int x; int width; // do the layout for (Component component : components) { componentDimension = component.getPreferredSize(); x = parentInsets.left; width = componentDimension.width; if (alignment == CENTER) { x = (parentDimension.width - componentDimension.width) / 2; } else if (alignment == RIGHT) { x = parentDimension.width - componentDimension.width - parentInsets.right; } else if (alignment == STRETCH) { width = parentDimension.width - parentInsets.left - parentInsets.right; } component.setBounds(x, y, width, componentDimension.height); y += componentDimension.height + vgap; } } } @Override public Dimension minimumLayoutSize(Container parent) { return layoutSize(parent, false); } @Override public Dimension preferredLayoutSize(Container parent) { return layoutSize(parent, true); } @Override public void addLayoutComponent(String name, Component comp) { // this LayoutManager does not store component specific information } @Override public void removeLayoutComponent(Component comp) { // this LayoutManager does not store component specific information } @Override public String toString() { String unknown = "Unknown"; String anchor = constantReps.containsKey(this.anchor) ? constantReps.get(this.anchor) : unknown; String alignment = constantReps.containsKey(this.alignment) ? constantReps.get(this.alignment) : unknown; return String.format("%s[vgap=%dpx align=%s anchor=%s]", getClass().getName(), vgap, alignment, anchor); } }