~ubuntu-branches/ubuntu/trusty/libjgoodies-forms-java/trusty

« back to all changes in this revision

Viewing changes to src/main/com/jgoodies/forms/builder/DefaultFormBuilder.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2008-02-25 10:57:07 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080225105707-pe51fdbcq1dt3vi6
Tags: 1.2.0-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All Rights Reserved.
3
 
 *
4
 
 * Redistribution and use in source and binary forms, with or without 
5
 
 * modification, are permitted provided that the following conditions are met:
6
 
 * 
7
 
 *  o Redistributions of source code must retain the above copyright notice, 
8
 
 *    this list of conditions and the following disclaimer. 
9
 
 *     
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. 
13
 
 *     
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. 
17
 
 *     
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. 
29
 
 */
30
 
 
31
 
package com.jgoodies.forms.builder;
32
 
 
33
 
import java.awt.Component;
34
 
import java.util.ResourceBundle;
35
 
 
36
 
import javax.swing.JComponent;
37
 
import javax.swing.JLabel;
38
 
import javax.swing.JPanel;
39
 
 
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;
44
 
 
45
 
/**
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>
50
 
 * 
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>
57
 
 * 
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>
63
 
 * 
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>
70
 
 * 
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 &amp; Tricks
76
 
 * that are part of the Forms documentation.<p>
77
 
 * 
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>
87
 
 * 
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>&amp;</tt>). 
93
 
 * For example <tt>&quot;&amp;Save&quot</tt>, or 
94
 
 * <tt>&quot;Save&nbsp;&amp;as&quot</tt>. To use the ampersand itself, 
95
 
 * duplicate it, for example <tt>&quot;Look&amp;&amp;Feel&quot</tt>.<p>
96
 
 * 
97
 
 * <strong>Example:</strong>
98
 
 * <pre>
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();
106
 
 *
107
 
 *     builder.appendSeparator("Flange");
108
 
 *
109
 
 *     builder.append("Identifier", identifierField);
110
 
 *     builder.nextLine();
111
 
 *
112
 
 *     builder.append("PTI [kW]",   new JTextField());          
113
 
 *     builder.append("Power [kW]", new JTextField());
114
 
 *
115
 
 *     builder.append("s [mm]",     new JTextField());
116
 
 *     builder.nextLine();
117
 
 *
118
 
 *     builder.appendSeparator("Diameters");
119
 
 *
120
 
 *     builder.append("da [mm]",    new JTextField());          
121
 
 *     builder.append("di [mm]",    new JTextField());
122
 
 *
123
 
 *     builder.append("da2 [mm]",   new JTextField());          
124
 
 *     builder.append("di2 [mm]",   new JTextField());
125
 
 *
126
 
 *     builder.append("R [mm]",     new JTextField());          
127
 
 *     builder.append("D [mm]",     new JTextField());
128
 
 *
129
 
 *     builder.appendSeparator("Criteria");
130
 
 *
131
 
 *     builder.append("Location",   buildLocationComboBox());   
132
 
 *     builder.append("k-factor",   new JTextField());
133
 
 *
134
 
 *     builder.appendSeparator("Bolts");
135
 
 *
136
 
 *     builder.append("Material",   ViewerUIFactory.buildMaterialComboBox());
137
 
 *     builder.nextLine();
138
 
 *
139
 
 *     builder.append("Numbers",    new JTextField());
140
 
 *     builder.nextLine();
141
 
 *
142
 
 *     builder.append("ds [mm]",    new JTextField());
143
 
 * }
144
 
 * </pre><p>
145
 
 * 
146
 
 * <strong>Custom Row Example:</strong>
147
 
 * <pre>
148
 
 * public JComponent buildPanel() {
149
 
 *     initComponents();
150
 
 *
151
 
 *     FormLayout layout = new FormLayout(
152
 
 *             "right:pref, 3dlu, default:grow", 
153
 
 *             "");
154
 
 *     DefaultFormBuilder builder = new DefaultFormBuilder(layout);
155
 
 *     builder.setDefaultDialogBorder();
156
 
 *     builder.setRowGroupingEnabled(true);
157
 
 *      
158
 
 *     CellConstraints cc = new CellConstraints();
159
 
 *
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();
174
 
 *
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);
187
 
 *
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));
201
 
 *
202
 
 *     return builder.getPanel();
203
 
 * }
204
 
 * </pre><p>
205
 
 * 
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>.
209
 
 * 
210
 
 * @author      Karsten Lentzsch
211
 
 * @version $Revision: 1.9 $
212
 
 * @since 1.0.3
213
 
 * 
214
 
 * @see com.jgoodies.forms.builder.AbstractFormBuilder
215
 
 * @see com.jgoodies.forms.factories.FormFactory
216
 
 * @see com.jgoodies.forms.layout.FormLayout
217
 
 */
