org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.SequenceCreatedEventsFlaggingSiriusCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.SequenceCreatedEventsFlaggingSiriusCommand.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2015 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.sequence.internal.tool.command.builders;

import java.util.Collection;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.sirius.business.api.session.CustomDataConstants;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.SessionManager;
import org.eclipse.sirius.diagram.AbsoluteBoundsFilter;
import org.eclipse.sirius.diagram.DDiagram;
import org.eclipse.sirius.diagram.DDiagramElement;
import org.eclipse.sirius.diagram.DiagramFactory;
import org.eclipse.sirius.diagram.business.api.refresh.CanonicalSynchronizer;
import org.eclipse.sirius.diagram.business.api.refresh.CanonicalSynchronizerFactory;
import org.eclipse.sirius.diagram.sequence.Messages;
import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.base.Options;
import org.eclipse.sirius.tools.api.command.SiriusCommand;
import org.eclipse.sirius.tools.api.ui.PostRefreshCommandFactory;
import org.eclipse.sirius.tools.api.ui.RefreshEditorsPrecommitListener;
import org.eclipse.sirius.viewpoint.DRepresentation;
import org.eclipse.sirius.viewpoint.DSemanticDecorator;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * Specific sequence viewpoint command to flag created elements from tool.
 * 
 * @author mporhel
 */
public class SequenceCreatedEventsFlaggingSiriusCommand extends SiriusCommand {

    private Predicate<DDiagramElement> shouldFlag;

    private DDiagram parentDiagram;

    private Point lostNodesLocation;

    /**
     * Constructor.
     * 
     * @param domain
     *            the editing domain.
     * @param name
     *            the command name.
     * @param diagram
     *            the current diagram
     * @param shouldFlag
     *            predicates to select created {@link DDiagramElement} eleemnts
     *            to flag.
     */
    public SequenceCreatedEventsFlaggingSiriusCommand(TransactionalEditingDomain domain, String name,
            DDiagram diagram, Predicate<DDiagramElement> shouldFlag) {
        super(domain, name);
        this.parentDiagram = diagram;
        this.shouldFlag = completeShouldFlagPredicate(shouldFlag);
    }

    private Predicate<DDiagramElement> completeShouldFlagPredicate(Predicate<DDiagramElement> pred) {
        Predicate<DDiagramElement> result = LostMessageEnd.viewpointElementPredicate();
        if (pred != null) {
            result = Predicates.or(pred, result);
        }
        return result;
    }

    @Override
    protected void doExecute() {
        super.doExecute();

        flagNewElements();
    }

    private void flagNewElements() {
        final Collection<EObject> createdSemantics = getCreatedObjects();

        final Collection<EObject> mainSemantics = flagAndRegisterMainCreatedElements();
        flagPostRefresh(mainSemantics, createdSemantics);
        flagPostPrecommitRefresh(mainSemantics, createdSemantics);
    }

    private void flagPostPrecommitRefresh(final Collection<EObject> mainSemantics,
            final Collection<EObject> createdObjects) {
        if (parentDiagram instanceof DSemanticDecorator
                && ((DSemanticDecorator) parentDiagram).getTarget() != null) {
            final EObject semanticElement = ((DSemanticDecorator) parentDiagram).getTarget();
            final Session session = SessionManager.INSTANCE.getSession(semanticElement);
            if (session != null) {
                final RefreshEditorsPrecommitListener listener = session.getRefreshEditorsListener();
                PostRefreshCommandFactory factory = new SequencePostRefreshFactory(parentDiagram, session,
                        mainSemantics, createdObjects);
                listener.addPostRefreshCommandFactory(factory);
            }
        }
    }

    /**
     * Flag directly created by tool elements and register main semantics.
     */
    private Collection<EObject> flagAndRegisterMainCreatedElements() {
        final Collection<EObject> mainSemantics = Sets.newHashSet();
        final Collection<DDiagramElement> createdDDE = Lists
                .newArrayList(Iterables.filter(getCreatedRepresentationElements(), DDiagramElement.class));
        for (DDiagramElement dde : createdDDE) {
            if (shouldFlag != null && shouldFlag.apply(dde)) {
                safeAddCreationFlag(dde, LayoutConstants.TOOL_CREATION_FLAG);
                mainSemantics.add(dde.getTarget());
            } else if (dde.getTarget() != null) {
                mainSemantics.add(dde.getTarget());
            }
        }
        return mainSemantics;
    }

