package com.towel.awt.ann;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import javax.swing.AbstractButton;
import com.towel.reflec.ClassIntrospector;
import com.towel.reflec.ClassIntrospector.AnnotatedElement;
// @formatter:off
/**
* Manager that maps an action or an <code>ActionListener</code> to a button.
*
* @author Marcos A. Vasconcelos Junior
* @see <a href="https://github.com/MarkyVasconcelos/Towel/wiki/ActionManager">ActionManager wiki</a>
*/
// @formatter:on
public class ActionManager {
private Object comp;
private Class<?> clazz;
/**
* Creates an <code>ActionManager</code> that handles the events for the
* given components.
*
* @param comp
* the object that contains the annotated attributes
*/
public ActionManager(Object comp) {
clazz = comp.getClass();
this.comp = comp;
List<AnnotatedElement<Field, ActionSequence>> sequences = new ClassIntrospector(
clazz).getAnnotatedDeclaredFields(ActionSequence.class);
for (AnnotatedElement<Field, ActionSequence> ann : sequences) {
AbstractButton button;
try {
ann.getElement().setAccessible(true);
button = (AbstractButton) ann.getElement().get(comp);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
for (Action action : ann.getAnnotation().value())
resolve(button, action);
}
List<AnnotatedElement<Field, Action>> annotateds = new ClassIntrospector(
clazz).getAnnotatedDeclaredFields(Action.class);
for (AnnotatedElement<Field, Action> ann : annotateds) {
AbstractButton button;
try {
ann.getElement().setAccessible(true);
button = (AbstractButton) ann.getElement().get(comp);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
Action action = ann.getAnnotation();
resolve(button, action);
}
}
private void resolve(AbstractButton button, Action action) {
Class<?> listener = action.listener();
String method = action.method();
if (listener.equals(ActionListener.class))
try {
button.addActionListener(new MethodInvokerListener(method));
} catch (NoSuchMethodException e1) {
throw new RuntimeException(e1);
}
else
try {
if ((listener.getModifiers() & Modifier.STATIC) != 0)
button.addActionListener((ActionListener) listener
.newInstance());
else {
Constructor<?> constr = listener
.getDeclaredConstructor(clazz);
constr.setAccessible(true);
button.addActionListener((ActionListener) constr
.newInstance(comp));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private class MethodInvokerListener implements ActionListener {
private Method method;
public MethodInvokerListener(String method)
throws NoSuchMethodException {
this.method = clazz.getDeclaredMethod(method);
this.method.setAccessible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
try {
method.invoke(comp);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}