org.eclipse.sirius.diagram.ui.business.internal.migration.DiagramRepresentationsFileMigrationParticipantV670.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.diagram.ui.business.internal.migration.DiagramRepresentationsFileMigrationParticipantV670.java

Source

/*******************************************************************************
 * Copyright (c) 2013 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.ui.business.internal.migration;

import java.util.Iterator;
import java.util.List;

import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.gmf.runtime.notation.Bounds;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.LayoutConstraint;
import org.eclipse.gmf.runtime.notation.Location;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.sirius.diagram.AbstractDNode;
import org.eclipse.sirius.diagram.CollapseFilter;
import org.eclipse.sirius.diagram.DDiagram;
import org.eclipse.sirius.diagram.DDiagramElement;
import org.eclipse.sirius.diagram.DNode;
import org.eclipse.sirius.diagram.DNodeContainer;
import org.eclipse.sirius.diagram.DNodeList;
import org.eclipse.sirius.diagram.DiagramFactory;
import org.eclipse.sirius.diagram.DiagramPackage;
import org.eclipse.sirius.diagram.GraphicalFilter;
import org.eclipse.sirius.diagram.IndirectlyCollapseFilter;
import org.eclipse.sirius.diagram.business.api.query.DDiagramElementQuery;
import org.eclipse.sirius.diagram.description.DescriptionPackage;
import org.eclipse.sirius.diagram.ui.business.api.query.NodeQuery;
import org.eclipse.sirius.diagram.ui.edit.internal.part.PortLayoutHelper;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNode2EditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNode3EditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNode4EditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeContainer2EditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeContainerEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeList2EditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeListEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.NotationViewIDs;
import org.eclipse.sirius.diagram.ui.internal.refresh.GMFHelper;
import org.eclipse.sirius.diagram.ui.internal.refresh.borderednode.CanonicalDBorderItemLocator;
import org.eclipse.sirius.diagram.ui.part.SiriusVisualIDRegistry;
import org.eclipse.sirius.diagram.ui.tools.api.graphical.edit.styles.IBorderItemOffsets;
import org.osgi.framework.Version;

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

/**
 * The migration code of Sirius 6.7.0.
 * 
 * @author lredor
 */
public class DiagramRepresentationsFileMigrationParticipantV670 {
    /**
     * The VP version for this migration.
     */
    public static final Version MIGRATION_VERSION = new Version("6.7.0.201302181200"); //$NON-NLS-1$

    private Predicate<Node> isBorderedNode = new IsBorderedNodePredicate();

    private Predicate<Node> isDirectlyCollapsedNode = new IsDirectlyCollapsedNodePredicate();

    /**
     * Migration of Bounds type to Location type. In some case, label might have
     * a wrong constraint type in GMF Annotation model (a Bounds instead of a
     * Location).
     * 
     * @param diagrams
     *            list of GMF Diagram to migrate.
     */
    public void migrateLabelConstraintFromBoundsToLocation(List<Diagram> diagrams) {
        for (Diagram diagram : diagrams) {
            Iterator<EObject> iterator = diagram.eAllContents();
            while (iterator.hasNext()) {
                EObject element = iterator.next();
                if (element instanceof Node) {
                    Node node = (Node) element;
                    int typeInt = SiriusVisualIDRegistry.getVisualID(node.getType());
                    // whatever the label position (border or node), the layout
                    // constraint should always be a location and not a bounds.
                    // 5001: a label of a Bordered node on a node.
                    // 5002: a node label
                    // 5003: a node label (where the node is in a container)
                    // 5010: a bordered node label (where the bordered node is
                    // in a container)
                    if (typeInt == NotationViewIDs.DNODE_NAME_EDIT_PART_VISUAL_ID
                            || typeInt == NotationViewIDs.DNODE_NAME_2_EDIT_PART_VISUAL_ID
                            || typeInt == NotationViewIDs.DNODE_NAME_3_EDIT_PART_VISUAL_ID
                            || typeInt == NotationViewIDs.DNODE_NAME_4_EDIT_PART_VISUAL_ID) {
                        LayoutConstraint layoutConstraint = node.getLayoutConstraint();
                        if (layoutConstraint instanceof Bounds) {
                            Location location = NotationFactory.eINSTANCE.createLocation();
                            location.setX(((Bounds) layoutConstraint).getX());
                            location.setY(((Bounds) layoutConstraint).getY());
                            node.setLayoutConstraint(location);
                        }
                    }
                }
            }
        }
    }

    /**
     * 1-Add new IndirectlyCollapseFilter to node (bordered or not) that is
     * contained in collapsed element.<BR>
     * 2-Set width and height of graphical filter of collapsed bordered nodes
     * according to current GMF size and the set the GMF bounds according to
     * there collapsed size and location. 3-Migrate the GMF bounds of the
     * bordered nodes to ensure that they do not overlap each other. Before, the
     * GMF bounds can be inconsistent (with draw2d) and overlap can exists.
     * 
     * @param diagrams
     *            list of GMF Diagram to migrate.
     */
    public void migrateGMFBoundsOfBorderedNodes(List<Diagram> diagrams) {
        for (Diagram diagram : Iterables.filter(diagrams, new IsStandardDiagramPredicate())) {
            // 1-Add new IndirectlyCollapseFilter
            migrateChildrenOfCollapsedNode(diagram);
            // 2-Set width and height of graphical filters of collapsed nodes
            // (directly or not) with GMF size and set GMF bounds.
            migrateGraphicalFiltersAndGMFBounds(diagram);
            // 3-Move bordered node to avoid overlaps
            avoidOverlaps(diagram);
        }
    }

