2
* Copyright (c) 2002-2008 JGoodies Karsten Lentzsch. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of JGoodies Karsten Lentzsch nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
package com.jgoodies.forms.builder;
33
import javax.swing.Action;
34
import javax.swing.JButton;
35
import javax.swing.JComponent;
36
import javax.swing.JPanel;
38
import com.jgoodies.forms.factories.Borders;
39
import com.jgoodies.forms.factories.FormFactory;
40
import com.jgoodies.forms.layout.ColumnSpec;
41
import com.jgoodies.forms.layout.ConstantSize;
42
import com.jgoodies.forms.layout.FormLayout;
43
import com.jgoodies.forms.layout.RowSpec;
44
import com.jgoodies.forms.util.LayoutStyle;
47
* A non-visual builder for building consistent button bars that comply
48
* with popular style guides. Utilizes the JGoodies {@link FormLayout}
49
* and honors the platform's {@link LayoutStyle} regarding button sizes,
50
* gap widths, and the default button order.<p>
52
* This is an improved version of the older {@link ButtonBarBuilder}.
53
* The ButtonBarBuilder2 has a simpler, safer, and more convenient API,
54
* see below for a comparison.<p>
56
* <strong>ButtonBarBuilder2 vs. ButtonBarBuilder:</strong><br>
57
* ButtonBarBuilder2 uses only 3 component types that can be added:
58
* <em>button</em>, <em>standard</em>, and <em>growing button</em>, where
59
* ButtonBarBuilder has <em>button</em>, <em>fixed</em>, and <em>growing</em>.
60
* Also, the ButtonBarBuilder2 doesn't group buttons.
61
* The layout of the ButtonBarBuilder and ButtonBarBuilder2 is the same
62
* if all buttons are smaller than {@link LayoutStyle#getDefaultButtonWidth()}.
63
* If some buttons are wider, ButtonBarBuilder2 will make only these buttons
64
* wider, where the old ButtonBarBuilder makes all (gridded) buttons wider.
67
* <strong>Examples:</strong><pre>
68
* // Build a right-aligned bar for: OK, Cancel, Apply
69
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
71
* builder.addButton(okButton);
72
* builder.addRelatedGap();
73
* builder.addButton(cancelButton);
74
* builder.addRelatedGap();
75
* builder.addButton(applyButton);
76
* return builder.getPanel();
78
* // Add a sequence of related buttons
79
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
81
* builder.addButton(okButton, cancelButton, applyButton);
82
* return builder.getPanel();
84
* // Add a sequence of related buttons for given Actions
85
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
87
* builder.addButton(okAction, cancelAction, applyAction);
88
* return builder.getPanel();
91
* Buttons are added to a builder individually or as a sequence.
93
* To honor the platform's button order (left-to-right vs. right-to-left)
94
* this builder uses the <em>leftToRightButtonOrder</em> property.
95
* It is initialized with the current LayoutStyle's button order,
96
* which in turn is left-to-right on most platforms and right-to-left
97
* on the Mac OS X. Builder methods that create sequences of buttons
98
* (e.g. {@link #addButton(JComponent[])} honor the button order.
99
* If you want to ignore the default button order, you can either
100
* add individual buttons, or create a ButtonBarBuilder2 instance
101
* with the order set to left-to-right. For the latter see
102
* {@link #createLeftToRightBuilder()}. Also see the button order
105
* <strong>Example:</strong><br>
106
* The following example builds a button bar with <i>Help</i> button on the
107
* left-hand side and <i>OK, Cancel, Apply</i> buttons on the right-hand side.
109
* private JPanel createHelpOKCancelApplyBar(
110
* JButton help, JButton ok, JButton cancel, JButton apply) {
111
* ButtonBarBuilder2 builder = new ButtonBarBuilder2();
112
* builder.addButton(help);
113
* builder.addUnrelatedGap();
115
* builder.addButton(new JButton[]{ok, cancel, apply});
116
* return builder.getPanel();
120
* <strong>Button Order Example:</strong><br>
121
* The following example builds three button bars where one honors
122
* the platform's button order and the other two ignore it.
124
* public JComponent buildPanel() {
125
* FormLayout layout = new FormLayout("pref");
126
* DefaultFormBuilder rowBuilder = new DefaultFormBuilder(layout);
127
* rowBuilder.setDefaultDialogBorder();
129
* rowBuilder.append(buildButtonSequence(new ButtonBarBuilder2()));
130
* rowBuilder.append(buildButtonSequence(ButtonBarBuilder2.createLeftToRightBuilder()));
131
* rowBuilder.append(buildIndividualButtons(new ButtonBarBuilder2()));
133
* return rowBuilder.getPanel();
136
* private Component buildButtonSequence(ButtonBarBuilder2 builder) {
137
* builder.addButton(new JButton[] {
138
* new JButton("One"),
139
* new JButton("Two"),
140
* new JButton("Three")
142
* return builder.getPanel();
145
* private Component buildIndividualButtons(ButtonBarBuilder2 builder) {
146
* builder.addButton(new JButton("One"));
147
* builder.addRelatedGap();
148
* builder.addButton(new JButton("Two"));
149
* builder.addRelatedGap();
150
* builder.addButton(new JButton("Three"));
151
* return builder.getPanel();
155
* @author Karsten Lentzsch
156
* @version $Revision: 1.9 $
158
* @see ButtonStackBuilder
159
* @see com.jgoodies.forms.factories.ButtonBarFactory
160
* @see com.jgoodies.forms.util.LayoutStyle
162
public class ButtonBarBuilder2 extends AbstractButtonPanelBuilder {
165
* Specifies the columns of the initial FormLayout used in constructors.
167
private static final ColumnSpec[] COL_SPECS =
171
* Specifies the FormLayout's the single button bar row.
173
private static final RowSpec[] ROW_SPECS =
174
new RowSpec[]{ RowSpec.decode("center:pref") };
178
* The client property key used to indicate that a button shall
179
* get narrow margins on the left and right hand side.<p>
181
* This optional setting will be honored by all JGoodies Look&Feel
182
* implementations. The Mac Aqua l&f uses narrow margins only.
183
* Other look&feel implementations will likely ignore this key
184
* and so may render a wider button margin.
186
private static final String NARROW_KEY = "jgoodies.isNarrow";
190
* Describes how sequences of buttons are added to the button bar:
191
* left-to-right or right-to-left. This setting is initialized using
192
* the current {@link LayoutStyle}'s button order. It is honored
193
* only by builder methods that build sequences of button, for example
194
* {@link #addButton(JComponent[])}, and ignored if you add
195
* individual button, for example using {@link #addButton(JComponent)}.
197
* @see #isLeftToRight()
198
* @see #setLeftToRight(boolean)
199
* @see #addGrowing(JComponent[])
201
private boolean leftToRight;
204
// Instance Creation ****************************************************
207
* Constructs an empty ButtonBarBuilder2 on a JPanel.
209
public ButtonBarBuilder2() {
210
this(new JPanel(null));
215
* Constructs an empty ButtonBarBuilder2 on the given panel.
217
* @param panel the layout container
219
public ButtonBarBuilder2(JPanel panel) {
220
super(new FormLayout(COL_SPECS, ROW_SPECS), panel);
221
leftToRight = LayoutStyle.getCurrent().isLeftToRightButtonOrder();
227
* Creates and returns a ButtonBarBuilder2 with
228
* a left to right button order.
230
* @return a button bar builder with button order set to left-to-right
232
public static ButtonBarBuilder2 createLeftToRightBuilder() {
233
ButtonBarBuilder2 builder = new ButtonBarBuilder2();
234
builder.setLeftToRightButtonOrder(true);
239
// Accessing Properties *************************************************
242
* Returns whether button sequences will be ordered from
243
* left to right or from right to left.
245
* @return true if button sequences are ordered from left to right
247
* @see LayoutStyle#isLeftToRightButtonOrder()
249
public boolean isLeftToRightButtonOrder() {
255
* Sets the order for button sequences to either left to right,
258
* @param newButtonOrder true if button sequences shall be ordered
261
* @see LayoutStyle#isLeftToRightButtonOrder()
263
public void setLeftToRightButtonOrder(boolean newButtonOrder) {
264
leftToRight = newButtonOrder;
268
// Default Borders ******************************************************
271
* Sets a default border that has a gap in the bar's north.
273
public void setDefaultButtonBarGapBorder() {
274
setBorder(Borders.BUTTON_BAR_GAP_BORDER);
278
// Spacing ****************************************************************
281
* Adds a glue that will be given the extra space,
282
* if this button bar is larger than its preferred size.
284
public void addGlue() {
291
* Adds the standard horizontal gap for related components.
293
* @see LayoutStyle#getRelatedComponentsPadX()
295
public void addRelatedGap() {
296
appendRelatedComponentsGapColumn();
302
* Adds the standard horizontal gap for unrelated components.
304
* @see LayoutStyle#getUnrelatedComponentsPadX()
306
public void addUnrelatedGap() {
307
appendUnrelatedComponentsGapColumn();
313
* Adds a horizontal strut of the specified width.
314
* For related and unrelated components use {@link #addRelatedGap()}
315
* and {@link #addUnrelatedGap()} respectively.
317
* @param width describes the gap width
319
* @see ColumnSpec#createGap(ConstantSize)
321
public void addStrut(ConstantSize width) {
322
getLayout().appendColumn(ColumnSpec.createGap(width));
328
* Adds a command button component that has a minimum width
329
* specified by the {@link LayoutStyle#getDefaultButtonWidth()}.<p>
331
* Although a JButton is expected, any JComponent is accepted
332
* to allow custom button component types.
334
* @param button the component to add
336
* @throws NullPointerException if {@code button} is {@code null}
338
public void addButton(JComponent button) {
339
button.putClientProperty(NARROW_KEY, Boolean.TRUE);
340
getLayout().appendColumn(FormFactory.BUTTON_COLSPEC);
347
* Adds a sequence of related button components.
348
* Each button has the minimum width as specified by
349
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
350
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
352
* This method is equivalent to
353
* <code>addButton(new JComponent[]{button1, button2});</code>
355
* @param button1 the first button to add
356
* @param button2 the second button to add
358
* @throws NullPointerException if a button is {@code null}
360
* @see #addButton(JComponent[])
362
public void addButton(
364
JComponent button2) {
365
addButton(new JComponent[]{button1, button2});
370
* Adds a sequence of related button components.
371
* Each button has the minimum width as specified by
372
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
373
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
375
* This method is equivalent to
376
* <code>addButton(new JComponent[]{button1, button2, button3});</code>
378
* @param button1 the first button to add
379
* @param button2 the second button to add
380
* @param button3 the third button to add
382
* @throws NullPointerException if a button is {@code null}
384
* @see #addButton(JComponent[])
386
public void addButton(
389
JComponent button3) {
390
addButton(new JComponent[]{button1, button2, button3});
395
* Adds a sequence of related button components.
396
* Each button has the minimum width as specified by
397
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
398
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
400
* This method is equivalent to
401
* <code>addButton(new JComponent[]{button1, button2, button3, button4});</code>
403
* @param button1 the first button to add
404
* @param button2 the second button to add
405
* @param button3 the third button to add
406
* @param button4 the fourth button to add
408
* @throws NullPointerException if a button is {@code null}
410
* @see #addButton(JComponent[])
412
public void addButton(
416
JComponent button4) {
417
addButton(new JComponent[]{button1, button2, button3, button4});
422
* Adds a sequence of related button components.
423
* Each button has the minimum width as specified by
424
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
425
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
427
* This method is equivalent to
428
* <code>addButton(new JComponent[]{button1, button2, button3, button4, button5});</code>
430
* @param button1 the first button to add
431
* @param button2 the second button to add
432
* @param button3 the third button to add
433
* @param button4 the fourth button to add
434
* @param button5 the fifth button to add
436
* @throws NullPointerException if a button is {@code null}
438
* @see #addButton(JComponent[])
440
public void addButton(
445
JComponent button5) {
446
addButton(new JComponent[]{button1, button2, button3, button4, button5});
451
* Adds a sequence of related button components.
452
* Each button has the minimum width as specified by
453
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
454
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
456
* Uses this builder's button order (left-to-right vs. right-to-left).
457
* If you want to use a fixed order, add individual buttons instead.<p>
459
* Although JButtons are expected, general JComponents are accepted
460
* to allow custom button component types.
462
* @param buttons an array of buttons to add
464
* @throws NullPointerException if the button array or a button is {@code null}
465
* @throws IllegalArgumentException if the button array is empty
467
* @see #addButton(JComponent)
469
public void addButton(JComponent[] buttons) {
471
throw new NullPointerException("The button array must not be null.");
472
int length = buttons.length;
474
throw new IllegalArgumentException("The button array must not be empty.");
475
for (int i = 0; i < length; i++) {
476
int index = leftToRight ? i : length -1 - i;
477
addButton(buttons[index]);
478
if (i < buttons.length - 1)
485
* Adds a JButton for the given Action that has a minimum width
486
* specified by the {@link LayoutStyle#getDefaultButtonWidth()}.
488
* @param action the action that describes the button to add
490
* @throws NullPointerException if {@code action} is {@code null}
492
* @see #addButton(JComponent)
494
public void addButton(Action action) {
496
throw new NullPointerException("The button Action must not be null.");
497
addButton(new JButton(action));
502
* Adds a sequence of related JButtons built from the given Actions.
503
* Each button has the minimum width as specified by
504
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
505
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
507
* This method is equivalent to
508
* <code>addButton(new Action[]{action1, action2});</code>
510
* @param action1 describes the first button to add
511
* @param action2 describes the second button to add
513
* @throws NullPointerException if an Action is {@code null}
515
* @see #addButton(Action[])
516
* @see #addButton(JComponent[])
518
public void addButton(
521
addButton(new Action[]{action1, action2});
526
* Adds a sequence of related JButtons built from the given Actions.
527
* Each button has the minimum width as specified by
528
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
529
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
531
* This method is equivalent to
532
* <code>addButton(new Action[]{action1, action2, action3});</code>
534
* @param action1 describes the first button to add
535
* @param action2 describes the second button to add
536
* @param action3 describes the third button to add
538
* @throws NullPointerException if an Action is {@code null}
540
* @see #addButton(Action[])
541
* @see #addButton(JComponent[])
543
public void addButton(
547
addButton(new Action[]{action1, action2, action3});
552
* Adds a sequence of related JButtons built from the given Actions.
553
* Each button has the minimum width as specified by
554
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
555
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
557
* This method is equivalent to
558
* <code>addButton(new Action[]{action1, action2, action3, action4});</code>
560
* @param action1 describes the first button to add
561
* @param action2 describes the second button to add
562
* @param action3 describes the third button to add
563
* @param action4 describes the fourth button to add
565
* @throws NullPointerException if an Action is {@code null}
567
* @see #addButton(Action[])
568
* @see #addButton(JComponent[])
570
public void addButton(
575
addButton(new Action[]{action1, action2, action3, action4});
580
* Adds a sequence of related JButtons built from the given Actions.
581
* Each button has the minimum width as specified by
582
* {@link LayoutStyle#getDefaultButtonWidth()}. The gap width between
583
* the buttons is {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
585
* This method is equivalent to
586
* <code>addButton(new Action[]{action1, action2, action3, action4, action5});</code>
588
* @param action1 describes the first button to add
589
* @param action2 describes the second button to add
590
* @param action3 describes the third button to add
591
* @param action4 describes the fourth button to add
592
* @param action5 describes the fifth button to add
594
* @throws NullPointerException if an Action is {@code null}
596
* @see #addButton(Action[])
597
* @see #addButton(JComponent[])
599
public void addButton(
605
addButton(new Action[]{action1, action2, action3, action4, action5});
610
* Adds a sequence of related JButtons built from the given Actions
611
* that are separated by the default gap as specified by
612
* {@link LayoutStyle#getRelatedComponentsPadX()}.<p>
614
* Uses this builder's button order (left-to-right vs. right-to-left).
615
* If you want to use a fixed order, add individual Actions instead.
617
* @param actions the Actions that describe the buttons to add
619
* @throws NullPointerException if the Action array or an Action is {@code null}
620
* @throws IllegalArgumentException if the Action array is empty
622
* @see #addButton(JComponent[])
624
public void addButton(Action[] actions) {
626
throw new NullPointerException("The Action array must not be null.");
627
int length = actions.length;
629
throw new IllegalArgumentException("The Action array must not be empty.");
630
JButton[] buttons = new JButton[length];
631
for (int i = 0; i < length; i++) {
632
buttons[i] = new JButton(actions[i]);
638
// Other ******************************************************************
641
* Adds a button or other component that grows if the container grows.
642
* The component's initial size (before it grows) is specified
643
* by the {@link LayoutStyle#getDefaultButtonWidth()}.
645
* @param component the component to add
647
public void addGrowing(JComponent component) {
648
getLayout().appendColumn(FormFactory.GROWING_BUTTON_COLSPEC);
649
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
656
* Adds a sequence of related growing buttons
657
* where each is separated by a default gap.
658
* Honors this builder's button order. If you
659
* want to use a fixed left to right order,
660
* add individual buttons.
662
* @param buttons an array of buttons to add
666
public void addGrowing(JComponent[] buttons) {
667
int length = buttons.length;
668
for (int i = 0; i < length; i++) {
669
int index = leftToRight ? i : length -1 - i;
670
addGrowing(buttons[index]);
671
if (i < buttons.length - 1)
678
* Adds a fixed size component with narrow margin. Unlike the gridded
679
* components, this component keeps its individual preferred dimension.
681
* @param component the component to add
683
public void addFixed(JComponent component) {
684
component.putClientProperty(NARROW_KEY, Boolean.TRUE);
685
getLayout().appendColumn(FormFactory.PREF_COLSPEC);