2 * JIconToggleButton.java
\r
4 * Created on 28 October 2001, 15:59
\r
5 * $Header: /VisTA/CID/Components/JIconToggleButton.java 7 7/11/01 16:53 Tj $
\r
7 * $History: JIconToggleButton.java $
\r
9 * ***************** Version 7 *****************
\r
10 * User: Tj Date: 7/11/01 Time: 16:53
\r
11 * Updated in $/VisTA/CID/Components
\r
12 * Fixed bug in updateUI() whereby setUI() was calling
\r
13 * BasicIconRadioButtonUI.createUI() rather than
\r
14 * BasicIconToggleButtonUI.createUI() !! Note to self: beware of copying
\r
15 * and pasting code from similar classes!
\r
17 * ***************** Version 6 *****************
\r
18 * User: Tj Date: 2/11/01 Time: 1:31
\r
19 * Updated in $/VisTA/CID/Components
\r
20 * Added algorithm to updateUI() to dynamically detect if this component
\r
21 * has become a part of the javax.swing package
\r
23 * ***************** Version 5 *****************
\r
24 * User: Tj Date: 1/11/01 Time: 22:53
\r
25 * Updated in $/VisTA/CID/Components
\r
26 * Ready for Bean Testing
\r
28 * ***************** Version 4 *****************
\r
29 * User: Tj Date: 31/10/01 Time: 5:09
\r
30 * Updated in $/VisTA/CID/Components
\r
34 package org.tjworld.components;
\r
36 import java.awt.Graphics;
\r
37 import javax.swing.AbstractButton;
\r
38 import javax.swing.JToggleButton;
\r
39 import javax.swing.Icon;
\r
40 import javax.swing.UIManager;
\r
41 import javax.accessibility.*;
\r
42 import javax.swing.plaf.basic.BasicToggleButtonUI;
\r
43 import org.tjworld.components.BasicIconToggleButtonUI;
\r
46 * A JToggleButton that can have an icon in the same way that a JMenuItem can.
\r
48 * That is: [stateIcon] [[userIcon] [Text]]
\r
50 * setIcon() and setPressedIcon() access the User functionality indicator icons.
\r
51 * get/setSelectedStateIcon(), get/setDeselectedStateIcon(),
\r
52 * get/setDisabledSelectedStateIcon() and get/setDisabledDeselectedStateIcon()
\r
53 * access the button state indicator icon.
\r
55 * By default the state icons are null in a JIconToggleButton, but are used in inheriting
\r
56 * classes such as JIconRadioButton and JIconCheckBox.
\r
58 * Positioning logic (in BasicIconToggleButtonUI) places the stateIcon 'first' and closest to the
\r
59 * leading edge of the button.
\r
60 * In a LeftToRight Locale that means close to the left edge of the button.
\r
61 * The default icon is placed with the button Text (if any) and positioned according to the rules
\r
62 * governing text placement.
\r
64 * getMinimumSize() will return a dimension that will show the stateIcon and userIcon but no text.
\r
66 * A new UI delegate <code>BasicIconToggleButtonUI</code> knows how to paint this component, and
\r
67 * is registered with the UIManager when an instance of this component is first created.
\r
69 * Note: AbstractButton.setIcon() and AbstractButton.setPressedIcon() have been overridden
\r
70 * to remove the bug that fires the wrong accessibleContext.PropertyChange notification in
\r
71 * Java versions upto and including 1.4 beta 2 (the bug means setIcon() passes pressedIcon and
\r
72 * setPressedIcon() passes defaultIcon as the 'new' Object reference!)
\r
74 * PropertyChange Event Properties:
\r
75 * "selectedStateIcon", "disabledSelectedStateIcon", "deselectedStateIcon","disabledDeselectedStateIcon"
\r
78 * @version 1.4.4 1 Nov, 2001 Removed all User icons - will use the inherited versions and only provide logic for State Icons in this class
\r
79 * @version 1.4.4 31 Oct, 2001 Renamed 'check' icons to 'state' icons
\r
80 * version 1.4.3 31 Oct, 2001 Increased variations in check Icons: selected/deselected/enabled/disabled
\r
81 * version 1.4.2 Altered icon handling: userIcon now defaultIcon, checkIcon is new
\r
83 * @see JToggleButton
\r
86 * @see JRadioButtonMenuItem
\r
87 * @see JCheckBoxMenuItem
\r
88 * @see BasicIconToggleButtonUI
\r
89 * @see BasicIconButtonListener
\r
92 public class JIconToggleButton extends JToggleButton {
\r
94 * @see #getUIClassID
\r
97 private static final String uiClassID = "BasicIconToggleButtonUI";
\r
99 /** The state indicator displayed when the button is enabled + selected */
\r
100 protected Icon selectedStateIcon = null;
\r
102 /** The state indicator displayed when the button is disabled + selected */
\r
103 protected Icon disabledSelectedStateIcon = null;
\r
105 /** The state indicator displayed when the button is enabled + unselected */
\r
106 protected Icon unselectedStateIcon = null;
\r
108 /** The state indicator displayed when the button is disabled + unselected */
\r
109 protected Icon disabledUnselectedStateIcon = null;
\r
111 /** Identifies a change to the icon that represents the enabled selected button */
\r
112 public static final String SELECTED_STATEICON_CHANGED_PROPERTY = "selectedStateIcon";
\r
114 /** Identifies a change to the icon that represents the disabled selected button */
\r
115 public static final String DISABLED_SELECTED_STATEICON_CHANGED_PROPERTY = "disabledSelectedStateIcon";
\r
117 /** Identifies a change to the icon that represents the enabled unselected button */
\r
118 public static final String UNSELECTED_STATEICON_CHANGED_PROPERTY = "unselectedStateIcon";
\r
120 /** Identifies a change to the icon that represents the disabled unselected button */
\r
121 public static final String DISABLED_UNSELECTED_STATEICON_CHANGED_PROPERTY = "disabledUnselectedStateIcon";
\r
123 /** Creates new 'empty' JIconToggleButton */
\r
124 public JIconToggleButton() {
\r
125 this((String)null, (Icon)null, (Icon)null, false);
\r
128 /** Creates a new JIconToggleButton with enabled and disabled User icons */
\r
129 public JIconToggleButton(Icon user, Icon disabledUser) {
\r
130 this((String)null, user, disabledUser, false);
\r
133 /** Creates a new JIconToggleButton with Label, enabled and disabled User icons */
\r
134 public JIconToggleButton(String text, Icon user, Icon disabledUser, boolean selected) {
\r
135 super(text, user, selected);
\r
136 super.setDisabledIcon(disabledUser);
\r
140 * Sets the look and feel object that renders this component.
\r
142 * @param ui the <code>BasicIconToggleButtonUI</code> L&F object
\r
143 * @see UIDefaults#getUI
\r
147 * attribute: visualUpdate true
\r
148 * description: The UI object that implements the Component's LookAndFeel.
\r
150 public void setUI(BasicIconToggleButtonUI ui) {
\r
151 // needed for compilations before BasicToggleButtonUI has been compiled
\r
152 // public void setUI(BasicToggleButtonUI ui) {
\r
157 * Resets the UI property with a value from the current look and feel.
\r
159 * @see JComponent#updateUI
\r
161 public void updateUI() {
\r
162 // clever way of dynamically detecting if JIconToggleButton has become part of the
\r
163 // javax.swing package rather than the org.tjworld.components package
\r
164 String className = this.getClass().getName();
\r
166 if(className.startsWith("javax.swing.")) //** Use when this component IS a part of a Look & Feel
\r
167 setUI((BasicIconToggleButtonUI)UIManager.getUI(this));
\r
170 setUI(BasicIconToggleButtonUI.createUI(this));
\r
171 /* use when this component IS NOT a part of any Look & Feel
\r
172 * this makes sure the UIManager doesn't throw an error
\r
173 * when it tries to use the current Look & Feel classloader
\r
174 * to load the UI delegate, because the delegate (BasicIconRadioButtonUI)
\r
175 * isn't included in the Look & Feel package.
\r
180 * Returns a string that specifies the name of the l&f class
\r
181 * that renders this component.
\r
183 * @return String "ToggleButtonUI"
\r
184 * @see JComponent#getUIClassID
\r
185 * @see UIDefaults#getUI
\r
187 * description: A string that specifies the name of the L&F class
\r
189 public String getUIClassID() {
\r
193 /** Convenience method to get the currently active state-indicator icon
\r
195 * @returns The icon valid for the button's current state
\r
197 public Icon getStateIcon() {
\r
199 if(isSelected()) { // button is selected
\r
200 state = selectedStateIcon; // standard condition
\r
201 if(!isEnabled() && disabledSelectedStateIcon != null) // might be able to indicate a disabled button too
\r
202 state = disabledSelectedStateIcon;
\r
204 else { // unselected
\r
205 state = unselectedStateIcon;
\r
206 if(!isEnabled() && disabledUnselectedStateIcon != null) // might be able to indicate a disabled button too
\r
207 state = disabledUnselectedStateIcon;
\r
212 /** Sets the enabled selected state icon
\r
213 * Displayed when the button is enabled + selected
\r
214 * @param stateicon The new icon, or null to remove the existing Icon
\r
217 * attribute: visualUpdate true
\r
218 * description: The selected state icon for the button.
\r
220 public void setSelectedStateIcon(Icon stateicon) {
\r
221 Icon oldSelStateIcon = selectedStateIcon; // copy the old Icon
\r
222 selectedStateIcon = stateicon; // replace with the new
\r
223 // inform Listeners; revalidate & repaint (when button is enabled)
\r
224 changeIcon(SELECTED_STATEICON_CHANGED_PROPERTY, oldSelStateIcon, selectedStateIcon, true);
\r
227 /** Gets the enabled selected state icon
\r
228 * @returns The state icon, or null if no icon is set
\r
230 public Icon getSelectedStateIcon() {
\r
231 return selectedStateIcon;
\r
234 /** Sets the disabled selected state icon
\r
235 * Displayed when the button is disabled + selected
\r
236 * @param stateicon The new icon, or null to remove the existing icon
\r
239 * attribute: visualUpdate true
\r
240 * description: The disabled selected state icon for the button.
\r
242 public void setDisabledSelectedStateIcon(Icon stateicon) {
\r
243 Icon oldDisSelStateIcon = disabledSelectedStateIcon; // copy the old Icon
\r
244 disabledSelectedStateIcon = stateicon; // replace with the new
\r
245 // inform Listeners; revalidate & repaint (when button is disabled)
\r
246 changeIcon(DISABLED_SELECTED_STATEICON_CHANGED_PROPERTY, oldDisSelStateIcon, disabledSelectedStateIcon, false);
\r
249 /** Gets the disabled selected state icon
\r
250 * @returns The disabled icon, or null if no icon is set
\r
252 public Icon getDisabledSelectedStateIcon() {
\r
253 return disabledSelectedStateIcon;
\r
256 /** Sets the enabled unselected state icon
\r
257 * Displayed when the button is enabled + unselected
\r
258 * @param stateicon The new icon, or null to remove the existing icon
\r
261 * attribute: visualUpdate true
\r
262 * description: The unselected state icon for the button.
\r
264 public void setUnselectedStateIcon(Icon stateicon) {
\r
265 Icon oldUnselStateIcon = unselectedStateIcon; // copy the old Icon
\r
266 unselectedStateIcon = stateicon; // replace with the new
\r
267 // inform Listeners; revalidate & repaint (when button is enabled)
\r
268 changeIcon(UNSELECTED_STATEICON_CHANGED_PROPERTY, oldUnselStateIcon, unselectedStateIcon, true);
\r
271 /** Gets the enabled unselected state icon
\r
272 * @returns The state icon, or null if no icon is set
\r
274 public Icon getUnselectedStateIcon() {
\r
275 return unselectedStateIcon;
\r
278 /** Sets the disabled unselected state icon
\r
279 * Displayed when the button is disabled + unselected
\r
280 * @param stateicon The new icon, or null to remove the existing icon
\r
283 * attribute: visualUpdate true
\r
284 * description: The disabled unselected state icon for the button.
\r
286 public void setDisabledUnselectedStateIcon(Icon stateicon) {
\r
287 Icon oldDisUnselStateIcon = disabledUnselectedStateIcon; // copy the old Icon
\r
288 disabledUnselectedStateIcon = stateicon; // replace with the new
\r
289 // inform Listeners; revalidate & repaint (when button is disabled)
\r
290 changeIcon(DISABLED_UNSELECTED_STATEICON_CHANGED_PROPERTY, oldDisUnselStateIcon, disabledUnselectedStateIcon, false);
\r
293 /** Gets the disabled unselected state icon
\r
294 * @returns The disabled icon, or null if no icon is set
\r
296 public Icon getDisabledUnselectedStateIcon() {
\r
297 return disabledUnselectedStateIcon;
\r
300 /** Overrides AbstractButton.setIcon()
\r
301 * Overcomes bug whereby the Accessible context causes the wrong newIcon to be passed
\r
302 * with the PropertyChange Event
\r
304 * @param defaultIcon the icon used as the default image
\r
305 * @see AbstractButton#setIcon
\r
308 * attribute: visualUpdate true
\r
309 * description: The button's default icon
\r
311 public void setIcon(Icon newIcon) {
\r
312 Icon oldIcon = getIcon(); // get the old one - can't access the private member Icon directly
\r
314 /* Bit of a bodge, can't simply replicate the code in AbstractButton.setIcon()
\r
315 * because members are private.
\r
316 * Because of this, this Button will fire two PropertyChange Events, one from
\r
317 * AbstractButton.setIcon() quickly followed by the corrected PropertyChange from
\r
320 super.setIcon(newIcon);
\r
322 // inform Listeners; revalidate & repaint (when button is enabled)
\r
323 changeIcon(AbstractButton.ICON_CHANGED_PROPERTY, oldIcon, newIcon, true);
\r
326 /** Overrides AbstractButton.setPressedIcon()
\r
327 * Overcomes bug whereby the Accessible context causes the wrong newIcon to be passed
\r
328 * with the PropertyChange Event
\r
330 * @see AbstractButton#setIcon
\r
331 * @param defaultIcon the icon used as the default image
\r
334 * attribute: visualUpdate true
\r
335 * description: The pressed icon for the button.
\r
337 public void setPressedIcon(Icon newIcon) {
\r
338 Icon oldIcon = getPressedIcon();
\r
340 /* Bit of a bodge, can't simply replicate the code in AbstractButton.setIcon()
\r
341 * because members are private.
\r
342 * Because of this, this Button will fire two PropertyChange Events, one from
\r
343 * AbstractButton.setPressedIcon() quickly followed by the corrected PropertyChange from
\r
346 super.setPressedIcon(newIcon);
\r
348 // inform Listeners; revalidate & repaint (when button is disabled)
\r
349 changeIcon(AbstractButton.PRESSED_ICON_CHANGED_PROPERTY, oldIcon, newIcon, true);
\r
353 * Overrides the <code>JComponent.paintComponent()</code> method, then paints
\r
354 * the interior in the same way as the UI delegate would paint a RadioButtonMenuItem,
\r
355 * but without the Accelerator or Arrow.
\r
357 * That is: [stateIcon] [[userIcon] [Text]]
\r
359 * @param g the <code>Graphics</code> object to protect
\r
360 * @see JComponent#paintComponent
\r
362 protected void paintComponent(Graphics g) {
\r
364 Graphics scratchGraphics = g.create();
\r
366 ui.update(scratchGraphics, this);
\r
369 scratchGraphics.dispose();
\r
375 * Common functionality required when an Icon is changed
\r
377 * Update the Accessible Context and might need to revalidate (if the Icon's size has changed)
\r
378 * and repaint (if it's currently on display)
\r
380 * @param property The Property Name to fire to registered PropertyChange event listeners
\r
381 * @param oldIcon The Icon being replaced
\r
382 * @param newIcon The replacement Icon
\r
383 * @param enabled true if this Icon is used when the button is enabled, false if used when the button is disabled
\r
385 protected void changeIcon(String property, Icon oldIcon, Icon newIcon, boolean enabled) {
\r
386 firePropertyChange(property, oldIcon, newIcon); // inform PropertyChange Event listeners
\r
387 if(accessibleContext != null)
\r
388 accessibleContext.firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, oldIcon, newIcon);
\r
390 if(newIcon != oldIcon ) { // don't redo layout or paint if the Icon hasn't altered
\r
391 if(newIcon == null || oldIcon == null || newIcon.getIconWidth() != oldIcon.getIconWidth() || newIcon.getIconHeight() != oldIcon.getIconHeight())
\r
394 if(isEnabled() == enabled) repaint(); // only cause a repaint when the Icon being changed matches the one currently on display
\r
398 /** Reports useful information about this Button
\r
399 * @returns textual information
\r
401 public String toString() {
\r
402 String text = super.toString();
\r
403 if(text.charAt(text.length()-1) == ']') // strip off closing brackets from super's report
\r
404 text = text.substring(0,text.length()-1);
\r
406 text += ",selectedStateIcon=";
\r
407 if(selectedStateIcon != null)
\r
408 text += selectedStateIcon.toString();
\r
409 text += ",disabledSelectedStateIcon=";
\r
410 if(disabledSelectedStateIcon != null)
\r
411 text += disabledSelectedStateIcon.toString();
\r
412 text += ",unselectedStateIcon=";
\r
413 if(unselectedStateIcon != null)
\r
414 text += unselectedStateIcon.toString();
\r
415 text += ",disabledUnselectedStateIcon=";
\r
416 if(disabledUnselectedStateIcon != null)
\r
417 text += disabledUnselectedStateIcon.toString();
\r
418 text += ",ComponentUI=" + getUIClassID() + "]";
\r