2
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. 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 Flamingo Kirill Grouchnikov 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.
30
package org.pushingpixels.flamingo.api.common;
32
import java.awt.Component;
35
import javax.swing.event.ChangeEvent;
36
import javax.swing.event.ChangeListener;
38
import org.pushingpixels.flamingo.internal.ui.common.BasicCommandButtonStripUI;
39
import org.pushingpixels.flamingo.internal.ui.common.CommandButtonStripUI;
42
* Button strip component. Provides visual appearance of a strip. The buttons in
43
* the strip are either drawn horizontally with no horizontal space between them
44
* or drawn vertically with no vertical space between them.
46
* @author Kirill Grouchnikov
48
public class JCommandButtonStrip extends JComponent {
50
* The UI class ID string.
52
public static final String uiClassID = "CommandButtonStripUI";
55
* Element state for the buttons in this button strip. Default state is
56
* {@link CommandButtonDisplayState#SMALL}.
58
protected CommandButtonDisplayState displayState;
61
* Scale factor for horizontal gaps.
63
* @see #setVGapScaleFactor(double)
65
protected double hgapScaleFactor;
68
* Scale factor for vertical gaps.
70
* @see #setVGapScaleFactor(double)
72
protected double vgapScaleFactor;
75
* Button strip orientation.
77
* @author Kirill Grouchnikov
79
public enum StripOrientation {
81
* Horizontal strip orientation.
86
* Vertical strip orientation.
92
* Orientation of <code>this</code> strip.
94
* @see #getOrientation()
96
private StripOrientation orientation;
99
* Creates an empty horizontally-oriented strip.
101
public JCommandButtonStrip() {
102
this(StripOrientation.HORIZONTAL);
106
* Creates an empty strip.
109
* Orientation for this strip.
111
public JCommandButtonStrip(StripOrientation orientation) {
112
this.orientation = orientation;
113
this.displayState = CommandButtonDisplayState.SMALL;
114
switch (orientation) {
116
this.hgapScaleFactor = 0.75;
117
this.vgapScaleFactor = 1.0;
120
this.hgapScaleFactor = 1.0;
121
this.vgapScaleFactor = 0.75;
124
this.setOpaque(false);
129
* Sets the display state for the buttons in this button strip. This method
130
* must be called <em>before</em> adding the first command button. The
131
* default state is {@link CommandButtonDisplayState#SMALL}.
133
* @param elementState
134
* New element state for the buttons in this button strip.
136
public void setDisplayState(CommandButtonDisplayState elementState) {
137
if (this.getComponentCount() > 0) {
138
throw new IllegalStateException(
139
"Can't call this method after buttons have been already added");
141
this.displayState = elementState;
145
* Sets the horizontal gap scale factor for the buttons in this button
146
* strip. This method must be called <em>before</em> adding the first
150
* The default horizontal gap scale factor for horizontally oriented strips
151
* is 0.75. The default horizontal gap scale factor for vertically oriented
155
* @param hgapScaleFactor
156
* New horizontal gap scale factor for the buttons in this button
158
* @see #setVGapScaleFactor(double)
160
public void setHGapScaleFactor(double hgapScaleFactor) {
161
if (this.getComponentCount() > 0) {
162
throw new IllegalStateException(
163
"Can't call this method after buttons have been already added");
165
this.hgapScaleFactor = hgapScaleFactor;
169
* Sets the vertical gap scale factor for the buttons in this button strip.
170
* This method must be called <em>before</em> adding the first command
174
* The default vertical gap scale factor for vertically oriented strips is
175
* 0.75. The default vertical gap scale factor for horizontally oriented
179
* @param vgapScaleFactor
180
* New vertical gap scale factor for the buttons in this button
182
* @see #setHGapScaleFactor(double)
184
public void setVGapScaleFactor(double vgapScaleFactor) {
185
if (this.getComponentCount() > 0) {
186
throw new IllegalStateException(
187
"Can't call this method after buttons have been already added");
189
this.vgapScaleFactor = vgapScaleFactor;
195
* @see java.awt.Container#add(java.awt.Component, java.lang.Object, int)
198
public void add(Component comp, Object constraints, int index) {
199
throw new UnsupportedOperationException();
205
* @see java.awt.Container#add(java.awt.Component, java.lang.Object)
208
public void add(Component comp, Object constraints) {
209
throw new UnsupportedOperationException();
215
* @see java.awt.Container#add(java.awt.Component, int)
218
public Component add(Component comp, int index) {
219
if (!(comp instanceof AbstractCommandButton))
220
throw new UnsupportedOperationException();
221
this.configureCommandButton((AbstractCommandButton) comp);
222
return super.add(comp, index);
228
* @see java.awt.Container#add(java.awt.Component)
231
public Component add(Component comp) {
232
if (!(comp instanceof AbstractCommandButton))
233
throw new UnsupportedOperationException();
235
this.configureCommandButton((AbstractCommandButton) comp);
236
Component result = super.add(comp);
239
this.fireStateChanged();
244
* Configures the specified command button.
247
* Command button to configure.
249
private void configureCommandButton(AbstractCommandButton button) {
250
button.setDisplayState(this.displayState);
251
button.setHGapScaleFactor(this.hgapScaleFactor);
252
button.setVGapScaleFactor(this.vgapScaleFactor);
253
button.setFlat(false);
259
* @see java.awt.Container#add(java.lang.String, java.awt.Component)
262
public Component add(String name, Component comp) {
263
throw new UnsupportedOperationException();
267
* Sets the new UI delegate.
272
public void setUI(CommandButtonStripUI ui) {
277
* Resets the UI property to a value from the current look and feel.
279
* @see JComponent#updateUI
282
public void updateUI() {
283
if (UIManager.get(getUIClassID()) != null) {
284
setUI((CommandButtonStripUI) UIManager.getUI(this));
286
setUI(BasicCommandButtonStripUI.createUI(this));
291
* Returns the UI object which implements the L&F for this component.
293
* @return a <code>ButtonStripUI</code> object
294
* @see #setUI(org.pushingpixels.flamingo.internal.ui.common.CommandButtonStripUI)
296
public CommandButtonStripUI getUI() {
297
return (CommandButtonStripUI) ui;
301
* Returns the name of the UI class that implements the L&F for this
304
* @return the string "ButtonStripUI"
305
* @see JComponent#getUIClassID
306
* @see UIDefaults#getUI(javax.swing.JComponent)
309
public String getUIClassID() {
314
* Returns the number of buttons in <code>this</code> strip.
316
* @return Number of buttons in <code>this</code> strip.
317
* @see #getButton(int)
319
public int getButtonCount() {
320
return this.getComponentCount();
324
* Returns the specified button component of <code>this</code> strip.
328
* @return The matching button.
329
* @see #getButtonCount()
331
public AbstractCommandButton getButton(int index) {
332
return (AbstractCommandButton) this.getComponent(index);
336
* Checks whether the specified button is the first button in
337
* <code>this</code> strip.
341
* @return <code>true</code> if the specified button is the first button in
342
* <code>this</code> strip, <code>false</code> otherwise.
343
* @see #isLast(AbstractCommandButton)
345
public boolean isFirst(AbstractCommandButton button) {
346
return (button == this.getButton(0));
350
* Checks whether the specified button is the last button in
351
* <code>this</code> strip.
355
* @return <code>true</code> if the specified button is the last button in
356
* <code>this</code> strip, <code>false</code> otherwise.
357
* @see #isFirst(AbstractCommandButton)
359
public boolean isLast(AbstractCommandButton button) {
360
return (button == this.getButton(this.getButtonCount() - 1));
364
* Returns the orientation of <code>this</code> strip.
366
* @return Orientation of <code>this</code> strip.
368
public StripOrientation getOrientation() {
373
* Adds the specified change listener to track changes to this command
377
* Change listener to add.
378
* @see #removeChangeListener(ChangeListener)
380
public void addChangeListener(ChangeListener l) {
381
this.listenerList.add(ChangeListener.class, l);
385
* Removes the specified change listener from tracking changes to this
386
* command button strip.
389
* Change listener to remove.
390
* @see #addChangeListener(ChangeListener)
392
public void removeChangeListener(ChangeListener l) {
393
this.listenerList.remove(ChangeListener.class, l);
397
* Notifies all registered listener that the state of this command button
400
protected void fireStateChanged() {
401
// Guaranteed to return a non-null array
402
Object[] listeners = this.listenerList.getListenerList();
403
// Process the listeners last to first, notifying
404
// those that are interested in this event
405
ChangeEvent event = new ChangeEvent(this);
406
for (int i = listeners.length - 2; i >= 0; i -= 2) {
407
if (listeners[i] == ChangeListener.class) {
408
((ChangeListener) listeners[i + 1]).stateChanged(event);