218
 
public final class DefaultFormBuilder extends I15dPanelBuilder {
219
 
 
220
 
    /**
221
 
     * Holds the row specification that is reused to describe
222
 
     * the constant gaps between component lines.
223
 
     */
224
 
    private RowSpec lineGapSpec = FormFactory.LINE_GAP_ROWSPEC;
225
 
 
226
 
    /**
227
 
     * Holds the row specification that describes the constant gaps 
228
 
     * between paragraphs.
229
 
     */
230
 
    private RowSpec paragraphGapSpec = FormFactory.PARAGRAPH_GAP_ROWSPEC;
231
 
    
232
 
    /**
233
 
     * Holds the offset of the leading column - often 0 or 1.
234
 
     * 
235
 
     * @see #getLeadingColumnOffset()
236
 
     * @see #setLeadingColumnOffset(int)
237
 
     * @see #getLeadingColumn()
238
 
     */
239
 
    private int leadingColumnOffset = 0;
240
 
    
241
 
    /**
242
 
     * Determines whether new data rows are being grouped or not. 
243
 
     * 
244
 
     * @see #isRowGroupingEnabled()
245
 
     * @see #setRowGroupingEnabled(boolean)
246
 
     */
247
 
    private boolean rowGroupingEnabled = false;
248
 
    
249
 
 
250
 
    // Instance Creation ****************************************************
251
 
 
252
 
    /**
253
 
     * Constructs an instance of <code>DefaultFormBuilder</code> for the given
254
 
     * layout.
255
 
     * 
256
 
     * @param layout    the <code>FormLayout</code> to be used
257
 
     */    
258
 
    public DefaultFormBuilder(FormLayout layout) {
259
 
        this(new JPanel(null), layout);
260
 
    }
261
 
    
262
 
    /**
263
 
     * Constructs an instance of <code>DefaultFormBuilder</code> for the given
264
 
     * panel and layout.
265
 
     * 
266
 
     * @param layout    the <code>FormLayout</code> to be used
267
 
     * @param panel     the layout container
268
 
     */    
269
 
    public DefaultFormBuilder(FormLayout layout, JPanel panel) {
270
 
        this(panel, layout, null);
271
 
    }
272
 
    
273
 
    /**
274
 
     * Constructs an instance of <code>DefaultFormBuilder</code> for the given
275
 
     * layout and resource bundle.
276
 
     * 
277
 
     * @param layout    the <code>FormLayout</code> to be used
278
 
     * @param bundle    the <code>ResourceBundle</code> used to lookup i15d
279
 
     * strings
280
 
     */    
281
 
    public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) {
282
 
        this(new JPanel(null), layout, bundle);
283
 
    }
284
 
    
285
 
    /**
286
 
     * Constructs an instance of <code>DefaultFormBuilder</code> for the given
287
 
     * panel, layout and resource bundle.
288
 
     * 
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
292
 
     * strings
293
 
     */    
294
 
    public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle, JPanel panel) {
295
 
        super(layout, bundle, panel);
296
 
    }
297
 
 
298
 
    
299
 
    /**
300
 
     * Constructs an instance of <code>DefaultFormBuilder</code> for the given
301
 
     * panel and layout.
302
 
     * 
303
 
     * @param panel     the layout container
304
 
     * @param layout    the <code>FormLayout</code> to be used
305
 
     * 
306
 
     * @deprecated Replaced by {@link #DefaultFormBuilder(FormLayout, JPanel)}.
307
 
     */    
308
 
    public DefaultFormBuilder(JPanel panel, FormLayout layout) {
309
 
        this(layout, null, panel);
310
 
    }
