001: /*
002: * Copyright (c) 2002-2004 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 using
047: * the {@link FormLayout}. This builder combines frequently used panel building
048: * steps: add a new row, add a label, proceed to the next data column, then add
049: * a component.
050: * <p>
051: *
052: * The extra value lies in the <code>#append</code> methods that append gap
053: * rows and component rows if necessary and then add the given components. They
054: * are built upon the superclass behavior <code>#appendRow</code> and the set
055: * of <code>#add</code> methods. A set of component appenders allows to add a
056: * textual label and associated component in a single step.
057: * <p>
058: *
059: * This builder can map resource keys to internationalized (i15d) texts when
060: * creating text labels, titles and titled separators. Therefore you must
061: * specify a <code>ResourceBundle</code> in the constructor. The builder
062: * methods throw an <code>IllegalStateException</code> if one of the mapping
063: * builder methods is invoked and no bundle has been set.
064: * <p>
065: *
066: * You can configure the build process by setting a leading column, enabling the
067: * row grouping and by modifying the gaps between normal lines and between
068: * paragraphs. The leading column will be honored if the cursor proceeds to the
069: * next row. All appended components start in the specified lead column, except
070: * appended separators that span all columns.
071: * <p>
072: *
073: * It is temptive to use the DefaultFormBuilder all the time and to let it add
074: * rows automatically. Use a simpler style if it increases the code readability.
075: * Explicit row specifications and cell constraints make your layout easier to
076: * understand - but harder to maintain. See also the accompanying tutorial
077: * sources and the Tips & Tricks that are part of the Forms documentation.
078: * <p>
079: *
080: * Sometimes a form consists of many standardized rows but has a few rows that
081: * require a customization. The DefaultFormBuilder can do everything that the
082: * superclasses {@link com.jgoodies.forms.builder.AbstractFormBuilder} and
083: * {@link com.jgoodies.forms.builder.PanelBuilder} can do; among other things:
084: * appending new rows and moving the cursor. Again, ask yourself if the
085: * DefaultFormBuilder is the appropriate builder. As a rule of thumb you should
086: * have more components than builder commands. There are different ways to add
087: * custom rows. Find below example code that presents and compares the pros and
088: * cons of three approaches.
089: * <p>
090: *
091: * The texts used in methods <code>#append(String, ...)</code> and
092: * <code>#appendTitle(String)</code> as well as the localized texts used in
093: * methods <code>#appendI15d</code> and <code>#appendI15dTitle</code> can
094: * contain an optional mnemonic marker. The mnemonic and mnemonic index are
095: * indicated by a single ampersand (<tt>&</tt>). For example
096: * <tt>"&Save"</tt>, or <tt>"Save &as"</tt>.
097: * To use the ampersand itself, duplicate it, for example
098: * <tt>"Look&&Feel"</tt>.
099: * <p>
100: *
101: * <strong>Example:</strong>
102: *
103: * <pre>
104: * public void build() {
105: * FormLayout layout = new FormLayout("right:max(40dlu;pref), 3dlu, 80dlu, 7dlu, " // 1st major colum
106: * + "right:max(40dlu;pref), 3dlu, 80dlu", // 2nd major column
107: * ""); // add rows dynamically
108: * DefaultFormBuilder builder = new DefaultFormBuilder(layout);
109: * builder.setDefaultDialogBorder();
110: *
111: * builder.appendSeparator("Flange");
112: *
113: * builder.append("Identifier", identifierField);
114: * builder.nextLine();
115: *
116: * builder.append("PTI [kW]", new JTextField());
117: * builder.append("Power [kW]", new JTextField());
118: *
119: * builder.append("s [mm]", new JTextField());
120: * builder.nextLine();
121: *
122: * builder.appendSeparator("Diameters");
123: *
124: * builder.append("da [mm]", new JTextField());
125: * builder.append("di [mm]", new JTextField());
126: *
127: * builder.append("da2 [mm]", new JTextField());
128: * builder.append("di2 [mm]", new JTextField());
129: *
130: * builder.append("R [mm]", new JTextField());
131: * builder.append("D [mm]", new JTextField());
132: *
133: * builder.appendSeparator("Criteria");
134: *
135: * builder.append("Location", buildLocationComboBox());
136: * builder.append("k-factor", new JTextField());
137: *
138: * builder.appendSeparator("Bolts");
139: *
140: * builder.append("Material", ViewerUIFactory.buildMaterialComboBox());
141: * builder.nextLine();
142: *
143: * builder.append("Numbers", new JTextField());
144: * builder.nextLine();
145: *
146: * builder.append("ds [mm]", new JTextField());
147: * }
148: * </pre>
149: *
150: * <p>
151: *
152: * <strong>Custom Row Example:</strong>
153: *
154: * <pre>
155: * public JComponent buildPanel() {
156: * initComponents();
157: *
158: * FormLayout layout = new FormLayout("right:pref, 3dlu, default:grow", "");
159: * DefaultFormBuilder builder = new DefaultFormBuilder(layout);
160: * builder.setDefaultDialogBorder();
161: * builder.setRowGroupingEnabled(true);
162: *
163: * CellConstraints cc = new CellConstraints();
164: *
165: * // In this approach, we add a gap and a custom row.
166: * // The advantage of this approach is, that we can express
167: * // the row spec and comment area cell constraints freely.
168: * // The disadvantage is the misalignment of the leading label.
169: * // Also the row's height may be inconsistent with other rows.
170: * builder.appendSeparator("Single Custom Row");
171: * builder.append("Name", name1Field);
172: * builder.appendRow(builder.getLineGapSpec());
173: * builder.appendRow(new RowSpec("top:31dlu")); // Assumes line is 14, gap is 3
174: * builder.nextLine(2);
175: * builder.append("Comment");
176: * builder.add(new JScrollPane(comment1Area), cc.xy(builder.getColumn(), builder.getRow(), "fill, fill"));
177: * builder.nextLine();
178: *
179: * // In this approach, we append a standard row with gap before it.
180: * // The advantage is, that the leading label is aligned well.
181: * // The disadvantage is that the comment area now spans
182: * // multiple cells and is slightly less flexible.
183: * // Also the row's height may be inconsistent with other rows.
184: * builder.appendSeparator("Standard + Custom Row");
185: * builder.append("Name", name2Field);
186: * builder.append("Comment");
187: * builder.appendRow(new RowSpec("17dlu")); // Assumes line is 14, gap is 3
188: * builder.add(new JScrollPane(comment2Area), cc.xywh(builder.getColumn(), builder.getRow(), 1, 2));
189: * builder.nextLine(2);
190: *
191: * // In this approach, we append two standard rows with associated gaps.
192: * // The advantage is, that the leading label is aligned well,
193: * // and the height is consistent with other rows.
194: * // The disadvantage is that the comment area now spans
195: * // multiple cells and is slightly less flexible.
196: * builder.appendSeparator("Two Standard Rows");
197: * builder.append("Name", name3Field);
198: * builder.append("Comment");
199: * builder.nextLine();
200: * builder.append("");
201: * builder.nextRow(-2);
202: * builder.add(new JScrollPane(comment3Area), cc.xywh(builder.getColumn(), builder.getRow(), 1, 3));
203: *
204: * return builder.getPanel();
205: * }
206: * </pre>
207: *
208: * <p>
209: *
210: * TODO: Consider adding a method for appending a component that spans the
211: * remaining columns in the current row. Method name candidates are
212: * <code>#appendFullSpan</code> and <code>#appendRemaining</code>.
213: *
214: * @author Karsten Lentzsch
215: * @version $Revision: 1.2 $
216: * @since 1.0.3
217: *
218: * @see com.jgoodies.forms.builder.AbstractFormBuilder
219: * @see com.jgoodies.forms.factories.FormFactory
220: * @see com.jgoodies.forms.layout.FormLayout
221: */
222: public final class DefaultFormBuilder extends I15dPanelBuilder {
223:
224: /**
225: * Holds the row specification that is reused to describe the constant gaps
226: * between component lines.
227: */
228: private RowSpec lineGapSpec = FormFactory.LINE_GAP_ROWSPEC;
229:
230: /**
231: * Holds the row specification that describes the constant gaps between
232: * paragraphs.
233: */
234: private RowSpec paragraphGapSpec = FormFactory.PARAGRAPH_GAP_ROWSPEC;
235:
236: /**
237: * Holds the offset of the leading column - often 0 or 1.
238: *
239: * @see #getLeadingColumnOffset()
240: * @see #setLeadingColumnOffset(int)
241: * @see #getLeadingColumn()
242: */
243: private int leadingColumnOffset = 0;
244:
245: /**
246: * Determines whether new data rows are being grouped or not.
247: *
248: * @see #isRowGroupingEnabled()
249: * @see #setRowGroupingEnabled(boolean)
250: */
251: private boolean rowGroupingEnabled = false;
252:
253: // Instance Creation ****************************************************
254:
255: /**
256: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
257: * layout.
258: *
259: * @param layout
260: * the <code>FormLayout</code> to be used
261: */
262: public DefaultFormBuilder(FormLayout layout) {
263: this (new JPanel(null), layout);
264: }
265:
266: /**
267: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
268: * panel and layout.
269: *
270: * @param layout
271: * the <code>FormLayout</code> to be used
272: * @param panel
273: * the layout container
274: */
275: public DefaultFormBuilder(FormLayout layout, JPanel panel) {
276: this (panel, layout, null);
277: }
278:
279: /**
280: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
281: * layout and resource bundle.
282: *
283: * @param layout
284: * the <code>FormLayout</code> to be used
285: * @param bundle
286: * the <code>ResourceBundle</code> used to lookup i15d strings
287: */
288: public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) {
289: this (new JPanel(null), layout, bundle);
290: }
291:
292: /**
293: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
294: * panel, layout and resource bundle.
295: *
296: * @param layout
297: * the <code>FormLayout</code> to be used
298: * @param panel
299: * the layout container
300: * @param bundle
301: * the <code>ResourceBundle</code> used to lookup i15d strings
302: */
303: public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle,
304: JPanel panel) {
305: super (layout, bundle, panel);
306: }
307:
308: /**
309: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
310: * panel and layout.
311: *
312: * @param panel
313: * the layout container
314: * @param layout
315: * the <code>FormLayout</code> to be used
316: *
317: * @deprecated Replaced by {@link #DefaultFormBuilder(FormLayout, JPanel)}.
318: */
319: public DefaultFormBuilder(JPanel panel, FormLayout layout) {
320: this (layout, null, panel);
321: }
322:
323: /**
324: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
325: * panel, layout and resource bundle.
326: *
327: * @param panel
328: * the layout container
329: * @param layout
330: * the <code>FormLayout</code> to be used
331: * @param bundle
332: * the <code>ResourceBundle</code> used to lookup i15d strings
333: *
334: * @deprecated Replaced by
335: * {@link #DefaultFormBuilder(FormLayout, ResourceBundle, JPanel)}.
336: */
337: public DefaultFormBuilder(JPanel panel, FormLayout layout,
338: ResourceBundle bundle) {
339: super (layout, bundle, panel);
340: }
341:
342: // Settings Gap Sizes ***************************************************
343:
344: /**
345: * Returns the row specification that is used to separate component lines.
346: *
347: * @return the <code>RowSpec</code> that is used to separate lines
348: */
349: public RowSpec getLineGapSpec() {
350: return lineGapSpec;
351: }
352:
353: /**
354: * Sets the size of gaps between component lines using the given constant
355: * size.
356: * <p>
357: *
358: * <strong>Examples:</strong>
359: *
360: * <pre>
361: * builder.setLineGapSize(Sizes.ZERO);
362: * builder.setLineGapSize(Sizes.DLUY9);
363: * builder.setLineGapSize(Sizes.pixel(1));
364: * </pre>
365: *
366: * @param lineGapSize
367: * the <code>ConstantSize</code> that describes the size of the
368: * gaps between component lines
369: */
370: public void setLineGapSize(ConstantSize lineGapSize) {
371: RowSpec rowSpec = FormFactory.createGapRowSpec(lineGapSize);
372: this .lineGapSpec = rowSpec;
373: }
374:
375: /**
376: * Sets the size of gaps between paragraphs using the given constant size.
377: * <p>
378: *
379: * <strong>Examples:</strong>
380: *
381: * <pre>
382: * builder.setParagraphGapSize(Sizes.DLUY14);
383: * builder.setParagraphGapSize(Sizes.dluY(22));
384: * builder.setParagraphGapSize(Sizes.pixel(42));
385: * </pre>
386: *
387: * @param paragraphGapSize
388: * the <code>ConstantSize</code> that describes the size of the
389: * gaps between paragraphs
390: */
391: public void setParagraphGapSize(ConstantSize paragraphGapSize) {
392: RowSpec rowSpec = FormFactory
393: .createGapRowSpec(paragraphGapSize);
394: this .paragraphGapSpec = rowSpec;
395: }
396:
397: /**
398: * Returns the offset of the leading column, often 0 or 1.
399: *
400: * @return the offset of the leading column
401: */
402: public int getLeadingColumnOffset() {
403: return leadingColumnOffset;
404: }
405:
406: /**
407: * Sets the offset of the leading column, often 0 or 1.
408: *
409: * @param columnOffset
410: * the new offset of the leading column
411: */
412: public void setLeadingColumnOffset(int columnOffset) {
413: this .leadingColumnOffset = columnOffset;
414: }
415:
416: /**
417: * Returns whether new data rows are being grouped or not.
418: *
419: * @return true indicates grouping enabled, false disabled
420: */
421: public boolean isRowGroupingEnabled() {
422: return rowGroupingEnabled;
423: }
424:
425: /**
426: * Enables or disables the grouping of new data rows.
427: *
428: * @param enabled
429: * indicates grouping enabled, false disabled
430: */
431: public void setRowGroupingEnabled(boolean enabled) {
432: rowGroupingEnabled = enabled;
433: }
434:
435: // Filling Columns ******************************************************
436:
437: /**
438: * Adds a component to the panel using the default constraints with a column
439: * span of 1. Then proceeds to the next data column.
440: *
441: * @param component
442: * the component to add
443: */
444: public void append(Component component) {
445: append(component, 1);
446: }
447:
448: /**
449: * Adds a component to the panel using the default constraints with the
450: * given columnSpan. Proceeds to the next data column.
451: *
452: * @param component
453: * the component to append
454: * @param columnSpan
455: * the column span used to add
456: */
457: public void append(Component component, int columnSpan) {
458: ensureCursorColumnInGrid();
459: ensureHasGapRow(lineGapSpec);
460: ensureHasComponentLine();
461:
462: add(component, createLeftAdjustedConstraints(columnSpan));
463: nextColumn(columnSpan + 1);
464: }
465:
466: /**
467: * Adds two components to the panel; each component will span a single data
468: * column. Proceeds to the next data column.
469: *
470: * @param c1
471: * the first component to add
472: * @param c2
473: * the second component to add
474: */
475: public void append(Component c1, Component c2) {
476: append(c1);
477: append(c2);
478: }
479:
480: /**
481: * Adds three components to the panel; each component will span a single
482: * data column. Proceeds to the next data column.
483: *
484: * @param c1
485: * the first component to add
486: * @param c2
487: * the second component to add
488: * @param c3
489: * the third component to add
490: */
491: public void append(Component c1, Component c2, Component c3) {
492: append(c1);
493: append(c2);
494: append(c3);
495: }
496:
497: // Appending Labels with optional components ------------------------------
498:
499: /**
500: * Adds a text label to the panel and proceeds to the next column.
501: *
502: * @param textWithMnemonic
503: * the label's text - may mark a mnemonic
504: * @return the added label
505: */
506: public JLabel append(String textWithMnemonic) {
507: JLabel label = getComponentFactory().createLabel(
508: textWithMnemonic);
509: append(label);
510: return label;
511: }
512:
513: /**
514: * Adds a text label and component to the panel. Then proceeds to the next
515: * data column.
516: *
517: * @param textWithMnemonic
518: * the label's text - may mark a mnemonic
519: * @param component
520: * the component to add
521: * @return the added label
522: */
523: public JLabel append(String textWithMnemonic, Component component) {
524: return append(textWithMnemonic, component, 1);
525: }
526:
527: /**
528: * Adds a text label and component to the panel; the component will span the
529: * specified number columns. Proceeds to the next data column.
530: * <p>
531: * The created label is labelling the given component; so the component gets
532: * the focus if the (optional) label mnemonic is pressed.
533: *
534: * @param textWithMnemonic
535: * the label's text - may mark a mnemonic
536: * @param c
537: * the component to add
538: * @param columnSpan
539: * number of columns the component shall span
540: * @return the added label
541: * @see JLabel#setLabelFor(java.awt.Component)
542: */
543: public JLabel append(String textWithMnemonic, Component c,
544: int columnSpan) {
545: JLabel label = append(textWithMnemonic);
546: label.setLabelFor(c);
547: append(c, columnSpan);
548: return label;
549: }
550:
551: /**
552: * Adds a text label and two components to the panel; each component will
553: * span a single column. Proceeds to the next data column.
554: *
555: * @param textWithMnemonic
556: * the label's text - may mark a mnemonic
557: * @param c1
558: * the first component to add
559: * @param c2
560: * the second component to add
561: * @return the added label
562: */
563: public JLabel append(String textWithMnemonic, Component c1,
564: Component c2) {
565: JLabel label = append(textWithMnemonic, c1);
566: append(c2);
567: return label;
568: }
569:
570: /**
571: * Adds a text label and two components to the panel; each component will
572: * span a single column. Proceeds to the next data column.
573: *
574: * @param textWithMnemonic
575: * the label's text - may mark a mnemonic
576: * @param c1
577: * the first component to add
578: * @param c2
579: * the second component to add
580: * @param colSpan
581: * the column span for the second component
582: */
583: public void append(String textWithMnemonic, Component c1,
584: Component c2, int colSpan) {
585: append(textWithMnemonic, c1);
586: append(c2, colSpan);
587: }
588:
589: /**
590: * Adds a text label and three components to the panel; each component will
591: * span a single column. Proceeds to the next data column.
592: *
593: * @param textWithMnemonic
594: * the label's text - may mark a mnemonic
595: * @param c1
596: * the first component to add
597: * @param c2
598: * the second component to add
599: * @param c3
600: * the third component to add
601: * @return the added label
602: */
603: public JLabel append(String textWithMnemonic, Component c1,
604: Component c2, Component c3) {
605: JLabel label = append(textWithMnemonic, c1, c2);
606: append(c3);
607: return label;
608: }
609:
610: /**
611: * Adds a text label and four components to the panel; each component will
612: * span a single column. Proceeds to the next data column.
613: *
614: * @param textWithMnemonic
615: * the label's text - may mark a mnemonic
616: * @param c1
617: * the first component to add
618: * @param c2
619: * the second component to add
620: * @param c3
621: * the third component to add
622: * @param c4
623: * the fourth component to add
624: * @return the added label
625: */
626: public JLabel append(String textWithMnemonic, Component c1,
627: Component c2, Component c3, Component c4) {
628: JLabel label = append(textWithMnemonic, c1, c2, c3);
629: append(c4);
630: return label;
631: }
632:
633: // Appending internationalized labels with optional components ------------
634:
635: /**
636: * Adds an internationalized (i15d) text label to the panel using the given
637: * resource key and proceeds to the next column.
638: *
639: * @param resourceKey
640: * the resource key for the the label's text
641: * @return the added label
642: */
643: public JLabel appendI15d(String resourceKey) {
644: return append(getI15dString(resourceKey));
645: }
646:
647: /**
648: * Adds an internationalized (i15d) text label to the panel using the given
649: * resource key; then proceeds to the next data column and adds a component
650: * with the given column span. Proceeds to the next data column.
651: *
652: * @param resourceKey
653: * the resource key for the text to add
654: * @param c
655: * the component to add
656: * @param columnSpan
657: * number of columns the component shall span
658: * @return the added label
659: */
660: public JLabel appendI15d(String resourceKey, Component c,
661: int columnSpan) {
662: JLabel label = appendI15d(resourceKey);
663: append(c, columnSpan);
664: return label;
665: }
666:
667: /**
668: * Adds an internationalized (i15d) text label and component to the panel.
669: * Then proceeds to the next data column.
670: *
671: * @param resourceKey
672: * the resource key for the text to add
673: * @param component
674: * the component to add
675: * @return the added label
676: */
677: public JLabel appendI15d(String resourceKey, Component component) {
678: return appendI15d(resourceKey, component, 1);
679: }
680:
681: /**
682: * Adds an internationalized (i15d) text label and component to the panel.
683: * Then proceeds to the next data column. Goes to the next line if the
684: * boolean flag is set.
685: *
686: * @param resourceKey
687: * the resource key for the text to add
688: * @param component
689: * the component to add
690: * @param nextLine
691: * true forces a next line
692: * @return the added label
693: */
694: public JLabel appendI15d(String resourceKey, Component component,
695: boolean nextLine) {
696: JLabel label = appendI15d(resourceKey, component, 1);
697: if (nextLine) {
698: nextLine();
699: }
700: return label;
701: }
702:
703: /**
704: * Adds an internationalized (i15d) text label and two components to the
705: * panel; each component will span a single column. Proceeds to the next
706: * data column.
707: *
708: * @param resourceKey
709: * the resource key for the text to add
710: * @param c1
711: * the first component to add
712: * @param c2
713: * the second component to add
714: * @return the added label
715: */
716: public JLabel appendI15d(String resourceKey, Component c1,
717: Component c2) {
718: JLabel label = appendI15d(resourceKey, c1);
719: append(c2);
720: return label;
721: }
722:
723: /**
724: * Adds an internationalized (i15d) text label and two components to the
725: * panel; each component will span a single column. Proceeds to the next
726: * data column.
727: *
728: * @param resourceKey
729: * the resource key for the text to add
730: * @param c1
731: * the first component to add
732: * @param c2
733: * the second component to add
734: * @param colSpan
735: * the column span for the second component
736: * @return the added label
737: */
738: public JLabel appendI15d(String resourceKey, Component c1,
739: Component c2, int colSpan) {
740: JLabel label = appendI15d(resourceKey, c1);
741: append(c2, colSpan);
742: return label;
743: }
744:
745: /**
746: * Adds an internationalized (i15d) text label and three components to the
747: * panel; each component will span a single column. Proceeds to the next
748: * data column.
749: *
750: * @param resourceKey
751: * the resource key for the text to add
752: * @param c1
753: * the first component to add
754: * @param c2
755: * the second component to add
756: * @param c3
757: * the third component to add
758: * @return the added label
759: */
760: public JLabel appendI15d(String resourceKey, Component c1,
761: Component c2, Component c3) {
762: JLabel label = appendI15d(resourceKey, c1, c2);
763: append(c3);
764: return label;
765: }
766:
767: /**
768: * Adds an internationalized (i15d) text label and four components to the
769: * panel; each component will span a single column. Proceeds to the next
770: * data column.
771: *
772: * @param resourceKey
773: * the resource key for the text to add
774: * @param c1
775: * the first component to add
776: * @param c2
777: * the second component to add
778: * @param c3
779: * the third component to add
780: * @param c4
781: * the third component to add
782: * @return the added label
783: */
784: public JLabel appendI15d(String resourceKey, Component c1,
785: Component c2, Component c3, Component c4) {
786: JLabel label = appendI15d(resourceKey, c1, c2, c3);
787: append(c4);
788: return label;
789: }
790:
791: // Adding Titles ----------------------------------------------------------
792:
793: /**
794: * Adds a title label to the panel and proceeds to the next column.
795: *
796: * @param textWithMnemonic
797: * the label's text - may mark a mnemonic
798: * @return the added title label
799: */
800: public JLabel appendTitle(String textWithMnemonic) {
801: JLabel titleLabel = getComponentFactory().createTitle(
802: textWithMnemonic);
803: append(titleLabel);
804: return titleLabel;
805: }
806:
807: /**
808: * Adds an internationalized title label to the panel and proceeds to the
809: * next column.
810: *
811: * @param resourceKey
812: * the resource key for the title's text
813: * @return the added title label
814: */
815: public JLabel appendI15dTitle(String resourceKey) {
816: return appendTitle(getI15dString(resourceKey));
817: }
818:
819: // Appending Separators ---------------------------------------------------
820:
821: /**
822: * Adds a separator without text that spans all columns.
823: *
824: * @return the added titled separator
825: */
826: public JComponent appendSeparator() {
827: return appendSeparator("");
828: }
829:
830: /**
831: * Adds a separator with the given text that spans all columns.
832: *
833: * @param text
834: * the separator title text
835: * @return the added titled separator
836: */
837: public JComponent appendSeparator(String text) {
838: ensureCursorColumnInGrid();
839: ensureHasGapRow(paragraphGapSpec);
840: ensureHasComponentLine();
841:
842: setColumn(super .getLeadingColumn());
843: int columnSpan = getColumnCount();
844: setColumnSpan(getColumnCount());
845: JComponent titledSeparator = addSeparator(text);
846: setColumnSpan(1);
847: nextColumn(columnSpan);
848: return titledSeparator;
849: }
850:
851: /**
852: * Appends an internationalized titled separator for the given resource key
853: * that spans all columns.
854: *
855: * @param resourceKey
856: * the resource key for the separator title's text
857: */
858: public void appendI15dSeparator(String resourceKey) {
859: appendSeparator(getI15dString(resourceKey));
860: }
861:
862: // Overriding Superclass Behavior ***************************************
863:
864: /**
865: * Returns the leading column. Unlike the superclass this method honors the
866: * column offset.
867: *
868: * @return the leading column
869: */
870: protected int getLeadingColumn() {
871: int column = super .getLeadingColumn();
872: return column + getLeadingColumnOffset()
873: * getColumnIncrementSign();
874: }
875:
876: // Adding Rows **********************************************************
877:
878: /**
879: * Ensures that the cursor is in the grid. In case it's beyond the form's
880: * right hand side, the cursor is moved to the leading column of the next
881: * line.
882: */
883: private void ensureCursorColumnInGrid() {
884: if ((isLeftToRight() && (getColumn() > getColumnCount()))
885: || (!isLeftToRight() && (getColumn() < 1))) {
886: nextLine();
887: }
888: }
889:
890: /**
891: * Ensures that we have a gap row before the next component row. Checks if
892: * the current row is the given <code>RowSpec</code> and appends this row
893: * spec if necessary.
894: *
895: * @param gapRowSpec
896: * the row specification to check for
897: */
898: private void ensureHasGapRow(RowSpec gapRowSpec) {
899: if ((getRow() == 1) || (getRow() <= getRowCount()))
900: return;
901:
902: if (getRow() <= getRowCount()) {
903: RowSpec rowSpec = getCursorRowSpec();
904: if ((rowSpec == gapRowSpec))
905: return;
906: }
907: appendRow(gapRowSpec);
908: nextLine();
909: }
910:
911: /**
912: * Ensures that the form has a component row. Adds a component row if the
913: * cursor is beyond the form's bottom.
914: */
915: private void ensureHasComponentLine() {
916: if (getRow() <= getRowCount())
917: return;
918: appendRow(FormFactory.PREF_ROWSPEC);
919: if (isRowGroupingEnabled()) {
920: getLayout().addGroupedRow(getRow());
921: }
922: }
923:
924: /**
925: * Looks up and returns the row specification of the current row.
926: *
927: * @return the row specification of the current row
928: */
929: private RowSpec getCursorRowSpec() {
930: return getLayout().getRowSpec(getRow());
931: }
932:
933: }
|