[571826] Add feedback and put validator in cache for Operand resize

Reuse the same pattern than the execution and frame resizes.

Bug: 571826
Change-Id: I10aaa490860db1504119d02939bcd4fe54f41d98
Signed-off-by: Maxime Porhel <maxime.porhel@obeo.fr>
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java
index 735a03f..29beaa8 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2020 THALES GLOBAL SERVICES and others.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES and others.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -16,7 +16,6 @@
 import java.util.Collection;
 import java.util.List;
 
-import org.eclipse.draw2d.ColorConstants;
 import org.eclipse.draw2d.Figure;
 import org.eclipse.draw2d.FreeformViewport;
 import org.eclipse.draw2d.IFigure;
@@ -60,7 +59,11 @@
     /**
      * The color to use for the horizontal feedback rules shown when moving/resizing an execution.
      */
-    private static final Color FRAME_FEEDBACK_COLOR = ColorConstants.lightGray;
+    private static final Color FRAME_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.ISE_FEEDBACK_COLOR;
+
+    private static final Color CONFLICT_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.CONFLICT_FEEDBACK_COLOR;
+
+    private static final Color EXPANSION_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.EXPANSION_FEEDBACK_COLOR;
 
     private Collection<Figure> guides = new ArrayList<>();
 
@@ -151,7 +154,7 @@
             screenRange.performScale(GraphicalHelper.getZoom(getHost()));
             Range expand = RangeHelper.verticalRange(screenRange);
 
-            RangeGuide expansion = new RangeGuide(validator.isValid() ? ColorConstants.blue : ColorConstants.red, expand, true);
+            RangeGuide expansion = new RangeGuide(validator.isValid() ? EXPANSION_FEEDBACK_COLOR : CONFLICT_FEEDBACK_COLOR, expand, true);
             bounds.height = expand.width();
             bounds.y = expand.getLowerBound();
             expansion.setBounds(bounds);
@@ -169,7 +172,7 @@
             bounds.y = conflictingPosition.y;
             bounds.height = 1;
 
-            HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+            HorizontalGuide conflictGuide = new HorizontalGuide(CONFLICT_FEEDBACK_COLOR, conflictingPosition.y);
             conflictGuide.setBounds(bounds);
             addFeedback(conflictGuide);
             guides.add(conflictGuide);
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java
index 98067e2..7911008 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2020 THALES GLOBAL SERVICES and others.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES and others.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -20,7 +20,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.eclipse.draw2d.ColorConstants;
 import org.eclipse.draw2d.Figure;
 import org.eclipse.draw2d.FreeformViewport;
 import org.eclipse.draw2d.IFigure;
@@ -102,7 +101,11 @@
     /**
      * The color to use for the horizontal feedback rules shown when moving/resizing an execution.
      */
-    protected static final Color EXECUTION_FEEDBACK_COLOR = ColorConstants.lightGray;
+    protected static final Color EXECUTION_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.ISE_FEEDBACK_COLOR;
+
+    private static final Color CONFLICT_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.CONFLICT_FEEDBACK_COLOR;
+
+    private static final Color EXPANSION_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.EXPANSION_FEEDBACK_COLOR;
 
     /**
      * Additional figures for feedback.
@@ -573,7 +576,7 @@
             bounds.y = conflictingPosition.y;
             bounds.height = 1;
 
-            HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+            HorizontalGuide conflictGuide = new HorizontalGuide(CONFLICT_FEEDBACK_COLOR, conflictingPosition.y);
             conflictGuide.setBounds(bounds);
             addFeedback(conflictGuide);
             guides.add(conflictGuide);
@@ -589,7 +592,7 @@
             bounds.height = expand.width();
             bounds.y = expand.getLowerBound();
 
-            RangeGuide expansion = new RangeGuide(validator.isValid() ? ColorConstants.blue : ColorConstants.red, expand, true);
+            RangeGuide expansion = new RangeGuide(validator.isValid() ? EXPANSION_FEEDBACK_COLOR : CONFLICT_FEEDBACK_COLOR, expand, true);
             expansion.setBounds(bounds);
             addFeedback(expansion);
             guides.add(expansion);
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java
index 2ab41d5..868a956 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -13,7 +13,6 @@
 package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
 
 import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.draw2d.ColorConstants;
 import org.eclipse.draw2d.IFigure;
 import org.eclipse.draw2d.PositionConstants;
 import org.eclipse.draw2d.geometry.Point;
@@ -71,9 +70,8 @@
 /**
  * A specialized semantic edit policy for sequence diagram elements.
  * <ul>
- * <li>Overrides the REQ_CONNECTION_END to invoke the appropriate message
- * creation tool with the additional variables required for its insertion at the
- * right place in the semantic model.</li>
+ * <li>Overrides the REQ_CONNECTION_END to invoke the appropriate message creation tool with the additional variables
+ * required for its insertion at the right place in the semantic model.</li>
  * <li>Shows horizontal feedback lines when an execution is moved/resized.</li>
  * </ul>
  * 
@@ -84,8 +82,8 @@
     private RangeGuide forbiddenRangeArea;
 
     /**
-     * Overridden to handle the REQ_CONNECTION_END specially as the location at
-     * which a message is created has a semantic meaning.
+     * Overridden to handle the REQ_CONNECTION_END specially as the location at which a message is created has a
+     * semantic meaning.
      * <p>
      * {@inheritDoc}
      */
