diff options
author | Camille Letavernier | 2018-05-04 14:35:27 +0000 |
---|---|---|
committer | Nicolas FAUVERGUE | 2018-05-22 15:58:01 +0000 |
commit | 6abb6f2000f2efe7201bcdf989572fffa302a943 (patch) | |
tree | 1e2afa7cfe4b0cc9990bd71bd7d34940d5b3d141 /plugins/uml | |
parent | d4f0d45f9f3881b9313349150e37ab03a779647c (diff) | |
download | org.eclipse.papyrus-6abb6f2000f2efe7201bcdf989572fffa302a943.tar.gz org.eclipse.papyrus-6abb6f2000f2efe7201bcdf989572fffa302a943.tar.xz org.eclipse.papyrus-6abb6f2000f2efe7201bcdf989572fffa302a943.zip |
Bug 533678: [Sequence Diagram] Creation of a new InteractionOperand in a
CombinedFragment
https://bugs.eclipse.org/bugs/show_bug.cgi?id=533678
Change-Id: I4f13d706fbca0620c9d3f415718ca6533860ccf2
Signed-off-by: Camille Letavernier <cletavernier@eclipsesource.com>
Diffstat (limited to 'plugins/uml')
4 files changed, 200 insertions, 53 deletions
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java index 250a58d0d49..7b48b580c57 100644 --- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java +++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2017 CEA LIST and others. + * Copyright (c) 2017, 2018 CEA LIST, EclipseSource and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,31 +8,100 @@ * * Contributors: * CEA LIST - Initial API and implementation + * EclipseSource - Bugs 533770, 533678 * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.sequence.edit.policies; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.geometry.Dimension; +import org.eclipse.draw2d.geometry.Point; +import org.eclipse.draw2d.geometry.Rectangle; +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.commands.Command; +import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.common.core.command.ICommand; +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.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor; -import org.eclipse.gmf.runtime.notation.Bounds; -import org.eclipse.gmf.runtime.notation.Node; +import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.papyrus.infra.gmfdiag.common.adapter.NotationAndTypeAdapter; import org.eclipse.papyrus.infra.gmfdiag.common.editpolicies.DefaultCreationEditPolicy; -import org.eclipse.papyrus.uml.diagram.sequence.command.SetResizeAndLocationCommand; +import org.eclipse.papyrus.infra.services.edit.utils.RequestParameterConstants; +import org.eclipse.papyrus.uml.diagram.sequence.command.SetResizeCommand; +import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionOperandEditPart; /** * @author Patrick Tessier * @since 3.0 - * This class is used to set location and dimension for the InteractionOperand + * This class is used to set location and dimension for the InteractionOperand * */ public class CombinedCreationEditPolicy extends DefaultCreationEditPolicy { /** + * {@inheritDoc} + * + * <p> + * The {@link CombinedCreationEditPolicy} also takes the {@link RequestParameterConstants#INSERT_AT} + * parameter into account, if present, to allow creating new operands in the middle of the CF's operands + * list. + * </p> + * + * @param request + * @return + */ + @Override + protected Command getCreateCommand(CreateViewRequest request) { + Command createCommand = super.getCreateCommand(request); + if (request.getExtendedData().get(RequestParameterConstants.INSERT_AT) instanceof Integer) { + int insertAt = (Integer) request.getExtendedData().get(RequestParameterConstants.INSERT_AT); + if (insertAt >= 0) { + // The view descriptor has an index, but we can't rely on it: the descriptor is created directly + // by the palette tool, in a very generic layer, and always uses -1 as the index. + GraphicalEditPart graphicalHost = (GraphicalEditPart) getHost(); + ICommand insertAtCommand = new AbstractTransactionalCommand(graphicalHost.getEditingDomain(), "Insert view at " + insertAt, null) { + + @Override + protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { + View container = graphicalHost.getNotationView(); + EList<View> children = container.getPersistedChildren(); + List<? extends ViewDescriptor> viewDescriptors = request.getViewDescriptors(); + List<ViewDescriptor> reversedDescriptors = new ArrayList<>(viewDescriptors); + Collections.reverse(reversedDescriptors); + for (ViewDescriptor descriptor : reversedDescriptors) { + children.move(insertAt, (View) descriptor.getAdapter(View.class)); + } + return CommandResult.newOKCommandResult(); + } + }; + return new ICommandProxy(createCommand == null ? insertAtCommand : new CommandProxy(createCommand).compose(insertAtCommand).reduce()); + } + } + return createCommand; + } + + /** + * <p> + * Adds a command to properly update the CF's operand(s) sizes. This policy will + * make sure the new Operand is created "under the mouse cursor", shrinking + * the existing Operand under the mouse cursor if necessary. + * </p> + * * @see org.eclipse.papyrus.infra.gmfdiag.common.editpolicies.DefaultCreationEditPolicy#getSetBoundsCommand(org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest, org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor) * * @param request @@ -42,21 +111,96 @@ public class CombinedCreationEditPolicy extends DefaultCreationEditPolicy { @Override protected ICommand getSetBoundsCommand(CreateViewRequest request, ViewDescriptor descriptor) { TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); - Node node=(Node)((GraphicalEditPart)getHost()).getNotationView(); - int labelHeight=27; - Node combinedFragmentNode = (Node)((GraphicalEditPart)(getHost().getParent())).getNotationView(); - int y=0; - int height=((Bounds)combinedFragmentNode.getLayoutConstraint()).getHeight()-labelHeight; - for(int i=0; i<getHost().getChildren().size();i++) { - - Node currentNode=(Node)(((GraphicalEditPart)getHost().getChildren().get(i))).getNotationView(); - int previousheight=((Bounds)currentNode.getLayoutConstraint()).getHeight(); - y=y+previousheight; - height=height-previousheight; + GraphicalEditPart compartmentEditPart = (GraphicalEditPart) getHost(); + + IFigure compartmentFigure = compartmentEditPart.getFigure(); + Point locationToViewer = request.getLocation().getCopy(); // Relative to visible viewer area (Changes when scroll/zoom is applied). + + Point locationToCompartment = locationToViewer.getCopy(); // Transform to diagram coordinates (Relative to the compartment). + compartmentFigure.translateToRelative(locationToCompartment); + compartmentFigure.translateFromParent(locationToCompartment); + + final GraphicalEditPart targetOperandPart = findOperandAt(locationToCompartment, compartmentEditPart); + + // TODO Support feedback (From mouse location to the top of the next operand, or to the bottom of the CF) + + if (targetOperandPart != null) { + + final IFigure targetOperandFigure = targetOperandPart.getFigure(); + Rectangle targetOperandBounds = targetOperandFigure.getBounds(); + + Point locationToOperand = locationToViewer.getCopy(); + targetOperandFigure.translateToRelative(locationToOperand); + targetOperandFigure.translateFromParent(locationToOperand); + + // We get the size from the mouse cursor location to the bottom of the existing operand + int height = targetOperandBounds.getBottom().y() - locationToOperand.y(); + + Dimension size = new Dimension(-1, height); + ICommand setBoundsCommand = new SetResizeCommand(editingDomain, "Set dimension", descriptor, size); + + // Also reduce the size of the existing operand, to avoid shifting the entire operands stack + View view = targetOperandPart.getNotationView(); + + int siblingHeight = targetOperandPart.getFigure().getBounds().height(); + + Dimension siblingDimension = new Dimension(-1, siblingHeight - height); + ICommand reduceSiblingSizeCommand = new SetResizeCommand(editingDomain, "Set dimension", new NotationAndTypeAdapter(view.getElement(), view), siblingDimension); + return setBoundsCommand.compose(reduceSiblingSizeCommand); } - org.eclipse.draw2d.geometry.Rectangle rect= new org.eclipse.draw2d.geometry.Rectangle(0,y ,-1,height); - ICommand setBoundsCommand = new SetResizeAndLocationCommand(editingDomain, "Set dimension", descriptor, rect); + + // Shouldn't happen in a well-formed diagram, since a CF should always have at least one operand. + // If this happens, simply take all available height + Rectangle clientArea = compartmentFigure.getClientArea(); + int height = clientArea.height(); + Dimension size = new Dimension(-1, height); + ICommand setBoundsCommand = new SetResizeCommand(editingDomain, "Set dimension", descriptor, size); return setBoundsCommand; } + private static InteractionOperandEditPart findOperandAt(Point locationToCompartment, GraphicalEditPart compartmentPart) { + final EditPart targetPart = findEditPartAt(locationToCompartment, compartmentPart); + + final InteractionOperandEditPart operandEditPart; + if (targetPart instanceof InteractionOperandEditPart) { + operandEditPart = (InteractionOperandEditPart) targetPart; + } else if (targetPart != null) { + operandEditPart = findParentOperandPart(targetPart); + } else { + operandEditPart = null; + } + return operandEditPart; + } + + private static EditPart findEditPartAt(Point locationToCompartment, GraphicalEditPart compartmentPart) { + IFigure targetOperandFigure = compartmentPart.getFigure().findFigureAt(locationToCompartment); + final EditPart targetPart; + if (targetOperandFigure == null) { + targetPart = null; + } else { + EditPart partForFigure = null; + IFigure currentFigure = targetOperandFigure; + while (currentFigure != null) { + partForFigure = (EditPart) compartmentPart.getViewer().getVisualPartMap().get(currentFigure); + if (partForFigure != null) { + break; + } + currentFigure = currentFigure.getParent(); + } + targetPart = partForFigure; + } + return targetPart; + } + + private static InteractionOperandEditPart findParentOperandPart(final EditPart part) { + EditPart currentPart = part.getParent(); + while (currentPart != null) { + if (currentPart instanceof InteractionOperandEditPart) { + return (InteractionOperandEditPart) currentPart; + } + currentPart = currentPart.getParent(); + } + return null; + } + } diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/InteractionOperandLayoutEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/InteractionOperandLayoutEditPolicy.java index 7c950800336..8657f8cf122 100644 --- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/InteractionOperandLayoutEditPolicy.java +++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/InteractionOperandLayoutEditPolicy.java @@ -14,6 +14,7 @@ package org.eclipse.papyrus.uml.diagram.sequence.edit.policies; import java.util.List; +import java.util.Map; import org.eclipse.draw2d.geometry.Point; import org.eclipse.gef.EditPart; @@ -29,14 +30,15 @@ import org.eclipse.gmf.runtime.diagram.ui.editpolicies.XYLayoutEditPolicy; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeRequest; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest; +import org.eclipse.papyrus.infra.services.edit.utils.RequestParameterConstants; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionOperandGuardEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes; /** * The custom LayoutEditPolicy for InteractionOperandEditPart. -* this class has been customized to prevent the strange feedback of lifeline during the move -* + * this class has been customized to prevent the strange feedback of lifeline during the move + * */ public class InteractionOperandLayoutEditPolicy extends XYLayoutEditPolicy { @@ -65,6 +67,9 @@ public class InteractionOperandLayoutEditPolicy extends XYLayoutEditPolicy { EditPart interactionCompartment = combinedFragment.getParent(); if (REQ_CREATE.equals(request.getType()) && request instanceof CreateUnspecifiedTypeRequest) { if (UMLElementTypes.InteractionOperand_Shape.equals(((CreateUnspecifiedTypeRequest) request).getElementTypes().get(0))) { + Map<? super String, Object> extendedData = request.getExtendedData(); + int hostIndex = combinedFragmentCompartment.getChildren().indexOf(getHost()); + extendedData.put(RequestParameterConstants.INSERT_AT, hostIndex + 1); // Insert after the target return combinedFragmentCompartment.getCommand(request); } else if (UMLElementTypes.CombinedFragment_Shape.equals(((CreateUnspecifiedTypeRequest) request).getElementTypes().get(0))) { // Fixed bug about creating on InteractionOperand. (executed Twice). @@ -133,6 +138,7 @@ public class InteractionOperandLayoutEditPolicy extends XYLayoutEditPolicy { } return super.getOrphanChildrenCommand(request); } + /** * @see org.eclipse.gef.editpolicies.ConstrainedLayoutEditPolicy#createAddCommand(org.eclipse.gef.requests.ChangeBoundsRequest, org.eclipse.gef.EditPart, java.lang.Object) * @@ -143,11 +149,12 @@ public class InteractionOperandLayoutEditPolicy extends XYLayoutEditPolicy { */ @Override protected Command createAddCommand(ChangeBoundsRequest request, EditPart child, Object constraint) { - if( child instanceof LifelineEditPart) { + if (child instanceof LifelineEditPart) { return UnexecutableCommand.INSTANCE; } return super.createAddCommand(request, child, constraint); } + /** * @see org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart#showTargetFeedback(org.eclipse.gef.Request) * @@ -155,11 +162,11 @@ public class InteractionOperandLayoutEditPolicy extends XYLayoutEditPolicy { */ @Override public void showTargetFeedback(Request request) { - if(request instanceof ChangeBoundsRequest){ - ChangeBoundsRequest changeBoundsRequest= (ChangeBoundsRequest)request; + if (request instanceof ChangeBoundsRequest) { + ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) request; - if( changeBoundsRequest.getEditParts().get(0) instanceof LifelineEditPart) { - changeBoundsRequest.setMoveDelta(new Point(changeBoundsRequest.getMoveDelta().x,0)); + if (changeBoundsRequest.getEditParts().get(0) instanceof LifelineEditPart) { + changeBoundsRequest.setMoveDelta(new Point(changeBoundsRequest.getMoveDelta().x, 0)); } } super.showTargetFeedback(request); diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java index dcac8f89f5b..fb6d52f2dc0 100644 --- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java +++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java @@ -28,18 +28,10 @@ import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; -import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest; -import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest.ViewAndElementDescriptor; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; -import org.eclipse.gmf.runtime.emf.type.core.IElementType; -import org.eclipse.gmf.runtime.notation.Bounds; -import org.eclipse.gmf.runtime.notation.Node; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper; import org.eclipse.papyrus.uml.diagram.sequence.command.SetResizeCommand; -import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CInteractionOperandEditPart; -import org.eclipse.papyrus.uml.service.types.element.UMLDIElementTypes; -import org.eclipse.papyrus.uml.service.types.utils.ElementUtil; /** @@ -74,21 +66,6 @@ public class ResizeOperandEditPolicy extends GraphicalEditPolicy { */ @Override public Command getCommand(Request request) { - if (request instanceof CreateViewAndElementRequest) { - CreateViewAndElementRequest req = (CreateViewAndElementRequest) request; - ViewAndElementDescriptor descriptor = (req).getViewAndElementDescriptor(); - IElementType elementType = descriptor.getElementAdapter().getAdapter(IElementType.class); - if (ElementUtil.isTypeOf(elementType, UMLDIElementTypes.INTERACTION_OPERAND_SHAPE)) { - Node combinedFragmentNode = (Node) ((GraphicalEditPart) (getHost().getParent())).getNotationView(); - // we add a new Operand so we add the default height - int height = ((Bounds) combinedFragmentNode.getLayoutConstraint()).getHeight(); - if (getHost().getChildren().size() > 0) { - int newHeight = height + CInteractionOperandEditPart.DEFAULT_HEIGHT; - - return new ICommandProxy(new SetResizeCommand(getEditingDomain(), "set dimension", new EObjectAdapter(combinedFragmentNode), new Dimension(BoundForEditPart.getWidthFromView(combinedFragmentNode), newHeight))); - } - } - } if (RequestConstants.REQ_RESIZE_CHILDREN.equals(request.getType())) { CompositeCommand compositeCommand = new CompositeCommand("Resize Operands"); ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) request; diff --git a/plugins/uml/org.eclipse.papyrus.uml.service.types/src/org/eclipse/papyrus/uml/service/types/helper/advice/CombinedFragmentEditHelperAdvice.java b/plugins/uml/org.eclipse.papyrus.uml.service.types/src/org/eclipse/papyrus/uml/service/types/helper/advice/CombinedFragmentEditHelperAdvice.java index e02ff6e2ca4..7dcaf1ad530 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.service.types/src/org/eclipse/papyrus/uml/service/types/helper/advice/CombinedFragmentEditHelperAdvice.java +++ b/plugins/uml/org.eclipse.papyrus.uml.service.types/src/org/eclipse/papyrus/uml/service/types/helper/advice/CombinedFragmentEditHelperAdvice.java @@ -1,6 +1,6 @@ /***************************************************************************** - * Copyright (c) 2017, 2018 CEA LIST, Christian W. Damus, and others. - * + * Copyright (c) 2017, 2018 CEA LIST, Christian W. Damus, EclipseSource, 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 @@ -9,9 +9,9 @@ * Contributors: * Nicolas FAUVERGUE (CEA LIST) nicolas.fauvergue@cea.fr - Initial API and implementation * Christian W. Damus - bug 533682 - * + * EclipseSource - Bug 533678 + * *****************************************************************************/ - package org.eclipse.papyrus.uml.service.types.helper.advice; import org.eclipse.core.commands.ExecutionException; @@ -22,7 +22,10 @@ import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.emf.type.core.commands.ConfigureElementCommand; import org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice; import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest; +import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest; import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest; +import org.eclipse.papyrus.infra.services.edit.commands.InsertAtCommand; +import org.eclipse.papyrus.infra.services.edit.utils.RequestParameterConstants; import org.eclipse.papyrus.uml.tools.utils.NamedElementUtil; import org.eclipse.uml2.uml.CombinedFragment; import org.eclipse.uml2.uml.InteractionOperand; @@ -30,7 +33,7 @@ import org.eclipse.uml2.uml.UMLFactory; /** * This allows to manage the combined fragment creation with an interaction operand at the same moment. - * + * * @since 3.0 */ public class CombinedFragmentEditHelperAdvice extends AbstractEditHelperAdvice { @@ -55,6 +58,22 @@ public class CombinedFragmentEditHelperAdvice extends AbstractEditHelperAdvice { } /** + * @see org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice#getAfterCreateCommand(org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest) + * + * @param request + * @return + */ + @Override + protected ICommand getAfterCreateCommand(CreateElementRequest request) { + ICommand afterCreateCommand = super.getAfterCreateCommand(request); + if (request.getParameter(RequestParameterConstants.INSERT_AT) instanceof Integer) { + InsertAtCommand insertAtCommand = new InsertAtCommand(request); + return afterCreateCommand == null ? insertAtCommand : afterCreateCommand.compose(insertAtCommand); + } + return afterCreateCommand; + } + + /** * Create an interaction operand. */ public static InteractionOperand createInteractionOperand() { |