/******************************************************************************* * Copyright (c) 2014, 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.fx.operations; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.operations.AbstractOperation; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.gef.fx.anchors.IAnchor; import org.eclipse.gef.fx.nodes.Connection; /** * An {@link BendConnectionOperation} can be used to manipulate an * {@link Connection} in an undo-context. * * @author mwienand * */ public class BendConnectionOperation extends AbstractOperation implements ITransactionalOperation { private final Connection connection; private final List<IAnchor> initialAnchors; private final List<IAnchor> newAnchors; /** * Constructs a new operation from the given connection. The lists of old * and new {@link IAnchor}s are initialized based on the connection. * * @param connection * The {@link Connection} which will be modified by this * operation. */ public BendConnectionOperation(Connection connection) { super("Bend"); this.connection = connection; this.initialAnchors = new ArrayList<>( onlyExplicit(connection.getAnchorsUnmodifiable())); this.newAnchors = new ArrayList<>(initialAnchors); } @Override public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if (connection != null) { // FIXME: use IBendableContentPart.bendVisual(List<BendPoint>) // update anchors (if needed) if (!onlyExplicit(connection.getAnchorsUnmodifiable()) .equals(newAnchors)) { connection.setAnchors(newAnchors); } } return Status.OK_STATUS; } /** * Returns the {@link Connection} which is manipulated by this operation. * * @return The {@link Connection} which is manipulated by this operation. */ public Connection getConnection() { return connection; } /** * Returns the index within the Connection's anchors for the given explicit * anchor 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. */ public int getConnectionIndex(int explicitAnchorIndex) { int explicitCount = -1; for (int i = 0; i < getConnection().getAnchorsUnmodifiable() .size(); i++) { IAnchor a = getConnection().getAnchor(i); if (!getConnection().getRouter().wasInserted(a)) { explicitCount++; } if (explicitCount == explicitAnchorIndex) { // found all operation indices return i; } } throw new IllegalArgumentException( "Cannot determine connection index for operation index " + explicitAnchorIndex + "."); } /** * Returns the list of {@link IAnchor}s which will replace the connection's * anchors upon undoing. * * @return The list of {@link IAnchor}s which will replace the connection's * anchors upon undoing. */ public List<IAnchor> getInitialAnchors() { return initialAnchors; } /** * Returns the list of {@link IAnchor}s which will replace the connection's * anchors upon execution. * * @return The list of {@link IAnchor}s which will replace the connection's * anchors upon execution. */ public List<IAnchor> getNewAnchors() { return newAnchors; } @Override public boolean isContentRelevant() { return true; } @Override public boolean isNoOp() { // FIXME: use IBendableContentPart.bendVisual(List<BendPoint>) return initialAnchors.equals(newAnchors); } private List<IAnchor> onlyExplicit(List<IAnchor> anchors) { ArrayList<IAnchor> explicit = new ArrayList<>(anchors); Iterator<IAnchor> it = explicit.iterator(); while (it.hasNext()) { IAnchor anchor = it.next(); if (connection.getRouter().wasInserted(anchor)) { it.remove(); } } return explicit; } @Override public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return execute(monitor, info); } /** * Sets the list of {@link IAnchor}s which will replace the connection's * anchors upon execution. * * @param newAnchors * The list of {@link IAnchor}s which will replace the * connection's anchors upon execution. */ public void setNewAnchors(List<IAnchor> newAnchors) { // FIXME: use List<BendPoint> this.newAnchors.clear(); this.newAnchors.addAll(onlyExplicit(newAnchors)); } @Override public String toString() { return "BendConnectionOperation"; } @Override public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if (connection != null) { // FIXME: use IBendableContentPart // check if we have to update anchors here if (!onlyExplicit(connection.getAnchorsUnmodifiable()) .equals(initialAnchors)) { connection.setAnchors(initialAnchors); } } return Status.OK_STATUS; } }