/*******************************************************************************
* 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.behavior.commands;
import java.util.HashMap;
import org.eclipse.emf.ecore.EObject;
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.ChoicePoint;
import org.eclipse.etrice.core.room.ChoicepointTerminal;
import org.eclipse.etrice.core.room.EntryPoint;
import org.eclipse.etrice.core.room.ExitPoint;
import org.eclipse.etrice.core.room.InitialTransition;
import org.eclipse.etrice.core.room.NonInitialTransition;
import org.eclipse.etrice.core.room.State;
import org.eclipse.etrice.core.room.StateGraph;
import org.eclipse.etrice.core.room.StateTerminal;
import org.eclipse.etrice.core.room.SubStateTrPointTerminal;
import org.eclipse.etrice.core.room.TrPoint;
import org.eclipse.etrice.core.room.TrPointTerminal;
import org.eclipse.etrice.core.room.Transition;
import org.eclipse.etrice.core.room.TransitionTerminal;
import org.eclipse.etrice.ui.behavior.support.ChoicePointSupport;
import org.eclipse.etrice.ui.behavior.support.ContextSwitcher;
import org.eclipse.etrice.ui.behavior.support.StateGraphSupport;
import org.eclipse.etrice.ui.behavior.support.StateSupport;
import org.eclipse.graphiti.datatypes.ILocation;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
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.algorithms.styles.Point;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.FreeFormConnection;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.ui.services.GraphitiUi;
public class PopulateDiagramCommand extends RecordingCommand {
private static final String INITIAL = "init";
private static final String STATE = "state:";
private static final String TP = "tp:";
private static final String CP = "cp:";
private static final String SEP = ".";
private ActorClass ac;
private Diagram diagram;
private IFeatureProvider fp;
public PopulateDiagramCommand(Diagram diag, ActorClass ac, TransactionalEditingDomain domain) {
super(domain);
this.diagram = diag;
this.ac = ac;
IDiagramTypeProvider dtp = GraphitiUi.getExtensionManager().createDiagramTypeProvider(diagram, "org.eclipse.etrice.ui.behavior.diagramTypeProvider"); //$NON-NLS-1$
fp = dtp.getFeatureProvider();
}
@Override
protected void doExecute() {
fp.link(diagram, ac);
// we use a temporary structure to create the whole tree
StateGraphContext tree = StateGraphContext.createContextTree(ac);
addStateGraph(tree, diagram);
ContextSwitcher.switchTop(diagram);
}
private void addStateGraph(StateGraphContext ctx, ContainerShape parent) {
AddContext addContext = new AddContext();
addContext.setNewObject(ctx.getStateGraph());
addContext.setTargetContainer(parent);
addContext.setX(StateGraphSupport.MARGIN);
addContext.setY(StateGraphSupport.MARGIN);
ContainerShape sgShape = (ContainerShape) fp.addIfPossible(addContext);
if (sgShape==null)
return;
final HashMap<String, Anchor> node2anchor = new HashMap<String, Anchor>();
addInitialPointIff(ctx.getStateGraph(), sgShape, node2anchor);
addTransitionPoints(ctx.getStateGraph(), sgShape, node2anchor);
addStates(ctx.getStateGraph(), sgShape, node2anchor);
addChoicePoints(ctx.getStateGraph(), sgShape, node2anchor);
for (StateGraphContext sub : ctx.getChildren()) {
addStateGraph(sub, parent);
}
getSubTpAnchors(sgShape, node2anchor);
addTransitions(ctx.getStateGraph(), sgShape, node2anchor);
}
/**
* @param sgShape
* @param node2anchor
*/
private void getSubTpAnchors(ContainerShape sgShape, HashMap<String, Anchor> node2anchor) {
for (Shape childShape : sgShape.getChildren()) {
EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(childShape);
if (bo instanceof State)
getAnchors((State) bo, childShape, node2anchor);
}
}
private void addTransitions(StateGraph ctx, ContainerShape sgShape,
HashMap<String, Anchor> node2anchor) {
for (Transition trans : ctx.getTransitions()) {
String from = (trans instanceof InitialTransition)? INITIAL:getKey(((NonInitialTransition)trans).getFrom(), ctx);
String to = getKey(trans.getTo(), ctx);
Anchor src = node2anchor.get(from);
Anchor dst = node2anchor.get(to);
assert(src!=null && dst!=null): "transition enpoints must be present";
AddConnectionContext context = new AddConnectionContext(src, dst);
context.setNewObject(trans);
PictogramElement pe = fp.addIfPossible(context);
if (src==dst && pe instanceof FreeFormConnection) {
FreeFormConnection conn = (FreeFormConnection) pe;
ILocation begin = Graphiti.getPeService().getLocationRelativeToDiagram(conn.getStart());
Point pt = Graphiti.getGaService().createPoint(begin.getX(), begin.getY()+StateGraphSupport.MARGIN*3);
conn.getBendpoints().add(pt);
}
}
}
private void addTransitionPoints(StateGraph ctx, ContainerShape sgShape,
HashMap<String, Anchor> node2anchor) {
int width = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getWidth();
int n = ctx.getTrPoints().size();
int delta = width/(n+1);
int pos = delta;
for (TrPoint tp : ctx.getTrPoints()) {
addTrPoint(tp, ctx, sgShape, pos+StateSupport.MARGIN, node2anchor);
pos += delta;
}
}
private void addTrPoint(TrPoint tp, StateGraph sg, ContainerShape sgShape,
int pos, HashMap<String, Anchor> node2anchor) {
AddContext addContext = new AddContext();
addContext.setNewObject(tp);
addContext.setTargetContainer(sgShape);
addContext.setX(pos);
addContext.setY(0);
ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext);
assert(!pe.getAnchors().isEmpty()): "transition point should have an anchor";
node2anchor.put(getKey(tp, sg), pe.getAnchors().get(0));
}
private void addStates(StateGraph sg, ContainerShape sgShape,
HashMap<String, Anchor> node2anchor) {
int width = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getWidth();
int n = sg.getStates().size();
int delta = width/(n+1);
int pos = delta;
for (State s : sg.getStates()) {
addState(s, sg, sgShape, pos+StateSupport.MARGIN, node2anchor);
pos += delta;
}
}
private void addState(State s, StateGraph sg, ContainerShape sgShape,
int pos, HashMap<String, Anchor> node2anchor) {
AddContext addContext = new AddContext();
addContext.setNewObject(s);
addContext.setTargetContainer(sgShape);
addContext.setX(pos);
addContext.setY(StateGraphSupport.DEFAULT_SIZE_Y/4);
ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext);
assert(pe!=null): "state should have been created";
assert(!pe.getAnchors().isEmpty()): "state should have an anchor";
}
private void addChoicePoints(StateGraph sg, ContainerShape sgShape,
HashMap<String, Anchor> node2anchor) {
int width = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getWidth();
int n = sg.getChPoints().size();
int delta = width/(n+1);
int pos = delta;
for (ChoicePoint cp : sg.getChPoints()) {
addChoicePoint(cp, sg, sgShape, pos+ChoicePointSupport.ITEM_SIZE, node2anchor);
pos += delta;
}
}
private void addChoicePoint(ChoicePoint cp, StateGraph sg, ContainerShape sgShape,
int pos, HashMap<String, Anchor> node2anchor) {
AddContext addContext = new AddContext();
addContext.setNewObject(cp);
addContext.setTargetContainer(sgShape);
addContext.setX(pos);
addContext.setY(StateGraphSupport.DEFAULT_SIZE_Y/2);
ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext);
assert(pe!=null): "choice point should have been created";
assert(!pe.getAnchors().isEmpty()): "choice point should have an anchor";
node2anchor.put(getKey(cp, sg), pe.getAnchors().get(0));
}
private void addInitialPointIff(StateGraph sg, ContainerShape sgShape,
HashMap<String, Anchor> node2anchor) {
boolean hasInitialTransition = false;
for (Transition t : sg.getTransitions()) {
if (t instanceof InitialTransition) {
hasInitialTransition = true;
break;
}
}
if (!hasInitialTransition)
return;
AddContext addContext = new AddContext();
addContext.setNewObject(sg);
addContext.setTargetContainer(sgShape);
addContext.setX(3*StateGraphSupport.MARGIN);
addContext.setY(3*StateGraphSupport.MARGIN);
ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext);
assert(pe!=null): "initial point should have been created";
assert(!pe.getAnchors().isEmpty()): "initial point should have an anchor";
node2anchor.put(INITIAL, pe.getAnchors().get(0));
}
private void getAnchors(State state, PictogramElement stateShape,
final HashMap<String, Anchor> node2anchor) {
if (stateShape instanceof ContainerShape) {
node2anchor.put(getKey(state, null), ((ContainerShape)stateShape).getAnchors().get(0));
for (Shape child : ((ContainerShape) stateShape).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 EntryPoint || obj instanceof ExitPoint) {
node2anchor.put(getKey(obj, null), childShape.getAnchors().get(0));
}
}
}
}
}
}
}
private static String getKey(EObject obj, StateGraph sg) {
if (obj instanceof TrPoint) {
TrPoint tp = (TrPoint) obj;
if (tp.eContainer()==sg)
return TP+tp.getName();
else {
if (tp.eContainer().eContainer() instanceof State) {
State s = (State) tp.eContainer().eContainer();
return TP+tp.getName()+SEP+s.getName();
}
else {
assert(false): "State expected";
}
}
}
else if (obj instanceof State) {
return STATE+((State)obj).getName();
}
else if (obj instanceof ChoicePoint) {
return CP+((ChoicePoint)obj).getName();
}
else if (obj instanceof TransitionTerminal) {
TransitionTerminal tt = (TransitionTerminal) obj;
if (tt instanceof ChoicepointTerminal) {
return CP+((ChoicepointTerminal)tt).getCp().getName();
}
else if (tt instanceof StateTerminal) {
return STATE+((StateTerminal)tt).getState().getName();
}
else if (tt instanceof SubStateTrPointTerminal) {
SubStateTrPointTerminal sstt = (SubStateTrPointTerminal) tt;
return TP+sstt.getTrPoint().getName()+SEP+sstt.getState().getName();
}
else if (tt instanceof TrPointTerminal) {
return TP+((TrPointTerminal)tt).getTrPoint().getName();
}
else {
assert(false): "unexpected sub type";
}
}
assert(false): "unexpected type";
return null;
}
}