Java tutorial
/* * Copyright (c) 2002-2014 JGoodies Software GmbH. 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 Software GmbH 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 java.awt.Color; import java.awt.Component; import java.util.ResourceBundle; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.Border; import com.jgoodies.common.internal.StringResourceAccessor; import com.jgoodies.common.swing.MnemonicUtils; import com.jgoodies.forms.layout.ConstantSize; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.FormSpecs; import com.jgoodies.forms.layout.RowSpec; /** * Provides a means to build form-oriented panels quickly and consistently * 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> * * The extra value lies in the {@code #append} methods that * append gap rows and component rows if necessary and then add * the given components. They are built upon the superclass behavior * {@code #appendRow} and the set of {@code #add} methods. * A set of component appenders allows to add a textual label and * associated component in a single step.<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} in the constructor. * The builder methods throw an {@code IllegalStateException} if one * of the mapping builder methods is invoked and no bundle has been set.<p> * * You can configure the build process by setting a leading column, * enabling the row grouping and by modifying the gaps between normal * lines and between paragraphs. The leading column will be honored * if the cursor proceeds to the next row. All appended components * start in the specified lead column, except appended separators that * span all columns.<p> * * It is temptive to use the DefaultFormBuilder all the time and * to let it add rows automatically. Use a simpler style if it increases * the code readability. Explicit row specifications and cell constraints * make your layout easier to understand - but harder to maintain. * See also the accompanying tutorial sources and the Tips & Tricks * that are part of the Forms documentation.<p> * * Sometimes a form consists of many standardized rows but has a few * rows that require a customization. The DefaultFormBuilder can do everything * that the superclasses {@link com.jgoodies.forms.builder.AbstractFormBuilder} * and {@link com.jgoodies.forms.builder.PanelBuilder} can do; * among other things: appending new rows and moving the cursor. * Again, ask yourself if the DefaultFormBuilder is the appropriate builder. * As a rule of thumb you should have more components than builder commands. * There are different ways to add custom rows. Find below example code * that presents and compares the pros and cons of three approaches.<p> * * The texts for labels and titles can be <em>marked texts</em>, * i.e. strings with an optional mnemonic marker. * See the {@link MnemonicUtils} class comment for details.<p> * * <strong>Example:</strong> * <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) * .border(Borders.DIALOG); * * 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><p> * * <strong>Custom Row Example:</strong> * <pre> * public JComponent buildPanel() { * initComponents(); * * FormLayout layout = new FormLayout( * "right:pref, 3dlu, default:grow", * ""); * DefaultFormBuilder builder = new DefaultFormBuilder(layout) * .border(Borders.DIALOG) * .rowGroupingEnabled(true); * * // In this approach, we add a gap and a custom row. * // The advantage of this approach is, that we can express * // the row spec and comment area cell constraints freely. * // The disadvantage is the misalignment of the leading label. * // Also the row's height may be inconsistent with other rows. * builder.appendSeparator("Single Custom Row"); * builder.append("Name", name1Field); * builder.appendLineGapRow(); * builder.appendRow(RowSpec.decode("top:31dlu")); // Assumes line is 14, gap is 3 * builder.nextLine(2); * builder.append("Comment"); * builder.add(new JScrollPane(comment1Area), * CC.xy(builder.getColumn(), builder.getRow(), "fill, fill")); * builder.nextLine(); * * // In this approach, we append a standard row with gap before it. * // The advantage is, that the leading label is aligned well. * // The disadvantage is that the comment area now spans * // multiple cells and is slightly less flexible. * // Also the row's height may be inconsistent with other rows. * builder.appendSeparator("Standard + Custom Row"); * builder.append("Name", name2Field); * builder.append("Comment"); * builder.appendRow(RowSpec.decode("17dlu")); // Assumes line is 14, gap is 3 * builder.add(new JScrollPane(comment2Area), * CC.xywh(builder.getColumn(), builder.getRow(), 1, 2)); * builder.nextLine(2); * * // In this approach, we append two standard rows with associated gaps. * // The advantage is, that the leading label is aligned well, * // and the height is consistent with other rows. * // The disadvantage is that the comment area now spans * // multiple cells and is slightly less flexible. * builder.appendSeparator("Two Standard Rows"); * builder.append("Name", name3Field); * builder.append("Comment"); * builder.nextLine(); * builder.append(""); * builder.nextRow(-2); * builder.add(new JScrollPane(comment3Area), * CC.xywh(builder.getColumn(), builder.getRow(), 1, 3)); * * return builder.build(); * } * </pre><p> * * TODO: Consider adding a method for appending a component that spans the * remaining columns in the current row. Method name candidates are * {@code #appendFullSpan} and {@code #appendRemaining}. * * @author Karsten Lentzsch * @version $Revision: 1.16 $ * @since 1.0.3 * * @see com.jgoodies.forms.builder.AbstractFormBuilder * @see com.jgoodies.forms.layout.FormSpecs * @see com.jgoodies.forms.layout.FormLayout */ public final class DefaultFormBuilder extends I15dPanelBuilder { /** * Holds the row specification that is reused to describe rows * that are intended for labels and components. * * @see #setDefaultRowSpec(RowSpec) */ private RowSpec defaultRowSpec = FormSpecs.PREF_ROWSPEC; /** * Holds the row specification that is reused to describe * the constant gaps between component lines. * * @see #setLineGapSize(ConstantSize) */ private RowSpec lineGapSpec = FormSpecs.LINE_GAP_ROWSPEC; /** * Holds the row specification that describes the constant gaps * between paragraphs. * * @see #setParagraphGapSize(ConstantSize) */ private RowSpec paragraphGapSpec = FormSpecs.PARAGRAPH_GAP_ROWSPEC; /** * Holds the offset of the leading column - often 0 or 1. * * @see #getLeadingColumnOffset() * @see #setLeadingColumnOffset(int) * @see #getLeadingColumn() */ private int leadingColumnOffset = 0; /** * Determines whether new data rows are being grouped or not. * * @see #isRowGroupingEnabled() * @see #setRowGroupingEnabled(boolean) */ private boolean rowGroupingEnabled = false; // Instance Creation **************************************************** /** * Constructs a {@code DefaultFormBuilder} for the given * layout. * * @param layout the {@code FormLayout} to be used * * @throws NullPointerException if {@code layout} is {@code null} */ public DefaultFormBuilder(FormLayout layout) { this(layout, new JPanel(null)); } /** * Constructs a {@code DefaultFormBuilder} for the given * layout and panel. * * @param layout the {@code FormLayout} to be used * @param container the layout container * * @throws NullPointerException if {@code layout} or {@code container} is {@code null} */ public DefaultFormBuilder(FormLayout layout, JPanel container) { this(layout, (StringResourceAccessor) null, container); } /** * Constructs a {@code DefaultFormBuilder} for the given * layout and resource bundle. * * @param layout the {@code FormLayout} to be used * @param bundle the {@code ResourceBundle} used to lookup i15d * strings * * @throws NullPointerException if {@code layout} is {@code null} */ public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) { super(layout, bundle); } /** * Constructs a {@code DefaultFormBuilder} for the given * layout, resource bundle, and panel. * * @param layout the {@code FormLayout} to be used * @param container the layout container * @param bundle the {@code ResourceBundle} used to lookup i15d * strings * * @throws NullPointerException if {@code layout} or {@code container} is {@code null} */ public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle, JPanel container) { super(layout, bundle, container); } /** * Constructs a {@code DefaultFormBuilder} for the given * layout and resource bundle. * * @param layout the {@code FormLayout} to be used * @param localizer used to lookup i15d strings * * @throws NullPointerException if {@code layout} is {@code null} */ public DefaultFormBuilder(FormLayout layout, StringResourceAccessor localizer) { super(layout, localizer); } /** * Constructs a {@code DefaultFormBuilder} for the given * layout, resource bundle, and panel. * * @param layout the {@code FormLayout} to be used * @param container the layout container * @param localizer used to lookup i15d strings * * @throws NullPointerException if {@code layout} or {@code container} is {@code null} */ public DefaultFormBuilder(FormLayout layout, StringResourceAccessor localizer, JPanel container) { super(layout, localizer, container); } // Frequently Used Panel Properties *************************************** @Override public DefaultFormBuilder background(Color background) { super.background(background); return this; } @Override public DefaultFormBuilder border(Border border) { super.border(border); return this; } @Override public DefaultFormBuilder border(String emptyBorderSpec) { super.border(emptyBorderSpec); return this; } @Override public DefaultFormBuilder opaque(boolean b) { super.opaque(b); return this; } // Modern (Cascading) Style Configuration ********************************* /** * Sets the row specification that shall be used for component rows. * It is {@link FormSpecs#PREF_ROWSPEC} by default. * * @param defaultRowSpec the RowSpec to be used for component rows */ public DefaultFormBuilder defaultRowSpec(RowSpec defaultRowSpec) { this.defaultRowSpec = defaultRowSpec; return this; } /** * Sets the size of gaps between component lines using the given * constant size.<p> * * <strong>Examples:</strong><pre> * .lineGapSize(Sizes.ZERO); * .lineGapSize(Sizes.DLUY9); * .lineGapSize(Sizes.pixel(1)); * </pre> * * @param lineGapSize the {@code ConstantSize} that describes * the size of the gaps between component lines */ public DefaultFormBuilder lineGapSize(ConstantSize lineGapSize) { RowSpec rowSpec = RowSpec.createGap(lineGapSize); this.lineGapSpec = rowSpec; return this; } /** * Sets the size of gaps between paragraphs using the given * constant size.<p> * * <strong>Examples:</strong><pre> * .setParagraphGapSize(Sizes.DLUY14); * .setParagraphGapSize(Sizes.dluY(22)); * .setParagraphGapSize(Sizes.pixel(42)); * </pre> * * @param paragraphGapSize the {@code ConstantSize} that describes * the size of the gaps between paragraphs */ public DefaultFormBuilder paragraphGapSize(ConstantSize paragraphGapSize) { RowSpec rowSpec = RowSpec.createGap(paragraphGapSize); this.paragraphGapSpec = rowSpec; return this; } /** * Sets the offset of the leading column, often 0 or 1. * * @param columnOffset the new offset of the leading column */ public DefaultFormBuilder leadingColumnOffset(int columnOffset) { this.leadingColumnOffset = columnOffset; return this; } /** * Enables or disables the grouping of new data rows. * * @param enabled indicates grouping enabled, false disabled */ public DefaultFormBuilder rowGroupingEnabled(boolean enabled) { rowGroupingEnabled = enabled; return this; } // Old Style Configuration ************************************************ /** * Returns the row specification that is used for component rows. * * @return the {@code RowSpec} used for component rows * * @since 1.2 * @deprecated Obsolete; will be deleted from the next version */ @Deprecated public RowSpec getDefaultRowSpec() { return defaultRowSpec; } /** * Sets the row specification that shall be used for component rows. * It is {@link FormSpecs#PREF_ROWSPEC} by default. * * @param defaultRowSpec the RowSpec to be used for component rows * * @since 1.2 * @deprecated Replaced by {@link #defaultRowSpec(RowSpec)} */ @Deprecated public void setDefaultRowSpec(RowSpec defaultRowSpec) { this.defaultRowSpec = defaultRowSpec; } /** * Returns the row specification that is used to separate component row. * * @return the {@code RowSpec} that is used to separate component rows * @deprecated Obsolete; will be deleted from the next version */ @Deprecated public RowSpec getLineGapSpec() { return lineGapSpec; } /** * Sets the size of gaps between component lines using the given * constant size.<p> * * <strong>Examples:</strong><pre> * .setLineGapSize(Sizes.ZERO); * .setLineGapSize(Sizes.DLUY9); * .setLineGapSize(Sizes.pixel(1)); * </pre> * * @param lineGapSize the {@code ConstantSize} that describes * the size of the gaps between component lines * @deprecated Replaced by {@link #lineGapSize(ConstantSize)} */ @Deprecated public void setLineGapSize(ConstantSize lineGapSize) { RowSpec rowSpec = RowSpec.createGap(lineGapSize); this.lineGapSpec = rowSpec; } /** * Sets the size of gaps between paragraphs using the given * constant size.<p> * * <strong>Examples:</strong><pre> * .setParagraphGapSize(Sizes.DLUY14); * .setParagraphGapSize(Sizes.dluY(22)); * .setParagraphGapSize(Sizes.pixel(42)); * </pre> * * @param paragraphGapSize the {@code ConstantSize} that describes * the size of the gaps between paragraphs * @deprecated Replaced by {@link #lineGapSize(ConstantSize)} */ @Deprecated public void setParagraphGapSize(ConstantSize paragraphGapSize) { RowSpec rowSpec = RowSpec.createGap(paragraphGapSize); this.paragraphGapSpec = rowSpec; } /** * Returns the offset of the leading column, often 0 or 1. * * @return the offset of the leading column * @deprecated Obsolete; will be deleted from the next version */ @Deprecated 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 * @deprecated Replaced by {@link #leadingColumnOffset(int)} */ @Deprecated 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 * @deprecated Obsolete; will be deleted from the next version */ @Deprecated public boolean isRowGroupingEnabled() { return rowGroupingEnabled; } /** * Enables or disables the grouping of new data rows. * * @param enabled indicates grouping enabled, false disabled * @deprecated Replaced by {@link #rowGroupingEnabled(boolean)} */ @Deprecated public void setRowGroupingEnabled(boolean enabled) { rowGroupingEnabled = enabled; } // Appending Rows ******************************************************** /** * Appends a row with this builder's line gap size. * * @see #lineGapSize(ConstantSize) * @see #appendRow(String) */ public final void appendLineGapRow() { appendRow(lineGapSpec); } // Filling Columns ****************************************************** /** * Adds a component to the panel using the default constraints * with a column span of 1. Then 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(); add(component, createLeftAdjustedConstraints(columnSpan)); 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.<p> * * The created label is labeling 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 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, * and goes to the next line if the boolean flag is set.<p> * * The created label is labeling 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 nextLine true forces a next line * @return the added label * @see JLabel#setLabelFor(java.awt.Component) */ public JLabel append(String textWithMnemonic, Component c, boolean nextLine) { JLabel label = append(textWithMnemonic, c); if (nextLine) { nextLine(); } return label; } /** * 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 labeling 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(java.awt.Component) */ 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.<p> * * The created label is labeling the first 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 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.<p> * * The created label is labeling the first 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 c1 the first component to add * @param c2 the second component to add * @param colSpan the column span for the second component * @return the created label */ public JLabel append(String textWithMnemonic, Component c1, Component c2, int colSpan) { JLabel label = append(textWithMnemonic, c1); append(c2, colSpan); return label; } /** * Adds a text label and three components to the panel; each component * will span a single column. Proceeds to the next data column.<p> * * The created label is labeling the first 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 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.<p> * * The created label is labeling the first 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 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(getResourceString(resourceKey)); } /** * Adds an internationalized (i15d) text label and component * to the panel. Then proceeds to the next data column.<p> * * The created label is labeling the given component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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 append(getResourceString(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.<p> * * The created label is labeling the first component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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) { return append(getResourceString(resourceKey), component, nextLine); } /** * 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.<p> * * The created label is labeling the first component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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) { return append(getResourceString(resourceKey), c, columnSpan); } /** * 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.<p> * * The created label is labeling the first component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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) { return append(getResourceString(resourceKey), c1, c2); } /** * 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.<p> * * The created label is labeling the first component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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) { return append(getResourceString(resourceKey), c1, c2, colSpan); } /** * 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.<p> * * The created label is labeling the first component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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) { return append(getResourceString(resourceKey), c1, c2, c3); } /** * 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.<p> * * The created label is labeling the first component; so the component * gets the focus if the (optional) label mnemonic is pressed. * * @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) { return append(getResourceString(resourceKey), c1, c2, c3, c4); } // 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(getResourceString(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 * @return the added titled separator */ public JComponent appendI15dSeparator(String resourceKey) { return appendSeparator(getResourceString(resourceKey)); } // Overriding Superclass Behavior *************************************** /** * Returns the leading column. Unlike the superclass this method * honors the column offset. * * @return the leading column */ @Override protected int getLeadingColumn() { int column = super.getLeadingColumn(); return column + leadingColumnOffset * 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 (isLeftToRight() && getColumn() > getColumnCount() || !isLeftToRight() && getColumn() < 1) { nextLine(); } } /** * Ensures that we have a gap row before the next component row. * Checks if the current row is the given {@code RowSpec} * 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(defaultRowSpec); if (rowGroupingEnabled) { getLayout().addGroupedRow(getRow()); } } /** * Looks up and returns the row specification of the current row. * * @return the row specification of the current row */ private RowSpec getCursorRowSpec() { return getLayout().getRowSpec(getRow()); } }