org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper.java

Source

/*******************************************************************************
 * Copyright (c) 2010 THALES GLOBAL SERVICES.
 * 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:
 *    Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
import org.eclipse.gmf.runtime.notation.Bounds;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.IdentityAnchor;
import org.eclipse.gmf.runtime.notation.LayoutConstraint;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
import org.eclipse.sirius.diagram.sequence.business.internal.VerticalPositionFunction;
import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
import org.eclipse.sirius.diagram.sequence.util.Range;
import org.eclipse.sirius.diagram.ui.tools.api.graphical.edit.styles.IBorderItemOffsets;
import org.eclipse.sirius.diagram.ui.tools.api.util.GMFNotationHelper;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

/**
 * Utility class to collect helper methods which deal with GraphicalOrdering but
 * which are not part of its API.
 * 
 * @author pcdavid
 */
public final class SequenceGraphicalHelper {
    private SequenceGraphicalHelper() {
        // Prevent instantiation.
    }

    /**
     * Finds and returns the EventEnd which corresponds to the first event
     * graphically above the specified Y coordinate in a diagram.
     * 
     * @param diagram
     *            the diagram.
     * @param y
     *            the Y coordinate (in logical space)
     * @return the EventEnd which corresponds to the first event above Y.
     */
    public static EventEnd getEndBefore(SequenceDDiagram diagram, int y) {
        VerticalPositionFunction vpf = new VerticalPositionFunction(diagram);
        for (EventEnd end : Lists.reverse(diagram.getGraphicalOrdering().getEventEnds())) {
            int pos = vpf.apply(end);
            if (pos != VerticalPositionFunction.INVALID_POSITION && pos <= y) {
                return end;
            }
        }
        return null;
    }

    /**
     * Finds and returns the InstanceRole semantic element which corresponds to
     * the first element graphically above the specified X coordinate in a
     * diagram.
     * 
     * @param diagram
     *            the diagram.
     * @param x
     *            the X coordinate (in logical space)
     * @return the element which corresponds to the first InstanceRole above X.
     */
    public static EObject getInstanceRoleBefore(SequenceDDiagram diagram, int x) {
        Iterable<Diagram> diagramViews = Iterables.filter(
                ISequenceElementAccessor.getViewsForSemanticElement(diagram, diagram.getTarget()), Diagram.class);
        if (!Iterables.isEmpty(diagramViews)) {
            Option<SequenceDiagram> seqDiag = ISequenceElementAccessor
                    .getSequenceDiagram(diagramViews.iterator().next());
            if (seqDiag.some()) {
                for (InstanceRole ir : Lists.reverse(seqDiag.get().getSortedInstanceRole())) {
                    int pos = ir.getProperLogicalBounds().x;
                    if (pos <= x) {
                        return ir.getSemanticTargetElement().get();
                    }
                }
            }
        }
        return null;
    }

    /**
     * Finds and returns the EventEnd which corresponds to the first event
     * graphically below the specified Y coordinate in a diagram.
     * 
     * @param diagram
     *            the diagram.
     * @param y
     *            the Y coordinate
     * @return the EventEnd which corresponds to the first event below Y.
     */
    public static EventEnd getEndAfter(SequenceDDiagram diagram, int y) {
        VerticalPositionFunction vpf = new VerticalPositionFunction(diagram);
        for (EventEnd end : diagram.getGraphicalOrdering().getEventEnds()) {
            int pos = vpf.apply(end);
            if (pos != VerticalPositionFunction.INVALID_POSITION && pos > y) {
                return end;
            }
        }
        return null;
    }

    /**
     * Returns the normalized Y location of the Center of an edit part, using
     * only information from the GMF model (not Draw2D figures).
     * 
     * @param part
     *            the edit part.
     * @return the absolute, normalized Y location of the Center of the
     *         DNodeEditPart.
     */
    public static int getAbsoluteYCenterFromGMFView(IGraphicalEditPart part) {
        if (part instanceof ShapeNodeEditPart) {
            Rectangle absoluteboundsRectangle = SequenceGraphicalHelper.getAbsoluteBoundsFromGMFView(part);
            return absoluteboundsRectangle.getCenter().y;
        }
        // FIXME This uses Draw2D info
        Point location = part.getFigure().getBounds().getCenter().getCopy();
        GraphicalHelper.screen2logical(location, part);
        return location.y;
    }

    /**
     * Returns the normalized Y location of the Center of an edit part, using
     * only information from the GMF model (not Draw2D figures).
     * 
     * Use information from the GMF Notation model if available (which is most
     * of the time), and fall back to the Draw2D Figure's bounds otherwise. The
     * figure's bounds is always available, but depending on the time of the
     * call it may be out of date (pending a revalidate/repaint).
     * 
     * @param part
     *            the edit part
     * 
     * @return the absolute normalized bounds of the ISequenceEvent edit part
     */
    public static Rectangle getAbsoluteBoundsFromGMFView(IGraphicalEditPart part) {
        Rectangle rect;

        /*
         * Initialize with Draw2D information. May be out of date under some
         * conditions.
         */
        rect = part.getFigure().getBounds().getCopy();
        if (part instanceof LifelineEditPart) {
            SequenceGraphicalHelper.handleLifelineEditPartOffset(rect);
        }

        /*
         * Handle Node case with Notation information
         */
        if (part.getNotationView() instanceof Node) {
            Node node = (Node) part.getNotationView();
            Point absLoc = GMFNotationHelper.getAbsoluteLocation(node);

            LayoutConstraint layoutConstraint = node.getLayoutConstraint();
            if (layoutConstraint instanceof Bounds) {
                Bounds bounds = (Bounds) layoutConstraint;
                rect.setLocation(absLoc.x, absLoc.y);

                // prevent auto size
                if (bounds.getWidth() != -1) {
                    rect.width = bounds.getWidth();
                }

                // prevent auto size
                if (bounds.getHeight() != -1) {
                    rect.height = bounds.getHeight();
                }

                if (!(part instanceof InstanceRoleEditPart)) {
                    SequenceGraphicalHelper.handleLifelineEditPartOffset(rect);
                }
            }
        }

        return rect;
    }

    private static void handleLifelineEditPartOffset(Rectangle rect) {
        // FIXME LifelineEditPart are placed with offset which did
        // not appear in GMF model
        rect.translate(0, IBorderItemOffsets.DEFAULT_OFFSET.height);
    }

    /**
     * Return the absolute anchor position for the given range and anchor.
     * 
     * @param anchor
     *            the current anchor.
     * @param range
     *            range of the ISequenceEvent which supports the anchor.
     * @return the absolute anchor position.
     */
    public static int getAnchorAbsolutePosition(IdentityAnchor anchor, Range range) {
        PrecisionPoint rel = anchor != null ? BaseSlidableAnchor.parseTerminalString(anchor.getId())
                : new PrecisionPoint(0.5, 0.5);
        return range.getLowerBound() + (int) Math.round(rel.preciseY() * range.width());
    }
}