001 /*
002 * $Id: AbstractActionExt.java,v 1.7 2006/03/29 03:37:47 rbair Exp $
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
022 package org.jdesktop.swingx.action;
023
024 import java.awt.event.ItemEvent;
025 import java.awt.event.ItemListener;
026 import java.beans.PropertyChangeListener;
027
028 import javax.swing.AbstractAction;
029 import javax.swing.Action;
030 import javax.swing.Icon;
031 import javax.swing.KeyStroke;
032
033 /**
034 * Extends the concept of the Action to include toggle or group states.
035 *
036 */
037 public abstract class AbstractActionExt extends AbstractAction
038 implements ItemListener {
039
040 /**
041 * The key for the large icon
042 */
043 public static final String LARGE_ICON = "__LargeIcon__";
044
045 /**
046 * The key for the button group
047 */
048 public static final String GROUP = "__Group__";
049
050 /**
051 * The key for the flag which indicates that this is a state type.
052 */
053 public static final String IS_STATE = "__State__";
054
055 /**
056 * Specified whether the action is selected; the default is false
057 */
058 private boolean selected = false;
059
060 /**
061 * Default constructor, does nothing.
062 *
063 */
064 public AbstractActionExt() {
065 // default constructor
066 }
067 /**
068 * Copy constuctor copies the state.
069 */
070 public AbstractActionExt(AbstractActionExt action) {
071 Object[] keys = action.getKeys();
072 for (int i = 0; i < keys.length; i++) {
073 putValue((String)keys[i], action.getValue((String)keys[i]));
074 }
075 this.selected = action.selected;
076 this.enabled = action.enabled;
077
078 // Copy change listeners.
079 PropertyChangeListener[] listeners = action.getPropertyChangeListeners();
080 for (int i = 0; i < listeners.length; i++) {
081 addPropertyChangeListener(listeners[i]);
082 }
083 }
084
085 public AbstractActionExt(String name) {
086 super(name);
087 }
088
089 public AbstractActionExt(String name, Icon icon) {
090 super(name, icon);
091 }
092
093 /**
094 * Constructs an Action with the label and command
095 *
096 * @param name name of the action usually used as a label
097 * @param command command key of the action
098 */
099 public AbstractActionExt(String name, String command) {
100 this(name);
101 setActionCommand(command);
102 }
103
104 /**
105 * @param name display name of the action
106 * @param command the value of the action command key
107 * @param icon icon to display
108 */
109 public AbstractActionExt(String name, String command, Icon icon) {
110 super(name, icon);
111 setActionCommand(command);
112 }
113 /**
114 * Returns a short desciption of the action.
115 *
116 * @return the short description or null
117 */
118 public String getShortDescription() {
119 return (String)getValue(Action.SHORT_DESCRIPTION);
120 }
121
122 /**
123 * Sets the short desciption of the action. This will also
124 * set the long description value is it is null.
125 * <p>
126 * This is a convenience method for <code>putValue</code> with the
127 * <code>Action.SHORT_DESCRIPTION</code> key.
128 *
129 * @param desc the short description; can be <code>null</code>w
130 * @see Action#SHORT_DESCRIPTION
131 * @see Action#putValue
132 */
133 public void setShortDescription(String desc) {
134 putValue(Action.SHORT_DESCRIPTION, desc);
135 if (desc != null && getLongDescription() == null) {
136 setLongDescription(desc);
137 }
138 }
139
140 /**
141 * Returns a long desciption of the action.
142 *
143 * @return the long description or null
144 */
145 public String getLongDescription() {
146 return (String)getValue(Action.LONG_DESCRIPTION);
147 }
148
149 /**
150 * Sets the long desciption of the action. This will also set the
151 * value of the short description if that value is null.
152 * <p>
153 * This is a convenience method for <code>putValue</code> with the
154 * <code>Action.LONG_DESCRIPTION</code> key.
155 *
156 * @param desc the long description; can be <code>null</code>
157 * @see Action#LONG_DESCRIPTION
158 * @see Action#putValue
159 */
160 public void setLongDescription(String desc) {
161 putValue(Action.LONG_DESCRIPTION, desc);
162 if (desc != null && getShortDescription() == null) {
163 setShortDescription(desc);
164 }
165 }
166
167 /**
168 * Returns a small icon which represents the action.
169 *
170 * @return the small icon or null
171 */
172 public Icon getSmallIcon() {
173 return (Icon)getValue(SMALL_ICON);
174 }
175
176 /**
177 * Sets the small icon which represents the action.
178 * <p>
179 * This is a convenience method for <code>putValue</code> with the
180 * <code>Action.SMALL_ICON</code> key.
181 *
182 * @param icon the small icon; can be <code>null</code>
183 * @see Action#SMALL_ICON
184 * @see Action#putValue
185 */
186 public void setSmallIcon(Icon icon) {
187 putValue(SMALL_ICON, icon);
188 }
189
190 /**
191 * Returns a large icon which represents the action.
192 *
193 * @return the large icon or null
194 */
195 public Icon getLargeIcon() {
196 return (Icon)getValue(LARGE_ICON);
197 }
198
199 /**
200 * Sets the large icon which represents the action.
201 * <p>
202 * This is a convenience method for <code>putValue</code> with the
203 * <code>LARGE_ICON</code> key.
204 *
205 * @param icon the large icon; can be <code>null</code>
206 * @see #LARGE_ICON
207 * @see Action#putValue
208 */
209 public void setLargeIcon(Icon icon) {
210 putValue(LARGE_ICON, icon);
211 }
212
213 /**
214 * Sets the name of the action.
215 * <p>
216 * This is a convenience method for <code>putValue</code> with the
217 * <code>Action.NAME</code> key.
218 *
219 * @param name the name of the action; can be <code>null</code>
220 * @see Action#NAME
221 * @see Action#putValue
222 */
223 public void setName(String name) {
224 putValue(Action.NAME, name);
225 }
226
227 /**
228 * Returns the name of the action.
229 *
230 * @return the name of the action or null
231 */
232 public String getName() {
233 return (String)getValue(Action.NAME);
234 }
235
236 public void setMnemonic(String mnemonic) {
237 if (mnemonic != null && mnemonic.length() > 0) {
238 putValue(Action.MNEMONIC_KEY, new Integer(mnemonic.charAt(0)));
239 }
240 }
241
242 /**
243 * Sets the mnemonic key code for the action.
244 * <p>
245 * This is a convenience method for <code>putValue</code> with the
246 * <code>Action.MNEMONIC_KEY</code> key.
247 * <p>
248 * This method does not validate the value. Please see
249 * {@link javax.swing.AbstractButton#setMnemonic(int)} for details
250 * concerning the value of the mnemonic.
251 *
252 * @param mnemonic an int key code mnemonic or 0
253 * @see javax.swing.AbstractButton#setMnemonic(int)
254 * @see Action#MNEMONIC_KEY
255 * @see Action#putValue
256 */
257 public void setMnemonic(int mnemonic) {
258 putValue(Action.MNEMONIC_KEY, new Integer(mnemonic));
259 }
260
261 /**
262 * Return the mnemonic key code for the action.
263 *
264 * @return the mnemonic or 0
265 */
266 public int getMnemonic() {
267 Integer value = (Integer)getValue(Action.MNEMONIC_KEY);
268 if (value != null) {
269 return value.intValue();
270 }
271 return '\0';
272 }
273
274 /**
275 * Sets the action command key. The action command key
276 * is used to identify the action.
277 * <p>
278 * This is a convenience method for <code>putValue</code> with the
279 * <code>Action.ACTION_COMMAND_KEY</code> key.
280 *
281 * @param key the action command
282 * @see Action#ACTION_COMMAND_KEY
283 * @see Action#putValue
284 */
285 public void setActionCommand(Object key) {
286 putValue(Action.ACTION_COMMAND_KEY, key);
287 }
288
289 /**
290 * Returns the action command.
291 *
292 * @return the action command or null
293 */
294 public Object getActionCommand() {
295 return getValue(Action.ACTION_COMMAND_KEY);
296 }
297
298 /**
299 * Returns the key stroke which represents an accelerator
300 * for the action.
301 *
302 * @return the key stroke or null
303 */
304 public KeyStroke getAccelerator() {
305 return (KeyStroke)getValue(Action.ACCELERATOR_KEY);
306 }
307
308 /**
309 * Sets the key stroke which represents an accelerator
310 * for the action.
311 * <p>
312 * This is a convenience method for <code>putValue</code> with the
313 * <code>Action.ACCELERATOR_KEY</code> key.
314 *
315 * @param key the key stroke; can be <code>null</code>
316 * @see Action#ACCELERATOR_KEY
317 * @see Action#putValue
318 */
319 public void setAccelerator(KeyStroke key) {
320 putValue(Action.ACCELERATOR_KEY, key);
321 }
322
323 /**
324 * Sets the group identity of the state action. This is used to
325 * identify the action as part of a button group.
326 */
327 public void setGroup(Object group) {
328 putValue(GROUP, group);
329 }
330
331 public Object getGroup() {
332 return getValue(GROUP);
333 }
334
335 /**
336 * Will perform cleanup on the object.
337 * Should be called when finished with the Action. This should be used if
338 * a new action is constructed from the properties of an old action.
339 * The old action properties should be disposed.
340 */
341 public void dispose() {
342 PropertyChangeListener[] listeners = getPropertyChangeListeners();
343 for (int i = 0; i < listeners.length; i++) {
344 removePropertyChangeListener(listeners[i]);
345 }
346 }
347
348 // Properties etc....
349
350 /**
351 * Inicates if this action has states. If this method returns
352 * true then the this will send ItemEvents to ItemListeners
353 * when the control constructed with this action in invoked.
354 *
355 * @return true if this can handle states
356 */
357 public boolean isStateAction() {
358 Boolean state = (Boolean)getValue(IS_STATE);
359 if (state != null) {
360 return state.booleanValue();
361 }
362 return false;
363 }
364
365 /**
366 * Set the state property to true.
367 */
368 public void setStateAction() {
369 setStateAction(true);
370 }
371
372 /**
373 * Set the state property.
374 *
375 * @param state if true then this action will fire ItemEvents
376 */
377 public void setStateAction(boolean state) {
378 putValue(IS_STATE, Boolean.valueOf(state));
379 }
380
381 /**
382 * @return true if the action is in the selected state
383 */
384 public boolean isSelected() {
385 return selected;
386 }
387
388 /**
389 * Changes the state of the action
390 * @param newValue true to set the action as selected of the action.
391 */
392 public synchronized void setSelected(boolean newValue) {
393 boolean oldValue = this.selected;
394 if (oldValue != newValue) {
395 this.selected = newValue;
396 firePropertyChange("selected", Boolean.valueOf(oldValue),
397 Boolean.valueOf(newValue));
398 }
399 }
400
401 public String toString() {
402 StringBuffer buffer = new StringBuffer("[");
403 // RG: Fix for J2SE 5.0; Can't cascade append() calls because
404 // return type in StringBuffer and AbstractStringBuilder are different
405 buffer.append(this.getClass().toString());
406 buffer.append(":");
407 try {
408 Object[] keys = getKeys();
409 for (int i = 0; i < keys.length; i++) {
410 buffer.append(keys[i]);
411 buffer.append('=');
412 buffer.append(getValue( (String) keys[i]).toString());
413 if (i < keys.length - 1) {
414 buffer.append(',');
415 }
416 }
417 buffer.append(']');
418 }
419 catch (Exception ex) { // RG: append(char) throws IOException in J2SE 5.0
420 /** @todo Log it */
421 }
422 return buffer.toString();
423 }
424
425 /**
426 * @inheritDoc
427 * Default to no-op
428 */
429 public void itemStateChanged(ItemEvent e) {
430 }
431 }