New file |
| | |
| | | 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 <code>componentOrientation</code> |
| | | * property and may be one of two values: |
| | | * <ul> |
| | | * <li><code>ComponentOrientation.TOP_TO_BOTTOM</code> |
| | | * <li><code>ComponentOrientation.BOTTOM_TO_TOP</code> |
| | | * </ul> |
| | | * 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 <code>align</code> |
| | | * property. The possible values are: |
| | | * <ul> |
| | | * <li>{@link #TOP TOP} |
| | | * <li>{@link #BOTTOM BOTTOM} |
| | | * <li>{@link #CENTER CENTER} |
| | | * <li>{@link #LEADING LEADING} |
| | | * <li>{@link #TRAILING TRAILING} |
| | | * </ul> |
| | | * <p> |
| | | */ |
| | | 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; |
| | | |
| | | /** |
| | | * <code>align</code> is the property that determines |
| | | * how each column distributes empty space. |
| | | * It can be one of the following three values: |
| | | * <ul> |
| | | * <code>TOP</code> |
| | | * <code>BOTTOM</code> |
| | | * <code>CENTER</code> |
| | | * </ul> |
| | | * |
| | | * @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 |
| | | * <code>Container</code>. |
| | | * |
| | | * @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 <code>Container</code>. |
| | | * |
| | | * @see #getHgap() |
| | | * @see #setHgap(int) |
| | | */ |
| | | int vgap; |
| | | |
| | | /** |
| | | * Constructs a new <code>VerticalFlowLayout</code> with a centered alignment and a |
| | | * default 5-unit horizontal and vertical gap. |
| | | */ |
| | | public VerticalFlowLayout() |
| | | { |
| | | this(CENTER, 5, 5); |
| | | } |
| | | |
| | | /** |
| | | * Constructs a new <code>VerticalFlowLayout</code> with the specified |
| | | * alignment and a default 5-unit horizontal and vertical gap. |
| | | * The value of the alignment argument must be one of |
| | | * <code>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>, |
| | | * or <code>VerticalFlowLayout.CENTER</code> |
| | | * @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. |
| | | * <p> |
| | | * The value of the alignment argument must be one of |
| | | * <code>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>, |
| | | * or <code>VerticalFlowLayout.CENTER</code>. |
| | | * @param align the alignment value |
| | | * @param hgap the horizontal gap between components |
| | | * and between the components and the |
| | | * borders of the <code>Container</code> |
| | | * @param vgap the vertical gap between components |
| | | * and between the components and the |
| | | * borders of the <code>Container</code> |
| | | */ |
| | | 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 <code>VerticalFlowLayout.TOP</code>, |
| | | * <code>VerticalFlowLayout.BOTTOM</code> or <code>VerticalFlowLayout.CENTER</code>, |
| | | * @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 |
| | | * <ul> |
| | | * <li><code>VerticalFlowLayout.TOP</code> |
| | | * <li><code>VerticalFlowLayout.BOTTOM</code> |
| | | * <li><code>VerticalFlowLayout.CENTER</code> |
| | | * </ul> |
| | | * @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 <code>Container</code> |
| | | * |
| | | * @return the horizontal gap between components |
| | | * and between the components and the borders |
| | | * of the <code>Container</code> |
| | | * @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 |
| | | * <code>Container</code>. |
| | | * |
| | | * @param hgap the horizontal gap between components |
| | | * and between the components and the borders |
| | | * of the <code>Container</code> |
| | | * @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 |
| | | * <code>Container</code>. |
| | | * |
| | | * @return the vertical gap between components |
| | | * and between the components and the borders |
| | | * of the <code>Container</code> |
| | | * @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 <code>Container</code>. |
| | | * |
| | | * @param vgap the vertical gap between components |
| | | * and between the components and the borders |
| | | * of the <code>Container</code> |
| | | * @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 |
| | | * <i>visible</i> 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 <i>visible</i> |
| | | * 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 |
| | | * <i>visible</i> component take |
| | | * its preferred size by reshaping the components in the |
| | | * target container in order to satisfy the alignment of |
| | | * this <code>VerticalFlowLayout</code> 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 <code>VerticalFlowLayout</code> |
| | | * 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); |
| | | } |
| | | |
| | | |
| | | } |