/**
*
*/
package org.javabuilders.swt.handler.type;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.logging.Logger;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Widget;
import org.javabuilders.BuildException;
import org.javabuilders.BuildProcess;
import org.javabuilders.BuilderConfig;
import org.javabuilders.Node;
import org.javabuilders.handler.AbstractTypeHandler;
import org.javabuilders.handler.ITypeHandlerFinishProcessor;
import org.javabuilders.swt.SwtJavaBuilder;
import org.javabuilders.swt.SwtBuilderUtils;
import org.javabuilders.util.BuilderUtils;
/**
* Generic handler for instantiating all SWT Widgets/Controls
* @author Jacek Furmankiewicz
*/
public class WidgetTypeHandler extends AbstractTypeHandler implements ITypeHandlerFinishProcessor {
private static final WidgetTypeHandler singleton = new WidgetTypeHandler();
/**
* Returns singleton
* @return Singleton
*/
public static WidgetTypeHandler getInstance() {
return singleton;
}
/**
* Constructor
*/
protected WidgetTypeHandler() {}
/* (non-Javadoc)
* @see org.javabuilders.handler.ITypeHandler#createNewInstance(org.javabuilders.BuilderConfig, org.javabuilders.BuildProcess, org.javabuilders.Node, java.lang.String, java.util.Map)
*/
public Node createNewInstance(BuilderConfig config, BuildProcess process,
Node parent, String key, Map<String, Object> typeDefinition)
throws BuildException {
Object instance = null;
//parent Control can be in a parent Node or sent explicitly
if ((parent != null && parent.getMainObject() != null) ||
process.getBuildResult().getProperties().get(SwtJavaBuilder.PARENT) != null) {
Class<?> type = BuilderUtils.getClassFromAlias(process, key, null);
int style = SwtBuilderUtils.getSWTStyle(typeDefinition.get(SwtJavaBuilder.STYLE));
try {
instance = executeConstructor(parent, type, style, process);
if (instance == null) {
throw new Exception("No valid constructor found for " + key);
}
//handle widgets embedded in a Scrolled Composite
if (parent != null && parent.getMainObject() instanceof ScrolledComposite &&
instance instanceof Control) {
ScrolledComposite sc = (ScrolledComposite) parent.getMainObject();
sc.setContent((Control) instance);
}
} catch (BuildException e) {
throw e;
} catch (Exception e) {
throw new BuildException("Failed to create instance of type {0} for a parent of type {1} : {2} {3}",
type.getSimpleName(), parent.getMainObject().getClass().getSimpleName(),
e.getClass(), e.getMessage());
}
}
return useExistingInstance(config, process, parent, key, typeDefinition, instance);
}
//attempts to find the proper parent/constructor/style combination to execute
private Widget executeConstructor(Node parent, Class<?> type, int style, BuildProcess process) throws BuildException {
Widget instance = null;
//parent Control can be from parent node or specified explicitly
//the explicit parent should be used only on the root (first object being created)
Object explicitParent = process.getBuildResult().getProperties().get(SwtJavaBuilder.PARENT);
Object parentControl = (explicitParent != null && parent == null) ?
explicitParent : parent.getMainObject();
try {
Constructor<?> simpleConstructor = null;
Constructor<?> styleConstructor = null;
for (Constructor<?> c : type.getConstructors()) {
if (c.getParameterTypes().length == 1 &&
c.getParameterTypes()[0].isAssignableFrom(parentControl.getClass())) {
simpleConstructor = c;
} else if (c.getParameterTypes().length == 2 &&
c.getParameterTypes()[0].isAssignableFrom(parentControl.getClass()) &&
c.getParameterTypes()[1].equals(int.class)) {
styleConstructor = c;
}
}
if (styleConstructor != null) {
instance = (Widget) styleConstructor.newInstance(parentControl,style);
} else if (simpleConstructor != null) {
instance = (Widget) simpleConstructor.newInstance(parentControl);
} else {
//keep looking for a proper parent
instance = executeConstructor(parent.getParent(),type,style, process);
}
} catch (BuildException e) {
throw e;
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof BuildException) {
throw (BuildException)e.getTargetException();
} else {
throw new BuildException("Failed to create instance of type {0} for a parent of type {1}: {2} {3} {4}",
type.getSimpleName(), parent.getMainObject().getClass().getSimpleName(),
e.getClass(), e.getMessage(), e.getTargetException());
}
} catch (Exception e) {
throw new BuildException("Failed to create instance of type {0} for a parent of type {1}: {2} {3}",
type.getSimpleName(), parent.getMainObject().getClass().getSimpleName(),
e.getClass(), e.getMessage());
}
return instance;
}
/* (non-Javadoc)
* @see org.javabuilders.handler.ITypeHandler#useExistingInstance(org.javabuilders.BuilderConfig, org.javabuilders.BuildProcess, org.javabuilders.Node, java.lang.String, java.util.Map, java.lang.Object)
*/
public Node useExistingInstance(BuilderConfig config, BuildProcess process,
Node parent, String key, Map<String, Object> typeDefinition,
Object instance) throws BuildException {
Node node = new Node(parent,key,typeDefinition);
node.setMainObject(instance);
return node;
}
/* (non-Javadoc)
* @see org.javabuilders.handler.ITypeHandlerFinishProcessor#finish(org.javabuilders.BuilderConfig, org.javabuilders.BuildProcess, org.javabuilders.Node, java.lang.String, java.util.Map)
*/
public void finish(BuilderConfig config, BuildProcess process,
Node current, String key, Map<String, Object> typeDefinition)
throws BuildException {
if (current.getMainObject() instanceof Control) {
((Control)current.getMainObject()).pack();
}
}
/* (non-Javadoc)
* @see org.javabuilders.IKeyValueConsumer#getApplicableClass()
*/
public Class<Widget> getApplicableClass() {
return Widget.class;
}
}