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.awt.ComponentOrientation;
035: import java.awt.Container;
036:
037: import com.jgoodies.forms.factories.FormFactory;
038: import com.jgoodies.forms.layout.CellConstraints;
039: import com.jgoodies.forms.layout.ColumnSpec;
040: import com.jgoodies.forms.layout.FormLayout;
041: import com.jgoodies.forms.layout.RowSpec;
042:
043: /**
044: * An abstract class that minimizes the effort required to implement non-visual
045: * builders that use the {@link FormLayout}.
046: * <p>
047: *
048: * Builders hide details of the FormLayout and provide convenience behavior that
049: * assists you in constructing a form. This class provides a cell cursor that
050: * helps you traverse a form while you add components. Also, it offers several
051: * methods to append custom and logical columns and rows.
052: *
053: * @author Karsten Lentzsch
054: * @version $Revision: 1.2 $
055: *
056: * @see ButtonBarBuilder
057: * @see ButtonStackBuilder
058: * @see PanelBuilder
059: * @see I15dPanelBuilder
060: * @see DefaultFormBuilder
061: */
062: public abstract class AbstractFormBuilder {
063:
064: /**
065: * Holds the layout container that we are building.
066: */
067: private final Container container;
068:
069: /**
070: * Holds the instance of <code>FormLayout</code> that is used to specifiy,
071: * fill and layout this form.
072: */
073: private final FormLayout layout;
074:
075: /**
076: * Holds an instance of <code>CellConstraints</code> that will be used to
077: * specify the location, extent and alignments of the component to be added
078: * next.
079: */
080: private CellConstraints currentCellConstraints;
081:
082: /**
083: * Specifies if we fill the grid from left to right or right to left. This
084: * value is initialized during the construction from the layout container's
085: * component orientation.
086: *
087: * @see #isLeftToRight()
088: * @see #setLeftToRight(boolean)
089: * @see ComponentOrientation
090: */
091: private boolean leftToRight;
092:
093: // Instance Creation ****************************************************
094:
095: /**
096: * Constructs an instance of <code>AbstractFormBuilder</code> for the
097: * given FormLayout and layout container.
098: *
099: * @param layout
100: * the {@link FormLayout} to use
101: * @param container
102: * the layout container
103: *
104: * @throws NullPointerException
105: * if the layout or container is null
106: */
107: public AbstractFormBuilder(FormLayout layout, Container container) {
108: if (layout == null)
109: throw new NullPointerException(
110: "The layout must not be null.");
111:
112: if (container == null)
113: throw new NullPointerException(
114: "The layout container must not be null.");
115:
116: this .container = container;
117: this .layout = layout;
118:
119: container.setLayout(layout);
120: currentCellConstraints = new CellConstraints();
121: ComponentOrientation orientation = container
122: .getComponentOrientation();
123: leftToRight = orientation.isLeftToRight()
124: || !orientation.isHorizontal();
125: }
126:
127: /**
128: * Constructs an instance of <code>AbstractFormBuilder</code> for the
129: * given container and form layout.
130: *
131: * @param container
132: * the layout container
133: * @param layout
134: * the {@link FormLayout} to use
135: *
136: * @deprecated Replaced by
137: * {@link #AbstractFormBuilder(FormLayout, Container)}.
138: */
139: public AbstractFormBuilder(Container container, FormLayout layout) {
140: this (layout, container);
141: }
142:
143: // Accessors ************************************************************
144:
145: /**
146: * Returns the container used to build the form.
147: *
148: * @return the layout container
149: */
150: public final Container getContainer() {
151: return container;
152: }
153:
154: /**
155: * Returns the instance of {@link FormLayout} used to build this form.
156: *
157: * @return the FormLayout
158: */
159: public final FormLayout getLayout() {
160: return layout;
161: }
162:
163: /**
164: * Returns the number of columns in the form.
165: *
166: * @return the number of columns
167: */
168: public final int getColumnCount() {
169: return getLayout().getColumnCount();
170: }
171:
172: /**
173: * Returns the number of rows in the form.
174: *
175: * @return the number of rows
176: */
177: public final int getRowCount() {
178: return getLayout().getRowCount();
179: }
180:
181: // Accessing the Cursor Direction ***************************************
182:
183: /**
184: * Returns whether this builder fills the form left-to-right or
185: * right-to-left. The initial value of this property is set during the
186: * builder construction from the layout container's
187: * <code>componentOrientation</code> property.
188: *
189: * @return true indicates left-to-right, false indicates right-to-left
190: *
191: * @see #setLeftToRight(boolean)
192: * @see ComponentOrientation
193: */
194: public final boolean isLeftToRight() {
195: return leftToRight;
196: }
197:
198: /**
199: * Sets the form fill direction to left-to-right or right-to-left. The
200: * initial value of this property is set during the builder construction
201: * from the layout container's <code>componentOrientation</code> property.
202: *
203: * @param b
204: * true indicates left-to-right, false right-to-left
205: *
206: * @see #isLeftToRight()
207: * @see ComponentOrientation
208: */
209: public final void setLeftToRight(boolean b) {
210: leftToRight = b;
211: }
212:
213: // Accessing the Cursor Location and Extent *****************************
214:
215: /**
216: * Returns the cursor's column.
217: *
218: * @return the cursor's column
219: */
220: public final int getColumn() {
221: return currentCellConstraints.gridX;
222: }
223:
224: /**
225: * Sets the cursor to the given column.
226: *
227: * @param column
228: * the cursor's new column index
229: */
230: public final void setColumn(int column) {
231: currentCellConstraints.gridX = column;
232: }
233:
234: /**
235: * Returns the cursor's row.
236: *
237: * @return the cursor's row
238: */
239: public final int getRow() {
240: return currentCellConstraints.gridY;
241: }
242:
243: /**
244: * Sets the cursor to the given row.
245: *
246: * @param row
247: * the cursor's new row index
248: */
249: public final void setRow(int row) {
250: currentCellConstraints.gridY = row;
251: }
252:
253: /**
254: * Sets the cursor's column span.
255: *
256: * @param columnSpan
257: * the cursor's new column span (grid width)
258: */
259: public final void setColumnSpan(int columnSpan) {
260: currentCellConstraints.gridWidth = columnSpan;
261: }
262:
263: /**
264: * Sets the cursor's row span.
265: *
266: * @param rowSpan
267: * the cursor's new row span (grid height)
268: */
269: public final void setRowSpan(int rowSpan) {
270: currentCellConstraints.gridHeight = rowSpan;
271: }
272:
273: /**
274: * Sets the cursor's origin to the given column and row.
275: *
276: * @param column
277: * the new column index
278: * @param row
279: * the new row index
280: */
281: public final void setOrigin(int column, int row) {
282: setColumn(column);
283: setRow(row);
284: }
285:
286: /**
287: * Sets the cursor's extent to the given column span and row span.
288: *
289: * @param columnSpan
290: * the new column span (grid width)
291: * @param rowSpan
292: * the new row span (grid height)
293: */
294: public final void setExtent(int columnSpan, int rowSpan) {
295: setColumnSpan(columnSpan);
296: setRowSpan(rowSpan);
297: }
298:
299: /**
300: * Sets the cell bounds (location and extent) to the given column, row,
301: * column span and row span.
302: *
303: * @param column
304: * the new column index (grid x)
305: * @param row
306: * the new row index (grid y)
307: * @param columnSpan
308: * the new column span (grid width)
309: * @param rowSpan
310: * the new row span (grid height)
311: */
312: public final void setBounds(int column, int row, int columnSpan,
313: int rowSpan) {
314: setColumn(column);
315: setRow(row);
316: setColumnSpan(columnSpan);
317: setRowSpan(rowSpan);
318: }
319:
320: /**
321: * Moves to the next column, does the same as #nextColumn(1).
322: */
323: public final void nextColumn() {
324: nextColumn(1);
325: }
326:
327: /**
328: * Moves to the next column.
329: *
330: * @param columns
331: * number of columns to move
332: */
333: public final void nextColumn(int columns) {
334: currentCellConstraints.gridX += columns
335: * getColumnIncrementSign();
336: }
337:
338: /**
339: * Increases the row by one; does the same as #nextRow(1).
340: */
341: public final void nextRow() {
342: nextRow(1);
343: }
344:
345: /**
346: * Increases the row by the specified rows.
347: *
348: * @param rows
349: * number of rows to move
350: */
351: public final void nextRow(int rows) {
352: currentCellConstraints.gridY += rows;
353: }
354:
355: /**
356: * Moves to the next line: increases the row and resets the column; does the
357: * same as #nextLine(1).
358: */
359: public final void nextLine() {
360: nextLine(1);
361: }
362:
363: /**
364: * Moves the cursor down several lines: increases the row by the specified
365: * number of lines and sets the cursor to the leading column.
366: *
367: * @param lines
368: * number of rows to move
369: */
370: public final void nextLine(int lines) {
371: nextRow(lines);
372: setColumn(getLeadingColumn());
373: }
374:
375: // Form Constraints Alignment *******************************************
376:
377: /**
378: * Sets the horizontal alignment.
379: *
380: * @param alignment
381: * the new horizontal alignment
382: */
383: public final void setHAlignment(CellConstraints.Alignment alignment) {
384: currentCellConstraints.hAlign = alignment;
385: }
386:
387: /**
388: * Sets the vertical alignment.
389: *
390: * @param alignment
391: * the new vertical alignment
392: */
393: public final void setVAlignment(CellConstraints.Alignment alignment) {
394: currentCellConstraints.vAlign = alignment;
395: }
396:
397: /**
398: * Sets the horizontal and vertical alignment.
399: *
400: * @param hAlign
401: * the new horizontal alignment
402: * @param vAlign
403: * the new vertical alignment
404: */
405: public final void setAlignment(CellConstraints.Alignment hAlign,
406: CellConstraints.Alignment vAlign) {
407: setHAlignment(hAlign);
408: setVAlignment(vAlign);
409: }
410:
411: // Appending Columns ******************************************************
412:
413: /**
414: * Appends the given column specification to the builder's layout.
415: *
416: * @param columnSpec
417: * the column specification object to append
418: *
419: * @see #appendColumn(String)
420: */
421: public final void appendColumn(ColumnSpec columnSpec) {
422: getLayout().appendColumn(columnSpec);
423: }
424:
425: /**
426: * Appends a column specification to the builder's layout that represents
427: * the given string encoding.
428: *
429: * @param encodedColumnSpec
430: * the column specification to append in encoded form
431: *
432: * @see #appendColumn(ColumnSpec)
433: */
434: public final void appendColumn(String encodedColumnSpec) {
435: appendColumn(new ColumnSpec(encodedColumnSpec));
436: }
437:
438: /**
439: * Appends a glue column.
440: *
441: * @see #appendLabelComponentsGapColumn()
442: * @see #appendRelatedComponentsGapColumn()
443: * @see #appendUnrelatedComponentsGapColumn()
444: */
445: public final void appendGlueColumn() {
446: appendColumn(FormFactory.GLUE_COLSPEC);
447: }
448:
449: /**
450: * Appends a column that is the default gap between a label and its
451: * associated component.
452: *
453: * @since 1.0.3
454: *
455: * @see #appendGlueColumn()
456: * @see #appendRelatedComponentsGapColumn()
457: * @see #appendUnrelatedComponentsGapColumn()
458: */
459: public final void appendLabelComponentsGapColumn() {
460: appendColumn(FormFactory.LABEL_COMPONENT_GAP_COLSPEC);
461: }
462:
463: /**
464: * Appends a column that is the default gap for related components.
465: *
466: * @see #appendGlueColumn()
467: * @see #appendLabelComponentsGapColumn()
468: * @see #appendUnrelatedComponentsGapColumn()
469: */
470: public final void appendRelatedComponentsGapColumn() {
471: appendColumn(FormFactory.RELATED_GAP_COLSPEC);
472: }
473:
474: /**
475: * Appends a column that is the default gap for unrelated components.
476: *
477: * @see #appendGlueColumn()
478: * @see #appendLabelComponentsGapColumn()
479: * @see #appendRelatedComponentsGapColumn()
480: */
481: public final void appendUnrelatedComponentsGapColumn() {
482: appendColumn(FormFactory.UNRELATED_GAP_COLSPEC);
483: }
484:
485: // Appending Rows ********************************************************
486:
487: /**
488: * Appends the given row specification to the builder's layout.
489: *
490: * @param rowSpec
491: * the row specification object to append
492: *
493: * @see #appendRow(String)
494: */
495: public final void appendRow(RowSpec rowSpec) {
496: getLayout().appendRow(rowSpec);
497: }
498:
499: /**
500: * Appends a row specification to the builder's layout that represents the
501: * given string encoding.
502: *
503: * @param encodedRowSpec
504: * the row specification to append in encoded form
505: *
506: * @see #appendRow(RowSpec)
507: */
508: public final void appendRow(String encodedRowSpec) {
509: appendRow(new RowSpec(encodedRowSpec));
510: }
511:
512: /**
513: * Appends a glue row.
514: *
515: * @see #appendRelatedComponentsGapRow()
516: * @see #appendUnrelatedComponentsGapRow()
517: * @see #appendParagraphGapRow()
518: */
519: public final void appendGlueRow() {
520: appendRow(FormFactory.GLUE_ROWSPEC);
521: }
522:
523: /**
524: * Appends a row that is the default gap for related components.
525: *
526: * @see #appendGlueRow()
527: * @see #appendUnrelatedComponentsGapRow()
528: * @see #appendParagraphGapRow()
529: */
530: public final void appendRelatedComponentsGapRow() {
531: appendRow(FormFactory.RELATED_GAP_ROWSPEC);
532: }
533:
534: /**
535: * Appends a row that is the default gap for unrelated components.
536: *
537: * @see #appendGlueRow()
538: * @see #appendRelatedComponentsGapRow()
539: * @see #appendParagraphGapRow()
540: */
541: public final void appendUnrelatedComponentsGapRow() {
542: appendRow(FormFactory.UNRELATED_GAP_ROWSPEC);
543: }
544:
545: /**
546: * Appends a row that is the default gap for paragraphs.
547: *
548: * @since 1.0.3
549: *
550: * @see #appendGlueRow()
551: * @see #appendRelatedComponentsGapRow()
552: * @see #appendUnrelatedComponentsGapRow()
553: */
554: public final void appendParagraphGapRow() {
555: appendRow(FormFactory.PARAGRAPH_GAP_ROWSPEC);
556: }
557:
558: // Adding Components ****************************************************
559:
560: /**
561: * Adds a component to the panel using the given cell constraints.
562: *
563: * @param component
564: * the component to add
565: * @param cellConstraints
566: * the component's cell constraints
567: * @return the added component
568: */
569: public final Component add(Component component,
570: CellConstraints cellConstraints) {
571: container.add(component, cellConstraints);
572: return component;
573: }
574:
575: /**
576: * Adds a component to the panel using the given encoded cell constraints.
577: *
578: * @param component
579: * the component to add
580: * @param encodedCellConstraints
581: * the component's encoded cell constraints
582: * @return the added component
583: */
584: public final Component add(Component component,
585: String encodedCellConstraints) {
586: container.add(component, new CellConstraints(
587: encodedCellConstraints));
588: return component;
589: }
590:
591: /**
592: * Adds a component to the container using the default cell constraints.
593: * Note that when building from left to right, this method won't adjust the
594: * cell constraints if the column span is larger than 1. In this case you
595: * should use {@link #add(Component, CellConstraints)} with a cell
596: * constraints object created by {@link #createLeftAdjustedConstraints(int)}.
597: *
598: * @param component
599: * the component to add
600: * @return the added component
601: *
602: * @see #add(Component, CellConstraints)
603: * @see #createLeftAdjustedConstraints(int)
604: */
605: public final Component add(Component component) {
606: add(component, currentCellConstraints);
607: return component;
608: }
609:
610: // Misc *****************************************************************
611:
612: /**
613: * Returns the CellConstraints object that is used as a cursor and holds the
614: * current column span and row span.
615: *
616: * @return the builder's current {@link CellConstraints} object
617: */
618: protected final CellConstraints cellConstraints() {
619: return currentCellConstraints;
620: }
621:
622: /**
623: * Returns the index of the leading column.
624: * <p>
625: *
626: * Subclasses may override this method, for example, if the form has a
627: * leading gap column that should not be filled with components.
628: *
629: * @return the leading column
630: */
631: protected int getLeadingColumn() {
632: return isLeftToRight() ? 1 : getColumnCount();
633: }
634:
635: /**
636: * Returns the sign (-1 or 1) used to increment the cursor's column when
637: * moving to the next column.
638: *
639: * @return -1 for right-to-left, 1 for left-to-right
640: */
641: protected final int getColumnIncrementSign() {
642: return isLeftToRight() ? 1 : -1;
643: }
644:
645: /**
646: * Creates and returns a <code>CellConstraints</code> object at the
647: * current cursor position that uses the given column span and is adjusted
648: * to the left. Useful when building from right to left.
649: *
650: * @param columnSpan
651: * the column span to be used in the constraints
652: * @return CellConstraints adjusted to the left hand side
653: */
654: protected final CellConstraints createLeftAdjustedConstraints(
655: int columnSpan) {
656: int firstColumn = isLeftToRight() ? getColumn() : getColumn()
657: + 1 - columnSpan;
658: return new CellConstraints(firstColumn, getRow(), columnSpan,
659: cellConstraints().gridHeight);
660: }
661:
662: }
|