/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.gef.editparts; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Viewport; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.EditPart; import org.eclipse.gef.ExposeHelper; import org.eclipse.gef.GraphicalEditPart; /** * An implementation of <code>ExposeHelper</code> for use with editparts using a * <code>Viewport</code>. * * @author hudsonr * @since 2.0 */ public class ViewportExposeHelper extends ViewportHelper implements ExposeHelper { private Insets exposeMargin; private int minimumFrameCount = 3; private int maximumFrameCount = 8; /** * Constructs a new ViewportExposeHelper on the specified GraphicalEditPart. * The GraphicalEditPart must have a <code>Viewport</code> somewhere between * its <i>contentsPane</i> and its <i>figure</i> inclusively. * * @param owner * the GraphicalEditPart that owns the Viewport */ public ViewportExposeHelper(GraphicalEditPart owner) { super(owner); } /** * Exposes the descendant EditPart by smoothly scrolling the * <code>Viewport</code>. The smoothness is determined by the minimum and * maximum frame count, and the overall amount being scrolled. * * @see org.eclipse.gef.ExposeHelper#exposeDescendant(EditPart) */ public void exposeDescendant(EditPart part) { Viewport port = findViewport(owner); if (port == null) return; IFigure target = ((GraphicalEditPart) part).getFigure(); /* * All calculations are done relative to the contents of the viewport. * The expose margin is added in absolute coordinates, and then taken * back to relative viewport coordinates. */ Rectangle exposeRegion = target.getBounds().getCopy(); target.translateToAbsolute(exposeRegion); if (exposeMargin != null) exposeRegion.expand(exposeMargin); port.getContents().translateToRelative(exposeRegion); Point offset = port.getContents().getBounds().getLocation(); // By substracting the offset, the region is now the difference from the // contents origin. exposeRegion.translate(offset.negate()); exposeRegion.translate(port.getHorizontalRangeModel().getMinimum(), port.getVerticalRangeModel().getMinimum()); Dimension viewportSize = port.getClientArea().getSize(); Point topLeft = exposeRegion.getTopLeft(); Point bottomRight = exposeRegion.getBottomRight().translate( viewportSize.getNegated()); Point finalLocation = new Point(); if (viewportSize.width < exposeRegion.width) finalLocation.x = Math.min(bottomRight.x, Math.max(topLeft.x, port.getViewLocation().x)); else finalLocation.x = Math.min(topLeft.x, Math.max(bottomRight.x, port.getViewLocation().x)); if (viewportSize.height < exposeRegion.height) finalLocation.y = Math.min(bottomRight.y, Math.max(topLeft.y, port.getViewLocation().y)); else finalLocation.y = Math.min(topLeft.y, Math.max(bottomRight.y, port.getViewLocation().y)); Point startLocation = port.getViewLocation(); int dx = finalLocation.x - startLocation.x; int dy = finalLocation.y - startLocation.y; int frames = (Math.abs(dx) + Math.abs(dy)) / 15; frames = Math.max(frames, getMinimumFrameCount()); frames = Math.min(frames, getMaximumFrameCount()); int stepX = Math.min((dx / frames), (viewportSize.width / 3)); int stepY = Math.min((dy / frames), (viewportSize.height / 3)); for (int i = 1; i < frames; i++) { port.setViewLocation(startLocation.x + stepX * i, startLocation.y + stepY * i); port.getUpdateManager().performUpdate(); } port.setViewLocation(finalLocation); } /** * Returns the maximumFrameCount. * * @return int */ public int getMaximumFrameCount() { return maximumFrameCount; } /** * Returns the minimumFrameCount. * * @return int */ public int getMinimumFrameCount() { return minimumFrameCount; } /** * Sets the amount of margin to be left around the descendant being exposed. * There is no margin by default. * * @param margin * the margin in pixels */ public void setMargin(Insets margin) { exposeMargin = margin; } /** * Sets the maximumFrameCount. * * @param maximumFrameCount * The maximumFrameCount to set */ public void setMaximumFrameCount(int maximumFrameCount) { this.maximumFrameCount = maximumFrameCount; } /** * Sets the minimumFrameCount. * * @param minimumFrameCount * The minimumFrameCount to set */ public void setMinimumFrameCount(int minimumFrameCount) { this.minimumFrameCount = minimumFrameCount; if (getMaximumFrameCount() < minimumFrameCount) setMaximumFrameCount(minimumFrameCount); } }