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 }