blob: 9f2186b6a2033c3114afff6a2cf8f86f6b47e7b0 [file] [log] [blame]
/**
* Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
* 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:
* Florian Pirchner - Initial implementation
*/
package org.eclipse.osbp.ecview.dsl.extensions
import com.google.inject.Inject
import java.util.List
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.util.EcoreUtil
import org.eclipse.xtext.common.types.JvmOperation
import org.eclipse.xtext.common.types.JvmType
import org.eclipse.osbp.ecview.semantic.uimodel.UiBeanSlot
import org.eclipse.osbp.ecview.semantic.uimodel.UiBinding
import org.eclipse.osbp.ecview.semantic.uimodel.UiBindingEndpointAlias
import org.eclipse.osbp.ecview.semantic.uimodel.UiBindingEndpointAssignment
import org.eclipse.osbp.ecview.semantic.uimodel.UiBindingExpression
import org.eclipse.osbp.ecview.semantic.uimodel.UiCommandBindableDef
import org.eclipse.osbp.ecview.semantic.uimodel.UiEmbeddable
import org.eclipse.osbp.ecview.semantic.uimodel.UiModel
import org.eclipse.osbp.ecview.semantic.uimodel.UiTypedBindableDef
import org.eclipse.xtext.common.types.JvmDeclaredType
import java.util.Collection
class BindingInfoHelper {
@Inject
BindableTypeProvider typeOfBoundPropertyProvider;
def dispatch void collectBindingInfo(UiBindingEndpointAssignment assignment, BindingInfo info) {
var result = if(info !== null) info else new BindingInfo
if (assignment.typedBindableAlias !== null) {
assignment.typedBindableAlias.collectBindingInfo(result)
} else {
assignment.typedBindableDef.collectBindingInfo(result)
}
// on the way back up the structure, collect the path
if (assignment.path !== null) {
info.appendPath(assignment.path.toPathString)
info.typeOfBoundProperty = assignment.path.typeofLastSegment
info.deepestJvmField = assignment.path.operationofLastSegment
val pathType = assignment.path.typeofSecondLastSegment
if (info.typeForBinding === null && pathType !== null) {
info.typeForBinding = pathType
}
}
}
def dispatch void collectBindingInfo(UiBeanSlot slot, BindingInfo info) {
info.bindingRoot = slot
info.typeForBinding = slot.jvmType?.type
}
def dispatch void collectBindingInfo(UiBindingEndpointAlias alias, BindingInfo info) {
alias.endpoint.collectBindingInfo(info)
}
def dispatch void collectBindingInfo(UiTypedBindableDef definition, BindingInfo info) {
// must be the last element
info.typeForBinding = typeOfBoundPropertyProvider.getType(definition)
info.bindingRoot = definition.rawBindableOfLastSegment
val bindingMethod = definition.method
if (bindingMethod !== null) {
if (!bindingMethod.targetName.nullOrEmpty) {
info.appendPath(bindingMethod.targetName)
} else {
info.appendPath(bindingMethod.name)
}
}
}
def dispatch void collectBindingInfo(UiCommandBindableDef definition, BindingInfo info) {
// must be the last element
info.typeForBinding = typeOfBoundPropertyProvider.getType(definition)
info.bindingRoot = definition.command
}
def dispatch void collectBindingInfo(UiBindingExpression definition, BindingInfo info) {
throw new UnsupportedOperationException
}
/**
* @param embeddable the embeddable
* @return all bindings, where the embeddable is a raw bindable. If binding alias is used, this method can not return these bindings.
*/
def List<UiBinding> findBindings(UiEmbeddable embeddable) {
val result = <UiBinding>newArrayList()
val uiModel = embeddable.uiModel
for (EObject object : EcoreUtil.getAllContents(uiModel, true).toIterable) {
if (object instanceof UiTypedBindableDef) {
if (object.rawBindable === embeddable) {
val UiBinding found = findBinding(object as UiTypedBindableDef)
if (found !== null) {
result += found
}
}
}
}
return result
}
/**
* Tries to find the UiBinding in the container hierarchy of the given binding defintion.
* @param bindableDef the binding definition
* @return the UiBinding, otherwise null
*/
def UiBinding findBinding(UiTypedBindableDef bindableDef) {
var parent = bindableDef.eContainer
while (parent !== null) {
if (parent instanceof UiBinding) {
return parent
} else {
parent = parent.eContainer
}
}
return null
}
/**
* Returns all opposite binding endpoints, that share a binding with the embeddable.<br>
* For instance:<br>
* bind customer.name --&gt; [textField].value<br>
* In this case <code>textField</code> is given and the endpoint for <code>customer.name</code> is returned
* @param embeddable the embeddable
* @param propertyName the property name
* @return all opposite binding endpoints, that share a binding with the embeddable.
*/
def List<UiBindingEndpointAssignment> findOppositeEndpointAssignments(UiEmbeddable embeddable, String propertyName) {
val result = <UiBindingEndpointAssignment>newArrayList()
val uiModel = embeddable.uiModel
for (EObject object : EcoreUtil.getAllContents(uiModel, true).toIterable) {
if (object instanceof UiTypedBindableDef) {
if (propertyName === null || object.method !== null && object.method.name !== null && object.method.name.equals(propertyName)) {
if (object.rawBindable === embeddable || object.rawBindableOfLastSegment === embeddable) {
val UiBindingEndpointAssignment found = findOppositeEndpointAssignment(
object as UiTypedBindableDef)
if (found !== null) {
result += found
}
}
}
}
}
return result
}
/**
* Returns the opposite binding endpoint, that share a binding with the embeddable.<br>
* For instance:<br>
* bind customer.name --&gt; [textField].value<br>
* In this case <code>textField</code> is given and the endpoint for <code>customer.name</code> is returned
* @param embeddable the embeddable
* @param propertyName the property name
* @return the opposite binding endpoint, that share a binding with the embeddable.
*/
def List<JvmOperation> findBoundOppositeJvmOperations(UiEmbeddable embeddable, String propertyName) {
val result = <JvmOperation>newArrayList()
for (UiBindingEndpointAssignment assignment : findOppositeEndpointAssignments(embeddable, propertyName)) {
val BindingInfo info = new BindingInfo
collectBindingInfo(assignment, info)
result += info.deepestJvmField
}
return result
}
/**
* Returns the opposite binding endpoint, that share a binding with the embeddable.<br>
* For instance:<br>
* bind customer.name --&gt; [textField].value<br>
* In this case <code>textField</code> is given and the endpoint for <code>customer.name</code> is returned
* @param bindableDef the binding definition
* @return the opposite binding endpoint, that share a binding with the embeddable.
*/
def UiBindingEndpointAssignment findOppositeEndpointAssignment(UiTypedBindableDef bindableDef) {
var EObject child = bindableDef
var parent = bindableDef.eContainer
while (parent !== null) {
if (parent instanceof UiBinding) {
if (parent.source === child) {
return parent.target as UiBindingEndpointAssignment
} else if (parent.target === child) {
return parent.source as UiBindingEndpointAssignment
}
} else {
child = parent
parent = child.eContainer
}
}
return null
}
/**
* Returns the package name of the eObject.
*
* @param eObject the object
* @return the package name of the eObject.
*/
def String getPackage(EObject eObject) {
if (eObject === null) {
return "";
}
if (eObject instanceof UiModel) {
return (eObject as UiModel).getPackageName();
} else {
return getPackage(eObject.eContainer());
}
}
/**
* Returns the UiModel of the eObject.
*
* @param eObject the object
* @return the UiModel of the eObject.
*/
def UiModel getUiModel(EObject eObject) {
if (eObject === null) {
return null;
}
if (eObject instanceof UiModel) {
return eObject as UiModel;
} else {
return getUiModel(eObject.eContainer());
}
}
public static class BindingInfo {
/**
* The type of the bound property. For nested bindings it is the last element available
*/
private JvmType typeOfBoundProperty
/**
* The type of the binding. For nested bindings it is the element before the bound property
*/
private JvmType typeForBinding
/**
* The deepest JvmOperation in the hierarchy. This field is used to bind.
*/
private JvmOperation deepestJvmField
/**
* The nested path using dot notation.
*/
private StringBuilder path = new StringBuilder
/**
* The element the binding should be installed on
*/
private EObject bindingRoot
/**
* Append the segment to the path.
*
* @param segment the segment
*/
def appendPath(String segment) {
if (segment.nullOrEmpty) {
return
}
if (path.length > 0) {
path.append(".")
}
path.append(segment)
}
def JvmType getTypeOfBoundProperty() {
return typeOfBoundProperty
}
def void setTypeOfBoundProperty(JvmType typeOfBoundProperty) {
this.typeOfBoundProperty = typeOfBoundProperty
}
def JvmType getTypeForBinding() {
return typeForBinding
}
def void setTypeForBinding(JvmType typeForBinding) {
this.typeForBinding = typeForBinding
}
def JvmOperation getDeepestJvmField() {
return deepestJvmField
}
def void setDeepestJvmField(JvmOperation typeOfBoundProperty) {
this.deepestJvmField = deepestJvmField
}
def EObject getBindingRoot() {
return bindingRoot
}
def void setBindingRoot(EObject bindingRoot) {
this.bindingRoot = bindingRoot
}
def StringBuilder getPath() {
return path
}
def boolean isNested() {
return path.toString.contains(".")
}
def boolean isCollection() {
if(typeForBinding instanceof JvmDeclaredType) {
return typeForBinding.extendedInterfaces.exists[it.qualifiedName.equals(Collection.canonicalName)]
}
return false
}
}
}