    /**
     * Flag indirectly created by tool elements, distinguish the main semantics
     * from other semantics elements.
     */
    private Collection<DDiagramElement> flagPostRefresh(final Collection<EObject> mainSemantics,
            final Collection<EObject> createdSemantics) {
        Collection<DDiagramElement> flags = Lists.newArrayList();

        if (parentDiagram != null && shouldFlag != null) {
            for (DDiagramElement dde : Iterables.filter(parentDiagram.getDiagramElements(), shouldFlag)) {
                Option<DDiagramElement> flagged = Options.newNone();
                if (dde.getTarget() != null) {
                    if (mainSemantics.contains(dde.getTarget())) {
                        flagged = safeAddCreationFlag(dde, LayoutConstants.TOOL_CREATION_FLAG);
                    } else if (createdSemantics.contains(dde.getTarget())) {
                        flagged = safeAddCreationFlag(dde, LayoutConstants.TOOL_CREATION_FLAG_FROM_SEMANTIC);
                    }
                }
                if (flagged.some()) {
                    flags.add(flagged.get());
                }
            }
        }

        return flags;
    }

    private Option<DDiagramElement> safeAddCreationFlag(DDiagramElement dde, Rectangle toolCreationFlag) {
        if (Iterables.isEmpty(Iterables.filter(dde.getGraphicalFilters(), AbsoluteBoundsFilter.class))) {
            AbsoluteBoundsFilter flag = getFlag(toolCreationFlag);

            if (LostMessageEnd.viewpointElementPredicate().apply(dde) && lostNodesLocation != null) {
                flag.setY(lostNodesLocation.y);
            }

            dde.getGraphicalFilters().add(flag);
            return Options.newSome(dde);
        }
        return Options.newNone();
    }

    private AbsoluteBoundsFilter getFlag(Rectangle toolCreationFlag) {
        AbsoluteBoundsFilter flag = DiagramFactory.eINSTANCE.createAbsoluteBoundsFilter();
        flag.setX(toolCreationFlag.x);
        flag.setY(toolCreationFlag.y);
        flag.setHeight(toolCreationFlag.height);
        flag.setWidth(toolCreationFlag.width);

        return flag;
    }

    /**
     * Set lost nodes location, for first layout.
     * 
     * @param location
     *            location of lost nodes.
     */
    public void setLostNodesLocation(Point location) {
        this.lostNodesLocation = location;
    }

    /**
     * Post refresh factory to flag elements created during precommit
     * representation refresh.
     */
    private final class SequencePostRefreshFactory implements PostRefreshCommandFactory {

        private final Collection<EObject> mainSemantics = Lists.newArrayList();

        private final Collection<EObject> createdObjects = Lists.newArrayList();

        private final Session session;

        private final DDiagram diagram;

        public SequencePostRefreshFactory(DDiagram parentDiagram, Session session,
                Collection<EObject> mainSemantics, Collection<EObject> createdObjects) {
            this.diagram = parentDiagram;
            this.session = session;
            this.mainSemantics.addAll(mainSemantics);
            this.createdObjects.addAll(createdObjects);
        }

        @Override
        public Command getPostCommandToExecute(TransactionalEditingDomain domain,
                Collection<DRepresentation> refreshedRepresentations) {
            Command result = null;
            // Flag new elements of the clicked with tool diagram -> diagram
            if (session != null && diagram != null && refreshedRepresentations.contains(diagram)) {
                final Collection<EObject> gmfDiags = session.getServices()
                        .getCustomData(CustomDataConstants.GMF_DIAGRAMS, diagram);
                if (!gmfDiags.isEmpty()) {
                    CompoundCommand cc = new CompoundCommand();
                    for (final Diagram gmfDiag : Iterables.filter(gmfDiags, Diagram.class)) {
                        cc.append(new SequenceFlagAndSyncCommand(domain, gmfDiag, mainSemantics, createdObjects));
                    }
                    result = cc;
                }
            }
            return result;

        }
    }

    /**
     * Command to flag elements created during precommit representation refresh.
     */
    private final class SequenceFlagAndSyncCommand extends RecordingCommand {

        private final Collection<EObject> mainSemantics = Lists.newArrayList();

        private final Collection<EObject> createdObjects = Lists.newArrayList();

        private final Diagram gmfDiag;

        public SequenceFlagAndSyncCommand(TransactionalEditingDomain domain, Diagram gmfDiag,
                Collection<EObject> mainSemantics, Collection<EObject> createdObjects) {
            super(domain, Messages.SequenceFlagAndSyncCommand_commandName);
            this.gmfDiag = gmfDiag;
            this.mainSemantics.addAll(mainSemantics);
            this.createdObjects.addAll(createdObjects);
        }

        @Override
        protected void doExecute() {
            Collection<DDiagramElement> flagPostRefresh = flagPostRefresh(mainSemantics, createdObjects);

            if (flagPostRefresh != null
                    && Iterables.any(flagPostRefresh, LostMessageEnd.viewpointElementPredicate())) {
                CanonicalSynchronizer canonicalSynchronizer = CanonicalSynchronizerFactory.INSTANCE
                        .createCanonicalSynchronizer(gmfDiag);
                canonicalSynchronizer.storeViewsToArrange(false);
                canonicalSynchronizer.synchronize();
            }

            if (mainSemantics != null) {
                mainSemantics.clear();
            }

            if (createdObjects != null) {
                createdObjects.clear();
            }
        }
    }
}