Java tutorial
/******************************************************************************* * Copyright (c) 2011, 2015 THALES GLOBAL SERVICES and others. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.sirius.diagram.ui.internal.refresh; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.PositionConstants; 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.emf.ecore.EObject; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; import org.eclipse.gmf.runtime.notation.Bounds; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.Edge; import org.eclipse.gmf.runtime.notation.LayoutConstraint; import org.eclipse.gmf.runtime.notation.Location; import org.eclipse.gmf.runtime.notation.Node; import org.eclipse.gmf.runtime.notation.RelativeBendpoints; import org.eclipse.gmf.runtime.notation.Size; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint; import org.eclipse.sirius.common.ui.tools.api.util.EclipseUIUtil; import org.eclipse.sirius.diagram.AbstractDNode; import org.eclipse.sirius.diagram.ContainerStyle; import org.eclipse.sirius.diagram.DDiagram; import org.eclipse.sirius.diagram.DDiagramElementContainer; import org.eclipse.sirius.diagram.DNode; import org.eclipse.sirius.diagram.DNodeContainer; import org.eclipse.sirius.diagram.DNodeList; import org.eclipse.sirius.diagram.business.internal.query.DDiagramElementContainerExperimentalQuery; import org.eclipse.sirius.diagram.business.internal.query.DNodeContainerExperimentalQuery; import org.eclipse.sirius.diagram.ui.business.api.query.NodeQuery; import org.eclipse.sirius.diagram.ui.business.api.query.ViewQuery; import org.eclipse.sirius.diagram.ui.business.internal.query.DNodeContainerQuery; import org.eclipse.sirius.diagram.ui.business.internal.query.DNodeQuery; import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramElementContainerEditPart; import org.eclipse.sirius.diagram.ui.internal.edit.parts.AbstractDNodeContainerCompartmentEditPart; import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeContainer2EditPart; import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeList2EditPart; import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeListEditPart; import org.eclipse.sirius.diagram.ui.internal.refresh.borderednode.CanonicalDBorderItemLocator; import org.eclipse.sirius.diagram.ui.part.SiriusVisualIDRegistry; import org.eclipse.sirius.diagram.ui.provider.Messages; import org.eclipse.sirius.diagram.ui.tools.api.graphical.edit.styles.IContainerLabelOffsets; import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutUtils; import org.eclipse.sirius.diagram.ui.tools.internal.figure.LabelBorderStyleIds; import org.eclipse.sirius.ext.base.Option; import org.eclipse.sirius.ext.base.Options; import org.eclipse.sirius.ui.business.api.dialect.DialectEditor; import org.eclipse.sirius.ui.business.api.session.IEditingSession; import org.eclipse.sirius.ui.business.api.session.SessionUIManager; import org.eclipse.sirius.viewpoint.description.style.LabelBorderStyleDescription; import org.eclipse.ui.IEditorPart; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; /** * GMF Helper. * * @author edugueperoux */ public final class GMFHelper { /** * see org.eclipse.sirius.diagram.ui.internal.edit.parts. * AbstractDNodeContainerCompartmentEditPart.DEFAULT_MARGIN the Y value is * the DEFAULT_MARGIN + the InvisibleResizableCompartmentFigure top Inset * (1px) */ private static Point CONTAINER_INSETS = new Point(AbstractDNodeContainerCompartmentEditPart.DEFAULT_MARGIN, IContainerLabelOffsets.LABEL_OFFSET); private GMFHelper() { // Helper to not instantiate } /** * Get the absolute location relative to the origin (Diagram). * * @param node * the GMF Node * * @return the absolute location of the node relative to the origin * (Diagram) */ public static Point getAbsoluteLocation(Node node) { return getAbsoluteLocation(node, false); } /** * Get the absolute location relative to the origin (Diagram). * * @param node * the GMF Node * @param insetsAware * true to consider the draw2D figures insets. * <strong>Warning:</strong> Those insets are based on the * current Sirius editParts and could become wrong if a developer * customizes them. * * @return the absolute location of the node relative to the origin * (Diagram) */ public static Point getAbsoluteLocation(Node node, boolean insetsAware) { Node currentNode = node; Point absoluteNodeLocation = getLocation(currentNode); if (currentNode.eContainer() instanceof Node) { currentNode = (Node) currentNode.eContainer(); Point parentNodeLocation = getAbsoluteLocation(currentNode, insetsAware); absoluteNodeLocation.translate(parentNodeLocation); if (insetsAware) { translateWithInsets(absoluteNodeLocation, node); } } return absoluteNodeLocation; } /** * Shift the current node absolute location by the container insets. * * @param locationToTranslate * the current computed location that will be translated by the * container insets. * @param currentNode * the current node for which we translate location. We do not * change the currentNode bounds. */ private static void translateWithInsets(Point locationToTranslate, Node currentNode) { NodeQuery nodeQuery = new NodeQuery(currentNode); Node parentNode = (Node) currentNode.eContainer(); NodeQuery parentNodeQuery = new NodeQuery(parentNode); // bordered node are not concerned by those insets. We also check if the // parent node corresponds to a container. if (!nodeQuery.isBorderedNode() && parentNodeQuery.isContainer()) { EObject element = parentNode.getElement(); if (element instanceof DDiagramElementContainer) { DDiagramElementContainer ddec = (DDiagramElementContainer) element; ContainerStyle containerStyle = ddec.getOwnedStyle(); int borderSize = containerStyle.getBorderSize().intValue(); // RegionContainer do not have containers insets if (ddec instanceof DNodeContainer) { if (new DNodeContainerExperimentalQuery((DNodeContainer) ddec).isRegionContainer() || hasFullLabelBorder(ddec)) { locationToTranslate.translate(0, CONTAINER_INSETS.y); locationToTranslate.translate(0, getLabelSize(parentNode)).translate(0, AbstractDiagramElementContainerEditPart.DEFAULT_SPACING); } else { locationToTranslate.translate(CONTAINER_INSETS); } } DDiagramElementContainerExperimentalQuery regionQuery = new DDiagramElementContainerExperimentalQuery( ddec); if (regionQuery.isRegionInHorizontalStack()) { locationToTranslate.translate((isFirstRegion(ddec) ? 0 : borderSize), 1); } else if (regionQuery.isRegionInVerticalStack()) { locationToTranslate.translate(1, (isFirstRegion(ddec) ? 1 : borderSize)); } else { locationToTranslate.translate(borderSize, borderSize); } } } } private static boolean hasFullLabelBorder(DDiagramElementContainer ddec) { Option<LabelBorderStyleDescription> labelBorderStyle = new DDiagramElementContainerExperimentalQuery(ddec) .getLabelBorderStyle(); return labelBorderStyle.some() && LabelBorderStyleIds.LABEL_FULL_BORDER_STYLE_FOR_CONTAINER_ID .equals(labelBorderStyle.get().getId()); } private static int getLabelSize(Node parentNode) { int labelSize = 0; for (Node child : Iterables.filter(parentNode.getVisibleChildren(), Node.class)) { if (new ViewQuery(child).isForNameEditPart()) { // TODO Compute the real label height // It depends on the font size // It might require to set the layout constraint of the label // GMF node which will not be used by the // ConstrainedToolbarLayout to locate the label but might be // usefull to store the value in the model. labelSize = 16; break; } } return labelSize; } private static boolean isFirstRegion(DDiagramElementContainer ddec) { EObject potentialRegionContainer = ddec.eContainer(); if (potentialRegionContainer instanceof DNodeContainer) { Iterable<DDiagramElementContainer> regions = Iterables.filter( ((DNodeContainer) potentialRegionContainer).getOwnedDiagramElements(), DDiagramElementContainer.class); return !Iterables.isEmpty(regions) && ddec == Iterables.getFirst(regions, null); } return false; } /** * Shift the current node absolute bounds location by the container insets. * * @param boundsToTranslate * the current computed bounds that will be translated by the * container insets. * @param currentNode * the current node for which we translate bounds. We do not * change the currentNode bounds. */ private static void translateWithInsets(Rectangle boundsToTranslate, Node currentNode) { Point location = boundsToTranslate.getLocation(); translateWithInsets(location, currentNode); boundsToTranslate.setLocation(location); } /** * Compute the location of a GMF node. * * @param node * the node whose location to compute. * @return the location of the node. */ public static Point getLocation(Node node) { Point location = new Point(0, 0); LayoutConstraint layoutConstraint = node.getLayoutConstraint(); if (layoutConstraint instanceof Bounds) { Bounds gmfBounds = (Bounds) layoutConstraint; location.x = gmfBounds.getX(); location.y = gmfBounds.getY(); // manage location of bordered node with closest side if (node.getElement() instanceof DNode && node.getElement().eContainer() instanceof AbstractDNode) { DNode dNode = (DNode) node.getElement(); AbstractDNode parentAbstractDNode = (AbstractDNode) dNode.eContainer(); if (parentAbstractDNode.getOwnedBorderedNodes().contains(dNode)) { Node parentNode = (Node) node.eContainer(); LayoutConstraint parentLayoutConstraint = parentNode.getLayoutConstraint(); if (parentLayoutConstraint instanceof Bounds) { Bounds parentBounds = (Bounds) parentLayoutConstraint; int position = CanonicalDBorderItemLocator.findClosestSideOfParent( new Rectangle(gmfBounds.getX(), gmfBounds.getY(), gmfBounds.getWidth(), gmfBounds.getHeight()), new Rectangle(parentBounds.getX(), parentBounds.getY(), parentBounds.getWidth(), parentBounds.getHeight())); updateLocation(location, position, parentBounds, gmfBounds); } } } } return location; } private static void updateLocation(Point location, int position, Bounds parentBounds, Bounds gmfBounds) { switch (position) { case PositionConstants.NORTH: case PositionConstants.SOUTH: if (location.x == 0) { location.x += (parentBounds.getWidth() - gmfBounds.getWidth()) / 2; } break; case PositionConstants.WEST: case PositionConstants.EAST: if (location.y == 0) { location.y += (parentBounds.getHeight() - gmfBounds.getHeight()) / 2; } break; default: break; } } /** * Get the absolute bounds relative to the origin (Diagram). * * @param node * the GMF Node * * @return the absolute bounds of the node relative to the origin (Diagram) */ public static Rectangle getAbsoluteBounds(Node node) { return getAbsoluteBounds(node, false); } /** * Get the absolute bounds relative to the origin (Diagram). * * @param node * the GMF Node * @param insetsAware * true to consider the draw2D figures insets. * <strong>Warning:</strong> Those insets are based on the * current Sirius editParts and could become wrong if a developer * customizes them. * * @return the absolute bounds of the node relative to the origin (Diagram) */ public static Rectangle getAbsoluteBounds(Node node, boolean insetsAware) { Node currentNode = node; Rectangle absoluteNodeBounds = getBounds(currentNode); if (currentNode.eContainer() instanceof Node) { currentNode = (Node) currentNode.eContainer(); Point parentNodeLocation = getAbsoluteLocation(currentNode, insetsAware); absoluteNodeBounds = absoluteNodeBounds.getTranslated(parentNodeLocation); if (insetsAware) { translateWithInsets(absoluteNodeBounds, node); } } return absoluteNodeBounds; } /** * Get the absolute bounds relative to the origin (Diagram). * * @param edge * the GMF Node * * @return the absolute bounds of the edge relative to the origin (Diagram) */ public static Option<Rectangle> getAbsoluteBounds(Edge edge) { return getAbsoluteBounds(edge, false); } /** * Get the absolute bounds relative to the origin (Diagram). * * @param edge * the GMF Node * @param insetsAware * true to consider the draw2D figures insets. * <strong>Warning:</strong> Those insets are based on the * current Sirius editParts and could become wrong if a developer * customizes them. * * @return the absolute bounds of the edge relative to the origin (Diagram) */ public static Option<Rectangle> getAbsoluteBounds(Edge edge, boolean insetsAware) { // Workaround for canonical refresh about edge on edge Option<Rectangle> optionalSourceBounds = getAbsoluteBounds(edge.getSource(), insetsAware); Option<Rectangle> optionalTargetBounds = getAbsoluteBounds(edge.getTarget(), insetsAware); if (optionalSourceBounds.some() && optionalTargetBounds.some()) { return Options.newSome(optionalSourceBounds.get().union(optionalTargetBounds.get())); } return Options.newNone(); } /** * Get the absolute bounds relative to the origin (Diagram). * * @param view * the GMF Node or Edge * * @return an optional absolute bounds of the node or edge relative to the * origin (Diagram) */ public static Option<Rectangle> getAbsoluteBounds(View view) { return getAbsoluteBounds(view, false); } /** * Get the absolute bounds relative to the origin (Diagram). * * @param view * the GMF Node or Edge * @param insetsAware * true to consider the draw2D figures insets. * <strong>Warning:</strong> Those insets are based on the * current Sirius editParts and could become wrong if a developer * customizes them. * * @return an optional absolute bounds of the node or edge relative to the * origin (Diagram) */ public static Option<Rectangle> getAbsoluteBounds(View view, boolean insetsAware) { Option<Rectangle> result = Options.newNone(); if (view instanceof Node) { result = Options.newSome(getAbsoluteBounds((Node) view, insetsAware)); } else if (view instanceof Edge) { result = getAbsoluteBounds((Edge) view, insetsAware); } return result; } /** * Compute the bounds of a GMF node. * * @param node * the node whose bounds to compute. * @return the bounds of the node. */ public static Rectangle getBounds(Node node) { return getBounds(node, false); } /** * Compute the bounds of a GMF node. * * @param node * the node whose bounds to compute. * @param useFigureForAutoSizeConstraint * true to use figure for auto size constraint * @return the bounds of the node. */ public static Rectangle getBounds(Node node, boolean useFigureForAutoSizeConstraint) { return getBounds(node, useFigureForAutoSizeConstraint, false); } /** * Compute the bounds of a GMF node. * * @param node * the node whose bounds to compute. * @param useFigureForAutoSizeConstraint * true to use figure for auto size constraint * @param forceFigureAutoSize * if useFigureForAutoSizeConstraint and if the found edit part * supports it, force auto size and validate the parent to get * the auto-sized dimension (during auto-size for exemple) * @return the bounds of the node. */ public static Rectangle getBounds(Node node, boolean useFigureForAutoSizeConstraint, boolean forceFigureAutoSize) { Rectangle bounds = new Rectangle(0, 0, 0, 0); LayoutConstraint layoutConstraint = node.getLayoutConstraint(); EObject element = node.getElement(); if (element instanceof AbstractDNode) { AbstractDNode abstractDNode = (AbstractDNode) element; if (layoutConstraint instanceof Location) { bounds.x = ((Location) layoutConstraint).getX(); bounds.y = ((Location) layoutConstraint).getY(); } if (layoutConstraint instanceof Size) { bounds.width = ((Size) layoutConstraint).getWidth(); bounds.height = ((Size) layoutConstraint).getHeight(); } else { bounds.width = -1; bounds.height = -1; } if (new ViewQuery(node).isForNameEditPart()) { if (abstractDNode.getName() == null || abstractDNode.getName().length() == 0) { if (bounds.width == -1) { bounds.width = 0; } if (bounds.height == -1) { bounds.height = 0; } } else { // Make a default size for label (this size is purely an // average estimate) replaceAutoSize(node, bounds, useFigureForAutoSizeConstraint, new Dimension(50, 20)); } } else { replaceAutoSize(node, bounds, useFigureForAutoSizeConstraint, null); } } return bounds; } /** * This method replace the -1x-1 size with a more realistic size. This size * is probably not exactly the same as in draw2d but much closer that -1x-1. * * @param node * The GMF node with the auto-size * @param bounds * The bounds with auto-size to replace. * @param useFigureForAutoSizeConstraint * true to use draw2d figure to get size * @param providedDefaultSize * The size used for creation for this kind of <code>node</code>. * It is the minimum size. */ private static void replaceAutoSize(Node node, Rectangle bounds, boolean useFigureForAutoSizeConstraint, Dimension providedDefaultSize) { if (bounds.width == -1 || bounds.height == -1) { Dimension defaultSize = providedDefaultSize; if (providedDefaultSize == null) { // if there is no default size, we compute it from the given // node. EObject element = node.getElement(); if (element instanceof AbstractDNode) { defaultSize = getDefaultSize((AbstractDNode) element); } } if (useFigureForAutoSizeConstraint) { // Use the figure (if founded) to set width and height // instead of (-1, -1) Option<GraphicalEditPart> optionalTargetEditPart = getGraphicalEditPart(node); // CHECKSTYLE:OFF if (optionalTargetEditPart.some()) { GraphicalEditPart graphicalEditPart = optionalTargetEditPart.get(); if (graphicalEditPart instanceof AbstractDiagramElementContainerEditPart) { ((AbstractDiagramElementContainerEditPart) graphicalEditPart).forceFigureAutosize(); ((GraphicalEditPart) graphicalEditPart.getParent()).getFigure().validate(); } Rectangle figureBounds = graphicalEditPart.getFigure().getBounds(); if (bounds.width == -1) { bounds.width = figureBounds.width; } if (bounds.height == -1) { bounds.height = figureBounds.height; } } else { // Diagram editor might be initializing and there is no edit // part yet. For regions we might retrieve the previous // known constraints in the GMF model by looking into the // GMF location of the next region as they were computed // from the location and size of the current region. lookForNextRegionLocation(bounds, node); } // CHECKSTYLE:ON } else { // Compute the bounds of all children and use the lowest // one (y+height) for height and the rightmost one // (x+width) for width. Point bottomRight = getBottomRight(node); if (bounds.width == -1) { if (bottomRight.x > defaultSize.width) { bounds.width = bottomRight.x; } else { bounds.width = defaultSize.width; } } if (bounds.height == -1) { if (bottomRight.y > defaultSize.height) { bounds.height = bottomRight.y; } else { bounds.height = defaultSize.height; } } } if (bounds.width == -1) { bounds.width = defaultSize.width; } if (bounds.height == -1) { bounds.height = defaultSize.height; } } } private static void lookForNextRegionLocation(Rectangle bounds, Node node) { EObject element = node.getElement(); if (element instanceof DDiagramElementContainer && node.eContainer() instanceof Node) { DDiagramElementContainer ddec = (DDiagramElementContainer) element; DDiagramElementContainerExperimentalQuery query = new DDiagramElementContainerExperimentalQuery(ddec); boolean isRegion = query.isRegion(); EList children = ((Node) node.eContainer()).getChildren(); int nextIndex = children.indexOf(node) + 1; if (isRegion && nextIndex != 0 && nextIndex < children.size() && children.get(nextIndex) instanceof Node) { Node nextNode = (Node) children.get(nextIndex); int visualID = SiriusVisualIDRegistry.getVisualID(nextNode.getType()); if (DNodeContainer2EditPart.VISUAL_ID == visualID || DNodeListEditPart.VISUAL_ID == visualID || DNodeList2EditPart.VISUAL_ID == visualID) { // DNodeContainerEditPart.VISUAL_ID == visualID is not // checked as a region cannot be a DNodeContainerEditPart as // it is directly contained by the diagram part. LayoutConstraint layoutConstraint = nextNode.getLayoutConstraint(); if (layoutConstraint instanceof Location) { Location nextLocation = (Location) layoutConstraint; // Update only the parent stack direction if some layout // has already been done. if (bounds.width == -1 && query.isRegionInHorizontalStack() && nextLocation.getX() != 0) { bounds.width = nextLocation.getX() - bounds.x; } if (bounds.height == -1 && query.isRegionInVerticalStack() && nextLocation.getY() != 0) { bounds.height = nextLocation.getY() - bounds.y; } } } } } } /** * Returns a new Point representing the bottom right point of all bounds of * children of this Node. Useful for Node with size of -1x-1 to be more * accurate (but it is still not necessarily the same size that draw2d). * * @param node * the node whose bottom right corner is to compute. * * @return Point at the bottom right of the rectangle */ public static Point getBottomRight(Node node) { int right = 0; int bottom = 0; for (Iterator<Node> children = Iterators.filter(node.getChildren().iterator(), Node.class); children .hasNext(); /* */) { Node child = children.next(); // The bordered nodes is ignored if (!(new NodeQuery(node).isBorderedNode())) { Rectangle bounds = getBounds(child); Point bottomRight = bounds.getBottomRight(); if (bottomRight.x > right) { right = bottomRight.x; } if (bottomRight.y > bottom) { bottom = bottomRight.y; } } } return new Point(right, bottom); } private static Dimension getDefaultSize(AbstractDNode abstractDNode) { Dimension defaultSize = new Dimension(-1, -1); if (abstractDNode instanceof DNode) { defaultSize = new DNodeQuery((DNode) abstractDNode).getDefaultDimension(); } else if (abstractDNode instanceof DNodeContainer) { defaultSize = new DNodeContainerQuery((DNodeContainer) abstractDNode).getDefaultDimension(); } else if (abstractDNode instanceof DNodeList) { defaultSize = LayoutUtils.NEW_DEFAULT_CONTAINER_DIMENSION; } return defaultSize; } /** * Return an option with the editPart corresponding to the <code>view</code> * in the current diagram or an empty Option if there is no corresponding * editPart. * * @param view * The view element that is searched * @return The optional corresponding edit part. */ public static Option<GraphicalEditPart> getGraphicalEditPart(View view) { Option<GraphicalEditPart> result = Options.newNone(); DiagramEditor diagramEditor = null; if (view != null) { final IEditorPart editor = EclipseUIUtil.getActiveEditor(); Diagram diagram = view.getDiagram(); if (editor instanceof DiagramEditor && ((DiagramEditor) editor).getDiagram() == diagram) { diagramEditor = (DiagramEditor) editor; } else if (diagram.getElement() instanceof DDiagram) { DDiagram diag = (DDiagram) diagram.getElement(); for (IEditingSession uiSession : SessionUIManager.INSTANCE.getUISessions()) { DialectEditor dialectEditor = uiSession.getEditor(diag); if (dialectEditor instanceof DiagramEditor && ((DiagramEditor) editor).getDiagram() != diagram) { diagramEditor = (DiagramEditor) dialectEditor; } } } } if (diagramEditor != null) { return getGraphicalEditPart(view, diagramEditor); } return result; } /** * Return an option with the editPart corresponding to the <code>view</code> * in the current diagram or an empty Option if there is no corresponding * editPart. * * @param view * The view element that is searched * @param editor * the editor where looking for the edit part. * @return The optional corresponding edit part. */ public static Option<GraphicalEditPart> getGraphicalEditPart(View view, DiagramEditor editor) { Option<GraphicalEditPart> result = Options.newNone(); final Map<?, ?> editPartRegistry = editor.getDiagramGraphicalViewer().getEditPartRegistry(); final EditPart targetEditPart = (EditPart) editPartRegistry.get(view); if (targetEditPart instanceof GraphicalEditPart) { result = Options.newSome((GraphicalEditPart) targetEditPart); } return result; } /** * Get the points list computed from GMF bendpoints according to source side * for the <code>edgeEditPart</code>. * * @param edgeEditPart * The concerned edge edit part. * @return Points list * @throws IllegalArgumentException * when the edgeEditPart is not as expected */ public static List<Point> getPointsFromSource(ConnectionEditPart edgeEditPart) throws IllegalArgumentException { if (edgeEditPart.getModel() instanceof Edge && edgeEditPart.getFigure() instanceof Connection) { List<Point> result = Lists.newArrayList(); Edge gmfEdge = (Edge) edgeEditPart.getModel(); Connection connectionFigure = (Connection) edgeEditPart.getFigure(); Point srcAnchorLoc = connectionFigure.getSourceAnchor().getReferencePoint(); connectionFigure.translateToRelative(srcAnchorLoc); RelativeBendpoints bp = (RelativeBendpoints) gmfEdge.getBendpoints(); for (int i = 0; i < bp.getPoints().size(); i++) { RelativeBendpoint rbp = (RelativeBendpoint) bp.getPoints().get(i); Point fromSrc = srcAnchorLoc.getTranslated(rbp.getSourceX(), rbp.getSourceY()); result.add(fromSrc); } return result; } throw new IllegalArgumentException(Messages.GMFHelper_invalidEdgeModelAndFigure); } /** * Get the points list computed from GMF bendpoints according to target side * for the <code>edgeEditPart</code>. * * @param edgeEditPart * The concerned edge edit part. * @return Points list * @throws IllegalArgumentException * when the edgeEditPart is not as expected */ public static List<Point> getPointsFromTarget(ConnectionEditPart edgeEditPart) throws IllegalArgumentException { if (edgeEditPart.getModel() instanceof Edge && edgeEditPart.getFigure() instanceof Connection) { List<Point> result = Lists.newArrayList(); Edge gmfEdge = (Edge) edgeEditPart.getModel(); Connection connectionFigure = (Connection) edgeEditPart.getFigure(); Point tgtAnchorLoc = connectionFigure.getTargetAnchor().getReferencePoint(); connectionFigure.translateToRelative(tgtAnchorLoc); RelativeBendpoints bp = (RelativeBendpoints) gmfEdge.getBendpoints(); for (int i = 0; i < bp.getPoints().size(); i++) { RelativeBendpoint rbp = (RelativeBendpoint) bp.getPoints().get(i); Point fromTgt = tgtAnchorLoc.getTranslated(rbp.getTargetX(), rbp.getTargetY()); result.add(fromTgt); } return result; } throw new IllegalArgumentException(Messages.GMFHelper_invalidEdgeModelAndFigure); } }