diff options
Diffstat (limited to 'plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common.groups/src/org/eclipse/papyrus/uml/diagram/common/groups/core/utils/Utils.java')
-rw-r--r-- | plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common.groups/src/org/eclipse/papyrus/uml/diagram/common/groups/core/utils/Utils.java | 2110 |
1 files changed, 1055 insertions, 1055 deletions
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common.groups/src/org/eclipse/papyrus/uml/diagram/common/groups/core/utils/Utils.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common.groups/src/org/eclipse/papyrus/uml/diagram/common/groups/core/utils/Utils.java index c037b5347c3..31aa1a0c216 100644 --- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common.groups/src/org/eclipse/papyrus/uml/diagram/common/groups/core/utils/Utils.java +++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common.groups/src/org/eclipse/papyrus/uml/diagram/common/groups/core/utils/Utils.java @@ -1,1055 +1,1055 @@ -/*****************************************************************************
- * 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.core.utils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.draw2d.Graphics;
-import org.eclipse.draw2d.IFigure;
-import org.eclipse.draw2d.RoundedRectangle;
-import org.eclipse.draw2d.geometry.Dimension;
-import org.eclipse.draw2d.geometry.Point;
-import org.eclipse.draw2d.geometry.Rectangle;
-import org.eclipse.emf.common.command.Command;
-import org.eclipse.emf.common.command.CompoundCommand;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.edit.command.AddCommand;
-import org.eclipse.emf.edit.command.RemoveCommand;
-import org.eclipse.gef.EditPart;
-import org.eclipse.gef.EditPartViewer;
-import org.eclipse.gef.LayerConstants;
-import org.eclipse.gef.editparts.LayerManager;
-import org.eclipse.gef.requests.ChangeBoundsRequest;
-import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
-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.editparts.IPrimaryEditPart;
-import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart;
-import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest;
-import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
-import org.eclipse.gmf.runtime.notation.Bounds;
-import org.eclipse.gmf.runtime.notation.LayoutConstraint;
-import org.eclipse.gmf.runtime.notation.Node;
-import org.eclipse.gmf.runtime.notation.View;
-import org.eclipse.papyrus.commands.wrappers.GEFtoEMFCommandWrapper;
-import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChangeModelParentCommand;
-import org.eclipse.papyrus.uml.diagram.common.groups.core.groupcontainment.GroupContainmentRegistry;
-import org.eclipse.papyrus.uml.diagram.common.groups.groupcontainment.AbstractContainerNodeDescriptor;
-import org.eclipse.papyrus.uml.diagram.common.groups.utils.GraphicalAndModelElementComparator;
-import org.eclipse.papyrus.uml.diagram.common.groups.utils.GraphicalAndModelElementComparator.Mode;
-
-
-/**
- * This class provides utility methods useful for the group framework.
- *
- * @author vhemery and adaussy
- */
-public class Utils {
-
- /**
- * Find the containers which may contain an edit part in the given bounds.
- *
- * @param bounds
- * the new or old bounds of the item
- * @param diagramPart
- * the diagram edit part
- * @return the list of edit parts that are registered through the group framework and that can contain an element within the given bounds
- */
- public static List<IGraphicalEditPart> findPossibleParents(Rectangle bounds, DiagramEditPart diagramPart) {
- if (diagramPart == null) {
- return Collections.emptyList();
- }
- Set<IGraphicalEditPart> groupParts = new HashSet<IGraphicalEditPart>();
- // For all object in diagram, find edit parts
- for (Object view : diagramPart.getViewer().getEditPartRegistry().keySet()) {
- if (view instanceof View) {
- Object editpart = diagramPart.getViewer().getEditPartRegistry().get(view);
- if (editpart instanceof IGraphicalEditPart) {
- IGraphicalEditPart part = (IGraphicalEditPart) editpart;
- // If this group is handled by the group framework
- if (GroupContainmentRegistry.isContainerConcerned(part)) {
- // recover group descriptor of this part
- AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(part);
- // Look if I can get the Eclass from the IdoneContainer
- // And I look if its contain the element we want it to be compared with
- if (desc.getContentArea(part).contains(bounds)) {
- groupParts.add(part);
- }
- }
- }
- }
- }
- return new ArrayList<IGraphicalEditPart>(groupParts);
- }
-
- /**
- * Find containers which may be chosen as graphical and as model parent of the element which has already been created
- *
- * @param graphicalParentsToComplete
- * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList())
- * @param modelParentsToComplete
- * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList())
- * @param childPart
- * Edit part of the element we want to find out which may be its containers
- * @param doTransalte
- * if true compute the list of all graphical and model parent after moving and false compute the list before moving
- * @return true if succeed
- */
- @SuppressWarnings("unchecked")
- public static boolean createComputedListsOfParents(List<IGraphicalEditPart> graphicalParentsToComplete, List<IGraphicalEditPart> modelParentsToComplete, IGraphicalEditPart childPart, ChangeBoundsRequest request, boolean doTransalte) {
- Collection<View> diagramViews = new ArrayList<View>(childPart.getViewer().getEditPartRegistry().keySet());
- Object _elementView = childPart.getModel();
- if (_elementView instanceof View) {
- diagramViews.remove(_elementView);
- View myGroupView = (View) _elementView;
- withdrawGraphicalSonsOf(diagramViews, myGroupView);
- }
- Rectangle bounds = null;
- EClass childType = null;
- if (childPart != null) {
- bounds = Utils.getAbsoluteBounds(childPart).getCopy();
- childType = childPart.resolveSemanticElement().eClass();
- }
- if (doTransalte) {
- bounds = request.getTransformedRectangle(bounds);
- }
- return createComputedListsOfParents(graphicalParentsToComplete, modelParentsToComplete, bounds, childType, diagramViews, childPart);
- }
-
- /**
- * Find containers which may be chosen as graphical and as model parent of the element (after creation)
- *
- * @param graphicalParentsToComplete
- * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList())
- * @param modelParentsToComplete
- * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList())
- * @param creationRequest
- * request of creation
- * @param anyPart
- * An edit part to get the viewer
- * @param child
- * The EClass of the element to create
- * @param elementName
- * Name of the element to be created (name used to look for default size FIXME)
- * @return true if succeed
- */
- @SuppressWarnings("unchecked")
- public static boolean createComputedListsOfParents(List<IGraphicalEditPart> graphicalParentsToComplete, List<IGraphicalEditPart> modelParentsToComplete, CreateViewAndElementRequest creationRequest, IGraphicalEditPart anyPart, EClass child) {
- Collection<View> diagramViews = new ArrayList<View>(anyPart.getViewer().getEditPartRegistry().keySet());
- Dimension size = creationRequest.getSize();
- // FIXME : Add a correct default size
- // If size == null then a default size is used to create the bounds of the new elements
- if (size == null || size.isEmpty()) {
- size = new Dimension(0, 0);
- }
- Rectangle bounds = new Rectangle(creationRequest.getLocation(), size);
- return createComputedListsOfParents(graphicalParentsToComplete, modelParentsToComplete, bounds, child, diagramViews, anyPart);
- }
-
- /**
- * Find containers which may be chosen as graphical and as model parent of the element to create
- *
- * @param graphicalParentsToComplete
- * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList())
- * @param modelParentsToComplete
- * an empty list that will be filled with edits part of available model parents e.g. new ArrayList())
- * @param bounds
- * Bounds of the element
- * @param request
- * createElementRequest of the current request
- * @param views
- * Collection of view to iteration on
- * @param anyPart
- * an edit part of the diagram to get the viewer
- * @return true if successful
- */
- private static boolean createComputedListsOfParents(List<IGraphicalEditPart> graphicalParentsToComplete, List<IGraphicalEditPart> modelParentsToComplete, Rectangle bounds, EClass child, Collection<View> views, IGraphicalEditPart anyPart) {
- if (views.isEmpty()) {
- return false;
- }
- for (Object view : views) {
- if (view instanceof View) {
- Object editpart = anyPart.getViewer().getEditPartRegistry().get(view);
- if (editpart instanceof IGraphicalEditPart) {
- IGraphicalEditPart part = (IGraphicalEditPart) editpart;
- if (GroupContainmentRegistry.isContainerConcerned(part)) {
- AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(part);
- // Check if the current part contains the element
- // FIXME replace this piece of code by isItVisualyContained
- if (desc.getContentArea(part).contains(bounds)) {
- if (child instanceof EClass) {
- if (desc.canIBeModelParentOf(child)) {
- // If an edit part can be a model parent then is also a possible graphical parent
- graphicalParentsToComplete.add(part);
- modelParentsToComplete.add(part);
- } else {
- if (desc.canIBeGraphicalParentOf(child)) {
- graphicalParentsToComplete.add(part);
- }
- }
- }
- }
- }
- }
- }
- }
- // Try to reduce the number of available parents by removing
- if (graphicalParentsToComplete.size() > 1) {
- withdrawUselessAncestorsElements(graphicalParentsToComplete, Mode.GRAPHICAL_AND_MODEL);
- }
- if (modelParentsToComplete.size() > 1) {
- withdrawUselessAncestorsElements(modelParentsToComplete, Mode.MODEL);
- }
- // FIXME Sort the two list in order to have the most relevant parent first (lowest surface )
- return true;
- }
-
- /**
- * This method complete the list childsToComplete to add element which are visually contained in the element in creation "parent" and which can
- * be graphical children of this new elements
- *
- * @param childsToComplete
- * Empty list which will contain in the newly created element "parent" and which can be graphical children of this new elements
- * @param creationRequest
- * request of creation
- * @param anyPart
- * An edit part to get the viewer
- * @param descriptor
- * Descriptor of the element in creation
- * @param ElementTypeName
- * Name of the element to be created (name used to look for default size FIXME)
- * @return true if succeed
- */
- public static boolean createComputedListsOfVisualYRelatedElements(List<IGraphicalEditPart> childsToComplete, CreateViewAndElementRequest creationRequest, IGraphicalEditPart anyPart, AbstractContainerNodeDescriptor descriptor) {
- Collection<View> diagramViews = new ArrayList<View>(anyPart.getViewer().getEditPartRegistry().keySet());
- Dimension size = creationRequest.getSize();
- // FIXME : Add a correct default size
- // If size == null then a default size is used to create the bounds of the new elements
- if (size == null || size.isEmpty()) {
- size = new Dimension(0, 0);
- }
- Rectangle bounds = new Rectangle(creationRequest.getLocation(), size);
- createComputedListsOfVisualyRelatedElements(childsToComplete, bounds, descriptor, diagramViews, anyPart);
- return true;
- }
-
- /**
- * This method complete the list childsToComplete to add element which are visually contained in the element which is moving ("parent") and which
- * can
- * be graphical children of this new elements
- *
- * @param childsToComplete
- * Empty list which will contain in the newly created element "parent" and which can be graphical children of this new elements
- * @param request
- * {@link ChangeBoundsRequest}
- * @param parentPart
- * {@link IGraphicalEditPart} of the parent
- * @param descriptor
- * {@link AbstractContainerNodeDescriptor} of the parent
- * @return true is succeed
- */
- public static boolean createComputedListsOfVisuallyRelatedElements(List<IGraphicalEditPart> childsToComplete, ChangeBoundsRequest request, IGraphicalEditPart parentPart, AbstractContainerNodeDescriptor descriptor, boolean doTransalte) {
- Collection<View> diagramViews = new ArrayList<View>(parentPart.getViewer().getEditPartRegistry().keySet());
- diagramViews.remove(parentPart.getModel());
- Rectangle bounds = null;
-
- IGraphicalEditPart compartmentEditPart = (IGraphicalEditPart) Utils.getCompartementEditPartFromMainEditPart(parentPart.getViewer().getEditPartRegistry(), parentPart);
- if (compartmentEditPart == null) {
- compartmentEditPart = parentPart;
- }
- if (parentPart != null) {
- bounds = Utils.getAbsoluteBounds(compartmentEditPart).getCopy();
- }
- if (doTransalte) {
- // bounds.translate(request.getMoveDelta());
- bounds = request.getTransformedRectangle(bounds);
- }
- createComputedListsOfVisualyRelatedElements(childsToComplete, bounds, descriptor, diagramViews, parentPart);
- return true;
- }
-
- /***
- * Compute a list of all group which include the bounds of my element which has been moved with the following request
- *
- * @param element
- * Element which we can know the groups which it intersect
- * @param request
- * {@link ChangeBoundsRequest} of the moving group
- * @param doTranslate
- * if true translate the bound of the element. (used to find the difference between element before and after the command)
- * @return The list of {@link IGraphicalEditPart} group that which has their compartment edit part which intersect the compartment of my
- */
- public static List<IGraphicalEditPart> createComputeListsOfAllGroupContainerVisually(IGraphicalEditPart element, ChangeBoundsRequest request, boolean doTranslate, IGraphicalEditPart movingParent) {
- List<IGraphicalEditPart> result = new ArrayList<IGraphicalEditPart>();
- EditPartViewer viewer = element.getViewer();
- Map editPartRegistry = null;
- if (viewer != null) {
- editPartRegistry = viewer.getEditPartRegistry();
- }
- // Test on entrances
- if (editPartRegistry == null || element == null) {
- return null;
- }
- // Get the compartment edit part
- IGraphicalEditPart myCompartmentEditPart = (IGraphicalEditPart) getCompartementEditPartFromMainEditPart(editPartRegistry, element);
- Rectangle myBounds = null;
- /*
- * Find the bounds of the compartment if none use the figure bounds
- */
- if (myCompartmentEditPart != null) {
- myBounds = getAbsoluteBounds(myCompartmentEditPart).getCopy();
- } else {
- myBounds = getAbsoluteBounds(element).getCopy();
- }
- /*
- * If use the translated figure use as bounds for the childs its bounds translated with the delta move
- */
- if (doTranslate) {
- myBounds = myBounds.translate(request.getMoveDelta());
- }
-
- Collection<View> diagramViews = new ArrayList<View>(editPartRegistry.keySet());
- Object _elementView = element.getModel();
- diagramViews.remove(_elementView);
- /*
- * Withdraw from the collection of element all elements which are graphical child in myGroupView
- */
- if (_elementView instanceof View) {
- View myGroupView = (View) _elementView;
- withdrawGraphicalSonsOf(diagramViews, myGroupView);
- }
-
- /*
- * For all graphical edits parts try to know if it visually contained the child
- */
- for (Object view : diagramViews) {
- if (view instanceof View) {
- Object editpart = editPartRegistry.get(view);
- if (editpart instanceof IGraphicalEditPart) {
- IGraphicalEditPart part = (IGraphicalEditPart) editpart;
- IGraphicalEditPart partCompartment = (IGraphicalEditPart) getCompartementEditPartFromMainEditPart(editPartRegistry, part);
- if (GroupContainmentRegistry.isContainerConcerned(part) && partCompartment != null) {
- Rectangle partBounds = getAbsoluteBounds(partCompartment);
- if ((part.getParent().equals(movingParent) || partCompartment.equals(movingParent)) && doTranslate) {
- partBounds = request.getTransformedRectangle(partBounds);
- }
- if (partBounds.contains(myBounds)) {
- result.add(part);
- }
- }
- }
- }
- }
-
-
- return result;
- }
-
- /**
- * Function which withdraw from a list of view all view which are descendant of the myView parameter
- * (This function is called recursively
- *
- * @param views
- * List of the view
- * @param myView
- * The view we want to remove the descendant
- */
- private static void withdrawGraphicalSonsOf(Collection<View> views, View myView) {
- for (Object o : myView.getChildren()) {
- if (o instanceof View) {
- View childView = (View) o;
- withdrawGraphicalSonsOf(views, childView);
- views.remove(childView);
- }
-
- }
- }
-
- /**
- * Find containers which may be chosen as graphical and as model parent of the element
- *
- * @param childsToComplete
- * Empty list which will contain in the newly created element "parent" and which can be graphical children of this new elements
- * @param parentsBounds
- * Bounds of the element
- * @param descriptors
- * Descriptor of the element in creation
- * @param views
- * Collection of view to iteration on
- * @param anyPart
- * an edit part of the diagram to get the viewer
- * @return true if succeed
- */
- private static boolean createComputedListsOfVisualyRelatedElements(List<IGraphicalEditPart> childsToComplete, Rectangle parentsBounds, AbstractContainerNodeDescriptor descriptor, Collection<View> views, IGraphicalEditPart anyPart) {
- /*
- * 1 - Compute the EClass(s) which the element can be parent of : listEclass
- * 2 - Iterate on views : v
- * 2.1 - If v correspond to a main editPart : part
- * 2.1.1 - If v correspond to a a EClass which belong to listEclass
- * 2.1.1.1 - If part is visually contained is the parent then add to the list
- * 3 - Withdraw useless elements
- */
- // Set<AbstractContainerNodeDescriptor> descriptors = GroupContainmentRegistry.getDescriptorsWithContainerEClass(parentEclass);
- List<EClass> possibleChildrenEClass = new ArrayList<EClass>(descriptor.getPossibleGraphicalChildren());
- if (!possibleChildrenEClass.isEmpty()) {
- for (Object view : views) {
- if (view instanceof View) {
- View childView = (View) view;
- EObject element = childView.getElement();
- if (element != null) {
- EClass childEclass = (element.eClass());
- Object editpart = anyPart.getViewer().getEditPartRegistry().get(childView);
- if (editpart instanceof IGraphicalEditPart) {
- IGraphicalEditPart part = (IGraphicalEditPart) editpart;
- if (isMainEditPart(part)) {
- for (EClass possibleChild : possibleChildrenEClass) {
- if (possibleChild.isSuperTypeOf(childEclass)) {
- if (isItVisualyContained(parentsBounds, part)) {
- childsToComplete.add(part);
- break;
- }
- }
- }
- }
- }
- }
- }
- }
- if (childsToComplete.size() > 1) {
- withdrawUselessDescendantElements(childsToComplete, Mode.GRAPHICAL_AND_MODEL);
- }
- }
-
- return true;
- }
-
- /**
- * This methods is used to know if an edit part is contained in a rectangle
- *
- * @param parentBounds
- * Rectangle of the parent
- * @param child
- * IGraphicalEditPart of the element we want to test
- * @return true if the bounds of child are contained in parentsBounds
- */
- private static boolean isItVisualyContained(Rectangle parentBounds, IGraphicalEditPart child) {
-
- if (child.getParent() instanceof IGraphicalEditPart) {
- // an edit part is considered the "main" edit part of an element if it is not contained in an edit part of the same element (e.g. not a label nor a compartment)
- // Rectangle bounds = child.getFigure().getBounds().getCopy();
- //
- // ((IGraphicalEditPart)child.getParent()).getFigure().translateToAbsolute(bounds);
-
- Rectangle bounds = Utils.getAbsoluteBounds(child);
- if (bounds != null) {
- if (parentBounds.contains(bounds)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return true if the edit part is the main editPart of a model element (e.g the label is not the main edit part of an activityPartition
- *
- * @param part
- * IGraphicalEditPart to test
- * @return
- */
- public static boolean isMainEditPart(IGraphicalEditPart part) {
- EObject currentElement = part.resolveSemanticElement();
- EditPart parentEditPart = part.getParent();
- if (parentEditPart instanceof IGraphicalEditPart) {
- return !currentElement.equals(((IGraphicalEditPart) parentEditPart).resolveSemanticElement());
- } else {
- return true;
- }
- }
-
- /**
- * This method remove all elements from the list which have a parent in the (graphical model) or model in the list
- *
- * @param listToModify
- * List of elements (IGraphicalEditPart
- * @param mode
- * if GraphicalAndModelElementComparator.MODEL then it only take care of model parent if
- * GraphicalAndModelElementComparator.GRAPHICAL_AND_MODEL it take care of graphical and logical relationship
- * @return true if succeed
- */
- private static void withdrawUselessAncestorsElements(List<IGraphicalEditPart> listToModify, Mode mode) {
- if (!listToModify.isEmpty()) {
-
- GraphicalAndModelElementComparator comparator = new GraphicalAndModelElementComparator(listToModify.get(0));
- // Select the comparator mode
-
- comparator.setMode(mode);
-
- /**
- * Keep in the list only elements which which have no smaller element ( with this comparator)
- *
- */
- for (int element = 0; element < listToModify.size(); element++) {
- for (int elementToCompare = element + 1; elementToCompare < listToModify.size(); elementToCompare++) {
- int compare = comparator.compare(listToModify.get(element), listToModify.get(elementToCompare));
- if (compare < 0) {
- listToModify.remove(element);
- element--;
- elementToCompare = listToModify.size();
-
- } else if (compare > 0) {
- listToModify.remove(elementToCompare);
- elementToCompare--;
- }
- }
- }
- }
- }
-
- /**
- * This method will withdraw all EObject directly referenced by object which are also referenced by one of its parents (parent by reference and
- * parent by containment)
- *
- * @param object
- */
- public static void withDrawRedundantElementReferenced(EObject object) {
- /*
- * Algo :
- * 1 - Select all references which are Group Framework concerned and which represent a reference to a parent
- * 2 - Create a Set directlyReferencedByElement of EObject directly referenced by object
- * 3 - Iterate thought parents to see if one of them also point at an element of directlyReferencedByElement
- */
- /*
- * 1 - Select all references which are Group Framework concerned and which represent a reference to a parent
- */
- Set<EReference> groupFrameworkReferences = GroupContainmentRegistry.getAllERefencesFromNodeToGroup();
- HashMap<EObject, EReference> referencingGroupsAndTheirRelation = new HashMap<EObject, EReference>();
- Set<EObject> elementToVosit = new HashSet<EObject>();
- for (EReference ref : groupFrameworkReferences) {
- if (object.eClass().getEAllReferences().contains(ref)) {
- // list of groups containing the object
- List<EObject> groups;
- if (ref.isMany()) {
- groups = (List<EObject>) object.eGet(ref);
- } else {
- groups = Collections.singletonList((EObject) object.eGet(ref));
- }
- if (!ref.isContainment()) {
- /*
- * 2 - Create a Set directlyReferencedByElement of EObject directly referenced by object
- */
- for (EObject element : groups) {
- if (!referencingGroupsAndTheirRelation.containsKey(element) && !ref.isDerived()) {
- referencingGroupsAndTheirRelation.put(element, ref);
- }
- }
- }
- for (EObject group : groups) {
- if (group != null) {
- elementToVosit.add(group);
- }
- }
- }
- }
- Set<EObject> elementAlreadyVisited = new HashSet<EObject>();
- for (EObject visitingElement : elementToVosit) {
- withDrawRedundantElementReferenced(object, groupFrameworkReferences, referencingGroupsAndTheirRelation, elementAlreadyVisited, visitingElement);
- }
- }
-
- /**
- * This method will withdraw all EObject directly referenced by object which are also referenced by one of its parents (parent by reference and
- * parent by containment). This method is called recursively
- *
- * @param originalEObject
- * The EObject on which you want to check the reference
- * @param groupFrameworkReferences
- * All the EReference which are used on the groupFramework and which represent a relation from a element to its parent
- * @param directlyReferencedByElement
- * Set of elements which are directly referenced by the original element
- * @param elementAlreadyVisited
- * Set of element already visited. Used to avoid infinite loop
- * @param visitingElement
- * The current element which is being visited
- */
- private static void withDrawRedundantElementReferenced(EObject originalEObject, Set<EReference> groupFrameworkReferences, Map<EObject, EReference> directlyReferencedByElement, Set<EObject> elementAlreadyVisited, EObject visitingElement) {
- if (visitingElement != null) {
- elementAlreadyVisited.add(visitingElement);
- for (EReference ref : groupFrameworkReferences) {
- if (visitingElement != null) {
- if (visitingElement.eClass().getEAllReferences().contains(ref)) {
- List<EObject> groups;
- if (ref.isMany()) {
- groups = (List<EObject>) visitingElement.eGet(ref);
- } else {
- groups = Collections.singletonList((EObject) visitingElement.eGet(ref));
- }
- for (EObject currentElementParentGroup : groups) {
- // If it belong to the directly referenced element then
- if (directlyReferencedByElement.containsKey(currentElementParentGroup)) {
- withdrawEObjectFromReference(originalEObject, currentElementParentGroup, directlyReferencedByElement.get(currentElementParentGroup));
- // parents already handled in the first recursion (as direct parent group)
- } else if (elementAlreadyVisited.contains(currentElementParentGroup)) {
- // element already met, avoid infinite loop
- org.eclipse.papyrus.uml.diagram.common.groups.Activator.getDefault().getLog().log(new Status(IStatus.WARNING, org.eclipse.papyrus.uml.diagram.common.groups.Activator.PLUGIN_ID, "There is a circle element reference"));
- } else {
- // else iterate recursively also on this group's parents
- withDrawRedundantElementReferenced(originalEObject, groupFrameworkReferences, directlyReferencedByElement, elementAlreadyVisited, currentElementParentGroup);
- // elementToVosit.add(currentCompareElement);
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * This method is used to with an element of a reference
- *
- * @param source
- * EObject from which the reference start
- * @param destination
- * EObject to which the reference start
- * @param ref
- * EReference
- */
- private static void withdrawEObjectFromReference(EObject source, EObject destination, EReference ref) {
- if (ref != null && source != null && destination != null) {
- if (ref != null && ref.isMany()) {
- Collection<EObject> collection = (Collection<EObject>) source.eGet(ref);
- if (collection.contains(destination)) {
- collection.remove(destination);
- }
- } else if (ref != null && !ref.isMany()) {
- source.eUnset(ref);
- }
- }
- }
-
- /**
- * This method remove all elements from the list which have a descendant in the (graphical model) or model in the list
- *
- * @param listToModify
- * List of elements (IGraphicalEditPart
- * @param mode
- * if GraphicalAndModelElementComparator.MODEL then it only take care of model parent if
- * GraphicalAndModelElementComparator.GRAPHICAL_AND_MODEL it take care of graphical and logical relationship
- * @return true if succeed
- */
- private static boolean withdrawUselessDescendantElements(List<IGraphicalEditPart> listToModify, Mode mode) {
-
- if (!listToModify.isEmpty()) {
-
- GraphicalAndModelElementComparator comparator = new GraphicalAndModelElementComparator(listToModify.get(0));
- // Select the comparator mode
- comparator.setMode(mode);
- for (int element = 0; element < listToModify.size(); element++) {
- for (int elementToCompare = element + 1; elementToCompare < listToModify.size(); elementToCompare++) {
- int compare = comparator.compare(listToModify.get(element), listToModify.get(elementToCompare));
- if (compare > 0) {
- listToModify.remove(element);
- element--;
- elementToCompare = listToModify.size();
-
- } else if (compare < 0) {
- listToModify.remove(elementToCompare);
- elementToCompare--;
- }
- }
- }
- }
- return true;
- }
-
-
-
-
-
- /**
- * Find the children edit parts which may be contained by the group in the given bounds.
- *
- * @param contentArea
- * the new or old content area the group
- * @param groupEditPart
- * the group edit part
- * @param diagramPart
- * the diagram edit part
- * @return the list of edit parts that are within the given bounds and which element can be children according to the group framework
- */
- public static List<IGraphicalEditPart> findPossibleChildren(Rectangle contentArea, IGraphicalEditPart groupEditPart, DiagramEditPart diagramPart) {
- AbstractContainerNodeDescriptor descriptor = GroupContainmentRegistry.getContainerDescriptor(groupEditPart);
- if (diagramPart == null || descriptor == null) {
- return Collections.emptyList();
- }
- Set<IGraphicalEditPart> groupParts = new HashSet<IGraphicalEditPart>();
- for (Object view : diagramPart.getViewer().getEditPartRegistry().keySet()) {
- if (view instanceof View) {
- Object editpart = diagramPart.getViewer().getEditPartRegistry().get(view);
- if (editpart instanceof IGraphicalEditPart && editpart instanceof IPrimaryEditPart && !groupEditPart.equals(editpart)) {
- IGraphicalEditPart part = (IGraphicalEditPart) editpart;
- // check bounds
- boolean boundsOK = false;
- if (groupEditPart.getChildren().contains(editpart)) {
- // graphically contained part will follow the move.
- boundsOK = true;
- } else {
- Rectangle figBounds = part.getFigure().getBounds().getCopy();
- part.getFigure().translateToAbsolute(figBounds);
- if (contentArea.contains(figBounds)) {
- boundsOK = true;
- }
- }
- if (boundsOK) {
- // check group can contain
- EObject child = part.resolveSemanticElement();
- for (EReference refToChildren : descriptor.getChildrenReferences()) {
- if (refToChildren.getEReferenceType().isInstance(child)) {
- groupParts.add(part);
- break;
- }
- }
- }
- }
- }
- }
- return new ArrayList<IGraphicalEditPart>(groupParts);
- }
-
- // Debug purpose
- public static void drawRect(IGraphicalEditPart editPart, Rectangle refContentArea) {
- RoundedRectangle rectFeedback = new RoundedRectangle();
- rectFeedback.setBounds(refContentArea);
- rectFeedback.setCornerDimensions(new Dimension(0, 0));
- rectFeedback.setLineWidth(2);
- rectFeedback.setLineStyle(Graphics.LINE_DASH);
- rectFeedback.setForegroundColor(editPart.getFigure().getForegroundColor());
- rectFeedback.setOpaque(true);
- rectFeedback.setFill(false);
-
- IFigure layer = LayerManager.Helper.find(editPart).getLayer(LayerConstants.FEEDBACK_LAYER);
- layer.add(rectFeedback);
- }
-
- /**
- * Get the command to change the graphical parent of an element
- *
- * @param childPart
- * the child edit part to change parent
- * @param newParent
- * the new graphical parent
- * @return the command or null if no effect
- */
- public static Command getUpdateGraphicalParentCmd(IGraphicalEditPart childPart, IGraphicalEditPart newParent) {
- if (childPart.getParent().equals(newParent)) {
- return null;
- }
- ChangeBoundsRequest request = new ChangeBoundsRequest();
- request.setMoveDelta(new Point(0, 0));
- request.setSizeDelta(new Dimension(0, 0));
- request.setEditParts(childPart);
- Point loc = childPart.getFigure().getBounds().getLocation().getCopy();
- childPart.getFigure().translateToAbsolute(loc);
- request.setLocation(loc);
- request.setType(RequestConstants.REQ_DROP);
- org.eclipse.gef.commands.Command cmd = newParent.getCommand(request);
- if (cmd != null && cmd.canExecute()) {
- return new GEFtoEMFCommandWrapper(cmd);
- } else {
- return null;
- }
- }
-
- /**
- * Get the command to add a reference from a parent group edit part to its new child
- *
- * @param newParentpart
- * the new parent edit part which contains children by reference
- * @param newChildPart
- * the child edit part
- * @return the command or null
- */
- public static Command getAddReferenceToChildCmd(IGraphicalEditPart newParentpart, IGraphicalEditPart newChildPart) {
- AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(newParentpart);
- EObject parent = newParentpart.resolveSemanticElement();
- EObject child = newChildPart.resolveSemanticElement();
- // get the better child reference to use
- EReference usedReference = getBestReferenceAmongList(desc.getChildrenReferences(), child);
- if (usedReference != null) {
- return new AddCommand(newParentpart.getEditingDomain(), parent, usedReference, child);
- } else {
- // no possible child reference
- return null;
- }
- }
-
- /**
- * Get the best reference (nearest to child's type) to a child among the list
- *
- * @param childrenReferences
- * the possible children references
- * @param child
- * the child eobject to choose a referencefor
- * @return the most precise child reference or null
- */
- public static EReference getBestReferenceAmongList(List<EReference> childrenReferences, EObject child) {
- EReference usedReference = null;
- for (EReference ref : childrenReferences) {
- if (ref.getEReferenceType().isInstance(child)) {
- if (usedReference == null || ref.getEReferenceType().getEAllSuperTypes().contains(usedReference.getEReferenceType())) {
- // the ref feature is more precise than the previously selected one. Use it instead.
- usedReference = ref;
- }
- }
- }
- return usedReference;
- }
-
- /**
- * Get the command to remove a reference from a parent group edit part to its old child
- *
- * @param oldParentpart
- * the old parent edit part which contains children by reference
- * @param oldChildPart
- * the child edit part
- * @return the command or null
- */
- public static Command getRemoveReferenceToChildCmd(IGraphicalEditPart oldParentpart, IGraphicalEditPart oldChildPart) {
- AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(oldParentpart);
- EObject parent = oldParentpart.resolveSemanticElement();
- EObject child = oldChildPart.resolveSemanticElement();
- CompoundCommand globalCmd = new CompoundCommand();
- // get the better child reference to use
- EReference usedReference = null;
- for (EReference ref : desc.getChildrenReferences()) {
- if (parent.eGet(ref) instanceof List<?>) {
- if (((List<?>) parent.eGet(ref)).contains(child)) {
- // remove the reference to the child
- Command cmd = new RemoveCommand(oldParentpart.getEditingDomain(), parent, usedReference, child);
- if (cmd.canExecute()) {
- globalCmd.append(cmd);
- }
- }
- }
- }
- if (!globalCmd.isEmpty()) {
- return globalCmd;
- } else {
- return null;
- }
- }
-
- /**
- * Get the bounds of an edit part
- *
- * @param part
- * edit part to find bounds
- * @return part's bounds in absolute coordinates
- */
- public static Rectangle getAbsoluteBounds(IGraphicalEditPart part) {
- // take bounds from figure
- part.getTopGraphicEditPart().refresh();
- Rectangle bounds = part.getFigure().getBounds().getCopy();
-
- if (part.getNotationView() instanceof Node) {
- // rather update with up to date model bounds
- Node node = (Node) part.getNotationView();
- LayoutConstraint cst = node.getLayoutConstraint();
- if (cst instanceof Bounds) {
- Bounds b = (Bounds) cst;
- Point parentLoc = part.getFigure().getParent().getBounds().getLocation();
- if (b.getX() > 0) {
- bounds.x = b.getX() + parentLoc.x;
- }
- if (b.getY() > 0) {
- bounds.y = b.getY() + parentLoc.y;
- }
- if (b.getHeight() != -1) {
- bounds.height = b.getHeight();
- }
- if (b.getWidth() != -1) {
- bounds.width = b.getWidth();
- }
- }
- }
-
- part.getFigure().getParent().translateToAbsolute(bounds);
-
- return bounds;
- }
-
- /**
- * This method compute the delta between to IGraphicalEditPart.
- *
- * @param oldParent
- * Old IGraphicalEditPart
- * @param newParent
- * New IGraphicalEditPart
- * @return Return a DDimention between the two bounds (often use to translate point or Rectangle)
- */
- public static Dimension computeDeltaToChangeParent(IGraphicalEditPart oldParent, IGraphicalEditPart newParent) {
- Rectangle hostBounds = Utils.getAbsoluteBounds(oldParent);
- Rectangle parentBounds = Utils.getAbsoluteBounds(newParent);
- Dimension delta = hostBounds.getLocation().getDifference(parentBounds.getLocation());
- return delta;
- }
-
- public static Dimension computeDeltaToChangeParent(IGraphicalEditPart oldParent, Rectangle newParent) {
- Rectangle hostBounds = Utils.getAbsoluteBounds(oldParent);
- Dimension delta = hostBounds.getLocation().getDifference(newParent.getLocation());
- return delta;
- }
-
- /**
- * Give the reference object which can reference the child for the parent type part
- *
- * @param parentType
- * EClass of the parent OBject you want to know the EReference
- * @param childType
- * EClass of the child you want to test
- * @return null if no reference is found
- */
- public static EReference getContainmentEReference(EClass parentType, EClass childType) {
- List<EReference> result = new ArrayList<EReference>();
- EReference usedReference = null;
- for (EReference reference : parentType.getEAllContainments()) {
- if (reference.getEReferenceType().isSuperTypeOf(childType) && !reference.isDerived()) {
- result.add(reference);
- }
- }
-
- // Select the best containment relation
- for (EReference ref : result) {
- if (usedReference == null || ref.getEReferenceType().getEAllSuperTypes().contains(usedReference.getEReferenceType())) {
- // the ref feature is more precise than the previously selected one. Use it instead.
- usedReference = ref;
- }
- }
- return usedReference;
- }
-
- /**
- *
- * @param editPartRegistry
- * Check if the object is contained in the editPartRegistery
- * @param _child
- * @return
- */
- public static boolean isContainedInRegistery(Map editPartRegistry, Object _child) {
- if (_child instanceof IGraphicalEditPart) {
- return editPartRegistry.containsKey(((IGraphicalEditPart) _child).getModel());
- }
- return false;
-
- }
-
- /**
- * Test is the element is a compartment edit part that can be used to create the child
- *
- * @param editPartRegistry
- * @param _child
- * @return
- */
- public static boolean isAGoodCompartementEditPart(Map editPartRegistry, Object _child) {
- return _child instanceof CompartmentEditPart && isContainedInRegistery(editPartRegistry, _child) && ((EditPart) _child) instanceof ShapeCompartmentEditPart;
- }
-
- /**
- * Get the compartment editPart from a parent editPart
- *
- * @param editPartRegistry
- * EditPartRegistery
- * @param parentEditPart
- * EditPart of the parent
- * @return the CompartementEditPart and null if not found
- */
- public static EditPart getCompartementEditPartFromMainEditPart(Map editPartRegistry, EditPart parentEditPart) {
- EditPart resultCompartmentEditPart = null;
- // An edit part has been found
- if (parentEditPart instanceof CompartmentEditPart) {
- resultCompartmentEditPart = parentEditPart;
- return resultCompartmentEditPart;
- } else {
- List<EditPart> potentialCompartementPart = new ArrayList<EditPart>();
- for (Object _child : parentEditPart.getChildren()) {
- if (isAGoodCompartementEditPart(editPartRegistry, _child)) {
- potentialCompartementPart.add((EditPart) _child);
- }
- }
- if (potentialCompartementPart.size() == 1) {
- resultCompartmentEditPart = potentialCompartementPart.get(0);
- return resultCompartmentEditPart;
- } else if (potentialCompartementPart.size() == 1) {
- // FIXME find a correct behavior if several potential CompartementPart (should normally never be the case)
- resultCompartmentEditPart = potentialCompartementPart.get(0);
- return resultCompartmentEditPart;
- }
- }
- return resultCompartmentEditPart;
- }
-
-
- /**
- * Get the child map needed for {@link ChangeModelParentCommand}
- *
- * @param elementType
- * {@link EClass} of the elemnt you want to find the default model parent
- * @param getHost
- * Host of the editPolicy
- * @param newIgraphicalParent
- * {@link IGraphicalEditPart} to complete with the new {@link IGraphicalEditPart} of the defautl model parent
- * @return
- */
- public static DefaultModelParent getDefaultModelParent(EClass elementType, IGraphicalEditPart getHost) {
- 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(elementType)) {
- return new DefaultModelParent(hostParent, containmentRelation);
- }
- }
- }
- hostParent = (IGraphicalEditPart) hostParent.getParent();
- }
- return null;
- }
-
- public static boolean isRequestGroupFrameworkConcerned(ChangeBoundsRequest request) {
- for (Object editPart : request.getEditParts()) {
- if (editPart instanceof IGraphicalEditPart) {
- IGraphicalEditPart iGraphicalEditPart = (IGraphicalEditPart) editPart;
- boolean isNodeConcerned = GroupContainmentRegistry.isNodeConcerned(iGraphicalEditPart);
- boolean isGroupConcerned = GroupContainmentRegistry.isContainerConcerned(iGraphicalEditPart);
- if (isGroupConcerned || isNodeConcerned) {
- return true;
- }
- }
- }
- return false;
- }
-}
+/***************************************************************************** + * 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.core.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.draw2d.Graphics; +import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.RoundedRectangle; +import org.eclipse.draw2d.geometry.Dimension; +import org.eclipse.draw2d.geometry.Point; +import org.eclipse.draw2d.geometry.Rectangle; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.edit.command.AddCommand; +import org.eclipse.emf.edit.command.RemoveCommand; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.gef.LayerConstants; +import org.eclipse.gef.editparts.LayerManager; +import org.eclipse.gef.requests.ChangeBoundsRequest; +import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart; +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.editparts.IPrimaryEditPart; +import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart; +import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest; +import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; +import org.eclipse.gmf.runtime.notation.Bounds; +import org.eclipse.gmf.runtime.notation.LayoutConstraint; +import org.eclipse.gmf.runtime.notation.Node; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.papyrus.commands.wrappers.GEFtoEMFCommandWrapper; +import org.eclipse.papyrus.uml.diagram.common.groups.commands.ChangeModelParentCommand; +import org.eclipse.papyrus.uml.diagram.common.groups.core.groupcontainment.GroupContainmentRegistry; +import org.eclipse.papyrus.uml.diagram.common.groups.groupcontainment.AbstractContainerNodeDescriptor; +import org.eclipse.papyrus.uml.diagram.common.groups.utils.GraphicalAndModelElementComparator; +import org.eclipse.papyrus.uml.diagram.common.groups.utils.GraphicalAndModelElementComparator.Mode; + + +/** + * This class provides utility methods useful for the group framework. + * + * @author vhemery and adaussy + */ +public class Utils { + + /** + * Find the containers which may contain an edit part in the given bounds. + * + * @param bounds + * the new or old bounds of the item + * @param diagramPart + * the diagram edit part + * @return the list of edit parts that are registered through the group framework and that can contain an element within the given bounds + */ + public static List<IGraphicalEditPart> findPossibleParents(Rectangle bounds, DiagramEditPart diagramPart) { + if (diagramPart == null) { + return Collections.emptyList(); + } + Set<IGraphicalEditPart> groupParts = new HashSet<IGraphicalEditPart>(); + // For all object in diagram, find edit parts + for (Object view : diagramPart.getViewer().getEditPartRegistry().keySet()) { + if (view instanceof View) { + Object editpart = diagramPart.getViewer().getEditPartRegistry().get(view); + if (editpart instanceof IGraphicalEditPart) { + IGraphicalEditPart part = (IGraphicalEditPart) editpart; + // If this group is handled by the group framework + if (GroupContainmentRegistry.isContainerConcerned(part)) { + // recover group descriptor of this part + AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(part); + // Look if I can get the Eclass from the IdoneContainer + // And I look if its contain the element we want it to be compared with + if (desc.getContentArea(part).contains(bounds)) { + groupParts.add(part); + } + } + } + } + } + return new ArrayList<IGraphicalEditPart>(groupParts); + } + + /** + * Find containers which may be chosen as graphical and as model parent of the element which has already been created + * + * @param graphicalParentsToComplete + * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList()) + * @param modelParentsToComplete + * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList()) + * @param childPart + * Edit part of the element we want to find out which may be its containers + * @param doTransalte + * if true compute the list of all graphical and model parent after moving and false compute the list before moving + * @return true if succeed + */ + @SuppressWarnings("unchecked") + public static boolean createComputedListsOfParents(List<IGraphicalEditPart> graphicalParentsToComplete, List<IGraphicalEditPart> modelParentsToComplete, IGraphicalEditPart childPart, ChangeBoundsRequest request, boolean doTransalte) { + Collection<View> diagramViews = new ArrayList<View>(childPart.getViewer().getEditPartRegistry().keySet()); + Object _elementView = childPart.getModel(); + if (_elementView instanceof View) { + diagramViews.remove(_elementView); + View myGroupView = (View) _elementView; + withdrawGraphicalSonsOf(diagramViews, myGroupView); + } + Rectangle bounds = null; + EClass childType = null; + if (childPart != null) { + bounds = Utils.getAbsoluteBounds(childPart).getCopy(); + childType = childPart.resolveSemanticElement().eClass(); + } + if (doTransalte) { + bounds = request.getTransformedRectangle(bounds); + } + return createComputedListsOfParents(graphicalParentsToComplete, modelParentsToComplete, bounds, childType, diagramViews, childPart); + } + + /** + * Find containers which may be chosen as graphical and as model parent of the element (after creation) + * + * @param graphicalParentsToComplete + * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList()) + * @param modelParentsToComplete + * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList()) + * @param creationRequest + * request of creation + * @param anyPart + * An edit part to get the viewer + * @param child + * The EClass of the element to create + * @param elementName + * Name of the element to be created (name used to look for default size FIXME) + * @return true if succeed + */ + @SuppressWarnings("unchecked") + public static boolean createComputedListsOfParents(List<IGraphicalEditPart> graphicalParentsToComplete, List<IGraphicalEditPart> modelParentsToComplete, CreateViewAndElementRequest creationRequest, IGraphicalEditPart anyPart, EClass child) { + Collection<View> diagramViews = new ArrayList<View>(anyPart.getViewer().getEditPartRegistry().keySet()); + Dimension size = creationRequest.getSize(); + // FIXME : Add a correct default size + // If size == null then a default size is used to create the bounds of the new elements + if (size == null || size.isEmpty()) { + size = new Dimension(0, 0); + } + Rectangle bounds = new Rectangle(creationRequest.getLocation(), size); + return createComputedListsOfParents(graphicalParentsToComplete, modelParentsToComplete, bounds, child, diagramViews, anyPart); + } + + /** + * Find containers which may be chosen as graphical and as model parent of the element to create + * + * @param graphicalParentsToComplete + * an empty list that will be filled with edits part of available graphical parents (e.g. new ArrayList()) + * @param modelParentsToComplete + * an empty list that will be filled with edits part of available model parents e.g. new ArrayList()) + * @param bounds + * Bounds of the element + * @param request + * createElementRequest of the current request + * @param views + * Collection of view to iteration on + * @param anyPart + * an edit part of the diagram to get the viewer + * @return true if successful + */ + private static boolean createComputedListsOfParents(List<IGraphicalEditPart> graphicalParentsToComplete, List<IGraphicalEditPart> modelParentsToComplete, Rectangle bounds, EClass child, Collection<View> views, IGraphicalEditPart anyPart) { + if (views.isEmpty()) { + return false; + } + for (Object view : views) { + if (view instanceof View) { + Object editpart = anyPart.getViewer().getEditPartRegistry().get(view); + if (editpart instanceof IGraphicalEditPart) { + IGraphicalEditPart part = (IGraphicalEditPart) editpart; + if (GroupContainmentRegistry.isContainerConcerned(part)) { + AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(part); + // Check if the current part contains the element + // FIXME replace this piece of code by isItVisualyContained + if (desc.getContentArea(part).contains(bounds)) { + if (child instanceof EClass) { + if (desc.canIBeModelParentOf(child)) { + // If an edit part can be a model parent then is also a possible graphical parent + graphicalParentsToComplete.add(part); + modelParentsToComplete.add(part); + } else { + if (desc.canIBeGraphicalParentOf(child)) { + graphicalParentsToComplete.add(part); + } + } + } + } + } + } + } + } + // Try to reduce the number of available parents by removing + if (graphicalParentsToComplete.size() > 1) { + withdrawUselessAncestorsElements(graphicalParentsToComplete, Mode.GRAPHICAL_AND_MODEL); + } + if (modelParentsToComplete.size() > 1) { + withdrawUselessAncestorsElements(modelParentsToComplete, Mode.MODEL); + } + // FIXME Sort the two list in order to have the most relevant parent first (lowest surface ) + return true; + } + + /** + * This method complete the list childsToComplete to add element which are visually contained in the element in creation "parent" and which can + * be graphical children of this new elements + * + * @param childsToComplete + * Empty list which will contain in the newly created element "parent" and which can be graphical children of this new elements + * @param creationRequest + * request of creation + * @param anyPart + * An edit part to get the viewer + * @param descriptor + * Descriptor of the element in creation + * @param ElementTypeName + * Name of the element to be created (name used to look for default size FIXME) + * @return true if succeed + */ + public static boolean createComputedListsOfVisualYRelatedElements(List<IGraphicalEditPart> childsToComplete, CreateViewAndElementRequest creationRequest, IGraphicalEditPart anyPart, AbstractContainerNodeDescriptor descriptor) { + Collection<View> diagramViews = new ArrayList<View>(anyPart.getViewer().getEditPartRegistry().keySet()); + Dimension size = creationRequest.getSize(); + // FIXME : Add a correct default size + // If size == null then a default size is used to create the bounds of the new elements + if (size == null || size.isEmpty()) { + size = new Dimension(0, 0); + } + Rectangle bounds = new Rectangle(creationRequest.getLocation(), size); + createComputedListsOfVisualyRelatedElements(childsToComplete, bounds, descriptor, diagramViews, anyPart); + return true; + } + + /** + * This method complete the list childsToComplete to add element which are visually contained in the element which is moving ("parent") and which + * can + * be graphical children of this new elements + * + * @param childsToComplete + * Empty list which will contain in the newly created element "parent" and which can be graphical children of this new elements + * @param request + * {@link ChangeBoundsRequest} + * @param parentPart + * {@link IGraphicalEditPart} of the parent + * @param descriptor + * {@link AbstractContainerNodeDescriptor} of the parent + * @return true is succeed + */ + public static boolean createComputedListsOfVisuallyRelatedElements(List<IGraphicalEditPart> childsToComplete, ChangeBoundsRequest request, IGraphicalEditPart parentPart, AbstractContainerNodeDescriptor descriptor, boolean doTransalte) { + Collection<View> diagramViews = new ArrayList<View>(parentPart.getViewer().getEditPartRegistry().keySet()); + diagramViews.remove(parentPart.getModel()); + Rectangle bounds = null; + + IGraphicalEditPart compartmentEditPart = (IGraphicalEditPart) Utils.getCompartementEditPartFromMainEditPart(parentPart.getViewer().getEditPartRegistry(), parentPart); + if (compartmentEditPart == null) { + compartmentEditPart = parentPart; + } + if (parentPart != null) { + bounds = Utils.getAbsoluteBounds(compartmentEditPart).getCopy(); + } + if (doTransalte) { + // bounds.translate(request.getMoveDelta()); + bounds = request.getTransformedRectangle(bounds); + } + createComputedListsOfVisualyRelatedElements(childsToComplete, bounds, descriptor, diagramViews, parentPart); + return true; + } + + /*** + * Compute a list of all group which include the bounds of my element which has been moved with the following request + * + * @param element + * Element which we can know the groups which it intersect + * @param request + * {@link ChangeBoundsRequest} of the moving group + * @param doTranslate + * if true translate the bound of the element. (used to find the difference between element before and after the command) + * @return The list of {@link IGraphicalEditPart} group that which has their compartment edit part which intersect the compartment of my + */ + public static List<IGraphicalEditPart> createComputeListsOfAllGroupContainerVisually(IGraphicalEditPart element, ChangeBoundsRequest request, boolean doTranslate, IGraphicalEditPart movingParent) { + List<IGraphicalEditPart> result = new ArrayList<IGraphicalEditPart>(); + EditPartViewer viewer = element.getViewer(); + Map editPartRegistry = null; + if (viewer != null) { + editPartRegistry = viewer.getEditPartRegistry(); + } + // Test on entrances + if (editPartRegistry == null || element == null) { + return null; + } + // Get the compartment edit part + IGraphicalEditPart myCompartmentEditPart = (IGraphicalEditPart) getCompartementEditPartFromMainEditPart(editPartRegistry, element); + Rectangle myBounds = null; + /* + * Find the bounds of the compartment if none use the figure bounds + */ + if (myCompartmentEditPart != null) { + myBounds = getAbsoluteBounds(myCompartmentEditPart).getCopy(); + } else { + myBounds = getAbsoluteBounds(element).getCopy(); + } + /* + * If use the translated figure use as bounds for the childs its bounds translated with the delta move + */ + if (doTranslate) { + myBounds = myBounds.translate(request.getMoveDelta()); + } + + Collection<View> diagramViews = new ArrayList<View>(editPartRegistry.keySet()); + Object _elementView = element.getModel(); + diagramViews.remove(_elementView); + /* + * Withdraw from the collection of element all elements which are graphical child in myGroupView + */ + if (_elementView instanceof View) { + View myGroupView = (View) _elementView; + withdrawGraphicalSonsOf(diagramViews, myGroupView); + } + + /* + * For all graphical edits parts try to know if it visually contained the child + */ + for (Object view : diagramViews) { + if (view instanceof View) { + Object editpart = editPartRegistry.get(view); + if (editpart instanceof IGraphicalEditPart) { + IGraphicalEditPart part = (IGraphicalEditPart) editpart; + IGraphicalEditPart partCompartment = (IGraphicalEditPart) getCompartementEditPartFromMainEditPart(editPartRegistry, part); + if (GroupContainmentRegistry.isContainerConcerned(part) && partCompartment != null) { + Rectangle partBounds = getAbsoluteBounds(partCompartment); + if ((part.getParent().equals(movingParent) || partCompartment.equals(movingParent)) && doTranslate) { + partBounds = request.getTransformedRectangle(partBounds); + } + if (partBounds.contains(myBounds)) { + result.add(part); + } + } + } + } + } + + + return result; + } + + /** + * Function which withdraw from a list of view all view which are descendant of the myView parameter + * (This function is called recursively + * + * @param views + * List of the view + * @param myView + * The view we want to remove the descendant + */ + private static void withdrawGraphicalSonsOf(Collection<View> views, View myView) { + for (Object o : myView.getChildren()) { + if (o instanceof View) { + View childView = (View) o; + withdrawGraphicalSonsOf(views, childView); + views.remove(childView); + } + + } + } + + /** + * Find containers which may be chosen as graphical and as model parent of the element + * + * @param childsToComplete + * Empty list which will contain in the newly created element "parent" and which can be graphical children of this new elements + * @param parentsBounds + * Bounds of the element + * @param descriptors + * Descriptor of the element in creation + * @param views + * Collection of view to iteration on + * @param anyPart + * an edit part of the diagram to get the viewer + * @return true if succeed + */ + private static boolean createComputedListsOfVisualyRelatedElements(List<IGraphicalEditPart> childsToComplete, Rectangle parentsBounds, AbstractContainerNodeDescriptor descriptor, Collection<View> views, IGraphicalEditPart anyPart) { + /* + * 1 - Compute the EClass(s) which the element can be parent of : listEclass + * 2 - Iterate on views : v + * 2.1 - If v correspond to a main editPart : part + * 2.1.1 - If v correspond to a a EClass which belong to listEclass + * 2.1.1.1 - If part is visually contained is the parent then add to the list + * 3 - Withdraw useless elements + */ + // Set<AbstractContainerNodeDescriptor> descriptors = GroupContainmentRegistry.getDescriptorsWithContainerEClass(parentEclass); + List<EClass> possibleChildrenEClass = new ArrayList<EClass>(descriptor.getPossibleGraphicalChildren()); + if (!possibleChildrenEClass.isEmpty()) { + for (Object view : views) { + if (view instanceof View) { + View childView = (View) view; + EObject element = childView.getElement(); + if (element != null) { + EClass childEclass = (element.eClass()); + Object editpart = anyPart.getViewer().getEditPartRegistry().get(childView); + if (editpart instanceof IGraphicalEditPart) { + IGraphicalEditPart part = (IGraphicalEditPart) editpart; + if (isMainEditPart(part)) { + for (EClass possibleChild : possibleChildrenEClass) { + if (possibleChild.isSuperTypeOf(childEclass)) { + if (isItVisualyContained(parentsBounds, part)) { + childsToComplete.add(part); + break; + } + } + } + } + } + } + } + } + if (childsToComplete.size() > 1) { + withdrawUselessDescendantElements(childsToComplete, Mode.GRAPHICAL_AND_MODEL); + } + } + + return true; + } + + /** + * This methods is used to know if an edit part is contained in a rectangle + * + * @param parentBounds + * Rectangle of the parent + * @param child + * IGraphicalEditPart of the element we want to test + * @return true if the bounds of child are contained in parentsBounds + */ + private static boolean isItVisualyContained(Rectangle parentBounds, IGraphicalEditPart child) { + + if (child.getParent() instanceof IGraphicalEditPart) { + // an edit part is considered the "main" edit part of an element if it is not contained in an edit part of the same element (e.g. not a label nor a compartment) + // Rectangle bounds = child.getFigure().getBounds().getCopy(); + // + // ((IGraphicalEditPart)child.getParent()).getFigure().translateToAbsolute(bounds); + + Rectangle bounds = Utils.getAbsoluteBounds(child); + if (bounds != null) { + if (parentBounds.contains(bounds)) { + return true; + } + } + } + return false; + } + + /** + * Return true if the edit part is the main editPart of a model element (e.g the label is not the main edit part of an activityPartition + * + * @param part + * IGraphicalEditPart to test + * @return + */ + public static boolean isMainEditPart(IGraphicalEditPart part) { + EObject currentElement = part.resolveSemanticElement(); + EditPart parentEditPart = part.getParent(); + if (parentEditPart instanceof IGraphicalEditPart) { + return !currentElement.equals(((IGraphicalEditPart) parentEditPart).resolveSemanticElement()); + } else { + return true; + } + } + + /** + * This method remove all elements from the list which have a parent in the (graphical model) or model in the list + * + * @param listToModify + * List of elements (IGraphicalEditPart + * @param mode + * if GraphicalAndModelElementComparator.MODEL then it only take care of model parent if + * GraphicalAndModelElementComparator.GRAPHICAL_AND_MODEL it take care of graphical and logical relationship + * @return true if succeed + */ + private static void withdrawUselessAncestorsElements(List<IGraphicalEditPart> listToModify, Mode mode) { + if (!listToModify.isEmpty()) { + + GraphicalAndModelElementComparator comparator = new GraphicalAndModelElementComparator(listToModify.get(0)); + // Select the comparator mode + + comparator.setMode(mode); + + /** + * Keep in the list only elements which which have no smaller element ( with this comparator) + * + */ + for (int element = 0; element < listToModify.size(); element++) { + for (int elementToCompare = element + 1; elementToCompare < listToModify.size(); elementToCompare++) { + int compare = comparator.compare(listToModify.get(element), listToModify.get(elementToCompare)); + if (compare < 0) { + listToModify.remove(element); + element--; + elementToCompare = listToModify.size(); + + } else if (compare > 0) { + listToModify.remove(elementToCompare); + elementToCompare--; + } + } + } + } + } + + /** + * This method will withdraw all EObject directly referenced by object which are also referenced by one of its parents (parent by reference and + * parent by containment) + * + * @param object + */ + public static void withDrawRedundantElementReferenced(EObject object) { + /* + * Algo : + * 1 - Select all references which are Group Framework concerned and which represent a reference to a parent + * 2 - Create a Set directlyReferencedByElement of EObject directly referenced by object + * 3 - Iterate thought parents to see if one of them also point at an element of directlyReferencedByElement + */ + /* + * 1 - Select all references which are Group Framework concerned and which represent a reference to a parent + */ + Set<EReference> groupFrameworkReferences = GroupContainmentRegistry.getAllERefencesFromNodeToGroup(); + HashMap<EObject, EReference> referencingGroupsAndTheirRelation = new HashMap<EObject, EReference>(); + Set<EObject> elementToVosit = new HashSet<EObject>(); + for (EReference ref : groupFrameworkReferences) { + if (object.eClass().getEAllReferences().contains(ref)) { + // list of groups containing the object + List<EObject> groups; + if (ref.isMany()) { + groups = (List<EObject>) object.eGet(ref); + } else { + groups = Collections.singletonList((EObject) object.eGet(ref)); + } + if (!ref.isContainment()) { + /* + * 2 - Create a Set directlyReferencedByElement of EObject directly referenced by object + */ + for (EObject element : groups) { + if (!referencingGroupsAndTheirRelation.containsKey(element) && !ref.isDerived()) { + referencingGroupsAndTheirRelation.put(element, ref); + } + } + } + for (EObject group : groups) { + if (group != null) { + elementToVosit.add(group); + } + } + } + } + Set<EObject> elementAlreadyVisited = new HashSet<EObject>(); + for (EObject visitingElement : elementToVosit) { + withDrawRedundantElementReferenced(object, groupFrameworkReferences, referencingGroupsAndTheirRelation, elementAlreadyVisited, visitingElement); + } + } + + /** + * This method will withdraw all EObject directly referenced by object which are also referenced by one of its parents (parent by reference and + * parent by containment). This method is called recursively + * + * @param originalEObject + * The EObject on which you want to check the reference + * @param groupFrameworkReferences + * All the EReference which are used on the groupFramework and which represent a relation from a element to its parent + * @param directlyReferencedByElement + * Set of elements which are directly referenced by the original element + * @param elementAlreadyVisited + * Set of element already visited. Used to avoid infinite loop + * @param visitingElement + * The current element which is being visited + */ + private static void withDrawRedundantElementReferenced(EObject originalEObject, Set<EReference> groupFrameworkReferences, Map<EObject, EReference> directlyReferencedByElement, Set<EObject> elementAlreadyVisited, EObject visitingElement) { + if (visitingElement != null) { + elementAlreadyVisited.add(visitingElement); + for (EReference ref : groupFrameworkReferences) { + if (visitingElement != null) { + if (visitingElement.eClass().getEAllReferences().contains(ref)) { + List<EObject> groups; + if (ref.isMany()) { + groups = (List<EObject>) visitingElement.eGet(ref); + } else { + groups = Collections.singletonList((EObject) visitingElement.eGet(ref)); + } + for (EObject currentElementParentGroup : groups) { + // If it belong to the directly referenced element then + if (directlyReferencedByElement.containsKey(currentElementParentGroup)) { + withdrawEObjectFromReference(originalEObject, currentElementParentGroup, directlyReferencedByElement.get(currentElementParentGroup)); + // parents already handled in the first recursion (as direct parent group) + } else if (elementAlreadyVisited.contains(currentElementParentGroup)) { + // element already met, avoid infinite loop + org.eclipse.papyrus.uml.diagram.common.groups.Activator.getDefault().getLog().log(new Status(IStatus.WARNING, org.eclipse.papyrus.uml.diagram.common.groups.Activator.PLUGIN_ID, "There is a circle element reference")); + } else { + // else iterate recursively also on this group's parents + withDrawRedundantElementReferenced(originalEObject, groupFrameworkReferences, directlyReferencedByElement, elementAlreadyVisited, currentElementParentGroup); + // elementToVosit.add(currentCompareElement); + } + } + } + } + } + } + } + + /** + * This method is used to with an element of a reference + * + * @param source + * EObject from which the reference start + * @param destination + * EObject to which the reference start + * @param ref + * EReference + */ + private static void withdrawEObjectFromReference(EObject source, EObject destination, EReference ref) { + if (ref != null && source != null && destination != null) { + if (ref != null && ref.isMany()) { + Collection<EObject> collection = (Collection<EObject>) source.eGet(ref); + if (collection.contains(destination)) { + collection.remove(destination); + } + } else if (ref != null && !ref.isMany()) { + source.eUnset(ref); + } + } + } + + /** + * This method remove all elements from the list which have a descendant in the (graphical model) or model in the list + * + * @param listToModify + * List of elements (IGraphicalEditPart + * @param mode + * if GraphicalAndModelElementComparator.MODEL then it only take care of model parent if + * GraphicalAndModelElementComparator.GRAPHICAL_AND_MODEL it take care of graphical and logical relationship + * @return true if succeed + */ + private static boolean withdrawUselessDescendantElements(List<IGraphicalEditPart> listToModify, Mode mode) { + + if (!listToModify.isEmpty()) { + + GraphicalAndModelElementComparator comparator = new GraphicalAndModelElementComparator(listToModify.get(0)); + // Select the comparator mode + comparator.setMode(mode); + for (int element = 0; element < listToModify.size(); element++) { + for (int elementToCompare = element + 1; elementToCompare < listToModify.size(); elementToCompare++) { + int compare = comparator.compare(listToModify.get(element), listToModify.get(elementToCompare)); + if (compare > 0) { + listToModify.remove(element); + element--; + elementToCompare = listToModify.size(); + + } else if (compare < 0) { + listToModify.remove(elementToCompare); + elementToCompare--; + } + } + } + } + return true; + } + + + + + + /** + * Find the children edit parts which may be contained by the group in the given bounds. + * + * @param contentArea + * the new or old content area the group + * @param groupEditPart + * the group edit part + * @param diagramPart + * the diagram edit part + * @return the list of edit parts that are within the given bounds and which element can be children according to the group framework + */ + public static List<IGraphicalEditPart> findPossibleChildren(Rectangle contentArea, IGraphicalEditPart groupEditPart, DiagramEditPart diagramPart) { + AbstractContainerNodeDescriptor descriptor = GroupContainmentRegistry.getContainerDescriptor(groupEditPart); + if (diagramPart == null || descriptor == null) { + return Collections.emptyList(); + } + Set<IGraphicalEditPart> groupParts = new HashSet<IGraphicalEditPart>(); + for (Object view : diagramPart.getViewer().getEditPartRegistry().keySet()) { + if (view instanceof View) { + Object editpart = diagramPart.getViewer().getEditPartRegistry().get(view); + if (editpart instanceof IGraphicalEditPart && editpart instanceof IPrimaryEditPart && !groupEditPart.equals(editpart)) { + IGraphicalEditPart part = (IGraphicalEditPart) editpart; + // check bounds + boolean boundsOK = false; + if (groupEditPart.getChildren().contains(editpart)) { + // graphically contained part will follow the move. + boundsOK = true; + } else { + Rectangle figBounds = part.getFigure().getBounds().getCopy(); + part.getFigure().translateToAbsolute(figBounds); + if (contentArea.contains(figBounds)) { + boundsOK = true; + } + } + if (boundsOK) { + // check group can contain + EObject child = part.resolveSemanticElement(); + for (EReference refToChildren : descriptor.getChildrenReferences()) { + if (refToChildren.getEReferenceType().isInstance(child)) { + groupParts.add(part); + break; + } + } + } + } + } + } + return new ArrayList<IGraphicalEditPart>(groupParts); + } + + // Debug purpose + public static void drawRect(IGraphicalEditPart editPart, Rectangle refContentArea) { + RoundedRectangle rectFeedback = new RoundedRectangle(); + rectFeedback.setBounds(refContentArea); + rectFeedback.setCornerDimensions(new Dimension(0, 0)); + rectFeedback.setLineWidth(2); + rectFeedback.setLineStyle(Graphics.LINE_DASH); + rectFeedback.setForegroundColor(editPart.getFigure().getForegroundColor()); + rectFeedback.setOpaque(true); + rectFeedback.setFill(false); + + IFigure layer = LayerManager.Helper.find(editPart).getLayer(LayerConstants.FEEDBACK_LAYER); + layer.add(rectFeedback); + } + + /** + * Get the command to change the graphical parent of an element + * + * @param childPart + * the child edit part to change parent + * @param newParent + * the new graphical parent + * @return the command or null if no effect + */ + public static Command getUpdateGraphicalParentCmd(IGraphicalEditPart childPart, IGraphicalEditPart newParent) { + if (childPart.getParent().equals(newParent)) { + return null; + } + ChangeBoundsRequest request = new ChangeBoundsRequest(); + request.setMoveDelta(new Point(0, 0)); + request.setSizeDelta(new Dimension(0, 0)); + request.setEditParts(childPart); + Point loc = childPart.getFigure().getBounds().getLocation().getCopy(); + childPart.getFigure().translateToAbsolute(loc); + request.setLocation(loc); + request.setType(RequestConstants.REQ_DROP); + org.eclipse.gef.commands.Command cmd = newParent.getCommand(request); + if (cmd != null && cmd.canExecute()) { + return new GEFtoEMFCommandWrapper(cmd); + } else { + return null; + } + } + + /** + * Get the command to add a reference from a parent group edit part to its new child + * + * @param newParentpart + * the new parent edit part which contains children by reference + * @param newChildPart + * the child edit part + * @return the command or null + */ + public static Command getAddReferenceToChildCmd(IGraphicalEditPart newParentpart, IGraphicalEditPart newChildPart) { + AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(newParentpart); + EObject parent = newParentpart.resolveSemanticElement(); + EObject child = newChildPart.resolveSemanticElement(); + // get the better child reference to use + EReference usedReference = getBestReferenceAmongList(desc.getChildrenReferences(), child); + if (usedReference != null) { + return new AddCommand(newParentpart.getEditingDomain(), parent, usedReference, child); + } else { + // no possible child reference + return null; + } + } + + /** + * Get the best reference (nearest to child's type) to a child among the list + * + * @param childrenReferences + * the possible children references + * @param child + * the child eobject to choose a referencefor + * @return the most precise child reference or null + */ + public static EReference getBestReferenceAmongList(List<EReference> childrenReferences, EObject child) { + EReference usedReference = null; + for (EReference ref : childrenReferences) { + if (ref.getEReferenceType().isInstance(child)) { + if (usedReference == null || ref.getEReferenceType().getEAllSuperTypes().contains(usedReference.getEReferenceType())) { + // the ref feature is more precise than the previously selected one. Use it instead. + usedReference = ref; + } + } + } + return usedReference; + } + + /** + * Get the command to remove a reference from a parent group edit part to its old child + * + * @param oldParentpart + * the old parent edit part which contains children by reference + * @param oldChildPart + * the child edit part + * @return the command or null + */ + public static Command getRemoveReferenceToChildCmd(IGraphicalEditPart oldParentpart, IGraphicalEditPart oldChildPart) { + AbstractContainerNodeDescriptor desc = GroupContainmentRegistry.getContainerDescriptor(oldParentpart); + EObject parent = oldParentpart.resolveSemanticElement(); + EObject child = oldChildPart.resolveSemanticElement(); + CompoundCommand globalCmd = new CompoundCommand(); + // get the better child reference to use + EReference usedReference = null; + for (EReference ref : desc.getChildrenReferences()) { + if (parent.eGet(ref) instanceof List<?>) { + if (((List<?>) parent.eGet(ref)).contains(child)) { + // remove the reference to the child + Command cmd = new RemoveCommand(oldParentpart.getEditingDomain(), parent, usedReference, child); + if (cmd.canExecute()) { + globalCmd.append(cmd); + } + } + } + } + if (!globalCmd.isEmpty()) { + return globalCmd; + } else { + return null; + } + } + + /** + * Get the bounds of an edit part + * + * @param part + * edit part to find bounds + * @return part's bounds in absolute coordinates + */ + public static Rectangle getAbsoluteBounds(IGraphicalEditPart part) { + // take bounds from figure + part.getTopGraphicEditPart().refresh(); + Rectangle bounds = part.getFigure().getBounds().getCopy(); + + if (part.getNotationView() instanceof Node) { + // rather update with up to date model bounds + Node node = (Node) part.getNotationView(); + LayoutConstraint cst = node.getLayoutConstraint(); + if (cst instanceof Bounds) { + Bounds b = (Bounds) cst; + Point parentLoc = part.getFigure().getParent().getBounds().getLocation(); + if (b.getX() > 0) { + bounds.x = b.getX() + parentLoc.x; + } + if (b.getY() > 0) { + bounds.y = b.getY() + parentLoc.y; + } + if (b.getHeight() != -1) { + bounds.height = b.getHeight(); + } + if (b.getWidth() != -1) { + bounds.width = b.getWidth(); + } + } + } + + part.getFigure().getParent().translateToAbsolute(bounds); + + return bounds; + } + + /** + * This method compute the delta between to IGraphicalEditPart. + * + * @param oldParent + * Old IGraphicalEditPart + * @param newParent + * New IGraphicalEditPart + * @return Return a DDimention between the two bounds (often use to translate point or Rectangle) + */ + public static Dimension computeDeltaToChangeParent(IGraphicalEditPart oldParent, IGraphicalEditPart newParent) { + Rectangle hostBounds = Utils.getAbsoluteBounds(oldParent); + Rectangle parentBounds = Utils.getAbsoluteBounds(newParent); + Dimension delta = hostBounds.getLocation().getDifference(parentBounds.getLocation()); + return delta; + } + + public static Dimension computeDeltaToChangeParent(IGraphicalEditPart oldParent, Rectangle newParent) { + Rectangle hostBounds = Utils.getAbsoluteBounds(oldParent); + Dimension delta = hostBounds.getLocation().getDifference(newParent.getLocation()); + return delta; + } + + /** + * Give the reference object which can reference the child for the parent type part + * + * @param parentType + * EClass of the parent OBject you want to know the EReference + * @param childType + * EClass of the child you want to test + * @return null if no reference is found + */ + public static EReference getContainmentEReference(EClass parentType, EClass childType) { + List<EReference> result = new ArrayList<EReference>(); + EReference usedReference = null; + for (EReference reference : parentType.getEAllContainments()) { + if (reference.getEReferenceType().isSuperTypeOf(childType) && !reference.isDerived()) { + result.add(reference); + } + } + + // Select the best containment relation + for (EReference ref : result) { + if (usedReference == null || ref.getEReferenceType().getEAllSuperTypes().contains(usedReference.getEReferenceType())) { + // the ref feature is more precise than the previously selected one. Use it instead. + usedReference = ref; + } + } + return usedReference; + } + + /** + * + * @param editPartRegistry + * Check if the object is contained in the editPartRegistery + * @param _child + * @return + */ + public static boolean isContainedInRegistery(Map editPartRegistry, Object _child) { + if (_child instanceof IGraphicalEditPart) { + return editPartRegistry.containsKey(((IGraphicalEditPart) _child).getModel()); + } + return false; + + } + + /** + * Test is the element is a compartment edit part that can be used to create the child + * + * @param editPartRegistry + * @param _child + * @return + */ + public static boolean isAGoodCompartementEditPart(Map editPartRegistry, Object _child) { + return _child instanceof CompartmentEditPart && isContainedInRegistery(editPartRegistry, _child) && ((EditPart) _child) instanceof ShapeCompartmentEditPart; + } + + /** + * Get the compartment editPart from a parent editPart + * + * @param editPartRegistry + * EditPartRegistery + * @param parentEditPart + * EditPart of the parent + * @return the CompartementEditPart and null if not found + */ + public static EditPart getCompartementEditPartFromMainEditPart(Map editPartRegistry, EditPart parentEditPart) { + EditPart resultCompartmentEditPart = null; + // An edit part has been found + if (parentEditPart instanceof CompartmentEditPart) { + resultCompartmentEditPart = parentEditPart; + return resultCompartmentEditPart; + } else { + List<EditPart> potentialCompartementPart = new ArrayList<EditPart>(); + for (Object _child : parentEditPart.getChildren()) { + if (isAGoodCompartementEditPart(editPartRegistry, _child)) { + potentialCompartementPart.add((EditPart) _child); + } + } + if (potentialCompartementPart.size() == 1) { + resultCompartmentEditPart = potentialCompartementPart.get(0); + return resultCompartmentEditPart; + } else if (potentialCompartementPart.size() == 1) { + // FIXME find a correct behavior if several potential CompartementPart (should normally never be the case) + resultCompartmentEditPart = potentialCompartementPart.get(0); + return resultCompartmentEditPart; + } + } + return resultCompartmentEditPart; + } + + + /** + * Get the child map needed for {@link ChangeModelParentCommand} + * + * @param elementType + * {@link EClass} of the elemnt you want to find the default model parent + * @param getHost + * Host of the editPolicy + * @param newIgraphicalParent + * {@link IGraphicalEditPart} to complete with the new {@link IGraphicalEditPart} of the defautl model parent + * @return + */ + public static DefaultModelParent getDefaultModelParent(EClass elementType, IGraphicalEditPart getHost) { + 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(elementType)) { + return new DefaultModelParent(hostParent, containmentRelation); + } + } + } + hostParent = (IGraphicalEditPart) hostParent.getParent(); + } + return null; + } + + public static boolean isRequestGroupFrameworkConcerned(ChangeBoundsRequest request) { + for (Object editPart : request.getEditParts()) { + if (editPart instanceof IGraphicalEditPart) { + IGraphicalEditPart iGraphicalEditPart = (IGraphicalEditPart) editPart; + boolean isNodeConcerned = GroupContainmentRegistry.isNodeConcerned(iGraphicalEditPart); + boolean isGroupConcerned = GroupContainmentRegistry.isContainerConcerned(iGraphicalEditPart); + if (isGroupConcerned || isNodeConcerned) { + return true; + } + } + } + return false; + } +} |