| /********************************************************************* |
| * Copyright (c) 2005, 2019 SAP SE |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * Contributors: |
| * SAP SE - initial API, implementation and documentation |
| * mwenz - Bug 352440 - Fixed deprecation warnings - contributed by Felix Velasco |
| * Bug 336488 - DiagramEditor API |
| * pjpaulin - Bug 352120 - Now uses IDiagramContainerUI interface |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| **********************************************************************/ |
| package org.eclipse.graphiti.ui.internal.editor; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.draw2d.Border; |
| import org.eclipse.draw2d.Figure; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.LightweightSystem; |
| import org.eclipse.draw2d.RangeModel; |
| import org.eclipse.draw2d.ScrollPaneSolver; |
| import org.eclipse.draw2d.UpdateListener; |
| import org.eclipse.draw2d.Viewport; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.graphiti.ui.editor.DiagramBehavior; |
| import org.eclipse.graphiti.ui.internal.parts.DiagramEditPart; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.widgets.Canvas; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| |
| /** |
| * A Canvas that contains {@link Figure Figures}. |
| * <p> |
| * Note: Only one of the styles RIGHT_TO_LEFT, LEFT_TO_RIGHT may be specified. |
| * </p> |
| * |
| * @noinstantiate This class is not intended to be instantiated by clients. |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class GFFigureCanvas extends Canvas implements IAdaptable { |
| |
| /** |
| * Never show scrollbar. |
| */ |
| public static int NEVER = 0; |
| |
| /** |
| * Automatically show scrollbar when needed. |
| */ |
| public static int AUTOMATIC = 1; |
| |
| /** |
| * Always show scrollbar. |
| */ |
| public static int ALWAYS = 2; |
| |
| private int vBarVisibility = AUTOMATIC; |
| |
| private int hBarVisibility = AUTOMATIC; |
| |
| private Viewport viewport; |
| |
| private Font font; |
| |
| private int hBarOffset; |
| |
| private int vBarOffset; |
| |
| private final Pixel bottomRightCorner = new Pixel(); |
| |
| private final Pixel topLeftCorner = new Pixel(); |
| |
| private boolean doScroll = true; |
| |
| private final GFUpdateListener gfUpdateListener = new GFUpdateListener(); |
| |
| private DiagramBehavior diagramBehavior = null; |
| |
| private boolean init = true; |
| |
| private final PropertyChangeListener horizontalChangeListener = new PropertyChangeListener() { |
| |
| double OldZoomlevel = 1D; |
| |
| public void propertyChange(PropertyChangeEvent event) { |
| |
| /* |
| * Check whether the viewport is larger than the diagram (might |
| * happen after resizing the viewport window). The symptom would be |
| * disappearing scrollbars... |
| */ |
| Rectangle diagramBounds = getDiagramBoundsFromCornerPixels(); |
| Rectangle clientArea = new Rectangle(getClientArea()); |
| int diff = diagramBounds.width - clientArea.width; |
| double zoomLevel = getZoomLevel(); |
| if (zoomLevel != OldZoomlevel || diff <= 0) { |
| /* move corner pixel */ |
| // <sw 120109> improve scroll behavior at zoom levels < 1 |
| bottomRightCorner.remove(); |
| Rectangle minimalDiagram = getDiagramBoundsFromEditPartChildren(); // minimal rectangle containing all shapes on the canvas |
| int newX = minimalDiagram.right(); |
| if (newX * zoomLevel <= clientArea.right()) { |
| newX = (int) (clientArea.right() / zoomLevel); |
| } |
| // </sw 120109> |
| bottomRightCorner.replace(newX, bottomRightCorner.getBounds().y); |
| OldZoomlevel = zoomLevel; |
| } |
| |
| RangeModel model = getViewport().getHorizontalRangeModel(); |
| hBarOffset = Math.max(0, -model.getMinimum()); |
| getHorizontalBar().setValues(model.getValue() + hBarOffset, model.getMinimum() + hBarOffset, model.getMaximum() + hBarOffset, |
| model.getExtent(), Math.max(1, model.getExtent() / 20), Math.max(1, model.getExtent() * 3 / 4)); |
| } |
| }; |
| |
| private final PropertyChangeListener verticalChangeListener = new PropertyChangeListener() { |
| |
| double OldZoomlevel = 1D; |
| |
| public void propertyChange(PropertyChangeEvent event) { |
| |
| /* |
| * Check whether the viewport is larger than the diagram (might |
| * happen after resizing the viewport window). The symptom would be |
| * disappearing scrollbars... |
| */ |
| Rectangle diagramBounds = getDiagramBoundsFromCornerPixels(); |
| Rectangle clientArea = new Rectangle(getClientArea()); |
| int diff = diagramBounds.height - clientArea.height; |
| double zoomLevel = getZoomLevel(); |
| if (zoomLevel != OldZoomlevel || diff <= 0) { |
| /* move corner pixel */ |
| // <sw 120109> improve scroll behavior at zoom levels < 1 |
| bottomRightCorner.remove(); |
| Rectangle minimalDiagram = getDiagramBoundsFromEditPartChildren(); // minimal rectangle containing all shapes on the canvas |
| int newY = minimalDiagram.bottom(); |
| if (newY * zoomLevel <= clientArea.bottom()) { |
| newY = (int) (clientArea.bottom() / zoomLevel); |
| } |
| // </sw 120109> |
| bottomRightCorner.replace(bottomRightCorner.getBounds().x, newY); |
| OldZoomlevel = zoomLevel; |
| } |
| |
| RangeModel model = getViewport().getVerticalRangeModel(); |
| vBarOffset = Math.max(0, -model.getMinimum()); |
| getVerticalBar().setValues(model.getValue() + vBarOffset, model.getMinimum() + vBarOffset, model.getMaximum() + vBarOffset, |
| model.getExtent(), Math.max(1, model.getExtent() / 20), Math.max(1, model.getExtent() * 3 / 4)); |
| } |
| }; |
| |
| private final LightweightSystem lws; |
| |
| /** |
| * Creates a new FigureCanvas with the given parent. |
| * |
| * @param parent |
| * the parent |
| * @param diagramEditor |
| * the diagram editor |
| */ |
| public GFFigureCanvas(Composite parent, DiagramBehavior diagramBehavior) { |
| this(parent, SWT.DOUBLE_BUFFERED, new LightweightSystem(), diagramBehavior); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * look at class javadoc for valid styles |
| * @param diagramEditor |
| * the diagram editor |
| * @since 3.1 |
| */ |
| public GFFigureCanvas(Composite parent, int style, DiagramBehavior diagramBehavior) { |
| this(parent, style, new LightweightSystem(), diagramBehavior); |
| } |
| |
| /** |
| * Constructs a new FigureCanvas with the given parent and |
| * LightweightSystem. |
| * |
| * @param parent |
| * the parent |
| * @param lws |
| * the LightweightSystem |
| * @param diagramEditor |
| * the diagram editor |
| */ |
| public GFFigureCanvas(Composite parent, LightweightSystem lws, DiagramBehavior diagramBehavior) { |
| this(parent, SWT.DOUBLE_BUFFERED, lws, diagramBehavior); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * look at class javadoc for valid styles |
| * @param lws |
| * the lightweight system |
| * @param diagramEditor |
| * the diagram editor |
| * @since 3.1 |
| */ |
| public GFFigureCanvas(Composite parent, int style, LightweightSystem lws, DiagramBehavior diagramBehavior) { |
| super(parent, checkStyle(style | SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL)); |
| getHorizontalBar().setVisible(false); |
| getVerticalBar().setVisible(false); |
| this.lws = lws; |
| this.diagramBehavior = diagramBehavior; |
| lws.setControl(this); |
| hook(); |
| } |
| |
| private static int checkStyle(int style) { |
| int validStyles = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT | SWT.V_SCROLL | SWT.H_SCROLL | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE |
| | SWT.DOUBLE_BUFFERED; |
| if ((style & ~validStyles) != 0) |
| throw new IllegalArgumentException("Invalid style being set on FigureCanvas"); //$NON-NLS-1$ |
| return style; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean) |
| */ |
| @Override |
| public org.eclipse.swt.graphics.Point computeSize(int wHint, int hHint, boolean changed) { |
| // TODO not accounting for scrollbars and trim |
| Dimension size = getLightweightSystem().getRootFigure().getPreferredSize(wHint, hHint); |
| size.union(new Dimension(wHint, hHint)); |
| return new org.eclipse.swt.graphics.Point(size.width, size.height); |
| } |
| |
| /** |
| * Gets the contents. |
| * |
| * @return the contents of the {@link Viewport}. |
| */ |
| public IFigure getContents() { |
| return getViewport().getContents(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.swt.widgets.Control#getFont() |
| */ |
| @Override |
| public Font getFont() { |
| if (font == null) |
| font = super.getFont(); |
| return font; |
| } |
| |
| /** |
| * Gets the horizontal scroll bar visibility. |
| * |
| * @return the horizontal scrollbar visibility. |
| */ |
| public int getHorizontalScrollBarVisibility() { |
| return hBarVisibility; |
| } |
| |
| /** |
| * Gets the lightweight system. |
| * |
| * @return the LightweightSystem |
| */ |
| public LightweightSystem getLightweightSystem() { |
| return lws; |
| } |
| |
| /** |
| * Gets the vertical scroll bar visibility. |
| * |
| * @return the vertical scrollbar visibility. |
| */ |
| public int getVerticalScrollBarVisibility() { |
| return vBarVisibility; |
| } |
| |
| /** |
| * Returns the Viewport. If it's <code>null</code>, a new one is created. |
| * |
| * @return the viewport |
| */ |
| public Viewport getViewport() { |
| if (viewport == null) |
| setViewport(new Viewport(true)); |
| return viewport; |
| } |
| |
| /** |
| * Adds listeners for scrolling. |
| */ |
| private void hook() { |
| getLightweightSystem().getUpdateManager().addUpdateListener(gfUpdateListener); |
| |
| getHorizontalBar().addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent event) { |
| scrollToX(event, getHorizontalBar().getSelection() - hBarOffset); |
| } |
| }); |
| |
| getVerticalBar().addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent event) { |
| scrollToY(event, getVerticalBar().getSelection() - vBarOffset); |
| } |
| }); |
| } |
| |
| private void hookViewport() { |
| getViewport().getHorizontalRangeModel().addPropertyChangeListener(horizontalChangeListener); |
| getViewport().getVerticalRangeModel().addPropertyChangeListener(verticalChangeListener); |
| } |
| |
| private void unhookViewport() { |
| getViewport().getHorizontalRangeModel().removePropertyChangeListener(horizontalChangeListener); |
| getViewport().getVerticalRangeModel().removePropertyChangeListener(verticalChangeListener); |
| } |
| |
| private void layoutViewport() { |
| /* |
| * Add two invisible pixels to the diagram in order to force the |
| * visibility of the scroll bars |
| */ |
| if (init) { |
| setCornerPixels(); |
| init = false; |
| } |
| |
| ScrollPaneSolver.Result result; |
| result = ScrollPaneSolver.solve(new Rectangle(getBounds()).setLocation(0, 0), getViewport(), getHorizontalScrollBarVisibility(), |
| getVerticalScrollBarVisibility(), computeTrim(0, 0, 0, 0).width, computeTrim(0, 0, 0, 0).height); |
| // sw: cannot activate next line (as in class FigureCanvas) since the |
| // method not visible |
| // sw getLightweightSystem().setIgnoreResize(true); |
| try { |
| if (getHorizontalBar().getVisible() != result.showH) |
| getHorizontalBar().setVisible(result.showH); |
| if (getVerticalBar().getVisible() != result.showV) |
| getVerticalBar().setVisible(result.showV); |
| Rectangle r = new Rectangle(getClientArea()); |
| r.setLocation(0, 0); |
| getLightweightSystem().getRootFigure().setBounds(r); |
| } finally { |
| // sw: cannot activate next line (as in class FigureCanvas) since |
| // the method not visible |
| // sw getLightweightSystem().setIgnoreResize(false); |
| } |
| } |
| |
| private Rectangle getDiagramBounds() { |
| Rectangle clientArea = new Rectangle(getClientArea()); |
| Rectangle bounds = getDiagramBoundsFromDiagramEditPart().getCopy(); |
| bounds.union(0, 0, clientArea.width, clientArea.height); |
| // ((FreeformFigure) getContents()).setFreeformBounds(bounds); |
| return bounds; |
| } |
| |
| /** |
| * Scrolls the contents horizontally so that they are offset by |
| * <code>hOffset</code>. |
| * |
| * @param hOffset |
| * the new horizontal offset |
| * @param event |
| * the event |
| */ |
| public void scrollToX(SelectionEvent event, int hOffset) { |
| |
| if (event == null) { |
| return; |
| } |
| |
| hOffset = verifyScrollBarOffset(getViewport().getHorizontalRangeModel(), hOffset); |
| int hOffsetOld = getViewport().getViewLocation().x; |
| |
| /* scrolling within the current size of the diagram in either direction */ |
| int dx = -hOffset + hOffsetOld; |
| |
| /* get zoom factor */ |
| double zoomLevel = getZoomLevel(); |
| |
| if (dx != 0) { // slider is not yet at left or right boundary |
| /* scroll with arrow buttons? regain space */ |
| if (event.detail == SWT.ARROW_UP || event.detail == SWT.ARROW_DOWN) { |
| regainHorizontalSpace(); |
| } |
| } else { |
| |
| if (event.detail == SWT.ARROW_UP) { // scrolling to the left |
| |
| /* scroll value */ |
| // <sw 120109> extend canvas only into positive region (as preferred by GEF) |
| // dx = -getHorizontalBar().getIncrement(); |
| dx = 0; |
| // </sw 120109> |
| /* |
| * compute diagram size from figures in DiagramEditPart |
| * (including corner pixels) |
| */ |
| Rectangle diagramBounds = getDiagramBounds(); |
| /* new scroll bar position has still to be at left boundary */ |
| hOffset = diagramBounds.x + dx; |
| /* |
| * move top left corner to the left; keep its current y-position |
| */ |
| // topLeftCorner.replace(hOffset + (int) (topLeftCorner.getSizeInPixel() / zoomLevel), topLeftCorner.getBounds().y); |
| topLeftCorner.replace(hOffset, topLeftCorner.getBounds().y); |
| /* adjust view port parameters */ |
| getViewport().getHorizontalRangeModel().setAll((int) (hOffset * zoomLevel), |
| (int) ((diagramBounds.width - Math.abs(dx)) * zoomLevel), bottomRightCorner.getBounds().x); |
| /* avoid double repaint of diagram later */ |
| doScroll = false; |
| |
| } |
| |
| else if (event.detail == SWT.ARROW_DOWN) { // scrolling to the right |
| |
| /* scroll value */ |
| dx = getHorizontalBar().getIncrement(); |
| /* |
| * compute diagram size from figures in DiagramEditPart |
| * (including corner pixels) |
| */ |
| Rectangle diagramBounds = getDiagramBounds(); |
| /* new scroll bar position has still to be at right boundary */ |
| hOffset = diagramBounds.right() + dx; |
| /* |
| * move bottom right corner to the right; keep its current |
| * y-position |
| */ |
| bottomRightCorner.replace(hOffset, bottomRightCorner.getBounds().y); |
| /* adjust view port parameters */ |
| getViewport().getHorizontalRangeModel().setAll((int) (hOffset * zoomLevel), |
| (int) ((diagramBounds.width - Math.abs(dx)) * zoomLevel), bottomRightCorner.getBounds().x); |
| /* avoid double repaint of diagram later */ |
| doScroll = false; |
| |
| } else { |
| /* scroll with slider */ |
| return; |
| } |
| } |
| |
| Rectangle clientArea = getViewport().getBounds().getShrinked(getViewport().getInsets()); |
| Rectangle blit = clientArea.getResized(-Math.abs(dx), 0); |
| Rectangle expose = clientArea.getCopy(); |
| Point dest = clientArea.getTopLeft(); |
| expose.width = Math.abs(dx); |
| if (dx < 0) { // Moving left? |
| blit.translate(-dx, 0); // Move blit area to the right |
| expose.x = dest.x + blit.width; |
| } else |
| // Moving right |
| dest.x += dx; // Move expose area to the right |
| |
| // fix for bug 41111 |
| Control[] children = getChildren(); |
| boolean[] manualMove = new boolean[children.length]; |
| for (int i = 0; i < children.length; i++) { |
| org.eclipse.swt.graphics.Rectangle bounds = children[i].getBounds(); |
| manualMove[i] = blit.width <= 0 || bounds.x > blit.x + blit.width || bounds.y > blit.y + blit.height |
| || bounds.x + bounds.width < blit.x || bounds.y + bounds.height < blit.y; |
| } |
| if (doScroll) { |
| scroll(dest.x, dest.y, blit.x, blit.y, blit.width, blit.height, true); |
| } |
| doScroll = true; |
| for (int i = 0; i < children.length; i++) { |
| org.eclipse.swt.graphics.Rectangle bounds = children[i].getBounds(); |
| if (manualMove[i]) |
| children[i].setBounds(bounds.x + dx, bounds.y, bounds.width, bounds.height); |
| } |
| |
| getViewport().setIgnoreScroll(true); |
| getViewport().setHorizontalLocation(hOffset); |
| getViewport().setIgnoreScroll(false); |
| |
| redraw(expose.x, expose.y, expose.width, expose.height, true); |
| |
| } |
| |
| /** |
| * Scrolls the contents vertically so that they are offset by |
| * <code>vOffset</code>. |
| * |
| * @param vOffset |
| * the new vertical offset |
| * @param event |
| * the event |
| */ |
| public void scrollToY(SelectionEvent event, int vOffset) { |
| |
| if (event == null) { |
| return; |
| } |
| |
| vOffset = verifyScrollBarOffset(getViewport().getVerticalRangeModel(), vOffset); |
| int vOffsetOld = getViewport().getViewLocation().y; |
| |
| /* scrolling within the current size of the diagram in either direction */ |
| int dy = -vOffset + vOffsetOld; |
| |
| /* get zoom factor */ |
| double zoomLevel = getZoomLevel(); |
| |
| if (dy != 0) { // slider is not yet at top or bottom boundary |
| /* scroll with arrow buttons? regain space */ |
| if (event.detail == SWT.ARROW_UP || event.detail == SWT.ARROW_DOWN) { |
| regainVerticalSpace(); |
| } |
| } else { |
| if (event.detail == SWT.ARROW_UP) { // scrolling to the top |
| |
| /* scroll value */ |
| // <sw 120109> extend canvas only into positive region (as preferred by GEF) |
| // dy = -getVerticalBar().getIncrement(); |
| dy = 0; |
| // </sw 120109> |
| /* |
| * compute diagram size from figures in DiagramEditPart |
| * (including corner pixels) |
| */ |
| Rectangle diagramBounds = getDiagramBounds(); |
| /* new scroll bar position has still to be at top boundary */ |
| vOffset = diagramBounds.y + dy; |
| /* move top left corner up; keep its current x-position */ |
| // topLeftCorner.replace(topLeftCorner.getBounds().x, vOffset + (int) (topLeftCorner.getSizeInPixel() / zoomLevel)); |
| topLeftCorner.replace(topLeftCorner.getBounds().x, vOffset); |
| /* adjust view port parameters */ |
| getViewport().getVerticalRangeModel().setAll((int) (vOffset * zoomLevel), |
| (int) ((diagramBounds.height - Math.abs(dy)) * zoomLevel), bottomRightCorner.getBounds().y); |
| /* avoid double repaint of diagram later */ |
| doScroll = false; |
| |
| } else if (event.detail == SWT.ARROW_DOWN) { // scrolling to the bottom |
| |
| /* scroll value */ |
| dy = getVerticalBar().getIncrement(); |
| /* |
| * compute diagram size from figures in DiagramEditPart |
| * (including corner pixels) |
| */ |
| Rectangle diagramBounds = getDiagramBounds(); |
| /* |
| * new scroll bar position has still to be at bottom boundary |
| */ |
| vOffset = diagramBounds.bottom() + dy; |
| /* |
| * move bottom right corner down; keep its current x-position |
| */ |
| bottomRightCorner.replace(bottomRightCorner.getBounds().x, vOffset); |
| /* adjust view port parameters */ |
| getViewport().getVerticalRangeModel().setAll((int) (vOffset * zoomLevel), |
| (int) ((diagramBounds.height - Math.abs(dy)) * zoomLevel), bottomRightCorner.getBounds().y); |
| /* avoid double repaint of diagram later */ |
| doScroll = false; |
| |
| } else { |
| /* scroll with slider */ |
| return; |
| } |
| } |
| |
| Rectangle clientArea = getViewport().getBounds().getShrinked(getViewport().getInsets()); |
| Rectangle blit = clientArea.getResized(0, -Math.abs(dy)); |
| Rectangle expose = clientArea.getCopy(); |
| Point dest = clientArea.getTopLeft(); |
| expose.height = Math.abs(dy); |
| if (dy < 0) { // Moving up? |
| blit.translate(0, -dy); // Move blit area down |
| expose.y = dest.y + blit.height; // Move expose area down |
| } else |
| // Moving down |
| dest.y += dy; |
| |
| // fix for bug 41111 |
| Control[] children = getChildren(); |
| boolean[] manualMove = new boolean[children.length]; |
| for (int i = 0; i < children.length; i++) { |
| org.eclipse.swt.graphics.Rectangle bounds = children[i].getBounds(); |
| manualMove[i] = blit.height <= 0 || bounds.x > blit.x + blit.width || bounds.y > blit.y + blit.height |
| || bounds.x + bounds.width < blit.x || bounds.y + bounds.height < blit.y; |
| } |
| if (doScroll) |
| scroll(dest.x, dest.y, blit.x, blit.y, blit.width, blit.height, true); |
| doScroll = true; |
| for (int i = 0; i < children.length; i++) { |
| org.eclipse.swt.graphics.Rectangle bounds = children[i].getBounds(); |
| if (manualMove[i]) |
| children[i].setBounds(bounds.x, bounds.y + dy, bounds.width, bounds.height); |
| } |
| |
| getViewport().setIgnoreScroll(true); |
| getViewport().setVerticalLocation(vOffset); |
| getViewport().setIgnoreScroll(false); |
| redraw(expose.x, expose.y, expose.width, expose.height, true); |
| } |
| |
| /** |
| * Regain space. |
| */ |
| public void regainSpace() { |
| bottomRightCorner.remove(); |
| topLeftCorner.remove(); |
| setCornerPixels(); |
| } |
| |
| /** |
| * Regain horizontal space. |
| */ |
| public void regainHorizontalSpace() { |
| /* save current corner pixel coordinates */ |
| final int topLeftY = topLeftCorner.getBounds().y; |
| final int bottomRightY = bottomRightCorner.getBounds().y; |
| |
| /* remove corner pixels to calculate current size of diagram contents */ |
| bottomRightCorner.remove(); |
| topLeftCorner.remove(); |
| |
| /* |
| * diagram contents size must not be smaller than the visible canvas |
| * area |
| */ |
| Rectangle minimalDiagram = getDiagramBoundsFromEditPartChildren(); // minimal rectangle containing all shapes on the canvas |
| final Rectangle clientArea = new Rectangle(getClientArea()); |
| final double zoomLevel = getZoomLevel(); |
| // <sw 120109> improve scroll behavior at zoom levels < 1. |
| int newBottomRightX = minimalDiagram.right(); |
| int newTopLeftX = minimalDiagram.x; |
| if (newBottomRightX * zoomLevel <= clientArea.right()) { |
| newBottomRightX = (int) (clientArea.right() / zoomLevel); |
| newTopLeftX = clientArea.x; |
| } |
| // diagramBounds.union(clientArea); |
| // </sw 120109> |
| |
| bottomRightCorner.set(newBottomRightX, bottomRightY); |
| topLeftCorner.set(newTopLeftX, topLeftY); |
| } |
| |
| /** |
| * Regain vertical space. |
| */ |
| public void regainVerticalSpace() { |
| /* save current corner pixel coordinates */ |
| final int topLeftX = topLeftCorner.getBounds().x; |
| final int bottomRightX = bottomRightCorner.getBounds().x; |
| |
| /* remove corner pixels to calculate current size of diagram contents */ |
| bottomRightCorner.remove(); |
| topLeftCorner.remove(); |
| |
| /* |
| * diagram contents size must not be smaller than the visible canvas |
| * area |
| */ |
| Rectangle minimalDiagram = getDiagramBoundsFromEditPartChildren(); |
| final Rectangle clientArea = new Rectangle(getClientArea()); |
| final double zoomLevel = getZoomLevel(); |
| // <sw 120109> improve scroll behavior at zoom levels < 1. |
| int newBottomRightY = minimalDiagram.bottom(); |
| int newTopLeftY = minimalDiagram.y; |
| if (newBottomRightY * zoomLevel <= clientArea.bottom()) { |
| newBottomRightY = (int) (clientArea.bottom() / zoomLevel); |
| newTopLeftY = clientArea.y; |
| } |
| // diagramBounds.union(clientArea); |
| // </sw 120109> |
| |
| bottomRightCorner.set(bottomRightX, newBottomRightY); |
| topLeftCorner.set(topLeftX, newTopLeftY); |
| } |
| |
| private double getZoomLevel() { |
| return diagramBehavior.getZoomLevel(); |
| } |
| |
| private Rectangle getDiagramBoundsFromDiagramEditPart() { |
| EditPart ep = diagramBehavior.getContentEditPart(); |
| if (ep instanceof DiagramEditPart && ((DiagramEditPart) ep).getFigure().getChildren().size() > 0) { |
| return ((DiagramEditPart) ep).getFigure().getBounds(); |
| } else { |
| return new Rectangle(getClientArea()); |
| } |
| } |
| |
| public Rectangle getDiagramBoundsFromEditPartChildren() { |
| EditPart ep = diagramBehavior.getContentEditPart(); |
| if (!(ep instanceof DiagramEditPart) || ((DiagramEditPart) ep).getFigure().getChildren().size() == 0) { |
| return new Rectangle(); |
| } |
| DiagramEditPart diagramEditPart = ((DiagramEditPart) ep); |
| @SuppressWarnings("unchecked") |
| List<IFigure> children = diagramEditPart.getFigure().getChildren(); |
| if (children.size() == 0) |
| return null; |
| |
| int minX = Integer.MAX_VALUE; |
| int minY = Integer.MAX_VALUE; |
| int maxX = Integer.MIN_VALUE; |
| int maxY = Integer.MIN_VALUE; |
| |
| for (IFigure child : children) { |
| int x1 = child.getBounds().x; |
| if (x1 < minX) { |
| minX = x1; |
| } |
| int y1 = child.getBounds().y; |
| if (y1 < minY) { |
| minY = y1; |
| } |
| int x2 = x1 + child.getBounds().width; |
| if (x2 > maxX) { |
| maxX = x2; |
| } |
| int y2 = y1 + child.getBounds().height; |
| if (y2 > maxY) { |
| maxY = y2; |
| } |
| } |
| return new Rectangle(minX, minY, maxX - minX, maxY - minY); |
| } |
| |
| private Rectangle getDiagramBoundsFromCornerPixels() { |
| Rectangle rectangle = topLeftCorner.getBounds().getCopy(); |
| return rectangle.union(bottomRightCorner.getBounds()); |
| } |
| |
| /** |
| * Scroll smooth to. |
| * |
| * @param x |
| * the x |
| * @param y |
| * the y |
| */ |
| public void scrollSmoothTo(int x, int y) { |
| // Ensure newHOffset and newVOffset are within the appropriate ranges |
| x = verifyScrollBarOffset(getViewport().getHorizontalRangeModel(), x); |
| y = verifyScrollBarOffset(getViewport().getVerticalRangeModel(), y); |
| |
| int oldX = getViewport().getViewLocation().x; |
| int oldY = getViewport().getViewLocation().y; |
| int dx = x - oldX; |
| int dy = y - oldY; |
| |
| if (dx == 0 && dy == 0) |
| return; // Nothing to do. |
| |
| Dimension viewingArea = getViewport().getClientArea().getSize(); |
| |
| int minFrames = 3; |
| int maxFrames = 6; |
| if (dx == 0 || dy == 0) { |
| minFrames = 6; |
| maxFrames = 13; |
| } |
| int frames = (Math.abs(dx) + Math.abs(dy)) / 15; |
| frames = Math.max(frames, minFrames); |
| frames = Math.min(frames, maxFrames); |
| |
| int stepX = Math.min((dx / frames), (viewingArea.width / 3)); |
| int stepY = Math.min((dy / frames), (viewingArea.height / 3)); |
| |
| for (int i = 1; i < frames; i++) { |
| scrollTo(oldX + i * stepX, oldY + i * stepY); |
| getViewport().getUpdateManager().performUpdate(); |
| } |
| scrollTo(x, y); |
| } |
| |
| /** |
| * Scroll to. |
| * |
| * @param x |
| * the x |
| * @param y |
| * the y |
| */ |
| public void scrollTo(int x, int y) { |
| x = verifyScrollBarOffset(getViewport().getHorizontalRangeModel(), x); |
| y = verifyScrollBarOffset(getViewport().getVerticalRangeModel(), y); |
| getViewport().setViewLocation(x, y); |
| } |
| |
| /** |
| * Sets the given border on the LightweightSystem's root figure. |
| * |
| * @param border |
| * The new border |
| */ |
| public void setBorder(Border border) { |
| getLightweightSystem().getRootFigure().setBorder(border); |
| } |
| |
| /** |
| * Sets the contents of the {@link Viewport}. |
| * |
| * @param figure |
| * the new contents |
| */ |
| public void setContents(IFigure figure) { |
| getViewport().setContents(figure); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.swt.widgets.Canvas#setFont(org.eclipse.swt.graphics.Font) |
| */ |
| @Override |
| public void setFont(Font font) { |
| this.font = font; |
| super.setFont(font); |
| } |
| |
| /** |
| * Sets the horizontal scrollbar visibility. Possible values are |
| * {@link #AUTOMATIC}, {@link #ALWAYS}, and {@link #NEVER}. |
| * |
| * @param v |
| * the new visibility |
| */ |
| public void setHorizontalScrollBarVisibility(int v) { |
| hBarVisibility = v; |
| } |
| |
| /** |
| * Sets both the horizontal and vertical scrollbar visibility to the given |
| * value. Possible values are {@link #AUTOMATIC}, {@link #ALWAYS}, and |
| * {@link #NEVER}. |
| * |
| * @param both |
| * the new visibility |
| */ |
| public void setScrollBarVisibility(int both) { |
| setHorizontalScrollBarVisibility(both); |
| setVerticalScrollBarVisibility(both); |
| } |
| |
| /** |
| * Sets the vertical scrollbar visibility. Possible values are |
| * {@link #AUTOMATIC}, {@link #ALWAYS}, and {@link #NEVER}. |
| * |
| * @param v |
| * the new visibility |
| */ |
| public void setVerticalScrollBarVisibility(int v) { |
| vBarVisibility = v; |
| } |
| |
| /** |
| * Sets the Viewport. The given Viewport must use "fake" scrolling. That is, |
| * it must be constructed using <code>new Viewport(true)</code>. |
| * |
| * @param vp |
| * the new viewport |
| */ |
| public void setViewport(Viewport vp) { |
| if (viewport != null) |
| unhookViewport(); |
| viewport = vp; |
| lws.setContents(viewport); |
| hookViewport(); |
| } |
| |
| private int verifyScrollBarOffset(RangeModel model, int value) { |
| value = Math.max(model.getMinimum(), value); |
| return Math.min(model.getMaximum() - model.getExtent(), value); |
| } |
| |
| public void removeCornerPixels() { |
| if (bottomRightCorner != null) { |
| bottomRightCorner.remove(); |
| } |
| if (topLeftCorner != null) { |
| topLeftCorner.remove(); |
| } |
| } |
| |
| public void setCornerPixels() { |
| Rectangle minimalDiagram = getDiagramBoundsFromEditPartChildren(); // minimal rectangle containing all shapes on the canvas |
| final Rectangle clientArea = new Rectangle(getClientArea()); // rectangle of displayed canvas area |
| minimalDiagram.union(clientArea); // in case the area of all shapes is smaller than the displayed canvas area |
| bottomRightCorner.set((minimalDiagram.right()), (minimalDiagram.bottom())); |
| topLeftCorner.set(minimalDiagram.x, minimalDiagram.y); |
| } |
| |
| /** |
| * The Class Pixel. |
| */ |
| class Pixel extends Figure { |
| /* |
| * this size seems to solve the rendering problems described in CSN |
| * 0120031469 0003011765 2008 |
| */ |
| private static final int SIZE = 5; |
| |
| /** |
| * Instantiates a new pixel. |
| */ |
| Pixel() { |
| super(); |
| } |
| |
| /** |
| * Adds the. |
| * |
| * @param newX |
| * the new x |
| * @param newY |
| * the new y |
| */ |
| protected void set(int newX, int newY) { |
| this.setBounds(new Rectangle(newX, newY, SIZE, SIZE)); |
| this.setOpaque(false); |
| /* debug settings --> */ |
| // this.setBackgroundColor(ColorConstants.red); |
| // this.setOpaque(true); |
| /* <-- debug settings */ |
| EditPart ep = diagramBehavior.getContentEditPart(); |
| ((DiagramEditPart) ep).getFigure().add(this); |
| } |
| |
| /** |
| * Replace. |
| * |
| * @param newX |
| * the new x |
| * @param newY |
| * the new y |
| */ |
| protected void replace(int newX, int newY) { |
| this.remove(); |
| this.set(newX, newY); |
| } |
| |
| /** |
| * Removes the. |
| */ |
| protected void remove() { |
| EditPart ep = diagramBehavior.getContentEditPart(); |
| IFigure diagram = ((DiagramEditPart) ep).getFigure(); |
| diagram.getChildren().remove(this); |
| } |
| |
| /** |
| * Gets the size in pixel. |
| * |
| * @return the size in pixel |
| */ |
| protected int getSizeInPixel() { |
| return SIZE; |
| } |
| |
| } |
| |
| /** |
| * The listener interface for receiving GFUpdate events. The class that is |
| * interested in processing a GFUpdate event implements this interface, and |
| * the object created with that class is registered with a component using |
| * the component's <code>addGFUpdateListener<code> method. When |
| * the GFUpdate event occurs, that object's appropriate |
| * method is invoked. |
| * |
| * @see GFUpdateEvent |
| */ |
| class GFUpdateListener implements UpdateListener { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.draw2d.UpdateListener#notifyPainting(org.eclipse.draw2d |
| * .geometry.Rectangle, java.util.Map) |
| */ |
| public void notifyPainting(Rectangle damage, @SuppressWarnings("rawtypes") java.util.Map dirtyRegions) { |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.UpdateListener#notifyValidating() |
| */ |
| public void notifyValidating() { |
| if (!isDisposed()) { |
| layoutViewport(); |
| } |
| |
| } |
| |
| } |
| |
| public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { |
| if (LightweightSystem.class == adapter) { |
| return getLightweightSystem(); |
| } |
| return null; |
| } |
| |
| } |