2
* Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of JGoodies Karsten Lentzsch nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
package com.jgoodies.forms.builder;
33
import java.awt.Component;
34
import java.util.ResourceBundle;
36
import javax.swing.JComponent;
37
import javax.swing.JLabel;
38
import javax.swing.JPanel;
40
import com.jgoodies.forms.factories.FormFactory;
41
import com.jgoodies.forms.layout.ConstantSize;
42
import com.jgoodies.forms.layout.FormLayout;
43
import com.jgoodies.forms.layout.RowSpec;
46
* Provides a means to build form-oriented panels quickly and consistently
47
* using the {@link FormLayout}. This builder combines frequently used
48
* panel building steps: add a new row, add a label, proceed to the next
49
* data column, then add a component.<p>
51
* The extra value lies in the <code>#append</code> methods that
52
* append gap rows and component rows if necessary and then add
53
* the given components. They are built upon the superclass behavior
54
* <code>#appendRow</code> and the set of <code>#add</code> methods.
55
* A set of component appenders allows to add a textual label and
56
* associated component in a single step.<p>
58
* This builder can map resource keys to internationalized (i15d) texts
59
* when creating text labels, titles and titled separators. Therefore
60
* you must specify a <code>ResourceBundle</code> in the constructor.
61
* The builder methods throw an <code>IllegalStateException</code> if one
62
* of the mapping builder methods is invoked and no bundle has been set.<p>
64
* You can configure the build process by setting a leading column,
65
* enabling the row grouping and by modifying the gaps between normal
66
* lines and between paragraphs. The leading column will be honored
67
* if the cursor proceeds to the next row. All appended components
68
* start in the specified lead column, except appended separators that
69
* span all columns.<p>
71
* It is temptive to use the DefaultFormBuilder all the time and
72
* to let it add rows automatically. Use a simpler style if it increases
73
* the code readability. Explicit row specifications and cell constraints
74
* make your layout easier to understand - but harder to maintain.
75
* See also the accompanying tutorial sources and the Tips & Tricks
76
* that are part of the Forms documentation.<p>
78
* Sometimes a form consists of many standardized rows but has a few
79
* rows that require a customization. The DefaultFormBuilder can do everything
80
* that the superclasses {@link com.jgoodies.forms.builder.AbstractFormBuilder}
81
* and {@link com.jgoodies.forms.builder.PanelBuilder} can do;
82
* among other things: appending new rows and moving the cursor.
83
* Again, ask yourself if the DefaultFormBuilder is the appropriate builder.
84
* As a rule of thumb you should have more components than builder commands.
85
* There are different ways to add custom rows. Find below example code
86
* that presents and compares the pros and cons of three approaches.<p>
88
* The texts used in methods <code>#append(String, ...)</code> and
89
* <code>#appendTitle(String)</code> as well as the localized texts used in
90
* methods <code>#appendI15d</code> and <code>#appendI15dTitle</code>
91
* can contain an optional mnemonic marker. The mnemonic and mnemonic index
92
* are indicated by a single ampersand (<tt>&</tt>).
93
* For example <tt>"&Save"</tt>, or
94
* <tt>"Save &as"</tt>. To use the ampersand itself,
95
* duplicate it, for example <tt>"Look&&Feel"</tt>.<p>
97
* <strong>Example:</strong>
99
* public void build() {
100
* FormLayout layout = new FormLayout(
101
* "right:max(40dlu;pref), 3dlu, 80dlu, 7dlu, " // 1st major colum
102
* + "right:max(40dlu;pref), 3dlu, 80dlu", // 2nd major column
103
* ""); // add rows dynamically
104
* DefaultFormBuilder builder = new DefaultFormBuilder(layout);
105
* builder.setDefaultDialogBorder();
107
* builder.appendSeparator("Flange");
109
* builder.append("Identifier", identifierField);
110
* builder.nextLine();
112
* builder.append("PTI [kW]", new JTextField());
113
* builder.append("Power [kW]", new JTextField());
115
* builder.append("s [mm]", new JTextField());
116
* builder.nextLine();
118
* builder.appendSeparator("Diameters");
120
* builder.append("da [mm]", new JTextField());
121
* builder.append("di [mm]", new JTextField());
123
* builder.append("da2 [mm]", new JTextField());
124
* builder.append("di2 [mm]", new JTextField());
126
* builder.append("R [mm]", new JTextField());
127
* builder.append("D [mm]", new JTextField());
129
* builder.appendSeparator("Criteria");
131
* builder.append("Location", buildLocationComboBox());
132
* builder.append("k-factor", new JTextField());
134
* builder.appendSeparator("Bolts");
136
* builder.append("Material", ViewerUIFactory.buildMaterialComboBox());
137
* builder.nextLine();
139
* builder.append("Numbers", new JTextField());
140
* builder.nextLine();
142
* builder.append("ds [mm]", new JTextField());
146
* <strong>Custom Row Example:</strong>
148
* public JComponent buildPanel() {
151
* FormLayout layout = new FormLayout(
152
* "right:pref, 3dlu, default:grow",
154
* DefaultFormBuilder builder = new DefaultFormBuilder(layout);
155
* builder.setDefaultDialogBorder();
156
* builder.setRowGroupingEnabled(true);
158
* CellConstraints cc = new CellConstraints();
160
* // In this approach, we add a gap and a custom row.
161
* // The advantage of this approach is, that we can express
162
* // the row spec and comment area cell constraints freely.
163
* // The disadvantage is the misalignment of the leading label.
164
* // Also the row's height may be inconsistent with other rows.
165
* builder.appendSeparator("Single Custom Row");
166
* builder.append("Name", name1Field);
167
* builder.appendRow(builder.getLineGapSpec());
168
* builder.appendRow(new RowSpec("top:31dlu")); // Assumes line is 14, gap is 3
169
* builder.nextLine(2);
170
* builder.append("Comment");
171
* builder.add(new JScrollPane(comment1Area),
172
* cc.xy(builder.getColumn(), builder.getRow(), "fill, fill"));
173
* builder.nextLine();
175
* // In this approach, we append a standard row with gap before it.
176
* // The advantage is, that the leading label is aligned well.
177
* // The disadvantage is that the comment area now spans
178
* // multiple cells and is slightly less flexible.
179
* // Also the row's height may be inconsistent with other rows.
180
* builder.appendSeparator("Standard + Custom Row");
181
* builder.append("Name", name2Field);
182
* builder.append("Comment");
183
* builder.appendRow(new RowSpec("17dlu")); // Assumes line is 14, gap is 3
184
* builder.add(new JScrollPane(comment2Area),
185
* cc.xywh(builder.getColumn(), builder.getRow(), 1, 2));
186
* builder.nextLine(2);
188
* // In this approach, we append two standard rows with associated gaps.
189
* // The advantage is, that the leading label is aligned well,
190
* // and the height is consistent with other rows.
191
* // The disadvantage is that the comment area now spans
192
* // multiple cells and is slightly less flexible.
193
* builder.appendSeparator("Two Standard Rows");
194
* builder.append("Name", name3Field);
195
* builder.append("Comment");
196
* builder.nextLine();
197
* builder.append("");
198
* builder.nextRow(-2);
199
* builder.add(new JScrollPane(comment3Area),
200
* cc.xywh(builder.getColumn(), builder.getRow(), 1, 3));
202
* return builder.getPanel();
206
* TODO: Consider adding a method for appending a component that spans the
207
* remaining columns in the current row. Method name candidates are
208
* <code>#appendFullSpan</code> and <code>#appendRemaining</code>.
210
* @author Karsten Lentzsch
211
* @version $Revision: 1.9 $
214
* @see com.jgoodies.forms.builder.AbstractFormBuilder
215
* @see com.jgoodies.forms.factories.FormFactory
216
* @see com.jgoodies.forms.layout.FormLayout
218
public final class DefaultFormBuilder extends I15dPanelBuilder {
221
* Holds the row specification that is reused to describe
222
* the constant gaps between component lines.
224
private RowSpec lineGapSpec = FormFactory.LINE_GAP_ROWSPEC;
227
* Holds the row specification that describes the constant gaps
228
* between paragraphs.
230
private RowSpec paragraphGapSpec = FormFactory.PARAGRAPH_GAP_ROWSPEC;
233
* Holds the offset of the leading column - often 0 or 1.
235
* @see #getLeadingColumnOffset()
236
* @see #setLeadingColumnOffset(int)
237
* @see #getLeadingColumn()
239
private int leadingColumnOffset = 0;
242
* Determines whether new data rows are being grouped or not.
244
* @see #isRowGroupingEnabled()
245
* @see #setRowGroupingEnabled(boolean)
247
private boolean rowGroupingEnabled = false;
250
// Instance Creation ****************************************************
253
* Constructs an instance of <code>DefaultFormBuilder</code> for the given
256
* @param layout the <code>FormLayout</code> to be used
258
public DefaultFormBuilder(FormLayout layout) {
259
this(new JPanel(null), layout);
263
* Constructs an instance of <code>DefaultFormBuilder</code> for the given
266
* @param layout the <code>FormLayout</code> to be used
267
* @param panel the layout container
269
public DefaultFormBuilder(FormLayout layout, JPanel panel) {
270
this(panel, layout, null);
274
* Constructs an instance of <code>DefaultFormBuilder</code> for the given
275
* layout and resource bundle.
277
* @param layout the <code>FormLayout</code> to be used
278
* @param bundle the <code>ResourceBundle</code> used to lookup i15d
281
public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) {
282
this(new JPanel(null), layout, bundle);
286
* Constructs an instance of <code>DefaultFormBuilder</code> for the given
287
* panel, layout and resource bundle.
289
* @param layout the <code>FormLayout</code> to be used
290
* @param panel the layout container
291
* @param bundle the <code>ResourceBundle</code> used to lookup i15d
294
public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle, JPanel panel) {
295
super(layout, bundle, panel);
300
* Constructs an instance of <code>DefaultFormBuilder</code> for the given
303
* @param panel the layout container
304
* @param layout the <code>FormLayout</code> to be used
306
* @deprecated Replaced by {@link #DefaultFormBuilder(FormLayout, JPanel)}.
308
public DefaultFormBuilder(JPanel panel, FormLayout layout) {
309
this(layout, null, panel);
313
* Constructs an instance of <code>DefaultFormBuilder</code> for the given
314
* panel, layout and resource bundle.
316
* @param panel the layout container
317
* @param layout the <code>FormLayout</code> to be used
318
* @param bundle the <code>ResourceBundle</code> used to lookup i15d
321
* @deprecated Replaced by {@link #DefaultFormBuilder(FormLayout, ResourceBundle, JPanel)}.
323
public DefaultFormBuilder(JPanel panel, FormLayout layout, ResourceBundle bundle) {
324
super(layout, bundle, panel);
328
// Settings Gap Sizes ***************************************************
331
* Returns the row specification that is used to separate component lines.
333
* @return the <code>RowSpec</code> that is used to separate lines
335
public RowSpec getLineGapSpec() {
340
* Sets the size of gaps between component lines using the given
343
* <strong>Examples:</strong><pre>
344
* builder.setLineGapSize(Sizes.ZERO);
345
* builder.setLineGapSize(Sizes.DLUY9);
346
* builder.setLineGapSize(Sizes.pixel(1));
349
* @param lineGapSize the <code>ConstantSize</code> that describes
350
* the size of the gaps between component lines
352
public void setLineGapSize(ConstantSize lineGapSize) {
353
RowSpec rowSpec = FormFactory.createGapRowSpec(lineGapSize);
354
this.lineGapSpec = rowSpec;
359
* Sets the size of gaps between paragraphs using the given
362
* <strong>Examples:</strong><pre>
363
* builder.setParagraphGapSize(Sizes.DLUY14);
364
* builder.setParagraphGapSize(Sizes.dluY(22));
365
* builder.setParagraphGapSize(Sizes.pixel(42));
368
* @param paragraphGapSize the <code>ConstantSize</code> that describes
369
* the size of the gaps between paragraphs
371
public void setParagraphGapSize(ConstantSize paragraphGapSize) {
372
RowSpec rowSpec = FormFactory.createGapRowSpec(paragraphGapSize);
373
this.paragraphGapSpec = rowSpec;
378
* Returns the offset of the leading column, often 0 or 1.
380
* @return the offset of the leading column
382
public int getLeadingColumnOffset() {
383
return leadingColumnOffset;
387
* Sets the offset of the leading column, often 0 or 1.
389
* @param columnOffset the new offset of the leading column
391
public void setLeadingColumnOffset(int columnOffset) {
392
this.leadingColumnOffset = columnOffset;
397
* Returns whether new data rows are being grouped or not.
399
* @return true indicates grouping enabled, false disabled
401
public boolean isRowGroupingEnabled() {
402
return rowGroupingEnabled;
406
* Enables or disables the grouping of new data rows.
408
* @param enabled indicates grouping enabled, false disabled
410
public void setRowGroupingEnabled(boolean enabled) {
411
rowGroupingEnabled = enabled;
415
// Filling Columns ******************************************************
418
* Adds a component to the panel using the default constraints
419
* with a column span of 1. Then proceeds to the next data column.
421
* @param component the component to add
423
public void append(Component component) {
424
append(component, 1);
428
* Adds a component to the panel using the default constraints with
429
* the given columnSpan. Proceeds to the next data column.
431
* @param component the component to append
432
* @param columnSpan the column span used to add
434
public void append(Component component, int columnSpan) {
435
ensureCursorColumnInGrid();
436
ensureHasGapRow(lineGapSpec);
437
ensureHasComponentLine();
439
add(component, createLeftAdjustedConstraints(columnSpan));
440
nextColumn(columnSpan + 1);
444
* Adds two components to the panel; each component will span a single
445
* data column. Proceeds to the next data column.
447
* @param c1 the first component to add
448
* @param c2 the second component to add
450
public void append(Component c1, Component c2) {
456
* Adds three components to the panel; each component will span a single
457
* data column. Proceeds to the next data column.
459
* @param c1 the first component to add
460
* @param c2 the second component to add
461
* @param c3 the third component to add
463
public void append(Component c1, Component c2, Component c3) {
470
// Appending Labels with optional components ------------------------------
473
* Adds a text label to the panel and proceeds to the next column.
475
* @param textWithMnemonic the label's text - may mark a mnemonic
476
* @return the added label
478
public JLabel append(String textWithMnemonic) {
479
JLabel label = getComponentFactory().createLabel(textWithMnemonic);
485
* Adds a text label and component to the panel.
486
* Then proceeds to the next data column.
488
* @param textWithMnemonic the label's text - may mark a mnemonic
489
* @param component the component to add
490
* @return the added label
492
public JLabel append(String textWithMnemonic, Component component) {
493
return append(textWithMnemonic, component, 1);
497
* Adds a text label and component to the panel; the component will span
498
* the specified number columns. Proceeds to the next data column.
500
* The created label is labelling the given component; so the component
501
* gets the focus if the (optional) label mnemonic is pressed.
503
* @param textWithMnemonic the label's text - may mark a mnemonic
504
* @param c the component to add
505
* @param columnSpan number of columns the component shall span
506
* @return the added label
507
* @see JLabel#setLabelFor(java.awt.Component)
509
public JLabel append(String textWithMnemonic, Component c, int columnSpan) {
510
JLabel label = append(textWithMnemonic);
511
label.setLabelFor(c);
512
append(c, columnSpan);
517
* Adds a text label and two components to the panel; each component
518
* will span a single column. Proceeds to the next data column.
520
* @param textWithMnemonic the label's text - may mark a mnemonic
521
* @param c1 the first component to add
522
* @param c2 the second component to add
523
* @return the added label
525
public JLabel append(String textWithMnemonic, Component c1, Component c2) {
526
JLabel label = append(textWithMnemonic, c1);
532
* Adds a text label and two components to the panel; each component
533
* will span a single column. Proceeds to the next data column.
535
* @param textWithMnemonic the label's text - may mark a mnemonic
536
* @param c1 the first component to add
537
* @param c2 the second component to add
538
* @param colSpan the column span for the second component
540
public void append(String textWithMnemonic, Component c1, Component c2, int colSpan) {
541
append(textWithMnemonic, c1);
546
* Adds a text label and three components to the panel; each component
547
* will span a single column. Proceeds to the next data column.
549
* @param textWithMnemonic the label's text - may mark a mnemonic
550
* @param c1 the first component to add
551
* @param c2 the second component to add
552
* @param c3 the third component to add
553
* @return the added label
555
public JLabel append(String textWithMnemonic, Component c1, Component c2, Component c3) {
556
JLabel label = append(textWithMnemonic, c1, c2);
562
* Adds a text label and four components to the panel; each component
563
* will span a single column. Proceeds to the next data column.
565
* @param textWithMnemonic the label's text - may mark a mnemonic
566
* @param c1 the first component to add
567
* @param c2 the second component to add
568
* @param c3 the third component to add
569
* @param c4 the fourth component to add
570
* @return the added label
572
public JLabel append(String textWithMnemonic, Component c1, Component c2, Component c3, Component c4) {
573
JLabel label = append(textWithMnemonic, c1, c2, c3);
579
// Appending internationalized labels with optional components ------------
582
* Adds an internationalized (i15d) text label to the panel using
583
* the given resource key and proceeds to the next column.
585
* @param resourceKey the resource key for the the label's text
586
* @return the added label
588
public JLabel appendI15d(String resourceKey) {
589
return append(getI15dString(resourceKey));
593
* Adds an internationalized (i15d) text label to the panel using the given resource key;
594
* then proceeds to the next data column and adds a component with
595
* the given column span. Proceeds to the next data column.
597
* @param resourceKey the resource key for the text to add
598
* @param c the component to add
599
* @param columnSpan number of columns the component shall span
600
* @return the added label
602
public JLabel appendI15d(String resourceKey, Component c, int columnSpan) {
603
JLabel label = appendI15d(resourceKey);
604
append(c, columnSpan);
609
* Adds an internationalized (i15d) text label and component to the panel.
610
* Then proceeds to the next data column.
612
* @param resourceKey the resource key for the text to add
613
* @param component the component to add
614
* @return the added label
616
public JLabel appendI15d(String resourceKey, Component component) {
617
return appendI15d(resourceKey, component, 1);
621
* Adds an internationalized (i15d) text label and component to the panel.
622
* Then proceeds to the next data column.
623
* Goes to the next line if the boolean flag is set.
625
* @param resourceKey the resource key for the text to add
626
* @param component the component to add
627
* @param nextLine true forces a next line
628
* @return the added label
630
public JLabel appendI15d(String resourceKey, Component component, boolean nextLine) {
631
JLabel label = appendI15d(resourceKey, component, 1);
639
* Adds an internationalized (i15d) text label and two components to the panel; each component
640
* will span a single column. Proceeds to the next data column.
642
* @param resourceKey the resource key for the text to add
643
* @param c1 the first component to add
644
* @param c2 the second component to add
645
* @return the added label
647
public JLabel appendI15d(String resourceKey, Component c1, Component c2) {
648
JLabel label = appendI15d(resourceKey, c1);
654
* Adds an internationalized (i15d) text label and two components to the panel; each component
655
* will span a single column. Proceeds to the next data column.
657
* @param resourceKey the resource key for the text to add
658
* @param c1 the first component to add
659
* @param c2 the second component to add
660
* @param colSpan the column span for the second component
661
* @return the added label
663
public JLabel appendI15d(String resourceKey, Component c1, Component c2, int colSpan) {
664
JLabel label = appendI15d(resourceKey, c1);
670
* Adds an internationalized (i15d) text label and three components to the panel; each component
671
* will span a single column. Proceeds to the next data column.
673
* @param resourceKey the resource key for the text to add
674
* @param c1 the first component to add
675
* @param c2 the second component to add
676
* @param c3 the third component to add
677
* @return the added label
679
public JLabel appendI15d(String resourceKey, Component c1, Component c2, Component c3) {
680
JLabel label = appendI15d(resourceKey, c1, c2);
686
* Adds an internationalized (i15d) text label and four components to the panel;
687
* each component will span a single column. Proceeds to the next data column.
689
* @param resourceKey the resource key for the text to add
690
* @param c1 the first component to add
691
* @param c2 the second component to add
692
* @param c3 the third component to add
693
* @param c4 the third component to add
694
* @return the added label
696
public JLabel appendI15d(String resourceKey, Component c1, Component c2, Component c3, Component c4) {
697
JLabel label = appendI15d(resourceKey, c1, c2, c3);
703
// Adding Titles ----------------------------------------------------------
706
* Adds a title label to the panel and proceeds to the next column.
708
* @param textWithMnemonic the label's text - may mark a mnemonic
709
* @return the added title label
711
public JLabel appendTitle(String textWithMnemonic) {
712
JLabel titleLabel = getComponentFactory().createTitle(textWithMnemonic);
718
* Adds an internationalized title label to the panel and
719
* proceeds to the next column.
721
* @param resourceKey the resource key for the title's text
722
* @return the added title label
724
public JLabel appendI15dTitle(String resourceKey) {
725
return appendTitle(getI15dString(resourceKey));
729
// Appending Separators ---------------------------------------------------
732
* Adds a separator without text that spans all columns.
734
* @return the added titled separator
736
public JComponent appendSeparator() {
737
return appendSeparator("");
741
* Adds a separator with the given text that spans all columns.
743
* @param text the separator title text
744
* @return the added titled separator
746
public JComponent appendSeparator(String text) {
747
ensureCursorColumnInGrid();
748
ensureHasGapRow(paragraphGapSpec);
749
ensureHasComponentLine();
751
setColumn(super.getLeadingColumn());
752
int columnSpan = getColumnCount();
753
setColumnSpan(getColumnCount());
754
JComponent titledSeparator = addSeparator(text);
756
nextColumn(columnSpan);
757
return titledSeparator;
761
* Appends an internationalized titled separator for
762
* the given resource key that spans all columns.
764
* @param resourceKey the resource key for the separator title's text
766
public void appendI15dSeparator(String resourceKey) {
767
appendSeparator(getI15dString(resourceKey));
771
// Overriding Superclass Behavior ***************************************
774
* Returns the leading column. Unlike the superclass this method
775
* honors the column offset.
777
* @return the leading column
779
protected int getLeadingColumn() {
780
int column = super.getLeadingColumn();
781
return column + getLeadingColumnOffset() * getColumnIncrementSign();
785
// Adding Rows **********************************************************
788
* Ensures that the cursor is in the grid. In case it's beyond the
789
* form's right hand side, the cursor is moved to the leading column
792
private void ensureCursorColumnInGrid() {
793
if ( ( isLeftToRight() && (getColumn() > getColumnCount()))
794
|| (!isLeftToRight() && (getColumn() < 1))) {
800
* Ensures that we have a gap row before the next component row.
801
* Checks if the current row is the given <code>RowSpec</code>
802
* and appends this row spec if necessary.
804
* @param gapRowSpec the row specification to check for
806
private void ensureHasGapRow(RowSpec gapRowSpec) {
807
if ((getRow() == 1) || (getRow() <= getRowCount()))
810
if (getRow() <= getRowCount()) {
811
RowSpec rowSpec = getCursorRowSpec();
812
if ((rowSpec == gapRowSpec))
815
appendRow(gapRowSpec);
820
* Ensures that the form has a component row. Adds a component row
821
* if the cursor is beyond the form's bottom.
823
private void ensureHasComponentLine() {
824
if (getRow() <= getRowCount()) return;
825
appendRow(FormFactory.PREF_ROWSPEC);
826
if (isRowGroupingEnabled()) {
827
getLayout().addGroupedRow(getRow());
832
* Looks up and returns the row specification of the current row.
834
* @return the row specification of the current row
836
private RowSpec getCursorRowSpec() {
837
return getLayout().getRowSpec(getRow());