blob: 9a5e9f74f683e04dd269a42fe3a44ba3b11c6e6b [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.emf.type.core.edithelper;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.IdentityCommand;
import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry;
import org.eclipse.gmf.runtime.emf.type.core.IContainerDescriptor;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;
import org.eclipse.gmf.runtime.emf.type.core.commands.CreateElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.CreateRelationshipCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.DestroyElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.DestroyReferenceCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.GetEditContextCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.MoveElementsCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.SetValueCommand;
import org.eclipse.gmf.runtime.emf.type.core.internal.impl.EClassUtil;
import org.eclipse.gmf.runtime.emf.type.core.internal.requests.RequestCacheEntries;
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.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyDependentsRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyReferenceRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DuplicateElementsRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.GetEditContextRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.MoveRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientReferenceRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
/**
* Abstract edit helper implementation. Implements the default edit command
* algorithm, which returns a composite command containing the following:
* <OL>
* <LI>'before' commands from matching element types and specializations</LI>
* <LI>'instead' command from this edit helper</LI>
* <LI>'after' commands from matching element types and specializations</LI>
* </OL>
* <P>
* The before and after commands are obtained by consulting the edit helper advice that
* is bound to the edit helper context in the edit request. Edit helper advice can
* be inherited from supertypes.
* <P>
* Clients should subclass this class when creating new edit helpers.
*
* @author ldamus
*/
public abstract class AbstractEditHelper
implements IEditHelper {
/**
* Map of the default containment features keyed on EClass. Each value is an
* EReference.
*/
private Map defaultContainmentFeatures = new HashMap();
/**
* Checks that I can get an executable edit command.
* <P>
* Subclasses should override if they have a different way to decide whether
* or not the edit is allowed.
*/
public boolean canEdit(IEditCommandRequest req) {
// Get the matching edit helper advice
IEditHelperAdvice[] advice = getEditHelperAdvice(req);
// Consult advisors to allow them to configure the request
configureRequest(req, advice);
// Consult advisors to allow them approve the request
boolean approved = approveRequest(req, advice);
if (!approved) {
return false;
}
ICommand command = getEditCommand(req, advice);
return command != null && command.canExecute();
}
/**
* Builds and returns the edit command, which is a composite command
* containing the following:
* <OL>
* <LI>'before' commands from matching element type specializations</LI>
* <LI>'instead' command from this edit helper</LI>
* <LI>'after' commands from matching element type specializations</LI>
* </OL>
* <P>
* Verifies that the edit request is approved before constructing the edit
* command.
*/
public ICommand getEditCommand(IEditCommandRequest req) {
// Get the matching edit helper advice
IEditHelperAdvice[] advice = getEditHelperAdvice(req);
// Consult advisors to allow them to configure the request
configureRequest(req, advice);
// Consult advisors to allow them approve the request
boolean approved = approveRequest(req, advice);
if (!approved) {
return null;
}
ICommand result = getEditCommand(req, advice);
if (result != null) {
return result.reduce();
}
return result;
}
/**
* Template method that implements the default edit command algorithm, which
* returns a composite command containing the following:
* <OL>
* <LI>'before' commands from matching element type specializations</LI>
* <LI>'instead' command from this edit helper</LI>
* <LI>'after' commands from matching element type specializations</LI>
* </OL>
*/
private ICommand getEditCommand(IEditCommandRequest req, IEditHelperAdvice[] advice) {
ICompositeCommand command = createCommand(req);
// Get 'before' commands from matching element type
// specializations
if (advice != null) {
for (int i = 0; i < advice.length; i++) {
IEditHelperAdvice nextAdvice = advice[i];
// Before commands
ICommand beforeAdvice = nextAdvice.getBeforeEditCommand(req);
if (beforeAdvice != null) {
if (beforeAdvice.canExecute()) {
command.compose(beforeAdvice);
} else {
return beforeAdvice;
}
}
}
}
// Check if the parameter has been set to ignore the default edit command.
Object replaceParam = req
.getParameter(IEditCommandRequest.REPLACE_DEFAULT_COMMAND);
if (replaceParam != Boolean.TRUE) {
// Get 'instead' command from this edit helper
ICommand insteadCommand = getInsteadCommand(req);
if (insteadCommand != null) {
if (insteadCommand.canExecute()) {
command.compose(insteadCommand);
} else {
return insteadCommand;
}
}
}
// Get 'after' commands from matching element type
// specializations
if (advice != null) {
for (int i = 0; i < advice.length; i++) {
IEditHelperAdvice nextAdvice = advice[i];
// After commands
ICommand afterAdvice = nextAdvice.getAfterEditCommand(req);
if (afterAdvice != null) {
if (afterAdvice.canExecute()) {
command.compose(afterAdvice);
} else {
return afterAdvice;
}
}
}
}
return command.isEmpty() ? null
: command;
}
/**
* Template method that consults the edit helper advice to configure the
* edit request.
*
* @param req
* the edit request
* @param advice
* array of applicable edit helper advice
*/
private void configureRequest(IEditCommandRequest req,
IEditHelperAdvice[] advice) {
if (advice != null) {
for (int i = 0; i < advice.length; i++) {
IEditHelperAdvice nextAdvice = advice[i];
nextAdvice.configureRequest(req);
}
}
// All advice has configured the request. Now consult this edit helper.
configureRequest(req);
}
/**
* Template method that consults the edit helper advice to see whether or
* not they approve the request. If all advice approves the request, then
* {@link #approveRequest(IEditCommandRequest)} is called to determine if
* this edit helper approves the request.
*
* @param req
* the edit request
* @param advice
* array of applicable edit helper advice
* @return <code>true</code> if the edit request is approved,
* <code>false</code> otherwise. No edit command will be
* constructed if the request is not approved.
*/
private boolean approveRequest(IEditCommandRequest req,
IEditHelperAdvice[] advice) {
if (advice != null) {
for (int i = 0; i < advice.length; i++) {
IEditHelperAdvice nextAdvice = advice[i];
boolean approved = nextAdvice.approveRequest(req);
if (!approved) {
// An advice doesn't approve this request
return false;
}
}
}
// All advice has approved the request. Now consult this edit helper.
return approveRequest(req);
}
/**
* Approves the edit gesture described in the <code>request</code>. This
* method will be consulted before the edit request is approved.
* <P>
* The default implementation does nothing. Subclasses should override if
* they wish to change the request parameters.
*
* @param request
* the edit request
*/
protected void configureRequest(IEditCommandRequest request) {
// does nothing, by default
}
/**
* Approves the edit gesture described in the <code>request</code>. This
* method will be consulted before the edit command is constructed.
* <P>
* The default implementation returns <code>true</code>. Subclasses
* should override if they wish to provide a different answer.
*
* @param req
* the edit request
* @return <code>true</code> if the edit request is approved,
* <code>false</code> otherwise. No edit command will be
* constructed if the request is not approved.
*/
protected boolean approveRequest(IEditCommandRequest request) {
return true;
}
/**
* Gets the array of edit helper advice for this request.
*
* @param req the edit request
* @return the edit helper advice, or <code>null</code> if there is none
*/
protected IEditHelperAdvice[] getEditHelperAdvice(IEditCommandRequest req) {
IEditHelperAdvice[] advices = null;
Object editHelperContext = req.getEditHelperContext();
Map cacheMaps = (Map) req
.getParameter(RequestCacheEntries.Cache_Maps);
if (cacheMaps != null) {
Map contextMap = (Map) cacheMaps.get(editHelperContext);
if (contextMap != null) {
advices = (IEditHelperAdvice[]) contextMap.get(RequestCacheEntries.EditHelper_Advice);
}
}
if (advices == null) {
advices = ElementTypeRegistry.getInstance().getEditHelperAdvice(
editHelperContext);
}
return advices;
}
/**
* Creates a new composite command.
* <P>
* Subclasses may override to provide their own kind of composite command.
*
* @param req the edit request
* @return a new composite command
*/
protected ICompositeCommand createCommand(IEditCommandRequest req) {
CompositeTransactionalCommand result = new CompositeTransactionalCommand(
req.getEditingDomain(), req.getLabel()) {
/**
* Extracts the first return value out of the collection of return
* values from the superclass command result.
*/
public CommandResult getCommandResult() {
CommandResult _result = super.getCommandResult();
IStatus status = (_result == null) ? null : _result.getStatus();
if (status != null && status.getSeverity() == IStatus.OK) {
Object returnObject = null;
Object returnValue = _result.getReturnValue();
if (returnValue instanceof Collection) {
Collection collection = (Collection) returnValue;
if (!collection.isEmpty()) {
returnObject = collection.iterator().next();
}
} else {
returnObject = returnValue;
}
_result = new CommandResult(status, returnObject);
}
return _result;
};
};
// commands (esp. destroy) are expected to be large nested structures,
// because there can be many discrete particles of advice
result.setTransactionNestingEnabled(false);
return result;
}
/**
* Gets my command to do the work described in <code>req</code>.
* <P>
* Delegates to the more specific methods in this class to actually get the
* command. Subclasses should override these more specific methods.
*
* @param req
* the edit request
* @return the command to do the requested work, or <code>null</code> if I
* don't support the requested work.
*/
protected ICommand getInsteadCommand(IEditCommandRequest req) {
if (req instanceof CreateRelationshipRequest) {
initializeDefaultFeature((CreateElementRequest) req);
return getCreateRelationshipCommand((CreateRelationshipRequest) req);
} else if (req instanceof CreateElementRequest) {
initializeDefaultFeature((CreateElementRequest) req);
return getCreateCommand((CreateElementRequest) req);
} else if (req instanceof ConfigureRequest) {
return getConfigureCommand((ConfigureRequest) req);
} else if (req instanceof DestroyElementRequest) {
return getDestroyElementCommand((DestroyElementRequest) req);
} else if (req instanceof DestroyDependentsRequest) {
return getDestroyDependentsCommand((DestroyDependentsRequest) req);
} else if (req instanceof DestroyReferenceRequest) {
return getDestroyReferenceCommand((DestroyReferenceRequest) req);
} else if (req instanceof DuplicateElementsRequest) {
return getDuplicateCommand((DuplicateElementsRequest) req);
} else if (req instanceof GetEditContextRequest) {
return getEditContextCommand((GetEditContextRequest) req);
} else if (req instanceof MoveRequest) {
return getMoveCommand((MoveRequest) req);
} else if (req instanceof ReorientReferenceRelationshipRequest) {
return getReorientReferenceRelationshipCommand((ReorientReferenceRelationshipRequest) req);
} else if (req instanceof ReorientRelationshipRequest) {
return getReorientRelationshipCommand((ReorientRelationshipRequest) req);
} else if (req instanceof SetRequest) {
return getSetCommand((SetRequest) req);
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gmf.runtime.emf.core.type.IEditHelper#getContainedValues(org.eclipse.emf.ecore.EObject,
* org.eclipse.emf.ecore.EReference)
*/
public List getContainedValues(EObject eContainer, EReference feature) {
return Arrays.asList(ElementTypeRegistry.getInstance()
.getContainedTypes(eContainer, feature));
}
/**
* Gets the command to configure a new element of my kind. By default,
* returns <code>null</code>. Subclasses may override to provide their
* command.
*
* @param req
* the configure request
* @return the configure command
*/
protected ICommand getConfigureCommand(ConfigureRequest req) {
return null;
}
/**
* Gets the command to create a new relationship in an element of my kind.
* <P>
* Returns the {@link IdentityCommand} if the request does not have a source
* or a target. This ensures that the create relationship gesture is enabled
* until the request can be completely specified.
* <P>
* Subclasses may override to provide their own command.
*
* @param req
* the create relationship request
* @return the create relationship command
*/
protected ICommand getCreateRelationshipCommand(
CreateRelationshipRequest req) {
EObject source = req.getSource();
EObject target = req.getTarget();
boolean noSourceOrTarget = (source == null || target == null);
boolean noSourceAndTarget = (source == null && target == null);
if (noSourceOrTarget && !noSourceAndTarget) {
// The request isn't complete yet. Return the identity command so
// that the create relationship gesture is enabled.
return IdentityCommand.INSTANCE;
}
return new CreateRelationshipCommand(req);
}
/**
* Gets the command to create a new element in an element of my kind.
* Subclasses may override to provide their command.
*
* @param req
* the create request
* @return the create command
*/
protected ICommand getCreateCommand(CreateElementRequest req) {
return new CreateElementCommand(req);
}
/**
* Sets the default feature in <code>req</code>, if there is no
* containment feature already in the request.
*
* @param req
* the create request
*/
public void initializeDefaultFeature(CreateElementRequest req) {
if (req.getContainmentFeature() == null) {
// First, try to find the feature from the element type
ISpecializationType specializationType = (ISpecializationType) req.getElementType().getAdapter(ISpecializationType.class);
if (specializationType != null) {
IContainerDescriptor containerDescriptor = specializationType.getEContainerDescriptor();
if (containerDescriptor != null) {
EReference[] features = containerDescriptor
.getContainmentFeatures();
if (features != null) {
for (int i = 0; i < features.length; i++) {
Object editHelperContext = req
.getEditHelperContext();
EClass eClass = null;
if (editHelperContext instanceof EClass) {
eClass = (EClass) editHelperContext;
} else if (editHelperContext instanceof EObject) {
eClass = ((EObject) editHelperContext).eClass();
} else if (editHelperContext instanceof IElementType) {
eClass = ((IElementType) editHelperContext)
.getEClass();
}
if (eClass != null
&& eClass.getEAllReferences().contains(
features[i])) {
// Use the first feature
req.initializeContainmentFeature((features[i]));
return;
}
}
}
}
}
// Next, try to get a default feature
EClass eClass = req.getElementType().getEClass();
if (eClass != null) {
req.initializeContainmentFeature(getDefaultContainmentFeature(eClass));
}
}
}
/**
* Gets the default feature to contain the <code>eClass</code>.
* <P>
* Returns <code>null</code> by default. Subclasses should override to
* provide the default feature, if there is one.
*
* @param eClass
* the EClass
* @return the default feature
*/
protected EReference getDefaultContainmentFeature(EClass eClass) {
EReference result = (EReference) getDefaultContainmentFeatures().get(
eClass);
if (result == null) {
// Bugzilla 298661: assume all models implicitly extend EObject
List superTypes = EClassUtil.getEAllSuperTypes(eClass);
Collections.reverse(superTypes);
Iterator i = superTypes.iterator();
while (i.hasNext() && result == null) {
EClass nextSuperType = (EClass) i.next();
result = (EReference) getDefaultContainmentFeatures().get(
nextSuperType);
}
}
return result;
}
protected Map getDefaultContainmentFeatures() {
return defaultContainmentFeatures;
}
/**
* Gets the command to set a value of an element of my kind. By default,
* returns <code>null</code>. Subclasses may override to provide their
* command.
*
* @param req
* the set request
* @return the set command
*/
protected ICommand getSetCommand(SetRequest req) {
return new SetValueCommand(req);
}
/**
* Gets the command to create or return the edit context element for the
* creation of a new element of my kind (e.g., when creating a relationship,
* the relationship may be owned by the source or target, or some ancestor
* of one or the other, or both). By default, returns a command
* that returns a <code>null</code> edit context.
* Subclasses may override to provide their command.
*
* @param req
* the get edit context request
* @return the get edit context command
*/
protected ICommand getEditContextCommand(GetEditContextRequest req) {
return new GetEditContextCommand(req);
}
/**
* Gets the command to destroy a single child of an element of my kind, and
* only it. By default, returns a {@link DestroyElementCommand}. Subclasses
* may override to provide their own command.
*
* @param req
* the destroy request
* @return a command that destroys only the element specified as the request's
* {@linkplain DestroyElementRequest#getElementToDestroy() element to destroy}
*/
protected ICommand getBasicDestroyElementCommand(DestroyElementRequest req) {
ICommand result = req.getBasicDestroyCommand();
if (result == null) {
result = new DestroyElementCommand(req);
} else {
// ensure that re-use of this request will not accidentally
// propagate this command, which would destroy the wrong object
req.setBasicDestroyCommand(null);
}
return result;
}
/**
* Gets the command to destroy a single child of an element of my kind along
* with its dependents (not related by containment). By default, returns a
* composite that destroys the elements and zero or more dependents.
*
* @param req
* the destroy request
* @return a command that destroys the element specified as the request's
* {@linkplain DestroyElementRequest#getElementToDestroy() element to destroy}
* and its non-containment dependents
*/
protected ICommand getDestroyElementWithDependentsCommand(
DestroyElementRequest req) {
ICommand result = getBasicDestroyElementCommand(req);
EObject initial = (EObject) req
.getParameter(DestroyElementRequest.INITIAL_ELEMENT_TO_DESTROY_PARAMETER);
if (initial == null) {
// set the parameter to keep track of the initial element to destroy
req.setParameter(
DestroyElementRequest.INITIAL_ELEMENT_TO_DESTROY_PARAMETER, req
.getElementToDestroy());
}
// get elements dependent on the element we are destroying, that
// must also be destroyed
DestroyDependentsRequest ddr = (DestroyDependentsRequest) req
.getParameter(DestroyElementRequest.DESTROY_DEPENDENTS_REQUEST_PARAMETER);
if (ddr == null) {
// create the destroy-dependents request that will be propagated to
// destroy requests for all elements destroyed in this operation
ddr = new DestroyDependentsRequest(req.getEditingDomain(), req
.getElementToDestroy(), req.isConfirmationRequired());
// propagate the parameters, including the initial element to
// destroy parameter
ddr.addParameters(req.getParameters());
ddr.setClientContext(req.getClientContext());
req
.setParameter(
DestroyElementRequest.DESTROY_DEPENDENTS_REQUEST_PARAMETER,
ddr);
} else {
ddr.setElementToDestroy(req.getElementToDestroy());
}
IElementType typeToDestroy = null;
Map cacheMaps = (Map) req.getParameter(RequestCacheEntries.Cache_Maps);
if (cacheMaps != null) {
Map map = (Map) cacheMaps.get(req.getElementToDestroy());
if (map != null) {
typeToDestroy = (IElementType) map
.get(RequestCacheEntries.Element_Type);
}
}
if (typeToDestroy == null) {
typeToDestroy = ElementTypeRegistry.getInstance().getElementType(
req.getElementToDestroy());
}
if (typeToDestroy != null) {
ICommand command = typeToDestroy.getEditCommand(ddr);
if (command != null) {
result = result.compose(command);
}
}
return result;
}
/**
* Gets the command to destroy a child of an element of my kind. By
* default, returns a composite command that destroys the element specified
* by the request and all of its contents.
*
* @param req
* the destroy request
* @return a command that destroys the element specified as the request's
* {@link DestroyElementRequest#getElementToDestroy() element to destroy}
* along with its contents and other dependents
*/
protected ICommand getDestroyElementCommand(DestroyElementRequest req) {
ICommand result = null;
EObject parent = req.getElementToDestroy();
if (req.getParameter(DestroyElementRequest.INITIAL_ELEMENT_TO_DESTROY_PARAMETER) == null) {
req.setParameter(DestroyElementRequest.INITIAL_ELEMENT_TO_DESTROY_PARAMETER, parent);
}
IElementType parentType = null;
Map cacheMaps = (Map) req
.getParameter(RequestCacheEntries.Cache_Maps);
Set checkedElement = null;
if (cacheMaps != null) {
checkedElement = (Set) cacheMaps
.get(RequestCacheEntries.Checked_Elements);
checkedElement.add(parent);
Map parentMap = (Map) cacheMaps.get(parent);
if (parentMap != null) {
parentType = (IElementType) parentMap
.get(RequestCacheEntries.Element_Type);
} else {
parentType = ElementTypeRegistry.getInstance().getElementType(
parent);
}
} else {
parentType = ElementTypeRegistry.getInstance().getElementType(
parent);
}
if (parentType != null) {
for (Iterator iter = parent.eContents().iterator(); iter.hasNext();) {
EObject next = (EObject) iter.next();
DestroyDependentsRequest ddr = (DestroyDependentsRequest) req.getParameter(
DestroyElementRequest.DESTROY_DEPENDENTS_REQUEST_PARAMETER);
// if another object is already destroying this one because it
// is (transitively) a dependent, then don't destroy it again .
if ((ddr == null) || ((checkedElement != null) && checkedElement.add(next)) || (!ddr.getDependentElementsToDestroy().contains(next))) {
// set the element to be destroyed
req.setElementToDestroy(next);
ICommand command = parentType.getEditCommand(req);
if (command != null) {
if (result == null) {
result = command;
} else {
result = result.compose(command);
}
// Under normal circumstances the command is executable.
// Checking canExecute here slows down large scenarios and it is therefore
// better to skip this check.
// if (!command.canExecute()) {
// // no point in continuing if we're abandoning the works
// break;
// }
}
}
}
}
// restore the elementToDestroy in the original request
req.setElementToDestroy(parent);
ICommand destroyParent = getDestroyElementWithDependentsCommand(req);
//bottom-up destruction: destroy children before parent
if (result == null) {
result = destroyParent;
} else {
result = result.compose(destroyParent);
}
return result;
}
/**
* Gets the command to destroy dependents of an element of my kind. By
* default, returns <code>null</code>. Subclasses may override to provide
* a command.
*
* @param req
* the destroy dependents request
* @return a command to destroy dependents, or <code>null</code>
*/
protected ICommand getDestroyDependentsCommand(DestroyDependentsRequest req) {
return null;
}
/**
* Gets the command to remove a reference from an element of my kind. By
* default, returns <code>null</code>. Subclasses may override to provide
* their command.
*
* @param req
* the destroy reference request
* @return the destroy reference command
*/
protected ICommand getDestroyReferenceCommand(DestroyReferenceRequest req) {
return new DestroyReferenceCommand(req);
}
/**
* Gets the command to duplicate a child in an element of my kind. By
* default, returns <code>null</code>. Subclasses may override to provide
* their command.
*
* @param req
* the duplicate request
* @return the duplicate command
*/
protected ICommand getDuplicateCommand(DuplicateElementsRequest req) {
return null;
}
/**
* Gets the command to move an element into an element of my kind. By
* default, returns <code>null</code>. Subclasses may override to provide
* their command.
*
* @param req
* the move request
* @return the move command
*/
protected ICommand getMoveCommand(MoveRequest req) {
return new MoveElementsCommand(req);
}
/**
* Gets the command to change the source or target of a reference in an
* element of my kind. By default, returns <code>null</code>. Subclasses
* may override to provide their command.
*
* @param req
* the reorient reference request
* @return the reorient reference command
*/
protected ICommand getReorientReferenceRelationshipCommand(
ReorientReferenceRelationshipRequest req) {
return null;
}
/**
* Gets the command to change the source or target of a relationship in an
* element of my kind. By default, returns <code>null</code>. Subclasses
* may override to provide their command.
*
* @param req
* the reorient relationship request
* @return the reorient relationship command
*/
protected ICommand getReorientRelationshipCommand(
ReorientRelationshipRequest req) {
return null;
}
}