/**
*
*/
package org.javabuilders.swt.handler.binding;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.*;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.javabuilders.BuildException;
import org.javabuilders.BuildProcess;
import org.javabuilders.BuilderConfig;
import org.javabuilders.NamedObjectProperty;
import org.javabuilders.Node;
import org.javabuilders.handler.binding.AbstractBuilderBindingsHandler;
import org.javabuilders.handler.binding.BindingSourceDefinition;
import org.javabuilders.swt.SwtBuilderUtils;
import org.javabuilders.util.PropertyUtils;
/**
* Implements data binding for the SWT domain using JFace Databinding
* @author Jacek Furmankiewicz
*
*/
public class JFaceDatabindingHandler extends AbstractBuilderBindingsHandler {
public static final String BACKGROUND = "background";
//public static final String DELAYED_VALUE = "delayedValue";
public static final String EDITABLE = "editable";
public static final String ENABLED = "enabled";
public static final String FONT = "font";
public static final String FOREGROUND = "foreground";
public static final String ITEMS = "items";
public static final String MAX = "max";
public static final String MIN = "min";
public static final String SELECTION = "selection";
public static final String SINGLE_SELECTION_INDEX = "singleSelectionIndex";
public static final String TEXT = "text";
public static final String TOOLTIP_TEXT = "tooltipText";
public static final String VISIBLE = "visible";
private static final String NESTED_MATCHER = ".+\\..+";
@SuppressWarnings("unused")
private static final int defaultDelayedValueDelay = 50;
private static final JFaceDatabindingHandler singleton = new JFaceDatabindingHandler();
/**
* @return Singleton
*/
public static JFaceDatabindingHandler getInstance() { return singleton;}
/**
* @param expression Binding expression to evaluate
* @return Evaluates if its a nested property expression
*/
public static boolean isNestedProperty(String expression) {
return expression.matches(NESTED_MATCHER);
}
private Map<String,Integer> updateStrategies = new HashMap<String, Integer>();
private JFaceDatabindingHandler() {
updateStrategies.put(READ, SWT.READ_ONLY);
updateStrategies.put(READ_ONCE, SWT.READ_ONLY);
updateStrategies.put(READ_WRITE, SWT.Modify);
}
/* (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);
DataBindingContext dbc = new DataBindingContext();
process.getBuildResult().setBindingContext(dbc);
Map<NamedObjectProperty,BindingSourceDefinition> defs = getBindingDefinitions(node, process);
for(NamedObjectProperty targetProperty : defs.keySet()) {
BindingSourceDefinition sourceDef = defs.get(targetProperty);
int strategy = updateStrategies.get(sourceDef.getUpdateStrategy());
Object source = sourceDef.getSource();
String sourceExpression = sourceDef.getBindingExpression();
Object target = process.getByName(targetProperty.getName());
String targetExpression = targetProperty.getPropertyExpression();
Object sourceObservable = getObservableValue(source, sourceExpression, strategy);
Object targetObservable = getObservableValue(target, targetExpression, strategy);
if (sourceObservable instanceof IObservableValue && targetObservable instanceof IObservableValue) {
dbc.bindValue((IObservableValue)sourceObservable, (IObservableValue)targetObservable, null, null);
} else if (sourceObservable instanceof IObservableList && targetObservable instanceof IObservableList) {
dbc.bindList((IObservableList)sourceObservable, (IObservableList)targetObservable, null, null);
} else {
throw new BuildException("Unable to bind, incompatible observable types: " + sourceObservable.getClass()
+ " / " + targetObservable.getClass());
}
}
return node;
}
//gets the observable value
private Object getObservableValue(Object root, String sourceExpression, int strategy) {
IObservableValue value = null;
IObservableList list = null;
Object source = root;
if (isNestedProperty(sourceExpression)) {
try {
String[] parts = SwtBuilderUtils.getNestedBindingExpressionParts(sourceExpression);
source = PropertyUtils.getNestedProperty(root, parts[0]);
sourceExpression = parts[1];
} catch (Exception e) {
throw new BuildException("Unable to get value of nested property for databinding: {0}. {1}",
sourceExpression, e.getMessage());
}
}
try {
if (source instanceof Control) {
//SWT control
Control control = (Control) source;
if (BACKGROUND.equals(sourceExpression)) {
value = SWTObservables.observeBackground(control);
//} else if (DELAYED_VALUE.equals(sourceExpression)) {
// value = SWTObservables.observeDelayedValue(defaultDelayedValueDelay, control);
} else if (EDITABLE.equals(sourceExpression)) {
value = SWTObservables.observeEditable(control);
} else if (ENABLED.equals(sourceExpression)) {
value = SWTObservables.observeEnabled(control);
} else if (FONT.equals(sourceExpression)) {
value = SWTObservables.observeFont(control);
} else if (FOREGROUND.equals(sourceExpression)) {
value = SWTObservables.observeForeground(control);
} else if (ITEMS.equals(sourceExpression)) {
list = SWTObservables.observeItems(control);
} else if (MAX.equals(sourceExpression)) {
value = SWTObservables.observeMax(control);
} else if (MIN.equals(sourceExpression)) {
value = SWTObservables.observeMin(control);
} else if (SELECTION.equals(sourceExpression)) {
value = SWTObservables.observeSelection(control);
} else if (SINGLE_SELECTION_INDEX.equals(sourceExpression)) {
value = SWTObservables.observeSingleSelectionIndex(control);
} else if (TEXT.equals(sourceExpression)) {
value = SWTObservables.observeText(control, strategy);
} else if (TOOLTIP_TEXT.equals(sourceExpression)) {
value = SWTObservables.observeTooltipText(control);
} else if (VISIBLE.equals(sourceExpression)) {
value = SWTObservables.observeVisible(control);
} else {
//fallback on JavaBean observable
value = BeansObservables.observeValue(source, sourceExpression);
}
} else {
if (List.class.isAssignableFrom(PropertyUtils.getPropertyType(source, sourceExpression))) {
list = BeansObservables.observeList(Realm.getDefault(), source, sourceExpression);
} else {
//JavaBean observable
value = BeansObservables.observeValue(source, sourceExpression);
}
}
if (value != null) {
return value;
} else {
return list;
}
} catch (Exception ex) {
throw new BuildException("Unable to obtain a JFace Databinding observable for {0}:{1} : {2}",
source.getClass().getName(), sourceExpression, ex.getMessage());
}
}
}