@@ -185,7 +183,7 @@
                     screenRange.performScale(GraphicalHelper.getZoom(getHost()));
                     Range forbiddenRange = RangeHelper.verticalRange(screenRange);
 
-                    forbiddenRangeArea = new RangeGuide(ColorConstants.red, forbiddenRange, true);
+                    forbiddenRangeArea = new RangeGuide(SequenceInteractionFeedBackBuilder.CONFLICT_FEEDBACK_COLOR, forbiddenRange, true);
                     Rectangle bounds = layer.getBounds().getCopy();
                     bounds.height = forbiddenRange.width();
                     bounds.y = forbiddenRange.getLowerBound();
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java
index c8462f2..790be47 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2020 THALES GLOBAL SERVICES and others.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES and others.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -12,8 +12,11 @@
  *******************************************************************************/
 package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.draw2d.Figure;
 import org.eclipse.draw2d.PositionConstants;
 import org.eclipse.draw2d.geometry.Dimension;
 import org.eclipse.draw2d.geometry.Point;
@@ -40,10 +43,12 @@
 import org.eclipse.gmf.runtime.notation.Size;
 import org.eclipse.sirius.diagram.DNodeContainer;
 import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
 import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
 import org.eclipse.sirius.diagram.sequence.ui.Messages;
 import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
 import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
 import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.OperandEditPart;
 import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.OperandResizeValidator;
 import org.eclipse.sirius.diagram.sequence.ui.tool.internal.ui.SequenceDragEditPartsTrackerEx.SequenceCacheDragTrackerHelper;
@@ -52,7 +57,10 @@
 import org.eclipse.sirius.diagram.ui.graphical.edit.policies.AirResizableEditPolicy;
 import org.eclipse.sirius.diagram.ui.graphical.edit.policies.SiriusResizeTracker;
 import org.eclipse.sirius.ext.base.Option;