    /**
     * Move bordered nodes to avoid overlaps.
     * 
     * @param diagram
     *            GMF Diagram to migrate.
     */
    private void avoidOverlaps(Diagram diagram) {
        // Get an iterator of bordered nodes that probably move
        Iterator<Node> viewIterator = Iterators.filter(Iterators.filter(diagram.eAllContents(), Node.class),
                isBorderedNode);
        // Get a list of bordered nodes that probably move (to ignore it
        // during the move of other bordered nodes. After a bordered node
        // has been moved, it is removed from this list.
        List<Node> otherBorderedNodesToIgnore = Lists.newArrayList(
                Iterators.filter(Iterators.filter(diagram.eAllContents(), Node.class), isBorderedNode));
        while (viewIterator.hasNext()) {
            Node node = viewIterator.next();
            Node parentNode = (Node) node.eContainer();
            // Create a canonicalDBorderItemLocator to locate this bordered
            // nodes according to current location and conflicts with other
            // bordered nodes.
            CanonicalDBorderItemLocator borderItemLocator = new CanonicalDBorderItemLocator(parentNode,
                    PositionConstants.NSEW);
            borderItemLocator.setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET);
            LayoutConstraint layoutConstraint = node.getLayoutConstraint();
            // The bordered node without layoutConstraint are ignored (it
            // should not have)
            if (layoutConstraint instanceof Location) {
                Rectangle constraint;
                if (layoutConstraint instanceof Bounds) {
                    Bounds bounds = (Bounds) layoutConstraint;
                    constraint = new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
                } else {
                    Location location = (Location) layoutConstraint;
                    constraint = new Rectangle(location.getX(), location.getY(), -1, -1);
                }
                Point parentAbsoluteLocation = GMFHelper.getAbsoluteLocation(parentNode);
                constraint.translate(parentAbsoluteLocation.x, parentAbsoluteLocation.y);
                final Point realLocation = borderItemLocator.getValidLocation(constraint, node,
                        otherBorderedNodesToIgnore);
                final Dimension d = realLocation.getDifference(parentAbsoluteLocation);
                realLocation.setLocation(new Point(d.width, d.height));

                // Set the new location for Location
                Location location = (Location) layoutConstraint;
                location.setX(realLocation.x);
                location.setY(realLocation.y);

            }
            // Remove this node from the list of bordered node to ignore.
            // Indeed, this port has now at its right location, so it should
            // no longer be ignored during conflict detection.
            otherBorderedNodesToIgnore.remove(node);
        }
    }

    /**
     * Set width and height of graphical filter of collapsed bordered nodes
     * according to current GMF size and the set the GMF bounds according to
     * there collapsed size and location.
     * 
     * @param diagram
     *            GMF Diagram to migrate.
     */
    private void migrateGraphicalFiltersAndGMFBounds(Diagram diagram) {
        Iterator<Node> viewIterator = Iterators.filter(Iterators.filter(diagram.eAllContents(), Node.class),
                isBorderedNode);
        while (viewIterator.hasNext()) {
            Node node = viewIterator.next();
            if (node.getElement() instanceof DNode && node.eContainer() instanceof Node) {
                // The element of a bordered node should be a DNode and the
                // parent of a bordered node should be a Node.
                DNode dNode = (DNode) node.getElement();
                if (new DDiagramElementQuery(dNode).isIndirectlyCollapsed()) {
                    // This node is collapsed.
                    Dimension expectedCollapsedSize = new NodeQuery(node).getCollapsedSize();
                    LayoutConstraint layoutConstraint = node.getLayoutConstraint();
                    if (layoutConstraint instanceof Bounds) {
                        Bounds bounds = (Bounds) layoutConstraint;
                        Rectangle rectBounds = GMFHelper.getAbsoluteBounds(node);
                        // The GMF node size must be stored in collapse
                        // filter (to can set this size
                        // when this node is expanded).
                        for (GraphicalFilter graphicalFilter : dNode.getGraphicalFilters()) {
                            if (graphicalFilter instanceof CollapseFilter) {
                                ((CollapseFilter) graphicalFilter).setWidth(bounds.getWidth());
                                ((CollapseFilter) graphicalFilter).setHeight(bounds.getHeight());
                            }
                        }
                        // Compute the parent border rectangle
                        Rectangle parentBorder = new NodeQuery((Node) node.eContainer()).getHandleBounds();
                        // Compute the new collapsed bounds
                        Rectangle newCollapsedBounds = PortLayoutHelper
                                .getCollapseCandidateLocation(expectedCollapsedSize, rectBounds, parentBorder);
                        // Translate to relative
                        newCollapsedBounds.translate(parentBorder.getLocation().negate());
                        // // Set new GMF bounds
                        Bounds newBounds = NotationFactory.eINSTANCE.createBounds();
                        newBounds.setX(newCollapsedBounds.x);
                        newBounds.setY(newCollapsedBounds.y);
                        newBounds.setWidth(newCollapsedBounds.width);
                        newBounds.setHeight(newCollapsedBounds.height);
                        node.setLayoutConstraint(newBounds);
                    }
                }
            }
        }
    }

    /**
     * Add a {@link IndirectlyCollapsedFilter} to the children of CollapsedNode
     * (to retrieve the same behavior as before). The migration of GMF bounds of
     * this indirectly collapsed nodes, if they are bordered nodes, are deal
     * later in method {{@link #migrateGMFBoundsOfBorderedNodes(List)}.
     * 
     * @param diagram
     *            GMF Diagram to migrate.
     */
    private void migrateChildrenOfCollapsedNode(Diagram diagram) {
        List<DDiagramElement> indirectlyCollaspedDDEs = Lists.newArrayList();
        Iterator<Node> viewIterator = Iterators.filter(Iterators.filter(diagram.eAllContents(), Node.class),
                isDirectlyCollapsedNode);
        while (viewIterator.hasNext()) {
            final Node node = viewIterator.next();
            if (node.getElement() instanceof AbstractDNode) {
                AbstractDNode abstractDNode = (AbstractDNode) node.getElement();
                indirectlyCollaspedDDEs.addAll(abstractDNode.getOwnedBorderedNodes());
                if (abstractDNode instanceof DNodeContainer) {
                    DNodeContainer dDiagramElementContainer = (DNodeContainer) abstractDNode;
                    indirectlyCollaspedDDEs.addAll(dDiagramElementContainer.getOwnedDiagramElements());
                } else if (abstractDNode instanceof DNodeList) {
                    DNodeList dNodeList = (DNodeList) abstractDNode;
                    indirectlyCollaspedDDEs.addAll(dNodeList.getOwnedElements());
                }
            }
        }
        for (DDiagramElement indirectlyCollaspedDDE : indirectlyCollaspedDDEs) {
            if (!Iterables.any(indirectlyCollaspedDDE.getGraphicalFilters(),
                    Predicates.instanceOf(IndirectlyCollapseFilter.class))) {
                IndirectlyCollapseFilter indirectlyCollapseFilter = DiagramFactory.eINSTANCE
                        .createIndirectlyCollapseFilter();
                indirectlyCollaspedDDE.getGraphicalFilters().add(indirectlyCollapseFilter);
            }
        }
    }

    /**
     * Predicate that checks that :
     * <UL>
     * <LI>The Diagram input reference a DDiagram,</LI>
     * <LI>and this DDiagram is defined by the ViewpointPackage,</LI>
     * <LI>and its description is defined by the DescriptionPackage,</LI>
     * </UL>
     */
    private static class IsStandardDiagramPredicate implements Predicate<Diagram> {
        public boolean apply(Diagram input) {
            boolean apply = false;
            if (input.getElement() instanceof DDiagram) {
                DDiagram diag = (DDiagram) input.getElement();
                EPackage diagPackage = diag.eClass().getEPackage();
                apply = DiagramPackage.eINSTANCE.equals(diagPackage);
                if (apply && diag.getDescription() != null) {
                    EPackage descriptionPackage = diag.getDescription().eClass().getEPackage();
                    apply = DescriptionPackage.eINSTANCE.equals(descriptionPackage);
                }
            }
            return apply;
        }
    }

    /**
     * Predicate that checks that :
     * <UL>
     * <LI>The input is a GMF Node,</LI>
     * <LI>and this Node is a bordered node.</LI>
     * </UL>
     */
    private static class IsBorderedNodePredicate implements Predicate<Node> {

        public boolean apply(Node input) {
            // Is this node the main view of a DNode and a border
            // node ?
            return new NodeQuery(input).isBorderedNode();
        }
    }

    /**
     * Predicate that checks that :
     * <UL>
     * <LI>The input corresponds to something that can be collapsed,</LI>
     * <LI>and the input is collapsed.</LI>
     * </UL>
     */

    private static class IsDirectlyCollapsedNodePredicate implements Predicate<Node> {
        public boolean apply(Node input) {
            boolean apply = false;

            int type = SiriusVisualIDRegistry.getVisualID(input.getType());
            boolean result = type == DNode2EditPart.VISUAL_ID || type == DNode4EditPart.VISUAL_ID;
            result = result || type == DNodeEditPart.VISUAL_ID || type == DNode3EditPart.VISUAL_ID;
            result = result || type == DNodeContainerEditPart.VISUAL_ID
                    || type == DNodeContainer2EditPart.VISUAL_ID;
            result = result || type == DNodeListEditPart.VISUAL_ID || type == DNodeList2EditPart.VISUAL_ID;

            if (result) {
                return new NodeQuery(input).isDirectlyCollapsed();
            }
            return apply;
        }
    }
}