311
 
    
312
 
    /**
313
 
     * Constructs an instance of <code>DefaultFormBuilder</code> for the given
314
 
     * panel, layout and resource bundle.
315
 
     * 
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
319
 
     * strings
320
 
     * 
321
 
     * @deprecated Replaced by {@link #DefaultFormBuilder(FormLayout, ResourceBundle, JPanel)}.
322
 
     */    
323
 
    public DefaultFormBuilder(JPanel panel, FormLayout layout, ResourceBundle bundle) {
324
 
        super(layout, bundle, panel);
325
 
    }
326
 
    
327
 
    
328
 
    // Settings Gap Sizes ***************************************************
329
 
 
330
 
    /**
331
 
     * Returns the row specification that is used to separate component lines.
332
 
     *  
333
 
     * @return the <code>RowSpec</code> that is used to separate lines 
334
 
     */
335
 
    public RowSpec getLineGapSpec() {
336
 
        return lineGapSpec;
337
 
    }
338
 
    
339
 
    /**
340
 
     * Sets the size of gaps between component lines using the given 
341
 
     * constant size.<p>
342
 
     * 
343
 
     * <strong>Examples:</strong><pre>
344
 
     * builder.setLineGapSize(Sizes.ZERO);
345
 
     * builder.setLineGapSize(Sizes.DLUY9);
346
 
     * builder.setLineGapSize(Sizes.pixel(1));
347
 
     * </pre>
348
 
     *  
349
 
     * @param lineGapSize   the <code>ConstantSize</code> that describes 
350
 
     *     the size of the gaps between component lines
351
 
     */
352
 
    public void setLineGapSize(ConstantSize lineGapSize) {
353
 
        RowSpec rowSpec = FormFactory.createGapRowSpec(lineGapSize);
354
 
        this.lineGapSpec = rowSpec;
355
 
    }
356
 
    
357
 
    
358
 
    /**
359
 
     * Sets the size of gaps between paragraphs using the given 
360
 
     * constant size.<p>
361
 
     * 
362
 
     * <strong>Examples:</strong><pre>
363
 
     * builder.setParagraphGapSize(Sizes.DLUY14);
364
 
     * builder.setParagraphGapSize(Sizes.dluY(22));
365
 
     * builder.setParagraphGapSize(Sizes.pixel(42));
366
 
     * </pre>
367
 
     *  
368
 
     * @param paragraphGapSize   the <code>ConstantSize</code> that describes 
369
 
     *     the size of the gaps between paragraphs
370
 
     */
371
 
    public void setParagraphGapSize(ConstantSize paragraphGapSize) {
372
 
        RowSpec rowSpec = FormFactory.createGapRowSpec(paragraphGapSize);
373
 
        this.paragraphGapSpec = rowSpec;
374
 
    }
375
 
    
376
 
    
377
 
    /**
378
 
     * Returns the offset of the leading column, often 0 or 1.
379
 
     * 
380
 
     * @return the offset of the leading column
381
 
     */
382
 
    public int getLeadingColumnOffset() {
383
 
        return leadingColumnOffset;
384
 
    }
385
 
    
386
 
    /**
387
 
     * Sets the offset of the leading column, often 0 or 1.
388
 
     * 
389
 
     * @param columnOffset  the new offset of the leading column
390
 
     */
391
 
    public void setLeadingColumnOffset(int columnOffset) {
392
 
        this.leadingColumnOffset = columnOffset;
393
 
    }
394
 
    
395
 
    
396
 
    /**
397
 
     * Returns whether new data rows are being grouped or not.
398
 
     * 
399
 
     * @return true indicates grouping enabled, false disabled
400
 
     */
401
 
    public boolean isRowGroupingEnabled() {
402
 
        return rowGroupingEnabled;
403
 
    }
404
 
    
405
 
    /**
406
 
     * Enables or disables the grouping of new data rows.
407
 
     * 
408
 
     * @param enabled  indicates grouping enabled, false disabled
409
 
     */
410
 
    public void setRowGroupingEnabled(boolean enabled) {
411
 
        rowGroupingEnabled = enabled;
412
 
    }
413
 
    
414
 
 
415
 
    // Filling Columns ******************************************************
