[441256] - Affixed nodes should only allow anchors at 2 of 4 sides + update anchor on move when changed side Change-Id: I30af783a10e1073a9a21613aec5fa799af9e45d5
diff --git a/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/LinksLFNodeFigure.java b/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/LinksLFNodeFigure.java index e5779cb..ce8d3f8 100644 --- a/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/LinksLFNodeFigure.java +++ b/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/LinksLFNodeFigure.java
@@ -3,12 +3,15 @@ import org.eclipse.draw2d.AbstractPointListShape; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.ScalablePolygonShape; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.draw2d.geometry.PrecisionPoint; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; +import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart; import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor; +import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator; import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure; public class LinksLFNodeFigure extends DefaultSizeNodeFigure { @@ -54,8 +57,24 @@ Point temp = p.getCopy(); translateToRelative(temp); PrecisionPoint pt = BaseSlidableAnchor.getAnchorRelativeLocation(temp, getBounds()); - if (isDefaultAnchorArea(pt)) + if (isDefaultAnchorArea(pt)) { return getConnectionAnchor(szAnchor); + } + + if (myHost instanceof IBorderItemEditPart) { + IBorderItemLocator locator = ((IBorderItemEditPart) myHost).getBorderItemLocator(); + switch (locator.getCurrentSideOfParent()) { + case PositionConstants.WEST: + case PositionConstants.EAST: + pt.setPreciseX(pt.preciseX() > 0.5 ? 1.0 : 0.0); + break; + case PositionConstants.SOUTH: + case PositionConstants.NORTH: + pt.setPreciseY(pt.preciseY() > 0.5 ? 1.0 : 0.0); + break; + } + } + return createAnchor(pt); } }
diff --git a/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/editpolicies/AdjustBorderItemAnchorsEditPolicy.java b/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/editpolicies/AdjustBorderItemAnchorsEditPolicy.java new file mode 100644 index 0000000..ae09bf5 --- /dev/null +++ b/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/custom-src/org/eclipse/gmf/tooling/runtime/linklf/editpolicies/AdjustBorderItemAnchorsEditPolicy.java
@@ -0,0 +1,200 @@ +package org.eclipse.gmf.tooling.runtime.linklf.editpolicies; + +import org.eclipse.draw2d.ConnectionAnchor; +import org.eclipse.draw2d.PositionConstants; +import org.eclipse.draw2d.geometry.PrecisionPoint; +import org.eclipse.draw2d.geometry.PrecisionRectangle; +import org.eclipse.draw2d.geometry.Rectangle; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.gef.GraphicalEditPart; +import org.eclipse.gef.commands.Command; +import org.eclipse.gef.handles.HandleBounds; +import org.eclipse.gef.requests.ChangeBoundsRequest; +import org.eclipse.gmf.runtime.common.core.command.ICommand; +import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand; +import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; +import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart; +import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart; +import org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart; +import org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator; +import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor; +import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator; +import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; + +/** + * This edit policy adjusts anchors for links from and to host {@link IBorderItemEditPart}. + * Adjustment ensures that the anchors are always located on the side which is parallel to the actual side + * of the parent this border item is affixed to. + */ +public class AdjustBorderItemAnchorsEditPolicy extends AdjustAbsoluteBendpointsEditPolicyBase { + + /** + * Default role for registering this edit policy. + * <p/> + * The value is prefixed by class FQN in order to avoid conflicts, but the literal should NOT be used anywhere. + */ + public static final String ROLE = AdjustBorderItemAnchorsEditPolicy.class.getName() + ":Role"; + + @Override + protected Command getAdjustLinksCommand(ChangeBoundsRequest req) { + if (getHost() instanceof IBorderItemEditPart && getHost() instanceof INodeEditPart) { + return getAdjustAnchorsCommand(req); + } + return null; + } + + protected Command getAdjustAnchorsCommand(ChangeBoundsRequest req) { + IBorderItemEditPart host = (IBorderItemEditPart) getHost(); + final IBorderItemLocator locator = host.getBorderItemLocator(); + if (locator == null) { + return null; + } + + Rectangle bounds; + if (host.getFigure() instanceof HandleBounds) { + bounds = ((HandleBounds) host.getFigure()).getHandleBounds(); + } else { + bounds = host.getFigure().getBounds(); + } + PrecisionRectangle rect = new PrecisionRectangle(bounds); + getHostFigure().translateToAbsolute(rect); + rect.translate(req.getMoveDelta()); + rect.resize(req.getSizeDelta()); + + getHostFigure().translateToRelative(rect); + Rectangle realLocation = locator.getValidLocation(rect.getCopy(), host.getFigure()); + + int projectedSide = BorderItemLocator.findClosestSideOfParent(realLocation, ((GraphicalEditPart) host.getParent()).getFigure().getBounds()); + int currentSide = locator.getCurrentSideOfParent(); + + int curIndex = getIndexForSide(currentSide); + int projectedIndex = getIndexForSide(projectedSide); + + if ((projectedSide & currentSide) != 0) { + return null; + } + + int rotation = projectedIndex - curIndex; + if (rotation < 0) { + rotation += 4; + } + if (rotation == 0) { + //weird + return null; + } + + ICommand result = null; + TransactionalEditingDomain domain = getHost().getEditingDomain(); + for (Object next : getHost().getSourceConnections()) { + if (next instanceof ConnectionEditPart) { + ConnectionEditPart nextLink = (ConnectionEditPart) next; + ConnectionAnchor anchor = nextLink.getConnectionFigure().getSourceAnchor(); + if (anchor == null) { + continue; + } + PrecisionPoint newRefPoint = rotateAnchorLocation(anchor, rotation); + String newTerminal = composeTerminalString(newRefPoint); + + SetConnectionAnchorsCommand nextCommand = new SetConnectionAnchorsCommand(domain, "Adjusting source anchors"); + nextCommand.setEdgeAdaptor(new EObjectAdapter(nextLink.getNotationView())); + nextCommand.setNewSourceTerminal(newTerminal); + + result = result == null ? nextCommand : result.compose(nextCommand); + } + } + + for (Object next : getHost().getTargetConnections()) { + if (next instanceof ConnectionEditPart) { + ConnectionEditPart nextLink = (ConnectionEditPart) next; + ConnectionAnchor anchor = nextLink.getConnectionFigure().getTargetAnchor(); + if (anchor == null) { + continue; + } + PrecisionPoint newRefPoint = rotateAnchorLocation(anchor, rotation); + String newTerminal = composeTerminalString(newRefPoint); + + SetConnectionAnchorsCommand nextCommand = new SetConnectionAnchorsCommand(domain, "Adjusting target anchors"); + nextCommand.setEdgeAdaptor(new EObjectAdapter(nextLink.getNotationView())); + nextCommand.setNewTargetTerminal(newTerminal); + + result = result == null ? nextCommand : result.compose(nextCommand); + } + } + + return result == null ? null : new ICommandProxy(result); + } + + private static int getIndexForSide(int side) { + if (hasBits(side, PositionConstants.NORTH)) { + return 0; + } + if (hasBits(side, PositionConstants.EAST)) { + return 1; + } + if (hasBits(side, PositionConstants.SOUTH)) { + return 2; + } + if (hasBits(side, PositionConstants.WEST)) { + return 3; + } + return 0; + } + + protected static String position2string(int position) { + if (position == PositionConstants.NONE) { + return "NONE"; + } + StringBuffer result = new StringBuffer(); + if (hasBits(position, PositionConstants.NORTH)) { + result.append("N"); + } + if (hasBits(position, PositionConstants.SOUTH)) { + result.append("S"); + } + if (hasBits(position, PositionConstants.WEST)) { + result.append("W"); + } + if (hasBits(position, PositionConstants.EAST)) { + result.append("E"); + } + + return result.toString(); + } + + protected static boolean hasBits(int value, int mask) { + return ((value & mask) != 0); + } + + protected PrecisionPoint rotateAnchorLocation(ConnectionAnchor anchor, int quarters) { + String terminal = ((BaseSlidableAnchor) anchor).getTerminal(); + PrecisionPoint result = BaseSlidableAnchor.parseTerminalString(terminal); + for (int i = 0; i < quarters; i++) { + double newX = 1. - result.preciseY(); + double newY = result.preciseX(); + result.setPreciseLocation(newX, newY); + } + return result; + } + + /** + * [GMFRT] make protected in {@link BaseSlidableAnchor} + * <p/> + * Creates a terminal string for any reference point passed in the format understandable by slidable anchors + * + * @param p + * - a <Code>PrecisionPoint</Code> that must be represented as a unique <Code>String</Code>, namely as "(preciseX,preciseY)" + * @return <code>String</code> terminal composed from specified <code>PrecisionPoint</code> + * @deprecated copy pasted from {@link BaseSlidableAnchor} + */ + @Deprecated + private String composeTerminalString(PrecisionPoint p) { + StringBuffer s = new StringBuffer(24); + s.append('('); // 1 char + s.append(p.preciseX()); // 10 chars + s.append(','); // 1 char + s.append(p.preciseY()); // 10 chars + s.append(')'); // 1 char + return s.toString(); // 24 chars max (+1 for safety, i.e. for string termination) + } + +}
diff --git a/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/src/org/eclipse/gmf/tooling/examples/linklf/diagram/edit/parts/PortEditPart.java b/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/src/org/eclipse/gmf/tooling/examples/linklf/diagram/edit/parts/PortEditPart.java index f62a265..c1160c0 100644 --- a/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/src/org/eclipse/gmf/tooling/examples/linklf/diagram/edit/parts/PortEditPart.java +++ b/test-examples/linklf/xtend/org.eclipse.gmf.tooling.examples.linklf.diagram/src/org/eclipse/gmf/tooling/examples/linklf/diagram/edit/parts/PortEditPart.java
@@ -20,6 +20,7 @@ import org.eclipse.gmf.tooling.examples.linklf.diagram.edit.policies.PortItemSemanticEditPolicy; import org.eclipse.gmf.tooling.runtime.linklf.LinksLFNodeFigure; import org.eclipse.gmf.tooling.runtime.linklf.ShapeNodeAnchorDelegate; +import org.eclipse.gmf.tooling.runtime.linklf.editpolicies.AdjustBorderItemAnchorsEditPolicy; import org.eclipse.gmf.tooling.runtime.linklf.editpolicies.AdjustImplicitlyMovedLinksEditPolicy; import org.eclipse.gmf.tooling.runtime.linklf.editpolicies.LinksLFGraphicalNodeEditPolicy; import org.eclipse.swt.graphics.Color; @@ -64,6 +65,7 @@ installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new LinksLFGraphicalNodeEditPolicy()); installEditPolicy(AdjustImplicitlyMovedLinksEditPolicy.ROLE, new AdjustImplicitlyMovedLinksEditPolicy()); + installEditPolicy(AdjustBorderItemAnchorsEditPolicy.ROLE, new AdjustBorderItemAnchorsEditPolicy()); } /**