001: /*
002: * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.forms.builder;
032:
033: import java.awt.Component;
034: import java.util.ResourceBundle;
035:
036: import javax.swing.JComponent;
037: import javax.swing.JLabel;
038: import javax.swing.JPanel;
039:
040: import com.jgoodies.forms.factories.FormFactory;
041: import com.jgoodies.forms.layout.ConstantSize;
042: import com.jgoodies.forms.layout.FormLayout;
043: import com.jgoodies.forms.layout.RowSpec;
044:
045: /**
046: * Provides a means to build form-oriented panels quickly and consistently
047: * using the {@link FormLayout}. This builder combines frequently used
048: * panel building steps: add a new row, add a label, proceed to the next
049: * data column, then add a component.<p>
050: *
051: * The extra value lies in the <code>#append</code> methods that
052: * append gap rows and component rows if necessary and then add
053: * the given components. They are built upon the superclass behavior
054: * <code>#appendRow</code> and the set of <code>#add</code> methods.
055: * A set of component appenders allows to add a textual label and
056: * associated component in a single step.<p>
057: *
058: * This builder can map resource keys to internationalized (i15d) texts
059: * when creating text labels, titles and titled separators. Therefore
060: * you must specify a <code>ResourceBundle</code> in the constructor.
061: * The builder methods throw an <code>IllegalStateException</code> if one
062: * of the mapping builder methods is invoked and no bundle has been set.<p>
063: *
064: * You can configure the build process by setting a leading column,
065: * enabling the row grouping and by modifying the gaps between normal
066: * lines and between paragraphs. The leading column will be honored
067: * if the cursor proceeds to the next row. All appended components
068: * start in the specified lead column, except appended separators that
069: * span all columns.<p>
070: *
071: * It is temptive to use the DefaultFormBuilder all the time and
072: * to let it add rows automatically. Use a simpler style if it increases
073: * the code readability. Explicit row specifications and cell constraints
074: * make your layout easier to understand - but harder to maintain.
075: * See also the accompanying tutorial sources and the Tips & Tricks
076: * that are part of the Forms documentation.<p>
077: *
078: * Sometimes a form consists of many standardized rows but has a few
079: * rows that require a customization. The DefaultFormBuilder can do everything
080: * that the superclasses {@link com.jgoodies.forms.builder.AbstractFormBuilder}
081: * and {@link com.jgoodies.forms.builder.PanelBuilder} can do;
082: * among other things: appending new rows and moving the cursor.
083: * Again, ask yourself if the DefaultFormBuilder is the appropriate builder.
084: * As a rule of thumb you should have more components than builder commands.
085: * There are different ways to add custom rows. Find below example code
086: * that presents and compares the pros and cons of three approaches.<p>
087: *
088: * The texts used in methods <code>#append(String, ...)</code> and
089: * <code>#appendTitle(String)</code> as well as the localized texts used in
090: * methods <code>#appendI15d</code> and <code>#appendI15dTitle</code>
091: * can contain an optional mnemonic marker. The mnemonic and mnemonic index
092: * are indicated by a single ampersand (<tt>&</tt>).
093: * For example <tt>"&Save"</tt>, or
094: * <tt>"Save &as"</tt>. To use the ampersand itself,
095: * duplicate it, for example <tt>"Look&&Feel"</tt>.<p>
096: *
097: * <strong>Example:</strong>
098: * <pre>
099: * 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.4 $
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: // Instance Creation ****************************************************
250:
251: /**
252: * Constructs a <code>DefaultFormBuilder</code> for the given
253: * layout.
254: *
255: * @param layout the <code>FormLayout</code> to be used
256: */
257: public DefaultFormBuilder(FormLayout layout) {
258: this (layout, new JPanel(null));
259: }
260:
261: /**
262: * Constructs a <code>DefaultFormBuilder</code> for the given
263: * layout and panel.
264: *
265: * @param layout the <code>FormLayout</code> to be used
266: * @param panel the layout container
267: */
268: public DefaultFormBuilder(FormLayout layout, JPanel panel) {
269: this (layout, null, panel);
270: }
271:
272: /**
273: * Constructs a <code>DefaultFormBuilder</code> for the given
274: * layout and resource bundle.
275: *
276: * @param layout the <code>FormLayout</code> to be used
277: * @param bundle the <code>ResourceBundle</code> used to lookup i15d
278: * strings
279: */
280: public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) {
281: this (layout, bundle, new JPanel(null));
282: }
283:
284: /**
285: * Constructs a <code>DefaultFormBuilder</code> for the given
286: * layout, resource bundle, and panel.
287: *
288: * @param layout the <code>FormLayout</code> to be used
289: * @param panel the layout container
290: * @param bundle the <code>ResourceBundle</code> used to lookup i15d
291: * strings
292: */
293: public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle,
294: JPanel panel) {
295: super (layout, bundle, panel);
296: }
297:
298: // Settings Gap Sizes ***************************************************
299:
300: /**
301: * Returns the row specification that is used to separate component lines.
302: *
303: * @return the <code>RowSpec</code> that is used to separate lines
304: */
305: public RowSpec getLineGapSpec() {
306: return lineGapSpec;
307: }
308:
309: /**
310: * Sets the size of gaps between component lines using the given
311: * constant size.<p>
312: *
313: * <strong>Examples:</strong><pre>
314: * builder.setLineGapSize(Sizes.ZERO);
315: * builder.setLineGapSize(Sizes.DLUY9);
316: * builder.setLineGapSize(Sizes.pixel(1));
317: * </pre>
318: *
319: * @param lineGapSize the <code>ConstantSize</code> that describes
320: * the size of the gaps between component lines
321: */
322: public void setLineGapSize(ConstantSize lineGapSize) {
323: RowSpec rowSpec = FormFactory.createGapRowSpec(lineGapSize);
324: this .lineGapSpec = rowSpec;
325: }
326:
327: /**
328: * Sets the size of gaps between paragraphs using the given
329: * constant size.<p>
330: *
331: * <strong>Examples:</strong><pre>
332: * builder.setParagraphGapSize(Sizes.DLUY14);
333: * builder.setParagraphGapSize(Sizes.dluY(22));
334: * builder.setParagraphGapSize(Sizes.pixel(42));
335: * </pre>
336: *
337: * @param paragraphGapSize the <code>ConstantSize</code> that describes
338: * the size of the gaps between paragraphs
339: */
340: public void setParagraphGapSize(ConstantSize paragraphGapSize) {
341: RowSpec rowSpec = FormFactory
342: .createGapRowSpec(paragraphGapSize);
343: this .paragraphGapSpec = rowSpec;
344: }
345:
346: /**
347: * Returns the offset of the leading column, often 0 or 1.
348: *
349: * @return the offset of the leading column
350: */
351: public int getLeadingColumnOffset() {
352: return leadingColumnOffset;
353: }
354:
355: /**
356: * Sets the offset of the leading column, often 0 or 1.
357: *
358: * @param columnOffset the new offset of the leading column
359: */
360: public void setLeadingColumnOffset(int columnOffset) {
361: this .leadingColumnOffset = columnOffset;
362: }
363:
364: /**
365: * Returns whether new data rows are being grouped or not.
366: *
367: * @return true indicates grouping enabled, false disabled
368: */
369: public boolean isRowGroupingEnabled() {
370: return rowGroupingEnabled;
371: }
372:
373: /**
374: * Enables or disables the grouping of new data rows.
375: *
376: * @param enabled indicates grouping enabled, false disabled
377: */
378: public void setRowGroupingEnabled(boolean enabled) {
379: rowGroupingEnabled = enabled;
380: }
381:
382: // Filling Columns ******************************************************
383:
384: /**
385: * Adds a component to the panel using the default constraints
386: * with a column span of 1. Then proceeds to the next data column.
387: *
388: * @param component the component to add
389: */
390: public void append(Component component) {
391: append(component, 1);
392: }
393:
394: /**
395: * Adds a component to the panel using the default constraints with
396: * the given columnSpan. Proceeds to the next data column.
397: *
398: * @param component the component to append
399: * @param columnSpan the column span used to add
400: */
401: public void append(Component component, int columnSpan) {
402: ensureCursorColumnInGrid();
403: ensureHasGapRow(lineGapSpec);
404: ensureHasComponentLine();
405:
406: add(component, createLeftAdjustedConstraints(columnSpan));
407: nextColumn(columnSpan + 1);
408: }
409:
410: /**
411: * Adds two components to the panel; each component will span a single
412: * data column. Proceeds to the next data column.
413: *
414: * @param c1 the first component to add
415: * @param c2 the second component to add
416: */
417: public void append(Component c1, Component c2) {
418: append(c1);
419: append(c2);
420: }
421:
422: /**
423: * Adds three components to the panel; each component will span a single
424: * data column. Proceeds to the next data column.
425: *
426: * @param c1 the first component to add
427: * @param c2 the second component to add
428: * @param c3 the third component to add
429: */
430: public void append(Component c1, Component c2, Component c3) {
431: append(c1);
432: append(c2);
433: append(c3);
434: }
435:
436: // Appending Labels with optional components ------------------------------
437:
438: /**
439: * Adds a text label to the panel and proceeds to the next column.
440: *
441: * @param textWithMnemonic the label's text - may mark a mnemonic
442: * @return the added label
443: */
444: public JLabel append(String textWithMnemonic) {
445: JLabel label = getComponentFactory().createLabel(
446: textWithMnemonic);
447: append(label);
448: return label;
449: }
450:
451: /**
452: * Adds a text label and component to the panel.
453: * Then proceeds to the next data column.<p>
454: *
455: * The created label is labelling the given component; so the component
456: * gets the focus if the (optional) label mnemonic is pressed.
457: *
458: * @param textWithMnemonic the label's text - may mark a mnemonic
459: * @param component the component to add
460: * @return the added label
461: */
462: public JLabel append(String textWithMnemonic, Component component) {
463: return append(textWithMnemonic, component, 1);
464: }
465:
466: /**
467: * Adds a text label and component to the panel; the component will span
468: * the specified number columns. Proceeds to the next data column,
469: * and goes to the next line if the boolean flag is set.<p>
470: *
471: * The created label is labelling the given component; so the component
472: * gets the focus if the (optional) label mnemonic is pressed.
473: *
474: * @param textWithMnemonic the label's text - may mark a mnemonic
475: * @param c the component to add
476: * @param nextLine true forces a next line
477: * @return the added label
478: * @see JLabel#setLabelFor(java.awt.Component)
479: */
480: public JLabel append(String textWithMnemonic, Component c,
481: boolean nextLine) {
482: JLabel label = append(textWithMnemonic, c);
483: if (nextLine) {
484: nextLine();
485: }
486: return label;
487: }
488:
489: /**
490: * Adds a text label and component to the panel; the component will span
491: * the specified number columns. Proceeds to the next data column.<p>
492: *
493: * The created label is labelling the given component; so the component
494: * gets the focus if the (optional) label mnemonic is pressed.
495: *
496: * @param textWithMnemonic the label's text - may mark a mnemonic
497: * @param c the component to add
498: * @param columnSpan number of columns the component shall span
499: * @return the added label
500: * @see JLabel#setLabelFor(java.awt.Component)
501: */
502: public JLabel append(String textWithMnemonic, Component c,
503: int columnSpan) {
504: JLabel label = append(textWithMnemonic);
505: label.setLabelFor(c);
506: append(c, columnSpan);
507: return label;
508: }
509:
510: /**
511: * Adds a text label and two components to the panel; each component
512: * will span a single column. Proceeds to the next data column.<p>
513: *
514: * The created label is labelling the first component; so the component
515: * gets the focus if the (optional) label mnemonic is pressed.
516: *
517: * @param textWithMnemonic the label's text - may mark a mnemonic
518: * @param c1 the first component to add
519: * @param c2 the second component to add
520: * @return the added label
521: */
522: public JLabel append(String textWithMnemonic, Component c1,
523: Component c2) {
524: JLabel label = append(textWithMnemonic, c1);
525: append(c2);
526: return label;
527: }
528:
529: /**
530: * Adds a text label and two components to the panel; each component
531: * will span a single column. Proceeds to the next data column.<p>
532: *
533: * The created label is labelling the first component; so the component
534: * gets the focus if the (optional) label mnemonic is pressed.
535: *
536: * @param textWithMnemonic the label's text - may mark a mnemonic
537: * @param c1 the first component to add
538: * @param c2 the second component to add
539: * @param colSpan the column span for the second component
540: * @return the created label
541: */
542: public JLabel append(String textWithMnemonic, Component c1,
543: Component c2, int colSpan) {
544: JLabel label = append(textWithMnemonic, c1);
545: append(c2, colSpan);
546: return label;
547: }
548:
549: /**
550: * Adds a text label and three components to the panel; each component
551: * will span a single column. Proceeds to the next data column.<p>
552: *
553: * The created label is labelling the first component; so the component
554: * gets the focus if the (optional) label mnemonic is pressed.
555: *
556: * @param textWithMnemonic the label's text - may mark a mnemonic
557: * @param c1 the first component to add
558: * @param c2 the second component to add
559: * @param c3 the third component to add
560: * @return the added label
561: */
562: public JLabel append(String textWithMnemonic, Component c1,
563: Component c2, Component c3) {
564: JLabel label = append(textWithMnemonic, c1, c2);
565: append(c3);
566: return label;
567: }
568:
569: /**
570: * Adds a text label and four components to the panel; each component
571: * will span a single column. Proceeds to the next data column.<p>
572: *
573: * The created label is labelling the first component; so the component
574: * gets the focus if the (optional) label mnemonic is pressed.
575: *
576: * @param textWithMnemonic the label's text - may mark a mnemonic
577: * @param c1 the first component to add
578: * @param c2 the second component to add
579: * @param c3 the third component to add
580: * @param c4 the fourth component to add
581: * @return the added label
582: */
583: public JLabel append(String textWithMnemonic, Component c1,
584: Component c2, Component c3, Component c4) {
585: JLabel label = append(textWithMnemonic, c1, c2, c3);
586: append(c4);
587: return label;
588: }
589:
590: // Appending internationalized labels with optional components ------------
591:
592: /**
593: * Adds an internationalized (i15d) text label to the panel using
594: * the given resource key and proceeds to the next column.
595: *
596: * @param resourceKey the resource key for the the label's text
597: * @return the added label
598: */
599: public JLabel appendI15d(String resourceKey) {
600: return append(getI15dString(resourceKey));
601: }
602:
603: /**
604: * Adds an internationalized (i15d) text label and component
605: * to the panel. Then proceeds to the next data column.<p>
606: *
607: * The created label is labelling the given component; so the component
608: * gets the focus if the (optional) label mnemonic is pressed.
609: *
610: * @param resourceKey the resource key for the text to add
611: * @param component the component to add
612: * @return the added label
613: */
614: public JLabel appendI15d(String resourceKey, Component component) {
615: return append(getI15dString(resourceKey), component, 1);
616: }
617:
618: /**
619: * Adds an internationalized (i15d) text label and component
620: * to the panel. Then proceeds to the next data column.
621: * Goes to the next line if the boolean flag is set.<p>
622: *
623: * The created label is labelling the first component; so the component
624: * gets the focus if the (optional) label mnemonic is pressed.
625: *
626: * @param resourceKey the resource key for the text to add
627: * @param component the component to add
628: * @param nextLine true forces a next line
629: * @return the added label
630: */
631: public JLabel appendI15d(String resourceKey, Component component,
632: boolean nextLine) {
633: return append(getI15dString(resourceKey), component, nextLine);
634: }
635:
636: /**
637: * Adds an internationalized (i15d) text label to the panel using
638: * the given resource key; then proceeds to the next data column
639: * and adds a component with the given column span.
640: * Proceeds to the next data column.<p>
641: *
642: * The created label is labelling the first component; so the component
643: * gets the focus if the (optional) label mnemonic is pressed.
644: *
645: * @param resourceKey the resource key for the text to add
646: * @param c the component to add
647: * @param columnSpan number of columns the component shall span
648: * @return the added label
649: */
650: public JLabel appendI15d(String resourceKey, Component c,
651: int columnSpan) {
652: return append(getI15dString(resourceKey), c, columnSpan);
653: }
654:
655: /**
656: * Adds an internationalized (i15d) text label and two components
657: * to the panel; each component will span a single column.
658: * Proceeds to the next data column.<p>
659: *
660: * The created label is labelling the first component; so the component
661: * gets the focus if the (optional) label mnemonic is pressed.
662: *
663: * @param resourceKey the resource key for the text to add
664: * @param c1 the first component to add
665: * @param c2 the second component to add
666: * @return the added label
667: */
668: public JLabel appendI15d(String resourceKey, Component c1,
669: Component c2) {
670: return append(getI15dString(resourceKey), c1, c2);
671: }
672:
673: /**
674: * Adds an internationalized (i15d) text label and two components
675: * to the panel; each component will span a single column.
676: * Proceeds to the next data column.<p>
677: *
678: * The created label is labelling the first component; so the component
679: * gets the focus if the (optional) label mnemonic is pressed.
680: *
681: * @param resourceKey the resource key for the text to add
682: * @param c1 the first component to add
683: * @param c2 the second component to add
684: * @param colSpan the column span for the second component
685: * @return the added label
686: */
687: public JLabel appendI15d(String resourceKey, Component c1,
688: Component c2, int colSpan) {
689: return append(getI15dString(resourceKey), c1, c2, colSpan);
690: }
691:
692: /**
693: * Adds an internationalized (i15d) text label and three components
694: * to the panel; each component will span a single column.
695: * Proceeds to the next data column.<p>
696: *
697: * The created label is labelling the first component; so the component
698: * gets the focus if the (optional) label mnemonic is pressed.
699: *
700: * @param resourceKey the resource key for the text to add
701: * @param c1 the first component to add
702: * @param c2 the second component to add
703: * @param c3 the third component to add
704: * @return the added label
705: */
706: public JLabel appendI15d(String resourceKey, Component c1,
707: Component c2, Component c3) {
708: return append(getI15dString(resourceKey), c1, c2, c3);
709: }
710:
711: /**
712: * Adds an internationalized (i15d) text label and four components
713: * to the panel; each component will span a single column.
714: * Proceeds to the next data column.<p>
715: *
716: * The created label is labelling the first component; so the component
717: * gets the focus if the (optional) label mnemonic is pressed.
718: *
719: * @param resourceKey the resource key for the text to add
720: * @param c1 the first component to add
721: * @param c2 the second component to add
722: * @param c3 the third component to add
723: * @param c4 the third component to add
724: * @return the added label
725: */
726: public JLabel appendI15d(String resourceKey, Component c1,
727: Component c2, Component c3, Component c4) {
728: return append(getI15dString(resourceKey), c1, c2, c3, c4);
729: }
730:
731: // Adding Titles ----------------------------------------------------------
732:
733: /**
734: * Adds a title label to the panel and proceeds to the next column.
735: *
736: * @param textWithMnemonic the label's text - may mark a mnemonic
737: * @return the added title label
738: */
739: public JLabel appendTitle(String textWithMnemonic) {
740: JLabel titleLabel = getComponentFactory().createTitle(
741: textWithMnemonic);
742: append(titleLabel);
743: return titleLabel;
744: }
745:
746: /**
747: * Adds an internationalized title label to the panel and
748: * proceeds to the next column.
749: *
750: * @param resourceKey the resource key for the title's text
751: * @return the added title label
752: */
753: public JLabel appendI15dTitle(String resourceKey) {
754: return appendTitle(getI15dString(resourceKey));
755: }
756:
757: // Appending Separators ---------------------------------------------------
758:
759: /**
760: * Adds a separator without text that spans all columns.
761: *
762: * @return the added titled separator
763: */
764: public JComponent appendSeparator() {
765: return appendSeparator("");
766: }
767:
768: /**
769: * Adds a separator with the given text that spans all columns.
770: *
771: * @param text the separator title text
772: * @return the added titled separator
773: */
774: public JComponent appendSeparator(String text) {
775: ensureCursorColumnInGrid();
776: ensureHasGapRow(paragraphGapSpec);
777: ensureHasComponentLine();
778:
779: setColumn(super .getLeadingColumn());
780: int columnSpan = getColumnCount();
781: setColumnSpan(getColumnCount());
782: JComponent titledSeparator = addSeparator(text);
783: setColumnSpan(1);
784: nextColumn(columnSpan);
785: return titledSeparator;
786: }
787:
788: /**
789: * Appends an internationalized titled separator for
790: * the given resource key that spans all columns.
791: *
792: * @param resourceKey the resource key for the separator title's text
793: * @return the added titled separator
794: */
795: public JComponent appendI15dSeparator(String resourceKey) {
796: return appendSeparator(getI15dString(resourceKey));
797: }
798:
799: // Overriding Superclass Behavior ***************************************
800:
801: /**
802: * Returns the leading column. Unlike the superclass this method
803: * honors the column offset.
804: *
805: * @return the leading column
806: */
807: protected int getLeadingColumn() {
808: int column = super .getLeadingColumn();
809: return column + getLeadingColumnOffset()
810: * getColumnIncrementSign();
811: }
812:
813: // Adding Rows **********************************************************
814:
815: /**
816: * Ensures that the cursor is in the grid. In case it's beyond the
817: * form's right hand side, the cursor is moved to the leading column
818: * of the next line.
819: */
820: private void ensureCursorColumnInGrid() {
821: if ((isLeftToRight() && (getColumn() > getColumnCount()))
822: || (!isLeftToRight() && (getColumn() < 1))) {
823: nextLine();
824: }
825: }
826:
827: /**
828: * Ensures that we have a gap row before the next component row.
829: * Checks if the current row is the given <code>RowSpec</code>
830: * and appends this row spec if necessary.
831: *
832: * @param gapRowSpec the row specification to check for
833: */
834: private void ensureHasGapRow(RowSpec gapRowSpec) {
835: if ((getRow() == 1) || (getRow() <= getRowCount()))
836: return;
837:
838: if (getRow() <= getRowCount()) {
839: RowSpec rowSpec = getCursorRowSpec();
840: if ((rowSpec == gapRowSpec))
841: return;
842: }
843: appendRow(gapRowSpec);
844: nextLine();
845: }
846:
847: /**
848: * Ensures that the form has a component row. Adds a component row
849: * if the cursor is beyond the form's bottom.
850: */
851: private void ensureHasComponentLine() {
852: if (getRow() <= getRowCount())
853: return;
854: appendRow(FormFactory.PREF_ROWSPEC);
855: if (isRowGroupingEnabled()) {
856: getLayout().addGroupedRow(getRow());
857: }
858: }
859:
860: /**
861: * Looks up and returns the row specification of the current row.
862: *
863: * @return the row specification of the current row
864: */
865: private RowSpec getCursorRowSpec() {
866: return getLayout().getRowSpec(getRow());
867: }
868:
869: }
|