org.eclipse.sirius.diagram.ui.graphical.edit.policies.RegionResizableEditPolicy.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.diagram.ui.graphical.edit.policies.RegionResizableEditPolicy.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 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.ui.graphical.edit.policies;

import java.util.Collections;
import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Locator;
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.common.notify.Notification;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gef.requests.AlignmentRequest;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IResizableCompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.handles.CompartmentCollapseHandle;
import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.sirius.diagram.DDiagramElement;
import org.eclipse.sirius.diagram.DDiagramElementContainer;
import org.eclipse.sirius.diagram.DNodeList;
import org.eclipse.sirius.diagram.DNodeListElement;
import org.eclipse.sirius.diagram.business.api.query.DDiagramElementQuery;
import org.eclipse.sirius.diagram.business.internal.query.DDiagramElementContainerExperimentalQuery;
import org.eclipse.sirius.diagram.ui.business.internal.query.RequestQuery;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramElementContainerEditPart;
import org.eclipse.sirius.diagram.ui.edit.api.part.IDiagramElementEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.AbstractDNodeContainerCompartmentEditPart;
import org.eclipse.sirius.diagram.ui.provider.Messages;
import org.eclipse.sirius.diagram.ui.tools.api.graphical.edit.styles.IContainerLabelOffsets;
import org.eclipse.sirius.diagram.ui.tools.internal.util.EditPartQuery;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.base.Options;
import org.eclipse.sirius.viewpoint.LabelAlignment;
import org.eclipse.sirius.viewpoint.LabelStyle;
import org.eclipse.sirius.viewpoint.Style;
import org.eclipse.sirius.viewpoint.ViewpointPackage;

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

/**
 * A {@link AirResizableEditPolicy} able to handle regions.
 * 
 * @author mporhel
 */
public class RegionResizableEditPolicy extends AirResizableEditPolicy {

    /**
     * {@inheritDoc}
     * 
     * Configure the edit policy regarding the host.
     */
    @Override
    public void setHost(EditPart host) {
        super.setHost(host);

        if (concernRegion()) {
            setResizeDirections(getParentStackDirection());
            setDragAllowed(false);
        }
    }

    /**
     * For regions, only put resize handles on authorized directions.
     *
     * {@inheritDoc}
     */
    @Override
    protected void createResizeHandle(List handles, int direction) {
        if (!concernRegion() || (getResizeDirections() & direction) == direction) {
            super.createResizeHandle(handles, direction);
        }
    }

    @Override
    protected List createSelectionHandles() {
        List createSelectionHandles = super.createSelectionHandles();

        addCollapseHandle(createSelectionHandles);
        return createSelectionHandles;
    }

    /**
     * Add the collapse handle of the region.
     * 
     * @param selectionHandles
     *            selection handles
     */
    protected void addCollapseHandle(List selectionHandles) {
        EditPart regionContainerPart = getRegionContainerPart();

        // DisableCollapse for Regions whose the RegionContainer is itself a
        // Region.
        if (concernRegion() && regionContainerPart instanceof AbstractDiagramElementContainerEditPart
                && !((AbstractDiagramElementContainerEditPart) regionContainerPart).isRegion()) {
            AbstractDiagramElementContainerEditPart hostPart = (AbstractDiagramElementContainerEditPart) getHost();
            LabelAlignment textAlignment = getTextAlignment(hostPart);
            Iterable<IResizableCompartmentEditPart> compartmentParts = Iterables.filter(hostPart.getChildren(),
                    IResizableCompartmentEditPart.class);
            if (new EditPartQuery(hostPart).getDrawerStyle() != null && !Iterables.isEmpty(compartmentParts)) {
                selectionHandles
                        .add(new RegionCollapseHandle(compartmentParts.iterator().next(), textAlignment, hostPart));
            }
        }
    }

    private LabelAlignment getTextAlignment(AbstractDiagramElementContainerEditPart hostPart) {
        LabelAlignment alignment = (LabelAlignment) ViewpointPackage.eINSTANCE.getLabelStyle_LabelAlignment()
                .getDefaultValue();

        DDiagramElement dde = hostPart.resolveDiagramElement();
        Style style = dde.getStyle();
        boolean hiddenLabel = new DDiagramElementQuery(dde).isLabelHidden();
        if (style instanceof LabelStyle && !hiddenLabel) {
            alignment = ((LabelStyle) style).getLabelAlignment();
        }
        if (hiddenLabel && dde instanceof DNodeList) {
            List<DNodeListElement> ownedElements = ((DNodeList) dde).getOwnedElements();
            if (!ownedElements.isEmpty() && ownedElements.get(0).getStyle() instanceof LabelStyle) {
                alignment = ((LabelStyle) ownedElements.get(0).getStyle()).getLabelAlignment();
            }
        }
        return alignment;
    }

    @Override
    protected Command getMoveCommand(final ChangeBoundsRequest request) {
        if (concernRegion()) {
            return UnexecutableCommand.INSTANCE;
        }

        return super.getMoveCommand(request);
    }

    @Override
    protected Command getAlignCommand(AlignmentRequest request) {
        if (concernRegion()) {
            return UnexecutableCommand.INSTANCE;
        }
        return super.getAlignCommand(request);
    }

    @Override
    protected Command getAutoSizeCommand(Request request) {
        Command autoSizeCommand = super.getAutoSizeCommand(request);
        if (concernRegion()) {
            EditPart regionContainerPart = getRegionContainerPart();
            Object object = request.getExtendedData()
                    .get(RegionContainerResizableEditPolicy.REGION_AUTO_SIZE_PROPAGATOR);
            if (object == getHost()) {
                autoSizeCommand = null;
            } else if (object != regionContainerPart) {
                // Redirect the auto-size to the parent RegionContainer
                Request req = new Request();
                req.setType(request.getType());
                req.getExtendedData().put(RegionContainerResizableEditPolicy.REGION_AUTO_SIZE_PROPAGATOR,
                        getHost());

                Command regionContainerAutoSizeCommand = regionContainerPart.getCommand(req);
                if (getHost() instanceof IDiagramElementEditPart && regionContainerAutoSizeCommand != null) {
                    CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(
                            ((IDiagramElementEditPart) getHost()).getEditingDomain(),
                            Messages.RegionResizableEditPolicy_regionAutoSizeCommandLabel);
                    ctc.add(new CommandProxy(autoSizeCommand));
                    ctc.add(new CommandProxy(regionContainerAutoSizeCommand));
                    autoSizeCommand = new ICommandProxy(ctc);
                }
            }
        }
        return autoSizeCommand;
    }

    @Override
    protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
        super.showChangeBoundsFeedback(request);

