001: /*
002: * Copyright (c) 2003 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: */package net.sourceforge.squirrel_sql.client.gui.builders;
030:
031: import java.awt.Component;
032: import java.util.ResourceBundle;
033:
034: import javax.swing.JComponent;
035: import javax.swing.JLabel;
036: import javax.swing.JPanel;
037: import com.jgoodies.forms.factories.FormFactory;
038: import com.jgoodies.forms.layout.ConstantSize;
039: import com.jgoodies.forms.layout.FormLayout;
040: import com.jgoodies.forms.layout.RowSpec;
041:
042: /** * Provides a means to build consistent form-oriented panels quickly
043: * using the {@link FormLayout}. This builder combines frequently used
044: * panel building steps: add a new row, add a label, proceed to the next
045: * data column, then add a component.
046: * <p>
047: * This builder can map resource keys to internationalized (i15d) texts
048: * when creating text labels, titles and titled separators. Therefore
049: * you must specify a <code>ResourceBundle</code> in the constructor.
050: * The builder methods throw an <code>IllegalStateException</code>
051: * if one of the mapping builder methods is invoked and no bundle has been set.
052: * <p>
053: * This class is not yet part of the binary Forms library;
054: * it comes with the Forms distributions as an extra.
055: * <b>The API is work in progress and may change without notice.</b>
056: * If you want to use this class, you may consider copying it into your codebase.
057: * <p>
058: * <b>Example:</b>
059: * <pre>
060: * public void build() {
061: * FormLayout layout = new FormLayout(
062: * "right:max(40dlu;pref), 3dlu, 80dlu, 7dlu, " // 1st major colum
063: * + "right:max(40dlu;pref), 3dlu, 80dlu", // 2nd major column
064: * ""); // add rows dynamically
065: * DefaultFormBuilder builder = new DefaultFormBuilder(layout);
066: * builder.setDefaultDialogBorder();
067: *
068: * builder.appendSeparator("Flange");
069: *
070: * builder.append("Identifier", identifierField);
071: * builder.nextLine();
072: *
073: * builder.append("PTI [kW]", new JTextField());
074: * builder.append("Power [kW]", new JTextField());
075: *
076: * builder.append("s [mm]", new JTextField());
077: * builder.nextLine();
078: *
079: * builder.appendSeparator("Diameters");
080: *
081: * builder.append("da [mm]", new JTextField());
082: * builder.append("di [mm]", new JTextField());
083: *
084: * builder.append("da2 [mm]", new JTextField());
085: * builder.append("di2 [mm]", new JTextField());
086: *
087: * builder.append("R [mm]", new JTextField());
088: * builder.append("D [mm]", new JTextField());
089: *
090: * builder.appendSeparator("Criteria");
091: *
092: * builder.append("Location", buildLocationComboBox());
093: * builder.append("k-factor", new JTextField());
094: *
095: * builder.appendSeparator("Bolts");
096: *
097: * builder.append("Material", ViewerUIFactory.buildMaterialComboBox());
098: * builder.nextLine();
099: *
100: * builder.append("Numbers", new JTextField());
101: * builder.nextLine();
102: *
103: * builder.append("ds [mm]", new JTextField());
104: * }
105: * </pre>
106: *
107: * @author Karsten Lentzsch
108: * @see com.jgoodies.forms.builder.AbstractFormBuilder
109: * @see com.jgoodies.forms.factories.FormFactory
110: * @see com.jgoodies.forms.layout.FormLayout
111: */
112: public final class DefaultFormBuilder extends I15dPanelBuilder {
113: /**
114: * Holds the row specification that is reused to describe
115: * the constant gaps between component lines.
116: */
117: private RowSpec lineGapSpec = FormFactory.LINE_GAP_ROWSPEC;
118: /**
119: * Holds the row specification that describes the constant gaps
120: * between paragraphs.
121: */
122: private RowSpec paragraphGapSpec = FormFactory.PARAGRAPH_GAP_ROWSPEC;
123: /**
124: * Holds the offset of the leading column - often 0 or 1.
125: */
126: private int leadingColumnOffset = 0;
127: /**
128: * Determines wether new data rows are being grouped or not.
129: */
130: private boolean rowGroupingEnabled = false;
131:
132: // Instance Creation ****************************************************
133: /** * Constructs an instance of <code>DefaultFormBuilder</code> for the given
134: * layout.
135: *
136: * @param layout the <code>FormLayout</code> to be used
137: */
138: public DefaultFormBuilder(FormLayout layout) {
139: this (new JPanel(), layout);
140: }
141:
142: /**
143: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
144: * panel and layout.
145: *
146: * @param panel the layout container
147: * @param layout the <code>FormLayout</code> to be used
148: */
149: public DefaultFormBuilder(JPanel panel, FormLayout layout) {
150: this (panel, layout, null);
151: }
152:
153: /**
154: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
155: * layout and resource bundle.
156: *
157: * @param layout the <code>FormLayout</code> to be used
158: * @param bundle the <code>ResourceBundle</code> used to lookup i15d
159: * strings
160: */
161: public DefaultFormBuilder(FormLayout layout, ResourceBundle bundle) {
162: this (new JPanel(), layout, bundle);
163: }
164:
165: /**
166: * Constructs an instance of <code>DefaultFormBuilder</code> for the given
167: * panel, layout and resource bundle.
168: *
169: * @param panel the layout container
170: * @param layout the <code>FormLayout</code> to be used
171: * @param bundle the <code>ResourceBundle</code> used to lookup i15d
172: * strings
173: */
174: public DefaultFormBuilder(JPanel panel, FormLayout layout,
175: ResourceBundle bundle) {
176: super (panel, layout, bundle);
177: }
178:
179: // Settings Gap Sizes ***************************************************
180: /**
181: * Sets the size of gaps between component lines using the given
182: * constant size.
183: *
184: * @param lineGapSize the <coide>ConstantSize</code> that describes
185: * the size of the gaps between component lines
186: */
187: public void setLineGapSize(ConstantSize lineGapSize) {
188: RowSpec rowSpec = FormFactory.createGapRowSpec(lineGapSize);
189: this .lineGapSpec = rowSpec.asUnmodifyable();
190: }
191:
192: /**
193: * Returns the row specification that is used to separate component lines.
194: *
195: * @return the <code>RowSpec</code> that is used to separate lines
196: */
197: public RowSpec getLineGapSpec() {
198: return lineGapSpec;
199: }
200:
201: /**
202: * Sets the size of gaps between paragraphs using the given
203: * constant size.
204: *
205: * @param paragraphGapSize the <coide>ConstantSize</code> that describes
206: * the size of the gaps between paragraphs
207: */
208: public void setParagraphGapSize(ConstantSize paragraphGapSize) {
209: RowSpec rowSpec = FormFactory
210: .createGapRowSpec(paragraphGapSize);
211: this .paragraphGapSpec = rowSpec.asUnmodifyable();
212: }
213:
214: /**
215: * Returns the offset of the leading column, often 0 or 1.
216: *
217: * @return the offset of the leading column
218: */
219: public int getLeadingColumnOffset() {
220: return leadingColumnOffset;
221: }
222:
223: /**
224: * Sets the offset of the leading column, often 0 or 1.
225: *
226: * @param columnOffset the new offset of the leading column
227: */
228: public void setLeadingColumnOffset(int columnOffset) {
229: this .leadingColumnOffset = columnOffset;
230: }
231:
232: /**
233: * Returns whether new data rows are being grouped or not.
234: *
235: * @return true indicates grouping enabled, false disabled
236: */
237: public boolean isRowGroupingEnabled() {
238: return rowGroupingEnabled;
239: }
240:
241: /**
242: * Enables or disables the grouping of new data rows.
243: *
244: * @param enabled indicates grouping enabled, false disabled
245: */
246: public void setRowGroupingEnabled(boolean enabled) {
247: rowGroupingEnabled = enabled;
248: }
249:
250: // Filling Columns ******************************************************
251: /**
252: * Adds a component to the panel using the default constraints.
253: * Proceeds to the next data column.
254: *
255: * @param component the component to add
256: */
257: public void append(Component component) {
258: append(component, 1);
259: }
260:
261: /**
262: * Adds a component to the panel using the default constraints with
263: * the given columnSpan. Proceeds to the next data column.
264: *
265: * @param component the component to append
266: * @param columnSpan the column span used to add
267: */
268: public void append(Component component, int columnSpan) {
269: ensureCursorColumnInGrid();
270: ensureHasGapRow(lineGapSpec);
271: ensureHasComponentLine();
272: setColumnSpan(columnSpan);
273: add(component);
274: setColumnSpan(1);
275: nextColumn(columnSpan + 1);
276: }
277:
278: /**
279: * Adds two components to the panel; each component will span a single
280: * data column. Proceeds to the next data column.
281: *
282: * @param c1 the first component to add
283: * @param c2 the second component to add
284: */
285: public void append(Component c1, Component c2) {
286: append(c1);
287: append(c2);
288: }
289:
290: /**
291: * Adds three components to the panel; each component will span a single
292: * data column. Proceeds to the next data column.
293: *
294: * @param c1 the first component to add
295: * @param c2 the second component to add
296: * @param c3 the third component to add
297: */
298: public void append(Component c1, Component c2, Component c3) {
299: append(c1);
300: append(c2);
301: append(c3);
302: }
303:
304: // Appending Labels with optional components ------------------------------
305: /**
306: * Adds a text label to the panel and proceeds to the next column.
307: *
308: * @param textWithMnemonic the label's text - may mark a mnemonic
309: * @return the added label
310: */
311: public JLabel append(String textWithMnemonic) {
312: JLabel label = getComponentFactory().createLabel(
313: textWithMnemonic);
314: append(label);
315: return label;
316: }
317:
318: /**
319: * Adds a text label and component to the panel.
320: * Then proceeds to the next data column.
321: *
322: * @param textWithMnemonic the label's text - may mark a mnemonic
323: * @param component the component to add
324: * @return the added label
325: */
326: public JLabel append(String textWithMnemonic, Component component) {
327: return append(textWithMnemonic, component, 1);
328: }
329:
330: /**
331: * Adds a text label and component to the panel; the component will span
332: * the specified number columns. Proceeds to the next data column.
333: * <p>
334: * The created label is labelling the given component; so the component
335: * gets the focus if the (optional) label mnemonic is pressed.
336: *
337: * @param textWithMnemonic the label's text - may mark a mnemonic
338: * @param c the component to add
339: * @param columnSpan number of columns the component shall span
340: * @return the added label
341: * @see JLabel#setLabelFor
342: */
343: public JLabel append(String textWithMnemonic, Component c,
344: int columnSpan) {
345: JLabel label = append(textWithMnemonic);
346: label.setLabelFor(c);
347: append(c, columnSpan);
348: return label;
349: }
350:
351: /**
352: * Adds a text label and two components to the panel; each component
353: * will span a single column. Proceeds to the next data column.
354: *
355: * @param textWithMnemonic the label's text - may mark a mnemonic
356: * @param c1 the first component to add
357: * @param c2 the second component to add
358: * @return the added label
359: */
360: public JLabel append(String textWithMnemonic, Component c1,
361: Component c2) {
362: JLabel label = append(textWithMnemonic, c1);
363: append(c2);
364: return label;
365: }
366:
367: /**
368: * Adds a text label and two components to the panel; each component
369: * will span a single column. Proceeds to the next data column.
370: *
371: * @param textWithMnemonic the label's text - may mark a mnemonic
372: * @param c1 the first component to add
373: * @param c2 the second component to add
374: * @param colSpan the column span for the second component
375: */
376: public void append(String textWithMnemonic, Component c1,
377: Component c2, int colSpan) {
378: append(textWithMnemonic, c1);
379: append(c2, colSpan);
380: }
381:
382: /**
383: * Adds a text label and three components to the panel; each component
384: * will span a single column. Proceeds to the next data column.
385: *
386: * @param textWithMnemonic the label's text - may mark a mnemonic
387: * @param c1 the first component to add
388: * @param c2 the second component to add
389: * @param c3 the third component to add
390: * @return the added label
391: */
392: public JLabel append(String textWithMnemonic, Component c1,
393: Component c2, Component c3) {
394: JLabel label = append(textWithMnemonic, c1, c2);
395: append(c3);
396: return label;
397: }
398:
399: /**
400: * Adds a text label and four components to the panel; each component
401: * will span a single column. Proceeds to the next data column.
402: *
403: * @param textWithMnemonic the label's text - may mark a mnemonic
404: * @param c1 the first component to add
405: * @param c2 the second component to add
406: * @param c3 the third component to add
407: * @param c4 the fourth component to add
408: * @return the added label
409: */
410: public JLabel append(String textWithMnemonic, Component c1,
411: Component c2, Component c3, Component c4) {
412: JLabel label = append(textWithMnemonic, c1, c2, c3);
413: append(c4);
414: return label;
415: }
416:
417: // Appending internationalized labels with optional components ------------
418: /**
419: * Adds an internationalized (i15d) text label to the panel using
420: * the given resource key and proceeds to the next column.
421: *
422: * @param resourceKey the resource key for the the label's text
423: * @return the added label
424: */
425: public JLabel appendI15d(String resourceKey) {
426: return append(getI15dString(resourceKey));
427: }
428:
429: /**
430: * Adds an internationalized (i15d) text label to the panel using the given resource key;
431: * then proceeds to the next data column and adds a component with
432: * the given column span. Proceeds to the next data column.
433: *
434: * @param resourceKey the resource key for the text to add
435: * @param c the component to add
436: * @param columnSpan number of columns the component shall span
437: * @return the added label
438: */
439: public JLabel appendI15d(String resourceKey, Component c,
440: int columnSpan) {
441: JLabel label = appendI15d(resourceKey);
442: append(c, columnSpan);
443: return label;
444: }
445:
446: /**
447: * Adds an internationalized (i15d) text label and component to the panel.
448: * Then proceeds to the next data column.
449: *
450: * @param resourceKey the resource key for the text to add
451: * @param component the component to add
452: * @return the added label
453: */
454: public JLabel appendI15d(String resourceKey, Component component) {
455: return appendI15d(resourceKey, component, 1);
456: }
457:
458: /**
459: * Adds an internationalized (i15d) text label and component to the panel.
460: * Then proceeds to the next data column.
461: * Goes to the next line if the boolean flag is set.
462: *
463: * @param resourceKey the resource key for the text to add
464: * @param component the component to add
465: * @param nextLine true forces a next line
466: * @return the added label
467: */
468: public JLabel appendI15d(String resourceKey, Component component,
469: boolean nextLine) {
470: JLabel label = appendI15d(resourceKey, component, 1);
471: if (nextLine) {
472: nextLine();
473: }
474: return label;
475: }
476:
477: /**
478: * Adds an internationalized (i15d) text label and two components to the panel; each component
479: * will span a single column. Proceeds to the next data column.
480: *
481: * @param resourceKey the resource key for the text to add
482: * @param c1 the first component to add
483: * @param c2 the second component to add
484: * @return the added label
485: */
486: public JLabel appendI15d(String resourceKey, Component c1,
487: Component c2) {
488: JLabel label = appendI15d(resourceKey, c1);
489: append(c2);
490: return label;
491: }
492:
493: /**
494: * Adds an internationalized (i15d) text label and two components to the panel; each component
495: * will span a single column. Proceeds to the next data column.
496: *
497: * @param resourceKey the resource key for the text to add
498: * @param c1 the first component to add
499: * @param c2 the second component to add
500: * @param colSpan the column span for the second component
501: * @return the added label
502: */
503: public JLabel appendI15d(String resourceKey, Component c1,
504: Component c2, int colSpan) {
505: JLabel label = appendI15d(resourceKey, c1);
506: append(c2, colSpan);
507: return label;
508: }
509:
510: /**
511: * Adds an internationalized (i15d) text label and three components to the panel; each component
512: * will span a single column. Proceeds to the next data column.
513: *
514: * @param resourceKey the resource key for the text to add
515: * @param c1 the first component to add
516: * @param c2 the second component to add
517: * @param c3 the third component to add
518: * @return the added label
519: */
520: public JLabel appendI15d(String resourceKey, Component c1,
521: Component c2, Component c3) {
522: JLabel label = appendI15d(resourceKey, c1, c2);
523: append(c3);
524: return label;
525: }
526:
527: /**
528: * Adds an internationalized (i15d) text label and four components to the panel;
529: * each component will span a single column. Proceeds to the next data column.
530: *
531: * @param resourceKey the resource key for the text to add
532: * @param c1 the first component to add
533: * @param c2 the second component to add
534: * @param c3 the third component to add
535: * @param c4 the third component to add
536: * @return the added label
537: */
538: public JLabel appendI15d(String resourceKey, Component c1,
539: Component c2, Component c3, Component c4) {
540: JLabel label = appendI15d(resourceKey, c1, c2, c3);
541: append(c4);
542: return label;
543: }
544:
545: // Adding Titles ----------------------------------------------------------
546: /**
547: * Adds a title label to the panel and proceeds to the next column.
548: *
549: * @param textWithMnemonic the label's text - may mark a mnemonic
550: * @return the added title label
551: */
552: public JLabel appendTitle(String textWithMnemonic) {
553: JLabel titleLabel = getComponentFactory().createTitle(
554: textWithMnemonic);
555: append(titleLabel);
556: return titleLabel;
557: }
558:
559: /**
560: * Adds an internationalized title label to the panel and
561: * proceeds to the next column.
562: *
563: * @param resourceKey the resource key for the title's text
564: * @return the added title label
565: */
566: public JLabel appendI15dTitle(String resourceKey) {
567: return appendTitle(getI15dString(resourceKey));
568: }
569:
570: // Appending Separators ---------------------------------------------------
571: /**
572: * Adds a separator without text that spans all columns.
573: *
574: * @return the added titled separator
575: */
576: public JComponent appendSeparator() {
577: return appendSeparator("");
578: }
579:
580: /**
581: * Adds a separator with the given text that spans all columns.
582: *
583: * @param text the separator title text
584: * @return the added titled separator
585: */
586: public JComponent appendSeparator(String text) {
587: ensureCursorColumnInGrid();
588: ensureHasGapRow(paragraphGapSpec);
589: ensureHasComponentLine();
590: setColumn(super .getLeadingColumn());
591: int columnSpan = getColumnCount();
592: setColumnSpan(getColumnCount());
593: JComponent titledSeparator = addSeparator(text);
594: setColumnSpan(1);
595: nextColumn(columnSpan);
596: return titledSeparator;
597: }
598:
599: /**
600: * Appends an internationalized titled separator for
601: * the given resource key that spans all columns.
602: *
603: * @param resourceKey the resource key for the separator title's text
604: */
605: public void appendI15dSeparator(String resourceKey) {
606: appendSeparator(getI15dString(resourceKey));
607: }
608:
609: // Overriding Superclass Behavior ***************************************
610: /**
611: * Returns the leading column. Unlike the superclass we take a
612: * column offset into account.
613: *
614: * @return the leading column
615: */
616: protected int getLeadingColumn() {
617: int column = super .getLeadingColumn();
618: return column + getLeadingColumnOffset()
619: * getColumnIncrementSign();
620: }
621:
622: // Adding Rows **********************************************************
623: /**
624: * Ensures that the cursor is in the grid. In case it's beyond the
625: * form's right hand side, the cursor is moved to the leading column
626: * of the next line.
627: */
628: private void ensureCursorColumnInGrid() {
629: if (getColumn() > getColumnCount()) {
630: nextLine();
631: }
632: }
633:
634: /**
635: * Ensures that we have a gap row before the next component row.
636: * Checks if the current row is the given <code>RowSpec</code>
637: * and appends this row spec if necessary.
638: *
639: * @param gapRowSpec the row specification to check for
640: */
641: private void ensureHasGapRow(RowSpec gapRowSpec) {
642: if ((getRow() == 1) || (getRow() <= getRowCount()))
643: return;
644: if (getRow() <= getRowCount()) {
645: RowSpec rowSpec = getCursorRowSpec();
646: if ((rowSpec == gapRowSpec))
647: return;
648: }
649: appendRow(gapRowSpec);
650: nextLine();
651: }
652:
653: /**
654: * Ensures that the form has a component row. Adds a component row
655: * if the cursor is beyond the form's bottom.
656: */
657: private void ensureHasComponentLine() {
658: if (getRow() <= getRowCount())
659: return;
660: appendRow(FormFactory.PREF_ROWSPEC);
661: if (isRowGroupingEnabled()) {
662: getLayout().addGroupedRow(getRow());
663: }
664: }
665:
666: /**
667: * Looks up and answers the row specification of the current row.
668: *
669: * @return the row specification of the current row
670: */
671: private RowSpec getCursorRowSpec() {
672: return getLayout().getRowSpec(getRow());
673: }
674: }
|