/***************************************************************************** * Copyright (c) 2014-15 CEA LIST, Montages 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: * Michael Golubev (Montages) - Initial API and implementation * *****************************************************************************/ package org.eclipse.gmf.tooling.runtime.linklf; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PrecisionRectangle; import org.eclipse.gef.EditPartViewer; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.SnapToGrid; /** * Utility class to compute active grid specification for given edit part * viewer. * <p/> * Clients may call static methods to compute grid spec once, or may setup * listeners that will automatically update the active spec when it changed * * @since 3.3 */ public class DiagramGridSpec { private final EditPartViewer myViewer; private PrecisionRectangle myRelativeGridSpec; private PrecisionRectangle myAbsoluteGridSpec; private final GridSpecListener myGridListener; public DiagramGridSpec(EditPartViewer viewer) { myViewer = viewer; myGridListener = new GridSpecListener() { @Override public void gridSpecChanged() { myRelativeGridSpec = null; myAbsoluteGridSpec = null; } }; myViewer.addPropertyChangeListener(myGridListener); } public void dispose() { myViewer.removePropertyChangeListener(myGridListener); myRelativeGridSpec = null; myAbsoluteGridSpec = null; } /** * Always returns the same instance to avoid endless creation * * @return active grid specification in absolute coordinates or * <code>null</code> if not enabled */ public PrecisionRectangle getAbsoluteGridSpec() { PrecisionRectangle result = getRelativeGridSpec(); if (result == null) { return null; } if (myAbsoluteGridSpec == null) { myAbsoluteGridSpec = new PrecisionRectangle(); } myAbsoluteGridSpec.setPreciseBounds(result.preciseX(), result.preciseY(), result.preciseWidth(), result.preciseHeight()); GraphicalEditPart diagramEP = (GraphicalEditPart) myViewer .getContents(); diagramEP.getContentPane().translateToAbsolute(myAbsoluteGridSpec); return myAbsoluteGridSpec; } private PrecisionRectangle getRelativeGridSpec() { if (myRelativeGridSpec == null) { myRelativeGridSpec = getRelativeGridSpec(myViewer); } return myRelativeGridSpec; } public EditPartViewer getViewer() { return myViewer; } /** * Computes actual grid specification (origin + single cell width and * height) in the absolute coordinate system. Note, in contrast to * {@link #getRelativeGridSpec(EditPartViewer)} this specification depends * on the active zoom or scroll and can't be cached by clients. * * @param viewer * @return absolute grid specification, or <code>null</code> if grid is not * enabled */ public static PrecisionRectangle getAbsoluteGridSpec(EditPartViewer viewer) { PrecisionRectangle spec = getRelativeGridSpec(viewer); if (spec != null) { GraphicalEditPart diagramEP = (GraphicalEditPart) viewer .getContents(); diagramEP.getContentPane().translateToAbsolute(spec); } return spec; } /** * Computes actual grid specification (origin + single cell width and * height) in the coordinates relative to the diagram content pane. * <p/> * This specification depends only on the grid-relative properties stored in * the {@link EditPartViewer}, so client may cache it and rely on * {@link EditPartViewer#addPropertyChangeListener(PropertyChangeListener)} * * @param viewer * @return grid specification in the coordinate system relative to diagram * content pane, or <code>null</code> if grid is not enabled */ private static PrecisionRectangle getRelativeGridSpec(EditPartViewer viewer) { Boolean enabled = (Boolean) viewer .getProperty(SnapToGrid.PROPERTY_GRID_ENABLED); if (enabled == null || !enabled) { return null; } double gridX = 0; double gridY = 0; Dimension spacing = (Dimension) viewer .getProperty(SnapToGrid.PROPERTY_GRID_SPACING); if (spacing != null) { gridX = spacing.preciseWidth(); gridY = spacing.preciseHeight(); } if (gridX <= 0) { gridX = SnapToGrid.DEFAULT_GRID_SIZE; } if (gridY <= 0) { gridY = SnapToGrid.DEFAULT_GRID_SIZE; } Point origin = (Point) viewer .getProperty(SnapToGrid.PROPERTY_GRID_ORIGIN); PrecisionRectangle result = new PrecisionRectangle(// origin == null ? 0 : origin.preciseX(), origin == null ? 0 : origin.preciseY(), gridX, gridY); return result; } public static abstract class GridSpecListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (SnapToGrid.PROPERTY_GRID_ORIGIN.equals(propertyName) || // SnapToGrid.PROPERTY_GRID_ENABLED.equals(propertyName) || // SnapToGrid.PROPERTY_GRID_SPACING.equals(propertyName)) { gridSpecChanged(); } } public abstract void gridSpecChanged(); }; }