        if (concernRegion()) {
            Option<ChangeBoundsRequest> siblingRequest = getConstrainedSiblingRequest(request);
            if (siblingRequest.some() && siblingRequest.get().getEditParts() != null
                    && siblingRequest.get().getEditParts().size() == 1) {
                if (siblingRequest.get().getTransformedRectangle(new Rectangle()).equals(new Rectangle())) {
                    return;
                }
                EditPart siblingPart = (EditPart) siblingRequest.get().getEditParts().get(0);
                siblingPart.showSourceFeedback(siblingRequest.get());
            }
        }
    }

    @Override
    protected void eraseChangeBoundsFeedback(ChangeBoundsRequest request) {
        super.eraseChangeBoundsFeedback(request);

        if (concernRegion()) {
            Option<ChangeBoundsRequest> siblingRequest = getConstrainedSiblingRequest(request);
            if (siblingRequest.some() && siblingRequest.get().getEditParts() != null
                    && siblingRequest.get().getEditParts().size() == 1) {
                if (siblingRequest.get().getTransformedRectangle(new Rectangle()).equals(new Rectangle())) {
                    return;
                }
                EditPart siblingPart = (EditPart) siblingRequest.get().getEditParts().get(0);
                siblingPart.eraseSourceFeedback(siblingRequest.get());
            }
        }
    }

    @Override
    protected Command getResizeCommand(ChangeBoundsRequest request) {
        EditPart host = getHost();
        RequestQuery query = new RequestQuery(request);

        if (host instanceof IGraphicalEditPart && new EditPartQuery((IGraphicalEditPart) host).isCollapsed()) {
            // Disable resize in the collapsed direction.
            boolean forbiddenCollapseResize = false;
            if (getParentStackDirection() == PositionConstants.NORTH_SOUTH) {
                forbiddenCollapseResize = (query.isResizeFromTop() || query.isResizeFromBottom())
                        && request.getSizeDelta().height() != 0;
            } else if (getParentStackDirection() == PositionConstants.EAST_WEST) {
                forbiddenCollapseResize = (query.isResizeFromLeft() || query.isResizeFromRight())
                        && request.getSizeDelta().width() != 0;
            }
            if (forbiddenCollapseResize) {
                return UnexecutableCommand.INSTANCE;
            }
        }

        if (isFirstRegionPart()) {
            request.getMoveDelta().setX(0);
            request.getMoveDelta().setY(0);
        } else if (getParentStackDirection() == PositionConstants.EAST_WEST) {
            request.getMoveDelta().setY(0);
        }
        return super.getResizeCommand(request);
    }

    /**
     * Complete the given composite command with Region specific resize
     * commands: the commands to report the resize on the RegionContainer or on
     * the sibling regions.
     */
    @Override
    protected void completeResizeCommand(CompositeTransactionalCommand ctc, ChangeBoundsRequest request) {
        boolean invalidRequest = request.getEditParts().size() > 1 && !request.isConstrainedResize()
                || request.isCenteredResize();
        if (invalidRequest || !validateResize(request)) {
            ctc.add(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
        }

        Option<ChangeBoundsRequest> siblingRequest = getConstrainedSiblingRequest(request);
        if (siblingRequest.some() && siblingRequest.get().getEditParts() != null
                && siblingRequest.get().getEditParts().size() == 1) {
            EditPart siblingPart = (EditPart) siblingRequest.get().getEditParts().get(0);
            ctc.add(new CommandProxy(siblingPart.getCommand(siblingRequest.get())));
        } else if (!(request.isConstrainedMove() || request.isConstrainedResize())) {
            ctc.add(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
        }

        Option<ChangeBoundsRequest> adjustChildrenRequest = getAdjustChildrenRequest(request);
        if (adjustChildrenRequest.some()) {
            super.completeResizeCommand(ctc, adjustChildrenRequest.get());
        }
    }

    /**
     * Return true to add the default {@link AirResizableEditPolicy} behavior in
     * completeResizeCommand: this will add the sub commands to adjust children
     * position: see
     * {@link org.eclipse.sirius.diagram.ui.internal.edit.commands.ChildrenAdjustmentCommand}
     * .
     * 
     * @param request
     *            the current change bounds request.
     * @return true to add the default {@link AirResizableEditPolicy} behavior.
     */
    protected Option<ChangeBoundsRequest> getAdjustChildrenRequest(ChangeBoundsRequest request) {
        ChangeBoundsRequest requestToCompensate = null;
        RequestQuery requestQuery = new RequestQuery(request);
        if (request.getExtendedData()
                .get(RegionContainerResizableEditPolicy.REGION_RESIZE_PROPAGATOR) == getRegionContainerPart()) {
            Object object = request.getExtendedData()
                    .get(RegionContainerResizableEditPolicy.REGION_RESIZE_INITIAL_REQUEST);
            int stackDirection = getParentStackDirection();
            boolean needsAdjust = false;
            if (stackDirection == PositionConstants.NORTH_SOUTH) {
                needsAdjust = requestQuery.isResizeFromLeft() || requestQuery.isResizeFromRight()
                        || requestQuery.isResizeFromTop() && isFirstRegionPart();
            } else if (stackDirection == PositionConstants.EAST_WEST) {
                needsAdjust = requestQuery.isResizeFromTop() || requestQuery.isResizeFromBottom()
                        || requestQuery.isResizeFromLeft() && isFirstRegionPart();
            }
            if (needsAdjust && object instanceof ChangeBoundsRequest) {
                requestToCompensate = (ChangeBoundsRequest) object;
            }
        } else {
            if (isFirstRegionPart() && (requestQuery.isResizeFromLeft() || requestQuery.isResizeFromTop())) {
                // The move part has been canceled for the concrete resize of
                // the region, because the move will be done on the region
                // container but we need to compensate the move on the children.
                Dimension delta = request.getSizeDelta().getNegated();
                request.setMoveDelta(new Point(delta.width, delta.height));
            }
            requestToCompensate = request;
        }
        return Options.newSome(requestToCompensate);
    }

    private boolean validateResize(ChangeBoundsRequest request) {
        IFigure hostFigure = getHostFigure();
        if (hostFigure != null) {
            Dimension minimumSize = hostFigure.getMinimumSize().getCopy();
            Rectangle resultingBounds = new RequestQuery(request)
                    .getLogicalTransformedRectangle(hostFigure.getBounds().getCopy());
            return resultingBounds.width >= minimumSize.width && resultingBounds.height >= minimumSize.height;
        }
        return false;
    }

    private Option<ChangeBoundsRequest> getConstrainedSiblingRequest(ChangeBoundsRequest request) {
        Option<ChangeBoundsRequest> constrainedRequest = Options.newNone();

        RequestQuery query = new RequestQuery(request);
        Dimension sizeDelta = request.getSizeDelta().getCopy();

        EditPart regionContainer = getRegionContainerPart();
        boolean allowedRegionContainerPropagation = !request.isConstrainedResize() || request.getExtendedData()
                .get(RegionContainerResizableEditPolicy.REGION_RESIZE_PROPAGATOR) != regionContainer;

        int stackDirection = getParentStackDirection();
        if (stackDirection == PositionConstants.NORTH_SOUTH) {
            constrainedRequest = Options.newSome(getVStackConstrainedSiblingRequest(request, query, sizeDelta,
                    allowedRegionContainerPropagation, regionContainer));
        } else if (stackDirection == PositionConstants.EAST_WEST) {
            constrainedRequest = Options.newSome(getHStackConstrainedSiblingRequest(request, query, sizeDelta,
                    allowedRegionContainerPropagation, regionContainer));
        }
        return constrainedRequest;
    }

    private ChangeBoundsRequest getVStackConstrainedSiblingRequest(ChangeBoundsRequest request, RequestQuery query,
            Dimension sizeDelta, boolean allowedRegionContainerPropagation, EditPart regionContainer) {
        ChangeBoundsRequest constrainedRequest = null;
        ChangeBoundsRequest req = initSiblingRequest(request);

        if (query.isResizeFromTop()) {
            if (!isFirstRegionPart()) {
                Option<AbstractDiagramElementContainerEditPart> pred = getPrecedingRegion();
                if (pred.some() && !request.isConstrainedResize()) {
                    req.setEditParts(pred.get());
                    req.setResizeDirection(PositionConstants.SOUTH);
                    req.setSizeDelta(new Dimension(0, sizeDelta.getNegated().height));
                    constrainedRequest = req;
                }
            } else if (allowedRegionContainerPropagation) {
                // resize regioncontainer from first region part resize.
                req.setEditParts(regionContainer);
                req.setResizeDirection(request.getResizeDirection());
                req.setSizeDelta(new Dimension(0, sizeDelta.height));
                req.setMoveDelta(new Point(0, -sizeDelta.height));
                constrainedRequest = req;
            }
        } else if (query.isResizeFromBottom()) {
            if (!isLastRegionPart()) {
                Option<AbstractDiagramElementContainerEditPart> follo = getFollowingRegion();
                if (follo.some() && !request.isConstrainedResize()) {
                    Point moveDelta = new Point(sizeDelta.width, sizeDelta.height);
                    req.setEditParts(follo.get());
                    req.setResizeDirection(PositionConstants.NORTH);
                    req.setSizeDelta(new Dimension(0, sizeDelta.getNegated().height));
                    req.setMoveDelta(new Point(0, moveDelta.y));
                    constrainedRequest = req;
                }
            } else if (allowedRegionContainerPropagation) {
                // resize regioncontainer from last region part resize.
                req.setEditParts(regionContainer);
                req.setResizeDirection(request.getResizeDirection());
                req.setSizeDelta(new Dimension(0, sizeDelta.height));
                constrainedRequest = req;
                // Handle F3 for regions in region to allow manual layout.
                // Allow manual resize of the region container to reduce
                // empty space due to VSM specified size or recursive
                // regions.
                constrainedRequest = handleEmptySpaceInContainerOnLastRegionResize(request, constrainedRequest);
            }
        } else if (query.isResizeFromRight() && allowedRegionContainerPropagation) {
            // resize regioncontainer.
            req.setEditParts(regionContainer);
            req.setResizeDirection(request.getResizeDirection());
            req.setSizeDelta(new Dimension(sizeDelta.width, 0));
            constrainedRequest = req;
        } else if (query.isResizeFromLeft() && allowedRegionContainerPropagation) {
            // resize regioncontainer.
            req.setEditParts(regionContainer);
            req.setResizeDirection(request.getResizeDirection());
            req.setSizeDelta(new Dimension(sizeDelta.width, 0));
            req.setMoveDelta(new Point(-sizeDelta.width, 0));
            constrainedRequest = req;
        }
        return constrainedRequest;
    }

    private ChangeBoundsRequest handleEmptySpaceInContainerOnLastRegionResize(ChangeBoundsRequest initialRequest,
            ChangeBoundsRequest constrainedRequest) {
        ChangeBoundsRequest result = constrainedRequest;
        Object object = initialRequest.getExtendedData().get(SiriusResizeTracker.CHILDREN_MOVE_MODE_KEY);
        boolean keepSameAbsoluteLocation = (object == null && SiriusResizeTracker.DEFAULT_CHILDREN_MOVE_MODE)
                || (object != null && ((Boolean) object).booleanValue());
        if (!initialRequest.isConstrainedResize() && !keepSameAbsoluteLocation) {
            result.setMoveDelta(new Point(0, 0));
            result.setSizeDelta(new Dimension(0, 0));

            IFigure hostFigure = getHostFigure();
            IFigure parentFigure = hostFigure.getParent();
            // Restrict the move to the parent bounds.
            if (!parentFigure.getBounds().contains(new RequestQuery(initialRequest)
                    .getLogicalTransformedRectangle(hostFigure.getBounds()).getBottomRight())) {
                result = null;
            }
        }
        return result;
    }

    private ChangeBoundsRequest getHStackConstrainedSiblingRequest(ChangeBoundsRequest request, RequestQuery query,
            Dimension sizeDelta, boolean regionContainerPropagationAllowed, EditPart regionContainer) {
        ChangeBoundsRequest constrainedRequest = null;
        ChangeBoundsRequest req = initSiblingRequest(request);

        if (query.isResizeFromLeft()) {
            if (!isFirstRegionPart()) {
                Option<AbstractDiagramElementContainerEditPart> pred = getPrecedingRegion();
                if (pred.some() && !request.isConstrainedResize()) {
                    req.setEditParts(pred.get());
                    req.setResizeDirection(PositionConstants.EAST);
                    req.setSizeDelta(new Dimension(sizeDelta.getNegated().width, 0));
                    constrainedRequest = req;
                }
            } else if (regionContainerPropagationAllowed) {
                // resize regioncontainer from first region part resize.
                req.setEditParts(regionContainer);
                req.setResizeDirection(request.getResizeDirection());
                req.setSizeDelta(new Dimension(sizeDelta.width, 0));
                req.setMoveDelta(new Point(-sizeDelta.width, 0));
                constrainedRequest = req;
            }
        } else if (query.isResizeFromRight()) {
            if (!isLastRegionPart()) {
                Option<AbstractDiagramElementContainerEditPart> follo = getFollowingRegion();
                if (follo.some() && !request.isConstrainedResize()) {
                    req.setEditParts(follo.get());
                    req.setResizeDirection(PositionConstants.WEST);
                    req.setSizeDelta(new Dimension(-sizeDelta.width, 0));
                    req.setMoveDelta(new Point(sizeDelta.width, 0));
                    constrainedRequest = req;
                }
            } else if (regionContainerPropagationAllowed) {
                // resize regioncontainer from last region part resize.
                req.setEditParts(regionContainer);
                req.setResizeDirection(request.getResizeDirection());
                req.setSizeDelta(new Dimension(sizeDelta.width, 0));
                constrainedRequest = req;
                // Handle F3 for regions in region to allow manual layout.
                // Allow manual resize of the region container to reduce
                // empty space due to VSM specified size or recursive
                // regions.
                constrainedRequest = handleEmptySpaceInContainerOnLastRegionResize(request, constrainedRequest);
            }
        } else if (query.isResizeFromBottom() && regionContainerPropagationAllowed) {
            // resize regioncontainer.
            req.setEditParts(regionContainer);
            req.setResizeDirection(request.getResizeDirection());
            req.setSizeDelta(new Dimension(0, sizeDelta.height));
            constrainedRequest = req;
        } else if (query.isResizeFromTop() && regionContainerPropagationAllowed) {
            // resize regioncontainer from first region part resize.
            req.setEditParts(regionContainer);
            req.setResizeDirection(request.getResizeDirection());
            req.setSizeDelta(new Dimension(0, sizeDelta.height));
            req.setMoveDelta(new Point(0, -sizeDelta.height));
            constrainedRequest = req;
        }
        return constrainedRequest;
    }

    private ChangeBoundsRequest initSiblingRequest(ChangeBoundsRequest request) {
        ChangeBoundsRequest req = new ChangeBoundsRequest();
        req.setConstrainedResize(true);
        req.setConstrainedMove(true);
        req.setType(request.getType());
        req.getExtendedData().put(RegionContainerResizableEditPolicy.REGION_RESIZE_PROPAGATOR, getHost());
        req.getExtendedData().put(SiriusResizeTracker.CHILDREN_MOVE_MODE_KEY,
                request.getExtendedData().get(SiriusResizeTracker.CHILDREN_MOVE_MODE_KEY));
        req.getExtendedData().put(RegionContainerResizableEditPolicy.REGION_RESIZE_INITIAL_REQUEST, request);
        return req;
    }

    private EditPart getRegionContainerPart() {
        EditPart regionContainer = getHost().getParent();
        if (regionContainer != null) {
            regionContainer = regionContainer.getParent();
        }
        return regionContainer;
    }

    private Option<AbstractDiagramElementContainerEditPart> getPrecedingRegion() {
        List<AbstractDiagramElementContainerEditPart> siblingRegions = getSiblingRegionParts();
        int precedingIndex = siblingRegions.indexOf(getHost()) - 1;
        if (precedingIndex >= 0 && siblingRegions.size() >= precedingIndex) {
            return Options.newSome(siblingRegions.get(precedingIndex));
        }
        return Options.newNone();
    }

    private Option<AbstractDiagramElementContainerEditPart> getFollowingRegion() {
        List<AbstractDiagramElementContainerEditPart> siblingRegions = getSiblingRegionParts();
        int followingIndex = siblingRegions.indexOf(getHost()) + 1;
        if (followingIndex > 0 && siblingRegions.size() > followingIndex) {
            return Options.newSome(siblingRegions.get(followingIndex));
        }
        return Options.newNone();
    }

    private boolean concernRegion() {
        boolean regionImpacted = false;
        EditPart hostPart = getHost();
        if (hostPart instanceof AbstractDiagramElementContainerEditPart) {
            IDiagramElementEditPart ideep = (IDiagramElementEditPart) hostPart;
            DDiagramElement dde = ideep.resolveDiagramElement();
            regionImpacted = dde instanceof DDiagramElementContainer
                    && new DDiagramElementContainerExperimentalQuery((DDiagramElementContainer) dde).isRegion();
        }
        return regionImpacted;
    }

    private int getParentStackDirection() {
        int direction = PositionConstants.NONE;
        EditPart hostPart = getHost();
        if (hostPart instanceof AbstractDiagramElementContainerEditPart) {
            direction = ((AbstractDiagramElementContainerEditPart) hostPart).getParentStackDirection();
        }
        return direction;
    }

    private List<AbstractDiagramElementContainerEditPart> getSiblingRegionParts() {
        EditPart parent = getHost() != null ? getHost().getParent() : null;
        if (parent instanceof AbstractDNodeContainerCompartmentEditPart) {
            return Lists.newArrayList(
                    Iterables.filter(parent.getChildren(), AbstractDiagramElementContainerEditPart.class));
        }
        return Collections.emptyList();
    }

    private boolean isFirstRegionPart() {
        Iterable<AbstractDiagramElementContainerEditPart> regionParts = getSiblingRegionParts();
        return !Iterables.isEmpty(regionParts) && Iterables.getFirst(regionParts, null) == getHost();
    }

    private boolean isLastRegionPart() {
        Iterable<AbstractDiagramElementContainerEditPart> regionParts = getSiblingRegionParts();
        return !Iterables.isEmpty(regionParts) && Iterables.getLast(regionParts, null) == getHost();

    }

    /**
     * Specific {@link CompartmentCollapseHandle} for Regions: it locates the
     * handle on the Region label area and not in its content pane, it takes the
     * label alignment of the Region into account.
     */
    private static class RegionCollapseHandle extends CompartmentCollapseHandle {

        private AbstractDiagramElementContainerEditPart regionPart;

        /**
         * Constructor.
         * 
         * @param owner
         *            the compartment part to collapse (the part whose GMF node
         *            has the drawer style)
         * @param alignment
         *            the label alignment to take into account to correctly
         *            locate the handle.
         * @param regionPart
         *            the region part to notify when drawer syle is expanded or
         *            collapsed.
         */
        public RegionCollapseHandle(IGraphicalEditPart owner, LabelAlignment alignment,
                AbstractDiagramElementContainerEditPart regionPart) {
            super(owner);
            this.regionPart = regionPart;
            setLocator(new RegionCollapseHandleLocator(alignment));
        }

        @Override
        public void notifyChanged(Notification notification) {
            super.notifyChanged(notification);

            // Redirect the collapse notification to the Region part.
            if (NotationPackage.eINSTANCE.getDrawerStyle_Collapsed() == notification.getFeature()) {
                regionPart.notifyChanged(notification);
            }
        }

        private class RegionCollapseHandleLocator implements Locator {
            private boolean isRegionTextLeftAligned;

            public RegionCollapseHandleLocator(LabelAlignment alignment) {
                this.isRegionTextLeftAligned = LabelAlignment.LEFT.equals(alignment);
            }

            @Override
            public void relocate(IFigure target) {
                IFigure handleOwner = getOwnerFigure();
                if (handleOwner.getParent() != null) {
                    handleOwner = handleOwner.getParent();
                }

                Rectangle theBounds = handleOwner.getClientArea().getCopy();
                handleOwner.translateToAbsolute(theBounds);
                target.translateToRelative(theBounds);

                // Display the handle at the same y location
                // regarding the figure topology (list/container,
                // label style choices)
                int leftOffset = 5;
                int topOffset = 0;
                if (handleOwner instanceof DefaultSizeNodeFigure) {
                    topOffset = IContainerLabelOffsets.LABEL_OFFSET;
                } else if (handleOwner.getBorder() != null && handleOwner.getBorder().getInsets(null) != null) {
                    topOffset = IContainerLabelOffsets.LABEL_OFFSET - handleOwner.getBorder().getInsets(null).top;
                }
                if (isRegionTextLeftAligned) {
                    target.setLocation(theBounds.getTopRight().getTranslated(-getBounds().width(), topOffset));
                } else {
                    target.setLocation(theBounds.getLocation().getTranslated(leftOffset, topOffset));
                }
            }
        }
    }
}