org.eclipse.sirius.diagram.ui.business.internal.command.SiriusSetConnectionAnchorsCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.diagram.ui.business.internal.command.SiriusSetConnectionAnchorsCommand.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2014 THALES GLOBAL SERVICES 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:
 *    Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.sirius.diagram.ui.business.internal.command;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.IdentityAnchor;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.sirius.diagram.AbstractDNode;
import org.eclipse.sirius.diagram.DNode;
import org.eclipse.sirius.diagram.DiagramPlugin;
import org.eclipse.sirius.diagram.business.api.query.EObjectQuery;
import org.eclipse.sirius.diagram.description.tool.ReconnectionKind;
import org.eclipse.sirius.diagram.ui.business.api.query.EdgeQuery;
import org.eclipse.sirius.ext.base.Option;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

/**
 * A custom SetConnectionAnchorsCommand used when edge reconnection is applied
 * by a reconnection tool (now executed in precommit).
 * 
 * @author <a href="mailto:steve.monnier@obeo.fr">Steve Monnier</a>
 * 
 * @since 0.9.0
 */
public class SiriusSetConnectionAnchorsCommand extends SetConnectionAnchorsCommand {

    /**
     * List of incoming/outgoing edges on the targeted edge before reconnection
     */
    private List<Edge> reconnectionTargetEdges;

    /**
     * Reconnection target
     */
    private View reconnectionTarget;

    /**
     * Reuse ReconnectionKind to save if reconnecting the source or the target
     * of the edge.
     */
    private ReconnectionKind reconnectionKind;

    /**
     * SiriusSetConnectionAnchorsCommand constructor.
     * 
     * @param editingDomain
     *            the current editing domain
     * @param label
     *            command label
     * @param reconnectionTarget
     *            the edge on which we are reconnecting
     * @param reconnectionTargetEdges
     *            the incoming(reconnectingSource as
     *            false)/outgoing(reconnectingSource as true) edges of the edge
     *            on which we are reconnecting
     * @param reconnectionKind
     *            indicates if it is a reconnection of the
     *            source(ReconnectionKind.RECONNECT_SOURCE) or the
     *            target(ReconnectionKind.RECONNECT_TARGET)
     */
    public SiriusSetConnectionAnchorsCommand(TransactionalEditingDomain editingDomain, String label,
            View reconnectionTarget, List<Edge> reconnectionTargetEdges, ReconnectionKind reconnectionKind) {
        super(editingDomain, label);
        this.reconnectionTarget = reconnectionTarget;
        this.reconnectionTargetEdges = new ArrayList<Edge>(reconnectionTargetEdges);
        assert reconnectionKind == ReconnectionKind.RECONNECT_SOURCE_LITERAL
                || reconnectionKind == ReconnectionKind.RECONNECT_TARGET_LITERAL : "reconnectionKind must be ReconnectionKind.RECONNECT_SOURCE or ReconnectionKind.RECONNECT_TARGET";
        this.reconnectionKind = reconnectionKind;
    }

