blob: 10313e5eb374c7be7c22080ff66502d2baac1cce [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2010 Soyatec (http://www.soyatec.com) and others.
* 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:
* Soyatec - initial API and implementation
*******************************************************************************/
package org.eclipse.xwt.internal.core;
import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.property.value.IValueProperty;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.xwt.IDataProvider;
import org.eclipse.xwt.XWT;
import org.eclipse.xwt.XWTException;
import org.eclipse.xwt.core.IBinding;
import org.eclipse.xwt.databinding.EventPropertyObservableValue;
import org.eclipse.xwt.databinding.JFaceXWTDataBinding;
import org.eclipse.xwt.databinding.ListToArrayObservableValue;
import org.eclipse.xwt.databinding.TypedViewerObservableValueDecorator;
import org.eclipse.xwt.dataproviders.IObjectDataProvider;
import org.eclipse.xwt.internal.utils.UserData;
import org.eclipse.xwt.javabean.metadata.properties.EventProperty;
import org.eclipse.xwt.metadata.IMetaclass;
import org.eclipse.xwt.metadata.IProperty;
import org.eclipse.xwt.metadata.ModelUtils;
public class ScopeManager {
public static final int AUTO = 0;
public static final int VALUE = 1;
public static final int SET = 2;
public static final int LIST = 3;
public static final int COLLECTION = 4;
public static IObservableValue observableValue(Object control,
Object value, String fullPath,
UpdateSourceTrigger updateSourceTrigger) {
try {
return observeValue(control, value, fullPath, updateSourceTrigger);
} catch (Exception e) {
}
return null;
}
public static IObservableList observableList(Object control, Object value,
String fullPath, UpdateSourceTrigger updateSourceTrigger) {
try {
return (IObservableList) observe(control, value, fullPath,
updateSourceTrigger, ScopeManager.LIST);
} catch (Exception e) {
}
return null;
}
public static IObservableSet observableSet(Object control, Object value,
String fullPath, UpdateSourceTrigger updateSourceTrigger) {
try {
return (IObservableSet) observe(control, value, fullPath,
updateSourceTrigger, ScopeManager.SET);
} catch (Exception e) {
}
return null;
}
/**
* Reserved only for the calling from XWTLoader
*
* @param context
* @param data
* @param propertyName
* @return
*/
public static IObservableValue findObservableValue(Object context,
Object control, Object data, String propertyName) {
ScopeKeeper scope = UserData.findScopeKeeper(context);
if (control == null) {
control = context;
}
return scope.getObservableValue(UserData.getWidget(control), data,
propertyName);
}
/**
* Reserved only for the calling from XWTLoader
*
* @param context
* @param data
* @param propertyName
* @return
*/
public static IObservableSet findObservableSet(Object context,
Object control, Object data, String propertyName) {
ScopeKeeper scope = UserData.findScopeKeeper(context);
if (control == null) {
control = context;
}
return scope.getObservableSet(UserData.getWidget(control), data,
propertyName);
}
/**
* Reserved only for the calling from XWTLoader
*
* @param context
* @param data
* @param propertyName
* @return
*/
public static IObservableList findObservableList(Object context,
Object control, Object data, String propertyName) {
ScopeKeeper scope = UserData.findScopeKeeper(context);
if (control == null) {
control = context;
}
return scope.getObservableList(UserData.getWidget(control), data,
propertyName);
}
static class ObservableValueBuilder {
private Widget widget;
private Object control;
private Object value;
private Object elementType;
private BindingExpressionPath expressionPath;
private UpdateSourceTrigger updateSourceTrigger;
private IDataProvider dataProvider;
private String currentPath;
private int observeKind = VALUE;
public ObservableValueBuilder(Object control, Object elementType,
BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger, int observeKind) {
this.control = control;
this.expressionPath = expressionPath;
this.elementType = elementType;
this.updateSourceTrigger = updateSourceTrigger;
this.observeKind = observeKind;
}
public IObservable observe(Object targetValue) {
this.value = targetValue;
widget = UserData.getWidget(control);
ScopeKeeper scopeManager = UserData.findScopeKeeper(widget);
if (scopeManager == null) {
return null;
}
if (expressionPath.getFullPath() == null) {
if (targetValue instanceof IObservable) {
return (IObservable) targetValue;
}
}
IObservable observable = scopeManager.getObservable(widget, value,
expressionPath.getStripedPath());
if (observable != null) {
while (observable instanceof IObservableValue
&& ((IObservableValue) observable).getValue() instanceof IObservable) {
observable = (IObservable) ((IObservableValue) observable)
.getValue();
}
return observable;
}
dataProvider = XWT.findDataProvider(value);
Object dataValue = value;
if (value instanceof IDataProvider) {
IDataProvider dataProvider = (IDataProvider) value;
dataValue = dataProvider.getData(null);
}
currentPath = null;
Object type = elementType;
String[] segments = expressionPath.getSegments();
if (segments == null || segments.length == 0) {
String segment = ModelUtils
.normalizePropertyName(expressionPath.getFullPath());
observable = resolveObservablevalue(scopeManager, dataValue,
type, segment);
} else {
if (observeKind == COLLECTION) {
// if the first is viewers' property
if (!JFaceXWTDataBinding.isViewerProperty(segments[0])) {
int kindValue = VALUE;
Object targetValueType = dataValue;
if (dataValue instanceof IObservableValue) {
targetValueType = ((IObservableValue) dataValue).getValueType();
}
Object propertyType = dataProvider.getModelService().toModelPropertyType(targetValueType, segments[0]);
if (propertyType instanceof Class<?>) {
Class<?> propertyTypeClass = (Class<?>) propertyType;
if (Collection.class.isAssignableFrom(propertyTypeClass) || propertyTypeClass.isArray()) {
kindValue = COLLECTION;
}
}
observeKind = kindValue;
}
}
int size = segments.length;
int lastObserveKind = observeKind;
observeKind = VALUE;
for (int i = 0; i < size; i++) {
String segment = segments[i];
if (i == (size - 1)) {
observeKind = lastObserveKind;
}
observable = resolveObservablevalue(scopeManager,
dataValue, type, segment);
// Hasan: As long as this is already an IObservableValue we
// should look deep into the chain
while (observable instanceof IObservableValue
&& ((IObservableValue) observable).getValue() instanceof IObservable) {
observable = (IObservable) ((IObservableValue) observable)
.getValue();
}
dataValue = observable;
if (i != size - 1) {
type = dataProvider.getModelService().toModelType(
dataValue);
if (type != null) {
dataProvider = XWT.findDataProvider(type);
}
}
}
}
return observable;
}
private IObservable resolveObservablevalue(ScopeKeeper scopeManager,
Object dataValue, Object type, String segment) {
if (!BindingExpressionPath.isEmptyPath(segment)) {
int length = segment.length();
if (length > 1 && segment.charAt(0) == '('
&& segment.charAt(length - 1) == ')') {
// It is class
String path = segment.substring(1, segment.length() - 1);
int index = path.lastIndexOf('.');
if (index != -1) {
String className = path.substring(0, index);
segment = path.substring(index + 1);
type = dataProvider.getModelService().loadModelType(
className);
if (type == null) {
type = dataProvider.getModelService()
.loadModelType(path);
if (type != null) {
segment = null;
}
}
if (type == null) {
throw new XWTException("Class " + className
+ " not found");
}
dataProvider = XWT.findDataProvider(type);
}
}
}
if (currentPath == null) {
currentPath = segment;
} else if (segment != null) {
currentPath = currentPath + '.' + segment;
}
IObservable segmentValue = scopeManager.getObservableValue(widget,
value, currentPath);
try {
if (segmentValue == null) {
if (segment != null) {
segmentValue = createValueProperty(dataValue, segment,
type);
if (segmentValue == null) {
throw new XWTException(" Property " + segment
+ " is not found in "
+ expressionPath.getFullPath());
// maybe to
// raise an
// exception
}
scopeManager.addObservableValue(widget, value,
currentPath, segmentValue);
} else if (dataValue instanceof IObservable){
segmentValue = (IObservable)dataValue;
}
}
else if (segment == null && type != null) {
if (segmentValue instanceof TypedViewerObservableValueDecorator) {
TypedViewerObservableValueDecorator typedViewerObservableValueDecorator = (TypedViewerObservableValueDecorator) segmentValue;
typedViewerObservableValueDecorator.setElementType(type);
}
}
} catch (IllegalArgumentException e) {
// Property is not found
String message = e.getMessage();
if (!message.startsWith("Could not find property with name")) {
throw e;
}
throw new XWTException(" Property " + segment
+ " is not found in " + expressionPath.getFullPath()); // maybe
// to
// raise
// an
// exception
}
return segmentValue;
}
protected IObservable createValueProperty(Object object,
String propertyName, Object targetType) {
IObservable observable = null;
Object type = null;
if (targetType == null) {
type = dataProvider.getModelService().toModelType(object);
} else {
type = targetType;
}
if (UserData.getWidget(object) != null) {
observable = JFaceXWTDataBinding.observeWidget(object,
propertyName, updateSourceTrigger, observeKind);
}
if (observable == null
&& dataProvider instanceof IObjectDataProvider) {
IMetaclass mateclass = XWT.getMetaclass(type);
IProperty property = mateclass.findProperty(propertyName);
if (property instanceof EventProperty) {
observable = new EventPropertyObservableValue(object,
(EventProperty) property);
}
}
if (observable != null) {
return observable;
}
observable = dataProvider.observe(object, propertyName, type,
observeKind);
if (observable instanceof IObservableValue) {
IObservableValue activeValue = (IObservableValue) observable;
Object valueType = activeValue.getValueType();
if (valueType instanceof Class<?>) {
// TODO maybe need to moved in IDataProvider
Class<?> classType = (Class<?>) valueType;
if (valueType != null && classType.isArray()) {
// Create a IObserableValue to handle the connection
// between
// Array and List
Object values = dataProvider.getData(propertyName);
ArrayList<Object> array = new ArrayList<Object>();
if (values != null) {
for (Object value : (Object[]) values) {
array.add(value);
}
}
WritableList writableList = new WritableList(XWT
.getRealm(), array, classType
.getComponentType());
return new ListToArrayObservableValue(writableList,
activeValue);
}
}
}
return observable;
}
}
static class ObservableFactory extends ObservableValueBuilder implements
IObservableFactory {
public ObservableFactory(Object control,
BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger) {
super(control, null, expressionPath, updateSourceTrigger, AUTO);
}
public IObservable createObservable(Object target) {
return observe(target);
}
}
public static IObservableValue observeValue(Object control, Object value,
String fullPath, UpdateSourceTrigger updateSourceTrigger) {
return observeValue(control, value,
new BindingExpressionPath(fullPath), updateSourceTrigger);
}
public static IObservableValue observeValue(Object control, Object value,
BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger) {
if (value == null) {
value = control;
}
ObservableValueBuilder builder = new ObservableValueBuilder(control,
null, expressionPath, updateSourceTrigger, ScopeManager.VALUE);
return (IObservableValue) builder.observe(value);
}
public static IObservable observe(Object control, Object value,
BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger) {
return observe(control, value, expressionPath, updateSourceTrigger,
AUTO);
}
public static IObservableFactory observableFactory(Object control,
BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger) {
return new ObservableFactory(control, expressionPath,
updateSourceTrigger);
}
public static IObservable observe(Object control, Object value,
String fullPath, UpdateSourceTrigger updateSourceTrigger,
int observeKind) {
return observe(control, value, new BindingExpressionPath(fullPath),
updateSourceTrigger, observeKind);
}
public static IObservable observe(Object control, Object value,
BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger, int observeKind) {
if (value == null) {
value = control;
}
ObservableValueBuilder builder = new ObservableValueBuilder(control,
null, expressionPath, updateSourceTrigger, observeKind);
return builder.observe(value);
}
public static IObservableValue observeValue(Object control, Object value,
Class<?> type, BindingExpressionPath expressionPath,
UpdateSourceTrigger updateSourceTrigger) {
ObservableValueBuilder builder = new ObservableValueBuilder(control,
type, expressionPath, updateSourceTrigger, ScopeManager.VALUE);
return (IObservableValue) builder.observe(value);
}
public static IValueProperty createValueProperty(Object control,
Object type, BindingExpressionPath expressionPath) {
IValueProperty valueProperty = null;
String[] segments = expressionPath.getSegments();
if (segments == null || segments.length == 0) {
String segment = expressionPath.getFullPath();
valueProperty = doCreateValueProperty(type, segment);
} else {
for (String segment : segments) {
IValueProperty segmentValueProperty = doCreateValueProperty(
type, segment);
if (valueProperty == null) {
valueProperty = segmentValueProperty;
} else {
valueProperty = valueProperty.value(segmentValueProperty);
}
type = valueProperty.getValueType();
}
}
return valueProperty;
}
protected static IValueProperty doCreateValueProperty(Object type,
String fullPath) {
IDataProvider dataProvider = XWT.findDataProvider(type);
return dataProvider.createValueProperty(type, fullPath);
}
/**
* Reserved only for the calling from XWTLoader
*
* @param context
* @param data
* @param propertyName
* @return
*/
public static boolean isPropertyReadOnly(IDataProvider dataProvider,
BindingExpressionPath expressionPath) {
String[] segments = expressionPath.getSegments();
if (segments == null || segments.length == 0) {
String segment = expressionPath.getFullPath();
return dataProvider.isPropertyReadOnly(segment);
} else {
Object type = null;
int last = segments.length - 1;
for (int i = 0; i < last; i++) {
String segment = segments[i];
int length = segment.length();
if (length > 1 && segment.charAt(0) == '('
&& segment.charAt(length - 1) == ')') {
// It is class
String path = segment.substring(1, segment.length() - 1);
int index = path.lastIndexOf('.');
if (index != -1) {
String className = path.substring(0, index);
segment = path.substring(index + 1);
type = dataProvider.getModelService().loadModelType(
className);
if (type == null) {
throw new XWTException("Class " + className
+ " not found");
}
dataProvider = XWT.findDataProvider(type);
}
}
type = dataProvider.getDataType(segment);
if (type != null) {
dataProvider = XWT.findDataProvider(type);
if (dataProvider == null) {
throw new XWTException(
"Data probider is not found for the type "
+ type.toString());
}
} else {
throw new XWTException(
"Type is not found for the property " + segment);
}
}
String segment = segments[last];
int length = segment.length();
if (length > 1 && segment.charAt(0) == '('
&& segment.charAt(length - 1) == ')') {
// It is class
String path = segment.substring(1, segment.length() - 1);
int index = path.lastIndexOf('.');
if (index != -1) {
String className = path.substring(0, index);
segment = path.substring(index + 1);
type = dataProvider.getModelService().loadModelType(
className);
if (type == null) {
throw new XWTException("Class " + className
+ " not found");
}
dataProvider = XWT.findDataProvider(type);
}
}
return dataProvider.isPropertyReadOnly(segment);
}
}
}