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
031package com.jgoodies.forms.factories;
032
033import com.jgoodies.forms.layout.ColumnSpec;
034import com.jgoodies.forms.layout.ConstantSize;
035import com.jgoodies.forms.layout.FormLayout;
036import com.jgoodies.forms.layout.FormSpec;
037import com.jgoodies.forms.layout.RowSpec;
038import com.jgoodies.forms.layout.Sizes;
039import com.jgoodies.forms.util.LayoutStyle;
040
041/**
042 * A factory that creates instances of FormLayout for frequently used
043 * form layouts. It makes form creation easier and more consistent.
044 *
045 * <p><strong>I consider removing the <code>FormLayout</code> factory methods.
046 * These seem to be less useful and may lead to poor layout readability.
047 * If you want to use these methods, you may consider copying them
048 * to your codebase.</strong></p>
049 *
050 * <p>The forms are described by major and minor columns. Major columns
051 * consist of a leading label and a set of related components, for example: a
052 * label plus textfield, or label plus textfield plus button. The component
053 * part of a major column is divided into minor columns as shown in this
054 * layout:</p>
055 * <pre>
056 * &lt;-    major column 1        -&gt;  &lt;-     major column 2       -&gt;
057 * label1 textfield1a textfield1b  label2 textfield2a textfield2b
058 * label3 textfield3a textfield3b  label4 textfield4
059 * label5 textfield5               label6 textfield6
060 * </pre>
061 *
062 * <p>Many forms use 1, 2, 3 or 4 major columns, which in turn are often split
063 * into 1, 2, 3 or 4 minor columns.</p>
064 *
065 * @author        Karsten Lentzsch
066 * @version $Revision$
067 *
068 * @see        com.jgoodies.forms.layout.FormLayout
069 * @see        ColumnSpec
070 */
071public final class FormFactory {
072
073    private FormFactory() {
074        // Suppresses default constructor, ensuring non-instantiability.
075    }
076
077    // Frequently used Column Specifications ********************************
078
079    /**
080     * An unmodifyable <code>ColumnSpec</code> that determines its width by
081     * computing the maximum of all column component minimum widths.
082     *
083     * @see #PREF_COLSPEC
084     * @see #DEFAULT_COLSPEC
085     */
086    public static final ColumnSpec MIN_COLSPEC = new ColumnSpec(Sizes.MINIMUM);
087
088    /**
089     * An unmodifyable <code>ColumnSpec</code> that determines its width by
090     * computing the maximum of all column component preferred widths.
091     *
092     * @see #MIN_COLSPEC
093     * @see #DEFAULT_COLSPEC
094     */
095    public static final ColumnSpec PREF_COLSPEC = new ColumnSpec(
096            Sizes.PREFERRED);
097
098    /**
099     * An unmodifyable <code>ColumnSpec</code> that determines its preferred
100     * width by computing the maximum of all column component preferred widths
101     * and its minimum width by computing all column component minimum widths.<p>
102     *
103     * Useful to let a column shrink from preferred width to minimum width
104     * if the container space gets scarce.
105     *
106     * @see #MIN_COLSPEC
107     * @see #PREF_COLSPEC
108     */
109    public static final ColumnSpec DEFAULT_COLSPEC = new ColumnSpec(
110            Sizes.DEFAULT);
111
112    /**
113     * An unmodifyable <code>ColumnSpec</code> that has an initial width
114     * of 0 pixels and that grows. Useful to describe <em>glue</em> columns
115     * that fill the space between other columns.
116     *
117     * @see #GLUE_ROWSPEC
118     */
119    public static final ColumnSpec GLUE_COLSPEC = new ColumnSpec(
120            ColumnSpec.DEFAULT, Sizes.ZERO, FormSpec.DEFAULT_GROW);
121
122    // Layout Style Dependent Column Specs ***********************************
123
124    /**
125     * Describes a logical horizontal gap between a label and an associated
126     * component. Useful for builders that automatically fill a grid with labels
127     * and components.<p>
128     *
129     * <strong>Note:</strong> In a future version this constant will likely
130     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
131     *
132     * @since 1.0.3
133     */
134    public static final ColumnSpec LABEL_COMPONENT_GAP_COLSPEC = createGapColumnSpec(
135            LayoutStyle.getCurrent().getLabelComponentPadX());
136
137    /**
138     * Describes a logical horizontal gap between two related components.
139     * For example the <em>OK</em> and <em>Cancel</em> buttons are considered
140     * related.<p>
141     *
142     * <strong>Note:</strong> In a future version this constant will likely
143     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
144     *
145     * @see #UNRELATED_GAP_COLSPEC
146     */
147    public static final ColumnSpec RELATED_GAP_COLSPEC = createGapColumnSpec(
148            LayoutStyle.getCurrent().getRelatedComponentsPadX());
149
150    /**
151     * Describes a logical horizontal gap between two unrelated components.<p>
152     *
153     * <strong>Note:</strong> In a future version this constant will likely
154     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
155     *
156     * @see #RELATED_GAP_COLSPEC
157     */
158    public static final ColumnSpec UNRELATED_GAP_COLSPEC = createGapColumnSpec(
159            LayoutStyle.getCurrent().getUnrelatedComponentsPadX());
160
161    /**
162     * Describes a logical horizontal column for a fixed size button. This spec
163     * honors the current layout style's default button minimum width.<p>
164     *
165     * <strong>Note:</strong> In a future version this constant will likely
166     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
167     *
168     * @see #GROWING_BUTTON_COLSPEC
169     */
170    public static final ColumnSpec BUTTON_COLSPEC = new ColumnSpec(
171            Sizes.bounded(Sizes.PREFERRED,
172                    LayoutStyle.getCurrent().getDefaultButtonWidth(), null));
173
174    /**
175     * Describes a logical horizontal column for a growing button. This spec
176     * does <em>not</em> use the layout style's default button minimum width.<p>
177     *
178     * <strong>Note:</strong> In a future version this constant will likely
179     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
180     *
181     * @see #BUTTON_COLSPEC
182     */
183    public static final ColumnSpec GROWING_BUTTON_COLSPEC = new ColumnSpec(
184            ColumnSpec.DEFAULT, BUTTON_COLSPEC.getSize(),
185            FormSpec.DEFAULT_GROW);
186
187    // Frequently used Row Specifications ***********************************
188
189    /**
190     * An unmodifyable <code>RowSpec</code> that determines its height by
191     * computing the maximum of all column component minimum heights.
192     *
193     * @see #PREF_ROWSPEC
194     * @see #DEFAULT_ROWSPEC
195     */
196    public static final RowSpec MIN_ROWSPEC = new RowSpec(Sizes.MINIMUM);
197
198    /**
199     * An unmodifyable <code>RowSpec</code> that determines its height by
200     * computing the maximum of all column component preferred heights.
201     *
202     * @see #MIN_ROWSPEC
203     * @see #DEFAULT_ROWSPEC
204     */
205    public static final RowSpec PREF_ROWSPEC = new RowSpec(Sizes.PREFERRED);
206
207    /**
208     * An unmodifyable <code>RowSpec</code> that determines its preferred
209     * height by computing the maximum of all column component preferred heights
210     * and its minimum height by computing all column component minimum heights.<p>
211     *
212     * Useful to let a column shrink from preferred height to minimum height
213     * if the container space gets scarce.
214     *
215     * @see #MIN_COLSPEC
216     * @see #PREF_COLSPEC
217     */
218    public static final RowSpec DEFAULT_ROWSPEC = new RowSpec(Sizes.DEFAULT);
219
220    /**
221     * An unmodifyable <code>RowSpec</code> that has an initial height
222     * of 0 pixels and that grows. Useful to describe <em>glue</em> rows
223     * that fill the space between other rows.
224     *
225     * @see #GLUE_COLSPEC
226     */
227    public static final RowSpec GLUE_ROWSPEC = new RowSpec(RowSpec.DEFAULT,
228            Sizes.ZERO, FormSpec.DEFAULT_GROW);
229
230    // Layout Style Dependent Row Specs *************************************
231
232    /**
233     * Describes a logical vertical gap between two related components.
234     * For example the <em>OK</em> and <em>Cancel</em> buttons are considered
235     * related.<p>
236     *
237     * <strong>Note:</strong> In a future version this constant will likely
238     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
239     *
240     * @see #UNRELATED_GAP_ROWSPEC
241     */
242    public static final RowSpec RELATED_GAP_ROWSPEC = createGapRowSpec(
243            LayoutStyle.getCurrent().getRelatedComponentsPadY());
244
245    /**
246     * Describes a logical vertical gap between two unrelated components.<p>
247     *
248     * <strong>Note:</strong> In a future version this constant will likely
249     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
250     *
251     * @see #RELATED_GAP_ROWSPEC
252     */
253    public static final RowSpec UNRELATED_GAP_ROWSPEC = createGapRowSpec(
254            LayoutStyle.getCurrent().getUnrelatedComponentsPadY());
255
256    /**
257     * Describes a logical vertical narrow gap between two rows in the grid.
258     * Useful if the vertical space is scarce or if an individual vertical gap
259     * shall be small than the default line gap.<p>
260     *
261     * <strong>Note:</strong> In a future version this constant will likely
262     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
263     *
264     * @see #LINE_GAP_ROWSPEC
265     * @see #PARAGRAPH_GAP_ROWSPEC
266     */
267    public static final RowSpec NARROW_LINE_GAP_ROWSPEC = createGapRowSpec(
268            LayoutStyle.getCurrent().getNarrowLinePad());
269
270    /**
271     * Describes the logical vertical default gap between two rows in the grid.
272     * A little bit larger than the narrow line gap.<p>
273     *
274     * <strong>Note:</strong> In a future version this constant will likely
275     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
276     *
277     * @see #NARROW_LINE_GAP_ROWSPEC
278     * @see #PARAGRAPH_GAP_ROWSPEC
279     */
280    public static final RowSpec LINE_GAP_ROWSPEC = createGapRowSpec(
281            LayoutStyle.getCurrent().getLinePad());
282
283    /**
284     * Describes the logical vertical default gap between two paragraphs in
285     * the layout grid. This gap is larger than the default line gap.<p>
286     *
287     * <strong>Note:</strong> In a future version this constant will likely
288     * be moved to a class <code>LogicalSize</code> or <code>StyledSize</code>.
289     *
290     * @see #NARROW_LINE_GAP_ROWSPEC
291     * @see #LINE_GAP_ROWSPEC
292     */
293    public static final RowSpec PARAGRAPH_GAP_ROWSPEC = createGapRowSpec(
294            LayoutStyle.getCurrent().getParagraphPad());
295
296    // Factory Methods ******************************************************
297
298    /**
299     * Creates and returns an instance of <code>FormLayout</code>
300     * to build forms with the specified number of major and minor columns.<p>
301     *
302     * The layout will use default values for all gaps.<p>
303     *
304     * <strong>This method may be removed from a future version.</strong>
305     *
306     * @param majorColumns     the number of used major columns
307     * @param minorColumns     the number of used minor columns
308     * @param labelColumnSpec  specifies the label columns
309     * @return a prepared <code>FormLayout</code>
310     */
311    public static FormLayout createColumnLayout(int majorColumns,
312            int minorColumns, ColumnSpec labelColumnSpec) {
313        return createColumnLayout(majorColumns, minorColumns, labelColumnSpec,
314                Sizes.DLUX14, Sizes.DLUX2);
315    }
316
317    /**
318     * Creates and returns an instance of <code>FormLayout</code>
319     * to build forms with the given number of major columns.
320     * Major columns consists of a label and a component section, where each
321     * component section is divided into the given number of minor columns.<p>
322     *
323     * The layout will use the specified gaps to separate major columns,
324     * and the label and component section.<p>
325     *
326     * <strong>This method may be removed from a future version.</strong>
327     *
328     * @param majorColumns         the number of major columns
329     * @param minorColumns         the number of minor columns
330     * @param labelColumnSpec      specifies the label columns
331     * @param indent               an optional <code>ConstantSize</code>
332     * that describes the width of the leading indent column
333     * @param minorColumnGap       a <code>ConstantSize</code> that describes
334     * the gap between minor columns
335     * @return a prepared <code>FormLayout</code>
336     */
337    public static FormLayout createColumnLayout(int majorColumns,
338            int minorColumns, ColumnSpec labelColumnSpec, ConstantSize indent,
339            ConstantSize minorColumnGap) {
340        return createColumnLayout(majorColumns, minorColumns, labelColumnSpec,
341                PREF_COLSPEC, indent, Sizes.DLUX14, minorColumnGap);
342    }
343
344    /**
345     * Creates and returns an instance of <code>FormLayout</code>
346     * to build forms with the given number of major columns.
347     * Major columns consists of a label and a component section, where each
348     * component section is divided into the given number of minor columns.<p>
349     *
350     * The layout will use the specified gaps to separate major columns,
351     * minor columns, and the label and component section.<p>
352     *
353     * <strong>This method may be removed from a future version.</strong>
354     *
355     * @param majorColumns         the number of major columns
356     * @param minorColumns         the number of minor columns
357     * @param labelColumnSpec      specifies the label columns
358     * @param componentColumnSpec  specifies the label columns
359     * @param indent               an optional <code>ConstantSize</code>
360     * that describes the width of the leading indent column
361     * @param majorColumnGap       a <code>ConstantSize</code> that describes
362     * the gap between major columns
363     * @param minorColumnGap       a <code>ConstantSize</code> that describes
364     * the gap between minor columns
365     * @return a prepared <code>FormLayout</code>
366     */
367    public static FormLayout createColumnLayout(int majorColumns,
368            int minorColumns, ColumnSpec labelColumnSpec,
369            ColumnSpec componentColumnSpec, ConstantSize indent,
370            ConstantSize majorColumnGap, ConstantSize minorColumnGap) {
371
372        ColumnSpec majorGapColSpec = createGapColumnSpec(majorColumnGap);
373        ColumnSpec minorGapColSpec = createGapColumnSpec(minorColumnGap);
374        FormLayout layout = new FormLayout(new ColumnSpec[] {},
375                new RowSpec[] {});
376
377        // Add the optional leading indent.
378        if (indent != null) {
379            layout.appendColumn(createGapColumnSpec(indent));
380        }
381        for (int i = 0; i < majorColumns; i++) {
382            // Add the optional label column with gap.
383            if (labelColumnSpec != null) {
384                layout.appendColumn(labelColumnSpec);
385                layout.appendColumn(RELATED_GAP_COLSPEC);
386            }
387            // Add the minor columns with separating gaps.
388            for (int j = 0; j < minorColumns; j++) {
389                layout.appendColumn(componentColumnSpec);
390                layout.addGroupedColumn(layout.getColumnCount());
391                if (j < minorColumns - 1) {
392                    layout.appendColumn(minorGapColSpec);
393                }
394            }
395            // Add a gap between major columns.
396            if (i < majorColumns - 1) {
397                layout.appendColumn(majorGapColSpec);
398            }
399        }
400        return layout;
401    }
402
403    // Helper Code **********************************************************
404
405    /**
406     * Creates and returns a {@link ColumnSpec} that represents a gap with the
407     * specified {@link ConstantSize}.
408     *
409     * @param gapSize        a <code>ConstantSize</code> that specifies the gap
410     * @return a <code>ColumnSpec</code> that describes a horizontal gap
411     */
412    public static ColumnSpec createGapColumnSpec(ConstantSize gapSize) {
413        return new ColumnSpec(ColumnSpec.LEFT, gapSize, FormSpec.NO_GROW);
414    }
415
416    /**
417     * Creates and returns a {@link RowSpec} that represents a gap with the
418     * specified {@link ConstantSize}.
419     *
420     * @param gapSize   a <code>ConstantSize</code> that specifies the gap
421     * @return a <code>RowSpec</code> that describes a vertical gap
422     */
423    public static RowSpec createGapRowSpec(ConstantSize gapSize) {
424        return new RowSpec(RowSpec.TOP, gapSize, FormSpec.NO_GROW);
425    }
426
427}