/******************************************************************************* * 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.fx.operations; 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.nodes.InfiniteCanvas; import org.eclipse.gef.geometry.convert.fx.FX2Geometry; import org.eclipse.gef.geometry.convert.fx.Geometry2FX; import org.eclipse.gef.geometry.planar.AffineTransform; import javafx.scene.transform.Affine; /** * The {@link ChangeViewportOperation} can be used to alter the scroll offset * and the content transformation of an {@link InfiniteCanvas}. It is used by * scroll/pan and zoom policies. * * @author mwienand * */ // TODO: we should speak of 'final' instead of 'new' public class ChangeViewportOperation extends AbstractOperation implements ITransactionalOperation { /** * The {@link InfiniteCanvas} that is manipulated by this operation. */ private InfiniteCanvas canvas; /** * The viewport width that is applied when undoing this operation. */ private double initialWidth; /** * The viewport width that is applied when executing this operation. */ private double newWidth; /** * The viewport height that is applied when undoing this operation. */ private double initialHeight; /** * The viewport height that is applied when executing this operation. */ private double newHeight; /** * The contents transformation that is applied when undoing this operation. */ private AffineTransform initialContentTransform; /** * The contents transformation that is applied when executing this * operation. */ private AffineTransform newContentTransform; /** * The horizontal translation that is applied when undoing this operation. */ private double initialHorizontalScrollOffset; /** * The horizontal translation that is applied when executing this operation. */ private double newHorizontalScrollOffset; /** * The vertical translation that is applied when undoing this operation. */ private double initialVerticalScrollOffset; /** * The vertical translation that is applied when executing this operation. */ private double newVerticalScrollOffset; /** * Creates a new {@link ChangeViewportOperation} to manipulate the given * {@link InfiniteCanvas}. The current viewport values are read and used * when undoing this operation. * * @param canvas * The {@link InfiniteCanvas} which is manipulated by this * operation. */ public ChangeViewportOperation(InfiniteCanvas canvas) { super("Change Viewport"); readViewport(canvas); } /** * Creates a new {@link ChangeViewportOperation} to manipulate the given * {@link InfiniteCanvas}. The current viewport values are read and used * when undoing this operation. The given * {@link java.awt.geom.AffineTransform} will be applied when executing this * operation. * * @param canvas * The {@link InfiniteCanvas} that is manipulated. * @param newContentTransform * The contents transformation which is applied when executing * this operation. */ public ChangeViewportOperation(InfiniteCanvas canvas, AffineTransform newContentTransform) { this(canvas); this.newContentTransform = newContentTransform; } /** * Creates a new {@link ChangeViewportOperation} to manipulate the given * {@link InfiniteCanvas}. The current viewport values are read and used * when undoing this operation. The given translation values will be applied * when executing this operation. * * @param canvas * The {@link InfiniteCanvas} that is manipulated. * @param newHorizontalScrollOffset * The horizontal translation that is applied when executing this * operation. * @param newVerticalScrollOffset * The vertical translation that is applied when executing this * operation. */ public ChangeViewportOperation(InfiniteCanvas canvas, double newHorizontalScrollOffset, double newVerticalScrollOffset) { this(canvas); this.newHorizontalScrollOffset = newHorizontalScrollOffset; this.newVerticalScrollOffset = newVerticalScrollOffset; } /** * Creates a new {@link ChangeViewportOperation} to manipulate the given * {@link InfiniteCanvas}. The current viewport values are read and used * when undoing this operation. The given translation values and contents * transformation will be applied when executing this operation. * * @param canvas * The {@link InfiniteCanvas} that is manipulated. * @param newHorizontalScrollOffset * The horizontal translation that is applied when executing this * operation. * @param newVerticalScrollOffset * The vertical translation that is applied when executing this * operation. * @param newContentTransform * The contents transformation which is applied when executing * this operation. */ public ChangeViewportOperation(InfiniteCanvas canvas, double newHorizontalScrollOffset, double newVerticalScrollOffset, AffineTransform newContentTransform) { this(canvas); this.newContentTransform = newContentTransform; this.newHorizontalScrollOffset = newHorizontalScrollOffset; this.newVerticalScrollOffset = newVerticalScrollOffset; } /** * Creates a new {@link ChangeViewportOperation} to manipulate the given * {@link InfiniteCanvas}. The current viewport values are read and used * when undoing this operation. The given translation values, dimensions, * and contents transformation will be applied when executing this * operation. * * @param canvas * The {@link InfiniteCanvas} that is manipulated. * @param newHorizontalScrollOffset * The horizontal translation that is applied when executing this * operation. * @param newVerticalScrollOffset * The vertical translation that is applied when executing this * operation. * @param newWidth * The viewport width that is applied when executing this * operation. * @param newHeight * The viewport height that is applied when executing this * operation. * @param newContentTransform * The contents transformation which is applied when executing * this operation. */ public ChangeViewportOperation(InfiniteCanvas canvas, double newHorizontalScrollOffset, double newVerticalScrollOffset, double newWidth, double newHeight, AffineTransform newContentTransform) { this(canvas); this.newWidth = newWidth; this.newHeight = newHeight; this.newContentTransform = newContentTransform; this.newHorizontalScrollOffset = newHorizontalScrollOffset; this.newVerticalScrollOffset = newVerticalScrollOffset; } /** * Concatenates the given {@link java.awt.geom.AffineTransform} to the * contents transformation that will be applied when executing this * operation. * * @param t * The {@link java.awt.geom.AffineTransform} which is * concatenated to the transformation that will be applied when * executing this operation. */ public void concatenateToNewContentTransform(AffineTransform t) { newContentTransform.concatenate(t); } @Override public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if (canvas.getPrefWidth() != newWidth) { canvas.setPrefWidth(newWidth); } if (canvas.getPrefHeight() != newHeight) { canvas.setPrefHeight(newHeight); } Affine newContentAffine = Geometry2FX.toFXAffine(newContentTransform); if (!canvas.getContentTransform().equals(newContentAffine)) { canvas.setContentTransform(newContentAffine); } if (canvas.getHorizontalScrollOffset() != newHorizontalScrollOffset) { canvas.setHorizontalScrollOffset(newHorizontalScrollOffset); } if (canvas.getVerticalScrollOffset() != newVerticalScrollOffset) { canvas.setVerticalScrollOffset(newVerticalScrollOffset); } return Status.OK_STATUS; } /** * Returns the {@link InfiniteCanvas} that is manipulated by this operation. * * @return The {@link InfiniteCanvas} that is manipulated by this operation. */ public InfiniteCanvas getInfiniteCanvas() { return canvas; } /** * Returns the contents transformation that will be applied when undoing * this operation. * * @return The contents transformation that will be applied when undoing * this operation. */ public AffineTransform getInitialContentTransform() { return initialContentTransform; } /** * Returns the viewport height that will be applied when undoing this * operation. * * @return The viewport height that will be applied when undoing this * operation. */ public double getInitialHeight() { return initialHeight; } /** * Returns the horizontal translation that will be applied when undoing this * operation. * * @return The horizontal translation that will be applied when undoing this * operation. */ public double getInitialHorizontalScrollOffset() { return initialHorizontalScrollOffset; } /** * Returns the vertical translation that will be applied when undoing this * operation. * * @return The vertical translation that will be applied when undoing this * operation. */ public double getInitialVerticalScrollOffset() { return initialVerticalScrollOffset; } /** * Returns the viewport width that will be applied when undoing this * operation. * * @return The viewport width that will be applied when undoing this * operation. */ public double getInitialWidth() { return initialWidth; } /** * Returns the contents transformation that will be applied when executing * this operation. * * @return The contents transformation that will be applied when executing * this operation. */ public AffineTransform getNewContentTransform() { return newContentTransform; } /** * Returns the viewport height that will be applied when executing this * operation. * * @return The viewport height that will be applied when executing this * operation. */ public double getNewHeight() { return newHeight; } /** * Returns the horizontal translation that will be applied when executing * this operation. * * @return The horizontal translation that will be applied when executing * this operation. */ public double getNewHorizontalScrollOffset() { return newHorizontalScrollOffset; } /** * Returns the vertical translation that will be applied when executing this * operation. * * @return The vertical translation that will be applied when executing this * operation. */ public double getNewVerticalScrollOffset() { return newVerticalScrollOffset; } /** * Returns the viewport width that will be applied when executing this * operation. * * @return The viewport width that will be applied when executing this * operation. */ public double getNewWidth() { return newWidth; } @Override public boolean isContentRelevant() { return false; } @Override public boolean isNoOp() { return getNewWidth() == getInitialWidth() && getNewHeight() == getInitialHeight() && (getNewContentTransform() == null ? getInitialContentTransform() == null : getNewContentTransform() .equals(getInitialContentTransform())) && getNewHorizontalScrollOffset() == getInitialHorizontalScrollOffset() && getNewVerticalScrollOffset() == getInitialVerticalScrollOffset(); } /** * Stores all relevant viewport values in fields, so that they can be * restored later. * * @param canvas * The {@link InfiniteCanvas} from which the values are read. */ protected void readViewport(InfiniteCanvas canvas) { this.canvas = canvas; initialWidth = canvas.getWidth(); initialHeight = canvas.getHeight(); initialContentTransform = FX2Geometry .toAffineTransform(canvas.getContentTransform()); initialHorizontalScrollOffset = canvas.getHorizontalScrollOffset(); initialVerticalScrollOffset = canvas.getVerticalScrollOffset(); // use old values for new values per default newWidth = initialWidth; newHeight = initialHeight; newContentTransform = initialContentTransform.getCopy(); newHorizontalScrollOffset = initialHorizontalScrollOffset; newVerticalScrollOffset = initialVerticalScrollOffset; } @Override public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return execute(monitor, info); } /** * Sets the initial content transform before applying the new value. * * @param initialContentTransform * The initialContentTransform to set. */ public void setInitialContentTransform( AffineTransform initialContentTransform) { this.initialContentTransform = initialContentTransform; } /** * Sets the initial height before applying the new value. * * @param initialHeight * The initialHeight to set. */ public void setInitialHeight(double initialHeight) { this.initialHeight = initialHeight; } /** * Sets the initial horizontal scroll offset before applying the new value. * * @param initialHorizontalScrollOffset * The initialHorizontalScrollOffset to set. */ public void setInitialHorizontalScrollOffset( double initialHorizontalScrollOffset) { this.initialHorizontalScrollOffset = initialHorizontalScrollOffset; } /** * Sets the initial vertical scroll offset before applying the new value. * * @param initialVerticalScrollOffset * The initialVerticalScrollOffset to set. */ public void setInitialVerticalScrollOffset( double initialVerticalScrollOffset) { this.initialVerticalScrollOffset = initialVerticalScrollOffset; } /** * Sets the initial width before applying the new value. * * @param initialWidth * The initialWidth to set. */ public void setInitialWidth(double initialWidth) { this.initialWidth = initialWidth; } /** * Sets the contents transformation that will be applied when executing this * operation to the given value. * * @param newContentTransform * The contents transformation to apply when executing this * operation. */ public void setNewContentTransform(AffineTransform newContentTransform) { this.newContentTransform = newContentTransform; } /** * Sets the viewport height that will be applied when executing this * operation to the given value. * * @param newHeight * The viewport height to apply when executing this operation. */ public void setNewHeight(double newHeight) { this.newHeight = newHeight; } /** * Sets the horizontal translation that will be applied when executing this * operation to the given value. * * @param newHorizontalScrollOffset * The horizontal translation to apply when executing this * operation. */ public void setNewHorizontalScrollOffset(double newHorizontalScrollOffset) { this.newHorizontalScrollOffset = newHorizontalScrollOffset; } /** * Sets the vertical translation that will be applied when executing this * operation to the given value. * * @param newVerticalScrollOffset * The vertical translation to apply when executing this * operation. */ public void setNewVerticalScrollOffset(double newVerticalScrollOffset) { this.newVerticalScrollOffset = newVerticalScrollOffset; } /** * Sets the viewport width that will be applied when executing this * operation to the given value. * * @param newWidth * The viewport width to apply when executing this operation. */ public void setNewWidth(double newWidth) { this.newWidth = newWidth; } @Override public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if (canvas.getPrefWidth() != initialWidth) { canvas.setPrefWidth(initialWidth); } if (canvas.getPrefHeight() != initialHeight) { canvas.setPrefHeight(initialHeight); } Affine initialContentAffine = Geometry2FX .toFXAffine(initialContentTransform); if (!canvas.getContentTransform().equals(initialContentAffine)) { canvas.setContentTransform(initialContentAffine); } if (canvas .getHorizontalScrollOffset() != initialHorizontalScrollOffset) { canvas.setHorizontalScrollOffset(initialHorizontalScrollOffset); } if (canvas.getVerticalScrollOffset() != initialVerticalScrollOffset) { canvas.setVerticalScrollOffset(initialVerticalScrollOffset); } return Status.OK_STATUS; } }