001 /*
002 * $Id: ActionManager.java 3197 2009-01-21 17:54:30Z 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 package org.jdesktop.swingx.action;
022
023 import java.io.PrintStream;
024 import java.util.Arrays;
025 import java.util.HashSet;
026 import java.util.Set;
027
028 import javax.swing.AbstractAction;
029 import javax.swing.Action;
030 import javax.swing.ActionMap;
031
032 /**
033 * The ActionManager manages sets of <code>javax.swing.Action</code>s for an
034 * application. There are convenience methods for getting and setting the state
035 * of the action.
036 * All of these elements have a unique id tag which is used by the ActionManager
037 * to reference the action. This id maps to the <code>Action.ACTION_COMMAND_KEY</code>
038 * on the Action.
039 * <p>
040 * The ActionManager may be used to conveniently register callback methods
041 * on BoundActions.
042 * <p>
043 * A typical use case of the ActionManager is:
044 * <p>
045 * <pre>
046 * ActionManager manager = ActionManager.getInstance();
047 *
048 * // load Actions
049 * manager.addAction(action);
050 *
051 * // Change the state of the action:
052 * manager.setEnabled("new-action", newState);
053 * </pre>
054 *
055 * The ActionManager also supports Actions that can have a selected state
056 * associated with them. These Actions are typically represented by a
057 * JCheckBox or similar widget. For such actions the registered method is
058 * invoked with an additional parameter indicating the selected state of
059 * the widget. For example, for the callback handler:
060 *<p>
061 * <pre>
062 * public class Handler {
063 * public void stateChanged(boolean newState);
064 * }
065 * </pre>
066 * The registration method would look similar:
067 * <pre>
068 * manager.registerCallback("select-action", new Handler(), "stateChanged");
069 * </pre>
070 *<p>
071 * The stateChanged method would be invoked as the selected state of
072 * the widget changed. Additionally if you need to change the selected
073 * state of the Action use the ActionManager method <code>setSelected</code>.
074 * <p>
075 * The <code>ActionContainerFactory</code> uses the managed Actions in a
076 * ActionManager to create user interface components. It uses the shared
077 * instance of ActionManager by default. For example, to create a JMenu based on an
078 * action-list id:
079 * <pre>
080 * ActionContainerFactory factory = new ActionContainerFactory();
081 * JMenu file = factory.createMenu(list);
082 * </pre>
083 *
084 * @see ActionContainerFactory
085 * @see TargetableAction
086 * @see BoundAction
087 * @author Mark Davidson
088 * @author Neil Weber
089 */
090 public class ActionManager extends ActionMap {
091
092 /**
093 * Shared instance of the singleton ActionManager.
094 */
095 private static ActionManager INSTANCE;
096
097 /**
098 * Creates the action manager. Use this constuctor if the application should
099 * support many ActionManagers. Otherwise, using the getInstance method will
100 * return a singleton.
101 */
102 public ActionManager() {
103 }
104
105 /**
106 * Return the instance of the ActionManger. If this has not been explicity
107 * set then it will be created.
108 *
109 * @return the ActionManager instance.
110 * @see #setInstance
111 */
112 public static ActionManager getInstance() {
113 if (INSTANCE == null) {
114 INSTANCE = new ActionManager();
115 }
116 return INSTANCE;
117 }
118
119 /**
120 * Sets the ActionManager instance.
121 */
122 public static void setInstance(ActionManager manager) {
123 INSTANCE = manager;
124 }
125
126 /**
127 * Returns the ids for all the managed actions.
128 * <p>
129 * An action id is a unique idenitfier which can
130 * be used to retrieve the corrspondng Action from the ActionManager.
131 * This identifier can also
132 * be used to set the properties of the action through the action
133 * manager like setting the state of the enabled or selected flags.
134 *
135 * @return a set which represents all the action ids
136 */
137 public Set<Object> getActionIDs() {
138 Object[] keys = keys();
139 if (keys == null) {
140 return null;
141 }
142
143 return new HashSet<Object>(Arrays.asList(keys));
144 }
145
146 public Action addAction(Action action) {
147 return addAction(action.getValue(Action.ACTION_COMMAND_KEY), action);
148 }
149
150 /**
151 * Adds an action to the ActionManager
152 * @param id value of the action id - which is value of the ACTION_COMMAND_KEY
153 * @param action Action to be managed
154 * @return the action that was added
155 */
156 public Action addAction(Object id, Action action) {
157 put(id, action);
158 return action;
159 }
160
161 /**
162 * Retrieves the action corresponding to an action id.
163 *
164 * @param id value of the action id
165 * @return an Action or null if id
166 */
167 public Action getAction(Object id) {
168 return get(id);
169 }
170
171 /**
172 * Convenience method for returning the TargetableAction
173 *
174 * @param id value of the action id
175 * @return the TargetableAction referenced by the named id or null
176 */
177 public TargetableAction getTargetableAction(Object id) {
178 Action a = getAction(id);
179 if (a instanceof TargetableAction) {
180 return (TargetableAction)a;
181 }
182 return null;
183 }
184
185 /**
186 * Convenience method for returning the BoundAction
187 *
188 * @param id value of the action id
189 * @return the TargetableAction referenced by the named id or null
190 */
191 public BoundAction getBoundAction(Object id) {
192 Action a = getAction(id);
193 if (a instanceof BoundAction) {
194 return (BoundAction)a;
195 }
196 return null;
197 }
198
199 /**
200 * Convenience method for returning the ServerAction
201 *
202 * @param id value of the action id
203 * @return the TargetableAction referenced by the named id or null
204 */
205 public ServerAction getServerAction(Object id) {
206 Action a = getAction(id);
207 if (a instanceof ServerAction) {
208 return (ServerAction)a;
209 }
210 return null;
211 }
212
213 /**
214 * Convenience method for returning the CompositeAction
215 *
216 * @param id value of the action id
217 * @return the TargetableAction referenced by the named id or null
218 */
219 public CompositeAction getCompositeAction(Object id) {
220 Action a = getAction(id);
221 if (a instanceof CompositeAction) {
222 return (CompositeAction)a;
223 }
224 return null;
225 }
226
227 /**
228 * Convenience method for returning the StateChangeAction
229 *
230 * @param id value of the action id
231 * @return the StateChangeAction referenced by the named id or null
232 */
233 private AbstractActionExt getStateChangeAction(Object id) {
234 Action a = getAction(id);
235 if (a != null && a instanceof AbstractActionExt) {
236 AbstractActionExt aa = (AbstractActionExt)a;
237 if (aa.isStateAction()) {
238 return aa;
239 }
240 }
241 return null;
242 }
243
244 /**
245 * Enables or disables the state of the Action corresponding to the
246 * action id. This method should be used
247 * by application developers to ensure that all components created from an
248 * action remain in synch with respect to their enabled state.
249 *
250 * @param id value of the action id
251 * @param enabled true if the action is to be enabled; otherwise false
252 */
253 public void setEnabled(Object id, boolean enabled) {
254 Action action = getAction(id);
255 if (action != null) {
256 action.setEnabled(enabled);
257 }
258 }
259
260
261 /**
262 * Returns the enabled state of the <code>Action</code>. When enabled,
263 * any component associated with this object is active and
264 * able to fire this object's <code>actionPerformed</code> method.
265 *
266 * @param id value of the action id
267 * @return true if this <code>Action</code> is enabled; false if the
268 * action doesn't exist or disabled.
269 */
270 public boolean isEnabled(Object id) {
271 Action action = getAction(id);
272 if (action != null) {
273 return action.isEnabled();
274 }
275 return false;
276 }
277
278 /**
279 * Sets the selected state of a toggle action. If the id doesn't
280 * correspond to a toggle action then it will fail silently.
281 *
282 * @param id the value of the action id
283 * @param selected true if the action is to be selected; otherwise false.
284 */
285 public void setSelected(Object id, boolean selected) {
286 AbstractActionExt action = getStateChangeAction(id);
287 if (action != null) {
288 action.setSelected(selected);
289 }
290 }
291
292 /**
293 * Gets the selected state of a toggle action. If the id doesn't
294 * correspond to a toggle action then it will fail silently.
295 *
296 * @param id the value of the action id
297 * @return true if the action is selected; false if the action
298 * doesn't exist or is disabled.
299 */
300 public boolean isSelected(Object id) {
301 AbstractActionExt action = getStateChangeAction(id);
302 if (action != null) {
303 return action.isSelected();
304 }
305 return false;
306 }
307
308 /**
309 * A diagnostic which prints the Attributes of an action
310 * on the printStream
311 */
312 static void printAction(PrintStream stream, Action action) {
313 stream.println("Attributes for " + action.getValue(Action.ACTION_COMMAND_KEY));
314
315 if (action instanceof AbstractAction) {
316 Object[] keys = ((AbstractAction)action).getKeys();
317
318 for (int i = 0; i < keys.length; i++) {
319 stream.println("\tkey: " + keys[i] + "\tvalue: " +
320 action.getValue((String)keys[i]));
321 }
322 }
323 }
324
325 /**
326 * Convenience method to register a callback method on a <code>BoundAction</code>
327 *
328 * @see BoundAction#registerCallback
329 * @param id value of the action id - which is the value of the ACTION_COMMAND_KEY
330 * @param handler the object which will be perform the action
331 * @param method the name of the method on the handler which will be called.
332 */
333 public void registerCallback(Object id, Object handler, String method) {
334 BoundAction action = getBoundAction(id);
335 if (action != null) {
336 action.registerCallback(handler, method);
337 }
338 }
339
340 //
341 // Convenience methods for determining the type of action.
342 //
343
344 /**
345 * Determines if the Action corresponding to the action id is a state changed
346 * action (toggle, group type action).
347 *
348 * @param id value of the action id
349 * @return true if the action id represents a multi state action; false otherwise
350 */
351 public boolean isStateAction(Object id) {
352 Action action = getAction(id);
353 if (action != null && action instanceof AbstractActionExt) {
354 return ((AbstractActionExt)action).isStateAction();
355 }
356 return false;
357 }
358
359 /**
360 * Test to determine if the action is a <code>TargetableAction</code>
361 */
362 public boolean isTargetableAction(Object id) {
363 return (getTargetableAction(id) != null);
364 }
365
366 /**
367 * Test to determine if the action is a <code>BoundAction</code>
368 */
369 public boolean isBoundAction(Object id) {
370 return (getBoundAction(id) != null);
371 }
372
373 /**
374 * Test to determine if the action is a <code>BoundAction</code>
375 */
376 public boolean isCompositeAction(Object id) {
377 return (getCompositeAction(id) != null);
378 }
379
380 /**
381 * Test to determine if the action is a <code>ServerAction</code>
382 */
383 public boolean isServerAction(Object id) {
384 return (getServerAction(id) != null);
385 }
386 }