/*******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, 2016, MontiCore, All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package de.monticore.genericgraphics.view.layout.kieler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.util.EList;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.swt.graphics.Font;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import com.google.common.collect.BiMap;
import de.cau.cs.kieler.core.kgraph.KEdge;
import de.cau.cs.kieler.core.kgraph.KGraphElement;
import de.cau.cs.kieler.core.kgraph.KLabel;
import de.cau.cs.kieler.core.kgraph.KLabeledGraphElement;
import de.cau.cs.kieler.core.kgraph.KNode;
import de.cau.cs.kieler.core.kgraph.KPort;
import de.cau.cs.kieler.core.properties.IProperty;
import de.cau.cs.kieler.core.properties.Property;
import de.cau.cs.kieler.kiml.LayoutContext;
import de.cau.cs.kieler.kiml.config.ILayoutConfig;
import de.cau.cs.kieler.kiml.config.VolatileLayoutConfig;
import de.cau.cs.kieler.kiml.klayoutdata.KEdgeLayout;
import de.cau.cs.kieler.kiml.klayoutdata.KLayoutDataFactory;
import de.cau.cs.kieler.kiml.klayoutdata.KPoint;
import de.cau.cs.kieler.kiml.klayoutdata.KShapeLayout;
import de.cau.cs.kieler.kiml.klayoutdata.impl.KEdgeLayoutImpl;
import de.cau.cs.kieler.kiml.klayoutdata.impl.KShapeLayoutImpl;
import de.cau.cs.kieler.kiml.options.EdgeLabelPlacement;
import de.cau.cs.kieler.kiml.options.EdgeType;
import de.cau.cs.kieler.kiml.options.LayoutOptions;
import de.cau.cs.kieler.kiml.ui.diagram.IDiagramLayoutManager;
import de.cau.cs.kieler.kiml.ui.diagram.LayoutMapping;
import de.cau.cs.kieler.kiml.util.KimlUtil;
import de.monticore.genericgraphics.GenericFormEditor;
import de.monticore.genericgraphics.GenericGraphicsEditor;
import de.monticore.genericgraphics.GenericGraphicsViewer;
import de.monticore.genericgraphics.controller.editparts.IMCConnectionEdgeEditPart;
import de.monticore.genericgraphics.controller.editparts.IMCEditPart;
import de.monticore.genericgraphics.controller.editparts.IMCGraphicalEditPart;
import de.monticore.genericgraphics.controller.editparts.IMCNodeEditPart;
import de.monticore.genericgraphics.controller.editparts.IMCShapeEditPart;
import de.monticore.genericgraphics.controller.editparts.IMCViewElementEditPart;
import de.monticore.genericgraphics.controller.editparts.connections.IMCConnectionEditPart;
import de.monticore.genericgraphics.controller.editparts.intern.TextConnectionLabelEditPart;
import de.monticore.genericgraphics.controller.views.outline.CombinedGraphicsOutlinePage;
import de.monticore.genericgraphics.model.ITextConnectionLabel;
import de.monticore.genericgraphics.model.graphics.IEdgeViewElement;
import de.monticore.genericgraphics.model.graphics.IShapeViewElement;
import de.monticore.genericgraphics.model.graphics.IViewElement;
import de.monticore.genericgraphics.model.impl.TextConnectionLabel;
import de.monticore.genericgraphics.view.figures.connections.MCBendpoint;
import de.monticore.genericgraphics.view.figures.connections.locators.ConnectionLocatorPosition;
import de.monticore.genericgraphics.view.layout.IConnectionType;
import de.se_rwth.commons.logging.Log;
/**
* <p>
* An implementation of {@link IDiagramLayoutManager}.
* </p>
* <p>
* Explanation: <br>
* The following methods need to be implemented (with javadoc explanation,
* ordered by call sequence):
* <ol>
* <li>{@link #supports(Object)}: Determine whether this layout manager is able
* to perform layout for the given object.</li>
* <li>{@link #getAdapterList()}: Returns the collection of adapter types
* handled by this factory.</li>
* <li>{@link #getAdapter(Object, Class)}: Returns an object which is an
* instance of the given class associated with the given object. Returns null if
* no such object can be found.</li>
* <li>{@link #buildLayoutGraph(IWorkbenchPart, Object)}: Build a KGraph
* instance for the given diagram. The resulting layout graph should reflect the
* structure of the original diagram. All graph elements must have KShapeLayouts
* or KEdgeLayouts attached, and their modification flags must be set to false.</li>
* <li>{@link #applyLayout(LayoutMapping, boolean, int)}: Apply the computed
* layout back to the diagram. Graph elements whose modification flag was not
* set during layout should be ignored.</li>
* </ol>
* </p>
* <p>
* This class works for {@link IMCEditPart IMCEditParts}. It iterates through
* all {@link IMCEditPart IMCEditParts} of the diagram and checks if they are
* {@link IMCViewElementEditPart IMCViewElementEditParts}. If it is a
* {@link IMCViewElementEditPart} the following elements are added to the
* KGraph:
* <ul>
* <li>{@link IMCShapeEditPart}: A {@link KNode} with {@link KShapeLayout} for
* {@link IShapeViewElement IShapeViewElements}</li>
* <li>{@link IMCConnectionEdgeEditPart}: A {@link KEdge} with
* {@link KEdgeLayout} for {@link IEdgeViewElement IEdgeViewElements}</li>
* <li>{@link ITextConnectionLabel IConnectionLabels}A {@link KLabel} with
* {@link KShapeLayout} for {@link IShapeViewElement IShapeViewElements}</li>
* </ul>
* Note: when the computed layout is applied, all bendpoints of a connections
* are relative Bendpoints, ignoring if they were absolute bendpoints before. If
* you want to change this behavior, look at the command creation in the
* {@link MCDiagramLayoutManager#applyLayout(LayoutMapping, boolean, int)}
* method. THe {@link ApplyLayoutCommand} has a flag to decide whether to use
* absolute or relative bendpoints.
* </p>
* <p>
* This class should serve as an example for future implementations.
* </p>
* <p>
* Not supported at the moment:
* <ul>
* <li>move anchors according to algorithm computation</li>
* <li>hierarchical nested view elements</li>
* </ul>
*
* @author Tim Enger
*/
public class MCDiagramLayoutManager implements IDiagramLayoutManager<IMCEditPart> {
/** editor part of the currently layouted diagram. */
private IProperty<GenericGraphicsViewer> GENERIC_VIEWER = new Property<GenericGraphicsViewer>("de.monticore.genericgraphics.GenericGraphicsViewer");
/**
* the volatile layout config for static properties such as minimal node
* sizes.
*/
private IProperty<VolatileLayoutConfig> STATIC_CONFIG = new Property<VolatileLayoutConfig>("de.monticore.genericgraphics.staticLayoutConfig");
/**
* stores a list of editparts that possibly have outgoing connections
*/
private IProperty<List<IMCGraphicalEditPart>> CONNECTIONS = new Property<List<IMCGraphicalEditPart>>("de.monticore.genericgraphics.CONNECTIONS");
private ILayoutConfig layoutConfig = new MCLayoutConfig();
/**
* Constructor
*/
public MCDiagramLayoutManager() {
}
@Override
public boolean supports(Object object) {
// TODO: check what should be supported
// return object instanceof GenericFormEditor || object instanceof IMCEditPart || object instanceof CombinedGraphicsOutlinePage;
return true;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Class[] getAdapterList() {
return new Class<?>[] { IMCEditPart.class };
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object getAdapter(Object object, Class adapterType) {
try {
if (adapterType.isAssignableFrom(ILayoutConfig.class)) {
return layoutConfig;
}
else if (adapterType.isAssignableFrom(IMCEditPart.class)) {
if (object != null) {
}
if (object instanceof IMCEditPart) {
return object;
}
else if (object instanceof GenericGraphicsEditor) {
return ((GenericGraphicsEditor) object).getContentEditPart();
}
else if (object instanceof GenericFormEditor) {
return ((GenericFormEditor) object).getGraphicalEditor().getContentEditPart();
}
else if (object instanceof CombinedGraphicsOutlinePage) {
return ((CombinedGraphicsOutlinePage) object).getGraphicalOutline().getViewer().getContentEditPart();
}
else if (object instanceof RootEditPart) {
return ((RootEditPart) object).getContents();
}
}
else if (object instanceof IAdaptable) {
return ((IAdaptable) object).getAdapter(adapterType);
}
}
catch (RuntimeException exception) {
// when the editor part has been closed NPEs can occur
}
return null;
}
@Override
public LayoutMapping<IMCEditPart> buildLayoutGraph(IWorkbenchPart workbenchPart, Object diagramPart) {
// System.err.println("MCDLM> buildLayout");
// System.err.println("-----> workbenchPart: " + workbenchPart);
// System.err.println("-----> diagramPart: " + diagramPart);
LayoutMapping<IMCEditPart> mapping = new LayoutMapping<IMCEditPart>(this);
mapping.setProperty(STATIC_CONFIG, new VolatileLayoutConfig(MCLayoutConfig.PRIORITY - 1));
mapping.setProperty(CONNECTIONS, new ArrayList<IMCNodeEditPart>());
GenericGraphicsViewer viewer = null;
// get the generic graphics viewer part
if (workbenchPart instanceof GenericGraphicsEditor) {
viewer = ((GenericGraphicsEditor) workbenchPart).getGraphicalViewer();
} else if (workbenchPart instanceof GenericFormEditor) {
viewer = ((GenericFormEditor) workbenchPart).getGraphicalEditor().getGraphicalViewer();
} else {
IContentOutlinePage outline = workbenchPart.getAdapter(IContentOutlinePage.class);
if (outline instanceof CombinedGraphicsOutlinePage) {
viewer = ((CombinedGraphicsOutlinePage) outline).getGraphicalOutline().getViewer();
}
}
// choose the layout root edit part
IMCEditPart layoutRootPart = null;
if (diagramPart instanceof IMCEditPart) {
layoutRootPart = (IMCEditPart) diagramPart;
}
if (layoutRootPart == null && viewer != null) {
layoutRootPart = viewer.getContentEditPart();
}
if (layoutRootPart == null) {
throw new UnsupportedOperationException("Not supported by this layout manager: Workbench part " + workbenchPart + ", Edit part " + diagramPart);
}
// set optional diagram editor
if (viewer != null) {
mapping.setProperty(GENERIC_VIEWER, viewer);
}
// set top level element
KNode topNode = KimlUtil.createInitializedNode();
KShapeLayout topLayout = topNode.getData(KShapeLayout.class);
GraphicalEditPart top = (GraphicalEditPart) layoutRootPart;
Rectangle topBounds = top.getFigure().getBounds();
topLayout.setPos(topBounds.x, topBounds.y);
topLayout.setSize(topBounds.width, topBounds.height);
mapping.getGraphMap().put(topNode, layoutRootPart);
mapping.setLayoutGraph(topNode);
mapping.setParentElement(layoutRootPart);
buildRecursively(mapping, layoutRootPart, topNode);
// after all editparts have been added, add connections
// and their labels
// all the connections need to have:
// -- IMCEditParts that are already added as parents
// -- PolylineConnections as figures
addAllConnections(mapping);
// create layout configurators for Generic Graphics Editors
mapping.getLayoutConfigs().add(layoutConfig);
mapping.getLayoutConfigs().add(mapping.getProperty(STATIC_CONFIG));
return mapping;
}
private void buildRecursively(LayoutMapping<IMCEditPart> mapping, IMCEditPart current, KNode parent) {
for (Object child : current.getChildren()) {
// add to the list of possible editparts with connections.
if (child instanceof IMCGraphicalEditPart) {
mapping.getProperty(CONNECTIONS).add((IMCGraphicalEditPart) child);
}
// we only want to layout view elements
// if its not an IMCViewElementEditPart:
// skip this level and add the next VEEditPart you find
// the parent KNode in KGraph will be the current parent node
if (!(child instanceof IMCShapeEditPart)) {
// as long as it's an IMCEditPart
if (child instanceof IMCEditPart) {
buildRecursively(mapping, (IMCEditPart) child, parent);
}
continue;
}
IMCShapeEditPart ep = (IMCShapeEditPart) child;
KNode node = KimlUtil.createInitializedNode();
KShapeLayout shapeLayout = node.getData(KShapeLayout.class);
node.setParent(parent);
setKShapeLayout(shapeLayout, ep);
mapping.getGraphMap().put(node, ep);
// the modification flag must initially be false
((KShapeLayoutImpl) shapeLayout).resetModificationFlag();
// add all its children
buildRecursively(mapping, ep, node);
}
}
@Override
public void applyLayout(LayoutMapping<IMCEditPart> mapping, boolean zoomToFit, int animationTime) {
Object layoutGraphObj = mapping.getParentElement();
if (layoutGraphObj instanceof IMCEditPart) {
ScalableRootEditPart rep = (ScalableRootEditPart) ((IMCEditPart) layoutGraphObj).getRoot();
ZoomManager zoomManager = rep.getZoomManager();
KNode parentNode = mapping.getLayoutGraph();
KShapeLayout parentLayout = parentNode.getData(KShapeLayout.class);
Dimension available = zoomManager.getViewport().getClientArea().getSize();
float desiredWidth = parentLayout.getWidth();
double scaleX = Math.min(available.width / desiredWidth, zoomManager.getMaxZoom());
float desiredHeight = parentLayout.getHeight();
double scaleY = Math.min(available.height / desiredHeight, zoomManager.getMaxZoom());
final double scale = Math.min(scaleX, scaleY);
applyLayout(mapping, zoomManager.getZoom());
if (zoomToFit) {
zoomManager.setViewLocation(new Point(0, 0));
zoomManager.setZoom(scale);
zoomManager.setViewLocation(new Point(0, 0));
}
}
else {
// assume 100% zoom level since we don't have any information
applyLayout(mapping, 1.0);
}
}
/**
* Applies the computed layout to the original diagram.
*
* @param mapping a layout mapping that was created by this layout manager
*/
private void applyLayout(LayoutMapping<IMCEditPart> mapping, double scale) {
// create a new command and execute it
// use relative bendpoints
Command applyCommand = new ApplyLayoutCommand(mapping, false, scale);
GenericGraphicsViewer viewer = mapping.getProperty(GENERIC_VIEWER);
if (viewer != null) {
CommandStack cStack = viewer.getEditDomain().getCommandStack();
cStack.execute(applyCommand);
} else {
Log.error("0xA1113 MCDiagramLayoutManager: no Editor was found! Cannot execute apply layout command!");
}
}
@Override
public void undoLayout(LayoutMapping<IMCEditPart> mapping) {
}
/**
* <p>
* Add all connections to the mapping.
* </p>
* <p>
* Therefore iterate through all added IMCEditParts and check for outgoing
* connections.
* </p>
*
* @param mapping The {@link LayoutMapping} to add all connections to.
*/
private void addAllConnections(LayoutMapping<IMCEditPart> mapping) {
BiMap<KGraphElement, IMCEditPart> graphMap = mapping.getGraphMap();
Map<KEdge, IMCEditPart> newCons = new HashMap<KEdge, IMCEditPart>();
for (IMCGraphicalEditPart ep : mapping.getProperty(CONNECTIONS)) {
// add all source connections
for (Object c : ep.getSourceConnections()) {
// add connections only, if they have an associated ViewElement
// check for IMCConnectionEditPart and IMCViewElementEditPart
// is necessary to ensure that computed bendpoints can be applied
if (!(c instanceof IMCConnectionEdgeEditPart)) {
continue;
}
IMCConnectionEdgeEditPart cep = (IMCConnectionEdgeEditPart) c;
// find a proper source node and source port
KGraphElement sourceElem = null;
EditPart sourceObj = cep.getSource();
if (sourceObj instanceof IMCEditPart) {
sourceElem = graphMap.inverse().get(sourceObj);
}
KNode sourceNode = null;
KPort sourcePort = null;
if (sourceElem instanceof KNode) {
sourceNode = (KNode) sourceElem;
}
else if (sourceElem instanceof KPort) {
sourcePort = (KPort) sourceElem;
sourceNode = sourcePort.getNode();
}
else {
continue;
}
// find a proper target node and target port
KGraphElement targetElem = null;
EditPart targetObj = cep.getTarget();
if (targetObj instanceof IMCEditPart) {
targetElem = graphMap.inverse().get(targetObj);
}
KNode targetNode = null;
KPort targetPort = null;
if (targetElem instanceof KNode) {
targetNode = (KNode) targetElem;
}
else if (targetElem instanceof KPort) {
targetPort = (KPort) targetElem;
targetNode = targetPort.getNode();
}
else {
continue;
}
KEdge edge = KimlUtil.createInitializedEdge();
if (sourceNode == null || targetNode == null) {
System.err.println("MCDLM> source: " + sourceNode + " target: " + targetNode + "! Skip this connection!");
continue;
}
// set source and target
edge.setSource(sourceNode);
if (sourcePort != null) {
edge.setSourcePort(sourcePort);
}
edge.setTarget(targetNode);
if (targetPort != null) {
edge.setTargetPort(targetPort);
}
newCons.put(edge, cep);
// store the current coordinates of the edge
KEdgeLayout edgeLayout = edge.getData(KEdgeLayout.class);
setKEdgeLayout(edgeLayout, cep.getViewElement(), ((PolylineConnection) cep.getFigure()));
if (cep instanceof IConnectionType) {
IConnectionType.Connection_Type type = ((IConnectionType) cep).getConnectionType();
if (type != null) {
switch (type) {
case ASSOCIATION:
edgeLayout.setProperty(LayoutOptions.EDGE_TYPE, EdgeType.ASSOCIATION);
break;
case DEPENDENCY:
edgeLayout.setProperty(LayoutOptions.EDGE_TYPE, EdgeType.DEPENDENCY);
break;
case GENERALIZATION:
edgeLayout.setProperty(LayoutOptions.EDGE_TYPE, EdgeType.GENERALIZATION);
break;
default:
edgeLayout.setProperty(LayoutOptions.EDGE_TYPE, EdgeType.ASSOCIATION);
break;
}
}
else {
edgeLayout.setProperty(LayoutOptions.EDGE_TYPE, EdgeType.ASSOCIATION);
}
}
// the modification flag must initially be false
((KEdgeLayoutImpl) edgeLayout).resetModificationFlag();
// check for labels to add
addAllLabels(mapping, cep, edge);
} // end-for souceConnections
} // end-for editparts
// add the connections to the graphMap
graphMap.putAll(newCons);
}
/**
* <p>
* Add all labels to the mapping.
* </p>
* <p>
* Therefore iterates through all children of the
* {@link IMCConnectionViewElementEditPart} and checks if instance of
* {@link TextConnectionLabelEditPart}. If so, add it as {@link KLabel} to the
* KGraph.
* </p>
*
* @param mapping The {@link LayoutMapping} to add all connections to
* @param cep The {@link IMCConnectionViewElementEditPart} to take the labels
* from.
* @param parent The parant {@link KLabeledGraphElement parent} in the KGraph
*/
private void addAllLabels(LayoutMapping<IMCEditPart> mapping, IMCConnectionEditPart cep, KLabeledGraphElement parent) {
for (Object child : cep.getChildren()) {
// if the child is not a connection label editpart then continue
if (!(child instanceof TextConnectionLabelEditPart)) {
continue;
}
TextConnectionLabelEditPart clep = (TextConnectionLabelEditPart) child;
TextConnectionLabel cLabel = (TextConnectionLabel) clep.getModel();
// IShapeViewElement sve = (IShapeViewElement) clep.getViewElement();
// check if label has text to display
if (cLabel.getTexts().isEmpty()) {
continue;
}
String text = cLabel.getString();
ConnectionLocatorPosition position = cLabel.getPosition();
Font font = cLabel.getFont();
if (position == null) {
continue;
}
KLabel kLabel = KimlUtil.createInitializedLabel(parent);
kLabel.setText(text);
VolatileLayoutConfig staticConfig = mapping.getProperty(STATIC_CONFIG);
// set position of label in config
switch (position) {
case BEFORE_SOURCE_UP:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.TAIL);
break;
case BEFORE_SOURCE_DOWN:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.TAIL);
break;
case SOURCE:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.TAIL);
break;
case MIDDLE_DOWN:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.CENTER);
break;
case MIDDLE_UP:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.CENTER);
break;
case BEFORE_TARGET_UP:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.HEAD);
break;
case BEFORE_TARGET_DOWN:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.HEAD);
break;
case TARGET:
staticConfig.setValue(LayoutOptions.EDGE_LABEL_PLACEMENT, kLabel, LayoutContext.GRAPH_ELEM, EdgeLabelPlacement.HEAD);
break;
default:
break;
}
// set font of label in config
if (font != null && !font.isDisposed()) {
staticConfig.setValue(LayoutOptions.FONT_NAME, kLabel, LayoutContext.GRAPH_ELEM, font.getFontData()[0].getName());
staticConfig.setValue(LayoutOptions.FONT_SIZE, kLabel, LayoutContext.GRAPH_ELEM, font.getFontData()[0].getHeight());
}
KShapeLayout layout = kLabel.getData(KShapeLayout.class);
setKShapeLayout(layout, clep);
// reset modification flag
((KShapeLayoutImpl) layout).resetModificationFlag();
mapping.getGraphMap().put(kLabel, clep);
}
}
/**
* <p>
* Sets the values of the {@link KShapeLayout} according to the given
* {@link IMCShapeEditPart} with a {@link IShapeViewElement}.
* </p>
* <p>
* If the width & height of the {@link IShapeViewElement} are
* <code>-1 (or below)</code>, then the preferred size of the {@link IFigure}
* of the {@link IMCShapeEditPart} is applied.
* </p>
*
* @param s The {@link KShapeLayout}
* @param ep The {@link IMCShapeEditPart} that stores a
* {@link IShapeViewElement} and a {@link IFigure} for setting the
* preferred size.
*/
private void setKShapeLayout(KShapeLayout s, IMCShapeEditPart ep) {
IViewElement ve = ep.getViewElement();
if (ve instanceof IShapeViewElement) {
IShapeViewElement sve = (IShapeViewElement) ve;
s.setPos(sve.getX(), sve.getY());
Dimension size = ep.getFigure().getPreferredSize();
// if width < 0, set preferred width
if (sve.getWidth() < 0) {
s.setWidth(size.width);
}
else {
s.setWidth(sve.getWidth());
}
// if height < 0, set preferred height
if (sve.getHeight() < 0) {
s.setHeight(size.height);
}
else {
s.setHeight(sve.getHeight());
}
}
}
/**
* Sets the values of the {@link KEdgeLayout} according to the given
* {@link IEdgeViewElement}.
*
* @param e The {@link KEdgeLayout}
* @param eve The {@link IEdgeViewElement}
*/
private void setKEdgeLayout(KEdgeLayout e, IEdgeViewElement eve, PolylineConnection con) {
List<MCBendpoint> bpList = eve.getConstraints();
Point start = con.getStart();
Point end = con.getEnd();
KPoint sourcePoint = e.getSourcePoint();
sourcePoint.setX(start.x);
sourcePoint.setY(start.y);
EList<KPoint> kBPList = e.getBendPoints();
for (int i = 1; i < bpList.size() - 1; i++) {
MCBendpoint bp = bpList.get(i);
KPoint kpoint = KLayoutDataFactory.eINSTANCE.createKPoint();
if (bp.isAbsolute()) {
// absolute bendpoint, nothing special todo here
Point a = bp.getAbsolutePoint();
kpoint.setX(a.x);
kpoint.setY(a.y);
}
else {
// we need to translate the relative point into an absolute one
Point refS = con.getSourceAnchor().getReferencePoint();
Dimension relStart = bp.getRelativeStart();
kpoint.setX(refS.x + relStart.width);
kpoint.setY(refS.y + relStart.height);
}
kBPList.add(kpoint);
}
KPoint targetPoint = e.getTargetPoint();
targetPoint.setX(end.x);
targetPoint.setY(end.y);
}
}