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

org.controlsfx.control.action.ActionMap Maven / Gradle / Ivy

Go to download

High quality UI controls and other tools to complement the core JavaFX distribution

There is a newer version: 11.2.1
Show newest version
/**
 * Copyright (c) 2013, 2015, ControlsFX
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *     * Neither the name of ControlsFX, any associated website, nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.controlsfx.control.action;

import javafx.event.ActionEvent;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Action Map provides an ability to create an action map of any object.
 * Attempts to convert methods annotated with {@link ActionProxy} to {@link Action}. 
 * 
 * 

Code Example

* Here's a very simple example of how to use ActionMap to register a class (in * this class it is the application class itself), and to then retrieve actions * out of the ActionMap (via the static {@link ActionMap#action(String)} method: *
* *
 * public class ActionMapDemo extends Application {
 *     public ActionMapDemo() {
 *         ActionMap.register(this);
 *         Action action11 = ActionMap.action("action11");
 *         Button actionButton = ActionUtils.createButton(action11);
 *     }
 *  
 *     @ActionProxy(text="Action 1.1", graphic="start.png", accelerator="ctrl+shift+T")
 *     private void action11() {
 *         System.out.println( "Action 1.1 is executed");
 *     }
 * }
 * 
* * If you require more control over the creation of the Action objects, you can either set the * global ActionFactory by calling ActionMap.setActionFactory() and/or you can use the factory * property on individual @ActionProxy declarations to set the factory on a case-by-case basis. * * @see ActionProxy * @see Action */ public class ActionMap { private static AnnotatedActionFactory actionFactory = new DefaultActionFactory(); private static final Map actions = new HashMap<>(); private ActionMap() { // no-op } /** * Returns the action factory used by ActionMap to construct AnnotatedAction instances. By default, this * is an instance of {@link DefaultActionFactory}. */ public static AnnotatedActionFactory getActionFactory() { return actionFactory; } /** * Sets the action factory used by ActionMap to construct AnnotatedAction instances. This factory can be overridden on * a case-by-case basis by specifying a factory class in {@link ActionProxy#factory()} */ public static void setActionFactory( AnnotatedActionFactory factory ) { Objects.requireNonNull( factory ); actionFactory = factory; } /** * Attempts to convert target's methods annotated with {@link ActionProxy} to {@link Action}s. * Three types of methods are currently converted: parameter-less methods, * methods with one parameter of type {@link ActionEvent}, and methods with two parameters * ({@link ActionEvent}, {@link Action}). * * Note that this method supports safe re-registration of a given instance or of another instance of the * same class that has already been registered. If another instance of the same class is registered, then * those actions will now be associated with the new instance. The first instance is implicitly unregistered. * * Actions are registered with their id or method name if id is not defined. * * @param target object to work on * @throws IllegalStateException if a method with unsupported parameters is annotated with {@link ActionProxy}. */ public static void register(Object target) { for (Method method : target.getClass().getDeclaredMethods()) { // Only process methods that have the ActionProxy annotation Annotation[] annotations = method.getAnnotationsByType(ActionProxy.class); if (annotations.length == 0) { continue; } // Only process methods that have // a) no parameters OR // b) one parameter of type ActionEvent OR // c) two parameters (ActionEvent, Action) int paramCount = method.getParameterCount(); Class[] paramTypes = method.getParameterTypes(); if (paramCount > 2) { throw new IllegalArgumentException( String.format( "Method %s has too many parameters", method.getName() ) ); } if (paramCount == 1 && !ActionEvent.class.isAssignableFrom( paramTypes[0] )) { throw new IllegalArgumentException( String.format( "Method %s -- single parameter must be of type ActionEvent", method.getName() ) ); } if (paramCount == 2 && (!ActionEvent.class.isAssignableFrom( paramTypes[0] ) || !Action.class.isAssignableFrom( paramTypes[1] ))) { throw new IllegalArgumentException( String.format( "Method %s -- parameters must be of types (ActionEvent, Action)", method.getName() ) ); } ActionProxy annotation = (ActionProxy) annotations[0]; AnnotatedActionFactory factory = determineActionFactory( annotation ); AnnotatedAction action = factory.createAction( annotation, method, target ); String id = annotation.id().isEmpty() ? method.getName() : annotation.id(); actions.put( id, action ); } } private static AnnotatedActionFactory determineActionFactory( ActionProxy annotation ) { // Default to using the global action factory AnnotatedActionFactory factory = actionFactory; // If an action-factory has been specified on this specific ActionProxy, then // instantiate it and use it instead. String factoryClassName = annotation.factory(); if (!factoryClassName.isEmpty()) { try { Class factoryClass = Class.forName( factoryClassName ); factory = (AnnotatedActionFactory) factoryClass.newInstance(); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException( String.format( "Action proxy refers to non-existant factory class %s", factoryClassName ), ex ); } catch (InstantiationException | IllegalAccessException ex) { throw new IllegalStateException( String.format( "Unable to instantiate action factory class %s", factoryClassName ), ex ); } } return factory; } /** * Removes all the actions associated with target object from the action map. * @param target object to work on */ public static void unregister(Object target) { if ( target != null ) { Iterator> entryIter = actions.entrySet().iterator(); while (entryIter.hasNext()) { Map.Entry entry = entryIter.next(); Object actionTarget = entry.getValue().getTarget(); if (actionTarget == null || actionTarget == target) { entryIter.remove(); } } } } /** * Returns action by its id. * @param id action id * @return action or null if id was not found */ public static Action action(String id) { return actions.get(id); } /** * Returns collection of actions by ids. Useful to create {@link ActionGroup}s. * Ids starting with "---" are converted to {@link ActionUtils#ACTION_SEPARATOR}. * Incorrect ids are ignored. * @param ids action ids * @return collection of actions */ public static Collection actions(String... ids) { List result = new ArrayList<>(); for( String id: ids ) { if ( id.startsWith("---")) result.add(ActionUtils.ACTION_SEPARATOR); //$NON-NLS-1$ Action action = action(id); if ( action != null ) result.add(action); } return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy