/*****************************************************************************
* Copyright (c) 2010 Atos Origin.
*
*
* 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:
* Atos Origin - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.common.groups.commands.utlis;
import java.util.ArrayList;
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.IAdaptable;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.Adaptable;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
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.commands.SemanticCreateCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
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.CreateViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
import org.eclipse.papyrus.uml.diagram.common.groups.Messages;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChangeGraphicalParentCommand;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChangeGraphicalParentCommand.Mode;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChangeModelParentCommand;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChooseChildrenNotificationCommand;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChooseParentNotificationCommand;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.SetUpReferencesCommand;
import org.eclipse.papyrus.uml.diagram.common.groups.commands.UpdateReferencesCommand;
import org.eclipse.papyrus.uml.diagram.common.groups.core.groupcontainment.GroupContainmentRegistry;
import org.eclipse.papyrus.uml.diagram.common.groups.core.utils.DefaultModelParent;
import org.eclipse.papyrus.uml.diagram.common.groups.core.utils.Utils;
import org.eclipse.papyrus.uml.diagram.common.groups.groupcontainment.AbstractContainerNodeDescriptor;
import org.eclipse.papyrus.uml.diagram.common.groups.utils.GroupRequestConstants;
/**
* Util class for command
*
* @author arthur daussy
*
*/
public class CommandsUtils {
/**
* Parameter in a request which define which host (IGrapicalEditPart) has to handle the request
*/
public static final String NEW_PARENT_HOST = "New_parent_host";
/**
* Parameter in a request which define the graphical parent ((IGrapicalEditPart))
*/
public static final String GRAPHICAL_PARENT = "Graphical_parent";
/**
* Get the semantic command to create a new element.
* This will set ups all references needed and create the semantic Container Parent Command
*
* @param requestAdapter
* Request adapter of the global request
* @param createElementCommand
* Create Element Request
* @param editingDomain
* TransactionalEditingDomain needed to create transactionnal command
* @param createElementRequest
* The request to create a new element
* @param createElementCommand
* The command to create the element just after its creation
* @return
*/
public static CompositeCommand getSemanticCommand(CreateElementRequestAdapter requestAdapter, TransactionalEditingDomain editingDomain, CreateElementRequest createElementRequest, Command createElementCommand, List<IGraphicalEditPart> graphicalParents) {
CompositeCommand semanticCommand;
/*
* create the semantic create wrapper command
*/
SemanticCreateCommand semanticContainerParentCommand = new SemanticCreateCommand(requestAdapter, createElementCommand);
/*
* Create a command to update references
*/
SetUpReferencesCommand setUpReferences = new SetUpReferencesCommand(editingDomain, semanticContainerParentCommand.getLabel(), requestAdapter, graphicalParents);
/*
* create the semantic global command
*/
semanticCommand = new CompositeCommand(semanticContainerParentCommand.getLabel());
if(semanticCommand != null) {
semanticCommand.compose(semanticContainerParentCommand);
}
if(setUpReferences != null) {
semanticCommand.compose(setUpReferences);
}
return semanticCommand;
}
/**
* Return the command which create the notification to asked to the user to choose the graphical parent of undetermined element (elements which
* have at least 2 possible graphical parent)
* FIXME change the composite command to a normal command (composite command is not needed anymore)
*
* @param editingDomain
* TransactionalEditingDomain in order to create the command
* @param request
* General request
* @return the composite command. This command is in two parts. The first represent the Notification to choose the model parent and if needed the
* command to chose the graphical parent.
*/
public static CompositeCommand getChooseParentNotification(TransactionalEditingDomain editingDomain, CreateViewAndElementRequest request, List<IGraphicalEditPart> graphicalParents, List<IGraphicalEditPart> modelParents, IGraphicalEditPart getHost) {
/*
* ChooseParentNotificationCommand
* 1 - Check if there is any choice to make
* 1.1 - Check that All list are initialized
* 1.2 - Check there are There at least 2 elements in one of the two least
* 2 - Create a composite command :
* 2.1 - Create the Graphical Choice command
* 2.2 - create the Model Choice command
*/
CompositeCommand choiceCommand = null;
if(graphicalParents != null && modelParents != null && (modelParents.size() > 1 || graphicalParents.size() > 1)) {
String chooseCommandLabel = "Print choice notifications";//$NON-NLS-1$
choiceCommand = new CompositeCommand(chooseCommandLabel);
if(modelParents.size() > 1) {
ChooseParentNotificationCommand modelNotificationCommand = new ChooseParentNotificationCommand(editingDomain, chooseCommandLabel + " : Model ", modelParents, request, ChooseParentNotificationCommand.MODEL_MODE, getHost);
choiceCommand.compose(modelNotificationCommand);
} else {
if(graphicalParents.size() > 1) {
ChooseParentNotificationCommand graphicalNotificationCommand = new ChooseParentNotificationCommand(editingDomain, chooseCommandLabel + " : Graphical ", graphicalParents, request, ChooseParentNotificationCommand.GRAPHICAL_MODE, getHost);
choiceCommand.compose(graphicalNotificationCommand);
}
}
}
return choiceCommand;
}
/**
* Return the command which create the notification to asked to the user to choose the graphical parent of undetermined element (elements which
* have at least 2 possible graphical parent)
* FIXME change the composite command to a normal command (composite command is not needed anymore)
*
* @param editingDomain
* TransactionalEditingDomain in order to create the command
* @param childAdapter
* {@link IAdaptable} to find the {@link IGraphicalEditPart} of the child
* @return the composite command. This command is in two parts. The first represent the Notification to choose the model parent and if needed the
* command to chose the graphical parent.
*/
public static CompositeCommand getChooseParentNotification(TransactionalEditingDomain editingDomain, ChangeBoundsRequest request, List<IGraphicalEditPart> graphicalParents, List<IGraphicalEditPart> modelParents, IGraphicalEditPart getHost) {
/*
* ChooseParentNotificationCommand
* 1 - Check if there is any choice to make
* 1.1 - Check that All list are initialized
* 1.2 - Check there are There at least 2 elements in one of the two least
* 2 - Create a composite command :
* 2.1 - Create the Graphical Choice command
* 2.2 - create the Model Choice command
*/
CompositeCommand choiceCommand = null;
if(graphicalParents != null && modelParents != null && (modelParents.size() > 1 || graphicalParents.size() > 1)) {
String chooseCommandLabel = "Print choice notifications";//$NON-NLS-1$
choiceCommand = new CompositeCommand(chooseCommandLabel);
if(modelParents.size() > 1) {
ChooseParentNotificationCommand modelNotificationCommand = new ChooseParentNotificationCommand(editingDomain, chooseCommandLabel + " : Model ", modelParents, request, ChooseParentNotificationCommand.MODEL_MODE, getHost);
choiceCommand.compose(modelNotificationCommand);
} else {
if(graphicalParents.size() > 1) {
ChooseParentNotificationCommand graphicalNotificationCommand = new ChooseParentNotificationCommand(editingDomain, chooseCommandLabel + " : Graphical ", graphicalParents, request, ChooseParentNotificationCommand.GRAPHICAL_MODE, getHost);
choiceCommand.compose(graphicalNotificationCommand);
}
}
}
return choiceCommand;
}
/**
* Check if the child already have a graphical parent and if its graphical parent is not a model parent on the new element in creation
*
* @param element
* Child we want to test
* @return true there a other group parent (which is not a parent of the new created element)
*/
public static boolean alreadyHaveGroupGraphicalParent(IGraphicalEditPart element, List<IGraphicalEditPart> modelParents) {
IGraphicalEditPart parent = (IGraphicalEditPart)element.getParent();
//CHANGE
return GroupContainmentRegistry.isContainerConcerned(parent) && !(element.getParent().getChildren().contains(parent));//!modelParents.contains(parent);
}
/**
* Get the depth at which the edit part is in the diagram
*
* @param part
* the edit part to test depth
* @return number of parents + 1
*/
public static int getDepth(IGraphicalEditPart part) {
int depth = 0;
EditPart parentPart = part;
while(parentPart != null) {
parentPart = parentPart.getParent();
depth++;
}
return depth;
}
/**
* Select the best models containers among the list of possible parents
*
* @param parents
* group parents
* @return the best model container (deepest one) or null if none
*/
public static IGraphicalEditPart selectBestModelContainer(List<IGraphicalEditPart> parents) {
IGraphicalEditPart container = null;
int containerDepth = 0;
//For all elements in parents
for(IGraphicalEditPart parent : parents) {
// select model containers only
if(GroupContainmentRegistry.isContainerModel(parent)) {
// select part the deepest in the diagram
int depth = getDepth(parent);
if(depth > containerDepth) {
container = parent;
}
}
}
return container;
}
/**
* This method is called if no model parent was found. It will return the command handled by a default container.
*
* @param request
* original request
* @param createElementRequest
* the creation request
* @param getHost
* Host of the {@link EditPolicy}
* @return the command as if handle by the default container. Return if the current container is the default container
*
*/
public static Command getCommandFromDefaultModelParent(CreateViewAndElementRequest request, CreateElementRequest createElementRequest, IGraphicalEditPart getHost) {
//If no model parent was found
//The system will look in the ancestor of the current host to find a element which can contain the new element and which is not a group
EClass typeToCreate = createElementRequest.getElementType().getEClass();
IGraphicalEditPart hostParent = getHost;
while(hostParent != null) {
EObject hostParentElement = hostParent.resolveSemanticElement();
if(GroupContainmentRegistry.getDescriptorsWithContainerEClass(hostParentElement.eClass()).isEmpty()) {
for(EReference containmentRelation : hostParentElement.eClass().getEAllContainments()) {
if(containmentRelation.getEReferenceType().isSuperTypeOf(typeToCreate)) {
if(getHost.equals(hostParent)) {
request.getExtendedData().put(NEW_PARENT_HOST, hostParent);
createElementRequest.setContainer(hostParentElement);
return null;
} else {
//This edit part can not handle the creation. It send it to the new hostParent
request.getExtendedData().put(CommandsUtils.NEW_PARENT_HOST, hostParent);
Command cmd = hostParent.getCommand(request);
return cmd;
}
}
}
}
hostParent = (IGraphicalEditPart)hostParent.getParent();
}
return null;
}
/**
* This method is called if no model parent was found. It will return the command handled by a default container. (For change bound request)
*
* @param request
* The change boudn request
* @param currentEditPart
* The element being moved
* @param getHost
* The host of the current {@link EditPolicy}
* @return the command as if handle by the default container. Return if the current container is the default container
*/
public static Command getCommandFromDefaultModelParent(ChangeBoundsRequest request, IGraphicalEditPart currentEditPart, IGraphicalEditPart getHost) {
//If no model parent was found
//The system will look in the ancestor of the current host to find a element which can contain the new element and which is not a group
EClass typeToCreate = currentEditPart.resolveSemanticElement().eClass();
IGraphicalEditPart hostParent = getHost;
while(hostParent != null) {
EObject hostParentElement = hostParent.resolveSemanticElement();
if(GroupContainmentRegistry.getDescriptorsWithContainerEClass(hostParentElement.eClass()).isEmpty()) {
for(EReference containmentRelation : hostParentElement.eClass().getEAllContainments()) {
if(containmentRelation.getEReferenceType().isSuperTypeOf(typeToCreate)) {
if(getHost.equals(hostParent)) {
return null;
} else {
//This edit part can not handle the creation. It send it to the new hostParent
request.getExtendedData().put(CommandsUtils.NEW_PARENT_HOST, hostParent);
Command cmd = hostParent.getCommand(request);
return cmd;
}
}
}
}
hostParent = (IGraphicalEditPart)hostParent.getParent();
}
return null;
}
/**
* Update model for all new direct child.
*
* @param directChildsToComplete
* List of all direct child
* @param descriptor
* descriptor of the group
* @param editingDomain
* Editing domain to create command
* @param parent
* RequestAdapter of the parent creation
* @param anyPart
* Igraphical editPart to get back EditPartRegistery
* @return CompositeCommand of all command updating model for each child
*/
public static ChangeModelParentCommand getUpdateChildrenModel(List<IGraphicalEditPart> directChildsToComplete, AbstractContainerNodeDescriptor descriptor, TransactionalEditingDomain editingDomain, IAdaptable parent, IGraphicalEditPart anyPart) {
ChangeModelParentCommand cmd = null;
Map<EObject, EReference> elementToMove = new HashMap<EObject, EReference>();
if(!directChildsToComplete.isEmpty()) {
for(IGraphicalEditPart child : directChildsToComplete) {
EObject childEObject = child.resolveSemanticElement();
EClass childEClass = childEObject.eClass();
if(descriptor.canIBeModelParentOf(childEClass)) {
elementToMove.put(childEObject, descriptor.getContainmentReferenceFor(childEClass));
}
}
}
if(!elementToMove.isEmpty()) {
cmd = new ChangeModelParentCommand(editingDomain, parent, elementToMove, anyPart);
}
return cmd;
}
/**
* set the {@see GroupRequestConstants#GRAPHICAL_CHILDREN} parameter of the request in order to make the list of children available in the
* LayoutEditPolicy
*
* @param automaticChildren
* All the {@link IGraphicalEditPart} you want to add as graphical children
* @param request
* request on which you want to add the parameter
*/
public static void updateGraphicalChildren(List<IGraphicalEditPart> automaticChildren, Request request) {
if(!automaticChildren.isEmpty()) {
request.getExtendedData().put(GroupRequestConstants.GRAPHICAL_CHILDREN, automaticChildren);
}
}
/**
* Create a notification to choose the graphical children of element in creation (request)
*
* @param allChildren
* All possible children
* @param automaticChildren
* All the children has been automatically graphical children
* @param request
* Creation request
* @param domain
* EditingDomain to create TransactionalCommand
* @param label
* Label of the command
* @param diagramPart
* @return The command or null is not possible
*/
public static CompositeCommand getChooseGraphicalChildrenNotificationCommand(List<IGraphicalEditPart> allChildren, List<IGraphicalEditPart> automaticChildren, CreateViewAndElementRequest request, TransactionalEditingDomain domain, String label, IGraphicalEditPart getHost, DiagramEditPart diagramPart) {
if(allChildren.size() > automaticChildren.size()) {
Iterator<? extends CreateViewRequest.ViewDescriptor> descriptors = request.getViewDescriptors().iterator();
CompositeCommand compositeCommand = new CompositeCommand(label);
while(descriptors.hasNext()) {
CreateViewRequest.ViewDescriptor descriptor = (CreateViewRequest.ViewDescriptor)descriptors.next();
ChooseChildrenNotificationCommand cmd = new ChooseChildrenNotificationCommand(domain, label, allChildren, automaticChildren, descriptor, getHost, diagramPart);
if(cmd != null) {
compositeCommand.compose(cmd);
}
}
return compositeCommand;
}
return null;
}
/**
* @see #getChooseGraphicalChildrenNotificationCommand(List, List, CreateViewAndElementRequest, TransactionalEditingDomain, String,
* IGraphicalEditPart).
* This time the we directly give the IAdaptable element of the view
* @param allChildren
* @see #getChooseGraphicalChildrenNotificationCommand
* @param automaticChildren
* @see #getChooseGraphicalChildrenNotificationCommand
* @param adapter
* IAdaptable of the parent group (Used to get the view)
* @param domain
* @see #getChooseGraphicalChildrenNotificationCommand
* @param label
* @see #getChooseGraphicalChildrenNotificationCommand
* @param getHost
* @see #getChooseGraphicalChildrenNotificationCommand
* @return
*/
public static CompositeCommand getChooseGraphicalChildrenNotificationCommand(List<IGraphicalEditPart> allChildren, List<IGraphicalEditPart> automaticChildren, IAdaptable adapter, TransactionalEditingDomain domain, String label, IGraphicalEditPart getHost, DiagramEditPart diagramPart) {
CompositeCommand result = null;
ChooseChildrenNotificationCommand cmd = new ChooseChildrenNotificationCommand(domain, label, allChildren, automaticChildren, adapter, getHost, diagramPart);
if(cmd != null) {
result = new CompositeCommand(label);
result.compose(cmd);
}
return result;
}
/**
* Give back the command to handle visually contained elements inside a new group in creation
* 0 - Check if the there is any descriptor (its means if the element in creation belong to the Group Framework
* 1 - Compute possible children elements (graphical and model)
* 2 - Update References
* 3 - Update Model (if needed)
* 4 - Reassign automatic graphical parent
* 5 - Create a notification command to choose the graphical parent if needed
*
* @param descriptors
* Descriptor of the group in creation
* @param request
* General request
* @param nameObject
* Name of the object (to find default size FIXME)
* @param diagramPart
* EditPart of the diagram
* @param editingDomain
* TransctionnalEditingDomain in order to create transactionnal command
* @param parentAdapter
* Parent adapter (Use to get the EObject back after creation and the {@link IGraphicalEditPart})
* @param modelParents
* @return the composite command of all this steps
*/
public static CompositeCommand getHandleChildrenCommand(Set<AbstractContainerNodeDescriptor> descriptors, Request request, DiagramEditPart diagramPart, TransactionalEditingDomain editingDomain, IAdaptable parentAdapter, List<IGraphicalEditPart> modelParents, IGraphicalEditPart getHost) {
CompositeCommand cc = null;
//Do the following only if the created element is a group
if(!descriptors.isEmpty()) {
//Command label
String handleChildrenLabel = "Handle Children command ";//$NON-NLS-1$
for(AbstractContainerNodeDescriptor descriptor : descriptors) {
/*
* Child visually contained in the new group which can be graphical children of this new group
*/
List<IGraphicalEditPart> directChildsToComplete = new ArrayList<IGraphicalEditPart>();
/*
* Old child visually contained before the request ( used in changeBound request )
*/
List<IGraphicalEditPart> oldDirectChildsToComplete = null;
/*
* Initialize the two list directChildsToComplete and oldDirectChildsToComplete
*/
oldDirectChildsToComplete = initDirectChildLists(request, diagramPart, parentAdapter, descriptor, directChildsToComplete, oldDirectChildsToComplete);
if((directChildsToComplete != null && !directChildsToComplete.isEmpty()) || (oldDirectChildsToComplete != null && !oldDirectChildsToComplete.isEmpty())) {
cc = new CompositeCommand(handleChildrenLabel);
/*
* List of elements atomically chosen as graphical child
*/
List<IGraphicalEditPart> newGraphicalChildren = new ArrayList<IGraphicalEditPart>();;
/*
* List of elements on which the user should be asked to choose the graphical parent
*/
List<IGraphicalEditPart> choiceToMakeChildren = new ArrayList<IGraphicalEditPart>();;
for(IGraphicalEditPart part : directChildsToComplete) {
if(alreadyHaveGroupGraphicalParent(part, modelParents)) {
if(isNotAlreadyAGraphicalSon(part, request, parentAdapter)) {
choiceToMakeChildren.add(part);
}
} else {
newGraphicalChildren.add(part);
}
}
/*
* Command to update model of directChild which can be contain by the moving group
*/
if(!directChildsToComplete.isEmpty()) {
ChangeModelParentCommand updateChildrenModel = getUpdateChildrenModel(directChildsToComplete, descriptor, editingDomain, parentAdapter, directChildsToComplete.get(0));
if(updateChildrenModel != null) {
cc.compose(updateChildrenModel);
}
}
/*
* Command to update visually contained element to set their graphical parent with the parent Adapter
*/
if(!newGraphicalChildren.isEmpty()) {
updateGraphicalChildren(newGraphicalChildren, request);
}
String updateCommandeLabel = "Update children references";//$NON-NLS-1$
/*
* Update all graphical children references and model
*/
updateReferencesAndModelOfGraphicalChildren(request, editingDomain, parentAdapter, cc, directChildsToComplete, oldDirectChildsToComplete, handleChildrenLabel + ":" + updateCommandeLabel + " -> " + "update reference graphical child", getHost, descriptor);
/*
* Command to update references of new child
*/
UpdateReferencesCommand updateRefCommand = new UpdateReferencesCommand(editingDomain, handleChildrenLabel + ":" + updateCommandeLabel + " -> " + "update reference new child", directChildsToComplete, descriptor, parentAdapter);
if(updateRefCommand != null) {
cc.compose(updateRefCommand);
}
/*
* Withdraw old referenced child which are not anymore has to be referenced
*/
withdrawOldChildrenReferences(editingDomain, parentAdapter, cc, handleChildrenLabel + ":" + updateCommandeLabel + " -> " + "remove reference from of child", descriptor, directChildsToComplete, oldDirectChildsToComplete);
/*
* Command to create the graphical notification
*/
String chooseGraphicalChildrenLabel = "Notification for choosing graphical children";//$NON-NLS-1$
CompositeCommand chooseGraphicalChildrenCommand = null;
if(request instanceof CreateViewAndElementRequest) {
chooseGraphicalChildrenCommand = getChooseGraphicalChildrenNotificationCommand(directChildsToComplete, newGraphicalChildren, (CreateViewAndElementRequest)request, editingDomain, chooseGraphicalChildrenLabel, getHost, diagramPart);
} else if(request instanceof ChangeBoundsRequest) {
chooseGraphicalChildrenCommand = getChooseGraphicalChildrenNotificationCommand(directChildsToComplete, newGraphicalChildren, parentAdapter, editingDomain, chooseGraphicalChildrenLabel, getHost, diagramPart);
}
if(chooseGraphicalChildrenCommand != null) {
cc.compose(chooseGraphicalChildrenCommand);
}
cc.reduce();
if(cc.isEmpty()) {
cc = null;
}
}
}
}
return cc;
}
/**
* True if the request is just a movin request
*
* @param request
* @return
*/
private static boolean isMovingRequest(ChangeBoundsRequest request) {
return request.getSizeDelta() == null || request.getSizeDelta().equals(0, 0);
}
/***
* Update all the graphical children from a model point of view and a reference poitn of view
* note: It also update the the lists childlist and oldchildlist. It will withdraw the from those list all graphical children if the reques tis a
* simple move. If the request is a resize then all the grazphical children has to be taken into accoutn for next changes
*
* @param request
* {@link ChangeBoundsRequest}
* @param editingDomain
* {@link TransactionalEditingDomain}
* @param parentAdapter
* Parent adapter used to get the {@link IGraphicalEditPart} of the parent
* @param cc
* {@link CompositeCommand} use to compose new commands
* @param childList
* List of all the visual child after transformation
* @param oldChildsList
* List of all the visual child before transformation
* @param updateCommandeLabel
* Label used to compose command
* @param getHost
* Host of the request
*/
private static void updateReferencesAndModelOfGraphicalChildren(Request request, TransactionalEditingDomain editingDomain, IAdaptable parentAdapter, CompositeCommand cc, List<IGraphicalEditPart> childList, List<IGraphicalEditPart> oldChildsList, String updateCommandeLabel, IGraphicalEditPart getHost, AbstractContainerNodeDescriptor descriptor) {
if(request instanceof ChangeBoundsRequest) {
Object _movingPart = parentAdapter.getAdapter(EditPart.class);
if(_movingPart instanceof IGraphicalEditPart) {
List<IGraphicalEditPart> graphicalChilds = new ArrayList<IGraphicalEditPart>();
IGraphicalEditPart movingEditPart = (IGraphicalEditPart)_movingPart;
//Look for all graphical children
graphicalChilds = getGraphicalChild(movingEditPart);
/*
* For all graphical children
* if request = moving request
* -> Suppress old references
* -> change model parent if needed
* -> Add new references
* if request = resizing
* -> If the resizing is from west side
* - Translate the node to unmodify the GMF comportment of resizing by west = node moving
* -> If after resizing the node are no longer in the group
* - Unset references
* - Change graphical parent
*/
ChangeBoundsRequest changeBoundRequest = (ChangeBoundsRequest)request;
for(IGraphicalEditPart graphicalChild : graphicalChilds) {
/*
* All groups that contains the node before transforming ( transforming = moving or resizing )
*/
List<IGraphicalEditPart> oldGroupContainer = Utils.createComputeListsOfAllGroupContainerVisually(graphicalChild, changeBoundRequest, false, movingEditPart);
/*
* All groups that contains the node after transforming
*/
List<IGraphicalEditPart> newGroupContainer = Utils.createComputeListsOfAllGroupContainerVisually(graphicalChild, changeBoundRequest, true, movingEditPart);
IGraphicalEditPart compartmentEditPart = (IGraphicalEditPart)Utils.getCompartementEditPartFromMainEditPart(movingEditPart.getViewer().getEditPartRegistry(), movingEditPart);
/*
* If is a moving request
* => Then the node should move with the group
*/
if(isMovingRequest(changeBoundRequest))
handleMovingRequestForGraphicalChildren(editingDomain, cc, updateCommandeLabel, getHost, graphicalChild, oldGroupContainer, newGroupContainer, compartmentEditPart);
else {
cc = handleResizingRequestForGraphicalChildren(editingDomain, parentAdapter, cc, childList, getHost, descriptor, movingEditPart, graphicalChild, changeBoundRequest, newGroupContainer);
}
}
/*
* Remove graphical children of the lists of node to handle
*/
childList.removeAll(graphicalChilds);
oldChildsList.removeAll(graphicalChilds);
}
}
}
/**
* Handle resizing request for all graphical children
* - Erase the moving children after resize from WEST/NORT WHEST/WEST
* - Handle children going out after resizing
*
* @param editingDomain
* {@link TransactionalEditingDomain}
* @param parentAdapter
* {@link Adaptable} use to get the {@link IGraphicalEditPart} of the parent at runtime
* @param cc
* {@link CompositeCommand} Use to add new Command
* @param childList
* List of all the visual child after transformation
* @param getHost
* Host of the request
* @param descriptor
* Descriptor of the group
* @param movingEditPart
* {@link IGraphicalEditPart} of the moving Edit Part (TODO Use the adapter to erase one argument)
* @param graphicalChild
* {@link IGraphicalEditPart} of the graphical child you want to handle
* @param changeBoundRequest
* {@link ChangeBoundsRequest}
* @param newGroupContainer
* All group which can contain the node after transforming
* @return
*/
private static CompositeCommand handleResizingRequestForGraphicalChildren(TransactionalEditingDomain editingDomain, IAdaptable parentAdapter, CompositeCommand cc, List<IGraphicalEditPart> childList, IGraphicalEditPart getHost, AbstractContainerNodeDescriptor descriptor, IGraphicalEditPart movingEditPart, IGraphicalEditPart graphicalChild, ChangeBoundsRequest changeBoundRequest, List<IGraphicalEditPart> newGroupContainer) {
/*
* If this is a resizing request.
* Node should not move => Only case possible = Graphical child which go out from the group
* -> Unmove node if resizing from west
* -> Handle no coming out
*/
int direction = changeBoundRequest.getResizeDirection();
Point previousnLocation = graphicalChild.getFigure().getBounds().getLocation().getCopy();
Point negatedMoeDelta = changeBoundRequest.getMoveDelta().getNegated().getCopy();
boolean correctLocation = false;
switch(direction) {
case org.eclipse.draw2d.PositionConstants.WEST:
previousnLocation.translate(negatedMoeDelta.x, 0);
correctLocation = true;
break;
case org.eclipse.draw2d.PositionConstants.NORTH:
previousnLocation.translate(0, negatedMoeDelta.y);
correctLocation = true;
break;
case org.eclipse.draw2d.PositionConstants.NORTH_WEST:
previousnLocation.translate(negatedMoeDelta);
correctLocation = true;
break;
default:
break;
}
if(!childList.contains(graphicalChild)) {
if(correctLocation) {
newGroupContainer.remove(movingEditPart);
newGroupContainer.remove(Utils.getCompartementEditPartFromMainEditPart(movingEditPart.getViewer().getEditPartRegistry(), movingEditPart));
correctLocation = false;
}
cc = handleGraphicalChildrenMovingOut(editingDomain, parentAdapter, cc, getHost, descriptor, movingEditPart, graphicalChild, newGroupContainer);
}
if(correctLocation) {
SetBoundsCommand sbc = new SetBoundsCommand(editingDomain, "West or North resizing correcting relative coordiante", graphicalChild, previousnLocation);
if(sbc != null) {
cc.compose(sbc);
}
}
return cc;
}
/**
* Handle all the graphical children of a group after a moving request
*
* @param editingDomain
* {@link TransactionalEditingDomain}
* @param cc
* {@link CommandProxy} to compose new commands
* @param updateCommandeLabel
* Label Used for the command
* @param getHost
* Host of the request
* @param graphicalChild
* Graphical child to handle
* @param oldGroupContainer
* All group that contained the node before transforming
* @param newGroupContainer
* All group that contains the node after transforming
* @param compartmentEditPart
* Compartment EditPart of the parent EditPart
*/
private static void handleMovingRequestForGraphicalChildren(TransactionalEditingDomain editingDomain, CompositeCommand cc, String updateCommandeLabel, IGraphicalEditPart getHost, IGraphicalEditPart graphicalChild, List<IGraphicalEditPart> oldGroupContainer, List<IGraphicalEditPart> newGroupContainer, IGraphicalEditPart compartmentEditPart) {
{
/*
* Suppress old reference
*/
for(IGraphicalEditPart parentGroup : oldGroupContainer) {
if(!newGroupContainer.contains(parentGroup) && !parentGroup.equals(compartmentEditPart)) {
/*
* Unset the reference
*/
UpdateReferencesCommand cmd1 = new UpdateReferencesCommand(editingDomain, updateCommandeLabel, Collections.singletonList(graphicalChild), GroupContainmentRegistry.getContainerDescriptor(parentGroup), parentGroup, UpdateReferencesCommand.UNSET_MODE);
if(cmd1 != null) {
cc.compose(cmd1);
}
}
}
//List of all model parent available (except the compartment edit part)
List<IGraphicalEditPart> modelParents = new ArrayList<IGraphicalEditPart>();
EObject childEObject = ((IGraphicalEditPart)graphicalChild).resolveSemanticElement();
//Does the child have already a valid model parent
boolean alreadyHaveValideModelParent = false;
AbstractContainerNodeDescriptor containerDescriptor = GroupContainmentRegistry.getContainerDescriptor(compartmentEditPart);
//If compartmentEditPart refer to a group which can be model parent then the child already have a model parent
if(containerDescriptor != null) {
alreadyHaveValideModelParent = containerDescriptor.canIBeModelParentOf(childEObject.eClass());
}
//Add new reference and update model
for(IGraphicalEditPart newParentGroup : newGroupContainer) {
//set Reference
UpdateReferencesCommand cmd2 = new UpdateReferencesCommand(editingDomain, updateCommandeLabel, Collections.singletonList(graphicalChild), GroupContainmentRegistry.getContainerDescriptor(newParentGroup), newParentGroup, UpdateReferencesCommand.SET_MODE);
if(cmd2 != null) {
cc.compose(cmd2);
}
//Create a list of all model parent available. Set alreadyHaveValideModelParent to true if the child already have a model parent wich is on the new model parent
AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(newParentGroup);
if(desc != null) {
if(desc.canIBeModelParentOf(childEObject.eClass())) {
modelParents.add(newParentGroup);
}
}
}
/*
* Do not have mode parent change it
*/
if(!alreadyHaveValideModelParent) {
Map<EObject, EReference> child = null;
IGraphicalEditPart newModelParent = null;
if(!modelParents.isEmpty()) {
newModelParent = modelParents.get(0);
AbstractContainerNodeDescriptor newDesc = GroupContainmentRegistry.getContainerDescriptor(newModelParent);
if(newDesc != null && newModelParent != null) {
EReference ref = newDesc.getContainmentReferenceFor(childEObject.eClass());
child = Collections.singletonMap(childEObject, ref);
}
} else {
DefaultModelParent parent = Utils.getDefaultModelParent(childEObject.eClass(), getHost);
child = Collections.singletonMap(childEObject, parent.geteReference());
newModelParent = parent.getiGraphicalEditPart();
}
if(child != null && newModelParent != null) {
ChangeModelParentCommand changeModelParent = new ChangeModelParentCommand(editingDomain, newModelParent, child, newModelParent);
if(changeModelParent != null) {
cc.compose(changeModelParent);
}
}
}
}
}
/**
* Handle children movign out from a group after resizing
*
* @param editingDomain
* {@link TransactionalEditingDomain}
* @param parentAdapter
* Parent adapter to get the {@link IGraphicalEditPart} at runtime
* @param cc
* {@link CompositeCommand} use to compose new commande
* @param getHost
* Host of the request
* @param descriptor
* AbstractContainerNodeDescriptor of the parent
* @param movingEditPart
* {@link IGraphicalEditPart} of the parent
* @param graphicalChild
* All graphical children of the group
* @param newGroupContainer
* Group that containt the node after transforming
* @return
*/
private static CompositeCommand handleGraphicalChildrenMovingOut(TransactionalEditingDomain editingDomain, IAdaptable parentAdapter, CompositeCommand cc, IGraphicalEditPart getHost, AbstractContainerNodeDescriptor descriptor, IGraphicalEditPart movingEditPart, IGraphicalEditPart graphicalChild, List<IGraphicalEditPart> newGroupContainer) {
String label = Messages.CommandsUtils_HandleGraphicalChildrenMovingOut_Label;
if(cc == null) {
cc = new CompositeCommand(label);
}
UpdateReferencesCommand updateRefCommand = new UpdateReferencesCommand(editingDomain, label, Collections.singletonList(graphicalChild), descriptor, parentAdapter, UpdateReferencesCommand.UNSET_MODE);
if(updateRefCommand != null) {
cc.compose(updateRefCommand);
}
IGraphicalEditPart newParent = null;
if(!newGroupContainer.isEmpty()) {
newParent = newGroupContainer.get(0);
} else {
newParent = (IGraphicalEditPart)movingEditPart.getParent(); //here add a default parent
}
/*
* FIXME
* Change
* Test is it is a containing feature
* Then change containing parent
*/
ChangeGraphicalParentCommand changeParentCmd = new ChangeGraphicalParentCommand(editingDomain, label + ": Changing graphical parent", newParent, graphicalChild, getHost);
if(changeParentCmd != null) {
cc.compose(changeParentCmd);
}
return cc;
}
/**
* Get all {@link IGraphicalEditPart} which are graphical children from a {@link IGraphicalEditPart} parent
*
* @param parentEditPart
* {@link IGraphicalEditPart} parent
* @return A {@link List} of {@link IGraphicalEditPart} of all the child and null parent part is not set properly
*/
private static List<IGraphicalEditPart> getGraphicalChild(IGraphicalEditPart parentEditPart) {
EditPartViewer viewer = null;
List<IGraphicalEditPart> result = null;
if(parentEditPart != null) {
viewer = parentEditPart.getViewer();
if(viewer != null) {
IGraphicalEditPart compartmentEditPart = (IGraphicalEditPart)Utils.getCompartementEditPartFromMainEditPart(viewer.getEditPartRegistry(), parentEditPart);
result = new ArrayList<IGraphicalEditPart>();
for(Object child : compartmentEditPart.getChildren()) {
if(child instanceof IGraphicalEditPart && GroupContainmentRegistry.isNodeConcerned((IGraphicalEditPart)child)) {
result.add((IGraphicalEditPart)child);
}
}
}
}
return result;
}
/**
* Initialize the two list directChildsToComplete and oldDirectChildsToComplete in order to get back all the child visually contained after et
* before the request
*
* @param request
* {@link Request} send by the system (for now handle {@link CreateViewAndElementRequest} and {@link ChangeBoundsRequest})
* @param diagramPart
* EditPart on the diagram
* @param parentAdapter
* {@link IAdaptable} of the parent group (used to get the {@link IGraphicalEditPart} and {@link View})
* @param descriptor
* {@link AbstractContainerNodeDescriptor} of the parent group
* @param directChildsToComplete
* List of all elements which can be graphical child after the request
* @param oldDirectChildsToComplete
* List of all elements which were graphical child before the request
* @return oldDirectChildsToComplete or null if not needed ( in case of {@link CreateViewAndElementRequest})
*/
private static List<IGraphicalEditPart> initDirectChildLists(Request request, IGraphicalEditPart diagramPart, IAdaptable parentAdapter, AbstractContainerNodeDescriptor descriptor, List<IGraphicalEditPart> directChildsToComplete, List<IGraphicalEditPart> oldDirectChildsToComplete) {
if(request instanceof CreateViewAndElementRequest) {
Utils.createComputedListsOfVisualYRelatedElements(directChildsToComplete, (CreateViewAndElementRequest)request, diagramPart, descriptor);
} else if(request instanceof ChangeBoundsRequest) {
Object _parentEditPart = parentAdapter.getAdapter(IGraphicalEditPart.class);
if(_parentEditPart instanceof IGraphicalEditPart) {
oldDirectChildsToComplete = new ArrayList<IGraphicalEditPart>();
Utils.createComputedListsOfVisuallyRelatedElements(directChildsToComplete, (ChangeBoundsRequest)request, (IGraphicalEditPart)_parentEditPart, descriptor, true);
Utils.createComputedListsOfVisuallyRelatedElements(oldDirectChildsToComplete, (ChangeBoundsRequest)request, (IGraphicalEditPart)_parentEditPart, descriptor, false);
}
}
return oldDirectChildsToComplete;
}
/**
* Withdraw all references of element which are no longer contained in the group.
* With graphically all the children which are not visually contained in the group
*
* @param editingDomain
* {@link TransactionalEditingDomain}
* @param parentAdapter
* {@link IAdaptable} of the parent group
* @param cc
* {@link CompositeCommand} to compose command the new command. (This command will be completed). If cc est nul then a new CompositeCommand
* is created
* @param handleChildrenLabel
* Label for the command
* @param descriptor
* {@link AbstractContainerNodeDescriptor} of the parent group
* @param directChildsToComplete
* List of all new element which are visually contained in the parent group
* @param oldDirectChildsToComplete
* List of all element which were visually contained in the parent group
* @return return the composite command or null is no command is in cc
*/
private static CompositeCommand withdrawOldChildrenReferences(TransactionalEditingDomain editingDomain, IAdaptable parentAdapter, CompositeCommand cc, String handleChildrenLabel, AbstractContainerNodeDescriptor descriptor, List<IGraphicalEditPart> directChildsToComplete, List<IGraphicalEditPart> oldDirectChildsToComplete) {
if(oldDirectChildsToComplete != null && !oldDirectChildsToComplete.isEmpty()) {
List<IGraphicalEditPart> childToWithdraw = new ArrayList<IGraphicalEditPart>();
for(IGraphicalEditPart child : oldDirectChildsToComplete) {
if(!directChildsToComplete.contains(child)) {
childToWithdraw.add(child);
}
}
if(!childToWithdraw.isEmpty()) {
String unreferencinComandLabel = "Unset Reference";
if(cc == null) {
cc = new CompositeCommand(handleChildrenLabel + ":" + unreferencinComandLabel);
}
UpdateReferencesCommand updateRefCommand = new UpdateReferencesCommand(editingDomain, handleChildrenLabel + ":" + unreferencinComandLabel, childToWithdraw, descriptor, parentAdapter, UpdateReferencesCommand.UNSET_MODE);
if(updateRefCommand != null) {
cc.compose(updateRefCommand);
}
}
cc.reduce();
if(cc.isEmpty()) {
cc = null;
}
}
return cc;
}
private static boolean isNotAlreadyAGraphicalSon(IGraphicalEditPart childPart, Request request, IAdaptable parentAdapter) {
if(request instanceof ChangeBoundsRequest) {
Object _editPart = parentAdapter.getAdapter(EditPart.class);
if(_editPart instanceof IGraphicalEditPart) {
IGraphicalEditPart parentPart = (IGraphicalEditPart)_editPart;
return !parentPart.getChildren().contains(childPart);
}
}
return true;
}
/**
* Set in the reqest the current Graphical parent and the current Model Parent
*
* @param request
* request change want to set
* @param _graphicalParents
* List of all graphical parent available
* @param _modelParents
* List of all Model parent available
* @param getHost
* host of the edit policy
* @return Return the default graphical parent
*/
public static IGraphicalEditPart setRequestParentsParameters(Request request, List<IGraphicalEditPart> _graphicalParents, List<IGraphicalEditPart> _modelParents, EditPart getHost) {
/*
* Choose the default graphical parent
* 1 - If no graphical parent found then the host become the graphical parent
* else by default the the graphical parent of the list become the graphical parent
*/
IGraphicalEditPart graphicalParent = null;
if(!_graphicalParents.isEmpty()) {
graphicalParent = _graphicalParents.get(0);
request.getExtendedData().put(GroupRequestConstants.GRAPHICAL_CONTAINERS, _graphicalParents);
}
if(_modelParents != null) {
request.getExtendedData().put(GroupRequestConstants.MODEL_CONTAINERS, _modelParents);
}
return graphicalParent;
}
/**
* Send the request to a suitable host. A suitable host is a host which can be a model parent of the editing element. This implementation allow
* you to deal with creation request
*
* @param request
* CreateViewAndElementRequest of the element in creation
* @param createElementRequest
* CreateElementRequest of the element in creation
* @param getHost
* Host of the editPolicy
* @param _modelParents
* All model parent available
* @return
*/
public static Command sendRequestSuitableHost(CreateViewAndElementRequest request, CreateElementRequest createElementRequest, IGraphicalEditPart getHost, List<IGraphicalEditPart> _modelParents) {
EObject modelContainer = null;
//If the system has found model parent
if(!_modelParents.isEmpty()) {
IGraphicalEditPart defaultGraphicalEditPart = _modelParents.get(0);
//If the current host is different the first element on the modelParent list the system send the request to its edit part
if(!getHost.equals(defaultGraphicalEditPart)) {
request.getExtendedData().put(NEW_PARENT_HOST, defaultGraphicalEditPart);
return defaultGraphicalEditPart.getCommand(request);
}
modelContainer = getHost.resolveSemanticElement();
createElementRequest.setContainer(modelContainer);
} else {
/*
* If there is no model found for this element we use the default element
*/
Command cmd = getCommandFromDefaultModelParent(request, createElementRequest, getHost);
if(cmd != null) {
return cmd;
}
}
return null;
}
/**
* Send the request to a suitable host. A suitable host is a host which can be a model parent of the editing element. This implementation allow
* you to deal with {@link ChangeBoundsRequest}
*
* @param request
* {@link ChangeBoundsRequest}
* @param getHost
* {@link EditPart} host of the {@link EditPolicy}
* @param _modelParents
* List of all {@link IGraphicalEditPart} which can be model parent of the moving element
* @param movingEditPart
* The {@link IGraphicalEditPart} of the moving {@link EditPart}
* @return
*/
public static Command sendRequestSuitableHost(ChangeBoundsRequest request, IGraphicalEditPart getHost, List<IGraphicalEditPart> _modelParents, IGraphicalEditPart movingEditPart) {
//If the system has found model parent
if(!_modelParents.isEmpty()) {
IGraphicalEditPart defaultModelParentEditPart;
//TODO redo tests with this
if(_modelParents.contains(movingEditPart.getParent())) {
defaultModelParentEditPart = (IGraphicalEditPart)movingEditPart.getParent();
} else {
defaultModelParentEditPart = _modelParents.get(0);
}
//If the current host is different the first element on the modelParent list the system send the request to its edit part
if(!getHost.equals(defaultModelParentEditPart)) {
return defaultModelParentEditPart.getCommand(request);
}
} else {
/*
* If there is no model found for this element we use the default element
* FIXME 1 - Check the safety of editParts.get(0) . Try to move several element in the same time
*/
Command cmd = getCommandFromDefaultModelParent(request, movingEditPart, getHost);
if(cmd != null) {
return cmd;
}
}
return null;
}
/**
* This method handle request with multiple EditPart ( @see {@link ChangeBoundsRequest#getEditParts()} ).
* It will handle it by creating as many request as {@link EditPart} in {@link ChangeBoundsRequest#getEditParts()} and ask the host to handle it.
*
* @param request
* {@link ChangeBoundsRequest}
* @param label
* label of the resulting command if any
* @param getHost
* Host of the editPolicy
* @return Return the composite command if any. Null it the request has less than 2 edit part
*/
public static Command requestEditPartMultiplexor(ChangeBoundsRequest request, String label, IGraphicalEditPart getHost) {
CompositeCommand result = new CompositeCommand(label);
if(request.getEditParts().size() > 1) {
for(Object part : request.getEditParts()) {
ChangeBoundsRequest req = new ChangeBoundsRequest();
req.setEditParts(Collections.singletonList(part));
req.setMoveDelta(request.getMoveDelta());
req.setSizeDelta(request.getSizeDelta());
req.setLocation(request.getLocation());
req.setResizeDirection(request.getResizeDirection());
req.setCenteredResize(request.isCenteredResize());
req.setConstrainedMove(request.isConstrainedMove());
req.setConstrainedResize(request.isConstrainedResize());
req.setSnapToEnabled(request.isSnapToEnabled());
req.setType(RequestConstants.REQ_RESIZE_CHILDREN);
HashMap extendedData = new HashMap(request.getExtendedData());
req.setExtendedData(extendedData);
// Command cmd = getHost.getCommand(req);
Command cmd = getHost.getEditPolicy(EditPolicy.LAYOUT_ROLE).getCommand(req);
if(cmd != null) {
result.compose(new CommandProxy(cmd));
}
}
if(!result.isEmpty()) {
return new ICommandProxy(result);
}
}
return null;
}
/**
* Compose the command to change the graphical parent
*
* @param label
* Label of the command
* @param result
* Resulting composite command
* @param movingEditPart
* The {@link IGraphicalEditPart} which is moving
* @param editingDomain
* {@link TransactionalEditingDomain} use to create Transactionnal Command
* @param graphicalParent
* The new graphical parent
* @param request
*/
public static void getChangeGraphicalParentCommand(String label, CompositeCommand result, IGraphicalEditPart movingEditPart, TransactionalEditingDomain editingDomain, IGraphicalEditPart graphicalParent, IGraphicalEditPart getHost, ChangeBoundsRequest request) {
if(graphicalParent != null) {
ChangeGraphicalParentCommand changeGraphicalParent = new ChangeGraphicalParentCommand(editingDomain, label + ": change graphical parent", graphicalParent, movingEditPart, (IGraphicalEditPart)getHost, request);
if(changeGraphicalParent != null) {
changeGraphicalParent.setMode(Mode.MOVE_CHILD);
result.compose(changeGraphicalParent);
}
} else {
ChangeGraphicalParentCommand changeGraphicalParent = new ChangeGraphicalParentCommand(editingDomain, label + ": change graphical parent", (IGraphicalEditPart)getHost, movingEditPart, (IGraphicalEditPart)getHost, request);
if(changeGraphicalParent != null) {
changeGraphicalParent.setMode(Mode.MOVE_CHILD);
result.compose(changeGraphicalParent);
}
}
}
}