/*******************************************************************************
* 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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* CONTRIBUTORS:
* Thomas Schuetz and Henrik Rentz-Reichert (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.ui.structure.commands;
import java.util.HashMap;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.etrice.core.room.ActorClass;
import org.eclipse.etrice.core.room.ActorContainerClass;
import org.eclipse.etrice.core.room.ActorContainerRef;
import org.eclipse.etrice.core.room.ActorRef;
import org.eclipse.etrice.core.room.Binding;
import org.eclipse.etrice.core.room.BindingEndPoint;
import org.eclipse.etrice.core.room.InterfaceItem;
import org.eclipse.etrice.core.room.LayerConnection;
import org.eclipse.etrice.core.room.LogicalSystem;
import org.eclipse.etrice.core.room.Port;
import org.eclipse.etrice.core.room.RefSAPoint;
import org.eclipse.etrice.core.room.RelaySAPoint;
import org.eclipse.etrice.core.room.SAPoint;
import org.eclipse.etrice.core.room.SPPRef;
import org.eclipse.etrice.core.room.SPPoint;
import org.eclipse.etrice.core.room.StructureClass;
import org.eclipse.etrice.core.room.SubSystemClass;
import org.eclipse.etrice.ui.structure.DiagramAccess;
import org.eclipse.etrice.ui.structure.support.ActorContainerRefSupport;
import org.eclipse.etrice.ui.structure.support.StructureClassSupport;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
import org.eclipse.graphiti.features.context.impl.AddContext;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
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.ui.services.GraphitiUi;
public class PopulateDiagramCommand extends RecordingCommand {
private static final String SEP = "#";
private StructureClass sc;
private Diagram diagram;
public PopulateDiagramCommand(Diagram diag, StructureClass sc, TransactionalEditingDomain domain) {
super(domain);
this.diagram = diag;
this.sc = sc;
}
@Override
protected void doExecute() {
IDiagramTypeProvider dtp = GraphitiUi.getExtensionManager().createDiagramTypeProvider(diagram, "org.eclipse.etrice.ui.structure.diagramTypeProvider"); //$NON-NLS-1$
IFeatureProvider featureProvider = dtp.getFeatureProvider();
AddContext addContext = new AddContext();
addContext.setNewObject(sc);
addContext.setTargetContainer(diagram);
addContext.setX(StructureClassSupport.MARGIN);
addContext.setY(StructureClassSupport.MARGIN);
final HashMap<String, Anchor> ifitem2anchor = new HashMap<String, Anchor>();
IAddFeature addFeature = featureProvider.getAddFeature(addContext);
if (addFeature!=null && addFeature.canAdd(addContext)) {
ContainerShape acShape = (ContainerShape) addFeature.add(addContext);
int width = acShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getWidth();
addInterfaceItems(acShape, width, featureProvider, ifitem2anchor);
// actor container references
if (sc instanceof ActorContainerClass) {
ActorContainerClass acc = (ActorContainerClass) sc;
EList<? extends ActorContainerRef> actorRefs = acc.getActorRefs();
addRefItems(actorRefs, acShape, width, featureProvider, ifitem2anchor);
}
else if (sc instanceof LogicalSystem) {
LogicalSystem sys = (LogicalSystem) sc;
EList<? extends ActorContainerRef> subSystems = sys.getSubSystems();
addRefItems(subSystems, acShape, width, featureProvider, ifitem2anchor);
}
// layer connections
for (LayerConnection lc : sc.getConnections()) {
addLayerConnection(lc, featureProvider, ifitem2anchor);
}
// base class items
if (sc instanceof ActorClass) {
ActorClass base = ((ActorClass) sc).getBase();
// add inherited ports and refs and bindings (and preserve layout)
if (base!=null)
addInheritedItems(base, acShape, ifitem2anchor, featureProvider);
}
// bindings
for (Binding bind : sc.getBindings()) {
addBinding(bind, featureProvider, ifitem2anchor);
}
}
}
protected void addInterfaceItems(ContainerShape acShape, int width,
IFeatureProvider featureProvider,
final HashMap<String, Anchor> port2anchor) {
if (sc instanceof ActorClass) {
ActorClass ac = (ActorClass) sc;
// interface spps and ports
int n = ac.getIfPorts().size() + ac.getIfSPPs().size();
int delta = width/(n+1);
int pos = delta;
for (SPPRef spp : ac.getIfSPPs()) {
addInterfaceItem(spp, acShape, pos, featureProvider, port2anchor);
pos += delta;
}
for (Port port : ac.getIfPorts()) {
addInterfaceItem(port, acShape, pos, featureProvider, port2anchor);
pos += delta;
}
// internal ports
n = ac.getIntPorts().size();
delta = width/(n+1);
pos = delta;
addPorts(ac.getIntPorts(), acShape, width, featureProvider, port2anchor);
}
else if (sc instanceof SubSystemClass) {
SubSystemClass ssc = (SubSystemClass) sc;
// interface spps and ports
int n = ssc.getRelayPorts().size() + ssc.getIfSPPs().size();
int delta = width/(n+1);
int pos = delta;
for (SPPRef spp : ssc.getIfSPPs()) {
addInterfaceItem(spp, acShape, pos, featureProvider, port2anchor);
pos += delta;
}
for (Port port : ssc.getRelayPorts()) {
addInterfaceItem(port, acShape, pos, featureProvider, port2anchor);
pos += delta;
}
}
}
protected void addRefItems(EList<? extends ActorContainerRef> actorRefs,
ContainerShape acShape, int width,
IFeatureProvider featureProvider, final HashMap<String, Anchor> port2anchor) {
int n = actorRefs.size();
int delta = width/(n+1);
int pos = delta;
for (ActorContainerRef ar : actorRefs) {
addRefItem(ar, acShape, pos, featureProvider, port2anchor);
pos += delta;
}
}
protected void addPorts(EList<Port> ifPorts, ContainerShape acShape,
int width, IFeatureProvider featureProvider, final HashMap<String, Anchor> port2anchor) {
int n = ifPorts.size();
int delta = width/(n+1);
int pos = delta;
for (Port port : ifPorts) {
addInterfaceItem(port, acShape, pos, featureProvider, port2anchor);
pos += delta;
}
}
protected void addRefItem(ActorContainerRef obj, ContainerShape acShape, int pos, IFeatureProvider featureProvider, final HashMap<String, Anchor> port2anchor) {
AddContext addContext = new AddContext();
addContext.setNewObject(obj);
addContext.setTargetContainer(acShape);
addContext.setX(pos+StructureClassSupport.MARGIN-(ActorContainerRefSupport.DEFAULT_SIZE_X/2+ActorContainerRefSupport.MARGIN));
addContext.setY(4*StructureClassSupport.MARGIN);
ContainerShape refShape = (ContainerShape) featureProvider.addIfPossible(addContext);
getAnchors(obj, refShape, port2anchor);
}
protected void addInterfaceItem(InterfaceItem item, ContainerShape acShape, int pos, IFeatureProvider featureProvider, final HashMap<String, Anchor> port2anchor) {
AddContext addContext = new AddContext();
addContext.setNewObject(item);
addContext.setTargetContainer(acShape);
addContext.setX(pos+StructureClassSupport.MARGIN);
addContext.setY(StructureClassSupport.MARGIN);
ContainerShape pe = (ContainerShape) featureProvider.addIfPossible(addContext);
assert(!pe.getAnchors().isEmpty()): "interface item should have an anchor";
port2anchor.put(SEP+item.getName(), pe.getAnchors().get(0));
}
protected void addBinding(Binding bind, IFeatureProvider featureProvider,
final HashMap<String, Anchor> port2anchor) {
String ep1 = getName(bind.getEndpoint1());
String ep2 = getName(bind.getEndpoint2());
Anchor a1 = port2anchor.get(ep1);
Anchor a2 = port2anchor.get(ep2);
assert(a1!=null && a2!=null): "ports for binding must be present";
AddConnectionContext context = new AddConnectionContext(a1, a2);
context.setNewObject(bind);
featureProvider.addIfPossible(context);
}
protected void addLayerConnection(LayerConnection lc, IFeatureProvider featureProvider,
final HashMap<String, Anchor> port2anchor) {
String ep1 = getName(lc.getFrom());
String ep2 = getName(lc.getTo());
Anchor a1 = port2anchor.get(ep1);
Anchor a2 = port2anchor.get(ep2);
assert(a1!=null && a2!=null): "ports for layer connection must be present";
AddConnectionContext context = new AddConnectionContext(a1, a2);
context.setNewObject(lc);
featureProvider.addIfPossible(context);
}
private void addInheritedItems(ActorClass ac, ContainerShape acShape, HashMap<String,Anchor> port2anchor, IFeatureProvider featureProvider) {
// we don't have to recurse since the base class diagram already contains all inherited items
Diagram refDiag = new DiagramAccess().getDiagram(ac);
ResourceSet rs = ac.eResource().getResourceSet();
if (!refDiag.getChildren().isEmpty()) {
ContainerShape refAcShape = (ContainerShape) refDiag.getChildren().get(0);
Object bo = featureProvider.getBusinessObjectForPictogramElement(refAcShape);
if (bo instanceof StructureClass) {
StructureClass extRefClass = (StructureClass) bo;
assert(extRefClass.getName().equals(ac.getName())): "actor class names must match";
int scaleX = refAcShape.getGraphicsAlgorithm().getWidth()/StructureClassSupport.DEFAULT_SIZE_X;
int scaleY = refAcShape.getGraphicsAlgorithm().getHeight()/StructureClassSupport.DEFAULT_SIZE_Y;
for (Shape childShape : refAcShape.getChildren()) {
bo = featureProvider.getBusinessObjectForPictogramElement(childShape);
if (bo instanceof Port) {
Port ownObject = (Port) getOwnObject((Port)bo, rs);
int x = childShape.getGraphicsAlgorithm().getX()/scaleX;
int y = childShape.getGraphicsAlgorithm().getY()/scaleY;
ContainerShape pe = addItem(ownObject, x/scaleX, y/scaleY, acShape, featureProvider);
assert(!pe.getAnchors().isEmpty()): "port must have an anchor";
port2anchor.put(SEP+ownObject.getName(), pe.getAnchors().get(0));
}
else if (bo instanceof ActorRef) {
ActorContainerRef ownObject = (ActorContainerRef) getOwnObject((ActorRef)bo, rs);
int x = childShape.getGraphicsAlgorithm().getX()/scaleX;
int y = childShape.getGraphicsAlgorithm().getY()/scaleY;
ContainerShape arShape = addItem(ownObject, x/scaleX, y/scaleY, acShape, featureProvider);
getAnchors(ownObject, arShape, port2anchor);
}
}
for (Connection conn : refDiag.getConnections()) {
bo = featureProvider.getBusinessObjectForPictogramElement(conn);
if (bo instanceof Binding) {
Binding bind = (Binding)getOwnObject((Binding)bo, rs);
addBinding(bind, featureProvider, port2anchor);
}
}
}
}
}
private ContainerShape addItem(EObject obj, int x, int y, ContainerShape container, IFeatureProvider featureProvider) {
AddContext addContext = new AddContext();
addContext.setNewObject(obj);
addContext.setTargetContainer(container);
addContext.setX(x);
addContext.setY(y);
ContainerShape newShape = (ContainerShape) featureProvider.addIfPossible(addContext);
assert(newShape!=null): "shape creation must succeed";
return newShape;
}
private EObject getOwnObject(EObject obj, ResourceSet rs) {
URI uri = EcoreUtil.getURI(obj);
EObject own = rs.getEObject(uri, true);
assert(own!=null): "own object must exist";
return own;
}
protected void getAnchors(ActorContainerRef acr, PictogramElement refShape,
final HashMap<String, Anchor> port2anchor) {
if (refShape instanceof ContainerShape) {
port2anchor.put(acr.getName()+SEP, ((ContainerShape)refShape).getAnchors().get(0));
for (Shape child : ((ContainerShape) refShape).getChildren()) {
if (child instanceof ContainerShape) {
ContainerShape childShape = (ContainerShape) child;
if (!childShape.getAnchors().isEmpty()) {
if (!childShape.getLink().getBusinessObjects().isEmpty()) {
EObject obj = childShape.getLink().getBusinessObjects().get(0);
if (obj instanceof Port) {
port2anchor.put(acr.getName()+SEP+((Port)obj).getName(), childShape.getAnchors().get(0));
}
if (obj instanceof SPPRef) {
port2anchor.put(acr.getName()+SEP+((SPPRef)obj).getName(), childShape.getAnchors().get(0));
}
}
}
}
}
}
}
private String getName(BindingEndPoint ep) {
String ar = ep.getActorRef()==null? "":ep.getActorRef().getName();
String p = ep.getPort().getName();
return ar+SEP+p;
}
private String getName(SAPoint sapt) {
if (sapt instanceof RelaySAPoint) {
return SEP+((RelaySAPoint)sapt).getRelay().getName();
}
else if (sapt instanceof RefSAPoint) {
RefSAPoint rpt = (RefSAPoint) sapt;
return rpt.getRef().getName()+SEP;
}
assert(false): "unexpected sub type";
return null;
}
private String getName(SPPoint sppt) {
return sppt.getRef().getName()+SEP+sppt.getService().getName();
}
}