001: /*
002: * @(#)JideSplitButton.java 2/26/2005
003: *
004: * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
005: */
006: package com.jidesoft.swing;
007:
008: import com.jidesoft.plaf.LookAndFeelFactory;
009: import com.jidesoft.plaf.UIDefaultsLookup;
010: import com.jidesoft.plaf.basic.ThemePainter;
011:
012: import javax.swing.*;
013: import javax.swing.plaf.ButtonUI;
014: import java.awt.*;
015: import java.awt.event.ActionEvent;
016:
017: /**
018: * <code>JideSplitButton</code> is a combination of button and menu. There is a line in the middle of
019: * the button that splits the button into two portions. The portion before the line is a button.
020: * User can click on it and trigger an action. The portion after the line is a menu. User
021: * can click on it to show a normal menu.
022: * <p/>
023: */
024: public class JideSplitButton extends JideMenu implements ButtonStyle,
025: ComponentStateSupport {
026:
027: /**
028: * @see #getUIClassID
029: * @see #readObject
030: */
031: private static final String uiClassID = "JideSplitButtonUI";
032:
033: private int _buttonStyle = TOOLBAR_STYLE;
034:
035: private boolean _alwaysDropdown = false;
036:
037: public static final String PROPERTY_ALWAYS_DROPDOWN = "alwaysDropdown";
038:
039: public JideSplitButton() {
040: initComponent();
041: }
042:
043: public JideSplitButton(String s) {
044: super (s);
045: initComponent();
046: }
047:
048: public JideSplitButton(String s, Icon icon) {
049: super (s);
050: setIcon(icon);
051: initComponent();
052: }
053:
054: public JideSplitButton(Icon icon) {
055: super ("");
056: setIcon(icon);
057: initComponent();
058: }
059:
060: public JideSplitButton(Action a) {
061: super (a);
062: initComponent();
063: }
064:
065: protected void initComponent() {
066: setModel(new DefaultSplitButtonModel());
067: if (getAction() != null) {
068: configurePropertiesFromAction(getAction());
069: }
070: setFocusable(true);
071: setRequestFocusEnabled(false);
072: }
073:
074: /**
075: * Returns the split button 's current UI.
076: *
077: * @see #setUI
078: */
079: @Override
080: public ButtonUI getUI() {
081: return (ButtonUI) ui;
082: }
083:
084: /**
085: * Sets the L&F object that renders this component.
086: *
087: * @param ui the <code>JideSplitButtonUI</code> L&F object
088: * @see javax.swing.UIDefaults#getUI
089: */
090: @Override
091: public void setUI(ButtonUI ui) {
092: super .setUI(ui);
093: }
094:
095: /**
096: * Notification from the <code>UIFactory</code> that the L&F has changed.
097: * Called to replace the UI with the latest version from the
098: * <code>UIFactory</code>.
099: *
100: * @see javax.swing.JComponent#updateUI
101: */
102: @Override
103: public void updateUI() {
104: if (UIDefaultsLookup.get(uiClassID) == null) {
105: LookAndFeelFactory.installJideExtension();
106: }
107: setUI(UIManager.getUI(this ));
108: invalidate();
109: }
110:
111: /**
112: * Returns the name of the L&F class that renders this component.
113: *
114: * @return the string "JideSplitButtonUI"
115: * @see javax.swing.JComponent#getUIClassID
116: * @see javax.swing.UIDefaults#getUI
117: */
118: @Override
119: public String getUIClassID() {
120: return uiClassID;
121: }
122:
123: /**
124: * Returns the state of the button part of the JideSplitButton. True if the
125: * toggle button is selected, false if it's not.
126: *
127: * @return true if the toggle button is selected, otherwise false
128: */
129: public boolean isButtonSelected() {
130: return model instanceof SplitButtonModel
131: && ((DefaultSplitButtonModel) model).isButtonSelected();
132: }
133:
134: /**
135: * Sets the state of the button part of the JideSplitButton. Note that this method does not
136: * trigger an <code>actionEvent</code>.
137: * Call <code>doClick</code> to perform a programatic action change.
138: *
139: * @param b true if the button is selected, otherwise false
140: */
141: public void setButtonSelected(boolean b) {
142: if (model instanceof SplitButtonModel) {
143: ((DefaultSplitButtonModel) model).setButtonSelected(b);
144: }
145: }
146:
147: /**
148: * Returns the state of the button part of the JideSplitButton. True if the
149: * button is enabled, false if it's not.
150: *
151: * @return true if the button is enabled, otherwise false
152: */
153: public boolean isButtonEnabled() {
154: return model instanceof SplitButtonModel
155: && ((DefaultSplitButtonModel) model).isButtonEnabled();
156: }
157:
158: /**
159: * Sets the state of the button part of the JideSplitButton.
160: *
161: * @param b true if the button is enabled, otherwise false
162: */
163: public void setButtonEnabled(boolean b) {
164: if (model instanceof SplitButtonModel) {
165: ((DefaultSplitButtonModel) model).setButtonEnabled(b);
166: }
167: }
168:
169: /**
170: * Gets the button style.
171: *
172: * @return the button style.
173: */
174: public int getButtonStyle() {
175: return _buttonStyle;
176: }
177:
178: /**
179: * Sets the button style.
180: *
181: * @param buttonStyle the new button style.
182: */
183: public void setButtonStyle(int buttonStyle) {
184: if (buttonStyle < 0 || buttonStyle > FLAT_STYLE) {
185: throw new IllegalArgumentException(
186: "Only TOOLBAR_STYLE, TOOLBOX_STYLE, and FLAT_STYLE are supported");
187: }
188: if (buttonStyle == _buttonStyle)
189: return;
190:
191: int oldStyle = _buttonStyle;
192: _buttonStyle = buttonStyle;
193:
194: firePropertyChange(BUTTON_STYLE_PROPERTY, oldStyle,
195: _buttonStyle);
196: }
197:
198: /**
199: * Checks the alwaysDropdown property value.
200: *
201: * @return true or false. If true, the split button doesn't have default action. It always
202: * drops down the menu when mouse clicks
203: */
204: public boolean isAlwaysDropdown() {
205: return _alwaysDropdown;
206: }
207:
208: /**
209: * If the property is true, the split button doesn't have default action. It always
210: * drops down the menu when mouse clicks. By default, this value is false.
211: *
212: * @param alwaysDropdown true or false.
213: */
214: public void setAlwaysDropdown(boolean alwaysDropdown) {
215: if (_alwaysDropdown != alwaysDropdown) {
216: boolean old = _alwaysDropdown;
217: _alwaysDropdown = alwaysDropdown;
218: firePropertyChange(PROPERTY_ALWAYS_DROPDOWN, old,
219: alwaysDropdown);
220: }
221: }
222:
223: @Override
224: public void setText(String text) {
225: // this code is to fix a bug in JDK1.5's JMenuItem line 385. It should check hideActionText first
226: Boolean hide = (Boolean) getClientProperty("hideActionText");
227: if (hide == null || Boolean.FALSE.equals(hide)) {
228: super .setText(text);
229: }
230: }
231:
232: private Color _rolloverBackground;
233: private Color _selectedBackground;
234: private Color _pressedBackground;
235: private Color _rolloverForeground;
236: private Color _selectedForeground;
237: private Color _pressedForeground;
238:
239: private Color getRolloverBackground() {
240: return _rolloverBackground;
241: }
242:
243: private void setRolloverBackground(Color rolloverBackground) {
244: _rolloverBackground = rolloverBackground;
245: }
246:
247: private Color getSelectedBackground() {
248: return _selectedBackground;
249: }
250:
251: private void setSelectedBackground(Color selectedBackground) {
252: _selectedBackground = selectedBackground;
253: }
254:
255: private Color getPressedBackground() {
256: return _pressedBackground;
257: }
258:
259: private void setPressedBackground(Color pressedBackground) {
260: _pressedBackground = pressedBackground;
261: }
262:
263: private Color getRolloverForeground() {
264: return _rolloverForeground;
265: }
266:
267: private void setRolloverForeground(Color rolloverForeground) {
268: _rolloverForeground = rolloverForeground;
269: }
270:
271: private Color getSelectedForeground() {
272: return _selectedForeground;
273: }
274:
275: private void setSelectedForeground(Color selectedForeground) {
276: _selectedForeground = selectedForeground;
277: }
278:
279: private Color getPressedForeground() {
280: return _pressedForeground;
281: }
282:
283: private void setPressedForeground(Color pressedForeground) {
284: _pressedForeground = pressedForeground;
285: }
286:
287: /**
288: * Gets the background for different states. The states are defined in ThemePainter as constants.
289: * Not all states are supported by all components. If the state is not supported or background is never set,
290: * it will return null.
291: * <p/>
292: * Please note, each L&F will have its own way to paint the different backgrounds. This method allows you to customize it
293: * for each component to use a different background. So if you want the background to be used, don't use a ColorUIResource because
294: * UIResource is considered as a setting set by the L&F and any L&F can choose to ignore it.
295: *
296: * @param state the button state. Please refer to {@link com.jidesoft.plaf.basic.ThemePainter} to see the list of available states.
297: * @return the background for different states.
298: */
299: public Color getBackgroundOfState(int state) {
300: switch (state) {
301: case ThemePainter.STATE_DEFAULT:
302: return getBackground();
303: case ThemePainter.STATE_ROLLOVER:
304: return getRolloverBackground();
305: case ThemePainter.STATE_SELECTED:
306: return getSelectedBackground();
307: case ThemePainter.STATE_PRESSED:
308: return getPressedBackground();
309: }
310: return null;
311: }
312:
313: /**
314: * Sets the background for different states. The states are defined in ThemePainter as constants.
315: * Not all states are supported by all components. If the state is not supported or background is never set,
316: * it will return null.
317: * <p/>
318: * Please note, each L&F will have its own way to paint the different backgrounds. This method allows you to customize it
319: * for each component to use a different background. So if you want the background to be used, don't use a ColorUIResource because
320: * UIResource is considered as a setting set by the L&F and any L&F can choose to ignore it.
321: *
322: * @param state the button state. Please refer to {@link com.jidesoft.plaf.basic.ThemePainter} to see the list of available states.
323: * @param color the background color
324: */
325: public void setBackgroundOfState(int state, Color color) {
326: switch (state) {
327: case ThemePainter.STATE_DEFAULT:
328: setBackground(color);
329: break;
330: case ThemePainter.STATE_ROLLOVER:
331: setRolloverBackground(color);
332: break;
333: case ThemePainter.STATE_SELECTED:
334: setSelectedBackground(color);
335: break;
336: case ThemePainter.STATE_PRESSED:
337: setPressedBackground(color);
338: break;
339: }
340: }
341:
342: /**
343: * Gets the foreground for different states. The states are defined in ThemePainter as constants.
344: * Not all states are supported by all components. If the state is not supported or foreground is never set,
345: * it will return null.
346: * <p/>
347: * Please note, each L&F will have its own way to paint the different foregrounds. This method allows you to customize it
348: * for each component to use a different foreground. So if you want the foreground to be used, don't use a ColorUIResource because
349: * UIResource is considered as a setting set by the L&F and any L&F can choose to ignore it.
350: *
351: * @param state the button state. Please refer to {@link com.jidesoft.plaf.basic.ThemePainter} to see the list of available states.
352: * @return the foreground for different states.
353: */
354: public Color getForegroundOfState(int state) {
355: switch (state) {
356: case ThemePainter.STATE_DEFAULT:
357: return getForeground();
358: case ThemePainter.STATE_ROLLOVER:
359: return getRolloverForeground();
360: case ThemePainter.STATE_SELECTED:
361: return getSelectedForeground();
362: case ThemePainter.STATE_PRESSED:
363: return getPressedForeground();
364: }
365: return null;
366: }
367:
368: /**
369: * Sets the foreground for different states. The states are defined in ThemePainter as constants.
370: * Not all states are supported by all components. If the state is not supported or foreground is never set,
371: * it will return null.
372: * <p/>
373: * Please note, each L&F will have its own way to paint the different foregrounds. This method allows you to customize it
374: * for each component to use a different foreground. So if you want the foreground to be used, don't use a ColorUIResource because
375: * UIResource is considered as a setting set by the L&F and any L&F can choose to ignore it.
376: *
377: * @param state the button state. Please refer to {@link com.jidesoft.plaf.basic.ThemePainter} to see the list of available states.
378: * @param color the background color
379: */
380: public void setForegroundOfState(int state, Color color) {
381: switch (state) {
382: case ThemePainter.STATE_DEFAULT:
383: setForeground(color);
384: break;
385: case ThemePainter.STATE_ROLLOVER:
386: setRolloverForeground(color);
387: break;
388: case ThemePainter.STATE_SELECTED:
389: setSelectedForeground(color);
390: break;
391: case ThemePainter.STATE_PRESSED:
392: setPressedForeground(color);
393: break;
394: }
395: }
396:
397: /**
398: * Clicks on the button part of the <code>JideSplitButton</code>.
399: */
400: @Override
401: public void doClick() {
402: Action action = getActionMap().get("pressed");
403: if (action != null) {
404: action.actionPerformed(new ActionEvent(this , 0, ""));
405: }
406: }
407:
408: /**
409: * Clicks on the drop down menu part of the <code>JideSplitButton</code>.
410: */
411: public void doClickOnMenu() {
412: Action action = getActionMap().get("downPressed");
413: if (action != null) {
414: action.actionPerformed(new ActionEvent(this , 0, ""));
415: }
416: }
417: }
|