blob: 99754193104485c830a58954961644098b8ca9db [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 protos software gmbh (http://www.protos.de).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* CONTRIBUTORS:
* Thomas Schuetz and Henrik Rentz-Reichert (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.ui.structure.support;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.etrice.core.room.ActorContainerClass;
import org.eclipse.etrice.core.room.ActorContainerRef;
import org.eclipse.etrice.core.room.Binding;
import org.eclipse.etrice.core.room.BindingEndPoint;
import org.eclipse.etrice.core.room.CompoundProtocolClass;
import org.eclipse.etrice.core.room.GeneralProtocolClass;
import org.eclipse.etrice.core.room.Port;
import org.eclipse.etrice.core.room.RoomFactory;
import org.eclipse.etrice.core.room.StructureClass;
import org.eclipse.etrice.ui.common.base.support.BaseToolBehaviorProvider;
import org.eclipse.etrice.ui.common.base.support.CantRemoveFeature;
import org.eclipse.etrice.ui.common.base.support.ChangeAwareCreateConnectionFeature;
import org.eclipse.etrice.ui.common.base.support.ChangeAwareCustomFeature;
import org.eclipse.etrice.ui.common.base.support.DeleteWithoutConfirmFeature;
import org.eclipse.etrice.ui.structure.ImageProvider;
import org.eclipse.etrice.ui.structure.dialogs.SubProtocolSelectionDialog;
import org.eclipse.etrice.ui.structure.support.context.ConnectionUpdateContext;
import org.eclipse.etrice.ui.structure.support.context.InitialAddConnectionContext;
import org.eclipse.etrice.ui.structure.support.feature.ConnectionUpdateFeature;
import org.eclipse.etrice.ui.structure.support.provider.ConnectionProvider;
import org.eclipse.etrice.ui.structure.support.provider.DecorationProvider;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.ICreateConnectionFeature;
import org.eclipse.graphiti.features.IDeleteFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.IReconnectionFeature;
import org.eclipse.graphiti.features.IRemoveFeature;
import org.eclipse.graphiti.features.IUpdateFeature;
import org.eclipse.graphiti.features.context.IAddConnectionContext;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.context.ICreateConnectionContext;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.context.IDeleteContext;
import org.eclipse.graphiti.features.context.IDoubleClickContext;
import org.eclipse.graphiti.features.context.IReconnectionContext;
import org.eclipse.graphiti.features.context.IRemoveContext;
import org.eclipse.graphiti.features.context.IUpdateContext;
import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
import org.eclipse.graphiti.features.context.impl.ReconnectionContext;
import org.eclipse.graphiti.features.custom.ICustomFeature;
import org.eclipse.graphiti.features.impl.AbstractAddFeature;
import org.eclipse.graphiti.features.impl.DefaultReconnectionFeature;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.algorithms.Polyline;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.services.IGaService;
import org.eclipse.graphiti.services.IPeCreateService;
import org.eclipse.graphiti.tb.IToolBehaviorProvider;
import org.eclipse.graphiti.ui.features.DefaultFeatureProvider;
import org.eclipse.graphiti.util.ColorConstant;
import org.eclipse.graphiti.util.IColorConstant;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
public class BindingSupport {
public static final IColorConstant LINE_COLOR = new ColorConstant(0, 0, 0);
public static final IColorConstant INHERITED_COLOR = new ColorConstant(100, 100, 100);
static class FeatureProvider extends DefaultFeatureProvider {
private class CreateFeature extends ChangeAwareCreateConnectionFeature {
public CreateFeature(IFeatureProvider fp) {
super(fp, "Binding", "create Binding");
}
@Override
public String getCreateImageId() {
return ImageProvider.IMG_BINDING;
}
@Override
public boolean canCreate(ICreateConnectionContext context) {
IFeatureProvider featureProvider = getFeatureProvider();
Port src = SupportUtil.getInstance().getPort(context.getSourceAnchor(), featureProvider);
Port tgt = SupportUtil.getInstance().getPort(context.getTargetAnchor(), featureProvider);
ActorContainerRef srcRef = SupportUtil.getInstance().getRef(context.getSourceAnchor(), featureProvider);
if (src==null || tgt==null) {
return false;
}
StructureClass ac = SupportUtil.getInstance().getParent(context, featureProvider);
if (ac==null) {
return false;
}
ActorContainerRef tgtRef = SupportUtil.getInstance().getRef(context.getTargetAnchor(), featureProvider);
return SupportUtil.getInstance().getValidationUtil().isConnectable(src, srcRef, null, tgt, tgtRef, null, ac, null, false).isOk();
}
public boolean canStartConnection(ICreateConnectionContext context) {
if (context.getSourceAnchor()==null)
return false;
Port src = SupportUtil.getInstance().getPort(context.getSourceAnchor(), getFeatureProvider());
boolean canStart = src!=null;
if (canStart) {
ActorContainerRef ref = SupportUtil.getInstance().getRef(context.getSourceAnchor(), getFeatureProvider());
if (ref==null) {
// this port is local, i.e. owned by the parent itself
ActorContainerClass acc = (ActorContainerClass) src.eContainer();
if (!SupportUtil.getInstance().getValidationUtil().isConnectable(src, null, acc).isOk())
canStart = false;
}
else {
StructureClass acc = (StructureClass) ref.eContainer();
if (!SupportUtil.getInstance().getValidationUtil().isConnectable(src, ref, acc).isOk())
canStart = false;
}
}
return canStart;
}
@Override
public void attachedToSource(ICreateConnectionContext context) {
Port src = SupportUtil.getInstance().getPort(context.getSourceAnchor(), getFeatureProvider());
ActorContainerRef ref = SupportUtil.getInstance().getRef(context.getSourceAnchor(), getFeatureProvider());
StructureClass sc = SupportUtil.getInstance().getParent(context, getFeatureProvider());
beginHighLightMatches(sc, src, ref);
}
@Override
public void canceledAttaching(ICreateConnectionContext context) {
endHighLightMatches();
}
@Override
public void endConnecting() {
endHighLightMatches();
}
private void beginHighLightMatches(StructureClass sc, Port src, ActorContainerRef srcRef) {
if (src==null)
return;
ContainerShape scContainer = (ContainerShape) getDiagram().getChildren().get(0);
for (Shape subShape : scContainer.getChildren()) {
Object bo = getBusinessObjectForPictogramElement(subShape);
if (bo instanceof Port) {
if (SupportUtil.getInstance().getValidationUtil().isConnectable(src, srcRef, null, (Port) bo, null, null, sc, null, false).isOk()) {
DecorationProvider.addAllowedPortShape(subShape);
getDiagramBehavior().refreshRenderingDecorators(subShape);
}
}
else if (bo instanceof ActorContainerRef) {
ActorContainerRef tgtRef = (ActorContainerRef) bo;
for (Shape subSubShape : ((ContainerShape)subShape).getChildren()) {
bo = getBusinessObjectForPictogramElement(subSubShape);
if (bo instanceof Port) {
if (SupportUtil.getInstance().getValidationUtil().isConnectable(src, srcRef, null, (Port) bo, tgtRef, null, sc, null, false).isOk()) {
DecorationProvider.addAllowedPortShape(subSubShape);
getDiagramBehavior().refreshRenderingDecorators(subSubShape);
}
}
}
}
}
}
private void endHighLightMatches() {
DecorationProvider.clearAllowedPortShapes();
getDiagramBehavior().refresh();
}
@Override
protected Connection doCreate(ICreateConnectionContext context) {
Connection newConnection = null;
endHighLightMatches();
IFeatureProvider featureProvider = getFeatureProvider();
Port src = SupportUtil.getInstance().getPort(context.getSourceAnchor(), featureProvider);
Port dst = SupportUtil.getInstance().getPort(context.getTargetAnchor(), featureProvider);
StructureClass sc = SupportUtil.getInstance().getParent(context, featureProvider);
if (src!=null && dst!=null && sc!=null) {
Binding bind = RoomFactory.eINSTANCE.createBinding();
BindingEndPoint ep1 = RoomFactory.eINSTANCE.createBindingEndPoint();
ActorContainerRef ar1 = SupportUtil.getInstance().getRef(context.getSourceAnchor(), featureProvider);
ep1.setPort(src);
ep1.setActorRef(ar1);
BindingEndPoint ep2 = RoomFactory.eINSTANCE.createBindingEndPoint();
ActorContainerRef ar2 = SupportUtil.getInstance().getRef(context.getTargetAnchor(), featureProvider);
ep2.setPort(dst);
ep2.setActorRef(ar2);
bind.setEndpoint1(ep1);
bind.setEndpoint2(ep2);
GeneralProtocolClass srcGPC = src.getProtocol();
GeneralProtocolClass dstGPC = dst.getProtocol();
if (srcGPC instanceof CompoundProtocolClass || dstGPC instanceof CompoundProtocolClass) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
SubProtocolSelectionDialog dlg = new SubProtocolSelectionDialog(shell, src, ar1, dst, ar2, null, sc);
if (dlg.open()!=Window.OK)
return null;
ep1.setSub(dlg.getSelected().getLeft());
ep2.setSub(dlg.getSelected().getRight());
}
sc.getBindings().add(bind);
AddConnectionContext addContext = new AddConnectionContext(context.getSourceAnchor(), context.getTargetAnchor());
addContext.setNewObject(bind);
newConnection = (Connection) featureProvider.addIfPossible(addContext);
}
return newConnection;
}
}
private class AddFeature extends AbstractAddFeature {
public AddFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canAdd(IAddContext context) {
if(context.getNewObject() instanceof Binding)
return true;
return false;
}
@Override
public PictogramElement add(IAddContext context) {
Binding bind = (Binding) context.getNewObject();
boolean inherited = isInherited(getDiagram(), bind);
IPeCreateService peCreateService = Graphiti.getPeCreateService();
// CONNECTION WITH POLYLINE
Connection connection = peCreateService.createFreeFormConnection(getDiagram());
if(context instanceof InitialAddConnectionContext){
ConnectionProvider cp = ((InitialAddConnectionContext)context).getConnectionProvider();
Anchor a1 = cp.getAnchor(bind.getEndpoint1());
Anchor a2 = cp.getAnchor(bind.getEndpoint2());
assert(a1 != null && a2 != null) : "start and end anchor must be present";
connection.setStart(a1);
connection.setEnd(a2);
} else {
IAddConnectionContext addConContext = (IAddConnectionContext) context;
connection.setStart(addConContext.getSourceAnchor());
connection.setEnd(addConContext.getTargetAnchor());
}
Graphiti.getPeService().setPropertyValue(connection, Constants.TYPE_KEY, Constants.BIND_TYPE);
IGaService gaService = Graphiti.getGaService();
Polyline polyline = gaService.createPolyline(connection);
polyline.setForeground(manageColor(inherited?INHERITED_COLOR:LINE_COLOR));
// create link and wire it
link(connection, bind);
// call update
updatePictogramElement(connection);
return connection;
}
}
private class ReconnectionFeature extends DefaultReconnectionFeature {
private boolean doneChanges = false;
public ReconnectionFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canReconnect(IReconnectionContext context) {
if (!super.canReconnect(context))
return false;
Binding bind = (Binding) getBusinessObjectForPictogramElement(context.getConnection());
if (isInherited(getDiagram(), bind))
return false;
Anchor asrc = context.getConnection().getStart();
Anchor atgt = context.getConnection().getEnd();
if (context.getReconnectType().equals(ReconnectionContext.RECONNECT_SOURCE))
asrc = context.getNewAnchor();
else
atgt = context.getNewAnchor();
IFeatureProvider featureProvider = getFeatureProvider();
Port src = SupportUtil.getInstance().getPort(asrc, featureProvider);
Port tgt = SupportUtil.getInstance().getPort(atgt, featureProvider);
ActorContainerRef srcRef = SupportUtil.getInstance().getRef(asrc, featureProvider);
if (src==null || tgt==null) {
return false;
}
StructureClass ac = SupportUtil.getInstance().getParent(getDiagram(), featureProvider);
if (ac==null) {
return false;
}
ActorContainerRef tgtRef = SupportUtil.getInstance().getRef(atgt, featureProvider);
return SupportUtil.getInstance().getValidationUtil().isConnectable(
src, srcRef, bind.getEndpoint1().getSub(),
tgt, tgtRef, bind.getEndpoint2().getSub(),
ac, bind, true).isOk();
}
@Override
public void postReconnect(IReconnectionContext context) {
super.postReconnect(context);
IFeatureProvider featureProvider = getFeatureProvider();
Port src = SupportUtil.getInstance().getPort(context.getConnection().getStart(), featureProvider);
Port dst = SupportUtil.getInstance().getPort(context.getConnection().getEnd(), featureProvider);
StructureClass sc = SupportUtil.getInstance().getParent(getDiagram(), featureProvider);
if (src!=null && dst!=null && sc!=null) {
Binding bind = (Binding) getBusinessObjectForPictogramElement(context.getConnection());
BindingEndPoint ep1 = RoomFactory.eINSTANCE.createBindingEndPoint();
ActorContainerRef ar1 = SupportUtil.getInstance().getRef(context.getConnection().getStart(), featureProvider);
ep1.setPort(src);
ep1.setActorRef(ar1);
BindingEndPoint ep2 = RoomFactory.eINSTANCE.createBindingEndPoint();
ActorContainerRef ar2 = SupportUtil.getInstance().getRef(context.getConnection().getEnd(), featureProvider);
ep2.setPort(dst);
ep2.setActorRef(ar2);
GeneralProtocolClass srcGPC = src.getProtocol();
GeneralProtocolClass dstGPC = dst.getProtocol();
if (srcGPC instanceof GeneralProtocolClass || dstGPC instanceof GeneralProtocolClass) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
SubProtocolSelectionDialog dlg = new SubProtocolSelectionDialog(shell, src, ar1, dst, ar2, bind, sc);
if (dlg.open()!=Window.OK)
return;
ep1.setSub(dlg.getSelected().getLeft());
ep2.setSub(dlg.getSelected().getRight());
}
bind.setEndpoint1(ep1);
bind.setEndpoint2(ep2);
doneChanges = true;
}
}
@Override
public boolean hasDoneChanges() {
return doneChanges ;
}
}
private class UpdateFeature extends ConnectionUpdateFeature {
public UpdateFeature(IFeatureProvider fp) {
super(fp);
}
@Override
protected boolean canUpdate(EObject bo, PictogramElement pe) {
return bo instanceof Binding;
}
@Override
protected boolean update(EObject bo, IUpdateContext context) {
boolean success = super.update(bo, context);
Connection conn = (Connection) context.getPictogramElement();
if(context instanceof ConnectionUpdateContext){
ConnectionProvider cp = ((ConnectionUpdateContext) context).getConnectionProvider();
Binding bind = (Binding)bo;
Anchor newStart = cp.getAnchor(bind.getEndpoint1());
Anchor newEnd = cp.getAnchor(bind.getEndpoint2());
assert(newStart != null && newEnd != null) : "start and end anchor must be not null";
if(newStart != conn.getStart())
conn.setStart(newEnd);
if(newEnd != conn.getEnd())
conn.setEnd(newEnd);
}
return success;
}
}
private class DeleteFeature extends DeleteWithoutConfirmFeature {
public DeleteFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canDelete(IDeleteContext context) {
EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(context.getPictogramElement());
if (bo instanceof Binding) {
Binding b = (Binding) bo;
if (isInherited(getDiagram(), b))
return false;
}
return true;
}
}
private static class PropertyFeature extends ChangeAwareCustomFeature {
public PropertyFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public String getName() {
return "Edit Binding...";
}
@Override
public String getDescription() {
return "Edit Binding Properties";
}
public boolean canExecute(ICustomContext context) {
return getBusinessObjectForPictogramElement(context.getPictogramElements()[0]) instanceof Binding;
}
@Override
public boolean doExecute(ICustomContext context) {
Binding bind = (Binding) getBusinessObjectForPictogramElement(context.getPictogramElements()[0]);
StructureClass sc = (StructureClass) bind.eContainer();
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
SubProtocolSelectionDialog dlg = new SubProtocolSelectionDialog(
shell,
bind.getEndpoint1().getPort(), bind.getEndpoint1().getActorRef(),
bind.getEndpoint2().getPort(), bind.getEndpoint2().getActorRef(),
bind, sc);
if (dlg.open()==Window.OK){
bind.getEndpoint1().setSub(dlg.getSelected().getLeft());
bind.getEndpoint2().setSub(dlg.getSelected().getRight());
return true;
}
return false;
}
}
private IFeatureProvider fp;
public FeatureProvider(IDiagramTypeProvider dtp, IFeatureProvider fp) {
super(dtp);
this.fp = fp;
}
private boolean isInherited(Diagram diag, Binding b) {
StructureClass ac = (StructureClass) Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(diag.getChildren().get(0));
return (b.eContainer()!=ac);
}
@Override
public ICreateConnectionFeature[] getCreateConnectionFeatures() {
return new ICreateConnectionFeature[] { new CreateFeature(fp) };
}
@Override
public IAddFeature getAddFeature(IAddContext context) {
return new AddFeature(fp);
}
@Override
public IUpdateFeature getUpdateFeature(IUpdateContext context) {
return new UpdateFeature(fp);
}
@Override
public IReconnectionFeature getReconnectionFeature(IReconnectionContext context) {
return new ReconnectionFeature(fp);
}
@Override
public IRemoveFeature getRemoveFeature(IRemoveContext context) {
return new CantRemoveFeature(fp);
}
@Override
public IDeleteFeature getDeleteFeature(IDeleteContext context) {
return new DeleteFeature(fp);
}
@Override
public ICustomFeature[] getCustomFeatures(ICustomContext context) {
return new ICustomFeature[] { new PropertyFeature(fp) };
}
}
class BehaviorProvider extends BaseToolBehaviorProvider {
@Override
public Object getToolTip(GraphicsAlgorithm ga) {
// if this is called we know there is a business object!=null
PictogramElement pe = ga.getPictogramElement();
if (pe instanceof ConnectionDecorator)
pe = (PictogramElement) pe.eContainer();
EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(pe);
if (bo instanceof Binding) {
Binding bind = (Binding) bo;
return SupportUtil.getInstance().getRoomNameProvider().getDisplayName(bind);
}
return super.getToolTip(ga);
}
@Override
public ICustomFeature getDoubleClickFeature(IDoubleClickContext context) {
return new FeatureProvider.PropertyFeature(getDiagramTypeProvider().getFeatureProvider());
}
public BehaviorProvider(IDiagramTypeProvider dtp) {
super(dtp);
}
}
private FeatureProvider pfp;
private BehaviorProvider tbp;
public BindingSupport(IDiagramTypeProvider dtp, IFeatureProvider fp) {
pfp = new FeatureProvider(dtp,fp);
tbp = new BehaviorProvider(dtp);
}
public IFeatureProvider getFeatureProvider() {
return pfp;
}
public IToolBehaviorProvider getToolBehaviorProvider() {
return tbp;
}
}