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 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 that
047: * 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 an even
050: * higher level of abstraction for building consistent button bars.
051: * <p>
052: *
053: * Buttons added to the builder are either gridded or fixed and may fill their
054: * FormLayout cell or not. All gridded buttons get the same width, while fixed
055: * buttons use their own size. Gridded buttons honor the default minimum button
056: * width as specified by the current {@link com.jgoodies.forms.util.LayoutStyle}.
057: * <p>
058: *
059: * You can set an optional hint for narrow margin for the fixed width buttons.
060: * This is useful if you want to lay out a button bar that includes a button
061: * with a long text. For example, in a bar with 'Copy to Clipboard', 'OK',
062: * 'Cancel' you may declare the clipboard button as a fixed size button with
063: * narrow margins, OK and Cancel as gridded. Gridded buttons are marked as
064: * narrow by default. Note that some look&feels do not support the narrow
065: * margin feature, and conversely, others have only narrow margins. The JGoodies
066: * look&feels honor the setting, the Mac Aqua l&f uses narrow margins
067: * all the time.
068: * <p>
069: *
070: * To honor the platform's button order (left-to-right vs. right-to-left) this
071: * builder uses the <em>leftToRightButtonOrder</em> property. It is
072: * initialized with the current LayoutStyle's button order, which in turn is
073: * left-to-right on most platforms and right-to-left on the Mac OS X. Builder
074: * methods that create sequences of buttons (e.g.
075: * {@link #addGriddedButtons(JButton[])} honor the button order. If you want to
076: * ignore the default button order, you can either add add individual buttons,
077: * or create a ButtonBarBuilder instance with the order set to left-to-right.
078: * For the latter see {@link #createLeftToRightBuilder()}. Also see the button
079: * order example below.
080: * <p>
081: *
082: * <strong>Example:</strong><br>
083: * The following example builds a button bar with <i>Help</i> button on the
084: * left-hand side and <i>OK, Cancel, Apply</i> buttons on the right-hand side.
085: *
086: * <pre>
087: * private JPanel createHelpOKCancelApplyBar(JButton help, JButton ok, JButton cancel, JButton apply) {
088: * ButtonBarBuilder builder = new ButtonBarBuilder();
089: * builder.addGridded(help);
090: * builder.addRelatedGap();
091: * builder.addGlue();
092: * builder.addGriddedButtons(new JButton[] { ok, cancel, apply });
093: * return builder.getPanel();
094: * }
095: * </pre>
096: *
097: * <p>
098: *
099: * <strong>Button Order Example:</strong><br>
100: * The following example builds three button bars where one honors the
101: * platform's button order and the other two ignore it.
102: *
103: * <pre>
104: * public JComponent buildPanel() {
105: * FormLayout layout = new FormLayout("pref");
106: * DefaultFormBuilder rowBuilder = new DefaultFormBuilder(layout);
107: * rowBuilder.setDefaultDialogBorder();
108: *
109: * rowBuilder.append(buildButtonSequence(new ButtonBarBuilder()));
110: * rowBuilder.append(buildButtonSequence(ButtonBarBuilder.createLeftToRightBuilder()));
111: * rowBuilder.append(buildIndividualButtons(new ButtonBarBuilder()));
112: *
113: * return rowBuilder.getPanel();
114: * }
115: *
116: * private Component buildButtonSequence(ButtonBarBuilder builder) {
117: * builder.addGriddedButtons(new JButton[] { new JButton("One"), new JButton("Two"), new JButton("Three") });
118: * return builder.getPanel();
119: * }
120: *
121: * private Component buildIndividualButtons(ButtonBarBuilder builder) {
122: * builder.addGridded(new JButton("One"));
123: * builder.addRelatedGap();
124: * builder.addGridded(new JButton("Two"));
125: * builder.addRelatedGap();
126: * builder.addGridded(new JButton("Three"));
127: * return builder.getPanel();
128: * }
129: * </pre>
130: *
131: * @author Karsten Lentzsch
132: * @version $Revision: 1.2 $
133: *
134: * @see ButtonStackBuilder
135: * @see com.jgoodies.forms.factories.ButtonBarFactory
136: * @see com.jgoodies.forms.util.LayoutStyle
137: */
138: public final class ButtonBarBuilder extends PanelBuilder {
139:
140: /**
141: * Specifies the columns of the initial FormLayout used in constructors.
142: */
143: private static final ColumnSpec[] COL_SPECS = new ColumnSpec[] {};
144:
145: /**
146: * Specifies the FormLayout's the single button bar row.
147: */
148: private static final RowSpec[] ROW_SPECS = new RowSpec[] { new RowSpec(
149: "center:pref") };
150:
151: /**
152: * The client property key used to indicate that a button shall get narrow
153: * margins on the left and right hand side.
154: * <p>
155: *
156: * This optional setting will be honored by all JGoodies Look&Feel
157: * implementations. The Mac Aqua l&f uses narrow margins only. Other
158: * look&feel implementations will likely ignore this key and so may
159: * render a wider button margin.
160: */
161: private static final String NARROW_KEY = "jgoodies.isNarrow";
162:
163: /**
164: * Describes how sequences of buttons are added to the button bar:
165: * left-to-right or right-to-left. This setting is initialized using the
166: * current {@link LayoutStyle}'s button order. It is honored only by
167: * builder methods that build sequences of button, for example
168: * {@link #addGriddedButtons(JButton[])}, and ignored if you add individual
169: * button, for example using {@link #addGridded(JButton)}.
170: *
171: * @see #isLeftToRight()
172: * @see #setLeftToRight(boolean)
173: * @see #addGriddedButtons(JButton[])
174: * @see #addGriddedGrowingButtons(JButton[])
175: */
176: private boolean leftToRight;
177:
178: // Instance Creation ****************************************************
179:
180: /**
181: * Constructs an instance of <code>ButtonBarBuilder</code> on a
182: * <code>JPanel</code> using a preconfigured FormLayout as layout manager.
183: */
184: public ButtonBarBuilder() {
185: this (new JPanel(null));
186: }
187:
188: /**
189: * Constructs an instance of <code>ButtonBarBuilder</code> on the given
190: * panel using a preconfigured FormLayout as layout manager.
191: *
192: * @param panel
193: * the layout container
194: */
195: public ButtonBarBuilder(JPanel panel) {
196: super (new FormLayout(COL_SPECS, ROW_SPECS), panel);
197: leftToRight = LayoutStyle.getCurrent()
198: .isLeftToRightButtonOrder();
199: }
200:
201: /**
202: * Creates and returns a <code>ButtonBarBuilder</code> with initialized
203: * with a left to right button order.
204: *
205: * @return a button bar builder with button order set to left-to-right
206: */
207: public static ButtonBarBuilder createLeftToRightBuilder() {
208: ButtonBarBuilder builder = new ButtonBarBuilder();
209: builder.setLeftToRightButtonOrder(true);
210: return builder;
211: }
212:
213: // Accessing Properties *************************************************
214:
215: /**
216: * Returns whether button sequences will be ordered from left to right or
217: * from right to left.
218: *
219: * @return true if button sequences are ordered from left to right
220: * @since 1.0.3
221: *
222: * @see LayoutStyle#isLeftToRightButtonOrder()
223: */
224: public boolean isLeftToRightButtonOrder() {
225: return leftToRight;
226: }
227:
228: /**
229: * Sets the order for button sequences to either left to right, or right to
230: * left.
231: *
232: * @param newButtonOrder
233: * true if button sequences shall be ordered from left to right
234: * @since 1.0.3
235: *
236: * @see LayoutStyle#isLeftToRightButtonOrder()
237: */
238: public void setLeftToRightButtonOrder(boolean newButtonOrder) {
239: leftToRight = newButtonOrder;
240: }
241:
242: // Default Borders ******************************************************
243:
244: /**
245: * Sets a default border that has a gap in the bar's north.
246: */
247: public void setDefaultButtonBarGapBorder() {
248: getPanel().setBorder(Borders.BUTTON_BAR_GAP_BORDER);
249: }
250:
251: // Adding Components ****************************************************
252:
253: /**
254: * Adds a sequence of related gridded buttons each separated by a default
255: * gap. Honors this builder's button order. If you want to use a fixed left
256: * to right order, add individual buttons.
257: *
258: * @param buttons
259: * an array of buttons to add
260: *
261: * @see LayoutStyle
262: */
263: public void addGriddedButtons(JButton[] buttons) {
264: int length = buttons.length;
265: for (int i = 0; i < length; i++) {
266: int index = leftToRight ? i : length - 1 - i;
267: addGridded(buttons[index]);
268: if (i < buttons.length - 1)
269: addRelatedGap();
270: }
271: }
272:
273: /**
274: * Adds a sequence of gridded buttons that grow where each is separated by a
275: * default gap. Honors this builder's button order. If you want to use a
276: * fixed left to right order, add individual buttons.
277: *
278: * @param buttons
279: * an array of buttons to add
280: *
281: * @see LayoutStyle
282: */
283: public void addGriddedGrowingButtons(JButton[] buttons) {
284: int length = buttons.length;
285: for (int i = 0; i < length; i++) {
286: int index = leftToRight ? i : length - 1 - i;
287: addGriddedGrowing(buttons[index]);
288: if (i < buttons.length - 1)
289: addRelatedGap();
290: }
291: }
292:
293: /**
294: * Adds a fixed size component. Unlike the gridded components, this
295: * component keeps its individual preferred dimension.
296: *
297: * @param component
298: * the component to add
299: */
300: public void addFixed(JComponent component) {
301: getLayout().appendColumn(FormFactory.PREF_COLSPEC);
302: add(component);
303: nextColumn();
304: }
305:
306: /**
307: * Adds a fixed size component with narrow margins. Unlike the gridded
308: * components, this component keeps its individual preferred dimension.
309: *
310: * @param component
311: * the component to add
312: */
313: public void addFixedNarrow(JComponent component) {
314: component.putClientProperty(NARROW_KEY, Boolean.TRUE);
315: addFixed(component);
316: }
317:
318: /**
319: * Adds a gridded component, i.e. a component that will get the same
320: * dimension as all other gridded components.
321: *
322: * @param component
323: * the component to add
324: */
325: public void addGridded(JComponent component) {
326: getLayout().appendColumn(FormFactory.BUTTON_COLSPEC);
327: getLayout().addGroupedColumn(getColumn());
328: component.putClientProperty(NARROW_KEY, Boolean.TRUE);
329: add(component);
330: nextColumn();
331: }
332:
333: /**
334: * Adds a gridded component that grows. The component's initial size (before
335: * it grows) is the same as for all other gridded components.
336: *
337: * @param component
338: * the component to add
339: */
340: public void addGriddedGrowing(JComponent component) {
341: getLayout().appendColumn(FormFactory.GROWING_BUTTON_COLSPEC);
342: getLayout().addGroupedColumn(getColumn());
343: component.putClientProperty(NARROW_KEY, Boolean.TRUE);
344: add(component);
345: nextColumn();
346: }
347:
348: /**
349: * Adds a glue that will be given the extra space, if this box is larger
350: * than its preferred size.
351: */
352: public void addGlue() {
353: appendGlueColumn();
354: nextColumn();
355: }
356:
357: /**
358: * Adds the standard gap for related components.
359: */
360: public void addRelatedGap() {
361: appendRelatedComponentsGapColumn();
362: nextColumn();
363: }
364:
365: /**
366: * Adds the standard gap for unrelated components.
367: */
368: public void addUnrelatedGap() {
369: appendUnrelatedComponentsGapColumn();
370: nextColumn();
371: }
372:
373: /**
374: * Adds a strut of a specified size.
375: *
376: * @param size
377: * a <code>ConstantSize</code> that describes the gap's size
378: */
379: public void addStrut(ConstantSize size) {
380: getLayout().appendColumn(
381: new ColumnSpec(ColumnSpec.LEFT, size,
382: ColumnSpec.NO_GROW));
383: nextColumn();
384: }
385:
386: }
|