/******************************************************************************* | |
* 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); | |
} | |
} | |
} |