    /**
     * Overridden because the tool execution is now done in precommit.
     * Therefore, we can not use the getEdgeAdaptor() anymore.
     * 
     * {@inheritDoc}
     */
    @Override
    protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info)
            throws ExecutionException {
        CommandResult commandResult = CommandResult.newOKCommandResult();
        if (getEdgeAdaptor() != null) {
            commandResult = super.doExecuteWithResult(progressMonitor, info);
        } else {

            Edge edge = getEdge();

            assert null != edge : "Null edge in SetConnectionAnchorsCommand"; //$NON-NLS-1$   

            // In case the reconnectTool has not updated correctly the semantic
            // to
            // do the reconnect, the Edge can be null
            if (edge == null) {
                String message = "The semantic model was not correctly updated by the reconnect tool, the diagram part of the reconnect cannot be done";
                commandResult = CommandResult.newErrorCommandResult(message);
                DiagramPlugin.getDefault().logWarning(message);
            } else {

                // If there is tree brothers on the new source, we must use the
                // existing
                // sourceAnchor instead of the <code>newSourceTerminal</code>
                // parameter
                Option<IdentityAnchor> optionalSourceBortherAnchor = new EdgeQuery(edge)
                        .getSourceAnchorOfFirstBrotherWithSameSource();
                if (optionalSourceBortherAnchor.some()) {
                    setNewSourceTerminal(optionalSourceBortherAnchor.get().getId());
                }
                updateSourceAnchor(edge);
                // If there is tree brothers on the new target, we must use the
                // existing
                // targetAnchor instead of the <code>newTargetTerminal</code>
                // parameter
                Option<IdentityAnchor> optionalTargetBortherAnchor = new EdgeQuery(edge)
                        .getTargetAnchorOfFirstBrotherWithSameTarget();
                if (optionalTargetBortherAnchor.some()) {
                    setNewTargetTerminal(optionalTargetBortherAnchor.get().getId());
                }
                updateTargetAnchor(edge);
            }
        }
        return commandResult;
    }

    private void updateSourceAnchor(Edge edge) {
        if (getNewSourceTerminal() != null) {
            if (getNewSourceTerminal().length() == 0)
                edge.setSourceAnchor(null);
            else {
                IdentityAnchor a = (IdentityAnchor) edge.getSourceAnchor();
                if (a == null)
                    a = NotationFactory.eINSTANCE.createIdentityAnchor();
                a.setId(getNewSourceTerminal());
                edge.setSourceAnchor(a);
            }
        }
    }

    private void updateTargetAnchor(Edge edge) {
        if (getNewTargetTerminal() != null) {
            if (getNewTargetTerminal().length() == 0)
                edge.setTargetAnchor(null);
            else {
                IdentityAnchor a = (IdentityAnchor) edge.getTargetAnchor();
                if (a == null)
                    a = NotationFactory.eINSTANCE.createIdentityAnchor();
                a.setId(getNewTargetTerminal());
                edge.setTargetAnchor(a);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private Edge getEdge() {
        Edge edge = null;
        if (reconnectionKind == ReconnectionKind.RECONNECT_SOURCE_LITERAL) {
            final List<Edge> sourceEdges = new ArrayList<Edge>(reconnectionTarget.getSourceEdges());
            Iterables.removeAll(sourceEdges, reconnectionTargetEdges);
            Predicate<Edge> notToReconnectingEdge = new Predicate<Edge>() {

                public boolean apply(Edge input) {
                    return !sourceEdges.contains(input.getTarget());
                }
            };
            // For case with reconnect edge source from borderedNode to
            // borderedNode
            // when borderedNode is mapping with EReference
            if (sourceEdges.isEmpty() && reconnectionTarget.getElement() instanceof AbstractDNode) {
                AbstractDNode abstractDNode = (AbstractDNode) reconnectionTarget.getElement();
                List<DNode> borderedNodes = abstractDNode.getOwnedBorderedNodes();
                if (!borderedNodes.isEmpty()) {
                    DNode borderedNode = borderedNodes.get(borderedNodes.size() - 1);
                    Collection<EObject> inverseReferences = new EObjectQuery(borderedNode)
                            .getInverseReferences(NotationPackage.eINSTANCE.getView_Element());
                    Node nodeSource = Iterables.getOnlyElement(Iterables.filter(inverseReferences, Node.class));
                    List<Edge> sourceEdgesOfBorderedNode = new ArrayList<Edge>(nodeSource.getSourceEdges());
                    edge = Iterables
                            .getOnlyElement(Iterables.filter(sourceEdgesOfBorderedNode, notToReconnectingEdge));
                }
            } else {
                edge = Iterables.getOnlyElement(Iterables.filter(sourceEdges, notToReconnectingEdge));
            }
        } else {
            final List<Edge> targetEdges = new ArrayList<Edge>(reconnectionTarget.getTargetEdges());
            Iterables.removeAll(targetEdges, reconnectionTargetEdges);
            Predicate<Edge> notFromReconnectingEdge = new Predicate<Edge>() {

                public boolean apply(Edge input) {
                    return !targetEdges.contains(input.getSource());
                }
            };
            // For case with reconnect edge target from borderedNode to
            // borderedNode
            // when borderedNode is mapping with EReference
            if (targetEdges.isEmpty() && reconnectionTarget.getElement() instanceof AbstractDNode) {
                AbstractDNode abstractDNode = (AbstractDNode) reconnectionTarget.getElement();
                List<DNode> borderedNodes = abstractDNode.getOwnedBorderedNodes();
                if (!borderedNodes.isEmpty()) {
                    DNode borderedNode = borderedNodes.get(borderedNodes.size() - 1);
                    Collection<EObject> inverseReferences = new EObjectQuery(borderedNode)
                            .getInverseReferences(NotationPackage.eINSTANCE.getView_Element());
                    Node nodeTarget = Iterables.getOnlyElement(Iterables.filter(inverseReferences, Node.class));
                    List<Edge> targetEdgesOfBorderedNode = new ArrayList<Edge>(nodeTarget.getTargetEdges());
                    edge = Iterables
                            .getOnlyElement(Iterables.filter(targetEdgesOfBorderedNode, notFromReconnectingEdge));
                }
            } else {
                edge = Iterables.getOnlyElement(Iterables.filter(targetEdges, notFromReconnectingEdge));
            }
        }
        return edge;
    }
}