/* * Copyright (c) 2003 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 net.sourceforge.squirrel_sql.client.gui.builders; import java.awt.Component; import java.util.ResourceBundle; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import com.jgoodies.forms.factories.FormFactory; import com.jgoodies.forms.layout.ConstantSize; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.RowSpec; /** * Provides a means to build consistent form-oriented panels quickly * using the {@link FormLayout}. This builder combines frequently used * panel building steps: add a new row, add a label, proceed to the next * data column, then add a component. * <p> * This builder can map resource keys to internationalized (i15d) texts * when creating text labels, titles and titled separators. Therefore * you must specify a <code>ResourceBundle</code> in the constructor. * The builder methods throw an <code>IllegalStateException</code> * if one of the mapping builder methods is invoked and no bundle has been set. * <p> * This class is not yet part of the binary Forms library; * it comes with the Forms distributions as an extra. * <b>The API is work in progress and may change without notice.</b> * If you want to use this class, you may consider copying it into your codebase. * <p> * <b>Example:</b> * <pre> * public void build() { * FormLayout layout = new FormLayout( * "right:max(40dlu;pref), 3dlu, 80dlu, 7dlu, " // 1st major colum * + "right:max(40dlu;pref), 3dlu, 80dlu", // 2nd major column * ""); // add rows dynamically * DefaultFormBuilder builder = new DefaultFormBuilder(layout); * builder.setDefaultDialogBorder(); * * builder.appendSeparator("Flange"); * * builder.append("Identifier", identifierField); * builder.nextLine(); * * builder.append("PTI [kW]", new JTextField()); * builder.append("Power [kW]", new JTextField()); * * builder.append("s [mm]", new JTextField()); * builder.nextLine(); * * builder.appendSeparator("Diameters"); * * builder.append("da [mm]", new JTextField()); * builder.append("di [mm]", new JTextField()); * * builder.append("da2 [mm]", new JTextField()); * builder.append("di2 [mm]", new JTextField()); * * builder.append("R [mm]", new JTextField()); * builder.append("D [mm]", new JTextField()); * * builder.appendSeparator("Criteria"); * * builder.append("Location", buildLocationComboBox()); * builder.append("k-factor", new JTextField()); * * builder.appendSeparator("Bolts"); * * builder.append("Material", ViewerUIFactory.buildMaterialComboBox()); * builder.nextLine(); * * builder.append("Numbers", new JTextField()); * builder.nextLine(); * * builder.append("ds [mm]", new JTextField()); * } * </pre> * * @author Karsten Lentzsch * @see com.jgoodies.forms.builder.AbstractFormBuilder * @see com.jgoodies.forms.factories.FormFactory * @see com.jgoodies.forms.layout.FormLayout */ public final class DefaultFormBuilder extends I15dPanelBuilder { /** * Holds the row specification that is reused to describe * the constant gaps between component lines. */ private RowSpec lineGapSpec = FormFactory.LINE_GAP_ROWSPEC; /** * Holds the row specification that describes the constant gaps * between paragraphs. */ private RowSpec paragraphGapSpec = FormFactory.PARAGRAPH_GAP_ROWSPEC; /** * Holds the offset of the leading column - often 0 or 1. */ private int leadingColumnOffset = 0; /** * Determines wether new data rows are being grouped or not. */ private boolean rowGroupingEnabled = false; // Instance Creation **************************************************** /** * Constructs an instance of <code>DefaultFormBuilder</code> for the given * layout. * * @param layout the <code>FormLayout</code> to be used */ public DefaultFormBuilder(FormLayout layout) { this(new JPanel(), layout); } /** * Constructs an instance of <code>DefaultFormBuilder</code> for the given * panel and layout. * * @param panel the layout container * @param layout the <code>FormLayout</code> to be used */ public DefaultFormBuilder(JPanel panel, FormLayout layout) { this(panel, layout, null); } /** * Constructs an instance of <code>DefaultFormBuilder</code> for the given * layout and resource bundle. * * @param layout the <code>FormLayout</code> to be used * @param bundle the <code>ResourceBundle</code> used to lookup i15d * strings */ public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) { this(new JPanel(), layout, bundle); } /** * Constructs an instance of <code>DefaultFormBuilder</code> for the given * panel, layout and resource bundle. * * @param panel the layout container * @param layout the <code>FormLayout</code> to be used * @param bundle the <code>ResourceBundle</code> used to lookup i15d * strings */ public DefaultFormBuilder(JPanel panel, FormLayout layout, ResourceBundle bundle) { super(panel, layout, bundle); } // Settings Gap Sizes *************************************************** /** * Sets the size of gaps between component lines using the given * constant size. * * @param lineGapSize the <coide>ConstantSize</code> that describes * the size of the gaps between component lines */ public void setLineGapSize(ConstantSize lineGapSize) { RowSpec rowSpec = FormFactory.createGapRowSpec(lineGapSize); // No longer supported in version 1.0.4/1.0.5 which are the oldest available versions in maven // central repo // //this.lineGapSpec = rowSpec.asUnmodifyable(); this.lineGapSpec = rowSpec ; } /** * Returns the row specification that is used to separate component lines. * * @return the <code>RowSpec</code> that is used to separate lines */ public RowSpec getLineGapSpec() { return lineGapSpec; } /** * Sets the size of gaps between paragraphs using the given * constant size. * * @param paragraphGapSize the <coide>ConstantSize</code> that describes * the size of the gaps between paragraphs */ public void setParagraphGapSize(ConstantSize paragraphGapSize) { RowSpec rowSpec = FormFactory.createGapRowSpec(paragraphGapSize); // No longer supported in version 1.0.4/1.0.5 which are the oldest available versions in maven // central repo // //this.paragraphGapSpec = rowSpec.asUnmodifyable(); this.paragraphGapSpec = rowSpec; } /** * Returns the offset of the leading column, often 0 or 1. * * @return the offset of the leading column */ public int getLeadingColumnOffset() { return leadingColumnOffset; } /** * Sets the offset of the leading column, often 0 or 1. * * @param columnOffset the new offset of the leading column */ public void setLeadingColumnOffset(int columnOffset) { this.leadingColumnOffset = columnOffset; } /** * Returns whether new data rows are being grouped or not. * * @return true indicates grouping enabled, false disabled */ public boolean isRowGroupingEnabled() { return rowGroupingEnabled; } /** * Enables or disables the grouping of new data rows. * * @param enabled indicates grouping enabled, false disabled */ public void setRowGroupingEnabled(boolean enabled) { rowGroupingEnabled = enabled; } // Filling Columns ****************************************************** /** * Adds a component to the panel using the default constraints. * Proceeds to the next data column. * * @param component the component to add */ public void append(Component component) { append(component, 1); } /** * Adds a component to the panel using the default constraints with * the given columnSpan. Proceeds to the next data column. * * @param component the component to append * @param columnSpan the column span used to add */ public void append(Component component, int columnSpan) { ensureCursorColumnInGrid(); ensureHasGapRow(lineGapSpec); ensureHasComponentLine(); setColumnSpan(columnSpan); add(component); setColumnSpan(1); nextColumn(columnSpan + 1); } /** * Adds two components to the panel; each component will span a single * data column. Proceeds to the next data column. * * @param c1 the first component to add * @param c2 the second component to add */ public void append(Component c1, Component c2) { append(c1); append(c2); } /** * Adds three components to the panel; each component will span a single * data column. Proceeds to the next data column. * * @param c1 the first component to add * @param c2 the second component to add * @param c3 the third component to add */ public void append(Component c1, Component c2, Component c3) { append(c1); append(c2); append(c3); } // Appending Labels with optional components ------------------------------ /** * Adds a text label to the panel and proceeds to the next column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @return the added label */ public JLabel append(String textWithMnemonic) { JLabel label = getComponentFactory().createLabel(textWithMnemonic); append(label); return label; } /** * Adds a text label and component to the panel. * Then proceeds to the next data column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @param component the component to add * @return the added label */ public JLabel append(String textWithMnemonic, Component component) { return append(textWithMnemonic, component, 1); } /** * Adds a text label and component to the panel; the component will span * the specified number columns. Proceeds to the next data column. * <p> * The created label is labelling the given component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @param textWithMnemonic the label's text - may mark a mnemonic * @param c the component to add * @param columnSpan number of columns the component shall span * @return the added label * @see JLabel#setLabelFor */ public JLabel append(String textWithMnemonic, Component c, int columnSpan) { JLabel label = append(textWithMnemonic); label.setLabelFor(c); append(c, columnSpan); return label; } /** * Adds a text label and two components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @param c1 the first component to add * @param c2 the second component to add * @return the added label */ public JLabel append(String textWithMnemonic, Component c1, Component c2) { JLabel label = append(textWithMnemonic, c1); append(c2); return label; } /** * Adds a text label and two components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @param c1 the first component to add * @param c2 the second component to add * @param colSpan the column span for the second component */ public void append(String textWithMnemonic, Component c1, Component c2, int colSpan) { append(textWithMnemonic, c1); append(c2, colSpan); } /** * Adds a text label and three components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @param c1 the first component to add * @param c2 the second component to add * @param c3 the third component to add * @return the added label */ public JLabel append(String textWithMnemonic, Component c1, Component c2, Component c3) { JLabel label = append(textWithMnemonic, c1, c2); append(c3); return label; } /** * Adds a text label and four components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @param c1 the first component to add * @param c2 the second component to add * @param c3 the third component to add * @param c4 the fourth component to add * @return the added label */ public JLabel append(String textWithMnemonic, Component c1, Component c2, Component c3, Component c4) { JLabel label = append(textWithMnemonic, c1, c2, c3); append(c4); return label; } // Appending internationalized labels with optional components ------------ /** * Adds an internationalized (i15d) text label to the panel using * the given resource key and proceeds to the next column. * * @param resourceKey the resource key for the the label's text * @return the added label */ public JLabel appendI15d(String resourceKey) { return append(getI15dString(resourceKey)); } /** * Adds an internationalized (i15d) text label to the panel using the given resource key; * then proceeds to the next data column and adds a component with * the given column span. Proceeds to the next data column. * * @param resourceKey the resource key for the text to add * @param c the component to add * @param columnSpan number of columns the component shall span * @return the added label */ public JLabel appendI15d(String resourceKey, Component c, int columnSpan) { JLabel label = appendI15d(resourceKey); append(c, columnSpan); return label; } /** * Adds an internationalized (i15d) text label and component to the panel. * Then proceeds to the next data column. * * @param resourceKey the resource key for the text to add * @param component the component to add * @return the added label */ public JLabel appendI15d(String resourceKey, Component component) { return appendI15d(resourceKey, component, 1); } /** * Adds an internationalized (i15d) text label and component to the panel. * Then proceeds to the next data column. * Goes to the next line if the boolean flag is set. * * @param resourceKey the resource key for the text to add * @param component the component to add * @param nextLine true forces a next line * @return the added label */ public JLabel appendI15d(String resourceKey, Component component, boolean nextLine) { JLabel label = appendI15d(resourceKey, component, 1); if (nextLine) { nextLine(); } return label; } /** * Adds an internationalized (i15d) text label and two components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param resourceKey the resource key for the text to add * @param c1 the first component to add * @param c2 the second component to add * @return the added label */ public JLabel appendI15d(String resourceKey, Component c1, Component c2) { JLabel label = appendI15d(resourceKey, c1); append(c2); return label; } /** * Adds an internationalized (i15d) text label and two components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param resourceKey the resource key for the text to add * @param c1 the first component to add * @param c2 the second component to add * @param colSpan the column span for the second component * @return the added label */ public JLabel appendI15d(String resourceKey, Component c1, Component c2, int colSpan) { JLabel label = appendI15d(resourceKey, c1); append(c2, colSpan); return label; } /** * Adds an internationalized (i15d) text label and three components to the panel; each component * will span a single column. Proceeds to the next data column. * * @param resourceKey the resource key for the text to add * @param c1 the first component to add * @param c2 the second component to add * @param c3 the third component to add * @return the added label */ public JLabel appendI15d(String resourceKey, Component c1, Component c2, Component c3) { JLabel label = appendI15d(resourceKey, c1, c2); append(c3); return label; } /** * Adds an internationalized (i15d) text label and four components to the panel; * each component will span a single column. Proceeds to the next data column. * * @param resourceKey the resource key for the text to add * @param c1 the first component to add * @param c2 the second component to add * @param c3 the third component to add * @param c4 the third component to add * @return the added label */ public JLabel appendI15d(String resourceKey, Component c1, Component c2, Component c3, Component c4) { JLabel label = appendI15d(resourceKey, c1, c2, c3); append(c4); return label; } // Adding Titles ---------------------------------------------------------- /** * Adds a title label to the panel and proceeds to the next column. * * @param textWithMnemonic the label's text - may mark a mnemonic * @return the added title label */ public JLabel appendTitle(String textWithMnemonic) { JLabel titleLabel = getComponentFactory().createTitle(textWithMnemonic); append(titleLabel); return titleLabel; } /** * Adds an internationalized title label to the panel and * proceeds to the next column. * * @param resourceKey the resource key for the title's text * @return the added title label */ public JLabel appendI15dTitle(String resourceKey) { return appendTitle(getI15dString(resourceKey)); } // Appending Separators --------------------------------------------------- /** * Adds a separator without text that spans all columns. * * @return the added titled separator */ public JComponent appendSeparator() { return appendSeparator(""); } /** * Adds a separator with the given text that spans all columns. * * @param text the separator title text * @return the added titled separator */ public JComponent appendSeparator(String text) { ensureCursorColumnInGrid(); ensureHasGapRow(paragraphGapSpec); ensureHasComponentLine(); setColumn(super.getLeadingColumn()); int columnSpan = getColumnCount(); setColumnSpan(getColumnCount()); JComponent titledSeparator = addSeparator(text); setColumnSpan(1); nextColumn(columnSpan); return titledSeparator; } /** * Appends an internationalized titled separator for * the given resource key that spans all columns. * * @param resourceKey the resource key for the separator title's text */ public void appendI15dSeparator(String resourceKey) { appendSeparator(getI15dString(resourceKey)); } // Overriding Superclass Behavior *************************************** /** * Returns the leading column. Unlike the superclass we take a * column offset into account. * * @return the leading column */ protected int getLeadingColumn() { int column = super.getLeadingColumn(); return column + getLeadingColumnOffset() * getColumnIncrementSign(); } // Adding Rows ********************************************************** /** * Ensures that the cursor is in the grid. In case it's beyond the * form's right hand side, the cursor is moved to the leading column * of the next line. */ private void ensureCursorColumnInGrid() { if (getColumn() > getColumnCount()) { nextLine(); } } /** * Ensures that we have a gap row before the next component row. * Checks if the current row is the given <code>RowSpec</code> * and appends this row spec if necessary. * * @param gapRowSpec the row specification to check for */ private void ensureHasGapRow(RowSpec gapRowSpec) { if ((getRow() == 1) || (getRow() <= getRowCount())) return; if (getRow() <= getRowCount()) { RowSpec rowSpec = getCursorRowSpec(); if ((rowSpec == gapRowSpec)) return; } appendRow(gapRowSpec); nextLine(); } /** * Ensures that the form has a component row. Adds a component row * if the cursor is beyond the form's bottom. */ private void ensureHasComponentLine() { if (getRow() <= getRowCount()) return; appendRow(FormFactory.PREF_ROWSPEC); if (isRowGroupingEnabled()) { getLayout().addGroupedRow(getRow()); } } /** * Looks up and answers the row specification of the current row. * * @return the row specification of the current row */ private RowSpec getCursorRowSpec() { return getLayout().getRowSpec(getRow()); } }