| /******************************************************************************* |
| * Copyright (c) 2007-2019 THALES GLOBAL SERVICES and others. |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.sirius.diagram.ui.graphical.edit.policies; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Optional; |
| |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.draw2d.Connection; |
| import org.eclipse.draw2d.ConnectionAnchor; |
| import org.eclipse.draw2d.Graphics; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.PolylineDecoration; |
| import org.eclipse.draw2d.RectangleFigure; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.PointList; |
| import org.eclipse.draw2d.geometry.PrecisionPoint; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| import org.eclipse.emf.transaction.util.TransactionUtil; |
| import org.eclipse.gef.ConnectionEditPart; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.GraphicalEditPart; |
| import org.eclipse.gef.Request; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.gef.commands.CompoundCommand; |
| import org.eclipse.gef.commands.UnexecutableCommand; |
| import org.eclipse.gef.requests.CreateConnectionRequest; |
| import org.eclipse.gef.requests.CreateRequest; |
| import org.eclipse.gef.requests.DropRequest; |
| import org.eclipse.gef.requests.ReconnectRequest; |
| import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; |
| import org.eclipse.gmf.runtime.common.core.command.ICommand; |
| import org.eclipse.gmf.runtime.common.core.command.IdentityCommand; |
| import org.eclipse.gmf.runtime.common.core.util.StringStatics; |
| import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand; |
| import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionEndsCommand; |
| import org.eclipse.gmf.runtime.diagram.core.commands.SetPropertyCommand; |
| import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editpolicies.TreeGraphicalNodeEditPolicy; |
| import org.eclipse.gmf.runtime.diagram.ui.figures.ResizableCompartmentFigure; |
| import org.eclipse.gmf.runtime.diagram.ui.internal.properties.Properties; |
| import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; |
| import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor; |
| import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; |
| import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor; |
| import org.eclipse.gmf.runtime.notation.Anchor; |
| import org.eclipse.gmf.runtime.notation.Bendpoints; |
| import org.eclipse.gmf.runtime.notation.Diagram; |
| import org.eclipse.gmf.runtime.notation.Edge; |
| import org.eclipse.gmf.runtime.notation.IdentityAnchor; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.RelativeBendpoints; |
| import org.eclipse.gmf.runtime.notation.Routing; |
| import org.eclipse.gmf.runtime.notation.RoutingStyle; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint; |
| import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; |
| import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; |
| import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterSiriusVariables; |
| import org.eclipse.sirius.common.tools.api.util.StringUtil; |
| import org.eclipse.sirius.diagram.DDiagramElement; |
| import org.eclipse.sirius.diagram.DEdge; |
| import org.eclipse.sirius.diagram.DSemanticDiagram; |
| import org.eclipse.sirius.diagram.EdgeRouting; |
| import org.eclipse.sirius.diagram.EdgeStyle; |
| import org.eclipse.sirius.diagram.EdgeTarget; |
| import org.eclipse.sirius.diagram.business.api.query.EdgeCreationDescriptionQuery; |
| import org.eclipse.sirius.diagram.business.api.query.IEdgeMappingQuery; |
| import org.eclipse.sirius.diagram.business.api.query.ReconnectEdgeDescriptionQuery; |
| import org.eclipse.sirius.diagram.description.CenteringStyle; |
| import org.eclipse.sirius.diagram.description.CompositeLayout; |
| import org.eclipse.sirius.diagram.description.EdgeMapping; |
| import org.eclipse.sirius.diagram.description.Layout; |
| import org.eclipse.sirius.diagram.description.OrderedTreeLayout; |
| import org.eclipse.sirius.diagram.description.tool.EdgeCreationDescription; |
| import org.eclipse.sirius.diagram.description.tool.ReconnectEdgeDescription; |
| import org.eclipse.sirius.diagram.description.tool.ReconnectionKind; |
| import org.eclipse.sirius.diagram.tools.api.command.IDiagramCommandFactory; |
| import org.eclipse.sirius.diagram.tools.api.command.IDiagramCommandFactoryProvider; |
| import org.eclipse.sirius.diagram.ui.business.api.query.ConnectionEditPartQuery; |
| import org.eclipse.sirius.diagram.ui.business.api.view.SiriusLayoutDataManager; |
| import org.eclipse.sirius.diagram.ui.business.internal.command.SetReconnectingConnectionBendpointsCommand; |
| import org.eclipse.sirius.diagram.ui.business.internal.command.SiriusSetConnectionAnchorsCommand; |
| import org.eclipse.sirius.diagram.ui.business.internal.command.TreeLayoutSetConnectionAnchorsCommand; |
| import org.eclipse.sirius.diagram.ui.business.internal.helper.CreateConnectionRequestHelper; |
| import org.eclipse.sirius.diagram.ui.business.internal.query.DEdgeQuery; |
| import org.eclipse.sirius.diagram.ui.business.internal.query.RequestQuery; |
| import org.eclipse.sirius.diagram.ui.business.internal.view.EdgeLayoutData; |
| import org.eclipse.sirius.diagram.ui.business.internal.view.LayoutData; |
| import org.eclipse.sirius.diagram.ui.business.internal.view.RootLayoutData; |
| import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramEdgeEditPart.ViewEdgeFigure; |
| import org.eclipse.sirius.diagram.ui.edit.api.part.IDiagramEdgeEditPart; |
| import org.eclipse.sirius.diagram.ui.edit.internal.part.DiagramEdgeEditPartOperation; |
| import org.eclipse.sirius.diagram.ui.internal.edit.parts.DEdgeEditPart; |
| import org.eclipse.sirius.diagram.ui.internal.edit.policies.InitialPointsOfRequestDataManager; |
| import org.eclipse.sirius.diagram.ui.tools.api.command.GMFCommandWrapper; |
| import org.eclipse.sirius.diagram.ui.tools.api.editor.DDiagramEditor; |
| import org.eclipse.sirius.diagram.ui.tools.api.util.GMFNotationHelper; |
| import org.eclipse.sirius.ext.base.Option; |
| import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper; |
| import org.eclipse.sirius.viewpoint.DMappingBased; |
| import org.eclipse.sirius.viewpoint.DSemanticDecorator; |
| import org.eclipse.sirius.viewpoint.SiriusPlugin; |
| import org.eclipse.sirius.viewpoint.description.tool.ToolPackage; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Display; |
| |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Maps; |
| |
| /** |
| * This class manages the reconnection of an edge. |
| * |
| * @author ymortier |
| */ |
| @SuppressWarnings("restriction") |
| public class SiriusGraphicalNodeEditPolicy extends TreeGraphicalNodeEditPolicy { |
| |
| /** |
| * Constant used to store a {@link EdgeCreationDescription} in a Request.getExtendedData(). |
| */ |
| public static final String GMF_EDGE_CREATION_DESCRIPTION = "edge.creation.description"; //$NON-NLS-1$ |
| |
| /** |
| * Constant used to store the {@link EdgeTarget} source. |
| */ |
| public static final String GMF_EDGE_TARGET_SOURCE = "edgeTarget.source"; //$NON-NLS-1$ |
| |
| /** |
| * Constant used to store the location in GMF relative coordinates of the click on the {@link EdgeTarget} source. |
| */ |
| public static final String GMF_EDGE_LOCATION_SOURCE = "edge.location.source"; //$NON-NLS-1$ |
| |
| /** |
| * Constant use to store source terminal. |
| */ |
| public static final String GMF_EDGE_SOURCE_TERMINAL = "edge.newSourceTerminal"; //$NON-NLS-1$ |
| |
| /** |
| * Constant use to store the feedback figure. This feedback figure is used only when necessary (detection of |
| * potential straightened edge feedback). |
| */ |
| public static final String GMF_EDGE_FEEDBACK = "edge.feedback.figure"; //$NON-NLS-1$ |
| |
| /** |
| * Extra width edge for this feedback. |
| */ |
| private static final int WIDTH_FEEDBACK = 2; |
| |
| /** |
| * Figure for highlight figure feedback. |
| */ |
| private RectangleFigure highlightFigure; |
| |
| @Override |
| protected Command getReconnectSourceCommand(final ReconnectRequest request) { |
| if (request.getConnectionEditPart().getModel() instanceof Edge) { |
| final Edge edge = (Edge) request.getConnectionEditPart().getModel(); |
| if (GMFNotationHelper.isNoteAttachment(edge)) { |
| return super.getReconnectSourceCommand(request); |
| } |
| } |
| DEdge edge = null; |
| EdgeTarget target = null; |
| final ConnectionEditPart connectionEditPart = request.getConnectionEditPart(); |
| if (connectionEditPart.getModel() instanceof View && ((View) connectionEditPart.getModel()).getElement() instanceof DEdge) { |
| edge = (DEdge) ((View) connectionEditPart.getModel()).getElement(); |
| } |
| EdgeTarget source = null; |
| if (edge != null) { |
| source = edge.getSourceNode(); |
| } |
| if (request.getTarget().getModel() instanceof View && ((View) request.getTarget().getModel()).getElement() instanceof EdgeTarget) { |
| target = (EdgeTarget) ((View) request.getTarget().getModel()).getElement(); |
| } |
| |
| Command cmd = UnexecutableCommand.INSTANCE; |
| |
| if (source != null && target != null) { |
| if (target != source) { |
| Option<EdgeMapping> edgeMapping = new IEdgeMappingQuery(edge.getActualMapping()).getEdgeMapping(); |
| final ReconnectEdgeDescription tool = edgeMapping.some() ? getBestTool(edgeMapping.get(), true, source, target, edge, true) : null; |
| if (tool != null) { |
| final CompoundCommand result = new CompoundCommand(); |
| result.add(this.getToolCommand(tool, edge, source, target)); |
| result.add(getReconnectSourceCommandAfterTool(request)); |
| cmd = result; |
| } |
| } else if (isCenteredEnd(connectionEditPart, edge, CenteringStyle.SOURCE)) { |
| cmd = UnexecutableCommand.INSTANCE; |
| } else if (applySpecificTreeLayout(request.getConnectionEditPart())) { |
| cmd = getReconnectSourceForTreeLayoutCommand(request); |
| } else { |
| ConnectionEditPartQuery cepq = new ConnectionEditPartQuery(request.getConnectionEditPart()); |
| if (cepq.isEdgeWithObliqueRoutingStyle() || cepq.isEdgeWithRectilinearRoutingStyle()) { |
| cmd = getReconnectSourceOrTargetForObliqueOrRectilinearCommand(request, true); |
| } else { |
| cmd = super.getReconnectSourceCommand(request); |
| } |
| } |
| |
| } |
| |
| return cmd; |
| } |
| |
| /** |
| * Same behavior has super.getReconnectSourceCommand but using a custom |
| * SetConnectionAnchorsCommand because modification on reconnected edge are |
| * now done in precommit. |
| * |
| * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getReconnectSourceCommand(org.eclipse.gef.requests.ReconnectRequest) |
| */ |
| private Command getReconnectSourceCommandAfterTool(ReconnectRequest request) { |
| INodeEditPart node = getConnectableEditPart(); |
| if (node == null) { |
| return null; |
| } |
| |
| TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); |
| |
| ConnectionAnchor sourceAnchor = node.getSourceConnectionAnchor(request); |
| View sourceView = (View) request.getTarget().getModel(); |
| SiriusSetConnectionAnchorsCommand scaCommand = new SiriusSetConnectionAnchorsCommand(editingDomain, DiagramUIMessages.Commands_SetConnectionEndsCommand_Source, sourceView, |
| sourceView.getSourceEdges(), ReconnectionKind.RECONNECT_SOURCE_LITERAL); |
| scaCommand.setNewSourceTerminal(node.mapConnectionAnchorToTerminal(sourceAnchor)); |
| |
| // We retrieve the current target anchor and set it in the |
| // SiriusSetConnectionAnchorsCommand. when reconnecting the edge, a new |
| // edge is created and the anchor is lost, we need to set it back. |
| Connection connection = (Connection) ((GraphicalEditPart) request.getConnectionEditPart()).getFigure(); |
| ConnectionAnchor connectionAnchor = connection.getTargetAnchor(); |
| if (connectionAnchor instanceof BaseSlidableAnchor) { |
| String targetTerminal = ((BaseSlidableAnchor) connectionAnchor).getTerminal(); |
| scaCommand.setNewTargetTerminal(targetTerminal); |
| } |
| |
| CompositeCommand cc = new CompositeCommand(DiagramUIMessages.Commands_SetConnectionEndsCommand_Source); |
| cc.compose(scaCommand); |
| |
| // The router is the same, therefore the bendpoint of the new |
| // reconnected edge are set accordingly to the feedback of the |
| // previous edge under reconnection |
| |
| // Set points of Edge as they are graphically |
| Point tempSourceRefPoint = connection.getSourceAnchor().getReferencePoint(); |
| connection.translateToRelative(tempSourceRefPoint); |
| |
| Point tempTargetRefPoint = connection.getTargetAnchor().getReferencePoint(); |
| connection.translateToRelative(tempTargetRefPoint); |
| |
| PointList connectionPointList = connection.getPoints().getCopy(); |
| |
| restoreMissingBendpointOverCandidate(request, connectionPointList); |
| |
| // Set the connection bendpoints with a PointList using a command |
| SetReconnectingConnectionBendpointsCommand sbbCommand = new SetReconnectingConnectionBendpointsCommand(editingDomain, sourceView, sourceView.getSourceEdges(), |
| ReconnectionKind.RECONNECT_SOURCE_LITERAL); |
| sbbCommand.setNewPointList(connectionPointList, tempSourceRefPoint, tempTargetRefPoint); |
| if (request.getConnectionEditPart() instanceof org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) { |
| sbbCommand.setLabelsToUpdate((org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) request.getConnectionEditPart()); |
| } |
| |
| cc.compose(sbbCommand); |
| return new ICommandProxy(cc); |
| } |
| |
| @Override |
| protected Command getReconnectTargetCommand(final ReconnectRequest request) { |
| if (request.getConnectionEditPart().getModel() instanceof Edge) { |
| final Edge edge = (Edge) request.getConnectionEditPart().getModel(); |
| if (GMFNotationHelper.isNoteAttachment(edge)) { |
| return super.getReconnectTargetCommand(request); |
| } |
| } |
| DEdge edge = null; |
| EdgeTarget target = null; |
| final ConnectionEditPart connectionEditPart = request.getConnectionEditPart(); |
| if (connectionEditPart.getModel() instanceof View && ((View) connectionEditPart.getModel()).getElement() instanceof DEdge) { |
| edge = (DEdge) ((View) connectionEditPart.getModel()).getElement(); |
| } |
| EdgeTarget source = null; |
| if (edge != null) { |
| source = edge.getTargetNode(); |
| } |
| if (request.getTarget().getModel() instanceof View && ((View) request.getTarget().getModel()).getElement() instanceof EdgeTarget) { |
| target = (EdgeTarget) ((View) request.getTarget().getModel()).getElement(); |
| } |
| |
| Command cmd = UnexecutableCommand.INSTANCE; |
| if (source != null && target != null) { |
| if (target != source) { |
| Option<EdgeMapping> edgeMapping = new IEdgeMappingQuery(edge.getActualMapping()).getEdgeMapping(); |
| final ReconnectEdgeDescription tool = edgeMapping.some() ? getBestTool(edgeMapping.get(), false, source, target, edge, true) : null; |
| if (tool != null) { |
| final CompoundCommand result = new CompoundCommand(); |
| result.add(this.getToolCommand(tool, edge, source, target)); |
| result.add(getReconnectTargetCommandAfterTool(request)); |
| cmd = result; |
| } |
| } else if (isCenteredEnd(connectionEditPart, edge, CenteringStyle.TARGET)) { |
| cmd = UnexecutableCommand.INSTANCE; |
| } else { |
| ConnectionEditPartQuery cepq = new ConnectionEditPartQuery(request.getConnectionEditPart()); |
| if (cepq.isEdgeWithTreeRoutingStyle() && applySpecificTreeLayout(request.getConnectionEditPart())) { |
| cmd = getReconnectTargetForTreeLayoutCommand(request); |
| } else if (cepq.isEdgeWithObliqueRoutingStyle() || cepq.isEdgeWithRectilinearRoutingStyle()) { |
| cmd = getReconnectSourceOrTargetForObliqueOrRectilinearCommand(request, false); |
| } else { |
| cmd = super.getReconnectTargetCommand(request); |
| } |
| } |
| } |
| return cmd; |
| } |
| |
| private Command getReconnectSourceOrTargetForObliqueOrRectilinearCommand(ReconnectRequest request, boolean source) { |
| INodeEditPart node = getConnectableEditPart(); |
| INodeEditPart targetEP = getConnectionCompleteEditPart(request); |
| if (node == null || targetEP == null) { |
| return null; |
| } |
| |
| TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); |
| |
| ConnectionAnchor targetAnchor = getConnectionTargetAnchor(request); |
| |
| // Creation of the command that set the connection end points (source |
| // and target) |
| SetConnectionEndsCommand sceCommand = new SetConnectionEndsCommand(editingDomain, StringStatics.BLANK); |
| sceCommand.setEdgeAdaptor(new EObjectAdapter((EObject) request.getConnectionEditPart().getModel())); |
| if (source) { |
| sceCommand.setNewSourceAdaptor(targetEP); |
| } else { |
| sceCommand.setNewTargetAdaptor(targetEP); |
| } |
| // Creation of the command that set the connection anchors (also source |
| // and target) |
| SetConnectionAnchorsCommand scaCommand = new SetConnectionAnchorsCommand(editingDomain, StringStatics.BLANK); |
| scaCommand.setEdgeAdaptor(new EObjectAdapter((EObject) request.getConnectionEditPart().getModel())); |
| if (source) { |
| scaCommand.setNewSourceTerminal(targetEP.mapConnectionAnchorToTerminal(targetAnchor)); |
| } else { |
| scaCommand.setNewTargetTerminal(targetEP.mapConnectionAnchorToTerminal(targetAnchor)); |
| } |
| // Both command are composed in a composite command |
| CompositeCommand cc = new CompositeCommand(DiagramUIMessages.Commands_SetConnectionEndsCommand_Target); |
| cc.compose(sceCommand); |
| cc.compose(scaCommand); |
| // Set points of Edge as they are graphically |
| Connection connection = (Connection) ((GraphicalEditPart) request.getConnectionEditPart()).getFigure(); |
| Point tempSourceRefPoint = connection.getSourceAnchor().getReferencePoint(); |
| connection.translateToRelative(tempSourceRefPoint); |
| |
| Point tempTargetRefPoint = connection.getTargetAnchor().getReferencePoint(); |
| connection.translateToRelative(tempTargetRefPoint); |
| |
| PointList connectionPointList = connection.getPoints().getCopy(); |
| |
| // Set the connection bendpoints with a PointList using a command |
| SetConnectionBendpointsAndLabelCommmand sbbCommand = new SetConnectionBendpointsAndLabelCommmand(editingDomain); |
| sbbCommand.setEdgeAdapter(request.getConnectionEditPart()); |
| sbbCommand.setNewPointList(connectionPointList, tempSourceRefPoint, tempTargetRefPoint); |
| if (request.getConnectionEditPart() instanceof org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) { |
| sbbCommand.setLabelsToUpdate((org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) request.getConnectionEditPart(), |
| InitialPointsOfRequestDataManager.getOriginalPoints(request)); |
| } |
| cc.compose(sbbCommand); |
| |
| return new ICommandProxy(cc); |
| } |
| |
| private boolean isCenteredEnd(ConnectionEditPart connectionEditPart, DEdge edge, CenteringStyle centeringStyle) { |
| boolean returnValue = false; |
| EdgeStyle edgeStyle = edge.getOwnedStyle(); |
| if (edgeStyle != null) { |
| returnValue = edgeStyle.getCentered() == CenteringStyle.BOTH || edgeStyle.getCentered() == centeringStyle; |
| // if the edge is rectilinear and has only two bendpoints, we |
| // also forbid to move the opposite end, otherwise all the segment |
| // move. |
| if (!returnValue && EdgeRouting.MANHATTAN_LITERAL.getLiteral().equals(edgeStyle.getRoutingStyle().getLiteral())) { |
| IFigure figure = connectionEditPart.getFigure(); |
| if (figure instanceof Connection) { |
| returnValue = ((Connection) figure).getPoints().size() <= 2; |
| } |
| } |
| } |
| |
| return returnValue; |
| } |
| |
| /** |
| * Same behavior has super.getReconnectTargetCommand but using a custom |
| * SetConnectionAnchorsCommand because modification on reconnected edge are |
| * now done in precommit. |
| * |
| * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getReconnectTargetCommand(org.eclipse.gef.requests.ReconnectRequest) |
| */ |
| private Command getReconnectTargetCommandAfterTool(ReconnectRequest request) { |
| INodeEditPart node = getConnectableEditPart(); |
| if (node == null || getConnectionCompleteEditPart(request) == null) { |
| return null; |
| } |
| |
| TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); |
| |
| ConnectionAnchor targetAnchor = getConnectionTargetAnchor(request); |
| INodeEditPart targetEP = getConnectionCompleteEditPart(request); |
| |
| View targetView = (View) targetEP.getModel(); |
| SiriusSetConnectionAnchorsCommand scaCommand = new SiriusSetConnectionAnchorsCommand(editingDomain, DiagramUIMessages.Commands_SetConnectionEndsCommand_Target, targetView, |
| targetView.getTargetEdges(), ReconnectionKind.RECONNECT_TARGET_LITERAL); |
| scaCommand.setNewTargetTerminal(targetEP.mapConnectionAnchorToTerminal(targetAnchor)); |
| |
| // We retrieve the current source anchor and set it in the |
| // SiriusSetConnectionAnchorsCommand. when reconnecting the edge, a new |
| // edge is created and the anchor is lost, we need to set it back. |
| ConnectionEditPart cep = request.getConnectionEditPart(); |
| Connection connection = (Connection) cep.getFigure(); |
| ConnectionAnchor connectionAnchor = connection.getSourceAnchor(); |
| if (connectionAnchor instanceof BaseSlidableAnchor) { |
| String sourceTerminal = ((BaseSlidableAnchor) connectionAnchor).getTerminal(); |
| scaCommand.setNewSourceTerminal(sourceTerminal); |
| } |
| |
| Command cmd = new ICommandProxy(scaCommand); |
| |
| RoutingStyle style = (RoutingStyle) ((View) cep.getModel()).getStyle(NotationPackage.eINSTANCE.getRoutingStyle()); |
| Routing currentRouter = Routing.MANUAL_LITERAL; |
| if (style != null) { |
| currentRouter = style.getRouting(); |
| } |
| Command cmdRouter = getRoutingAdjustment(request.getConnectionEditPart(), getSemanticHint(request), currentRouter, request.getTarget()); |
| if (cmdRouter != null) { |
| // The router has changed, therefore bendpoints are "reset" to only |
| // source and target |
| cmd = cmd.chain(cmdRouter); |
| // reset the bendpoints |
| ConnectionAnchor sourceAnchor = node.getSourceConnectionAnchor(request); |
| PointList pointList = new PointList(); |
| pointList.addPoint(sourceAnchor.getLocation(targetAnchor.getReferencePoint())); |
| pointList.addPoint(targetAnchor.getLocation(sourceAnchor.getReferencePoint())); |
| |
| SetReconnectingConnectionBendpointsCommand sbbCommand = new SetReconnectingConnectionBendpointsCommand(editingDomain, targetView, targetView.getTargetEdges(), |
| ReconnectionKind.RECONNECT_TARGET_LITERAL); |
| sbbCommand.setNewPointList(pointList, sourceAnchor.getReferencePoint(), targetAnchor.getReferencePoint()); |
| if (request.getConnectionEditPart() instanceof org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) { |
| sbbCommand.setLabelsToUpdate((org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) request.getConnectionEditPart()); |
| } |
| Command cmdBP = new ICommandProxy(sbbCommand); |
| if (cmdBP != null) { |
| cmd = cmd.chain(cmdBP); |
| } |
| } else { |
| // The router is the same, therefore the bendpoint of the new |
| // reconnected edge are set accordingly to the feedback of the |
| // previous edge under reconnection |
| |
| // Set points of Edge as they are graphically |
| Point tempSourceRefPoint = connection.getSourceAnchor().getReferencePoint(); |
| connection.translateToRelative(tempSourceRefPoint); |
| |
| Point tempTargetRefPoint = connection.getTargetAnchor().getReferencePoint(); |
| connection.translateToRelative(tempTargetRefPoint); |
| |
| PointList connectionPointList = connection.getPoints().getCopy(); |
| |
| restoreMissingBendpointOverCandidate(request, connectionPointList); |
| |
| // Set the connection bendpoints with a PointList using a command |
| SetReconnectingConnectionBendpointsCommand sbbCommand = new SetReconnectingConnectionBendpointsCommand(editingDomain, targetView, targetView.getTargetEdges(), |
| ReconnectionKind.RECONNECT_TARGET_LITERAL); |
| sbbCommand.setNewPointList(connectionPointList, tempSourceRefPoint, tempTargetRefPoint); |
| if (request.getConnectionEditPart() instanceof org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) { |
| sbbCommand.setLabelsToUpdate((org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) request.getConnectionEditPart()); |
| } |
| |
| Command cmdBP = new ICommandProxy(sbbCommand); |
| if (cmdBP != null) { |
| cmd = cmd == null ? cmdBP : cmd.chain(cmdBP); |
| } |
| |
| } |
| return cmd; |
| } |
| |
| /** |
| * Because the feedback is handled by SiriusConnectionEndPointEditPolicy and |
| * the reconnection is handled by the current policy, when the reconnection |
| * switch to another target candidate some bendpoints can be missing on |
| * reconnection. The missing bendpoints are the result of the ObliqueRouter |
| * that removes bendpoints over the target candidate. |
| * |
| * @param request |
| * current {@link ReconnectRequest} |
| * @param connectionPointList |
| * Bendpoint location of the edge under reconnection |
| */ |
| private void restoreMissingBendpointOverCandidate(ReconnectRequest request, PointList connectionPointList) { |
| Edge edge = (Edge) request.getConnectionEditPart().getModel(); |
| Bendpoints bendpoints = edge.getBendpoints(); |
| Point sourceEndAnchorLocation = null; |
| Point targetEndAnchorLocation = null; |
| DEdge dedge = (DEdge) edge.getElement(); |
| |
| if (!EdgeRouting.STRAIGHT_LITERAL.equals(((EdgeStyle) dedge.getStyle()).getRoutingStyle()) |
| || bendpoints instanceof RelativeBendpoints && connectionPointList.size() == ((RelativeBendpoints) bendpoints).getPoints().size()) { |
| // Only the oblique router can remove bendpoints or there is no |
| // missing bendpoint here. Move Along. |
| return; |
| } |
| |
| // Computation of the location of the anchor on the end that is not |
| // under reconnection |
| sourceEndAnchorLocation = getAnchorLocation(((GraphicalEditPart) request.getConnectionEditPart().getSource()).getFigure().getBounds(), edge.getSourceAnchor()); |
| targetEndAnchorLocation = getAnchorLocation(((GraphicalEditPart) request.getConnectionEditPart().getTarget()).getFigure().getBounds(), edge.getTargetAnchor()); |
| |
| // Computation of the bendpoints locations before reconnection using |
| // data from the gmf model instead of the figure (unreliable as it |
| // updates during reconnection) |
| ArrayList<Point> previousBendpoints = Lists.<Point> newArrayList(); |
| if (bendpoints instanceof RelativeBendpoints && sourceEndAnchorLocation != null && targetEndAnchorLocation != null) { |
| RelativeBendpoints relativeBendpoints = (RelativeBendpoints) bendpoints; |
| List<?> points = relativeBendpoints.getPoints(); |
| for (RelativeBendpoint rbp : Iterables.filter(points, RelativeBendpoint.class)) { |
| Point benpointLocationFromSource = sourceEndAnchorLocation.getTranslated(rbp.getSourceX(), rbp.getSourceY()); |
| Point benpointLocationFromTarget = targetEndAnchorLocation.getTranslated(rbp.getTargetX(), rbp.getTargetY()); |
| if (!benpointLocationFromSource.equals(benpointLocationFromTarget)) { |
| // if bendpoint location computed from source and target are |
| // different, the edge is an average of both. We don't have |
| // reliable coordinates to process here but these |
| // coordinates will be matching after reconnection. |
| return; |
| } |
| previousBendpoints.add(benpointLocationFromSource); |
| } |
| } |
| |
| // Detection of bendpoints missing in the current connectionPointList |
| // compare to the original bendpoints |
| LinkedHashMap<Integer, Point> pointToAddByIndexMap = Maps.<Integer, Point> newLinkedHashMap(); |
| // We ignore the first and last bendpoints as they can't be hidden |
| for (int i = 1; i <= previousBendpoints.size() - 2; i++) { |
| // When a missing bendpoint is found the index must only increase |
| // for the list containing all bendpoints |
| if (connectionPointList.size() > i - pointToAddByIndexMap.keySet().size() && !connectionPointList.getPoint(i - pointToAddByIndexMap.keySet().size()).equals(previousBendpoints.get(i))) { |
| // Note that we could exclude the bendpoint over the target |
| // candidate but it will be handled by the ObliqueRouteur |
| pointToAddByIndexMap.put(i, previousBendpoints.get(i)); |
| } |
| } |
| |
| // Addition of the missing bendpoint at the expected index |
| pointToAddByIndexMap.forEach((index, point) -> connectionPointList.insertPoint(point, index)); |
| } |
| |
| /** |
| * Compute anchor location using its end bounds. |
| * |
| * @param untouchedEndBounds |
| * bounds of the element on which is the anchor |
| * @param previousAnchor |
| * the Anchor used to compute location |
| * @return the location of the anchor |
| */ |
| private Point getAnchorLocation(Rectangle untouchedEndBounds, Anchor previousAnchor) { |
| Point result = null; |
| PrecisionPoint rel = new PrecisionPoint(0.5, 0.5); |
| // Note that the anchor will be null if it is centered |
| if (previousAnchor instanceof IdentityAnchor) { |
| rel = BaseSlidableAnchor.parseTerminalString(((IdentityAnchor) previousAnchor).getId()); |
| } |
| result = new PrecisionPoint(untouchedEndBounds.getLocation().x + untouchedEndBounds.width * rel.preciseX(), untouchedEndBounds.getLocation().y + untouchedEndBounds.height * rel.preciseY()); |
| return result; |
| } |
| |
| private ReconnectEdgeDescription getBestTool(final EdgeMapping mapping, final boolean source, final EdgeTarget oldTarget, final EdgeTarget newTarget, final DEdge edge, |
| boolean computePreCondition) { |
| final List<ReconnectEdgeDescription> candidateTool = new ArrayList<ReconnectEdgeDescription>(mapping.getReconnections()); |
| |
| ReconnectEdgeDescription bestTool = null; |
| EObject semanticSource = null; |
| EObject semanticTarget = null; |
| EObject semanticElement = null; |
| |
| if (oldTarget instanceof DSemanticDecorator) { |
| semanticSource = ((DSemanticDecorator) oldTarget).getTarget(); |
| } |
| if (newTarget instanceof DSemanticDecorator) { |
| semanticTarget = ((DSemanticDecorator) newTarget).getTarget(); |
| } |
| semanticElement = ((DSemanticDecorator) edge).getTarget(); |
| |
| // get the tool that applies on source or target. |
| selectReconnectionToolCandidates(candidateTool, source); |
| |
| if (!candidateTool.isEmpty()) { |
| Iterator<ReconnectEdgeDescription> toolIterator = candidateTool.iterator(); |
| // Check precondtion |
| while (toolIterator.hasNext()) { |
| final ReconnectEdgeDescription myTool = toolIterator.next(); |
| final String precondition = myTool.getPrecondition(); |
| if (computePreCondition && precondition != null && !StringUtil.isEmpty(precondition)) { |
| |
| final IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticElement); |
| |
| interpreter.setVariable(IInterpreterSiriusVariables.DIAGRAM, edge.getParentDiagram()); |
| interpreter.setVariable(IInterpreterSiriusVariables.SOURCE, semanticSource); |
| interpreter.setVariable(IInterpreterSiriusVariables.SOURCE_VIEW, oldTarget); |
| interpreter.setVariable(IInterpreterSiriusVariables.TARGET, semanticTarget); |
| interpreter.setVariable(IInterpreterSiriusVariables.TARGET_VIEW, newTarget); |
| interpreter.setVariable(IInterpreterSiriusVariables.ELEMENT, semanticElement); |
| |
| final boolean preconditionOK = RuntimeLoggerManager.INSTANCE.decorate(interpreter).evaluateBoolean(semanticElement, myTool, |
| ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition()); |
| if (!preconditionOK) { |
| toolIterator.remove(); |
| } |
| |
| interpreter.unSetVariable(IInterpreterSiriusVariables.SOURCE); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.TARGET); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.ELEMENT); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.DIAGRAM); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.SOURCE_VIEW); |
| interpreter.unSetVariable(IInterpreterSiriusVariables.TARGET_VIEW); |
| } |
| } |
| // Check that the mapping of the new end is in the |
| // authorized list. |
| toolIterator = candidateTool.iterator(); |
| while (toolIterator.hasNext()) { |
| final ReconnectEdgeDescription myTool = toolIterator.next(); |
| if (!new ReconnectEdgeDescriptionQuery(myTool).isEndAuthorized(source, newTarget)) { |
| toolIterator.remove(); |
| } |
| } |
| |
| } |
| if (!candidateTool.isEmpty()) { |
| bestTool = candidateTool.get(0); |
| } |
| |
| return bestTool; |
| |
| } |
| |
| private void selectReconnectionToolCandidates(final List<ReconnectEdgeDescription> candidateTool, final boolean source) { |
| final Iterator<ReconnectEdgeDescription> iterTools = candidateTool.iterator(); |
| while (iterTools.hasNext()) { |
| final ReconnectEdgeDescription currentTool = iterTools.next(); |
| if ((source && currentTool.getReconnectionKind() == ReconnectionKind.RECONNECT_TARGET_LITERAL) |
| || (!source && currentTool.getReconnectionKind() == ReconnectionKind.RECONNECT_SOURCE_LITERAL)) { |
| iterTools.remove(); |
| } |
| } |
| } |
| |
| private Command getToolCommand(final ReconnectEdgeDescription tool, final DEdge edge, final EdgeTarget source, final EdgeTarget target) { |
| final DDiagramEditor diagramEditor = (DDiagramEditor) this.getHost().getViewer().getProperty(DDiagramEditor.EDITOR_ID); |
| if (diagramEditor != null) { |
| final Object adapter = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class); |
| final IDiagramCommandFactoryProvider cmdFactoryProvider = (IDiagramCommandFactoryProvider) adapter; |
| final TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(source); |
| final IDiagramCommandFactory emfCommandFactory = cmdFactoryProvider.getCommandFactory(domain); |
| return new ICommandProxy(new GMFCommandWrapper(domain, emfCommandFactory.buildReconnectEdgeCommandFromTool(tool, edge, source, target))); |
| } |
| return UnexecutableCommand.INSTANCE; |
| } |
| |
| @Override |
| protected Command getConnectionCreateCommand(CreateConnectionRequest request) { |
| Command connectionCreateCommand = null; |
| if (request instanceof CreateConnectionViewRequest) { |
| connectionCreateCommand = super.getConnectionCreateCommand(request); |
| } else { |
| if (CreateConnectionRequestHelper.computeConnectionStartExtendedData(request, getConnectableEditPart())) { |
| connectionCreateCommand = new ICommandProxy(IdentityCommand.INSTANCE); |
| } |
| } |
| if (connectionCreateCommand == null) { |
| connectionCreateCommand = super.getConnectionCreateCommand(request); |
| } |
| return connectionCreateCommand; |
| } |
| |
| @Override |
| protected Command getConnectionCompleteCommand(final CreateConnectionRequest request) { |
| Command connectionCompleteCommand = null; |
| |
| if (new RequestQuery(request).isNoteAttachmentCreationRequest()) { |
| connectionCompleteCommand = super.getConnectionCompleteCommand(request); |
| } else { |
| connectionCompleteCommand = buildSiriusConnectionCreationCmd(request); |
| } |
| return connectionCompleteCommand; |
| } |
| |
| private Command buildSiriusConnectionCreationCmd(CreateConnectionRequest request) { |
| Command viewpointConnectionCreationCmd = null; |
| INodeEditPart targetEP = getConnectionCompleteEditPart(request); |
| if (targetEP != null) { |
| |
| INodeEditPart sourceEditPart = (INodeEditPart) request.getSourceEditPart(); |
| |
| // Location relative to the source: Position where the user |
| // clicked, but snapped to grid if this feature is enabled |
| Point sourceLocation = getEdgeLocationSource(request); |
| // Location relative to the target: Position where the user |
| // clicked, but snapped to grid if this feature is enabled |
| Point targetLocation = getConvertedLocation(request); |
| EdgeLayoutData edgeLayoutData; |
| if (GraphicalHelper.isSnapToGridEnabled(sourceEditPart)) { |
| edgeLayoutData = getEdgeLayoutDataWithSnapToGrid(request, sourceEditPart, targetEP, sourceLocation, targetLocation); |
| } else { |
| edgeLayoutData = getEdgeLayoutData(request, sourceEditPart, targetEP, sourceLocation, targetLocation); |
| } |
| |
| DSemanticDecorator decorateSemanticElement = null; |
| if (this.getHost().getModel() instanceof View) { |
| View view = (View) this.getHost().getModel(); |
| if (view.getElement() instanceof DSemanticDecorator) { |
| decorateSemanticElement = (DSemanticDecorator) view.getElement(); |
| } |
| } |
| if (decorateSemanticElement instanceof EdgeTarget && request.getExtendedData().get(GMF_EDGE_CREATION_DESCRIPTION) instanceof EdgeCreationDescription) { |
| EdgeTarget source = (EdgeTarget) request.getExtendedData().get(GMF_EDGE_TARGET_SOURCE); |
| if (source != null) { |
| EdgeTarget target = (EdgeTarget) decorateSemanticElement; |
| EdgeCreationDescription edgeCreationDescription = (EdgeCreationDescription) request.getExtendedData().get(GMF_EDGE_CREATION_DESCRIPTION); |
| boolean canCreate = new EdgeCreationDescriptionQuery(edgeCreationDescription).canBeAppliedOn((DMappingBased) source, (DMappingBased) target); |
| if (canCreate) { |
| DDiagramEditor diagramEditor = (DDiagramEditor) this.getHost().getViewer().getProperty(DDiagramEditor.EDITOR_ID); |
| IDiagramCommandFactoryProvider cmdFactoryProvider = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class); |
| viewpointConnectionCreationCmd = buildCreateEdgeCommand(request, source, target, edgeCreationDescription, cmdFactoryProvider, edgeLayoutData); |
| } |
| } |
| } |
| } |
| return viewpointConnectionCreationCmd; |
| } |
| |
| /** |
| * Create the edge layout data that will be used later after the refresh. |
| * |
| * @param request |
| * The original creation request |
| * @param sourceEditPart |
| * the {@link EditPart} that the source end of the connection |
| * should be connected to. |
| * @param targetEditPart |
| * the {@link EditPart} that the target end of the connection |
| * should be connected to. |
| * @param sourceLocation |
| * the location of the first click (relative to the source edit |
| * part) |
| * @param targetLocation |
| * the location of the second click (relative to the target edit |
| * part) |
| * @return The edge layout data corresponding to the creation request. |
| */ |
| protected EdgeLayoutData getEdgeLayoutData(CreateConnectionRequest request, INodeEditPart sourceEditPart, INodeEditPart targetEditPart, Point sourceLocation, Point targetLocation) { |
| String newSourceTerminal = getEdgeTerminalSource(request); |
| ConnectionAnchor sourceAnchor = sourceEditPart.mapTerminalToConnectionAnchor(newSourceTerminal); |
| |
| ConnectionAnchor targetAnchor = targetEditPart.getTargetConnectionAnchor(request); |
| String newTargetTerminal = targetEditPart.mapConnectionAnchorToTerminal(targetAnchor); |
| |
| Point sourceRefPoint = sourceAnchor.getReferencePoint(); |
| Point targetRefPoint = targetAnchor.getReferencePoint(); |
| |
| PointList pointList = new PointList(); |
| if (request.getLocation() == null) { |
| pointList.addPoint(sourceAnchor.getLocation(targetAnchor.getReferencePoint())); |
| pointList.addPoint(targetAnchor.getLocation(sourceAnchor.getReferencePoint())); |
| } else { |
| pointList.addPoint(sourceAnchor.getLocation(request.getLocation())); |
| pointList.addPoint(targetAnchor.getLocation(request.getLocation())); |
| } |
| |
| final LayoutData sourceLayoutData = new RootLayoutData(sourceEditPart, sourceLocation.getCopy(), null); |
| final LayoutData targetLayoutData = new RootLayoutData(targetEditPart, targetLocation.getCopy(), null); |
| EdgeLayoutData edgeLayoutData = new EdgeLayoutData(sourceLayoutData, targetLayoutData); |
| |
| edgeLayoutData.setSourceTerminal("" + newSourceTerminal); //$NON-NLS-1$ |
| edgeLayoutData.setTargetTerminal("" + newTargetTerminal); //$NON-NLS-1$ |
| |
| edgeLayoutData.setPointList(pointList.getCopy()); |
| edgeLayoutData.setSourceRefPoint(sourceRefPoint.getCopy()); |
| edgeLayoutData.setTargetRefPoint(targetRefPoint.getCopy()); |
| return edgeLayoutData; |
| } |
| |
| /** |
| * Create the edge layout data that will be used later after the refresh. |
| * According to |
| * {@link #getEdgeLayoutData(CreateConnectionRequest, INodeEditPart, INodeEditPart, Point, Point)} |
| * this method ensures that the first point and the last point of the edge |
| * will be snap to the grid (at least one of there coordinates. The other is |
| * constrained by the side of the source (or the target).<BR> |
| * This is not possible to do it earlier (in feedback for example) because |
| * we should know source and target data to compute the new source and |
| * target location. |
| * |
| * @param request |
| * The original creation request |
| * @param sourceEditPart |
| * the {@link EditPart} that the source end of the connection |
| * should be connected to. |
| * @param targetEditPart |
| * the {@link EditPart} that the target end of the connection |
| * should be connected to. |
| * @param sourceLocation |
| * the location of the first click (relative to the source edit part), snapped to grid if feature enabled |
| * @param targetLocation |
| * the location of the second click (relative to the target edit part), snapped to grid if feature |
| * enabled |
| * @return The edge layout data corresponding to the creation request and to |
| * the snapToGrid state. |
| */ |
| protected EdgeLayoutData getEdgeLayoutDataWithSnapToGrid(CreateConnectionRequest request, INodeEditPart sourceEditPart, INodeEditPart targetEditPart, Point sourceLocation, Point targetLocation) { |
| IGraphicalEditPart srcEditPart = (IGraphicalEditPart) sourceEditPart; |
| IGraphicalEditPart tgtEditPart = (IGraphicalEditPart) targetEditPart; |
| |
| // Get the absolute source and target location but in 100% to facilitate |
| // the computing |
| Rectangle absoluteSourceBoundsIn100Percent = GraphicalHelper.getAbsoluteBoundsIn100Percent(sourceEditPart); |
| Point absoluteSourceLocationIn100Percent = sourceLocation.getTranslated(absoluteSourceBoundsIn100Percent.getTopLeft()); |
| Rectangle absoluteTargetBoundsIn100Percent = GraphicalHelper.getAbsoluteBoundsIn100Percent(targetEditPart); |
| Point absoluteTargetLocationIn100Percent = targetLocation.getTranslated(absoluteTargetBoundsIn100Percent.getTopLeft()); |
| |
| // Compute intersection between the line (source location<-->target |
| // location) and the source node |
| Optional<Point> intersectionSourcePoint = GraphicalHelper.getIntersection(absoluteSourceLocationIn100Percent, absoluteTargetLocationIn100Percent, srcEditPart, false, true); |
| // Compute intersection between the line (source location<-->target |
| // location) and the target node |
| Optional<Point> intersectionTargetPoint = GraphicalHelper.getIntersection(absoluteSourceLocationIn100Percent, absoluteTargetLocationIn100Percent, tgtEditPart, true, true); |
| // Compute the snap source location and the snap target location |
| if (intersectionSourcePoint.isPresent() && intersectionTargetPoint.isPresent()) { |
| PointList sourceSnappedPoints = snapLocationToGridAndToParentBorder(absoluteSourceLocationIn100Percent, absoluteSourceBoundsIn100Percent, intersectionSourcePoint.get()); |
| PointList targetSnappedPoints = snapLocationToGridAndToParentBorder(absoluteTargetLocationIn100Percent, absoluteTargetBoundsIn100Percent, intersectionTargetPoint.get()); |
| EdgeLayoutData edgeLayoutData = createEdgeLayoutData(srcEditPart, tgtEditPart, absoluteSourceBoundsIn100Percent, absoluteTargetBoundsIn100Percent, sourceSnappedPoints.getFirstPoint(), |
| targetSnappedPoints.getFirstPoint()); |
| EdgeLayoutData edgeLayoutData2 = createEdgeLayoutData(srcEditPart, tgtEditPart, absoluteSourceBoundsIn100Percent, absoluteTargetBoundsIn100Percent, sourceSnappedPoints.getLastPoint(), |
| targetSnappedPoints.getLastPoint()); |
| edgeLayoutData.setEdgeLayoutDataForBorderNodes(edgeLayoutData2); |
| return edgeLayoutData; |
| } else { |
| // There is probably a case not handle, use the default layout data |
| return getEdgeLayoutData(request, sourceEditPart, targetEditPart, sourceLocation, targetLocation); |
| } |
| } |
| |
| private EdgeLayoutData createEdgeLayoutData(IGraphicalEditPart sourceEditPart, IGraphicalEditPart targetEditPart, Rectangle absoluteSourceBoundsIn100Percent, |
| Rectangle absoluteTargetBoundsIn100Percent, Point absoluteSourceLocationSnapIn100Percent, Point absoluteTargetLocationSnapIn100Percent) { |
| EdgeLayoutData edgeLayoutData; |
| // Make snap source point relative to the source edit part |
| Point sourceLocationSnapIn100Percent = getTranslatedToRelative(absoluteSourceLocationSnapIn100Percent, absoluteSourceBoundsIn100Percent); |
| final LayoutData sourceLayoutData = new RootLayoutData(sourceEditPart, sourceLocationSnapIn100Percent, null); |
| // Make snap target point relative to the source edit part |
| Point targetLocationSnapIn100Percent = getTranslatedToRelative(absoluteTargetLocationSnapIn100Percent, absoluteTargetBoundsIn100Percent); |
| final LayoutData targetLayoutData = new RootLayoutData(targetEditPart, targetLocationSnapIn100Percent, null); |
| edgeLayoutData = new EdgeLayoutData(sourceLayoutData, targetLayoutData); |
| // Compute the new source terminal anchor |
| PrecisionPoint sourceTerminalPosition = new PrecisionPoint((double) sourceLocationSnapIn100Percent.x / absoluteSourceBoundsIn100Percent.width, |
| (double) sourceLocationSnapIn100Percent.y / absoluteSourceBoundsIn100Percent.height); |
| String sourceTerminal = new SlidableAnchor(null, sourceTerminalPosition).getTerminal(); |
| edgeLayoutData.setSourceTerminal("" + sourceTerminal); //$NON-NLS-1$ |
| // Compute the new target terminal anchor |
| PrecisionPoint targetTerminalPosition = new PrecisionPoint((double) targetLocationSnapIn100Percent.x / absoluteTargetBoundsIn100Percent.width, |
| (double) targetLocationSnapIn100Percent.y / absoluteTargetBoundsIn100Percent.height); |
| String targetTerminal = new SlidableAnchor(null, targetTerminalPosition).getTerminal(); |
| edgeLayoutData.setTargetTerminal("" + targetTerminal); //$NON-NLS-1$ |
| // Applied the zoom of the current diagram to set the pointList, the |
| // source reference point and the target reference point. |
| PrecisionPoint absoluteSourceLocationSnap = new PrecisionPoint(absoluteSourceLocationSnapIn100Percent); |
| GraphicalHelper.logical2screen(absoluteSourceLocationSnap, sourceEditPart); |
| PrecisionPoint absoluteTargteLoactionSnap = new PrecisionPoint(absoluteTargetLocationSnapIn100Percent); |
| GraphicalHelper.logical2screen(absoluteTargteLoactionSnap, targetEditPart); |
| |
| edgeLayoutData.setSourceRefPoint(absoluteSourceLocationSnap); |
| edgeLayoutData.setTargetRefPoint(absoluteTargteLoactionSnap); |
| |
| PointList pointList = new PointList(); |
| pointList.addPoint(absoluteSourceLocationSnap.getCopy()); |
| pointList.addPoint(absoluteTargteLoactionSnap.getCopy()); |
| edgeLayoutData.setPointList(pointList.getCopy()); |
| return edgeLayoutData; |
| } |
| |
| /** |
| * @param absoluteLocation |
| * The location in absolute coordinates (and in 100%) |
| * @param absoluteParentBounds |
| * The parent bounds in absolute coordinates (and in 100%) |
| * @param intersectionPoint |
| * The intersection location in absolute coordinates (and in 100%) |
| * @return a list of 2 points: the first is the intersection point snap to grid and to parent border, the second is |
| * snap to grid but on the nearest side of the parent border according to the click location |
| */ |
| private PointList snapLocationToGridAndToParentBorder(Point absoluteLocation, Rectangle absoluteParentBounds, Point intersectionPoint) { |
| PointList result = new PointList(); |
| Point absoluteLocationSnapIn100PercentOnIntersection; |
| Point absoluteLocationSnapIn100PercentOnNearestSide; |
| if (intersectionPoint.x == absoluteParentBounds.x || intersectionPoint.x == (absoluteParentBounds.x + absoluteParentBounds.width)) { |
| int yCoordinate = absoluteLocation.y; |
| // If y coordinate of absoluteLocation is outside the parent |
| // (possible if the snapToGrid "has attached" the location outside), |
| // we use the nearer parent side has coordinate. |
| if (absoluteParentBounds.y > yCoordinate) { |
| yCoordinate = absoluteParentBounds.y; |
| } else if (yCoordinate > (absoluteParentBounds.y + absoluteParentBounds.height)) { |
| yCoordinate = absoluteParentBounds.y + absoluteParentBounds.height; |
| } |
| absoluteLocationSnapIn100PercentOnIntersection = new Point(intersectionPoint.x, yCoordinate); |
| // Compute the x coordinate according to the nearest parent side |
| int xCoordinate = intersectionPoint.x; |
| if (absoluteLocation.x - absoluteParentBounds.x > absoluteParentBounds.getRight().x - absoluteLocation.x) { |
| xCoordinate = absoluteParentBounds.getRight().x; |
| } |
| absoluteLocationSnapIn100PercentOnNearestSide = absoluteLocation.getCopy(); |
| } else { |
| int xCoordinate = absoluteLocation.x; |
| // If x coordinate of absoluteLocation is outside the parent |
| // (possible if the snapToGrid "has attached" the location outside), |
| // we use the nearer parent side has coordinate. |
| if (absoluteParentBounds.x > xCoordinate) { |
| xCoordinate = absoluteParentBounds.x; |
| } else if (xCoordinate > (absoluteParentBounds.x + absoluteParentBounds.width)) { |
| xCoordinate = absoluteParentBounds.x + absoluteParentBounds.width; |
| } |
| absoluteLocationSnapIn100PercentOnIntersection = new Point(xCoordinate, intersectionPoint.y); |
| // Compute the y coordinate according to the nearest parent side |
| int yCoordinate = absoluteLocation.y; |
| if (absoluteLocation.y - absoluteParentBounds.y > absoluteParentBounds.getBottom().y - absoluteLocation.y) { |
| yCoordinate = absoluteParentBounds.getBottom().y; |
| } |
| absoluteLocationSnapIn100PercentOnNearestSide = absoluteLocation.getCopy(); |
| } |
| result.addPoint(absoluteLocationSnapIn100PercentOnIntersection); |
| result.addPoint(absoluteLocationSnapIn100PercentOnNearestSide); |
| return result; |
| } |
| |
| /** |
| * Get a new location point relative to the parent. |
| * |
| * @param absoluteLocation |
| * The location in absolute coordinates (and in 100%) |
| * @param absoluteParentBounds |
| * The parent bounds in absolute coordinates (and in 100%) |
| * @return The location relative to the parent |
| */ |
| private Point getTranslatedToRelative(Point absoluteLocation, Rectangle absoluteParentBounds) { |
| return new Point(absoluteLocation.x - absoluteParentBounds.x, absoluteLocation.y - absoluteParentBounds.y); |
| } |
| |
| private Point getConvertedLocation(final CreateRequest request) { |
| return getConvertedLocation(request.getLocation().getCopy(), getHost(), false); |
| } |
| |
| /** |
| * Convert a location to a location relative to its parent ( |
| * <code>referencePart</code>). |
| * |
| * @param pointToConvert |
| * The point to convert |
| * @param referencePart |
| * The reference edit part. |
| * @param feedbackCoordinates |
| * true if the pointToConvert is from feedback, false otherwise |
| * (coordinates from request). The coordinates from feedback must |
| * be first adapted to remove diagram scrollbar to retrieve same |
| * coordinates as from request. |
| * @return The converted point. |
| */ |
| private Point getConvertedLocation(Point pointToConvert, EditPart referencePart, boolean feedbackCoordinates) { |
| Point realLocation; |
| if (pointToConvert != null && referencePart instanceof GraphicalEditPart) { |
| final IFigure fig = ((GraphicalEditPart) referencePart).getFigure(); |
| if (feedbackCoordinates) { |
| // Remove diagram scrollbar |
| pointToConvert.translate(GraphicalHelper.getScrollSize((GraphicalEditPart) referencePart).negate()); |
| } |
| fig.translateToRelative(pointToConvert); |
| final Point containerLocation = fig.getBounds().getLocation(); |
| realLocation = new Point(pointToConvert.x - containerLocation.x, pointToConvert.y - containerLocation.y); |
| if (fig instanceof ResizableCompartmentFigure) { |
| final Point scrollOffset = ((ResizableCompartmentFigure) fig).getScrollPane().getViewport().getViewLocation(); |
| realLocation = new Point(realLocation.x + scrollOffset.x, realLocation.y + scrollOffset.y); |
| } |
| |
| } else { |
| realLocation = pointToConvert; |
| } |
| return realLocation; |
| } |
| |
| private String getEdgeTerminalSource(CreateConnectionRequest request) { |
| // By default take the source terminal put in request.getExtendedData() |
| // by the getConnectionCreateCommand() |
| String edgeTerminalSource = (String) request.getExtendedData().get(GMF_EDGE_SOURCE_TERMINAL); |
| if (edgeTerminalSource == null) { |
| // else take the one set in SetConnectionAnchorsCommand by the GMF |
| // GraphicalNodeEditPolicy |
| Command startCommand = request.getStartCommand(); |
| if (startCommand instanceof ICommandProxy) { |
| ICommandProxy commandProxy = (ICommandProxy) startCommand; |
| if (commandProxy.getICommand() instanceof CompositeCommand) { |
| CompositeCommand compositeCommand = (CompositeCommand) commandProxy.getICommand(); |
| Iterator<?> iterator = compositeCommand.iterator(); |
| while (iterator.hasNext()) { |
| Object cmd = iterator.next(); |
| if (cmd instanceof SetConnectionAnchorsCommand) { |
| SetConnectionAnchorsCommand setConnectionAnchorsCommand = (SetConnectionAnchorsCommand) cmd; |
| edgeTerminalSource = setConnectionAnchorsCommand.getNewSourceTerminal(); |
| } |
| } |
| } |
| } |
| } |
| return edgeTerminalSource; |
| } |
| |
| private Point getEdgeLocationSource(CreateConnectionRequest request) { |
| // By default take the location of the first click of the edge creation |
| // put in request.getExtendedData() by the getConnectionCreateCommand() |
| Point edgeLocationSource = (Point) request.getExtendedData().get(GMF_EDGE_LOCATION_SOURCE); |
| return edgeLocationSource; |
| } |
| |
| /** |
| * . @ param request . |
| * |
| * @param source |
| * . |
| * @param target |
| * . |
| * @param edgeCreationDescription |
| * . |
| * @param cmdFactoryProvider |
| * . |
| * @return . |
| * |
| * {@inheritDoc} |
| */ |
| protected Command buildCreateEdgeCommand(final CreateConnectionRequest request, EdgeTarget source, EdgeTarget target, EdgeCreationDescription edgeCreationDescription, |
| IDiagramCommandFactoryProvider cmdFactoryProvider, EdgeLayoutData edgeLayoutData) { |
| TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(source); |
| CompoundCommand result = new CompoundCommand(edgeCreationDescription.getName()); |
| // Store location hints so that the new view can be put as the proper |
| // location after the refresh. |
| addStoreLayoutDataCommand(result, edgeLayoutData, request); |
| // Create the actual edge |
| org.eclipse.emf.common.command.Command emfCommand = cmdFactoryProvider.getCommandFactory(domain).buildCreateEdgeCommandFromTool(source, target, edgeCreationDescription); |
| result.add(new ICommandProxy(new GMFCommandWrapper(domain, emfCommand))); |
| return result; |
| } |
| |
| /** |
| * Add a command to store the edge layout data. |
| * |
| * @param result |
| * The compound command |
| * @param edgeLayoutData |
| * The layout data to add to the SiriusLayoutDataManager |
| */ |
| protected void addStoreLayoutDataCommand(CompoundCommand result, final EdgeLayoutData edgeLayoutData) { |
| addStoreLayoutDataCommand(result, edgeLayoutData, null); |
| } |
| |
| /** |
| * Add a command to store the edge layout data. The edgeLayoutData can be |
| * override by another one extract from the feedback data stored in the |
| * request if necessary. The connection feedback of the request is used only |
| * if: |
| * <ul> |
| * <li>it is available in the extendedData of the request (key |
| * {@link #GMF_EDGE_FEEDBACK}).</li> |
| * <li>there is a potential straightened edge feedback (edge with only two |
| * points and with same x or same y).</li> |
| * </ul> |
| * . |
| * |
| * @param result |
| * The compound command |
| * @param edgeLayoutData |
| * The layout data to add to the SiriusLayoutDataManager |
| * @param request |
| * the CreateConnectionRequest |
| */ |
| protected void addStoreLayoutDataCommand(CompoundCommand result, final EdgeLayoutData edgeLayoutData, final CreateConnectionRequest request) { |
| result.add(new Command() { |
| @Override |
| public void execute() { |
| EdgeLayoutData feedbackEdgeLayoutData = null; |
| if (request != null) { |
| Connection connectionFeedback = (Connection) request.getExtendedData().get(SiriusGraphicalNodeEditPolicy.GMF_EDGE_FEEDBACK); |
| // The connection feedback is used only if we detect a |
| // potential straightened edge feedback. |
| if (connectionFeedback != null && connectionFeedback.getPoints().size() == 2 |
| && ((connectionFeedback.getPoints().getFirstPoint().x == connectionFeedback.getPoints().getLastPoint().x |
| || connectionFeedback.getPoints().getFirstPoint().y == connectionFeedback.getPoints().getLastPoint().y))) { |
| // Override edgeLayoutData |
| Point sourceLocationFromFeedback = connectionFeedback.getPoints().getFirstPoint(); |
| sourceLocationFromFeedback = getConvertedLocation(sourceLocationFromFeedback, request.getSourceEditPart(), true); |
| if (sourceLocationFromFeedback != null) { |
| Point targetLocationFromFeedback = connectionFeedback.getPoints().getLastPoint(); |
| targetLocationFromFeedback = getConvertedLocation(targetLocationFromFeedback, request.getTargetEditPart(), true); |
| if (GraphicalHelper.isSnapToGridEnabled(request.getSourceEditPart())) { |
| feedbackEdgeLayoutData = getEdgeLayoutDataWithSnapToGrid(request, (INodeEditPart) request.getSourceEditPart(), (INodeEditPart) request.getTargetEditPart(), |
| sourceLocationFromFeedback, targetLocationFromFeedback); |
| } else { |
| feedbackEdgeLayoutData = getEdgeLayoutData(request, (INodeEditPart) request.getSourceEditPart(), (INodeEditPart) request.getTargetEditPart(), |
| sourceLocationFromFeedback, targetLocationFromFeedback); |
| } |
| } |
| } |
| } |
| if (feedbackEdgeLayoutData != null) { |
| SiriusLayoutDataManager.INSTANCE.addData(feedbackEdgeLayoutData); |
| } else { |
| SiriusLayoutDataManager.INSTANCE.addData(edgeLayoutData); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| protected Command getRoutingAdjustment(IAdaptable connection, String connectionHint, Routing currentRouterType, EditPart target) { |
| Command cmd = null; |
| if (connectionHint == null || target == null || target.getModel() == null || ((View) target.getModel()).getElement() == null) { |
| return null; |
| } |
| // check if router needs to change type due to reorient. |
| Routing newRouterType = null; |
| if (connection instanceof IDiagramEdgeEditPart) { |
| DDiagramElement element = ((IDiagramEdgeEditPart) connection).resolveDiagramElement(); |
| if (element instanceof DEdge) { |
| DEdge dEdge = (DEdge) element; |
| newRouterType = new DEdgeQuery(dEdge).getRouting(); |
| if (newRouterType != null && !currentRouterType.equals(newRouterType)) { |
| // add commands for line routing. Convert the new connection |
| // and also the targeted connection. |
| TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(element); |
| ICommand spc = new SetPropertyCommand(domain, connection, Properties.ID_ROUTING, StringStatics.BLANK, newRouterType); |
| Command cmdRouter = new ICommandProxy(spc); |
| if (cmdRouter != null) { |
| cmd = cmdRouter; |
| } |
| } |
| } |
| } else { |
| cmd = super.getRoutingAdjustment(connection, connectionHint, currentRouterType, target); |
| } |
| return cmd; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * Overridden to be able to slide the target bendpoint of an edge when |
| * targeting another edge. This is the same code as in the super super class |
| * GraphicalNodeEditPolicy. |
| */ |
| @Override |
| protected ConnectionAnchor getConnectionTargetAnchor(Request request) { |
| if (request instanceof ReconnectRequest) { |
| ReconnectRequest reconnectRequest = (ReconnectRequest) request; |
| if (reconnectRequest.getTarget() instanceof DEdgeEditPart && reconnectRequest.getConnectionEditPart() instanceof DEdgeEditPart) { |
| INodeEditPart node = getConnectableEditPart(); |
| if (node != null) { |
| return node.getTargetConnectionAnchor(request); |
| } |
| } |
| } |
| return super.getConnectionTargetAnchor(request); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * Overridden to be able to slide the target bendpoint of an edge when |
| * targeting another edge. This is the same code as in the super super class |
| * GraphicalNodeEditPolicy. |
| */ |
| @Override |
| protected INodeEditPart getConnectionCompleteEditPart(Request request) { |
| if (request instanceof ReconnectRequest) { |
| ReconnectRequest reconnectRequest = (ReconnectRequest) request; |
| if (reconnectRequest.getTarget() instanceof DEdgeEditPart && reconnectRequest.getConnectionEditPart() instanceof DEdgeEditPart) { |
| if (getHost() instanceof INodeEditPart) { |
| return (INodeEditPart) getHost(); |
| } |
| } |
| } |
| return super.getConnectionCompleteEditPart(request); |
| } |
| |
| @Override |
| protected void showTargetConnectionFeedback(DropRequest request) { |
| removeHighlight(); |
| addHighlight(request); |
| } |
| |
| /** |
| * Add a highlight feedback figure on element reconnect. Change too the edge |
| * (highlight blue) if there is a reconnect on edge. |
| * |
| * @param request |
| */ |
| private void addHighlight(DropRequest request) { |
| Rectangle bounds = getHostFigure().getBounds().getCopy(); |
| getHostFigure().getParent().translateToAbsolute(bounds); |
| getFeedbackLayer().translateToRelative(bounds); |
| if (getHostFigure() instanceof ViewEdgeFigure) { |
| if (getHostFigure() != null && Display.getCurrent() != null && shouldBeHighlighted(request)) { |
| getHostFigure().setForegroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION)); |
| ((ViewEdgeFigure) getHostFigure()).setLineWidth(DiagramEdgeEditPartOperation.getLineWidth((IDiagramEdgeEditPart) getHost()) + WIDTH_FEEDBACK); |
| for (final Object child : getHostFigure().getChildren()) { |
| if (child instanceof PolylineDecoration) { |
| final PolylineDecoration decoration = (PolylineDecoration) child; |
| decoration.setLineWidth(DiagramEdgeEditPartOperation.getLineWidth((IDiagramEdgeEditPart) getHost()) + WIDTH_FEEDBACK); |
| } |
| } |
| } |
| } else { |
| |
| highlightFigure = new RectangleFigure() { |
| @Override |
| public void paint(Graphics graphics) { |
| graphics.setAlpha(128); |
| super.paint(graphics); |
| } |
| }; |
| highlightFigure.setBounds(bounds); |
| highlightFigure.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION)); |
| addFeedback(highlightFigure); |
| } |
| } |
| |
| private boolean shouldBeHighlighted(DropRequest request) { |
| if (request instanceof ReconnectRequest) { |
| boolean returnValue = false; |
| DEdge dEdge = getCurrentDEdge((ReconnectRequest) request); |
| if (dEdge != null) { |
| Option<EdgeMapping> edgeMapping = new IEdgeMappingQuery(dEdge.getActualMapping()).getEdgeMapping(); |
| if (edgeMapping.some()) { |
| returnValue = canCreateNewEdge(request, dEdge, edgeMapping.get()); |
| } |
| } |
| return returnValue; |
| } |
| // If the request is not a Reconnect one, we do not change the highlight |
| // behavior. |
| return true; |
| } |
| |
| private boolean canCreateNewEdge(DropRequest request, DEdge dEdge, EdgeMapping actualIEdgeMapping) { |
| ReconnectEdgeDescription bestTool = null; |
| EdgeTarget reconnectionTarget = getTargetElement((ReconnectRequest) request); |
| if (reconnectionTarget != null) { |
| // If we are reconnecting the source |
| if (RequestConstants.REQ_RECONNECT_SOURCE.equals(((ReconnectRequest) request).getType())) { |
| bestTool = getBestTool(actualIEdgeMapping, true, dEdge.getSourceNode(), reconnectionTarget, dEdge, false); |
| } |
| // Or the target |
| else if (RequestConstants.REQ_RECONNECT_TARGET.equals(((ReconnectRequest) request).getType())) { |
| bestTool = getBestTool(actualIEdgeMapping, false, dEdge.getTargetNode(), reconnectionTarget, dEdge, false); |
| } |
| } |
| return bestTool != null; |
| } |
| |
| private EdgeTarget getTargetElement(ReconnectRequest request) { |
| EditPart target = request.getTarget(); |
| if (target instanceof IGraphicalEditPart) { |
| EObject element = ((IGraphicalEditPart) target).resolveSemanticElement(); |
| if (element instanceof EdgeTarget) { |
| return (EdgeTarget) element; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Provides the current reconnected DEdge. |
| * |
| * @param request |
| * the Reconnect Request. |
| * @return the reconnected DEdge or null if not found. |
| */ |
| private DEdge getCurrentDEdge(ReconnectRequest request) { |
| ConnectionEditPart connectionEditPart = request.getConnectionEditPart(); |
| if (connectionEditPart instanceof IGraphicalEditPart) { |
| EObject semanticElement = ((IGraphicalEditPart) connectionEditPart).resolveSemanticElement(); |
| if (semanticElement instanceof DEdge) { |
| return (DEdge) semanticElement; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| protected void eraseTargetConnectionFeedback(DropRequest request) { |
| removeHighlight(); |
| } |
| |
| @Override |
| public void deactivate() { |
| // Last chance to remove the existing high light |
| removeHighlight(); |
| super.deactivate(); |
| } |
| |
| /** |
| * Remove hightLight Figure. |
| */ |
| private void removeHighlight() { |
| if (highlightFigure != null) { |
| removeFeedback(highlightFigure); |
| highlightFigure = null; |
| } |
| if (getHostFigure() instanceof ViewEdgeFigure) { |
| ((IDiagramEdgeEditPart) getHost()).refreshForegroundColor(); |
| ((IDiagramEdgeEditPart) getHost()).refreshLineStyle(); |
| } |
| } |
| |
| /** |
| * Check if this connectionEditPart has been described in the VSM with in a |
| * diagram with orderedTreeLayout or with compositeLayout and that it does |
| * not have another edge as extremity. |
| * |
| * @param connectionEditPart |
| * the edit part to check |
| * @return true if a specific tree layout must be apply (to compute GMF |
| * constraints according to draw2d), false otherwise |
| */ |
| private boolean applySpecificTreeLayout(ConnectionEditPart connectionEditPart) { |
| boolean isLayoutComponent = false; |
| if (!isSourceOrTargetIsEdge(connectionEditPart)) { |
| Diagram diagram = getDiagram(connectionEditPart); |
| if (diagram != null && diagram.getElement() instanceof DSemanticDiagram) { |
| DSemanticDiagram dSemanticDiagram = (DSemanticDiagram) diagram.getElement(); |
| Layout layout = dSemanticDiagram.getDescription().getLayout(); |
| isLayoutComponent = isOrderedTreeLayoutOrCompositeLayout(layout); |
| } |
| } |
| return isLayoutComponent; |
| } |
| |
| /** |
| * Check if the source or the target of this connection is another |
| * connection. |
| * |
| * @param connectionEditPart |
| * the edit part to check |
| * @return true if the source or the target of this connection is another |
| * connection, false otherwise. |
| */ |
| private boolean isSourceOrTargetIsEdge(ConnectionEditPart connectionEditPart) { |
| return connectionEditPart.getSource() instanceof ConnectionEditPart || connectionEditPart.getTarget() instanceof ConnectionEditPart; |
| } |
| |
| private Diagram getDiagram(ConnectionEditPart connectionEditPart) { |
| Diagram diagram = null; |
| if (connectionEditPart.getParent() instanceof DiagramRootEditPart) { |
| DiagramRootEditPart diagramRootEditPart = (DiagramRootEditPart) connectionEditPart.getParent(); |
| if (diagramRootEditPart.getChildren().get(0) instanceof DiagramEditPart) { |
| DiagramEditPart diagramEditPart = (DiagramEditPart) diagramRootEditPart.getChildren().get(0); |
| if (diagramEditPart.getModel() instanceof Diagram) { |
| diagram = (Diagram) diagramEditPart.getModel(); |
| } |
| } |
| } |
| return diagram; |
| } |
| |
| /** |
| * Check if this layout corresponds to tree so code must be call to modify |
| * GMF edges according to draw2d points. |
| * |
| * @param layout |
| * The layout to check |
| * @return true if this layout is an OrderedTreeLayout or a CompositeLayout, |
| * false otherwise |
| */ |
| private boolean isOrderedTreeLayoutOrCompositeLayout(Layout layout) { |
| return layout instanceof OrderedTreeLayout || layout instanceof CompositeLayout; |
| } |
| |
| /** |
| * Launch a specific command ({@link TreeLayoutSetConnectionAnchorsCommand} |
| * instead of the classical {@link SetConnectionAnchorsCommand}) to handle |
| * with tree layout and setting correctly all the anchors of the edge of the |
| * same tree. |
| * |
| * @param request |
| * The ReconnectRequest |
| * @return a Command |
| */ |
| private Command getReconnectTargetForTreeLayoutCommand(ReconnectRequest request) { |
| INodeEditPart node = getConnectableEditPart(); |
| Command cmd = null; |
| if (node != null) { |
| TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); |
| |
| ConnectionAnchor targetAnchor = getConnectionTargetAnchor(request); |
| INodeEditPart targetEP = getConnectionCompleteEditPart(request); |
| if (targetEP != null) { |
| SetConnectionEndsCommand sceCommand = new SetConnectionEndsCommand(editingDomain, StringStatics.BLANK); |
| sceCommand.setEdgeAdaptor(new EObjectAdapter((EObject) request.getConnectionEditPart().getModel())); |
| sceCommand.setNewTargetAdaptor(targetEP); |
| TreeLayoutSetConnectionAnchorsCommand scaCommand = new TreeLayoutSetConnectionAnchorsCommand(editingDomain, StringStatics.BLANK); |
| scaCommand.setEdgeAdaptor(request.getConnectionEditPart()); |
| scaCommand.setNewTargetTerminal(targetEP.mapConnectionAnchorToTerminal(targetAnchor)); |
| CompositeCommand cc = new CompositeCommand(DiagramUIMessages.Commands_SetConnectionEndsCommand_Target); |
| cc.compose(sceCommand); |
| cc.compose(scaCommand); |
| cmd = new ICommandProxy(cc); |
| // TODO Check what it does in the above code ... If removed the |
| // target of the first tree edge is not on the middle (not sure) |
| // EditPart cep = request.getConnectionEditPart(); |
| // RoutingStyle style = (RoutingStyle) ((View) |
| // cep.getModel()).getStyle(NotationPackage.eINSTANCE.getRoutingStyle()); |
| // Routing currentRouter = Routing.MANUAL_LITERAL; |
| // if (style != null) { |
| // currentRouter = style.getRouting(); |
| // } |
| // Command cmdRouter = |
| // getRoutingAdjustment(request.getConnectionEditPart(), |
| // getSemanticHint(request), currentRouter, |
| // request.getTarget()); |
| // if (cmdRouter != null) { |
| // cmd = cmd == null ? cmdRouter : cmd.chain(cmdRouter); |
| // // reset the bendpoints |
| // ConnectionAnchor sourceAnchor = |
| // node.getSourceConnectionAnchor(request); |
| // PointList pointList = new PointList(); |
| // pointList.addPoint(sourceAnchor.getLocation(targetAnchor.getReferencePoint())); |
| // pointList.addPoint(targetAnchor.getLocation(sourceAnchor.getReferencePoint())); |
| // |
| // SetConnectionBendpointsCommand sbbCommand = new |
| // SetConnectionBendpointsCommand(editingDomain); |
| // sbbCommand.setEdgeAdapter(request.getConnectionEditPart()); |
| // sbbCommand.setNewPointList(pointList, |
| // sourceAnchor.getReferencePoint(), |
| // targetAnchor.getReferencePoint()); |
| // Command cmdBP = new ICommandProxy(sbbCommand); |
| // if (cmdBP != null) { |
| // cmd = cmd == null ? cmdBP : cmd.chain(cmdBP); |
| // } |
| // } |
| } |
| } |
| return cmd; |
| } |
| |
| /** |
| * Launch a specific command ({@link TreeLayoutSetConnectionAnchorsCommand} |
| * instead of the classical {@link SetConnectionAnchorsCommand}) to handle |
| * with tree layout and setting correctly all the anchors of the edge of the |
| * same tree. |
| * |
| * @param request |
| * The ReconnectRequest |
| * @return a Command |
| */ |
| private Command getReconnectSourceForTreeLayoutCommand(ReconnectRequest request) { |
| INodeEditPart node = getConnectableEditPart(); |
| if (node == null) { |
| return null; |
| } |
| |
| TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); |
| |
| ConnectionAnchor sourceAnchor = node.getSourceConnectionAnchor(request); |
| SetConnectionEndsCommand sceCommand = new SetConnectionEndsCommand(editingDomain, StringStatics.BLANK); |
| sceCommand.setEdgeAdaptor(new EObjectAdapter((View) request.getConnectionEditPart().getModel())); |
| sceCommand.setNewSourceAdaptor(new EObjectAdapter((View) node.getModel())); |
| TreeLayoutSetConnectionAnchorsCommand scaCommand = new TreeLayoutSetConnectionAnchorsCommand(editingDomain, StringStatics.BLANK); |
| scaCommand.setEdgeAdaptor(request.getConnectionEditPart()); |
| scaCommand.setNewSourceTerminal(node.mapConnectionAnchorToTerminal(sourceAnchor)); |
| CompositeCommand cc = new CompositeCommand(DiagramUIMessages.Commands_SetConnectionEndsCommand_Source); |
| cc.compose(sceCommand); |
| cc.compose(scaCommand); |
| return new ICommandProxy(cc); |
| } |
| |
| @Override |
| protected void showCreationFeedback(CreateConnectionRequest request) { |
| super.showCreationFeedback(request); |
| // Add the connection feedback figure to the request to use it during |
| // the execution of the command. It is needed to not use the real mouse |
| // click locations but the feedback data instead. |
| request.getExtendedData().put(SiriusGraphicalNodeEditPolicy.GMF_EDGE_FEEDBACK, connectionFeedback); |
| } |
| } |