001: /*
002: * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.forms.builder;
032:
033: import javax.swing.JButton;
034: import javax.swing.JComponent;
035: import javax.swing.JPanel;
036:
037: import com.jgoodies.forms.factories.Borders;
038: import com.jgoodies.forms.factories.FormFactory;
039: import com.jgoodies.forms.layout.ColumnSpec;
040: import com.jgoodies.forms.layout.ConstantSize;
041: import com.jgoodies.forms.layout.FormLayout;
042: import com.jgoodies.forms.layout.RowSpec;
043: import com.jgoodies.forms.util.LayoutStyle;
044:
045: /**
046: * A non-visual builder that assists you in building consistent button bars
047: * that comply with popular UI style guides. It utilizes the {@link FormLayout}.
048: * This class is in turn used by the
049: * {@link com.jgoodies.forms.factories.ButtonBarFactory} that provides
050: * an even higher level of abstraction for building consistent button bars.<p>
051: *
052: * Buttons added to the builder are either gridded or fixed and may fill
053: * their FormLayout cell or not. All gridded buttons get the same width,
054: * while fixed buttons use their own size. Gridded buttons honor
055: * the default minimum button width as specified by the current
056: * {@link com.jgoodies.forms.util.LayoutStyle}.<p>
057: *
058: * You can set an optional hint for narrow margin for the fixed width buttons.
059: * This is useful if you want to lay out a button bar that includes a button
060: * with a long text. For example, in a bar with
061: * 'Copy to Clipboard', 'OK', 'Cancel' you may declare the clipboard button
062: * as a fixed size button with narrow margins, OK and Cancel as gridded.
063: * Gridded buttons are marked as narrow by default.
064: * Note that some look&feels do not support the narrow margin feature,
065: * and conversely, others have only narrow margins. The JGoodies look&feels
066: * honor the setting, the Mac Aqua l&f uses narrow margins all the time.<p>
067: *
068: * To honor the platform's button order (left-to-right vs. right-to-left)
069: * this builder uses the <em>leftToRightButtonOrder</em> property.
070: * It is initialized with the current LayoutStyle's button order,
071: * which in turn is left-to-right on most platforms and right-to-left
072: * on the Mac OS X. Builder methods that create sequences of buttons
073: * (e.g. {@link #addGriddedButtons(JButton[])} honor the button order.
074: * If you want to ignore the default button order, you can either
075: * add add individual buttons, or create a ButtonBarBuilder instance
076: * with the order set to left-to-right. For the latter see
077: * {@link #createLeftToRightBuilder()}. Also see the button order
078: * example below.<p>
079: *
080: * <strong>Example:</strong><br>
081: * The following example builds a button bar with <i>Help</i> button on the
082: * left-hand side and <i>OK, Cancel, Apply</i> buttons on the right-hand side.
083: * <pre>
084: * private JPanel createHelpOKCancelApplyBar(
085: * JButton help, JButton ok, JButton cancel, JButton apply) {
086: * ButtonBarBuilder builder = new ButtonBarBuilder();
087: * builder.addGridded(help);
088: * builder.addRelatedGap();
089: * builder.addGlue();
090: * builder.addGriddedButtons(new JButton[]{ok, cancel, apply});
091: * return builder.getPanel();
092: * }
093: * </pre><p>
094: *
095: * <strong>Button Order Example:</strong><br>
096: * The following example builds three button bars where one honors
097: * the platform's button order and the other two ignore it.
098: * <pre>
099: * public JComponent buildPanel() {
100: * FormLayout layout = new FormLayout("pref");
101: * DefaultFormBuilder rowBuilder = new DefaultFormBuilder(layout);
102: * rowBuilder.setDefaultDialogBorder();
103: *
104: * rowBuilder.append(buildButtonSequence(new ButtonBarBuilder()));
105: * rowBuilder.append(buildButtonSequence(ButtonBarBuilder.createLeftToRightBuilder()));
106: * rowBuilder.append(buildIndividualButtons(new ButtonBarBuilder()));
107: *
108: * return rowBuilder.getPanel();
109: * }
110: *
111: * private Component buildButtonSequence(ButtonBarBuilder builder) {
112: * builder.addGriddedButtons(new JButton[] {
113: * new JButton("One"),
114: * new JButton("Two"),
115: * new JButton("Three")
116: * });
117: * return builder.getPanel();
118: * }
119: *
120: * private Component buildIndividualButtons(ButtonBarBuilder builder) {
121: * builder.addGridded(new JButton("One"));
122: * builder.addRelatedGap();
123: * builder.addGridded(new JButton("Two"));
124: * builder.addRelatedGap();
125: * builder.addGridded(new JButton("Three"));
126: * return builder.getPanel();
127: * }
128: * </pre>
129: *
130: * @author Karsten Lentzsch
131: * @version $Revision: 1.3 $
132: *
133: * @see ButtonStackBuilder
134: * @see com.jgoodies.forms.factories.ButtonBarFactory
135: * @see com.jgoodies.forms.util.LayoutStyle
136: */
137: public final class ButtonBarBuilder extends PanelBuilder {
138:
139: /**
140: * Specifies the columns of the initial FormLayout used in constructors.
141: */
142: private static final ColumnSpec[] COL_SPECS = new ColumnSpec[] {};
143:
144: /**
145: * Specifies the FormLayout's the single button bar row.
146: */
147: private static final RowSpec[] ROW_SPECS = new RowSpec[] { new RowSpec(
148: "center:pref") };
149:
150: /**
151: * The client property key used to indicate that a button shall
152: * get narrow margins on the left and right hand side.<p>
153: *
154: * This optional setting will be honored by all JGoodies Look&Feel
155: * implementations. The Mac Aqua l&f uses narrow margins only.
156: * Other look&feel implementations will likely ignore this key
157: * and so may render a wider button margin.
158: */
159: private static final String NARROW_KEY = "jgoodies.isNarrow";
160:
161: /**
162: * Describes how sequences of buttons are added to the button bar:
163: * left-to-right or right-to-left. This setting is initialized using
164: * the current {@link LayoutStyle}'s button order. It is honored
165: * only by builder methods that build sequences of button, for example
166: * {@link #addGriddedButtons(JButton[])}, and ignored if you add
167: * individual button, for example using {@link #addGridded(JComponent)}.
168: *
169: * @see #isLeftToRight()
170: * @see #setLeftToRight(boolean)
171: * @see #addGriddedButtons(JButton[])
172: * @see #addGriddedGrowingButtons(JButton[])
173: */
174: private boolean leftToRight;
175:
176: // Instance Creation ****************************************************
177:
178: /**
179: * Constructs an instance of <code>ButtonBarBuilder</code> on a
180: * <code>JPanel</code> using a preconfigured FormLayout as layout manager.
181: */
182: public ButtonBarBuilder() {
183: this (new JPanel(null));
184: }
185:
186: /**
187: * Constructs an instance of <code>ButtonBarBuilder</code> on the given
188: * panel using a preconfigured FormLayout as layout manager.
189: *
190: * @param panel the layout container
191: */
192: public ButtonBarBuilder(JPanel panel) {
193: super (new FormLayout(COL_SPECS, ROW_SPECS), panel);
194: leftToRight = LayoutStyle.getCurrent()
195: .isLeftToRightButtonOrder();
196: }
197:
198: /**
199: * Creates and returns a <code>ButtonBarBuilder</code> with
200: * initialized with a left to right button order.
201: *
202: * @return a button bar builder with button order set to left-to-right
203: */
204: public static ButtonBarBuilder createLeftToRightBuilder() {
205: ButtonBarBuilder builder = new ButtonBarBuilder();
206: builder.setLeftToRightButtonOrder(true);
207: return builder;
208: }
209:
210: // Accessing Properties *************************************************
211:
212: /**
213: * Returns whether button sequences will be ordered from
214: * left to right or from right to left.
215: *
216: * @return true if button sequences are ordered from left to right
217: * @since 1.0.3
218: *
219: * @see LayoutStyle#isLeftToRightButtonOrder()
220: */
221: public boolean isLeftToRightButtonOrder() {
222: return leftToRight;
223: }
224:
225: /**
226: * Sets the order for button sequences to either left to right,
227: * or right to left.
228: *
229: * @param newButtonOrder true if button sequences shall be ordered
230: * from left to right
231: * @since 1.0.3
232: *
233: * @see LayoutStyle#isLeftToRightButtonOrder()
234: */
235: public void setLeftToRightButtonOrder(boolean newButtonOrder) {
236: leftToRight = newButtonOrder;
237: }
238:
239: // Default Borders ******************************************************
240:
241: /**
242: * Sets a default border that has a gap in the bar's north.
243: */
244: public void setDefaultButtonBarGapBorder() {
245: getPanel().setBorder(Borders.BUTTON_BAR_GAP_BORDER);
246: }
247:
248: // Adding Components ****************************************************
249:
250: /**
251: * Adds a sequence of related gridded buttons each separated by
252: * a default gap. Honors this builder's button order. If you
253: * want to use a fixed left to right order, add individual buttons.
254: *
255: * @param buttons an array of buttons to add
256: *
257: * @see LayoutStyle
258: */
259: public void addGriddedButtons(JButton[] buttons) {
260: int length = buttons.length;
261: for (int i = 0; i < length; i++) {
262: int index = leftToRight ? i : length - 1 - i;
263: addGridded(buttons[index]);
264: if (i < buttons.length - 1)
265: addRelatedGap();
266: }
267: }
268:
269: /**
270: * Adds a sequence of gridded buttons that grow
271: * where each is separated by a default gap.
272: * Honors this builder's button order. If you
273: * want to use a fixed left to right order,
274: * add individual buttons.
275: *
276: * @param buttons an array of buttons to add
277: *
278: * @see LayoutStyle
279: */
280: public void addGriddedGrowingButtons(JButton[] buttons) {
281: int length = buttons.length;
282: for (int i = 0; i < length; i++) {
283: int index = leftToRight ? i : length - 1 - i;
284: addGriddedGrowing(buttons[index]);
285: if (i < buttons.length - 1)
286: addRelatedGap();
287: }
288: }
289:
290: /**
291: * Adds a fixed size component. Unlike the gridded components,
292: * this component keeps its individual preferred dimension.
293: *
294: * @param component the component to add
295: */
296: public void addFixed(JComponent component) {
297: getLayout().appendColumn(FormFactory.PREF_COLSPEC);
298: add(component);
299: nextColumn();
300: }
301:
302: /**
303: * Adds a fixed size component with narrow margins. Unlike the gridded
304: * components, this component keeps its individual preferred dimension.
305: *
306: * @param component the component to add
307: */
308: public void addFixedNarrow(JComponent component) {
309: component.putClientProperty(NARROW_KEY, Boolean.TRUE);
310: addFixed(component);
311: }
312:
313: /**
314: * Adds a gridded component, i.e. a component that will get
315: * the same dimension as all other gridded components.
316: *
317: * @param component the component to add
318: */
319: public void addGridded(JComponent component) {
320: getLayout().appendColumn(FormFactory.BUTTON_COLSPEC);
321: getLayout().addGroupedColumn(getColumn());
322: component.putClientProperty(NARROW_KEY, Boolean.TRUE);
323: add(component);
324: nextColumn();
325: }
326:
327: /**
328: * Adds a gridded component that grows. The component's initial size
329: * (before it grows) is the same as for all other gridded components.
330: *
331: * @param component the component to add
332: */
333: public void addGriddedGrowing(JComponent component) {
334: getLayout().appendColumn(FormFactory.GROWING_BUTTON_COLSPEC);
335: getLayout().addGroupedColumn(getColumn());
336: component.putClientProperty(NARROW_KEY, Boolean.TRUE);
337: add(component);
338: nextColumn();
339: }
340:
341: /**
342: * Adds a glue that will be given the extra space,
343: * if this box is larger than its preferred size.
344: */
345: public void addGlue() {
346: appendGlueColumn();
347: nextColumn();
348: }
349:
350: /**
351: * Adds the standard gap for related components.
352: */
353: public void addRelatedGap() {
354: appendRelatedComponentsGapColumn();
355: nextColumn();
356: }
357:
358: /**
359: * Adds the standard gap for unrelated components.
360: */
361: public void addUnrelatedGap() {
362: appendUnrelatedComponentsGapColumn();
363: nextColumn();
364: }
365:
366: /**
367: * Adds a strut of a specified size.
368: *
369: * @param size a <code>ConstantSize</code> that describes the gap's size
370: */
371: public void addStrut(ConstantSize size) {
372: getLayout().appendColumn(
373: new ColumnSpec(ColumnSpec.LEFT, size,
374: ColumnSpec.NO_GROW));
375: nextColumn();
376: }
377:
378: }
|