416
 
    
417
 
    /**
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.
420
 
     * 
421
 
     * @param component the component to add
422
 
     */
423
 
    public void append(Component component) {
424
 
        append(component, 1);
425
 
    }
426
 
    
427
 
    /**
428
 
     * Adds a component to the panel using the default constraints with
429
 
     * the given columnSpan. Proceeds to the next data column.
430
 
     * 
431
 
     * @param component the component to append
432
 
     * @param columnSpan    the column span used to add 
433
 
     */
434
 
    public void append(Component component, int columnSpan) {
435
 
        ensureCursorColumnInGrid();
436
 
        ensureHasGapRow(lineGapSpec);
437
 
        ensureHasComponentLine();
438
 
        
439
 
        add(component, createLeftAdjustedConstraints(columnSpan));
440
 
        nextColumn(columnSpan + 1);
441
 
    }
442
 
 
443
 
    /**
444
 
     * Adds two components to the panel; each component will span a single
445
 
     * data column. Proceeds to the next data column.
446
 
     * 
447
 
     * @param c1    the first component to add
448
 
     * @param c2    the second component to add
449
 
     */    
450
 
    public void append(Component c1, Component c2) {
451
 
        append(c1);
452
 
        append(c2);
453
 
    }
454
 
 
455
 
    /**
456
 
     * Adds three components to the panel; each component will span a single
457
 
     * data column. Proceeds to the next data column.
458
 
     * 
459
 
     * @param c1    the first component to add
460
 
     * @param c2    the second component to add
461
 
     * @param c3    the third component to add
462
 
     */    
463
 
    public void append(Component c1, Component c2, Component c3) {
464
 
        append(c1);
465
 
        append(c2);
466
 
        append(c3);
467
 
    }
468
 
 
469
 
 
470
 
    // Appending Labels with optional components ------------------------------
471
 
 
472
 
    /**
473
 
     * Adds a text label to the panel and proceeds to the next column.
474
 
     * 
475
 
     * @param textWithMnemonic  the label's text - may mark a mnemonic
476
 
     * @return the added label
477
 
     */
478
 
    public JLabel append(String textWithMnemonic) {
479
 
        JLabel label = getComponentFactory().createLabel(textWithMnemonic);
480
 
        append(label);
481
 
        return label;
482
 
    }
483
 
 
484
 
    /**
485
 
     * Adds a text label and component to the panel. 
486
 
     * Then proceeds to the next data column.
487
 
     * 
488
 
     * @param textWithMnemonic  the label's text - may mark a mnemonic
489
 
     * @param component         the component to add
490
 
     * @return the added label
491
 
     */    
492
 
    public JLabel append(String textWithMnemonic, Component component) {
493
 
        return append(textWithMnemonic, component, 1);
494
 
    }
495
 
 
496
 
    /**
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.
499
 
     * <p>
500
 
     * The created label is labelling the given component; so the component
501
 
     * gets the focus if the (optional) label mnemonic is pressed.
502
 
     * 
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)
508
 
     */    
509
 
    public JLabel append(String textWithMnemonic, Component c, int columnSpan) {
510
 
        JLabel label = append(textWithMnemonic);
511
 
        label.setLabelFor(c);
512
 
        append(c, columnSpan);
513
 
        return label;
514
 
    }
515
 
 
516
 
    /**
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.
519
 
     * 
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
524
 
     */    
525
 
    public JLabel append(String textWithMnemonic, Component c1, Component c2) {
526
 
        JLabel label = append(textWithMnemonic, c1);
527
 
        append(c2);
528
 
        return label;
529
 
    }
530
 
 
531
 
    /**
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.
534
 
     * 
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
539
 
     */    
540
 
    public void append(String textWithMnemonic, Component c1, Component c2, int colSpan) {
541
 
        append(textWithMnemonic, c1);
542
 
        append(c2, colSpan);
543
 
    }
544
 
 
545
 
    /**
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.
548
 
     * 
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
554
 
     */    
555
 
    public JLabel append(String textWithMnemonic, Component c1, Component c2, Component c3) {
556
 
        JLabel label = append(textWithMnemonic, c1, c2);
557
 
        append(c3);
558
 
        return label;
559
 
    }
