package com.gitblit.client; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * A flow layout arranges components in a directional flow, much * like lines of text in a paragraph. The flow direction is * determined by the container's componentOrientation * property and may be one of two values: * * Flow layouts are typically used * to arrange buttons in a panel. It arranges buttons * horizontally until no more buttons fit on the same line. * The line alignment is determined by the align * property. The possible values are: * *

*/ public class VerticalFlowLayout implements LayoutManager, java.io.Serializable { /** * This value indicates that each row of components * should be left-justified. */ public static final int TOP = 0; /** * This value indicates that each row of components * should be centered. */ public static final int CENTER = 1; /** * This value indicates that each row of components * should be right-justified. */ public static final int BOTTOM = 2; /** * align is the property that determines * how each column distributes empty space. * It can be one of the following three values: *

* * @see #getAlignment * @see #setAlignment */ int align; // This is the one we actually use /** * The flow layout manager allows a seperation of * components with gaps. The horizontal gap will * specify the space between components and between * the components and the borders of the * Container. * * @see #getHgap() * @see #setHgap(int) */ int hgap; /** * The flow layout manager allows a seperation of * components with gaps. The vertical gap will * specify the space between rows and between the * the rows and the borders of the Container. * * @see #getHgap() * @see #setHgap(int) */ int vgap; /** * Constructs a new VerticalFlowLayout with a centered alignment and a * default 5-unit horizontal and vertical gap. */ public VerticalFlowLayout() { this(CENTER, 5, 5); } /** * Constructs a new VerticalFlowLayout with the specified * alignment and a default 5-unit horizontal and vertical gap. * The value of the alignment argument must be one of * VerticalFlowLayout.TOP, VerticalFlowLayout.BOTTOM, * or VerticalFlowLayout.CENTER * @param align the alignment value */ public VerticalFlowLayout(int align) { this(align, 5, 5); } /** * Creates a new flow layout manager with the indicated alignment * and the indicated horizontal and vertical gaps. *

* The value of the alignment argument must be one of * VerticalFlowLayout.TOP, VerticalFlowLayout.BOTTOM, * or VerticalFlowLayout.CENTER. * @param align the alignment value * @param hgap the horizontal gap between components * and between the components and the * borders of the Container * @param vgap the vertical gap between components * and between the components and the * borders of the Container */ public VerticalFlowLayout(int align, int hgap, int vgap) { this.hgap = hgap; this.vgap = vgap; setAlignment(align); } /** * Gets the alignment for this layout. * Possible values are VerticalFlowLayout.TOP, * VerticalFlowLayout.BOTTOM or VerticalFlowLayout.CENTER, * @return the alignment value for this layout * @see java.awt.VerticalFlowLayout#setAlignment * @since JDK1.1 */ public int getAlignment() { return align; } /** * Sets the alignment for this layout. Possible values are *

* @param align one of the alignment values shown above * @see #getAlignment() * @since JDK1.1 */ public void setAlignment(int align) { this.align = align; } /** * Gets the horizontal gap between components * and between the components and the borders * of the Container * * @return the horizontal gap between components * and between the components and the borders * of the Container * @see java.awt.VerticalFlowLayout#setHgap * @since JDK1.1 */ public int getHgap() { return hgap; } /** * Sets the horizontal gap between components and * between the components and the borders of the * Container. * * @param hgap the horizontal gap between components * and between the components and the borders * of the Container * @see java.awt.VerticalFlowLayout#getHgap * @since JDK1.1 */ public void setHgap(int hgap) { this.hgap = hgap; } /** * Gets the vertical gap between components and * between the components and the borders of the * Container. * * @return the vertical gap between components * and between the components and the borders * of the Container * @see java.awt.VerticalFlowLayout#setVgap * @since JDK1.1 */ public int getVgap() { return vgap; } /** * Sets the vertical gap between components and between * the components and the borders of the Container. * * @param vgap the vertical gap between components * and between the components and the borders * of the Container * @see java.awt.VerticalFlowLayout#getVgap */ public void setVgap(int vgap) { this.vgap = vgap; } /** * Adds the specified component to the layout. * Not used by this class. * @param name the name of the component * @param comp the component to be added */ public void addLayoutComponent(String name, Component comp) { } /** * Removes the specified component from the layout. * Not used by this class. * @param comp the component to remove * @see java.awt.Container#removeAll */ public void removeLayoutComponent(Component comp) { } /** * Returns the preferred dimensions for this layout given the * visible components in the specified target container. * * @param target the container that needs to be laid out * @return the preferred dimensions to lay out the * subcomponents of the specified container * @see Container * @see #minimumLayoutSize * @see java.awt.Container#getPreferredSize */ public Dimension preferredLayoutSize(Container target) { synchronized (target.getTreeLock()) { Dimension dim = new Dimension(0, 0); int nmembers = target.getComponentCount(); boolean firstVisibleComponent = true; for (int i = 0 ; i < nmembers ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = m.getPreferredSize(); dim.width = Math.max(dim.width, d.width); if (firstVisibleComponent) { firstVisibleComponent = false; } else { dim.height += vgap; } dim.height += d.height; } } Insets insets = target.getInsets(); dim.width += insets.left + insets.right + hgap*2; dim.height += insets.top + insets.bottom + vgap*2; return dim; } } /** * Returns the minimum dimensions needed to layout the visible * components contained in the specified target container. * @param target the container that needs to be laid out * @return the minimum dimensions to lay out the * subcomponents of the specified container * @see #preferredLayoutSize * @see java.awt.Container * @see java.awt.Container#doLayout */ public Dimension minimumLayoutSize(Container target) { synchronized (target.getTreeLock()) { Dimension dim = new Dimension(0, 0); int nmembers = target.getComponentCount(); boolean firstVisibleComponent = true; for (int i = 0 ; i < nmembers ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = m.getMinimumSize(); dim.width = Math.max(dim.width, d.width); if (firstVisibleComponent) { firstVisibleComponent = false; } else { dim.height += vgap; } dim.height += d.height; } } Insets insets = target.getInsets(); dim.width += insets.left + insets.right + hgap*2; dim.height += insets.top + insets.bottom + vgap*2; return dim; } } /** * Lays out the container. This method lets each * visible component take * its preferred size by reshaping the components in the * target container in order to satisfy the alignment of * this VerticalFlowLayout object. * * @param target the specified component being laid out * @see Container * @see java.awt.Container#doLayout */ public void layoutContainer(Container target) { synchronized (target.getTreeLock()) { Insets insets = target.getInsets(); int maxHeight = target.getSize().height - (insets.top + insets.bottom + vgap*2); int nmembers = target.getComponentCount(); int x = insets.left + hgap; int y = 0; int columnWidth = 0; int start = 0; boolean ttb = target.getComponentOrientation().isLeftToRight(); for (int i = 0 ; i < nmembers ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = m.getPreferredSize(); m.setSize(d.width, d.height); if ((y == 0) || ((y + d.height) <= maxHeight)) { if (y > 0) { y += vgap; } y += d.height; columnWidth = Math.max(columnWidth, d.width); } else { moveComponents(target, x, insets.top + vgap, columnWidth, maxHeight - y, start, i, ttb); y = d.height; x += hgap + columnWidth; columnWidth = d.width; start = i; } } } moveComponents(target, x, insets.top + vgap, columnWidth, maxHeight - y, start, nmembers, ttb); } } /** * Centers the elements in the specified row, if there is any slack. * @param target the component which needs to be moved * @param x the x coordinate * @param y the y coordinate * @param width the width dimensions * @param height the height dimensions * @param columnStart the beginning of the column * @param columnEnd the the ending of the column */ private void moveComponents( Container target, int x, int y, int width, int height, int columnStart, int columnEnd, boolean ttb) { switch (align) { case TOP: y += ttb ? 0 : height; break; case CENTER: y += height / 2; break; case BOTTOM: y += ttb ? height : 0; break; } for (int i = columnStart ; i < columnEnd ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { int cx; cx = x + (width - m.getSize().width) / 2; if (ttb) { m.setLocation(cx, y); } else { m.setLocation(cx, target.getSize().height - y - m.getSize().height); } y += m.getSize().height + vgap; } } } /** * Returns a string representation of this VerticalFlowLayout * object and its values. * @return a string representation of this layout */ public String toString() { String str = ""; switch (align) { case TOP: str = ",align=top"; break; case CENTER: str = ",align=center"; break; case BOTTOM: str = ",align=bottom"; break; } return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]"; } public static void main(String[] args) { JPanel main = new JPanel( new BorderLayout() ); final JPanel buttons = new JPanel(new VerticalFlowLayout() ); // buttons.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); main.add(buttons, BorderLayout.CENTER); for (int i = 0; i < 7; i++) { buttons.add( new JRadioButton("button " + i) ); } JButton button = new JButton("Add Radio Button"); main.add(button, BorderLayout.SOUTH); button.addActionListener( new ActionListener() { private int i = 8; public void actionPerformed(ActionEvent e) { buttons.add( new JRadioButton("button R Us" + i++) ); buttons.revalidate(); // pack(); } }); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(main); frame.setSize(300, 300); frame.setLocationRelativeTo(null); frame.setVisible(true); } }