/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.fib.model;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;
import javax.swing.JComponent;
import org.openflexo.antar.binding.BindingDefinition;
import org.openflexo.antar.binding.BindingDefinition.BindingDefinitionType;
import org.openflexo.antar.binding.BindingModel;
import org.openflexo.antar.binding.BindingVariableImpl;
import org.openflexo.antar.binding.ParameterizedTypeImpl;
import org.openflexo.fib.controller.FIBController;
import org.openflexo.fib.controller.FIBCustomDynamicModel;
import org.openflexo.swing.CustomPopup.ApplyCancelListener;
public class FIBCustom extends FIBWidget {
private static final Logger logger = Logger.getLogger(FIBCustom.class.getPackage().getName());
public static enum Parameters implements FIBModelAttribute {
componentClass, assignments
}
public static final String COMPONENT_NAME = "component";
public static interface FIBCustomComponent<T, C extends JComponent> {
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomComponentParameter {
/** name of parameter */
String name();
/** type of parameter */
Type type();
/** Enumeration of different types */
public static enum Type {
MANDATORY, OPTIONAL
};
}
public C getJComponent();
public T getEditedObject();
public void setEditedObject(T object);
public T getRevertValue();
public void setRevertValue(T object);
public void addApplyCancelListener(ApplyCancelListener l);
public void removeApplyCancelListener(ApplyCancelListener l);
public Class<T> getRepresentedType();
public void init(FIBCustom component, FIBController controller);
}
private Class componentClass;
private Class defaultDataClass = null;
private Vector<FIBCustomAssignment> assignments;
public FIBCustom() {
assignments = new Vector<FIBCustomAssignment>();
}
@Override
protected String getBaseName() {
return "CustomSelector";
}
@Override
public Type getDataType() {
if (getData() != null && getData().isSet() && getData().isValid()) {
return getData().getBinding().getAccessedType();
}
return getDefaultDataClass();
}
@Override
public Type getDefaultDataClass() {
if (getComponentClass() != null && defaultDataClass == null) {
defaultDataClass = getDataClassForComponent(getComponentClass());
}
if (defaultDataClass != null) {
return defaultDataClass;
}
return Object.class;
}
public Class getComponentClass() {
return componentClass;
}
public void setComponentClass(Class componentClass) {
FIBAttributeNotification<Class> notification = requireChange(Parameters.componentClass, componentClass);
if (notification != null) {
this.componentClass = componentClass;
if (componentClass != null) {
customComponentBindingModel = null;
createCustomComponentBindingModel();
for (Method m : componentClass.getMethods()) {
FIBCustomComponent.CustomComponentParameter annotation = m
.getAnnotation(FIBCustomComponent.CustomComponentParameter.class);
if (annotation != null) {
String variableName = COMPONENT_NAME + "." + annotation.name();
if (!hasAssignment(variableName)) {
addToAssignments(new FIBCustomAssignment(this, new DataBinding(variableName), null,
annotation.type() == FIBCustomComponent.CustomComponentParameter.Type.MANDATORY));
}
}
}
}
hasChanged(notification);
}
}
public boolean hasAssignment(String variableName) {
return getAssignent(variableName) != null;
}
public FIBCustomAssignment getAssignent(String variableName) {
for (FIBCustomAssignment a : assignments) {
if (variableName != null && variableName.equals(a.getVariable().toString())) {
return a;
}
}
return null;
}
public Vector<FIBCustomAssignment> getAssignments() {
return assignments;
}
public void setAssignments(Vector<FIBCustomAssignment> assignments) {
this.assignments = assignments;
}
public void addToAssignments(FIBCustomAssignment a) {
if (getAssignent(a.getVariable().toString()) != null) {
removeFromAssignments(getAssignent(a.getVariable().toString()));
}
a.setCustom(this);
assignments.add(a);
setChanged();
notifyObservers(new FIBAddingNotification<FIBCustomAssignment>(Parameters.assignments, a));
}
public void removeFromAssignments(FIBCustomAssignment a) {
a.setCustom(null);
assignments.remove(a);
setChanged();
notifyObservers(new FIBRemovingNotification<FIBCustomAssignment>(Parameters.assignments, a));
}
private BindingModel customComponentBindingModel;
public BindingModel getCustomComponentBindingModel() {
if (customComponentBindingModel == null) {
createCustomComponentBindingModel();
}
return customComponentBindingModel;
}
private void createCustomComponentBindingModel() {
customComponentBindingModel = new BindingModel();
customComponentBindingModel.addToBindingVariables(new BindingVariableImpl(this, COMPONENT_NAME, getComponentClass()));
// System.out.println("dataClass="+getDataClass()+" dataClassName="+dataClassName);
}
@Override
public void finalizeDeserialization() {
super.finalizeDeserialization();
for (FIBCustomAssignment assign : getAssignments()) {
assign.finalizeDeserialization();
}
}
@Override
public Type getDynamicAccessType() {
Type[] args = new Type[2];
args[0] = getDataType();
args[1] = getComponentClass();
return new ParameterizedTypeImpl(FIBCustomDynamicModel.class, args);
}
@Override
public Boolean getManageDynamicModel() {
return true;
}
public FIBCustomAssignment createAssignment() {
logger.info("Called createAssignment()");
FIBCustomAssignment newAssignment = new FIBCustomAssignment();
addToAssignments(newAssignment);
return newAssignment;
}
public FIBCustomAssignment deleteAssignment(FIBCustomAssignment assignment) {
logger.info("Called deleteAssignment() with " + assignment);
removeFromAssignments(assignment);
return assignment;
}
public static class FIBCustomAssignment extends FIBModelObject {
public static BindingDefinition VARIABLE = new BindingDefinition("variable", Object.class, BindingDefinitionType.GET_SET, true);
public BindingDefinition VALUE = new BindingDefinition("value", Object.class, BindingDefinitionType.GET, true);
public static enum Parameters implements FIBModelAttribute {
variable, value
}
private FIBCustom custom;
private DataBinding variable;
private DataBinding value;
private boolean mandatory = true;
@Override
public String toString() {
return "assignement(" + variable + "=" + value + ")";
}
public FIBCustomAssignment() {
}
public FIBCustomAssignment(FIBCustom custom, DataBinding variable, DataBinding value, boolean mandatory) {
this();
this.custom = custom;
this.mandatory = mandatory;
setVariable(variable);
setValue(value);
}
public boolean isMandatory() {
return mandatory;
}
public FIBCustom getCustom() {
return custom;
}
private void setCustom(FIBCustom custom) {
this.custom = custom;
if (value != null) {
value.setOwner(getCustom());
value.setBindingAttribute(Parameters.value);
}
}
@Override
public FIBComponent getRootComponent() {
if (getCustom() != null) {
return getCustom().getRootComponent();
}
return null;
}
public DataBinding getVariable() {
if (variable == null) {
variable = new DataBinding(this, Parameters.variable, VARIABLE);
}
return variable;
}
public void setVariable(DataBinding variable) {
variable.setOwner(this);
variable.setBindingAttribute(Parameters.variable);
variable.setBindingDefinition(VARIABLE);
this.variable = variable;
if (custom != null) {
variable.getBinding();
}
if (variable.hasBinding()) {
VALUE.setType(variable.getBinding().getAccessedType());
if (value != null) {
value.setBindingDefinition(VALUE);
}
}
}
public DataBinding getValue() {
if (value == null) {
value = new DataBinding(this, Parameters.value, VALUE);
}
return value;
}
public void setValue(DataBinding value) {
if (value != null) {
value.setOwner(getCustom()); // Warning, still null while deserializing
value.setBindingAttribute(Parameters.value); // Warning, still null while deserializing
value.setBindingDefinition(VALUE);
this.value = value;
} else {
getValue();
}
}
@Override
public void finalizeDeserialization() {
super.finalizeDeserialization();
if (variable != null) {
variable.finalizeDeserialization();
}
if (value != null) {
value.setOwner(getCustom());
value.setBindingAttribute(Parameters.value);
value.finalizeDeserialization();
}
}
@Override
public BindingModel getBindingModel() {
if (getCustom() != null) {
return getCustom().getCustomComponentBindingModel();
}
return null;
}
@Override
public List<? extends FIBModelObject> getEmbeddedObjects() {
return null;
}
}
/*public String getComponentClassName()
{
return componentClassName;
}
public void setComponentClassName(String componentClassName)
{
FIBAttributeNotification<String> notification = requireChange(
Parameters.componentClassName, componentClassName);
if (notification != null) {
this.componentClassName = componentClassName;
defaultDataClass = null;
hasChanged(notification);
}
}*/
private static final Hashtable<Class<?>, Class<?>> DATA_CLASS_FOR_COMPONENT = new Hashtable<Class<?>, Class<?>>();
/**
* Stuff to retrieve default data class from component class<br>
* NB: this is STATIC !!!!
*
* @param componentClass
* @return
*/
private static Class<?> getDataClassForComponent(Class<?> componentClass) {
Class<?> returned = DATA_CLASS_FOR_COMPONENT.get(componentClass);
if (returned == null) {
logger.info("Searching dataClass for " + componentClass);
FIBCustomComponent customComponent = null;
for (Constructor constructor : componentClass.getConstructors()) {
if (constructor.getGenericParameterTypes().length == 1) {
Object[] args = new Object[1];
args[0] = null;
try {
customComponent = (FIBCustomComponent) constructor.newInstance(args);
break;
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.warning("While trying to instanciate " + componentClass + " with null");
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassCastException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
logger.info("customComponent=" + customComponent);
if (customComponent != null) {
returned = customComponent.getRepresentedType();
DATA_CLASS_FOR_COMPONENT.put(componentClass, returned);
logger.info("Found " + returned);
return returned;
}
return Object.class;
}
return returned;
}
}