560
 
    
561
 
    /**
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.
564
 
     * 
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
571
 
     */    
572
 
    public JLabel append(String textWithMnemonic, Component c1, Component c2, Component c3, Component c4) {
573
 
        JLabel label = append(textWithMnemonic, c1, c2, c3);
574
 
        append(c4);
575
 
        return label;
576
 
    }
577
 
    
578
 
    
579
 
    // Appending internationalized labels with optional components ------------
580
 
 
581
 
    /**
582
 
     * Adds an internationalized (i15d) text label to the panel using 
583
 
     * the given resource key and proceeds to the next column.
584
 
     * 
585
 
     * @param resourceKey      the resource key for the the label's text
586
 
     * @return the added label
587
 
     */
588
 
    public JLabel appendI15d(String resourceKey) {
589
 
        return append(getI15dString(resourceKey));
590
 
    }
591
 
 
592
 
    /**
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.
596
 
     * 
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
601
 
     */    
602
 
    public JLabel appendI15d(String resourceKey, Component c, int columnSpan) {
603
 
        JLabel label = appendI15d(resourceKey);
604
 
        append(c, columnSpan);
605
 
        return label;
606
 
    }
607
 
 
608
 
    /**
609
 
     * Adds an internationalized (i15d) text label and component to the panel. 
610
 
     * Then proceeds to the next data column.
611
 
     * 
612
 
     * @param resourceKey  the resource key for the text to add
613
 
     * @param component  the component to add
614
 
     * @return the added label
615
 
     */    
616
 
    public JLabel appendI15d(String resourceKey, Component component) {
617
 
        return appendI15d(resourceKey, component, 1);
618
 
    }
619
 
 
620
 
    /**
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.
624
 
     * 
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
629
 
     */    
630
 
    public JLabel appendI15d(String resourceKey, Component component, boolean nextLine) {
631
 
        JLabel label = appendI15d(resourceKey, component, 1);
632
 
        if (nextLine) {
633
 
            nextLine();
634
 
        }
635
 
        return label;
636
 
    }
637
 
 
638
 
    /**
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.
641
 
     * 
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
646
 
     */    
647
 
    public JLabel appendI15d(String resourceKey, Component c1, Component c2) {
648
 
        JLabel label = appendI15d(resourceKey, c1);
649
 
        append(c2);
650
 
        return label;
651
 
    }
652
 
 
653
 
    /**
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.
656
 
     * 
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
662
 
     */    
663
 
    public JLabel appendI15d(String resourceKey, Component c1, Component c2, int colSpan) {
664
 
        JLabel label = appendI15d(resourceKey, c1);
665
 
        append(c2, colSpan);
666
 
        return label;
667
 
    }
668
 
 
669
 
    /**
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.
672
 
     * 
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
678
 
     */    
679
 
    public JLabel appendI15d(String resourceKey, Component c1, Component c2, Component c3) {
680
 
        JLabel label = appendI15d(resourceKey, c1, c2);
681
 
        append(c3);
682
 
        return label;
683
 
    }
684
 
 
685
 
    /**
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.
688
 
     * 
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
695
 
     */    
696
 
    public JLabel appendI15d(String resourceKey, Component c1, Component c2, Component c3, Component c4) {
697
 
        JLabel label = appendI15d(resourceKey, c1, c2, c3);
698
 
        append(c4);
699
 
        return label;
700
 
    }
701
 
 
702
 
 
703
 
    // Adding Titles ----------------------------------------------------------
704
 
     
705
 
    /**
706
 
     * Adds a title label to the panel and proceeds to the next column.
707
 
     * 
708
 
     * @param textWithMnemonic  the label's text - may mark a mnemonic
709
 
     * @return the added title label
710
 
     */
711
 
    public JLabel appendTitle(String textWithMnemonic) {
712
 
        JLabel titleLabel = getComponentFactory().createTitle(textWithMnemonic);
713
 
        append(titleLabel);
714
 
        return titleLabel;
715
 
    }
716
 
     
717
 
    /**
718
 
     * Adds an internationalized title label to the panel and 
719
 
     * proceeds to the next column.
720
 
     * 
721
 
     * @param resourceKey   the resource key for the title's text
722
 
     * @return the added title label
723
 
     */
