/*******************************************************************************
* Copyright (c) 2015, 2016 itemis AG 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:
* Matthias Wienand (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.mvc.tests.fx;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import java.awt.AWTException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.gef.common.adapt.AdapterKey;
import org.eclipse.gef.common.adapt.inject.AdapterMaps;
import org.eclipse.gef.fx.anchors.AnchorKey;
import org.eclipse.gef.fx.anchors.DynamicAnchor;
import org.eclipse.gef.fx.anchors.DynamicAnchor.AnchorageReferenceGeometry;
import org.eclipse.gef.fx.anchors.DynamicAnchor.AnchoredReferencePoint;
import org.eclipse.gef.fx.anchors.DynamicAnchor.PreferredOrientation;
import org.eclipse.gef.fx.anchors.IAnchor;
import org.eclipse.gef.fx.anchors.OrthogonalProjectionStrategy;
import org.eclipse.gef.fx.anchors.StaticAnchor;
import org.eclipse.gef.fx.nodes.Connection;
import org.eclipse.gef.fx.nodes.GeometryNode;
import org.eclipse.gef.fx.nodes.OrthogonalRouter;
import org.eclipse.gef.fx.utils.NodeUtils;
import org.eclipse.gef.geometry.convert.fx.FX2Geometry;
import org.eclipse.gef.geometry.convert.fx.Geometry2FX;
import org.eclipse.gef.geometry.euclidean.Vector;
import org.eclipse.gef.geometry.planar.AffineTransform;
import org.eclipse.gef.geometry.planar.IShape;
import org.eclipse.gef.geometry.planar.Line;
import org.eclipse.gef.geometry.planar.Point;
import org.eclipse.gef.geometry.planar.Polygon;
import org.eclipse.gef.mvc.fx.MvcFxModule;
import org.eclipse.gef.mvc.fx.domain.IDomain;
import org.eclipse.gef.mvc.fx.handlers.FocusAndSelectOnClickHandler;
import org.eclipse.gef.mvc.fx.handlers.TranslateSelectedOnDragHandler;
import org.eclipse.gef.mvc.fx.models.SelectionModel;
import org.eclipse.gef.mvc.fx.parts.AbstractContentPart;
import org.eclipse.gef.mvc.fx.parts.IBendableContentPart;
import org.eclipse.gef.mvc.fx.parts.IContentPart;
import org.eclipse.gef.mvc.fx.parts.IContentPartFactory;
import org.eclipse.gef.mvc.fx.parts.ITransformableContentPart;
import org.eclipse.gef.mvc.fx.parts.IVisualPart;
import org.eclipse.gef.mvc.fx.policies.BendConnectionPolicy;
import org.eclipse.gef.mvc.fx.policies.TransformPolicy;
import org.eclipse.gef.mvc.fx.providers.DefaultAnchorProvider;
import org.eclipse.gef.mvc.fx.providers.IAnchorProvider;
import org.eclipse.gef.mvc.fx.viewer.IViewer;
import org.eclipse.gef.mvc.tests.fx.rules.FXNonApplicationThreadRule;
import org.eclipse.gef.mvc.tests.fx.rules.FXNonApplicationThreadRule.RunnableWithResult;
import org.eclipse.gef.mvc.tests.fx.rules.FXNonApplicationThreadRule.RunnableWithResultAndParam;
import org.junit.Rule;
import org.junit.Test;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.multibindings.MapBinder;
import javafx.beans.binding.ObjectBinding;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Affine;
public class BendConnectionPolicyTests {
public static class AnchoragePart extends AbstractContentPart<Rectangle>
implements ITransformableContentPart<Rectangle> {
private Affine transform = new Affine();
@Override
protected Rectangle doCreateVisual() {
return new Rectangle(100, 100);
}
@Override
protected SetMultimap<? extends Object, String> doGetContentAnchorages() {
return HashMultimap.create();
}
@Override
protected List<? extends Object> doGetContentChildren() {
return Collections.emptyList();
}
@Override
protected void doRefreshVisual(final Rectangle visual) {
final org.eclipse.gef.geometry.planar.Rectangle rect = ((org.eclipse.gef.geometry.planar.IShape) getContent())
.getBounds();
visual.setX(rect.getX());
visual.setY(rect.getY());
visual.setWidth(rect.getWidth());
visual.setHeight(rect.getHeight());
}
@Override
public Affine getContentTransform() {
return transform;
}
@Override
public void setContentTransform(Affine transform) {
this.transform = transform;
}
}
public static class ConnectionContent {
public org.eclipse.gef.geometry.planar.IShape anchorageStart;
public org.eclipse.gef.geometry.planar.IShape anchorageEnd;
public boolean isSimple;
public ConnectionContent(final org.eclipse.gef.geometry.planar.IShape start,
final org.eclipse.gef.geometry.planar.IShape end) {
anchorageStart = start;
anchorageEnd = end;
}
public ConnectionContent(final org.eclipse.gef.geometry.planar.IShape start,
final org.eclipse.gef.geometry.planar.IShape end, final Point startRef, final Point endRef) {
anchorageStart = start;
anchorageEnd = end;
}
public Point getWayPoint() {
final Point delta = anchorageEnd.getBounds().getCenter()
.getTranslated(anchorageStart.getBounds().getCenter().getNegated());
Point wayPointInScene = anchorageStart.getBounds().getCenter().getTranslated(delta.getScaled(0.5));
return wayPointInScene;
}
}
public static class ConnectionPart extends AbstractContentPart<Connection>
implements IBendableContentPart<Connection>, ITransformableContentPart<Connection> {
public static final String START_ROLE = "start";
public static final String END_ROLE = "end";
private Affine transform = new Affine();
@Override
protected void doAttachToAnchorageVisual(final IVisualPart<? extends Node> anchorage, final String role) {
final IAnchor anchor = anchorage.getAdapter(IAnchorProvider.class).get(this, role);
if (role.equals(START_ROLE)) {
getVisual().setStartAnchor(anchor);
} else if (role.equals(END_ROLE)) {
getVisual().setEndAnchor(anchor);
} else {
throw new IllegalStateException("Cannot attach to anchor with role <" + role + ">.");
}
}
@Override
protected Connection doCreateVisual() {
return new Connection();
}
@Override
protected void doDetachFromAnchorageVisual(final IVisualPart<? extends Node> anchorage, final String role) {
if (role.equals(START_ROLE)) {
getVisual().setStartPoint(getVisual().getStartPoint());
} else if (role.equals(END_ROLE)) {
getVisual().setEndPoint(getVisual().getEndPoint());
} else {
throw new IllegalStateException("Cannot detach from anchor with role <" + role + ">.");
}
}
@Override
protected SetMultimap<? extends Object, String> doGetContentAnchorages() {
final SetMultimap<Object, String> contentAnchorages = HashMultimap.create();
contentAnchorages.put(getContent().anchorageStart, START_ROLE);
contentAnchorages.put(getContent().anchorageEnd, END_ROLE);
return contentAnchorages;
}
@Override
protected List<? extends Object> doGetContentChildren() {
return Collections.emptyList();
}
@Override
protected void doRefreshVisual(final Connection visual) {
if (!getContent().isSimple && visual.getControlPoints().size() == 0) {
visual.addControlPoint(0, getContent().getWayPoint());
}
}
@Override
public ConnectionContent getContent() {
return (ConnectionContent) super.getContent();
}
@Override
public List<org.eclipse.gef.mvc.fx.parts.IBendableContentPart.BendPoint> getContentBendPoints() {
return null;
}
@Override
public Affine getContentTransform() {
return transform;
}
@Override
public void setContentBendPoints(List<org.eclipse.gef.mvc.fx.parts.IBendableContentPart.BendPoint> bendPoints) {
}
@Override
public void setContentTransform(Affine transform) {
this.transform = transform;
}
}
public static class TestAnchorProvider extends DefaultAnchorProvider {
@Override
protected void initializeComputationParameters(final DynamicAnchor anchor) {
final AnchorageReferenceGeometry computationParameter = anchor
.getComputationParameter(AnchorageReferenceGeometry.class);
// if there is a default binding, remove it
if (computationParameter.isBound()) {
computationParameter.unbind();
}
computationParameter.set((IShape) ((IContentPart<?>) getAdaptable()).getContent());
}
}
public static class TestAnchorProviderWithStaticAnchor extends DefaultAnchorProvider {
private IAnchor staticAnchor;
@Override
public IAnchor get(IVisualPart<? extends Node> anchoredPart) {
if (staticAnchor == null) {
staticAnchor = new StaticAnchor(getAdaptable().getVisual(), new Point());
}
return staticAnchor;
}
}
public static class TestContentPartFactory implements IContentPartFactory {
@Inject
private Injector injector;
@Override
public IContentPart<? extends Node> createContentPart(final Object content,
final Map<Object, Object> contextMap) {
if (content instanceof org.eclipse.gef.geometry.planar.IShape) {
return injector.getInstance(AnchoragePart.class);
} else if (content instanceof ConnectionContent) {
return injector.getInstance(ConnectionPart.class);
} else {
throw new IllegalArgumentException(content.getClass().toString());
}
}
}
public static class TestModels {
public static List<Object> get_regression_makeExplicit() {
final List<Object> contents = new ArrayList<>();
final org.eclipse.gef.geometry.planar.Rectangle A = new org.eclipse.gef.geometry.planar.Rectangle(310, 0,
50, 50);
final org.eclipse.gef.geometry.planar.Rectangle B = new org.eclipse.gef.geometry.planar.Rectangle(0, 85, 50,
50);
contents.add(A);
contents.add(B);
final ConnectionContent connectionContent = new ConnectionContent(A, B);
connectionContent.isSimple = true;
contents.add(connectionContent);
return contents;
}
public static List<Object> getAB_AB() {
final List<Object> contents = new ArrayList<>();
final org.eclipse.gef.geometry.planar.Rectangle A = new org.eclipse.gef.geometry.planar.Rectangle(0, 0, 50,
50);
final org.eclipse.gef.geometry.planar.Rectangle B = new org.eclipse.gef.geometry.planar.Rectangle(500, 0,
50, 50);
contents.add(A);
contents.add(B);
contents.add(new ConnectionContent(A, B));
return contents;
}
public static List<Object> getAB_AB_simple() {
final List<Object> contents = new ArrayList<>();
final org.eclipse.gef.geometry.planar.Rectangle A = new org.eclipse.gef.geometry.planar.Rectangle(0, 0, 50,
50);
final org.eclipse.gef.geometry.planar.Rectangle B = new org.eclipse.gef.geometry.planar.Rectangle(500, 0,
50, 50);
contents.add(A);
contents.add(B);
final ConnectionContent connectionContent = new ConnectionContent(A, B);
connectionContent.isSimple = true;
contents.add(connectionContent);
return contents;
}
public static List<Object> getAB_offset_simple() {
final List<Object> contents = new ArrayList<>();
final org.eclipse.gef.geometry.planar.Rectangle A = new org.eclipse.gef.geometry.planar.Rectangle(0, 0, 50,
50);
final org.eclipse.gef.geometry.planar.Rectangle B = new org.eclipse.gef.geometry.planar.Rectangle(500, 500,
50, 50);
contents.add(A);
contents.add(B);
final ConnectionContent connectionContent = new ConnectionContent(A, B);
connectionContent.isSimple = true;
contents.add(connectionContent);
return contents;
}
public static List<Object> getAB_offset2_simple() {
final List<Object> contents = new ArrayList<>();
final org.eclipse.gef.geometry.planar.Rectangle A = new org.eclipse.gef.geometry.planar.Rectangle(0, 0, 50,
50);
final org.eclipse.gef.geometry.planar.Rectangle B = new org.eclipse.gef.geometry.planar.Rectangle(300, 500,
50, 50);
contents.add(A);
contents.add(B);
final ConnectionContent connectionContent = new ConnectionContent(A, B);
connectionContent.isSimple = true;
contents.add(connectionContent);
return contents;
}
public static List<Object> getABC_AB_BC() {
final List<Object> contents = new ArrayList<>();
final org.eclipse.gef.geometry.planar.Rectangle A = new org.eclipse.gef.geometry.planar.Rectangle(0, 0, 50,
50);
final org.eclipse.gef.geometry.planar.Rectangle B = new org.eclipse.gef.geometry.planar.Rectangle(100, 0,
50, 50);
final org.eclipse.gef.geometry.planar.Rectangle C = new org.eclipse.gef.geometry.planar.Rectangle(200, 0,
50, 50);
contents.add(A);
contents.add(B);
contents.add(C);
contents.add(new ConnectionContent(A, B));
contents.add(new ConnectionContent(B, C));
return contents;
}
public static List<Object> getDA_click_error() {
final Polygon startAnchorage = new Polygon(349.49988, 56.54434506500246, 359.9554149349976,
66.99988000000002, 349.49988, 77.45541493499758, 339.04434506500246, 66.99988000000002, 349.49988,
56.54434506500246);
final Polygon endAnchorage = new Polygon(338.49988, 237.54434506500243, 348.9554149349976, 247.99988,
338.49988, 258.4554149349975, 328.04434506500246, 247.99988, 338.49988, 237.54434506500243);
final Point startReferencePoint = new Point(356.25, -365.87);
final Point endReferencePoint = new Point(350.01, -190.0);
final List<Object> contents = new ArrayList<>();
contents.add(startAnchorage);
contents.add(endAnchorage);
final ConnectionContent connectionContent = new ConnectionContent(startAnchorage, endAnchorage,
startReferencePoint, endReferencePoint);
connectionContent.isSimple = true;
contents.add(connectionContent);
return contents;
}
}
public static class TestModule extends MvcFxModule {
@Override
protected void bindAbstractContentPartAdapters(final MapBinder<AdapterKey<?>, Object> adapterMapBinder) {
super.bindAbstractContentPartAdapters(adapterMapBinder);
// focus and select on click
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(FocusAndSelectOnClickHandler.class);
}
protected void bindAnchorageAdapters(final MapBinder<AdapterKey<?>, Object> adapterMapBinder) {
// transform policy
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TransformPolicy.class);
// relocate on drag
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TranslateSelectedOnDragHandler.class);
// bind dynamic anchor provider
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TestAnchorProvider.class);
}
protected void bindConnectionAdapters(final MapBinder<AdapterKey<?>, Object> adapterMapBinder) {
// relocate on drag
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TranslateSelectedOnDragHandler.class);
// bend
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(BendConnectionPolicy.class);
}
protected void bindIContentPartFactory() {
binder().bind(IContentPartFactory.class).toInstance(new TestContentPartFactory());
}
@Override
protected void configure() {
super.configure();
bindIContentPartFactory();
// contents
bindAnchorageAdapters(AdapterMaps.getAdapterMapBinder(binder(), AnchoragePart.class));
bindConnectionAdapters(AdapterMaps.getAdapterMapBinder(binder(), ConnectionPart.class));
}
}
public static class TestModuleWithStaticAnchor extends TestModule {
@Override
protected void bindAnchorageAdapters(final MapBinder<AdapterKey<?>, Object> adapterMapBinder) {
// transform policy
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TransformPolicy.class);
// relocate on drag
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TranslateSelectedOnDragHandler.class);
// bind dynamic anchor provider
adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(TestAnchorProviderWithStaticAnchor.class);
}
}
/**
* Returns the index within the Connection's anchors for the given explicit
* anchor index.
*
* @param connection
* The {@link Connection} for which to determine the anchor index
* matching the given explicit index.
* @param explicitAnchorIndex
* The explicit anchor index for which to return the connection
* index.
* @return The connection's anchor index for the given explicit anchor
* index.
*/
// FIXME: Duplicate code (see
// BendConnectionOperation#getConnectionIndex(int)). Find a better place
// for this functionality (perhaps within Connection or IConnectionRouter).
public static int getConnectionIndex(final Connection connection, final int explicitAnchorIndex) {
int explicitCount = -1;
for (int i = 0; i < connection.getPointsUnmodifiable().size(); i++) {
final IAnchor a = connection.getAnchor(i);
if (!connection.getRouter().wasInserted(a)) {
explicitCount++;
}
if (explicitCount == explicitAnchorIndex) {
// found all operation indices
return i;
}
}
throw new IllegalArgumentException(
"Cannot determine connection index for operation index " + explicitAnchorIndex + ".");
}
public static Point getPosition(final BendConnectionPolicy bendPolicy, final int explicitIndex) {
return bendPolicy.getHost().getVisual()
.getPoint(getConnectionIndex(bendPolicy.getHost().getVisual(), explicitIndex));
}
/**
* Ensure the JavaFX toolkit is properly initialized.
*/
@Rule
public FXNonApplicationThreadRule ctx = new FXNonApplicationThreadRule();
@Inject
private IDomain domain;
public int countExplicit(final Connection connection) {
int numExplicit = 0;
for (final IAnchor anchor : connection.getAnchorsUnmodifiable()) {
if (!connection.getRouter().wasInserted(anchor)) {
numExplicit++;
}
}
return numExplicit;
}
private IViewer createViewer(final List<Object> contents) throws Throwable {
// create injector (adjust module bindings for test)
final Injector injector = Guice.createInjector(new TestModule());
// inject domain
injector.injectMembers(this);
final IViewer viewer = domain.getAdapter(AdapterKey.get(IViewer.class, IDomain.CONTENT_VIEWER_ROLE));
ctx.createScene(viewer.getCanvas(), 400, 200);
// activate domain, so tool gets activated and can register listeners
ctx.runAndWait(new Runnable() {
@Override
public void run() {
domain.activate();
}
});
// set contents on JavaFX application thread (visuals are created)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
viewer.getContents().setAll(contents);
}
});
// check that the parts have been created
for (final Object content : contents) {
assertTrue(viewer.getContentPartMap().containsKey(content));
}
return viewer;
}
private IViewer createViewerWithStaticAnchor(final List<Object> contents) throws Throwable {
// create injector (adjust module bindings for test)
final Injector injector = Guice.createInjector(new TestModuleWithStaticAnchor());
// inject domain
injector.injectMembers(this);
final IViewer viewer = domain.getAdapter(AdapterKey.get(IViewer.class, IDomain.CONTENT_VIEWER_ROLE));
ctx.createScene(viewer.getCanvas(), 400, 200);
// activate domain, so tool gets activated and can register listeners
ctx.runAndWait(new Runnable() {
@Override
public void run() {
domain.activate();
}
});
// set contents on JavaFX application thread (visuals are created)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
viewer.getContents().setAll(contents);
}
});
// check that the parts have been created
for (final Object content : contents) {
assertTrue(viewer.getContentPartMap().containsKey(content));
}
return viewer;
}
private void equalsUnprecise(final Point p, final Point q) {
assertEquals(p + " and " + q + " are not (unprecisely) equal but differ in x: ", p.x, q.x, 0.5);
assertEquals(p + " and " + q + " are not (unprecisely) equal but differ in y: ", p.y, q.y, 0.5);
}
@Test
public void test_create_orthogonal_segment_from_implicit_connected() throws Throwable {
final List<Object> contents = TestModels.getAB_offset2_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
// XXX: The strategies are exchanged before setting the router
// so that a refresh will use these strategies
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy() {
@Override
public Point computePositionInScene(final Node anchorage, final Node anchored,
final Set<Parameter<?>> parameters) {
// ensure routing starts going to the right
return new Point(49, 25);
}
});
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy() {
@Override
public Point computePositionInScene(final Node anchorage, final Node anchored,
final Set<Parameter<?>> parameters) {
// ensure routing ends going to the right
return new Point(301, 525);
}
});
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// check if router inserted implicit points
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
// create new segment between 2nd implicit and end
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
// determine segment indices for neighbor anchors
final int firstSegmentIndex = 2;
final int secondSegmentIndex = 3;
// determine middle of segment
final Point firstPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getPoint(firstSegmentIndex);
}
});
final Point secondPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getPoint(secondSegmentIndex);
}
});
// check that segment to be selected is horizontal
assertEquals(firstPoint.y, secondPoint.y, 0.0001);
final Vector direction = new Vector(firstPoint, secondPoint);
final Point midPoint = firstPoint.getTranslated(direction.x / 2, direction.y / 2);
final Point2D midInScene = ctx.runAndWait(new RunnableWithResult<Point2D>() {
@Override
public Point2D run() {
return connection.getVisual().localToScene(midPoint.x, midPoint.y);
}
});
// determine connectedness of first anchor handle
final Node firstAnchorage = ctx.runAndWait(new RunnableWithResult<Node>() {
@Override
public Node run() {
return connection.getVisual().getAnchor(firstSegmentIndex).getAnchorage();
}
});
final boolean isFirstConnected = firstAnchorage != null && firstAnchorage != connection.getVisual();
// make the anchor handles explicit
final List<Integer> explicit = ctx.runAndWait(new RunnableWithResult<List<Integer>>() {
@Override
public List<Integer> run() {
return bendPolicy.makeExplicit(firstSegmentIndex - 1, secondSegmentIndex);
}
});
int firstAnchorIndex = explicit.get(1);
final Point firstAnchorHandleInitialPosition = ctx.runAndWait(new RunnableWithResultAndParam<Point, Integer>() {
@Override
public Point run(final Integer firstAnchorIndex) {
return getPosition(bendPolicy, firstAnchorIndex);
}
}, firstAnchorIndex);
int secondAnchorIndex = explicit.get(2);
assertEquals(4, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
// copy first point if connected
if (isFirstConnected) {
// use the copy as the new first anchor handle
firstAnchorIndex = ctx.runAndWait(new RunnableWithResultAndParam<Integer, Integer>() {
@Override
public Integer run(final Integer firstAnchorIndex) {
return bendPolicy.createAfter(firstAnchorIndex, FX2Geometry.toPoint(connection.getVisual()
.localToScene(Geometry2FX.toFXPoint(firstAnchorHandleInitialPosition))));
}
}, firstAnchorIndex);
}
// create new anchor at the segment's middle
secondAnchorIndex = ctx.runAndWait(new RunnableWithResultAndParam<Integer, Integer>() {
@Override
public Integer run(final Integer firstAnchorIndex) {
return bendPolicy.createAfter(firstAnchorIndex, FX2Geometry.toPoint(midInScene));
}
}, firstAnchorIndex);
// copy that new anchor
secondAnchorIndex = ctx.runAndWait(new RunnableWithResultAndParam<Integer, Integer>() {
@Override
public Integer run(final Integer firstAnchorIndex) {
return bendPolicy.createAfter(firstAnchorIndex, FX2Geometry.toPoint(midInScene));
}
}, firstAnchorIndex);
// check to be selected segment is horizontal
assertEquals(ctx.runAndWait(new RunnableWithResultAndParam<Point, Integer>() {
@Override
public Point run(final Integer firstAnchorIndex) {
return getPosition(bendPolicy, firstAnchorIndex);
}
}, firstAnchorIndex).y, ctx.runAndWait(new RunnableWithResultAndParam<Point, Integer>() {
@Override
public Point run(final Integer secondAnchorIndex) {
return getPosition(bendPolicy, secondAnchorIndex);
}
}, secondAnchorIndex).y, 0.0001);
// select the first anchor and the copy of the new mid anchor for
// movement
{
final int fai = firstAnchorIndex;
final int sai = secondAnchorIndex;
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(fai);
bendPolicy.select(sai);
}
});
}
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move new segment up
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -50));
}
});
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move new segment further up
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -100));
}
});
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move new segment further up
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -150));
}
});
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move new segment down a bit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -120));
}
});
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move new segment down a bit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -60));
}
});
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move new segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
// commit (i.e. normalize)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
}
@Test
public void test_end_overlays_way_restore() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
// verify that way point is present
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// find way point anchor
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final Point wayPoint = connection.getContent().getWayPoint();
final int wayPointAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
// check anchor position
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, wayPointAnchorHandle);
}
}));
// select end point
final int endAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(2);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(endAnchorHandle);
}
});
// move left to overlay the way point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(),
new Point(-wayPoint.getDistance(getPosition(bendPolicy, endAnchorHandle)), 0));
}
});
// verify that the point is removed
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// move back to restore the overlain anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
// verify point is present again
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(wayPoint, connection.getVisual().getPoint(1));
// verify point is present after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(wayPoint, connection.getVisual().getPoint(1));
}
@Test
public void test_move_connected_orthogonal_segment_down() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// copy start point and end point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int firstWayAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorIndex, startPoint);
}
});
final int secondWayAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorIndex, endPoint);
}
});
// check number of points
assertEquals(4, countExplicit(connection.getVisual()));
// move segment down by 100 to create 2 new segments
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayAnchorIndex);
bendPolicy.select(secondWayAnchorIndex);
bendPolicy.move(new Point(), new Point(0, 100));
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(endPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
}
@Test
public void test_move_connected_orthogonal_segment_down_translated() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// copy start point and end point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
assertEquals(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, startAnchorHandle);
}
}));
final Point firstWayPoint = startPoint.getCopy();
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, firstWayPoint);
}
});
assertEquals(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, startAnchorHandle);
}
}));
final Point secondWayPoint = endPoint.getCopy();
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, secondWayPoint);
}
});
// check number of points
assertEquals(4, countExplicit(connection.getVisual()));
// check coordinates
assertEquals(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, startAnchorHandle);
}
}));
assertEquals(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, firstWayAnchorHandle);
}
}));
assertEquals(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, secondWayAnchorHandle);
}
}));
assertEquals(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment down by 100 to create 2 new segments
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayAnchorHandle);
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.move(new Point(), new Point(0, 100));
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(firstWayPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
}
@Test
public void test_move_connected_orthogonal_segment_restore() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// copy start point and end point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
final int startAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int firstWayAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorIndex, startPoint);
}
});
final int secondWayAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorIndex, endPoint);
}
});
// check number of points
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
// move segment down by 100 to create 2 new segments
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayAnchorIndex);
bendPolicy.select(secondWayAnchorIndex);
bendPolicy.move(new Point(), new Point(0, 100));
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(endPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(startPoint.getTranslated(0, 25), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint.getTranslated(0, 25), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment back
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
// check number of points
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// check number of points after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
}
@Test
public void test_move_connected_orthogonal_segment_up() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// copy start point and end point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, startPoint);
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, endPoint);
}
});
// check number of points
assertEquals(4, countExplicit(connection.getVisual()));
// move segment down by 100 to create 2 new segments
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayAnchorHandle);
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.move(new Point(), new Point(0, -100));
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint.getTranslated(0, -100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(endPoint.getTranslated(0, -100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
}
@Test
public void test_move_explicit_orthogonal_segment_overlay() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// create control points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final Point firstWayPoint = new Point(startPoint.x + 100, startPoint.y);
final Point secondWayPoint = new Point(startPoint.x + 100, startPoint.y + 100);
final Point thirdWayPoint = new Point(startPoint.x + 200, startPoint.y + 100);
final Point fourthWayPoint = new Point(startPoint.x + 200, startPoint.y);
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, firstWayPoint);
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, secondWayPoint);
}
});
final int thirdWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(secondWayAnchorHandle, thirdWayPoint);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.createAfter(thirdWayAnchorHandle, fourthWayPoint);
}
});
// check number of points
assertEquals(6, countExplicit(connection.getVisual()));
// move segment up to create an overlay
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.select(thirdWayAnchorHandle);
bendPolicy.move(new Point(), new Point(0, -100));
}
});
// check number of points and their positions
assertEquals(2, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment further up to restore the removed points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -200));
}
});
// check number of points and their positions
assertEquals(6, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint.getTranslated(0, -200), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(thirdWayPoint.getTranslated(0, -200), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(2);
}
}));
equalsUnprecise(fourthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(3);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(6, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(thirdWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(2);
}
}));
equalsUnprecise(fourthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(3);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_move_explicit_orthogonal_segment_overlay_side() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// create control points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final Point firstWayPoint = new Point(startPoint.x + 100, startPoint.y);
final Point secondWayPoint = new Point(startPoint.x + 100, startPoint.y + 200);
final Point thirdWayPoint = new Point(startPoint.x + 200, startPoint.y + 200);
final Point fourthWayPoint = new Point(startPoint.x + 200, startPoint.y + 100);
final Point fifthWayPoint = new Point(startPoint.x + 300, startPoint.y + 100);
final Point sixthWayPoint = new Point(startPoint.x + 300, startPoint.y);
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, firstWayPoint);
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, secondWayPoint);
}
});
final int thirdWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(secondWayAnchorHandle, thirdWayPoint);
}
});
final int fourthWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(thirdWayAnchorHandle, fourthWayPoint);
}
});
final int fifthWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(fourthWayAnchorHandle, fifthWayPoint);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.createAfter(fifthWayAnchorHandle, sixthWayPoint);
}
});
// check number of points
assertEquals(8, countExplicit(connection.getVisual()));
// move segment to the right to create a 3 segment overlay
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayAnchorHandle);
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.move(new Point(), new Point(100, 0));
}
});
// check number of points and their positions
assertEquals(6, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint.getTranslated(100, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(fourthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(fifthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(2);
}
}));
equalsUnprecise(sixthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(3);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment back to the left to restore the original positions
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
assertEquals(8, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(thirdWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(2);
}
}));
equalsUnprecise(fourthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(3);
}
}));
equalsUnprecise(fifthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(4);
}
}));
equalsUnprecise(sixthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(5);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment to the right to create an unprecise 3 segment overlay
// (default threshold of 10px)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(95, 0));
}
});
assertEquals(6, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint.getTranslated(100, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(fourthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(fifthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(2);
}
}));
equalsUnprecise(sixthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(3);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// check if the overlay is still removed after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(6, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint.getTranslated(100, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(fourthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(fifthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(2);
}
}));
equalsUnprecise(sixthWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(3);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_move_explicit_orthogonal_segment_simple() throws Throwable {
final List<Object> contents = TestModels.getAB_offset_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// create control points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final Point firstWayPoint = new Point(startPoint.x + 100, startPoint.y);
final Point secondWayPoint = new Point(startPoint.x + 100, endPoint.y);
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, firstWayPoint);
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, secondWayPoint);
}
});
// start point and end point changed due to the new control points
startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// check number of points
assertEquals(4, countExplicit(connection.getVisual()));
// move segment to the left (no overlay)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayAnchorHandle);
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.move(new Point(), new Point(-10, 0));
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint.getTranslated(-10, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint.getTranslated(-10, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment to the right (no overlay)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(10, 0));
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint.getTranslated(10, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint.getTranslated(10, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_move_ortho_anchorages_horizontally() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// move start and end anchorage horizontally
AffineTransform translation = new AffineTransform().setToTranslation(50, 0);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
final AnchoragePart startAnchorage = (AnchoragePart) viewer.getContentPartMap().get(contents.get(0));
final AnchoragePart endAnchorage = (AnchoragePart) viewer.getContentPartMap().get(contents.get(1));
AffineTransform newStartTransform = FX2Geometry.toAffineTransform(startAnchorage.getVisualTransform())
.preConcatenate(translation);
AffineTransform newEndTransform = FX2Geometry.toAffineTransform(endAnchorage.getVisualTransform())
.preConcatenate(translation);
// XXX: Order is important! Move start first, so that end anchor
// computation does not yield a different result.
// System.out.println("TX START");
startAnchorage.setVisualTransform(Geometry2FX.toFXAffine(newStartTransform));
// System.out.println("TX END");
endAnchorage.setVisualTransform(Geometry2FX.toFXAffine(newEndTransform));
}
});
// ensure start and end point moved
final Point newStartPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point newEndPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
assertEquals(startPoint.getTransformed(translation), newStartPoint);
assertEquals(endPoint.getTransformed(translation), newEndPoint);
// reattach anchors
ctx.runAndWait(new Runnable() {
@Override
public void run() {
IAnchor startAnchor = connection.getVisual().getStartAnchor();
IAnchor endAnchor = connection.getVisual().getEndAnchor();
connection.getVisual().setStartPoint(new Point());
// System.out.println("#########################");
// System.out.println("#########################");
connection.getVisual().setEndPoint(new Point());
// System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@");
// System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@");
connection.getVisual().setStartAnchor(startAnchor);
// System.out.println("#########################");
// System.out.println("#########################");
connection.getVisual().setEndAnchor(endAnchor);
// System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@");
// System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@");
}
});
// ensure start and end point did not move
final Point newStartPoint2 = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point newEndPoint2 = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
assertEquals(newStartPoint, newStartPoint2);
assertEquals(newEndPoint, newEndPoint2);
}
@Test
public void test_move_segment_connected_overlay() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
// find start and end handles
final int startHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int endHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(1);
}
});
assertEquals(ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, startHandle);
}
}));
assertEquals(ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, endHandle);
}
}));
// copy both connected end points
final int leftCopy = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
Point position = getPosition(bendPolicy, startHandle);
Point localToScene = NodeUtils.localToScene(connection.getVisual(), position);
return bendPolicy.createAfter(startHandle, localToScene);
}
});
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, startHandle);
}
}), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, leftCopy);
}
}));
final int rightCopy = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createBefore(endHandle, getPosition(bendPolicy, endHandle));
}
});
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
ctx.runAndWait(new Runnable() {
@Override
public void run() {
assertEquals(getPosition(bendPolicy, endHandle), getPosition(bendPolicy, rightCopy));
}
});
// select the copies for movement
// and move down by 100
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(leftCopy);
bendPolicy.select(rightCopy);
bendPolicy.move(new Point(), new Point(0, 100));
}
});
// check if points are correct
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
// move back to get a double overlay
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
bendPolicy.commit();
}
});
// check if points have been removed
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
}
@Test
public void test_move_single_explicit_anchor() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
// find way point anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final Point wayPoint = connection.getContent().getWayPoint();
final int anchorBackwards = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
final int anchorForwards = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(1);
}
});
// assertEquals(1, anchorBackwards.getExplicitAnchorIndex());
assertEquals(anchorBackwards, anchorForwards);
// check anchor position
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, anchorBackwards);
}
}));
assertEquals(wayPoint, connection.getVisual().getPoint(1));
// select anchor
// and move down by 100
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(anchorBackwards);
bendPolicy.move(new Point(0, 0), new Point(0, 100));
}
});
assertEquals(wayPoint.getTranslated(0, 100), connection.getVisual().getPoint(1));
assertEquals(wayPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, anchorBackwards);
}
}));
// verify position after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(wayPoint.getTranslated(0, 100), connection.getVisual().getPoint(1));
}
@Test
public void test_overlay_segment_left_first() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// create control points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, new Point(100, 100));
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, new Point(100, 200));
}
});
final int thirdWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(secondWayAnchorHandle, new Point(200, 210));
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.createAfter(thirdWayAnchorHandle, new Point(200, 100));
}
});
// check if points are correct
assertEquals(7, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(100, 200), connection.getVisual().getPoint(2));
assertEquals(new Point(200, 210), connection.getVisual().getPoint(3));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(4));
// move segment so that only the second way anchor overlays the first
// way anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.select(thirdWayAnchorHandle);
bendPolicy.move(new Point(), new Point(0, -95));
}
});
// check if the overlaying was removed
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move segment so that also the third way anchor overlays the fourth
// way anchor, i.e. it is a double overlay
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -105));
}
});
// check if the overlaying anchors were removed
assertEquals(5, connection.getVisual().getPointsUnmodifiable().size());
// check that the overlain anchors have the same position as before
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(2));
// move segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
bendPolicy.commit();
}
});
// check that all anchors have been restored
assertEquals(7, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(100, 200), connection.getVisual().getPoint(2));
assertEquals(new Point(200, 210), connection.getVisual().getPoint(3));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(4));
}
@Test
public void test_overlay_segment_right_first() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// create control points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, new Point(100, 100));
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, new Point(100, 210));
}
});
final int thirdWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(secondWayAnchorHandle, new Point(200, 200));
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.createAfter(thirdWayAnchorHandle, new Point(200, 100));
}
});
// check if points are correct
assertEquals(7, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(100, 210), connection.getVisual().getPoint(2));
assertEquals(new Point(200, 200), connection.getVisual().getPoint(3));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(4));
// move segment so that only the second way anchor overlays the first
// way anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.select(thirdWayAnchorHandle);
bendPolicy.move(new Point(), new Point(0, -95));
}
});
// check if the overlaying was removed
assertEquals(6, connection.getVisual().getPointsUnmodifiable().size());
// move segment so that also the third way anchor overlays the fourth
// way anchor, i.e. it is a double overlay
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, -105));
}
});
// check if the overlaying anchors were removed
assertEquals(5, connection.getVisual().getPointsUnmodifiable().size());
// check that the overlain anchors have the same position as before
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(2));
// move segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
bendPolicy.commit();
}
});
// check that all anchors have been restored
assertEquals(7, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(100, 210), connection.getVisual().getPoint(2));
assertEquals(new Point(200, 200), connection.getVisual().getPoint(3));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(4));
}
@Test
public void test_overlay_segment_simple() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// create control points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
final int firstWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorHandle, new Point(100, 100));
}
});
final int secondWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayAnchorHandle, new Point(100, 200));
}
});
final int thirdWayAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(secondWayAnchorHandle, new Point(200, 200));
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.createAfter(thirdWayAnchorHandle, new Point(200, 100));
}
});
// check if points are correct
assertEquals(7, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(new Point(100, 100), connection.getVisual().getPoint(1));
assertEquals(new Point(100, 200), connection.getVisual().getPoint(2));
assertEquals(new Point(200, 200), connection.getVisual().getPoint(3));
assertEquals(new Point(200, 100), connection.getVisual().getPoint(4));
// move segment so that we get a double overlay
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(secondWayAnchorHandle);
bendPolicy.select(thirdWayAnchorHandle);
bendPolicy.move(new Point(), new Point(0, -100));
bendPolicy.commit();
}
});
// check if points have been removed
assertEquals(5, connection.getVisual().getPointsUnmodifiable().size());
}
@Test
public void test_overlay_single() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
// find way point anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final Point wayPoint = connection.getContent().getWayPoint();
final int anchorBackwards = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
final int anchorForwards = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(1);
}
});
// assertEquals(1, anchorBackwards.getExplicitAnchorIndex());
assertEquals(anchorBackwards, anchorForwards);
final int firstWayPointAnchorHandle = anchorBackwards;
// check anchor position
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, anchorBackwards);
}
}));
assertEquals(wayPoint, connection.getVisual().getPoint(1));
// create way point 20 px to the right of the existing one
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.createAfter(firstWayPointAnchorHandle, wayPoint.getTranslated(20, 0));
}
});
// verify that the point is inserted
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
// select first way point
// and move right by 20
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(firstWayPointAnchorHandle);
bendPolicy.move(new Point(), new Point(20, 0));
}
});
// verify that the point is removed
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// verify point is removed after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
}
@Test
public void test_regression_makeExplicit() throws Throwable {
final List<Object> contents = TestModels.get_regression_makeExplicit();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter() {
@Override
protected void updateComputationParameters(List<Point> points, int index, DynamicAnchor anchor,
AnchorKey key) {
if (index == 0) {
ObjectBinding<Point> refBinding = new ObjectBinding<Point>() {
{
bind(key.getAnchored().localToParentTransformProperty());
}
@Override
protected Point computeValue() {
return FX2Geometry.toPoint(key.getAnchored().parentToLocal(new Point2D(310, 40)));
}
};
anchor.getComputationParameter(key, PreferredOrientation.class).set(Orientation.HORIZONTAL);
anchor.getComputationParameter(key, AnchoredReferencePoint.class).bind(refBinding);
} else if (index == points.size() - 1) {
ObjectBinding<Point> refBinding = new ObjectBinding<Point>() {
{
bind(key.getAnchored().localToParentTransformProperty());
}
@Override
protected Point computeValue() {
return FX2Geometry.toPoint(key.getAnchored().parentToLocal(new Point2D(50, 95)));
}
};
anchor.getComputationParameter(key, PreferredOrientation.class).set(Orientation.HORIZONTAL);
anchor.getComputationParameter(key, AnchoredReferencePoint.class).bind(refBinding);
} else {
super.updateComputationParameters(points, index, anchor, key);
}
}
});
}
});
// System.out.println("\n\n\n\nSETUP COMPLETE\n\n\n\n");
// verify router inserted two control points
assertEquals(2, countExplicit(connection.getVisual()));
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
// verify control points share X coordinate
assertEquals(connection.getVisual().getPoint(1).x, connection.getVisual().getPoint(2).x, 0.5);
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// select first segment for manipulation
// and move down to endPoint height
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
// copy start anchor and make 1st router anchor explicit
bendPolicy.selectSegment(0);
bendPolicy.move(new Point(), new Point(0, endPoint.y - startPoint.y));
// overlay removal should remove both router anchors, so that
// only the start anchor, its copy and the end anchor are
// remaining
}
});
assertEquals(3, countExplicit(connection.getVisual()));
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
equalsUnprecise(new Point(startPoint.x, endPoint.y), connection.getVisual().getPoint(1));
// move segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
// check number of points and their positions
assertEquals(3, countExplicit(connection.getVisual()));
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move down to endPoint height - 5 so that it will snap with the two
// implicit points
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, endPoint.y - startPoint.y - 5));
}
});
assertEquals(3, countExplicit(connection.getVisual()));
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
equalsUnprecise(new Point(startPoint.x, endPoint.y), connection.getVisual().getPoint(1));
// move further down so that the segment is restored
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, endPoint.y - startPoint.y + 15));
}
});
assertEquals(4, countExplicit(connection.getVisual()));
assertEquals(5, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
// check that segment is "unsnapped", i.e. end point is still on initial
// y coordinate
final Point endPositionHint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPointHint();
}
});
assertEquals(connection.getVisual().getEndPoint().y, endPositionHint.y, 0.5);
// TODO: Ensure position hints are correctly restored.
// move segment back to its original position
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(3, countExplicit(connection.getVisual()));
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_relocateAnchor() throws Throwable {
final List<Object> contents = TestModels.getABC_AB_BC();
final IViewer viewer = createViewer(contents);
// save initial start point of second connection
final ConnectionPart secondConnectionPart = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final Point secondConnectionStart = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
((GeometryNode<?>) secondConnectionPart.getVisual().getCurve()).setStrokeWidth(5);
return secondConnectionPart.getVisual().getStartPoint();
}
});
// move mouse to first connection
final ConnectionPart firstConnectionPart = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 2));
final Point firstConnectionEnd = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
((GeometryNode<?>) firstConnectionPart.getVisual().getCurve()).setStrokeWidth(5);
return firstConnectionPart.getVisual().getEndPoint();
}
});
final Point firstConnectionMid = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return firstConnectionPart.getVisual().getStartPoint().getTranslated(firstConnectionPart.getVisual()
.getStartPoint().getDifference(firstConnectionPart.getVisual().getPoint(1)).getScaled(0.5));
}
});
ctx.mouseMove(firstConnectionPart.getVisual(), firstConnectionMid.x, firstConnectionMid.y);
// check selection is empty
ctx.runAndWait(new Runnable() {
@Override
public void run() {
ObservableList<IContentPart<? extends Node>> selectionUnmodifiable = viewer
.getAdapter(SelectionModel.class).getSelectionUnmodifiable();
assertTrue(selectionUnmodifiable.isEmpty());
}
});
// select connection
ctx.mousePress();
ctx.mouseRelease();
// check the connection is selected
ctx.runAndWait(new Runnable() {
@Override
public void run() {
ObservableList<IContentPart<? extends Node>> selectionUnmodifiable = viewer
.getAdapter(SelectionModel.class).getSelectionUnmodifiable();
assertTrue(selectionUnmodifiable.contains(firstConnectionPart));
}
});
// move mouse to second anchorage
final AnchoragePart secondPart = (AnchoragePart) viewer.getContentPartMap().get(contents.get(1));
final AtomicReference<Point> centerRef = new AtomicReference<>(null);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
centerRef.set(((org.eclipse.gef.geometry.planar.Rectangle) secondPart.getContent()).getCenter());
}
});
final Point center = centerRef.get();
ctx.mouseMove(secondPart.getVisual(), center.x, center.y);
// drag anchorage down by 10px
ctx.mousePress();
ctx.mouseDrag(center.x, center.y + 10);
ctx.mouseRelease();
// check the anchorage is selected
ctx.runAndWait(new Runnable() {
@Override
public void run() {
ObservableList<IContentPart<? extends Node>> selectionUnmodifiable = viewer
.getAdapter(SelectionModel.class).getSelectionUnmodifiable();
assertTrue(selectionUnmodifiable.contains(secondPart));
}
});
// check first connection was moved
assertNotEquals(firstConnectionEnd, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return firstConnectionPart.getVisual().getStartPoint();
}
}));
// check second connection was moved
assertNotEquals(secondConnectionStart, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return secondConnectionPart.getVisual().getStartPoint();
}
}));
}
/**
* <ol>
* <li>class com.thyssenkrupp.tkse.promise.mdse.process.ui.view.provider.
* ProcessDynamicAnchorProvider$1[Point(352.8252868652344,
* -365.8699951171875)]
* (com.thyssenkrupp.tkse.promise.mdse.process.ui.view.provider.
* ProcessDynamicAnchorProvider$1@665574fb)
* {org.eclipse.gef.mvc.fx.policies.
* BendConnectionPolicy$AnchorHandle@3eb7ff78},
* <ul>
* <li>DA anchorage geometry in scene = Polygon: (349.49988,
* 56.54434506500246) -> (359.9554149349976, 66.99988000000002) ->
* (349.49988, 77.45541493499758) -> (339.04434506500246,
* 66.99988000000002) -> (349.49988, 56.54434506500246)
* <li>DA anchor key = AnchorKey <start>
* <GeometryNode@333e01c6[styleClass=curve]>
* <li>DA anchored reference point = Point(356.25, -365.87)
* </ul>
* <li>class
* org.eclipse.gef.fx.nodes.OrthogonalRouter$OrthogonalPolylineRouterAnchor
* [Point(352.8252868652344, -190.0)], class
* org.eclipse.gef.fx.anchors.StaticAnchor[Point(356.25, -190.0)]
* (StaticAnchor[referencePosition = Point(356.25, -190.0)])
* {org.eclipse.gef.mvc.fx.policies.
* BendConnectionPolicy$AnchorHandle@50ad5625},
* <li>class com.thyssenkrupp.tkse.promise.mdse.process.ui.view.provider.
* ProcessDynamicAnchorProvider$1[Point(346.9552917480469, -190.0)]
* (com.thyssenkrupp.tkse.promise.mdse.process.ui.view.provider.
* ProcessDynamicAnchorProvider$1@1d921267)
* {org.eclipse.gef.mvc.fx.policies.
* BendConnectionPolicy$AnchorHandle@1c5f6292}
* <ul>
* <li>DA anchorage geometry in scene = Polygon: (338.49988,
* 237.54434506500243) -> (348.9554149349976, 247.99988) ->
* (338.49988, 258.4554149349975) -> (328.04434506500246, 247.99988)
* -> (338.49988, 237.54434506500243)
* <li>DA anchor key = AnchorKey <end>
* <GeometryNode@333e01c6[styleClass=curve]>
* <li>DA anchored reference point = Point(350.01, -190.0)
* </ul>
* </ol>
*
* @throws InterruptedException
* @throws InvocationTargetException
* @throws AWTException
*/
@Test
public void test_segment_select_error_split_segment() throws Throwable {
final List<Object> contents = TestModels.getDA_click_error();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final Point controlPoint = new Point(356.25, 237.54434204101562);
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
connection.getVisual().addControlPoint(0, controlPoint);
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// ensure router inserted point
assertEquals(3, countExplicit(connection.getVisual()));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
bendPolicy.selectSegment(0); // makes a router anchor explicit
bendPolicy.move(new Point(), new Point());
// XXX: Empty move() should use overlay removal to get rid of
// the recently added anchor (the one made explicit).
}
});
assertEquals(3, countExplicit(connection.getVisual()));
}
@Test
public void test_snap_reuse_ref_point() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
// manipulate contents so that second anchorage starts below the first
// anchorage
((org.eclipse.gef.geometry.planar.Rectangle) contents.get(1)).setY(20);
final IViewer viewer = createViewer(contents);
// query connection part
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// query bend policy for the connection
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// select first segment for manipulation
// and move down so that there are three segments
double moveDown = 15;
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
// double mid point
int midHandle = bendPolicy.getExplicitIndexAtOrBefore(1);
bendPolicy.createAfter(midHandle, connection.getVisual().getPoint(1));
bendPolicy.selectSegment(0);
bendPolicy.move(new Point(), new Point(0, moveDown));
}
});
assertEquals(4, countExplicit(connection.getVisual()));
assertEquals(4, connection.getVisual().getPointsUnmodifiable().size());
equalsUnprecise(startPoint.getTranslated(0, moveDown), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
equalsUnprecise(new Point(0.5 * startPoint.x + 0.5 * endPoint.x, startPoint.y + moveDown),
connection.getVisual().getPoint(1));
equalsUnprecise(new Point(0.5 * startPoint.x + 0.5 * endPoint.x, endPoint.y),
connection.getVisual().getPoint(2));
// drag segment upwards so that it snaps back to a single segment
double moveUp = 5;
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(0, moveUp));
}
});
// 3 points but only 1 segment, because the copied start point is at the
// same position as the start point
assertEquals(3, countExplicit(connection.getVisual()));
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(startPoint, connection.getVisual().getPoint(1));
assertEquals(startPoint, connection.getVisual().getStartPoint());
assertEquals(endPoint, connection.getVisual().getEndPoint());
// commit bending to normalize the edge
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(2, countExplicit(connection.getVisual()));
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(startPoint, connection.getVisual().getStartPoint());
assertEquals(endPoint, connection.getVisual().getEndPoint());
}
@Test
public void test_start_overlays_way_restore() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
// verify that way point is present
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// find way point anchor
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final Point wayPoint = connection.getContent().getWayPoint();
final int wayPointAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
// check anchor position
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, wayPointAnchorHandle);
}
}));
// select end point
final int startAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(0);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(startAnchorHandle);
}
});
// move to the right to overlay the way point
final double distance = wayPoint.getDistance(ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, startAnchorHandle);
}
}));
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(distance, 0));
}
});
// verify that the point is removed
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// move back to restore the overlain anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
// verify point is present again
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(wayPoint, connection.getVisual().getPoint(1));
// verify point is present after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(wayPoint, connection.getVisual().getPoint(1));
}
@Test
public void test_static_connected_move_orthogonal_segment_overlay_start_and_end() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewerWithStaticAnchor(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
Set<Entry<IVisualPart<? extends Node>, String>> anchorages = connection.getAnchoragesUnmodifiable().entries();
AnchoragePart sourceAnchorage = null;
AnchoragePart targetAnchorage = null;
for (Entry<IVisualPart<? extends Node>, String> e : anchorages) {
if (e.getValue().equals(ConnectionPart.START_ROLE)) {
sourceAnchorage = (AnchoragePart) e.getKey();
}
if (e.getValue().equals(ConnectionPart.END_ROLE)) {
targetAnchorage = (AnchoragePart) e.getKey();
}
}
final AnchoragePart startAnchorage = sourceAnchorage;
final AnchoragePart endAnchorage = targetAnchorage;
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router
ctx.runAndWait(new Runnable() {
@Override
public void run() {
connection.getVisual().setRouter(new OrthogonalRouter());
// FIXME: anchorage visuals do not have correct size, therefore,
// the start and end position is not computed but manually
// specified here
StaticAnchor anchor = (StaticAnchor) startAnchorage.getAdapter(IAnchorProvider.class).get(connection);
anchor.setReferencePosition(new Point());
anchor = (StaticAnchor) endAnchorage.getAdapter(IAnchorProvider.class).get(connection);
anchor.setReferencePosition(new Point(500, 0));
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// copy start and end point and move segment (start-copy, end-copy) down
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
Point firstWayPoint = startPoint.getCopy();
Point secondWayPoint = endPoint.getCopy();
ctx.runAndWait(new Runnable() {
@Override
public void run() {
int firstWayIndex = bendPolicy.createAfter(startAnchorIndex, firstWayPoint);
int secondWayIndex = bendPolicy.createAfter(firstWayIndex, secondWayPoint);
bendPolicy.select(firstWayIndex);
bendPolicy.select(secondWayIndex);
bendPolicy.move(new Point(), new Point(0, 100));
firstWayPoint.translate(0, 100);
secondWayPoint.translate(0, 100);
bendPolicy.commit();
}
});
// check points
assertEquals(4, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
// move segment up so that the way points are removed
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
bendPolicy.select(1);
bendPolicy.select(2);
bendPolicy.move(new Point(), new Point(0, -100));
bendPolicy.commit();
}
});
// check points
assertEquals(2, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_unconnected_move_orthogonal_segment_overlay_end() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// disconnect start point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(startAnchorIndex);
bendPolicy.move(new Point(), new Point(20, 0));
bendPolicy.commit();
}
});
startPoint.translate(20, 0);
// ensure number of points did not change
assertEquals(2, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
// disconnect end point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
{
final int endAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(endAnchorIndex);
bendPolicy.move(new Point(), new Point(-20, 0));
bendPolicy.commit();
}
});
}
endPoint.translate(-20, 0);
// ensure number of points did not change
assertEquals(2, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
// insert way point and copy that way point, so that the right segment
// (way-copy, end) can be dragged down to create three segments
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int firstWayIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorIndex, new Line(startPoint, endPoint).get(0.5));
}
});
final int secondWayIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayIndex, new Line(startPoint, endPoint).get(0.5));
}
});
final Point firstWayPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
});
final int endAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(secondWayIndex + 1);
}
});
// drag right segment (way-copy, end) down, so that the connection is
// divided into three segments: (start, way), (way, way-copy),
// (way-copy, end)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(secondWayIndex);
bendPolicy.select(endAnchorIndex);
bendPolicy.move(new Point(), new Point(0, 100));
endPoint.translate(0, 100);
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(firstWayPoint.getTranslated(0, 100), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
// drag middle segment (first-way, second-way) onto the end point in
// order to remove the second way point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
bendPolicy.select(firstWayIndex);
bendPolicy.select(secondWayIndex);
double dx = endPoint.x - firstWayPoint.x;
bendPolicy.move(new Point(), new Point(dx, 0));
firstWayPoint.translate(dx, 0);
bendPolicy.commit();
}
});
// ensure second way point was removed and the rest is in place
assertEquals(3, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_unconnected_move_orthogonal_segment_overlay_start() throws Throwable {
final List<Object> contents = TestModels.getAB_AB_simple();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// setup connection to be orthogonal, i.e. use orthogonal router and
// use orthogonal projection strategy at the anchorages
ctx.runAndWait(new Runnable() {
@Override
public void run() {
((DynamicAnchor) connection.getVisual().getStartAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
((DynamicAnchor) connection.getVisual().getEndAnchor())
.setComputationStrategy(new OrthogonalProjectionStrategy());
connection.getVisual().setRouter(new OrthogonalRouter());
}
});
// query start point and end point so that we can construct orthogonal
// control points
final Point startPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
});
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
});
// disconnect start point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int startAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(0);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(startAnchorIndex);
bendPolicy.move(new Point(), new Point(20, 0));
bendPolicy.commit();
}
});
startPoint.translate(20, 0);
// ensure number of points did not change
assertEquals(2, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
// disconnect end point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
{
final int endAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(endAnchorIndex);
bendPolicy.move(new Point(), new Point(-20, 0));
bendPolicy.commit();
}
});
}
endPoint.translate(-20, 0);
// ensure number of points did not change
assertEquals(2, (int) ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return connection.getVisual().getPointsUnmodifiable().size();
}
}));
// insert way point and copy that way point, so that the right segment
// (way-copy, end) can be dragged down to create three segments
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final int firstWayIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(startAnchorIndex, new Line(startPoint, endPoint).get(0.5));
}
});
final int secondWayIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.createAfter(firstWayIndex, new Line(startPoint, endPoint).get(0.5));
}
});
final Point firstWayPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
});
final Point secondWayPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
});
final int endAnchorIndex = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(secondWayIndex + 1);
}
});
// drag right segment (way-copy, end) down, so that the connection is
// divided into three segments: (start, way), (way, way-copy),
// (way-copy, end)
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(secondWayIndex);
bendPolicy.select(endAnchorIndex);
bendPolicy.move(new Point(), new Point(0, 100));
endPoint.translate(0, 100);
secondWayPoint.translate(0, 100);
bendPolicy.commit();
}
});
// check number of points and their positions
assertEquals(4, countExplicit(connection.getVisual()));
equalsUnprecise(firstWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(1);
}
}));
// drag middle segment (first-way, second-way) onto the start point in
// order to remove the first way point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
bendPolicy.select(firstWayIndex);
bendPolicy.select(secondWayIndex);
double dx = startPoint.x - firstWayPoint.x;
bendPolicy.move(new Point(), new Point(dx, 0));
firstWayPoint.translate(dx, 0);
secondWayPoint.translate(dx, 0);
bendPolicy.commit();
}
});
// ensure second way point was removed and the rest is in place
assertEquals(3, countExplicit(connection.getVisual()));
equalsUnprecise(startPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getStartPoint();
}
}));
equalsUnprecise(secondWayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getControlPoint(0);
}
}));
equalsUnprecise(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return connection.getVisual().getEndPoint();
}
}));
}
@Test
public void test_way_overlays_end_remove() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
// verify that way point is present
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// find way point anchor
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final Point wayPoint = connection.getContent().getWayPoint();
final int wayPointAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
// check anchor position
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, wayPointAnchorHandle);
}
}));
// select way point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(wayPointAnchorHandle);
}
});
// find end point handle
final int endPointHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(2);
}
});
// move to the right to overlay the end point, but not exactly onto it
final Point endPoint = ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, endPointHandle);
}
});
final double distance = wayPoint.getDistance(endPoint) - 5;
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(distance, 0));
}
});
// verify that the point is removed
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// verify that the end point is still at the same location
assertEquals(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, endPointHandle - 1);
}
}));
// verify point is removed after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(endPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, endPointHandle - 1);
}
}));
}
@Test
public void test_way_overlays_end_restore() throws Throwable {
final List<Object> contents = TestModels.getAB_AB();
final IViewer viewer = createViewer(contents);
// query bend policy for first connection
final ConnectionPart connection = (ConnectionPart) viewer.getContentPartMap()
.get(contents.get(contents.size() - 1));
// verify that way point is present
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
// find way point anchor
final BendConnectionPolicy bendPolicy = connection.getAdapter(BendConnectionPolicy.class);
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.init();
}
});
final Point wayPoint = connection.getContent().getWayPoint();
final int wayPointAnchorHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrBefore(1);
}
});
// check anchor position
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, wayPointAnchorHandle);
}
}));
// select way point
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.select(wayPointAnchorHandle);
}
});
// find end point handle
final int endPointHandle = ctx.runAndWait(new RunnableWithResult<Integer>() {
@Override
public Integer run() {
return bendPolicy.getExplicitIndexAtOrAfter(2);
}
});
// move to the right to overlay the end point
final double distance = wayPoint.getDistance(ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, endPointHandle);
}
}));
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point(distance, 0));
}
});
assertEquals(wayPoint.getTranslated(distance, 0), ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, wayPointAnchorHandle);
}
}));
// verify that the point is removed
assertEquals(2, connection.getVisual().getPointsUnmodifiable().size());
// move back to the left to restore the overlain anchor
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.move(new Point(), new Point());
}
});
assertEquals(wayPoint, ctx.runAndWait(new RunnableWithResult<Point>() {
@Override
public Point run() {
return getPosition(bendPolicy, wayPointAnchorHandle);
}
}));
// verify point is present again
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(wayPoint, connection.getVisual().getPoint(1));
// verify point is present after commit
ctx.runAndWait(new Runnable() {
@Override
public void run() {
bendPolicy.commit();
}
});
assertEquals(3, connection.getVisual().getPointsUnmodifiable().size());
assertEquals(wayPoint, connection.getVisual().getPoint(1));
}
}