+import org.eclipse.sirius.ext.draw2d.figure.HorizontalGuide;
+import org.eclipse.swt.graphics.Color;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 
 /**
@@ -63,6 +71,15 @@
 public class OperandResizableEditPolicy extends AirResizableEditPolicy {
 
     /**
+     * The color to use for the horizontal feedback rules shown when moving/resizing an execution.
+     */
+    private static final Color OPERAND_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.ISE_FEEDBACK_COLOR;
+
+    private static final String OPERAND_RESIZE_VALIDATOR = "org.eclipse.sirius.sequence.resize.operand.validator"; //$NON-NLS-1$
+
+    private Collection<Figure> guides = new ArrayList<>();
+
+    /**
      * Constructor.
      */
     public OperandResizableEditPolicy() {
@@ -86,8 +103,7 @@
         cancelHorizontalDelta(request);
 
         OperandEditPart oep = (OperandEditPart) getHost();
-        OperandResizeValidator operandResizeValidator = new OperandResizeValidator((Operand) oep.getISequenceEvent(), new RequestQuery(request));
-        operandResizeValidator.validate();
+        OperandResizeValidator operandResizeValidator = getOrCreateResizeValidator(request, (Operand) oep.getISequenceEvent());
 
         Command result;
         if (operandResizeValidator.isValid()) {
@@ -337,12 +353,42 @@
      */
     @Override
     protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+        eraseChangeBoundsFeedback(request);
+
         cancelHorizontalDelta(request);
         RequestQuery query = new RequestQuery(request);
         if (query.isMove()) {
             cancelVerticalDelta(request);
         }
+
+        cancelHorizontalDelta(request);
+
         super.showChangeBoundsFeedback(request);
+
+        ISequenceEventEditPart hostPart = (ISequenceEventEditPart) getHost();
+        RequestQuery requestQuery = new RequestQuery(request);
+
+        ISequenceEvent operand = hostPart.getISequenceEvent();
+        if (hostPart.getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isResize()) {
+            if (operand instanceof Operand) {
+                OperandResizeValidator validator = getOrCreateResizeValidator(request, (Operand) operand);
+
+                boolean valid = validator.isValid();
+                Range finalRange = validator.getFinalRange();
+                int y = requestQuery.isResizeFromTop() ? finalRange.getLowerBound() : finalRange.getUpperBound();
+                Color color = valid ? OPERAND_FEEDBACK_COLOR : SequenceInteractionFeedBackBuilder.CONFLICT_FEEDBACK_COLOR;
+
+                Figure guide = new HorizontalGuide(color, y);
+                Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+                bounds.height = 1;
+                bounds.y = y;
+                guide.setBounds(bounds);
+                addFeedback(guide);
+                guides.add(guide);
+
+            }
+        }
+
     }
 
     /**
@@ -377,4 +423,50 @@
         };
     }
 
+    /**
+     * Get the validator from the request extended data or a new one.
+     * 
+     * @param cbr
+     *            the current resize request.
+     * @param host
+     *            the host operand
+     * @return a validator.
+     */
+    public static OperandResizeValidator getOrCreateResizeValidator(ChangeBoundsRequest cbr, Operand host) {
+        RequestQuery requestQuery = new RequestQuery(cbr);
+        Preconditions.checkArgument(requestQuery.isResize());
+        OperandResizeValidator validator = null;
+        Object object = cbr.getExtendedData().get(OPERAND_RESIZE_VALIDATOR);
+        if (object instanceof OperandResizeValidator) {
+            validator = (OperandResizeValidator) object;
+            if (!validator.getRequestQuery().getLogicalDelta().equals(requestQuery.getLogicalDelta())) {
+                validator = null;
+            }
+        }
+
+        if (validator == null && requestQuery.isResize()) {
+            validator = new OperandResizeValidator(host, requestQuery);
+            cbr.getExtendedData().put(OPERAND_RESIZE_VALIDATOR, validator);
+        }
+        return validator;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void eraseChangeBoundsFeedback(ChangeBoundsRequest request) {
+        removeFeedBackOnGuides();
+        super.eraseChangeBoundsFeedback(request);
+    }
+
+    private void removeFeedBackOnGuides() {
+        if (guides != null && !guides.isEmpty()) {
+            for (Figure hGuide : guides) {
+                removeFeedback(hGuide);
+            }
+            guides.clear();
+        }
+    }
+
 }
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java
index 819f16d..de737eb 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -39,11 +39,21 @@
  * @author mporhel
  */
 public class SequenceInteractionFeedBackBuilder {
+
     /**
-     * The color to use for the horizontal feedback rules shown when
-     * moving/resizing an ISequencEvent.
+     * The color to use for the horizontal feedback rules shown when moving/resizing an ISequencEvent.
      */
-    private static final Color ISE_FEEDBACK_COLOR = ColorConstants.lightGray;
+    public static final Color ISE_FEEDBACK_COLOR = ColorConstants.lightGray;
+
+    /**
+     * The color to use for the horizontal feedback rules shown when an expansion is triggered.
+     */
+    public static final Color EXPANSION_FEEDBACK_COLOR = ColorConstants.blue;
+
+    /**
+     * The color to use for the horizontal feedback rules shown when there command is not valid.
+     */
+    public static final Color CONFLICT_FEEDBACK_COLOR = ColorConstants.red;
 
     private final AbstractSequenceInteractionValidator validator;
 
@@ -102,8 +112,8 @@
             Rectangle bounds = feedBackLayer.getBounds().getCopy();
             bounds.y = conflictingPosition.y;
             bounds.height = 1;
-            
-            HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+
+            HorizontalGuide conflictGuide = new HorizontalGuide(CONFLICT_FEEDBACK_COLOR, conflictingPosition.y);
             conflictGuide.setBounds(bounds);
             feedbacks.add(conflictGuide);
         }
@@ -117,7 +127,7 @@
             bounds.y = conflictRange.getLowerBound();
             bounds.height = Math.max(1, conflictRange.width());
 
-            RangeGuide guide = new RangeGuide(ColorConstants.red, conflictRange, true);
+            RangeGuide guide = new RangeGuide(CONFLICT_FEEDBACK_COLOR, conflictRange, true);
             guide.setBounds(bounds);
             feedbacks.add(guide);
         }
@@ -125,7 +135,7 @@
 
     private void feedBackErrors(Collection<Figure> feedbacks) {
         for (ISequenceEvent errorEvent : validator.getEventsInError()) {
-            addFeedBack(errorEvent, ColorConstants.red, true, feedbacks, validator.getRangeFunction().apply(errorEvent));
+            addFeedBack(errorEvent, CONFLICT_FEEDBACK_COLOR, true, feedbacks, validator.getRangeFunction().apply(errorEvent));
         }
     }
 
@@ -158,7 +168,7 @@
             screenRange.performScale(GraphicalHelper.getZoom(hostPart));
             Range expand = RangeHelper.verticalRange(screenRange);
 
-            RangeGuide expansion = new RangeGuide(validator.isValid() ? ColorConstants.blue : ColorConstants.red, expand, true);
+            RangeGuide expansion = new RangeGuide(validator.isValid() ? EXPANSION_FEEDBACK_COLOR : CONFLICT_FEEDBACK_COLOR, expand, true);
             bounds.height = expand.width();
             bounds.y = expand.getLowerBound();
             expansion.setBounds(bounds);
@@ -175,7 +185,7 @@
 
     private void feedBackCreatedElements(Collection<Figure> feedbacks) {
         for (Range creationRange : validator.getCreatedElements()) {
-            addFeedBack(null, validator.isValid() ? ISE_FEEDBACK_COLOR : ColorConstants.red, false, feedbacks, creationRange);
+            addFeedBack(null, validator.isValid() ? ISE_FEEDBACK_COLOR : CONFLICT_FEEDBACK_COLOR, false, feedbacks, creationRange);
         }
     }
 
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java
index c9c2960..10bd41d 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2019 THALES GLOBAL SERVICES and others.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES and others.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -17,7 +17,6 @@
 import java.util.Collection;
 import java.util.List;
 
-import org.eclipse.draw2d.ColorConstants;
 import org.eclipse.draw2d.Cursors;
 import org.eclipse.draw2d.Figure;
 import org.eclipse.draw2d.PositionConstants;
@@ -93,9 +92,8 @@
 import com.google.common.collect.Lists;
 
 /**
- * Specialized edit policy for sequence diagrams messages: tracks graphical
- * reordering and invokes user-specified reordering tool to reflect the changes
- * in the semantic model.
+ * Specialized edit policy for sequence diagrams messages: tracks graphical reordering and invokes user-specified
+ * reordering tool to reflect the changes in the semantic model.
  * <p>
  * This edit policy should only be installed on SequenceMessageEditParts.
  * 
@@ -109,10 +107,9 @@
     public static final String REQUEST_FROM_SEQUENCE_MESSAGE_EDIT_POLICY = "org.eclipse.sirius.sequence.resize.execution.from.bendpoint.request"; //$NON-NLS-1$
 
     /**
-     * The color top use for the horizontal feedback rules shown when moving a
-     * message.
+     * The color top use for the horizontal feedback rules shown when moving a message.
      */
