All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.application.ApplicationActionMap Maven / Gradle / Ivy

The newest version!

/*
 * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. Use is
 * subject to license terms.
 */ 

package org.jdesktop.application;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.ActionMap;



/**
 * An {@link javax.swing.ActionMap ActionMap} class where each entry 
 * corresponds to an @Action method from a single 
 * actionsClass (i.e. a class that contains one or more 
 * @Actions).  Each entry's key is the @Action's
 * name (the method name by default), and the value is an 
 * {@link ApplicationAction} that calls the @Actions method.
 * For example, the code below prints "Hello World":
 * 
 * public class HelloWorldActions {
 *     public @Action void Hello() { System.out.print("Hello "); }
 *     public @Action void World() { System.out.println("World"); }
 * }
 * // ...
 * ApplicationActionMap appAM = new ApplicationActionMap(SimpleActions.class);
 * ActionEvent e = new ActionEvent("no src", ActionEvent.ACTION_PERFORMED, "no cmd");
 * appAM.get("Hello").actionPerformed(e);
 * appAM.get("World").actionPerformed(e);
 * 
* *

* If a ResourceMap is provided then each * ApplicationAction's ({@link javax.swing.Action#putValue * putValue}, {@link javax.swing.Action#getValue getValue}) properties * are initialized from the ResourceMap. * *

* TBD: explain use of resourcemap including action types, actionsObject, * actionsClass, ProxyActions, * * @see ApplicationAction * @see ResourceMap * @author Hans Muller ([email protected]) */ public class ApplicationActionMap extends ActionMap { private final ApplicationContext context; private final ResourceMap resourceMap; private final Class actionsClass; private final Object actionsObject; private final List proxyActions; public ApplicationActionMap(ApplicationContext context, Class actionsClass, Object actionsObject, ResourceMap resourceMap) { if (context == null) { throw new IllegalArgumentException("null context"); } if (actionsClass == null) { throw new IllegalArgumentException("null actionsClass"); } if (actionsObject == null) { throw new IllegalArgumentException("null actionsObject"); } if (!(actionsClass.isInstance(actionsObject))) { throw new IllegalArgumentException("actionsObject not an instanceof actionsClass"); } this.context = context; this.actionsClass = actionsClass; this.actionsObject = actionsObject; this.resourceMap = resourceMap; this.proxyActions = new ArrayList(); addAnnotationActions(resourceMap); maybeAddActionsPCL(); } public final ApplicationContext getContext() { return context; } public final Class getActionsClass() { return actionsClass; } public final Object getActionsObject() { return actionsObject; } /** * All of the {@code @ProxyActions} recursively defined by this * {@code ApplicationActionMap} and its parent ancestors. *

* Returns a read-only list of the {@code @ProxyActions} defined * by this {@code ApplicationActionMap's} {@code actionClass} * and, recursively, by this {@code ApplicationActionMap's} parent. * If there are no proxyActions, an empty list is returned. * * @return a list of all the proxyActions for this {@code ApplicationActionMap} */ public List getProxyActions() { // TBD: proxyActions that shadow should be merged ArrayList allProxyActions = new ArrayList(proxyActions); ActionMap parent = getParent(); while(parent != null) { if (parent instanceof ApplicationActionMap) { allProxyActions.addAll(((ApplicationActionMap)parent).proxyActions); } parent = parent.getParent(); } return Collections.unmodifiableList(allProxyActions); } private String aString(String s, String emptyValue) { return (s.length() == 0) ? emptyValue : s; } private void putAction(String key, ApplicationAction action) { if (get(key) != null) { // TBD log a warning - two actions with the same key } put(key, action); } /* Add Actions for each actionsClass method with an @Action * annotation and for the class's @ProxyActions annotation */ private void addAnnotationActions(ResourceMap resourceMap) { Class actionsClass = getActionsClass(); // @Action for (Method m : actionsClass.getDeclaredMethods()) { Action action = m.getAnnotation(Action.class); if (action != null) { String methodName = m.getName(); String enabledProperty = aString(action.enabledProperty(), null); String selectedProperty = aString(action.selectedProperty(), null); String actionName = aString(action.name(), methodName); Task.BlockingScope block = action.block(); ApplicationAction appAction = new ApplicationAction(this, resourceMap, actionName, m, enabledProperty, selectedProperty, block); putAction(actionName, appAction); } } // @ProxyActions ProxyActions proxyActionsAnnotation = actionsClass.getAnnotation(ProxyActions.class); if (proxyActionsAnnotation != null) { for(String actionName : proxyActionsAnnotation.value()) { ApplicationAction appAction = new ApplicationAction(this, resourceMap, actionName); appAction.setEnabled(false); // will track the enabled property of the Action it's bound to putAction(actionName, appAction); proxyActions.add(appAction); } } } /* If any of the ApplicationActions need to track an * enabled or selected property defined in actionsClass, then add our * PropertyChangeListener. If none of the @Actions in actionClass * provide an enabledProperty or selectedProperty argument, then * we don't need to do this. */ private void maybeAddActionsPCL() { boolean needsPCL = false; Object[] keys = keys(); if (keys != null) { for (Object key : keys) { javax.swing.Action value = get(key); if (value instanceof ApplicationAction) { ApplicationAction actionAdapter = (ApplicationAction)value; if ((actionAdapter.getEnabledProperty() != null) || (actionAdapter.getSelectedProperty() != null)) { needsPCL = true; break; } } } if (needsPCL) { try { Class actionsClass = getActionsClass(); Method m = actionsClass.getMethod("addPropertyChangeListener", PropertyChangeListener.class); m.invoke(getActionsObject(), new ActionsPCL()); } catch (Exception e) { String s = "addPropertyChangeListener undefined " + actionsClass; throw new Error(s, e); } } } } /* When the value of an actionsClass @Action enabledProperty or * selectedProperty changes, forward the PropertyChangeEvent to * the ApplicationAction object itself. */ private class ActionsPCL implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent event) { String propertyName = event.getPropertyName(); Object[] keys = keys(); if (keys != null) { for (Object key : keys) { javax.swing.Action value = get(key); if (value instanceof ApplicationAction) { ApplicationAction appAction = (ApplicationAction)value; if (propertyName.equals(appAction.getEnabledProperty())) { appAction.forwardPropertyChangeEvent(event, "enabled"); } else if (propertyName.equals(appAction.getSelectedProperty())) { appAction.forwardPropertyChangeEvent(event, "selected"); } } } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy