/*******************************************************************************
* Copyright (c) 2013 RelationWare, Benno Luthiger
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* RelationWare, Benno Luthiger
******************************************************************************/
package org.ripla.rap.util;
import org.eclipse.core.databinding.AggregateValidationStatus;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.IWidgetValueProperty;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Widget;
/**
* Wrapper for DataBindingContext. This helper class provides convenience
* methods for binding model fields to form input widgets.
* <p>
* Usage examples:
*
* <pre>
* DataBindingHelper ctx = new DataBindingHelper(MyModel.class, myModel);
* ctx.bindValue(ctx.getWidgetToOserve(WidgetProp.TEXT, firstName),
* ctx.getModelToObserve("firstName"));
* </pre>
*
* to bind the text input field "firstName" to the <code>firstName</code> field
* of the MyModel instance "myModel".
* </p>
*
* @author Luthiger
* @see AbstractRiplaForm
*/
public class DataBindingHelper {
private final DataBindingContext context;
private final Class<?> modelCls;
private final Object model;
/**
* Enum for meaningful <code>IWidgetValueProperty</code> instances.
*/
public enum WidgetProp {
TEXT(WidgetProperties.text(SWT.Modify)), SELECTION(WidgetProperties
.selection());
private IWidgetValueProperty prop;
WidgetProp(final IWidgetValueProperty inProp) {
prop = inProp;
}
public IWidgetValueProperty get() {
return prop;
}
}
/**
* DataBindingHelper constructor.
*
* @param inModelClass
* Class the model (i.e. bean) class.
* @param inModelInstance
* Object the model (i.e. bean) instance.
*
*/
public DataBindingHelper(final Class<?> inModelClass,
final Object inModelInstance) {
context = new DataBindingContext();
modelCls = inModelClass;
model = inModelInstance;
}
/**
* Convenience method to create a target observable.
*
* @param inProperty
* {@link WidgetProp} the property to create the observable
* @param inWidget
* {@link Widget} the widget that is observed
* @return ISWTObservableValue
*/
public ISWTObservableValue getWidgetToOserve(final WidgetProp inProperty,
final Widget inWidget) {
return inProperty.get().observe(inWidget);
}
/**
* Convenience method to create a target observable.
*
* @param inModelProperty
* String the name of the model property to be observed.
* @return IObservableValue
*/
public IObservableValue getModelToObserve(final String inModelProperty) {
return BeanProperties.value(modelCls, inModelProperty).observe(model);
}
/**
* Creates a Binding to synchronize the values of two observable values.
*
* @param inTargetObservable
* {@link IObservableValue}
* @param inModelObservable
* {@link IObservableValue}
* @return {@link Binding}
*/
public final Binding bindValue(final IObservableValue inTargetObservable,
final IObservableValue inModelObservable) {
return context.bindValue(inTargetObservable, inModelObservable, null,
null);
}
/**
* Creates a Binding to synchronize the values of two observable values.
*
* @param inTargetObservable
* {@link IObservableValue}
* @param inModelObservable
* {@link IObservableValue}
* @param inStrategy
* {@link UpdateValueStrategy} a strategy to employ when the
* target is the source of the change and the model is the
* destination
* @return {@link Binding}
*/
public final Binding bindValue(final IObservableValue inTargetObservable,
final IObservableValue inModelObservable,
final UpdateValueStrategy inStrategy) {
return context.bindValue(inTargetObservable, inModelObservable,
inStrategy, null);
}
/**
* Creates a Binding to synchronize the values of two observable values.
* Decorates the input field to mark it as required.
*
* @param inTargetObservable
* {@link IObservableValue}
* @param inModelObservable
* {@link IObservableValue}
* @param inStrategy
* {@link UpdateValueStrategy} a strategy to employ when the
* target is the source of the change and the model is the
* destination
* @return {@link Binding}
*/
public final Binding bindValueRequired(
final IObservableValue inTargetObservable,
final IObservableValue inModelObservable,
final UpdateValueStrategy inStrategy) {
final Binding out = context.bindValue(inTargetObservable,
inModelObservable, inStrategy, null);
ControlDecorationSupport.create(out, SWT.TOP | SWT.LEFT);
return out;
}
/**
* Creates a Binding to synchronize the values of two observable values.
*
* @param inTargetObservable
* {@link IObservableValue}
* @param inModelObservable
* {@link IObservableValue}
* @param inTargetToModel
* {@link UpdateValueStrategy} a strategy to employ when the
* target is the source of the change and the model is the
* destination
* @param inModelToTarget
* {@link UpdateValueStrategy} a strategy to employ when the
* model is the source of the change and the target is the
* destination
* @return {@link Binding}
*/
public final Binding bindValue(final IObservableValue inTargetObservable,
final IObservableValue inModelObservable,
final UpdateValueStrategy inTargetToModel,
final UpdateValueStrategy inModelToTarget) {
return context.bindValue(inTargetObservable, inModelObservable,
inTargetToModel, inModelToTarget);
}
/**
* Creates a Binding to synchronize the values of two observable values.
* Decorates the input field to mark it as required.
*
* @param inTargetObservable
* {@link IObservableValue}
* @param inModelObservable
* {@link IObservableValue}
* @param inTargetToModel
* {@link UpdateValueStrategy} a strategy to employ when the
* target is the source of the change and the model is the
* destination
* @param inModelToTarget
* {@link UpdateValueStrategy} a strategy to employ when the
* model is the source of the change and the target is the
* destination
* @return {@link Binding}
*/
public final Binding bindValueRequired(
final IObservableValue inTargetObservable,
final IObservableValue inModelObservable,
final UpdateValueStrategy inTargetToModel,
final UpdateValueStrategy inModelToTarget) {
final Binding out = context.bindValue(inTargetObservable,
inModelObservable, inTargetToModel, inModelToTarget);
ControlDecorationSupport.create(out, SWT.TOP | SWT.LEFT);
return out;
}
/**
* Checks the aggregated input.
*
* @return boolean <code>true</code> if all validations passed, else
* <code>false</code>.
*/
public boolean checkStatus() {
final AggregateValidationStatus lStatus = new AggregateValidationStatus(
context, AggregateValidationStatus.MAX_SEVERITY);
final Object lValue = lStatus.getValue();
if (lValue instanceof IStatus) {
return ((IStatus) lValue).isOK();
}
return true;
}
/**
* Get all status messages as an html list (ul).
*
* @return String the status messages
*/
public String getStatusMsg() {
final AggregateValidationStatus lStatus = new AggregateValidationStatus(
context, AggregateValidationStatus.MERGED);
final Object lValue = lStatus.getValue();
if (lValue instanceof IStatus) {
final IStatus lStatusVal = (IStatus) lValue;
if (lStatusVal.isMultiStatus()) {
final StringBuilder out = new StringBuilder("<ul>");
for (final IStatus lChild : lStatusVal.getChildren()) {
out.append("<li>").append(lChild.getMessage())
.append("</li>");
}
out.append("</ul>");
return new String(out);
} else {
return String.format("<p>%s</p>", lStatusVal.getMessage());
}
}
return "";
}
/**
* Create a strategy using the specified validator before the value is set
* (to the model).
*
* @param inValidator
* {@link IValidator} the validator to check in input value
* @return {@link UpdateValueStrategy}
*/
public UpdateValueStrategy createStrategyBeforeSet(
final IValidator inValidator) {
final UpdateValueStrategy out = new UpdateValueStrategy();
out.setBeforeSetValidator(inValidator);
return out;
}
/**
* Create a strategy using the specified validator after the value is
* entered (i.e. before conversion).
*
* @param inValidator
* {@link IValidator} the validator to check in input value
* @return {@link UpdateValueStrategy}
*/
public UpdateValueStrategy createStrategyAfterGet(
final IValidator inValidator) {
final UpdateValueStrategy out = new UpdateValueStrategy();
out.setAfterGetValidator(inValidator);
return out;
}
/**
* Create a strategy using the specified validator after the value is
* converted.
*
* @param inValidator
* {@link IValidator} the validator to check in input value
* @return {@link UpdateValueStrategy}
*/
public UpdateValueStrategy createStrategyAfterConvert(
final IValidator inValidator) {
final UpdateValueStrategy out = new UpdateValueStrategy();
out.setAfterConvertValidator(inValidator);
return out;
}
}