-    private static final Color MESSAGE_FEEDBACK_COLOR = ColorConstants.lightGray;
+    private static final Color MESSAGE_FEEDBACK_COLOR = SequenceInteractionFeedBackBuilder.ISE_FEEDBACK_COLOR;
 
     private final Collection<Figure> guides = new ArrayList<>();
 
@@ -138,9 +135,8 @@
     @Override
     protected void addInvisibleCreationHandle(List list, ConnectionEditPart connEP, int i) {
         /*
-         * Do nothing: the handles created by default use a raw GEF drag tracker
-         * which we do not control, and which can lead to disconnections of
-         * branches on reflective messages.
+         * Do nothing: the handles created by default use a raw GEF drag tracker which we do not control, and which can
+         * lead to disconnections of branches on reflective messages.
          */
     }
 
@@ -208,7 +204,7 @@
                     Point conflictingPosition = new Point(0, conflict);
                     conflictingPosition.performScale(GraphicalHelper.getZoom(getHost()));
 
-                    HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+                    HorizontalGuide conflictGuide = new HorizontalGuide(SequenceInteractionFeedBackBuilder.CONFLICT_FEEDBACK_COLOR, conflictingPosition.y);
                     bounds.y = conflictingPosition.y;
                     bounds.height = 1;
                     conflictGuide.setBounds(bounds);
@@ -274,8 +270,7 @@
     }
 
     /**
-     * Moving a create message up and down will also show the feedback of the
-     * targeted instance role.
+     * Moving a create message up and down will also show the feedback of the targeted instance role.
      * 
      * @param request
      *            the "create message" move request
@@ -313,8 +308,7 @@
     }
 
     /**
-     * Moving a destroy message up and down will also show the feedback of the
-     * targeted end of life.
+     * Moving a destroy message up and down will also show the feedback of the targeted end of life.
      * 
      * @param request
      *            the "create message" move request
@@ -367,8 +361,7 @@
     }
 
     /**
-     * Change the place of the message in the semantic model if the new
-     * graphical positions requires it.
+     * Change the place of the message in the semantic model if the new graphical positions requires it.
      * <p>
      * {@inheritDoc}
      */
