package de.illu.swing;
import java.awt.Component;
import java.awt.Container;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;
import de.illu.util.Util;
/**
* MultiComponent ist eine Komponente die zu beliebig vielen Parents hinzugefügt
* werden kann.
*
* @author Illuvatar
*/
public class MultiComponent<T extends Component>
{
public static final Object OTHER_MULTI_COMPONENT = new Object();
private Class<T> compClass;
private Constructor<T> constructor;
private Object[] parameters;
private Map<T, Container> components = new HashMap<T, Container>();
/*
* Alle bisher ausgeführten Methoden
*/
private List<Action> actions = new ArrayList<Action>();
public MultiComponent(Class<T> clazz, Class[] parameterTypes,
Object... parameters) throws SecurityException,
NoSuchMethodException
{
this.compClass = clazz;
this.parameters = parameters;
constructor = compClass.getConstructor(parameterTypes);
}
/**
* Fügt die Komponente dem Container hinzu
*
* @throws NoSuchMethodException
* @throws SecurityException
*/
public void addTo(Container c) throws IllegalArgumentException,
InstantiationException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException
{
T comp = newComponent();
execActions(comp);
c.add(comp);
components.put(comp, c);
}
/**
* Fügt die Komponente dem Container hinzu
*
* @throws NoSuchMethodException
* @throws SecurityException
*/
public void addTo(Container c, int index) throws IllegalArgumentException,
InstantiationException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException
{
T comp = newComponent();
execActions(comp);
c.add(comp, index);
components.put(comp, c);
}
/**
* Fügt die Komponente dem Container hinzu
*
* @throws NoSuchMethodException
* @throws SecurityException
*/
public void addTo(Container c, Object constraints)
throws IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException,
SecurityException, NoSuchMethodException
{
T comp = newComponent();
execActions(comp);
c.add(comp, constraints);
components.put(comp, c);
}
/**
* Fügt die Komponente dem Container hinzu
*
* @throws NoSuchMethodException
* @throws SecurityException
*/
public void addTo(Container c, Object constraints, int index)
throws IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException,
SecurityException, NoSuchMethodException
{
T comp = newComponent();
execActions(comp);
c.add(comp, constraints, index);
components.put(comp, c);
}
/**
* Entfernt die Komponente einmal von dem Container
*/
public void removeFrom(Container c)
{
Set<Entry<T, Container>> set = components.entrySet();
for (Entry<T, Container> e : set) {
if (e.getValue() == c) {
c.remove(e.getKey());
components.remove(e.getKey());
break; // Remove only one time
}
}
}
/**
* Entfernt die Komponente von dem Container. Falls sie mehrmals auf dem
* Container ist, werden alle Instanzen entfernt.
*/
public void removeAllFrom(Container c)
{
Set<Entry<T, Container>> set = components.entrySet();
for (Entry<T, Container> e : set) {
if (e.getValue() == c) {
c.remove(e.getKey());
components.remove(e.getKey());
}
}
}
/**
* Verändert eine Eigenschaft der Komponente. Es wird die Methode
* set[property] (value) aufgerufen, wobei [property] der erste Parameter
* ist.
* Beispiel: <code>multiLabel.set("Text", String.class, name1);</code>
*/
public void set(String property, Class clazz, Object value)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException
{
Method m = compClass.getMethod("set" + property, clazz);
for (T comp : components.keySet()) {
m.invoke(comp, value);
}
Action a = new Action("set" + property, Util.asArray(clazz), Util
.asArray(value), null);
actions.add(a);
}
/**
* Gibt die bezeichnete Eigenschaft aller Komponenten zurück.
* Beispiel:
* <code>String name1 = multiLabel.get("Text")[0].toString();</code>
*/
public Object[] get(String property) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException
{
Method m = compClass.getMethod("get" + property);
Object[] ret = new Object[components.size()];
int cnt = 0;
for (T comp : components.keySet()) {
Object o = m.invoke(comp);
ret[cnt++] = o;
}
Action a = new Action("get" + property, new Class[0], new Object[0],
null);
actions.add(a);
return ret;
}
/**
* Ruft die angegebene Methode auf allen Komponenten auf.
*/
public Object[] invoke(String methodName, Class[] parameterTypes,
Object[] parameters) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException
{
Method m = compClass.getMethod(methodName, parameterTypes);
Object[] ret = new Object[components.size()];
int cnt = 0;
for (T comp : components.keySet()) {
Object o = m.invoke(comp, parameters);
ret[cnt++] = o;
}
Action a = new Action(methodName, parameterTypes, parameters, null);
actions.add(a);
return ret;
}
/**
* Ruft die angegebene Methode auf allen Komponenten auf. Falls in den
* Parametern MultiComponent.OTHER_MULTI_COMPONENT ist, wird dies durch die
* Komponente aus dem übergebenen zweiten MultiComponent ersetzt.
*
* @throws InstantiationException
*/
public Object[] invoke(String methodName, Class[] parameterTypes,
Object[] parameters, MultiComponent<?> otherComponent)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException, InstantiationException
{
Method m = compClass.getMethod(methodName, parameterTypes);
Object[] ret = new Object[components.size()];
int cnt = 0;
for (T comp : components.keySet()) {
Object[] newParams = new Object[parameters.length];
System.arraycopy(parameters, 0, newParams, 0, parameters.length);
for (int i = 0; i < newParams.length; i++) {
if (newParams[i] == MultiComponent.OTHER_MULTI_COMPONENT) {
newParams[i] = otherComponent.newComponent();
}
}
Object o = m.invoke(comp, newParams);
ret[cnt++] = o;
}
Action a = new Action(methodName, parameterTypes, parameters,
otherComponent);
actions.add(a);
return ret;
}
private T newComponent() throws InstantiationException,
IllegalAccessException, InvocationTargetException
{
T t = constructor.newInstance(parameters);
components.put(t, null);
return t;
}
/**
* Die neuen Komponenten so verändern, wie auch die alten verändert wurden.
*/
private void execActions(T t) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException,
InstantiationException
{
for (Action a : actions) {
Method m = compClass.getMethod(a.methodName, a.parameterTypes);
Object[] newParams = new Object[a.parameters.length];
System
.arraycopy(a.parameters, 0, newParams, 0,
a.parameters.length);
for (int i = 0; i < newParams.length; i++) {
if (newParams[i] == MultiComponent.OTHER_MULTI_COMPONENT) {
newParams[i] = a.otherComponent.newComponent();
}
}
m.invoke(t, newParams);
}
}
private static class Action
{
String methodName;
Class[] parameterTypes;
Object[] parameters;
MultiComponent<?> otherComponent;
public Action(String methodName, Class[] parameterTypes,
Object[] parameters, MultiComponent<?> otherComponent)
{
this.methodName = methodName;
this.parameterTypes = parameterTypes;
this.parameters = parameters;
this.otherComponent = otherComponent;
}
}
}