
com.jgoodies.forms.builder.ButtonBarBuilder2 Maven / Gradle / Ivy
Show all versions of jgoodiesforms Show documentation
/*
* Copyright (c) 2002-2012 JGoodies Karsten Lentzsch. 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 Karsten Lentzsch 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.jgoodies.forms.builder;
import static com.jgoodies.common.base.Preconditions.checkArgument;
import static com.jgoodies.common.base.Preconditions.checkNotNull;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.ConstantSize;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.util.LayoutStyle;
/**
* A non-visual builder for building consistent button bars that comply
* with popular style guides. Utilizes the JGoodies {@link FormLayout}
* and honors the platform's {@link LayoutStyle} regarding button sizes,
* gap widths, and the default button order.
*
* This is an improved version of the older {@code ButtonBarBuilder}.
* The ButtonBarBuilder2 has a simpler, safer, and more convenient API,
* see below for a comparison.
*
* ButtonBarBuilder2 vs. ButtonBarBuilder:
* ButtonBarBuilder2 uses only 3 component types that can be added:
* button, standard, and growing button, where
* ButtonBarBuilder has button, fixed, and growing.
* Also, the ButtonBarBuilder2 doesn't group buttons.
* The layout of the ButtonBarBuilder and ButtonBarBuilder2 is the same
* if all buttons are smaller than {@link LayoutStyle#getDefaultButtonWidth()}.
* If some buttons are wider, ButtonBarBuilder2 will make only these buttons
* wider, where the old ButtonBarBuilder makes all (gridded) buttons wider.
*
*
* Examples:
* // Build a right-aligned bar for: OK, Cancel, Apply
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
* builder.addGlue();
* builder.addButton(okButton);
* builder.addRelatedGap();
* builder.addButton(cancelButton);
* builder.addRelatedGap();
* builder.addButton(applyButton);
* return builder.getPanel();
*
* // Add a sequence of related buttons
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
* builder.addGlue();
* builder.addButton(okButton, cancelButton, applyButton);
* return builder.getPanel();
*
* // Add a sequence of related buttons for given Actions
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
* builder.addGlue();
* builder.addButton(okAction, cancelAction, applyAction);
* return builder.getPanel();
*
*
* Buttons are added to a builder individually or as a sequence.
*
* To honor the platform's button order (left-to-right vs. right-to-left)
* this builder uses the leftToRightButtonOrder property.
* It is initialized with the current LayoutStyle's button order,
* which in turn is left-to-right on most platforms and right-to-left
* on the Mac OS X. Builder methods that create sequences of buttons
* (e.g. {@link #addButton(JComponent[])} honor the button order.
* If you want to ignore the default button order, you can either
* add individual buttons, or create a ButtonBarBuilder2 instance
* with the order set to left-to-right. For the latter see
* {@link #createLeftToRightBuilder()}. Also see the button order
* example below.
*
* Example:
* The following example builds a button bar with Help button on the
* left-hand side and OK, Cancel, Apply buttons on the right-hand side.
*
* private JPanel createHelpOKCancelApplyBar(
* JButton help, JButton ok, JButton cancel, JButton apply) {
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
* builder.addButton(help);
* builder.addUnrelatedGap();
* builder.addGlue();
* builder.addButton(new JButton[]{ok, cancel, apply});
* return builder.getPanel();
* }
*
*
* Button Order Example:
* The following example builds three button bars where one honors
* the platform's button order and the other two ignore it.
*
* public JComponent buildPanel() {
* FormLayout layout = new FormLayout("pref");
* DefaultFormBuilder rowBuilder = new DefaultFormBuilder(layout);
* rowBuilder.setDefaultDialogBorder();
*
* rowBuilder.append(buildButtonSequence(new ButtonBarBuilder2()));
* rowBuilder.append(buildButtonSequence(ButtonBarBuilder2.createLeftToRightBuilder()));
* rowBuilder.append(buildIndividualButtons(new ButtonBarBuilder2()));
*
* return rowBuilder.getPanel();
* }
*
* private Component buildButtonSequence(ButtonBarBuilder2 builder) {
* builder.addButton(new JButton[] {
* new JButton("One"),
* new JButton("Two"),
* new JButton("Three")
* });
* return builder.getPanel();
* }
*
* private Component buildIndividualButtons(ButtonBarBuilder2 builder) {
* builder.addButton(new JButton("One"));
* builder.addRelatedGap();
* builder.addButton(new JButton("Two"));
* builder.addRelatedGap();
* builder.addButton(new JButton("Three"));
* return builder.getPanel();
* }
*
*
* @author Karsten Lentzsch
* @version $Revision: 1.18 $
*
* @see ButtonStackBuilder
* @see com.jgoodies.forms.factories.ButtonBarFactory
* @see com.jgoodies.forms.util.LayoutStyle
*/
public class ButtonBarBuilder2 extends AbstractButtonPanelBuilder {
/**
* Specifies the columns of the initial FormLayout used in constructors.
*/
private static final ColumnSpec[] COL_SPECS =
new ColumnSpec[]{};
/**
* Specifies the FormLayout's the single button bar row.
*/
private static final RowSpec[] ROW_SPECS =
new RowSpec[]{ RowSpec.decode("center:pref") };
/**
* Describes how sequences of buttons are added to the button bar:
* left-to-right or right-to-left. This setting is initialized using
* the current {@link LayoutStyle}'s button order. It is honored
* only by builder methods that build sequences of button, for example
* {@link #addButton(JComponent[])}, and ignored if you add
* individual button, for example using {@link #addButton(JComponent)}.
*
* @see #isLeftToRight()
* @see #setLeftToRight(boolean)
* @see #addGrowing(JComponent[])
*/
private boolean leftToRight;
// Instance Creation ******************************************************
/**
* Constructs an empty ButtonBarBuilder2 on a JPanel.
*/
public ButtonBarBuilder2() {
this(new JPanel(null));
}
/**
* Constructs an empty ButtonBarBuilder2 on the given panel.
*
* @param panel the layout container
*/
public ButtonBarBuilder2(JPanel panel) {
super(new FormLayout(COL_SPECS, ROW_SPECS), panel);
leftToRight = LayoutStyle.getCurrent().isLeftToRightButtonOrder();
}
/**
* Creates and returns an empty ButtonBarBuilder2 with
* a left to right button order.
*
* @return a button bar builder with button order set to left-to-right
*/
public static ButtonBarBuilder2 createLeftToRightBuilder() {
ButtonBarBuilder2 builder = new ButtonBarBuilder2();
builder.setLeftToRightButtonOrder(true);
return builder;
}
// Accessing Properties ***************************************************
/**
* Returns whether button sequences will be ordered from
* left to right or from right to left.
*
* @return true if button sequences are ordered from left to right
*
* @see LayoutStyle#isLeftToRightButtonOrder()
*/
public boolean isLeftToRightButtonOrder() {
return leftToRight;
}
/**
* Sets the order for button sequences to either left to right,
* or right to left.
*
* @param newButtonOrder true if button sequences shall be ordered
* from left to right
*
* @return this builder
*
* @see LayoutStyle#isLeftToRightButtonOrder()
*/
public ButtonBarBuilder2 setLeftToRightButtonOrder(boolean newButtonOrder) {
leftToRight = newButtonOrder;
return this;
}
// Default Borders ******************************************************
/**
* Sets a default border that has a gap in the bar's north.
*
* @return this builder
*/
public ButtonBarBuilder2 setDefaultButtonBarGapBorder() {
setBorder(Borders.BUTTON_BAR_GAP_BORDER);
return this;
}
// Spacing ****************************************************************
/**
* Adds a glue that will be given the extra space,
* if this button bar is larger than its preferred size.
*
* @return this builder
*/
public ButtonBarBuilder2 addGlue() {
appendGlueColumn();
nextColumn();
return this;
}
/**
* Adds the standard horizontal gap for related components.
*
* @return this builder
*
* @see LayoutStyle#getRelatedComponentsPadX()
*/
public ButtonBarBuilder2 addRelatedGap() {
appendRelatedComponentsGapColumn();
nextColumn();
return this;
}
/**
* Adds the standard horizontal gap for unrelated components.
*
* @return this builder
*
* @see LayoutStyle#getUnrelatedComponentsPadX()
*/
public ButtonBarBuilder2 addUnrelatedGap() {
appendUnrelatedComponentsGapColumn();
nextColumn();
return this;
}
/**
* Adds a horizontal strut of the specified width.
* For related and unrelated components use {@link #addRelatedGap()}
* and {@link #addUnrelatedGap()} respectively.
*
* @param width describes the gap width
*
* @return this builder
*
* @see ColumnSpec#createGap(ConstantSize)
*/
public ButtonBarBuilder2 addStrut(ConstantSize width) {
getLayout().appendColumn(ColumnSpec.createGap(width));
nextColumn();
return this;
}
// Buttons ****************************************************************
/**
* Adds a command button component that has a minimum width
* specified by the {@link LayoutStyle#getDefaultButtonWidth()}.
*
* Although a JButton is expected, any JComponent is accepted
* to allow custom button component types.
*
* @param button the component to add
*
* @return this builder
*
* @throws NullPointerException if {@code button} is {@code null}
*/
public ButtonBarBuilder2 addButton(JComponent button) {
button.putClientProperty(NARROW_KEY, Boolean.TRUE);
getLayout().appendColumn(FormFactory.BUTTON_COLSPEC);
add(button);
nextColumn();
return this;
}
/**
* Adds a sequence of related button components.
* Each button has the minimum width as specified by
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.
*
* Uses this builder's button order (left-to-right vs. right-to-left).
* If you want to use a fixed order, add individual buttons instead.
*
* Although JButtons are expected, general JComponents are accepted
* to allow custom button component types.
*
* @param buttons an array of buttons to add
*
* @return this builder
*
* @throws NullPointerException if the button array or a button is {@code null}
* @throws IllegalArgumentException if the button array is empty
*
* @see #addButton(JComponent)
*/
public ButtonBarBuilder2 addButton(JComponent... buttons) {
checkNotNull(buttons, "The button array must not be null.");
int length = buttons.length;
checkArgument(length > 0, "The button array must not be empty.");
for (int i = 0; i < length; i++) {
int index = leftToRight ? i : length -1 - i;
addButton(buttons[index]);
if (i < buttons.length - 1) {
addRelatedGap();
}
}
return this;
}
/**
* Adds a JButton for the given Action that has a minimum width
* specified by the {@link LayoutStyle#getDefaultButtonWidth()}.
*
* @param action the action that describes the button to add
*
* @return this builder
*
* @throws NullPointerException if {@code action} is {@code null}
*
* @see #addButton(JComponent)
*/
public ButtonBarBuilder2 addButton(Action action) {
checkNotNull(action, "The button Action must not be null.");
return addButton(createButton(action));
}
/**
* Adds a sequence of related JButtons built from the given Actions
* that are separated by the default gap as specified by
* {@link LayoutStyle#getRelatedComponentsPadX()}.
*
* Uses this builder's button order (left-to-right vs. right-to-left).
* If you want to use a fixed order, add individual Actions instead.
*
* @param actions the Actions that describe the buttons to add
*
* @return this builder
*
* @throws NullPointerException if the Action array or an Action is {@code null}
* @throws IllegalArgumentException if the Action array is empty
*
* @see #addButton(JComponent[])
*/
public ButtonBarBuilder2 addButton(Action... actions) {
checkNotNull(actions, "The Action array must not be null.");
int length = actions.length;
checkArgument(length > 0, "The Action array must not be empty.");
JButton[] buttons = new JButton[length];
for (int i = 0; i < length; i++) {
buttons[i] = createButton(actions[i]);
}
return addButton(buttons);
}
// Other ******************************************************************
/**
* Adds a button or other component that grows if the container grows.
* The component's initial size (before it grows) is specified
* by the {@link LayoutStyle#getDefaultButtonWidth()}.
*
* @param component the component to add
*
* @return this builder
*/
public ButtonBarBuilder2 addGrowing(JComponent component) {
getLayout().appendColumn(FormFactory.GROWING_BUTTON_COLSPEC);
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
add(component);
nextColumn();
return this;
}
/**
* Adds a sequence of related growing buttons
* where each is separated by a default gap.
* Honors this builder's button order. If you
* want to use a fixed left to right order,
* add individual buttons.
*
* @param buttons an array of buttons to add
*
* @return this builder
*
* @see LayoutStyle
*/
public ButtonBarBuilder2 addGrowing(JComponent... buttons) {
int length = buttons.length;
for (int i = 0; i < length; i++) {
int index = leftToRight ? i : length -1 - i;
addGrowing(buttons[index]);
if (i < buttons.length - 1) {
addRelatedGap();
}
}
return this;
}
/**
* Adds a fixed size component with narrow margin. Unlike the gridded
* components, this component keeps its individual preferred dimension.
*
* @param component the component to add
*
* @return this builder
*/
public ButtonBarBuilder2 addFixed(JComponent component) {
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
getLayout().appendColumn(FormFactory.PREF_COLSPEC);
add(component);
nextColumn();
return this;
}
}