001/* 002 * $Id: AbstractActionExt.java 4158 2012-02-03 18:29:40Z kschaefe $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022package org.jdesktop.swingx.action; 023 024import java.awt.event.ItemEvent; 025import java.awt.event.ItemListener; 026import java.beans.PropertyChangeListener; 027 028import javax.swing.AbstractAction; 029import javax.swing.Action; 030import javax.swing.Icon; 031import javax.swing.KeyStroke; 032 033/** 034 * Extends the concept of the Action to include toggle or group states. 035 * <p> 036 * SwingX 1.6.3 updates {@code AbstractActionExt} to use new features of {@link Action} that were 037 * added in {@code Java 1.6}. The selection is now managed with {@link Action#SELECTED_KEY}, which 038 * allows the action to correctly configured Swing buttons. The {@link #LARGE_ICON} has also been 039 * changed to correspond to {@link Action#LARGE_ICON_KEY}. 040 * 041 */ 042public abstract class AbstractActionExt extends AbstractAction 043 implements ItemListener { 044 045 /** 046 * The key for the large icon 047 * <p> 048 * As of SwingX 1.6.3 is now has the same value as {@link Action#LARGE_ICON_KEY}, which is new to 1.6. 049 */ 050 public static final String LARGE_ICON = Action.LARGE_ICON_KEY; 051 052 /** 053 * The key for the button group 054 */ 055 public static final String GROUP = "__Group__"; 056 057 /** 058 * The key for the flag which indicates that this is a state type. 059 */ 060 public static final String IS_STATE = "__State__"; 061 062 /** 063 * Default constructor, does nothing. 064 */ 065 public AbstractActionExt() { 066 this((String) null); 067 } 068 069 /** 070 * Copy constructor copies the state. 071 */ 072 public AbstractActionExt(AbstractActionExt action) { 073 Object[] keys = action.getKeys(); 074 for (int i = 0; i < keys.length; i++) { 075 putValue((String)keys[i], action.getValue((String)keys[i])); 076 } 077 this.enabled = action.enabled; 078 079 // Copy change listeners. 080 PropertyChangeListener[] listeners = action.getPropertyChangeListeners(); 081 for (int i = 0; i < listeners.length; i++) { 082 addPropertyChangeListener(listeners[i]); 083 } 084 } 085 086 public AbstractActionExt(String name) { 087 super(name); 088 } 089 090 public AbstractActionExt(String name, Icon icon) { 091 super(name, icon); 092 } 093 094 /** 095 * Constructs an Action with the label and command 096 * 097 * @param name name of the action usually used as a label 098 * @param command command key of the action 099 */ 100 public AbstractActionExt(String name, String command) { 101 this(name); 102 setActionCommand(command); 103 } 104 105 /** 106 * @param name display name of the action 107 * @param command the value of the action command key 108 * @param icon icon to display 109 */ 110 public AbstractActionExt(String name, String command, Icon icon) { 111 super(name, icon); 112 setActionCommand(command); 113 } 114 /** 115 * Returns a short description of the action. 116 * 117 * @return the short description or null 118 */ 119 public String getShortDescription() { 120 return (String)getValue(Action.SHORT_DESCRIPTION); 121 } 122 123 /** 124 * Sets the short description of the action. This will also 125 * set the long description value is it is null. 126 * <p> 127 * This is a convenience method for <code>putValue</code> with the 128 * <code>Action.SHORT_DESCRIPTION</code> key. 129 * 130 * @param desc the short description; can be <code>null</code>w 131 * @see Action#SHORT_DESCRIPTION 132 * @see Action#putValue 133 */ 134 public void setShortDescription(String desc) { 135 putValue(Action.SHORT_DESCRIPTION, desc); 136 if (desc != null && getLongDescription() == null) { 137 setLongDescription(desc); 138 } 139 } 140 141 /** 142 * Returns a long description of the action. 143 * 144 * @return the long description or null 145 */ 146 public String getLongDescription() { 147 return (String)getValue(Action.LONG_DESCRIPTION); 148 } 149 150 /** 151 * Sets the long description of the action. This will also set the 152 * value of the short description if that value is null. 153 * <p> 154 * This is a convenience method for <code>putValue</code> with the 155 * <code>Action.LONG_DESCRIPTION</code> key. 156 * 157 * @param desc the long description; can be <code>null</code> 158 * @see Action#LONG_DESCRIPTION 159 * @see Action#putValue 160 */ 161 public void setLongDescription(String desc) { 162 putValue(Action.LONG_DESCRIPTION, desc); 163 if (desc != null && getShortDescription() == null) { 164 setShortDescription(desc); 165 } 166 } 167 168 /** 169 * Returns a small icon which represents the action. 170 * 171 * @return the small icon or null 172 */ 173 public Icon getSmallIcon() { 174 return (Icon)getValue(SMALL_ICON); 175 } 176 177 /** 178 * Sets the small icon which represents the action. 179 * <p> 180 * This is a convenience method for <code>putValue</code> with the 181 * <code>Action.SMALL_ICON</code> key. 182 * 183 * @param icon the small icon; can be <code>null</code> 184 * @see Action#SMALL_ICON 185 * @see Action#putValue 186 */ 187 public void setSmallIcon(Icon icon) { 188 putValue(SMALL_ICON, icon); 189 } 190 191 /** 192 * Returns a large icon which represents the action. 193 * 194 * @return the large icon or null 195 */ 196 public Icon getLargeIcon() { 197 return (Icon)getValue(LARGE_ICON); 198 } 199 200 /** 201 * Sets the large icon which represents the action. 202 * <p> 203 * This is a convenience method for <code>putValue</code> with the 204 * <code>LARGE_ICON</code> key. 205 * 206 * @param icon the large icon; can be <code>null</code> 207 * @see #LARGE_ICON 208 * @see Action#putValue 209 */ 210 public void setLargeIcon(Icon icon) { 211 putValue(LARGE_ICON, icon); 212 } 213 214 /** 215 * Sets the name of the action. 216 * <p> 217 * This is a convenience method for <code>putValue</code> with the 218 * <code>Action.NAME</code> key. 219 * 220 * @param name the name of the action; can be <code>null</code> 221 * @see Action#NAME 222 * @see Action#putValue 223 */ 224 public void setName(String name) { 225 putValue(Action.NAME, name); 226 } 227 228 /** 229 * Returns the name of the action. 230 * 231 * @return the name of the action or null 232 */ 233 public String getName() { 234 return (String)getValue(Action.NAME); 235 } 236 237 public void setMnemonic(String mnemonic) { 238 if (mnemonic != null && mnemonic.length() > 0) { 239 putValue(Action.MNEMONIC_KEY, new Integer(mnemonic.charAt(0))); 240 } 241 } 242 243 /** 244 * Sets the mnemonic key code for the action. 245 * <p> 246 * This is a convenience method for <code>putValue</code> with the 247 * <code>Action.MNEMONIC_KEY</code> key. 248 * <p> 249 * This method does not validate the value. Please see 250 * {@link javax.swing.AbstractButton#setMnemonic(int)} for details 251 * concerning the value of the mnemonic. 252 * 253 * @param mnemonic an int key code mnemonic or 0 254 * @see javax.swing.AbstractButton#setMnemonic(int) 255 * @see Action#MNEMONIC_KEY 256 * @see Action#putValue 257 */ 258 public void setMnemonic(int mnemonic) { 259 putValue(Action.MNEMONIC_KEY, new Integer(mnemonic)); 260 } 261 262 /** 263 * Return the mnemonic key code for the action. 264 * 265 * @return the mnemonic or 0 266 */ 267 public int getMnemonic() { 268 Integer value = (Integer)getValue(Action.MNEMONIC_KEY); 269 if (value != null) { 270 return value.intValue(); 271 } 272 return '\0'; 273 } 274 275 /** 276 * Sets the action command key. The action command key 277 * is used to identify the action. 278 * <p> 279 * This is a convenience method for <code>putValue</code> with the 280 * <code>Action.ACTION_COMMAND_KEY</code> key. 281 * 282 * @param key the action command 283 * @see Action#ACTION_COMMAND_KEY 284 * @see Action#putValue 285 */ 286 public void setActionCommand(String key) { 287 putValue(Action.ACTION_COMMAND_KEY, key); 288 } 289 290 /** 291 * Returns the action command. 292 * 293 * @return the action command or null 294 */ 295 public String getActionCommand() { 296 return (String) getValue(Action.ACTION_COMMAND_KEY); 297 } 298 299 /** 300 * Returns the key stroke which represents an accelerator 301 * for the action. 302 * 303 * @return the key stroke or null 304 */ 305 public KeyStroke getAccelerator() { 306 return (KeyStroke)getValue(Action.ACCELERATOR_KEY); 307 } 308 309 /** 310 * Sets the key stroke which represents an accelerator 311 * for the action. 312 * <p> 313 * This is a convenience method for <code>putValue</code> with the 314 * <code>Action.ACCELERATOR_KEY</code> key. 315 * 316 * @param key the key stroke; can be <code>null</code> 317 * @see Action#ACCELERATOR_KEY 318 * @see Action#putValue 319 */ 320 public void setAccelerator(KeyStroke key) { 321 putValue(Action.ACCELERATOR_KEY, key); 322 } 323 324 /** 325 * Sets the group identity of the state action. This is used to 326 * identify the action as part of a button group. 327 */ 328 public void setGroup(Object group) { 329 putValue(GROUP, group); 330 } 331 332 public Object getGroup() { 333 return getValue(GROUP); 334 } 335 336 /** 337 * Will perform cleanup on the object. 338 * Should be called when finished with the Action. This should be used if 339 * a new action is constructed from the properties of an old action. 340 * The old action properties should be disposed. 341 */ 342 public void dispose() { 343 PropertyChangeListener[] listeners = getPropertyChangeListeners(); 344 for (int i = 0; i < listeners.length; i++) { 345 removePropertyChangeListener(listeners[i]); 346 } 347 } 348 349 // Properties etc.... 350 351 /** 352 * Indicates if this action has states. If this method returns 353 * true then the this will send ItemEvents to ItemListeners 354 * when the control constructed with this action in invoked. 355 * 356 * @return true if this can handle states 357 */ 358 public boolean isStateAction() { 359 Boolean state = (Boolean)getValue(IS_STATE); 360 if (state != null) { 361 return state.booleanValue(); 362 } 363 return false; 364 } 365 366 /** 367 * Set the state property to true. 368 */ 369 public void setStateAction() { 370 setStateAction(true); 371 } 372 373 /** 374 * Set the state property. 375 * 376 * @param state if true then this action will fire ItemEvents 377 */ 378 public void setStateAction(boolean state) { 379 putValue(IS_STATE, Boolean.valueOf(state)); 380 } 381 382 /** 383 * @return true if the action is in the selected state 384 */ 385 public boolean isSelected() { 386 Boolean selected = (Boolean) getValue(SELECTED_KEY); 387 388 if (selected == null) { 389 return false; 390 } 391 392 return selected.booleanValue(); 393 } 394 395 /** 396 * Changes the state of the action. This is a convenience method for updating the Action via the 397 * value map. 398 * 399 * @param newValue 400 * true to set the action as selected of the action. 401 * @see Action#SELECTED_KEY 402 */ 403 public void setSelected(boolean newValue) { 404 putValue(SELECTED_KEY, newValue); 405 } 406 407 @Override 408 public String toString() { 409 StringBuffer buffer = new StringBuffer("["); 410 // RG: Fix for J2SE 5.0; Can't cascade append() calls because 411 // return type in StringBuffer and AbstractStringBuilder are different 412 buffer.append(this.getClass().toString()); 413 buffer.append(":"); 414 try { 415 Object[] keys = getKeys(); 416 for (int i = 0; i < keys.length; i++) { 417 buffer.append(keys[i]); 418 buffer.append('='); 419 buffer.append(getValue( (String) keys[i]).toString()); 420 if (i < keys.length - 1) { 421 buffer.append(','); 422 } 423 } 424 buffer.append(']'); 425 } 426 catch (Exception ex) { // RG: append(char) throws IOException in J2SE 5.0 427 /** @todo Log it */ 428 } 429 return buffer.toString(); 430 } 431 432 /** 433 * Callback method as <code>ItemListener</code>. Updates internal state based 434 * on the given ItemEvent. <p> 435 * 436 * Here: synchs selected property if isStateAction(), does nothing otherwise. 437 * 438 * @param e the ItemEvent fired by a ItemSelectable on changing the selected 439 * state. 440 */ 441 @Override 442 public void itemStateChanged(ItemEvent e) { 443 if (isStateAction()) { 444 setSelected(ItemEvent.SELECTED == e.getStateChange()); 445 } 446 } 447}