/*
* Copyright (c) 2002-2007 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 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.FormSpec;
import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.util.LayoutStyle;
/**
* A non-visual builder that assists you in building consistent button bars
* that comply with popular UI style guides. It utilizes the {@link FormLayout}.
* This class is in turn used by the
* {@link com.jgoodies.forms.factories.ButtonBarFactory} that provides
* an even higher level of abstraction for building consistent button bars.<p>
*
* Buttons added to the builder are either gridded or fixed and may fill
* their FormLayout cell or not. All gridded buttons get the same width,
* while fixed buttons use their own size. Gridded buttons honor
* the default minimum button width as specified by the current
* {@link com.jgoodies.forms.util.LayoutStyle}.<p>
*
* You can set an optional hint for narrow margin for the fixed width buttons.
* This is useful if you want to lay out a button bar that includes a button
* with a long text. For example, in a bar with
* 'Copy to Clipboard', 'OK', 'Cancel' you may declare the clipboard button
* as a fixed size button with narrow margins, OK and Cancel as gridded.
* Gridded buttons are marked as narrow by default.
* Note that some look&feels do not support the narrow margin feature,
* and conversely, others have only narrow margins. The JGoodies look&feels
* honor the setting, the Mac Aqua l&f uses narrow margins all the time.<p>
*
* To honor the platform's button order (left-to-right vs. right-to-left)
* this builder uses the <em>leftToRightButtonOrder</em> 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 #addGriddedButtons(JButton[])} honor the button order.
* If you want to ignore the default button order, you can either
* add add individual buttons, or create a ButtonBarBuilder instance
* with the order set to left-to-right. For the latter see
* {@link #createLeftToRightBuilder()}. Also see the button order
* example below.<p>
*
* <strong>Example:</strong><br>
* The following example builds a button bar with <i>Help</i> button on the
* left-hand side and <i>OK, Cancel, Apply</i> buttons on the right-hand side.
* <pre>
* private JPanel createHelpOKCancelApplyBar(
* JButton help, JButton ok, JButton cancel, JButton apply) {
* ButtonBarBuilder builder = new ButtonBarBuilder();
* builder.addGridded(help);
* builder.addRelatedGap();
* builder.addGlue();
* builder.addGriddedButtons(new JButton[]{ok, cancel, apply});
* return builder.getPanel();
* }
* </pre><p>
*
* <strong>Button Order Example:</strong><br>
* The following example builds three button bars where one honors
* the platform's button order and the other two ignore it.
* <pre>
* public JComponent buildPanel() {
* FormLayout layout = new FormLayout("pref");
* DefaultFormBuilder rowBuilder = new DefaultFormBuilder(layout);
* rowBuilder.setDefaultDialogBorder();
*
* rowBuilder.append(buildButtonSequence(new ButtonBarBuilder()));
* rowBuilder.append(buildButtonSequence(ButtonBarBuilder.createLeftToRightBuilder()));
* rowBuilder.append(buildIndividualButtons(new ButtonBarBuilder()));
*
* return rowBuilder.getPanel();
* }
*
* private Component buildButtonSequence(ButtonBarBuilder builder) {
* builder.addGriddedButtons(new JButton[] {
* new JButton("One"),
* new JButton("Two"),
* new JButton("Three")
* });
* return builder.getPanel();
* }
*
* private Component buildIndividualButtons(ButtonBarBuilder builder) {
* builder.addGridded(new JButton("One"));
* builder.addRelatedGap();
* builder.addGridded(new JButton("Two"));
* builder.addRelatedGap();
* builder.addGridded(new JButton("Three"));
* return builder.getPanel();
* }
* </pre>
*
* @author Karsten Lentzsch
* @version $Revision$
*
* @see ButtonStackBuilder
* @see com.jgoodies.forms.factories.ButtonBarFactory
* @see com.jgoodies.forms.util.LayoutStyle
*/
public final class ButtonBarBuilder extends PanelBuilder {
/**
* 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[] { new RowSpec(
"center:pref") };
/**
* The client property key used to indicate that a button shall
* get narrow margins on the left and right hand side.<p>
*
* This optional setting will be honored by all JGoodies Look&Feel
* implementations. The Mac Aqua l&f uses narrow margins only.
* Other look&feel implementations will likely ignore this key
* and so may render a wider button margin.
*/
private static final String NARROW_KEY = "jgoodies.isNarrow";
/**
* 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 #addGriddedButtons(JButton[])}, and ignored if you add
* individual button, for example using {@link #addGridded(JComponent)}.
*
* @see #isLeftToRight()
* @see #setLeftToRight(boolean)
* @see #addGriddedButtons(JButton[])
* @see #addGriddedGrowingButtons(JButton[])
*/
private boolean leftToRight;
// Instance Creation ****************************************************
/**
* Constructs an instance of <code>ButtonBarBuilder</code> on a
* <code>JPanel</code> using a preconfigured FormLayout as layout manager.
*/
public ButtonBarBuilder() {
this(new JPanel(null));
}
/**
* Constructs an instance of <code>ButtonBarBuilder</code> on the given
* panel using a preconfigured FormLayout as layout manager.
*
* @param panel the layout container
*/
public ButtonBarBuilder(JPanel panel) {
super(new FormLayout(COL_SPECS, ROW_SPECS), panel);
leftToRight = LayoutStyle.getCurrent().isLeftToRightButtonOrder();
}
/**
* Creates and returns a <code>ButtonBarBuilder</code> with
* initialized with a left to right button order.
*
* @return a button bar builder with button order set to left-to-right
*/
public static ButtonBarBuilder createLeftToRightBuilder() {
ButtonBarBuilder builder = new ButtonBarBuilder();
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
* @since 1.0.3
*
* @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
* @since 1.0.3
*
* @see LayoutStyle#isLeftToRightButtonOrder()
*/
public void setLeftToRightButtonOrder(boolean newButtonOrder) {
leftToRight = newButtonOrder;
}
// Default Borders ******************************************************
/**
* Sets a default border that has a gap in the bar's north.
*/
public void setDefaultButtonBarGapBorder() {
getPanel().setBorder(Borders.BUTTON_BAR_GAP_BORDER);
}
// Adding Components ****************************************************
/**
* Adds a sequence of related gridded buttons each 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
*
* @see LayoutStyle
*/
public void addGriddedButtons(JButton[] buttons) {
int length = buttons.length;
for (int i = 0; i < length; i++) {
int index = leftToRight ? i : length - 1 - i;
addGridded(buttons[index]);
if (i < buttons.length - 1) {
addRelatedGap();
}
}
}
/**
* Adds a sequence of gridded buttons that grow
* 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
*
* @see LayoutStyle
*/
public void addGriddedGrowingButtons(JButton[] buttons) {
int length = buttons.length;
for (int i = 0; i < length; i++) {
int index = leftToRight ? i : length - 1 - i;
addGriddedGrowing(buttons[index]);
if (i < buttons.length - 1) {
addRelatedGap();
}
}
}
/**
* Adds a fixed size component. Unlike the gridded components,
* this component keeps its individual preferred dimension.
*
* @param component the component to add
*/
public void addFixed(JComponent component) {
getLayout().appendColumn(FormFactory.PREF_COLSPEC);
add(component);
nextColumn();
}
/**
* Adds a fixed size component with narrow margins. Unlike the gridded
* components, this component keeps its individual preferred dimension.
*
* @param component the component to add
*/
public void addFixedNarrow(JComponent component) {
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
addFixed(component);
}
/**
* Adds a gridded component, i.e. a component that will get
* the same dimension as all other gridded components.
*
* @param component the component to add
*/
public void addGridded(JComponent component) {
getLayout().appendColumn(FormFactory.BUTTON_COLSPEC);
getLayout().addGroupedColumn(getColumn());
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
add(component);
nextColumn();
}
/**
* Adds a gridded component that grows. The component's initial size
* (before it grows) is the same as for all other gridded components.
*
* @param component the component to add
*/
public void addGriddedGrowing(JComponent component) {
getLayout().appendColumn(FormFactory.GROWING_BUTTON_COLSPEC);
getLayout().addGroupedColumn(getColumn());
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
add(component);
nextColumn();
}
/**
* Adds a glue that will be given the extra space,
* if this box is larger than its preferred size.
*/
public void addGlue() {
appendGlueColumn();
nextColumn();
}
/**
* Adds the standard gap for related components.
*/
public void addRelatedGap() {
appendRelatedComponentsGapColumn();
nextColumn();
}
/**
* Adds the standard gap for unrelated components.
*/
public void addUnrelatedGap() {
appendUnrelatedComponentsGapColumn();
nextColumn();
}
/**
* Adds a strut of a specified size.
*
* @param size a <code>ConstantSize</code> that describes the gap's size
*/
public void addStrut(ConstantSize size) {
getLayout().appendColumn(
new ColumnSpec(ColumnSpec.LEFT, size, FormSpec.NO_GROW));
nextColumn();
}
}