@@ -401,7 +394,8 @@
             result = UnexecutableCommand.INSTANCE;
         } else {
             String label = baseCommand.getLabel();
-            CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(thisEvent.getEditingDomain(), MessageFormat.format(Messages.SequenceMessageEditPolicy_synchronizeOrderingCompositeCommand, label != null ? label : "<null>")); //$NON-NLS-1$
+            CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(thisEvent.getEditingDomain(),
+                    MessageFormat.format(Messages.SequenceMessageEditPolicy_synchronizeOrderingCompositeCommand, label != null ? label : "<null>")); //$NON-NLS-1$
             SequenceEditPartsOperations.appendFullRefresh(thisEvent, ctc);
 
             MoveType move = getMoveType(thisEvent, request, ends);
@@ -410,8 +404,7 @@
                 thisEvent.setCursor(Cursors.SIZENS);
             } else {
                 /*
-                 * Overridden to handle lifeline move/resize when moving the
-                 * selected create/destroy message.
+                 * Overridden to handle lifeline move/resize when moving the selected create/destroy message.
                  */
                 if (thisEvent.getTarget() instanceof InstanceRoleEditPart) {
                     ctc.compose(getMoveCreateMessageCommand(request, thisEvent, baseCommand));
@@ -656,16 +649,14 @@
     }
 
     /**
-     * Overridden to resize the targeted RoteExecitionEditPart when moving the
-     * selected destroy message.
+     * Overridden to resize the targeted RoteExecitionEditPart when moving the selected destroy message.
      * 
      * @param baseCommand
      * @param smep
      * 
      * @param request
      *            the current request
-     * @return a compound command if the destroy message is moved, the super
-     *         command otherwise
+     * @return a compound command if the destroy message is moved, the super command otherwise
      */
     private AbstractEMFOperation getMoveDestroyMessageCommand(BendpointRequest br, SequenceMessageEditPart smep, Command baseCommand) {
         CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(smep.getEditingDomain(), Messages.SequenceMessageEditPolicy_moveCreateMessageCommand);
@@ -712,14 +703,12 @@
     }
 
     /**
-     * Overridden to move the targeted InstanceRoleEditPart when moving the
-     * selected create message.
+     * Overridden to move the targeted InstanceRoleEditPart when moving the selected create message.
      * 
      * @param request
      *            the current request
      * @param baseCommand
-     * @return a compound command if the create message is moved, the super
-     *         command otherwise
+     * @return a compound command if the create message is moved, the super command otherwise
      */
     private AbstractEMFOperation getMoveCreateMessageCommand(BendpointRequest request, SequenceMessageEditPart smep, Command baseCommand) {
         Point normalizedLocation = request.getLocation().getCopy();
@@ -752,11 +741,9 @@
         cc.compose(new CommandProxy(baseCommand));
 
         /*
-         * These additional commands adjust the positions of the executions and
-         * messages on the lifeline so that visually they do not move. They are
-         * dual to the commands we add when moving a normal execution, as in
-         * that case we want all the executions and messages it contains to move
-         * along.
+         * These additional commands adjust the positions of the executions and messages on the lifeline so that
+         * visually they do not move. They are dual to the commands we add when moving a normal execution, as in that
+         * case we want all the executions and messages it contains to move along.
          */
         final LifelineEditPart lep = EditPartsHelper.getAllLifelines(instanceRoleEditPart).get(0);
 
@@ -772,8 +759,8 @@
     private void updateMovingTargetReferencePoint(Command baseCommand, final ChangeBoundsRequest cbr) {
         if (baseCommand instanceof ICommandProxy && ((ICommandProxy) baseCommand).getICommand() instanceof SetConnectionBendpointsCommand) {
             /*
-             * Update target reference point of the SetConnectionBendpoint base
-             * command to take into account he move ot the instance role.
+             * Update target reference point of the SetConnectionBendpoint base command to take into account he move ot
+             * the instance role.
              */
             SetConnectionBendpointsCommand scbc = (SetConnectionBendpointsCommand) ((ICommandProxy) baseCommand).getICommand();
             scbc.setNewPointList(scbc.getNewPointList(), scbc.getSourceRefPoint(), scbc.getTargetRefPoint().getCopy().getTranslated(cbr.getMoveDelta()));
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java
index f462d33..2559fba 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -40,10 +40,9 @@
 import com.google.common.collect.Lists;
 
 /**
- * This class is responsible to check whether a request on an interaction use
- * should be accepted (i.e. it would produce a well-formed diagram). While doing
- * the validation, it also stores all the relevant information required to
- * actually perform the interaction properly.
+ * This class is responsible to check whether a request on an interaction use should be accepted (i.e. it would produce
+ * a well-formed diagram). While doing the validation, it also stores all the relevant information required to actually
+ * perform the interaction properly.
  * 
  * @author mporhel
  */
@@ -126,8 +125,7 @@
      * Constructor.
      * 
      * @param frame
-     *            the interaction use or combined fragment which will be
-     *            resized.
+     *            the interaction use or combined fragment which will be resized.
      * @param requestQuery
      *            a query on the request targeting the execution.
      */
@@ -141,8 +139,7 @@
     }
 
     /**
-     * Return the validation status. Validate the request result in the first
-     * call only.
+     * Return the validation status. Validate the request result in the first call only.
      * 
      * @return the validation status.
      */
@@ -159,9 +156,8 @@
     }
 
     /**
-     * Performs all the computations required to validate the resizing, and
-     * stores any important information which will be useful to actually execute
-     * the resize if it is valid, like for example avoid contact with siblings.
+     * Performs all the computations required to validate the resizing, and stores any important information which will
+     * be useful to actually execute the resize if it is valid, like for example avoid contact with siblings.
      */
     protected void validate() {
         valid = checkAndComputeRanges();
@@ -205,8 +201,7 @@
     }
 
     /**
-     * Computes, checks and stores the initial and final range of the
-     * interaction use if the resize is performed.
+     * Computes, checks and stores the initial and final range of the interaction use if the resize is performed.
      */
     private boolean checkAndComputeRanges() {
         // Proper range
@@ -223,10 +218,9 @@
     }
 
     /**
-     * Resizing an interaction use can not change which parents it is on, and
-     * can not have any impact on that parents's ranges, so the final range of
-     * the interaction use after the resize must be strictly included in the
-     * ranges of the parents.
+     * Resizing an interaction use can not change which parents it is on, and can not have any impact on that parents's
+     * ranges, so the final range of the interaction use after the resize must be strictly included in the ranges of the
+     * parents.
      */
     private boolean checkFinalRangeStrictlyIncludedInParents(Collection<ISequenceEvent> parentEvents) {
         boolean checked = true;
@@ -241,8 +235,8 @@
                 parentRange = new Range(parentRange.getLowerBound(), parentRange.getUpperBound() + expansionZone.width());
             }
             /*
-             * We make two tests separately so that is is easier when debugging
-             * to determine which of the conditions went wrong, if any.
+             * We make two tests separately so that is is easier when debugging to determine which of the conditions
+             * went wrong, if any.
              */
             boolean interactionInRange = parentRange.includes(finalRange.grown(LayoutConstants.EXECUTION_CHILDREN_MARGIN));
             checked = checked && interactionInRange;
@@ -347,7 +341,7 @@
      * @param cbr
      *            the current resize request.
      * @param host
-     *            the host execution
+     *            the host frame
      * @return a validator.
      */
     public static AbstractInteractionFrameValidator getOrCreateResizeValidator(ChangeBoundsRequest cbr, AbstractFrame host) {
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java
index 044d806..6809ff8 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * Copyright (c) 2010, 2021 THALES GLOBAL SERVICES.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -24,9 +24,8 @@
 import org.eclipse.sirius.ext.base.Options;
 
 /**
- * This class is responsible to check whether a request on an operand should be
- * accepted (i.e. it would produce a well-formed diagram). While doing the
- * validation, it also stores all the relevant information required to actually
+ * This class is responsible to check whether a request on an operand should be accepted (i.e. it would produce a
+ * well-formed diagram). While doing the validation, it also stores all the relevant information required to actually
  * perform the interaction properly.
  * 
  * @author smonnier
@@ -56,7 +55,9 @@
 
     private Range finalSiblingOperandRange;
 
-    private boolean valid;
+    private boolean valid = true;
+
+    private boolean initialized;
 
     /**
      * Constructor.
@@ -78,7 +79,16 @@
         }
     }
 
-    public boolean isValid() {
+    /**
+     * Return the validation status. Validate the request result in the first call only.
+     * 
+     * @return the validation status.
+     */
+    public final boolean isValid() {
+        if (!initialized) {
+            validate();
+            initialized = true;
+        }
         return valid;
     }
 
@@ -87,19 +97,17 @@
     }
 
     /**
-     * Performs all the computations required to validate the resizing, and
-     * stores any important information which will be useful to actually execute
-     * the resize if it is valid, like for example avoid contact with siblings.
+     * Performs all the computations required to validate the resizing, and stores any important information which will
+     * be useful to actually execute the resize if it is valid, like for example avoid contact with siblings.
      */
-    public void validate() {
+    protected void validate() {
         valid = checkAndComputeRanges();
 
         valid = valid && checkContainedISequenceEvent();
     }
 
     /**
-     * Computes, checks and stores the initial and final range of the operand if
-     * the resize is performed.
+     * Computes, checks and stores the initial and final range of the operand if the resize is performed.
      */
     private boolean checkAndComputeRanges() {
         boolean result = true;
@@ -109,6 +117,7 @@
 
         if (newBounds.height < LayoutConstants.DEFAULT_OPERAND_HEIGHT) {
             result = false;
+            finalOperandRange = RangeHelper.verticalRange(newBounds);
         } else {
             // The current operand new range is valid, we can check the sibling
             // operand
@@ -151,4 +160,8 @@
         }
         return bounds.getCopy().translate(moveDelta).resize(sizeDelta);
     }
+
+    public RequestQuery getRequestQuery() {
+        return requestQuery;
+    }
 }