| /******************************************************************************* |
| * Copyright (c) 2012 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: |
| * Henrik Rentz-Reichert (initial contribution) |
| * |
| *******************************************************************************/ |
| |
| package org.eclipse.etrice.ui.behavior.fsm.support; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; |
| import org.eclipse.etrice.core.fsm.fSM.ModelComponent; |
| import org.eclipse.etrice.core.fsm.fSM.State; |
| import org.eclipse.etrice.core.fsm.fSM.StateGraph; |
| import org.eclipse.etrice.core.fsm.fSM.StateGraphItem; |
| import org.eclipse.etrice.core.fsm.fSM.StateGraphNode; |
| import org.eclipse.etrice.core.fsm.fSM.TrPoint; |
| import org.eclipse.etrice.core.fsm.fSM.Transition; |
| import org.eclipse.etrice.core.fsm.naming.FSMNameProvider; |
| import org.eclipse.etrice.ui.behavior.fsm.commands.StateGraphContext; |
| import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; |
| import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase; |
| import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; |
| import org.eclipse.graphiti.mm.algorithms.Text; |
| import org.eclipse.graphiti.mm.algorithms.styles.Point; |
| 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.FreeFormConnection; |
| import org.eclipse.graphiti.mm.pictograms.Shape; |
| import org.eclipse.graphiti.services.Graphiti; |
| import org.eclipse.graphiti.services.ILinkService; |
| |
| import com.google.inject.Injector; |
| |
| /** |
| * @author Henrik Rentz-Reichert (initial contribution) |
| * |
| */ |
| public class DefaultPositionProvider implements IPositionProvider { |
| private static class Position { |
| double x; |
| double y; |
| double sx; |
| double sy; |
| } |
| |
| private HashMap<String, Position> obj2pos = new HashMap<String, Position>(); |
| private HashMap<String, Position> subObj2pos = new HashMap<String, Position>(); |
| private HashMap<String, ArrayList<Position>> trans2points = new HashMap<String, ArrayList<Position>>(); |
| private HashMap<String, StateGraph> initialPointObj = new HashMap<String, StateGraph>(); |
| private HashMap<String, PosAndSize> sg2sz = new HashMap<String, PosAndSize>(); |
| private double scaleX; |
| private double scaleY; |
| private int posX, posY; |
| |
| public DefaultPositionProvider(ModelComponent mc, Injector injector) { |
| mapPositions(mc.getBase(), injector); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.etrice.ui.behavior.support.IPositionProvider#setScale(double, double) |
| */ |
| @Override |
| public void setScale(double sx, double sy) { |
| this.scaleX = sx; |
| this.scaleY = sy; |
| } |
| |
| @Override |
| public void setPosition(int x, int y){ |
| this.posX = x; |
| this.posY = y; |
| } |
| |
| public PosAndSize getPosition(StateGraphNode node) { |
| Position pos = obj2pos.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(node)); |
| if (pos==null) |
| return null; |
| |
| int margin = getMargin(node); |
| PosAndSize pt = new PosAndSize( |
| (int) (pos.x * scaleX) + margin, |
| (int) (pos.y * scaleY) + margin, |
| (int) (pos.sx * scaleX), |
| (int) (pos.sy * scaleY) |
| ); |
| return pt; |
| } |
| |
| @Override |
| public PosAndSize getPosition(StateGraph graph) { |
| EObject container = graph.eContainer(); |
| String path = "#init"; |
| if(container instanceof StateGraphNode) |
| path = FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath((StateGraphNode)container) + path; |
| Position pos = obj2pos.get(path); |
| |
| if (pos==null) |
| return null; |
| |
| int margin = getMargin(graph); |
| PosAndSize pt = new PosAndSize( |
| (int) (pos.x * scaleX) + margin, |
| (int) (pos.y * scaleY) + margin, |
| (int) (pos.sx * scaleX), |
| (int) (pos.sy * scaleY) |
| ); |
| return pt; |
| } |
| |
| public List<Pos> getPoints(Transition trans) { |
| ArrayList<Pos> result = new ArrayList<Pos>(); |
| |
| ArrayList<Position> list = trans2points.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(trans)); |
| if (list!=null) { |
| int i = 0; |
| for (Position p : list) { |
| Pos pos = |
| new Pos( |
| (int) (p.x * scaleX) + ((i==0)?0:posX), |
| (int) (p.y * scaleY) + ((i==0)?0:posY) |
| ); |
| result.add(pos); |
| i++; |
| } |
| } |
| |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.etrice.ui.behavior.support.IPositionProvider#getPositions(java.util.List) |
| */ |
| @Override |
| public <T extends StateGraphNode> List<PosAndSize> getPositions(List<T> nodes) { |
| ArrayList<PosAndSize> result = new ArrayList<PosAndSize>(nodes.size()); |
| |
| if (nodes.isEmpty()) |
| return result; |
| |
| int n = 0; |
| for (T node : nodes) { |
| PosAndSize pt = getPosition(node); |
| result.add(pt); |
| if (pt==null) |
| n++; |
| } |
| |
| int delta = (int) (scaleX/(n+1)); |
| int pos = delta; |
| |
| int h = StateGraphSupport.MARGIN; |
| if (nodes.get(0) instanceof State) |
| h = StateGraphSupport.MARGIN + StateGraphSupport.DEFAULT_SIZE_Y/4; |
| else if (nodes.get(0) instanceof ChoicePoint) |
| h = StateGraphSupport.MARGIN + StateGraphSupport.DEFAULT_SIZE_Y/2; |
| else if (nodes.get(0) instanceof TrPoint) |
| h = StateGraphSupport.MARGIN; |
| else { |
| assert(false): "unexpected sub type"; |
| } |
| |
| for (int i=0; i<nodes.size(); ++i) { |
| if (result.get(i)==null) { |
| PosAndSize pt = new PosAndSize( |
| pos, |
| h, |
| 0, |
| 0 |
| ); |
| result.set(i, pt); |
| |
| pos += delta; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Load base class diagrams recursively and put midpoint positions relative to boundary rectangle into map. |
| * |
| * Positions are relative to the invisible rectangle. They are transformed to the border rectangle and normalized. |
| * |
| * @param mc |
| * @param obj2pos |
| */ |
| private void mapPositions(ModelComponent mc, Injector injector) { |
| if (mc==null) |
| return; |
| |
| DiagramAccessBase diagramAccess = injector.getInstance(DiagramAccessBase.class); |
| Diagram diagram = diagramAccess.getDiagram(mc); |
| if (diagram==null) |
| return; |
| |
| StateGraphContext tree = StateGraphContext.createContextTree(FSMSupportUtil.getInstance().getModelComponent(diagram), injector); |
| FSMNameProvider fsmNameProvider = FSMSupportUtil.getInstance().getFSMNameProvider(); |
| |
| ILinkService linkService = Graphiti.getLinkService(); |
| for (Shape sgShape : diagram.getChildren()) { |
| // this is the level of StateGraphs |
| if (sgShape instanceof ContainerShape) { |
| EObject obj = linkService.getBusinessObjectForLinkedPictogramElement(sgShape); |
| GraphicsAlgorithm borderRect = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0); |
| double width = borderRect.getWidth(); |
| double height = borderRect.getHeight(); |
| PosAndSize sz = new PosAndSize( |
| sgShape.getGraphicsAlgorithm().getX(), sgShape.getGraphicsAlgorithm().getY(), |
| borderRect.getWidth(), borderRect.getHeight()); |
| sg2sz.put(fsmNameProvider.getFullPath((StateGraph) obj), sz); |
| for (Shape sgItemShape : ((ContainerShape)sgShape).getChildren()) { |
| // this is the level of States, TrPoints and ChoicePoints |
| obj = linkService.getBusinessObjectForLinkedPictogramElement(sgItemShape); |
| GraphicsAlgorithm ga = sgItemShape.getGraphicsAlgorithm(); |
| if(ga==null) |
| continue; |
| int margin = 0; |
| String path = null; |
| if (obj instanceof StateGraphNode) { |
| StateGraphNode node = (StateGraphNode)obj; |
| margin = getMargin(node); |
| path = fsmNameProvider.getFullPath((StateGraphItem) obj); |
| |
| if(sgItemShape instanceof ContainerShape){ |
| // sub items |
| for(Shape childShape : ((ContainerShape)sgItemShape).getChildren()){ |
| EObject childObj = linkService.getBusinessObjectForLinkedPictogramElement(childShape); |
| if(childObj instanceof StateGraphItem){ |
| GraphicsAlgorithm childGa = childShape.getGraphicsAlgorithm(); |
| String childPath = fsmNameProvider.getFullPath((StateGraphItem) childObj); |
| if (childPath != null) { |
| Position pos = new Position(); |
| pos.x = childGa.getX() / (double) (ga.getWidth() - 2 * margin); |
| pos.y = childGa.getY() / (double) (ga.getHeight() - 2 * margin); |
| pos.sx = -1; |
| pos.sy = -1; |
| subObj2pos.put(childPath, pos); |
| } |
| } |
| } |
| } |
| } else if(obj instanceof StateGraph){ |
| StateGraph graph = (StateGraph)obj; |
| margin = getMargin(graph); |
| EObject container = graph.eContainer(); |
| path = "#init"; |
| if(container instanceof StateGraphNode) |
| path = fsmNameProvider.getFullPath((StateGraphNode)container) + path; |
| initialPointObj.put(path, graph); |
| } |
| if(path != null){ |
| Position pos = new Position(); |
| pos.x = ga.getX() / width; |
| pos.y = ga.getY() / height; |
| pos.sx = (ga.getWidth() - 2*margin) / width; |
| pos.sy = (ga.getHeight()- 2*margin) / height; |
| obj2pos.put(path, pos); |
| } |
| |
| // Entry and Exit Points on State borders are treated by the insertion of the State |
| } |
| } |
| } |
| |
| for (Connection conn : diagram.getConnections()) { |
| EObject obj = linkService.getBusinessObjectForLinkedPictogramElement(conn); |
| if (obj instanceof Transition) { |
| ConnectionDecorator cd = conn.getConnectionDecorators().get(1); |
| if (cd.getGraphicsAlgorithm() instanceof Text) { |
| Transition trans = (Transition) obj; |
| StateGraph sg = tree.getContext(trans).getStateGraph(); |
| |
| // graph size |
| PosAndSize sz = sg2sz.get(fsmNameProvider.getFullPath(sg)); |
| ArrayList<Position> points = new ArrayList<Position>(); |
| trans2points.put(fsmNameProvider.getFullPath((Transition) obj), points); |
| |
| // label position |
| Position pos = new Position(); |
| pos.x = cd.getGraphicsAlgorithm().getX() / ((double)sz.getWidth()); |
| pos.y = cd.getGraphicsAlgorithm().getY() / ((double)sz.getHeight()); |
| points.add(pos); |
| |
| if (conn instanceof FreeFormConnection) { |
| for (Point bp : ((FreeFormConnection) conn).getBendpoints()) { |
| pos = new Position(); |
| pos.x = (bp.getX() - sz.getX()) / ((double)sz.getWidth()); |
| pos.y = (bp.getY() - sz.getY()) / ((double)sz.getHeight()); |
| points.add(pos); |
| } |
| } |
| } |
| |
| } |
| } |
| |
| // recursion |
| mapPositions(mc.getBase(), injector); |
| } |
| |
| private int getMargin(StateGraphNode node) { |
| if (node instanceof State) |
| return StateSupport.MARGIN; |
| else if (node instanceof TrPoint) |
| return TrPointSupport.MARGIN; |
| |
| return 0; |
| } |
| |
| private int getMargin(StateGraph graph) { |
| return 0; |
| } |
| |
| public StateGraph getInitialPoint(StateGraph graph){ |
| EObject container = graph.eContainer(); |
| String path = "#init"; |
| if(container instanceof StateGraphNode) |
| path = FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath((StateGraphNode)container) + path; |
| return initialPointObj.get(path); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.etrice.ui.behavior.support.IPositionProvider#getGraphSize(org.eclipse.etrice.core.room.StateGraph) |
| */ |
| @Override |
| public PosAndSize getGraphPosAndSize(StateGraph sg) { |
| return sg2sz.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(sg)); |
| } |
| |
| @Override |
| public double[] getSubPosition(StateGraphNode subNode) { |
| Position pos = subObj2pos.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(subNode)); |
| if (pos==null) |
| return null; |
| |
| return new double[]{pos.x, pos.y}; |
| } |
| } |