724
 
    public JLabel appendI15dTitle(String resourceKey) {
725
 
        return appendTitle(getI15dString(resourceKey));
726
 
    }
727
 
     
728
 
 
729
 
    // Appending Separators ---------------------------------------------------
730
 
 
731
 
    /**
732
 
     * Adds a separator without text that spans all columns.
733
 
     * 
734
 
     * @return the added titled separator 
735
 
     */
736
 
    public JComponent appendSeparator() {
737
 
        return appendSeparator("");
738
 
    }
739
 
 
740
 
    /**
741
 
     * Adds a separator with the given text that spans all columns.
742
 
     * 
743
 
     * @param text      the separator title text
744
 
     * @return the added titled separator 
745
 
     */
746
 
    public JComponent appendSeparator(String text) {
747
 
        ensureCursorColumnInGrid();
748
 
        ensureHasGapRow(paragraphGapSpec);
749
 
        ensureHasComponentLine();
750
 
        
751
 
        setColumn(super.getLeadingColumn());
752
 
        int columnSpan = getColumnCount();
753
 
        setColumnSpan(getColumnCount());
754
 
        JComponent titledSeparator = addSeparator(text);
755
 
        setColumnSpan(1);
756
 
        nextColumn(columnSpan);
757
 
        return titledSeparator;
758
 
    }
759
 
 
760
 
    /**
761
 
     * Appends an internationalized titled separator for 
762
 
     * the given resource key that spans all columns.
763
 
     * 
764
 
     * @param resourceKey   the resource key for the separator title's text
765
 
     */
766
 
    public void appendI15dSeparator(String resourceKey) {
767
 
        appendSeparator(getI15dString(resourceKey));
768
 
    }
769
 
    
770
 
 
771
 
    // Overriding Superclass Behavior ***************************************
772
 
    
773
 
    /**
774
 
     * Returns the leading column. Unlike the superclass this method
775
 
     * honors the column offset.
776
 
     * 
777
 
     * @return the leading column
778
 
     */
779
 
    protected int getLeadingColumn() {
780
 
        int column = super.getLeadingColumn();
781
 
        return column + getLeadingColumnOffset() * getColumnIncrementSign();
782
 
    }
783
 
    
784
 
    
785
 
    // Adding Rows **********************************************************
786
 
    
787
 
    /**
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
790
 
     * of the next line.
791
 
     */
792
 
    private void ensureCursorColumnInGrid() {
793
 
        if (   ( isLeftToRight() && (getColumn() > getColumnCount()))
794
 
            || (!isLeftToRight() && (getColumn() < 1))) {
795
 
            nextLine();
796
 
        }
797
 
    }
798
 
    
799
 
    /**
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.
803
 
     * 
804
 
     * @param gapRowSpec  the row specification to check for
805
 
     */
806
 
    private void ensureHasGapRow(RowSpec gapRowSpec) {
807
 
        if ((getRow() == 1) || (getRow() <= getRowCount()))
808
 
            return;
809
 
        
810
 
        if (getRow() <= getRowCount()) {
811
 
            RowSpec rowSpec = getCursorRowSpec();
812
 
            if ((rowSpec == gapRowSpec))
813
 
                return;
814
 
        }
815
 
        appendRow(gapRowSpec);
816
 
        nextLine();
817
 
    }
818
 
    
819
 
    /**
820
 
     * Ensures that the form has a component row. Adds a component row
821
 
     * if the cursor is beyond the form's bottom.
822
 
     */
823
 
    private void ensureHasComponentLine() {
824
 
        if (getRow() <= getRowCount()) return;
825
 
        appendRow(FormFactory.PREF_ROWSPEC);  
826
 
        if (isRowGroupingEnabled()) {
827
 
            getLayout().addGroupedRow(getRow());
828
 
        }      
829
 
    }
830
 
    
831
 
    /**
832
 
     * Looks up and returns the row specification of the current row.
833
 
     *  
834
 
     * @return the row specification of the current row
835
 
     */
836
 
    private RowSpec getCursorRowSpec() {
837
 
        return getLayout().getRowSpec(getRow());
838
 
    }
839
 
 
840
 
 
841
 
}