/***************************************************************************** * Copyright (c) 2011 Atos. * * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Arthur Daussy (Atos) - Initial API and implementation * Arthur Daussy - 371712 : 372745: [ActivityDiagram] Major refactoring group framework * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.activity.activitygroup; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.naming.InitialContext; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.Assert; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory; import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; import org.eclipse.gef.EditPolicy; import org.eclipse.gef.Request; import org.eclipse.gef.RequestConstants; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gef.requests.GroupRequest; import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy; import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest; import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.emf.type.core.commands.MoveElementsCommand; import org.eclipse.gmf.runtime.emf.type.core.requests.MoveRequest; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.infra.core.log.LogHelper; import org.eclipse.papyrus.infra.emf.gmf.command.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.infra.widgets.toolbox.notification.ICompositeCreator; import org.eclipse.papyrus.infra.widgets.toolbox.notification.INotification; import org.eclipse.papyrus.infra.widgets.toolbox.notification.NotificationRunnable; import org.eclipse.papyrus.infra.widgets.toolbox.notification.Type; import org.eclipse.papyrus.infra.widgets.toolbox.notification.builders.IContext; import org.eclipse.papyrus.infra.widgets.toolbox.notification.builders.NotificationBuilder; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.editpolicy.notifiers.GroupNotifyingOnMoveEditPolicy; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.editpolicy.notifiers.IGroupNotifier; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.predicates.AncestorFilter; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.predicates.DescendantsFilter; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.predicates.DescendantsFilterIGroupNotifier; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.predicates.SameContainerFilter; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.request.IGroupRequest; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.request.SetDeferredRequest; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.ui.IntegrateViewToConfigureComposite; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.utils.DebugUtils; import org.eclipse.papyrus.uml.diagram.activity.activitygroup.utils.Utils; import org.eclipse.papyrus.uml.diagram.activity.commands.DeferredSetValueCommand; import org.eclipse.papyrus.uml.diagram.activity.commands.RunNotificationCommand; import org.eclipse.papyrus.uml.diagram.activity.edit.part.ActivityGroup.IGroupCompartmentEditPart; import org.eclipse.papyrus.uml.diagram.activity.part.UMLDiagramEditorPlugin; import org.eclipse.papyrus.uml.diagram.common.commands.RemoveValueCommand; import org.eclipse.papyrus.uml.diagram.common.commands.RemoveValueRequest; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.uml2.uml.ActivityGroup; import org.eclipse.uml2.uml.Element; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; public class GroupRequestAdvisor implements IGroupRequestAdvisor { /** * Exception message */ private static final String UNABLE_TO_GET_THE_INTIAL_TARGET_REQUEST_BOUNDS = "Unable to get the intial target request bounds";////$NON-NLS-1$ /** * Debug message */ private static final String CHILDREN_REFERENCES_ARE = " ---- Children references are : ---- "; /** * Debug message */ private static final String ALL_PARENT_REFERENCES_ARE = " ---- All parent references are : ---- "; /** * Runnable to run command to change parent of selected element * * @author arthur daussy * */ private final class ChangeGraphicalParentRunnable implements NotificationRunnable { /** * New graphical host */ private final IGraphicalEditPart host; /** * Initial request */ private final IGroupRequest request; /** * List of all modified view * Used to compute list of modfied files */ private List viewTomodify; /** * Constructor * * @param host * New graphical host * @param request * Initial request */ private ChangeGraphicalParentRunnable(IGraphicalEditPart host, IGroupRequest request) { this.host = host; this.request = request; } /* * (non-Javadoc) * * @see org.eclipse.papyrus.ui.toolbox.notification.NotificationRunnable#run(org.eclipse.papyrus.ui.toolbox.notification.builders.IContext) */ @Override public void run(IContext context) { IntegrateViewToConfigureComposite composite = (IntegrateViewToConfigureComposite) context.get(org.eclipse.papyrus.infra.tools.notify.IContext.COMPOSITE_CREATED); final INotification notif = (INotification) context.get(org.eclipse.papyrus.infra.tools.notify.IContext.NOTIFICATION_OBJECT); CompositeTransactionalCommand ccMovingElement = new CompositeTransactionalCommand(request.getHostRequest().getEditingDomain(), "Move graphical elements into a new host");////$NON-NLS-1$ /* * Use to calculate impacted file */ viewTomodify = Lists.newArrayList(); IGraphicalEditPart hostEditPart = request.getHostRequest(); viewTomodify.add(host.getNotationView()); for (IGroupNotifier notifier : composite.getSelectedNotifier()) { IGraphicalEditPart notifierEditPart = notifier.getHostEditPart(); IGraphicalEditPart hostCompartmentEditPart = request.getNodeDescpitor().getCompartmentPartFromView(hostEditPart); /* * debugging label */ if (DebugUtils.isDebugging()) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Move "); stringBuilder.append(Utils.getCorrectLabel(notifierEditPart)); stringBuilder.append(" to "); stringBuilder.append(Utils.getCorrectLabel(hostEditPart)); DebugUtils.getLog().info(stringBuilder.toString()); } if (notifierEditPart != null) { EObject semanticElementToDrop = notifierEditPart.resolveSemanticElement(); if (semanticElementToDrop != null && hostCompartmentEditPart != null) { /* * Request to change graphical parent */ ChangeBoundsRequest chdBoundsRequest = new ChangeBoundsRequest(RequestConstants.REQ_ADD); chdBoundsRequest.setEditParts(notifierEditPart); viewTomodify.add(notifierEditPart.getNotationView()); Command dropcommand = hostCompartmentEditPart.getCommand(chdBoundsRequest); if (dropcommand != null) { ccMovingElement.compose(new CommandProxy(dropcommand)); } } else { // log error } } else { // log error } } /* * Execute resulting command */ if (ccMovingElement != null && !ccMovingElement.isEmpty()) { host.getEditingDomain().getCommandStack().execute(new GMFtoEMFCommandWrapper(ccMovingElement)); } notif.delete(); } /* * (non-Javadoc) * * @see org.eclipse.papyrus.ui.toolbox.notification.NotificationRunnable#getLabel() */ @Override public String getLabel() { return "OK"; } /** * @return the list of all EObject modifed */ public List getModifiedObject() { return viewTomodify == null ? Collections.emptyList() : viewTomodify; } } /** * SingletonHolder is loaded on the first execution of Singleton.getInstance() * or the first access to SingletonHolder.INSTANCE, not before. */ private static class SingletonHolder { public static final GroupRequestAdvisor instance = new GroupRequestAdvisor(); } /** * Get the instance of {@link GroupRequestAdvisor} * * @return */ public static GroupRequestAdvisor getInstance() { return SingletonHolder.instance; } /** * Store all the listener */ private Multimap listenners; /** * Logger */ private static LogHelper log = new LogHelper(UMLDiagramEditorPlugin.getInstance()); /*** * Private constructor */ private GroupRequestAdvisor() { listenners = ArrayListMultimap.create(); } /** * Add a {@link IGroupNotifier} * * @param editpolicy */ @Override public void addListenner(EObject eObject, IGroupNotifier editpolicy) { getListenerRegistry().put(eObject, editpolicy); } /** * Remove a {@link IGroupNotifier} * * @param editpolicy */ @Override public void removeListenner(IGroupNotifier editpolicy) { if (editpolicy == null) { return; } Iterator> iterator = getListenerRegistry().entries().iterator(); while (iterator.hasNext()) { Entry entry = iterator.next(); if (editpolicy.equals(entry.getValue())) { iterator.remove(); } } } @Override public ICommand notifyGroupFramework(IGroupRequest request) { if (DebugUtils.isDebugging()) { log.debug("***********************BEGIN : Group Request Advisor***********************************"); } /****************** * Handling parent ******************/ CompositeCommand cc = new CompositeCommand("Global command from GroupRequestAdvisor"); Request initialRequest = request.getInitialRequest(); if (initialRequest instanceof ChangeBoundsRequest) { handleMove(request, cc); } else if (initialRequest instanceof GroupRequest && RequestConstants.REQ_DELETE.equals(initialRequest.getType())) { handleDelete(request, cc); } if (cc != null && !cc.isEmpty()) { return cc; } return null; } protected void handleDelete(IGroupRequest request, CompositeCommand cc) { // request.getNodeDescpitor().getChildrenReferences() } /** * Handle move * * @param request * @param cc */ protected void handleMove(IGroupRequest request, CompositeCommand cc) { /* * All parent */ fillRequestWithAllPossibleParent(request); fillRequestWithAllPossibleChildren(request); Object elementAdapter = request.getTargetElement().getAdapter(EObject.class); if (elementAdapter instanceof EObject) { /* * Handle children */ handleSemanticChildren(request, cc, (EObject) elementAdapter); /* * Semantic of all the parent */ handleSemanticParents(request, cc, elementAdapter); } if (DebugUtils.isDebugging()) { log.debug("***********************END : Group Request Advisor***********************************"); } // /* // * For all new child send request // * For all GrChild create new request from old one and use dispatcher // */ // if(cc != null && !cc.isEmpty()) { // return cc; // } // return null; } /** * Handle all the children of the group (graphical and non graphical children) * * @param request * @param cc * @param targetElement */ protected void handleSemanticChildren(final IGroupRequest request, CompositeCommand cc, EObject targetElement) { List graphicalChildren = Lists.newArrayList(); /* * There is graphical childrne only when the node is moving */ if (request.getInitialRequest() instanceof ChangeBoundsRequest) { graphicalChildren = handleGraphicalChildren(request, cc); } /* * Unset */ for (Entry oldChildrenEntry : Utils.getOldChildren(request).entries()) { Multimap allActualChildren = request.getChildrenEReferenceMap(); EReference ref = oldChildrenEntry.getKey(); if (ref != null) { if (!allActualChildren.containsEntry(oldChildrenEntry.getValue(), ref)) { EReference eOpposite = ref.getEOpposite(); if (!graphicalChildren.contains(oldChildrenEntry.getValue())) { if (eOpposite != null && !eOpposite.isContainment() && !ref.isContainment()) { RemoveValueRequest rmVa = new RemoveValueRequest(targetElement, ref, Collections.singletonList(oldChildrenEntry.getValue())); RemoveValueCommand rmCmd = new RemoveValueCommand(rmVa); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("From handling parent : Remove ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(ref)); stringBuilder.append(" from ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(targetElement)); stringBuilder.append(" value ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(oldChildrenEntry.getValue()));// rmCmd.setLabel(stringBuilder.toString()); if (rmCmd != null) { cc.compose(rmCmd); } } } } } } /* * Set semantic */ Set newChildren = Sets.newHashSet(); for (Entry entry : request.getChildrenEReferenceMap().entries()) { EReference ref = entry.getKey(); if (ref != null) { EReference eOpposite = ref.getEOpposite(); if (!graphicalChildren.contains(entry.getValue())) { newChildren.add(entry.getValue()); if (eOpposite != null && !eOpposite.isContainment()) { SetDeferredRequest setRq = new SetDeferredRequest(request.getHostRequest().getEditingDomain(), request.getTargetElement(), ref, entry.getValue()); DeferredSetValueCommand setCmd = new DeferredSetValueCommand(setRq); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("From handling parent : Set deferred");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(entry.getValue())); stringBuilder.append(" from ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(ref)); stringBuilder.append(" value ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(entry.getValue()));// setCmd.setLabel(stringBuilder.toString()); if (setCmd != null) { cc.compose(setCmd); } } } } if (!newChildren.isEmpty()) { handleChangeParentNotificationCommand(request, cc, newChildren); } } } /** * Create a notification to user to ask him is he want to add its new children as graphical child of its parent group * * @param request * {@link InitialContext} {@link IGroupRequest} * @param cc * {@link CompositeCommand} to compose new commands * @param newChildren * List of all new children */ protected void handleChangeParentNotificationCommand(final IGroupRequest request, CompositeCommand cc, Set newChildren) { /* * Create dialog to suggest user to move views */ final IGraphicalEditPart host = request.getHostRequest(); /* * Get editpart of all children */ Iterable listOfChidren = Iterables.transform(newChildren, new Function() { @Override public IGroupNotifier apply(EObject arg0) { Collection notifiers = getListenerRegistry().get(arg0); for (IGroupNotifier notifier : notifiers) { IGraphicalEditPart notifierEditPart = notifier.getHostEditPart(); if (notifierEditPart != null) { if (EcoreUtil.isAncestor(host.getNotationView().getDiagram(), notifierEditPart.getNotationView())) { return notifier; } } } return null; } }); final Iterable listOfFilteredChidren = Iterables.filter(listOfChidren, Predicates.notNull()); List automaticChildren = Lists.newArrayList(); List nonAutomaticChildren = Lists.newArrayList(); /* * Dispatch children */ dispatchChildren(request, host, listOfFilteredChidren, automaticChildren, nonAutomaticChildren); IGraphicalEditPart hostEditPart = request.getHostRequest(); /* * Command to change graphical parent for element when we can guess graphical parent */ for (IGroupNotifier notifier : automaticChildren) { IGraphicalEditPart notifierEditPart = notifier.getHostEditPart(); IGraphicalEditPart hostCompartmentEditPart = request.getNodeDescpitor().getCompartmentPartFromView(hostEditPart); Request initialRequest = request.getInitialRequest(); Rectangle hostBounds = null; if (initialRequest instanceof ChangeBoundsRequest) { hostBounds = Utils.getAbslotueRequestBounds((ChangeBoundsRequest) initialRequest, hostCompartmentEditPart); } else { hostBounds = Utils.getAbsoluteBounds(hostCompartmentEditPart); } Rectangle childBounds = Utils.getAbsoluteBounds(notifierEditPart); MoveElementsCommand mvCmd = new MoveElementsCommand(new MoveRequest(hostCompartmentEditPart.getNotationView(), notifierEditPart.getNotationView())); /* * Integrate view into new compartment */ if (mvCmd != null && mvCmd.canExecute()) { cc.compose(mvCmd); } /* * Set view to the new location */ SetBoundsCommand setBoundCommand = new SetBoundsCommand(WorkspaceEditingDomainFactory.INSTANCE.getEditingDomain(host.getNotationView().eResource().getResourceSet()), "test", new EObjectAdapter(notifierEditPart.getNotationView()), childBounds.translate(hostBounds.getLocation().negate())); if (setBoundCommand != null && setBoundCommand.canExecute()) { cc.compose(setBoundCommand); } } /* * Create notification for element where we can NOT guess the graphical parent */ if (!nonAutomaticChildren.isEmpty()) { /* * create runnable to run the command */ ChangeGraphicalParentRunnable changeGraphicalParentRunnable = new ChangeGraphicalParentRunnable(host, request); final NotificationBuilder notification = createChangeGraphicalParentNotification(nonAutomaticChildren, changeGraphicalParentRunnable, hostEditPart); RunNotificationCommand runNotifCmd = new RunNotificationCommand(request.getHostRequest().getEditingDomain(), "Notification command", getWorkspaceFiles(changeGraphicalParentRunnable.getModifiedObject()), notification);////$NON-NLS-1$ cc.compose(runNotifCmd); } } /** * Dispatch all children in two category. * listOfFilteredChidren will contained all element to automatically add as graphical children * nonAutomaticChildren will contained all element to ask the user what to do with * * @param request * @param host * @param listOfFilteredChidren * @param automaticChildren * @param nonAutomaticChildren */ private void dispatchChildren(final IGroupRequest request, final IGraphicalEditPart host, final Iterable listOfFilteredChidren, List automaticChildren, List nonAutomaticChildren) { for (IGroupNotifier notifier : listOfFilteredChidren) { IGraphicalEditPart parentEditPart = getGraphicalParent(notifier.getHostEditPart()); if (parentEditPart != null) { EObject eObject = parentEditPart.resolveSemanticElement(); if (eObject instanceof ActivityGroup) { ActivityGroup group = (ActivityGroup) eObject; Collection groupNotifiers = listenners.get(group); if (!groupNotifiers.isEmpty()) { IGroupNotifier myGroupNotifier = groupNotifiers.iterator().next(); /* * Is the old container (an activity group) continaing the current moving element */ boolean isNewContainerVisuallyIncludeInOldContainer = myGroupNotifier.includes(Utils.getAbslotueRequestBounds((ChangeBoundsRequest) request.getInitialRequest(), host)); /* * Can the old container (an activity group) be a model a the current moving element */ boolean canTheOldContainerBeAModelParentOfTheNewContainer = myGroupNotifier.getHostGroupDescriptor().canIBeModelParentOf(host.resolveSemanticElement().eClass()); /* * */ boolean canTheNewContainerBeModelParentOfTheOldContianer = request.getNodeDescpitor().canIBeModelParentOf(host.resolveSemanticElement().eClass()); /* * Is the current moving element containing the old container */ IGroupNotifier currentElementNotifier = getIGroupNotifier(host); boolean isOldContainerVisuallyIncludeInNewContainer = currentElementNotifier.includes(Utils.getAbsoluteBounds(myGroupNotifier.getHostEditPart())); if (canTheOldContainerBeAModelParentOfTheNewContainer && isNewContainerVisuallyIncludeInOldContainer) { /* * Is going to be a new child of the old container */ automaticChildren.add(notifier); } else if (canTheNewContainerBeModelParentOfTheOldContianer && isOldContainerVisuallyIncludeInNewContainer) { /* * Is going to be a new container for the old container */ } else { /* * There is no containing relation between the groups */ if (currentElementNotifier.getHostGroupDescriptor().getContainmentReferenceFor(notifier.getHostEditPart().resolveSemanticElement().eClass()) == null) { nonAutomaticChildren.add(notifier); } else { // If containment link automatically add it to new group automaticChildren.add(notifier); } } } else { /* * No notifier where found */ nonAutomaticChildren.add(notifier); } } else { /* * If there is no container (which is group) */ if (!parentEditPart.equals(host)) { automaticChildren.add(notifier); } } } else { DebugUtils.getLog().error("Unable to retreive graphical parent of " + Utils.getCorrectLabel(notifier), null); } } } /** * Get the IGroupNotifier of the {@link IGraphicalEditPart} passed in argument * * @param host * @return */ private IGroupNotifier getIGroupNotifier(final IGraphicalEditPart host) { EditPolicy editPolicy = host.getEditPolicy(IGroupEditPolicies.GROUP_FRAMEWORK_NOTIFYING_ON_MOVE_EDIT_POLICY); if (editPolicy instanceof IGroupNotifier) { return (IGroupNotifier) editPolicy; } else { editPolicy = host.getEditPolicy(IGroupEditPolicies.GROUP_FRAMEWORK_NOTIFYING_ON_CREATION_EDIT_POLICY); if (editPolicy instanceof IGroupNotifier) { return (IGroupNotifier) editPolicy; } } throw new RuntimeException("Unable to retreive the IGroupNofier of the current group");////$NON-NLS-1$ } /** * Get the edit which represent the parent (semantically) of the edit part child passed in argument * * @param child * @return */ private IGraphicalEditPart getGraphicalParent(IGraphicalEditPart child) { IGraphicalEditPart result = child; EObject childElement = child.resolveSemanticElement(); if (child != null) { while (childElement == result.resolveSemanticElement()) { try { result = (IGraphicalEditPart) result.getParent(); } catch (ClassCastException e) { return result; } } } return result; } /** * Create a notification to ask user if he want to change the graphical parent of some elements * * @param listOfFilteredChidren * @param changeGraphicalParentRunnable * @return */ private NotificationBuilder createChangeGraphicalParentNotification(final Iterable listOfFilteredChidren, ChangeGraphicalParentRunnable changeGraphicalParentRunnable, final IGraphicalEditPart host) { return new NotificationBuilder().setType(Type.INFO).setAsynchronous(true).setTemporary(true).setDelay(3000).setTitle("Papyrus graphical modification").setComposite(new ICompositeCreator() { @Override public Composite createComposite(Composite parent, FormToolkit toolkit) { return new IntegrateViewToConfigureComposite(parent, SWT.NONE, Lists.newArrayList(Lists.newArrayList(listOfFilteredChidren)), "New elements are visually contained in the current group (" + Utils.getCorrectLabel(host) + ").\n Please select the elements you want to integrate into this group figure."); } }).addAction(changeGraphicalParentRunnable); } /** * Handle graphical children * * @param request * {@link IGroupRequest} * @param cc * {@link CompositeCommand} to compose new commands * @return The list of all graphical children already handled */ protected List handleGraphicalChildren(IGroupRequest request, CompositeCommand cc) { /* * List of all the graphical children */ List graphicalChildren = new ArrayList<>(); /* * Handle graphical children */ // Get graphical children Object targetEditPart = request.getTargetElement().getAdapter(IGraphicalEditPart.class); IGraphicalEditPart compartementEditPart = null; if (targetEditPart instanceof IGroupCompartmentEditPart) { compartementEditPart = ((IGraphicalEditPart) targetEditPart); } else if (targetEditPart instanceof IGraphicalEditPart) { IContainerNodeDescriptor nodeDescpitor = request.getNodeDescpitor(); if (nodeDescpitor != null) { compartementEditPart = nodeDescpitor.getCompartmentPartFromView((IGraphicalEditPart) targetEditPart); } } if (compartementEditPart != null) { /* * Transform an IGraphicalEditPart to the related GroupNotifyingEditPolicy */ @SuppressWarnings("unchecked") Iterable policies = Iterables.transform((List) compartementEditPart.getChildren(), new Function() { @Override public GroupNotifyingOnMoveEditPolicy apply(IGraphicalEditPart from) { EditPolicy editPolicy = from.getEditPolicy(IGroupEditPolicies.GROUP_FRAMEWORK_NOTIFYING_ON_MOVE_EDIT_POLICY); if (editPolicy instanceof GroupNotifyingOnMoveEditPolicy) { return (GroupNotifyingOnMoveEditPolicy) editPolicy; } return null; } }); for (final GroupNotifyingOnMoveEditPolicy p : policies) { if (p != null) { if (DebugUtils.isDebugging()) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("+++ Work for child "); stringBuilder.append(Utils.getCorrectLabel(p.getEObject())); stringBuilder.append(" +++"); DebugUtils.getLog().debug(stringBuilder.toString()); } Request initialRequest = request.getInitialRequest(); Request auxChReq = null; if (initialRequest instanceof ChangeBoundsRequest) { auxChReq = Utils.getChangeBoundsRequestCopy((ChangeBoundsRequest) initialRequest, p.getHostEditPart()); } else { auxChReq = initialRequest; } /* * Save graphical parent */ // auxChReq.getExtendedData().put(GROUP_FRAMEWORK_GRAPHICAL_PARENT, compartementEditPart.resolveSemanticElement()); graphicalChildren.add(p.getEObject()); Command childCommand = p.getCommand(auxChReq); if (childCommand != null && childCommand.canExecute()) { cc.compose(new CommandProxy(childCommand)); } } } } return graphicalChildren; } /** * Set and Unset semantic relation with parents * * @param request * {@link IGroupRequest} * @param cc * {@link CompositeCommand} to compose command * @param elementAdapter */ protected void handleSemanticParents(IGroupRequest request, CompositeCommand cc, Object elementAdapter) { EObject targetElement = (EObject) elementAdapter; Multimap allActualParent = request.getParentEReferenceMap(); for (Entry entry : Utils.getOldParents(request).entries()) { EReference ref = entry.getKey(); if (ref != null) { if (!allActualParent.containsEntry(ref, entry.getValue())) { EReference eOpposite = ref.getEOpposite(); if (eOpposite != null && !eOpposite.isContainment() && !eOpposite.isDerived()) { RemoveValueRequest rmVa = new RemoveValueRequest(targetElement, ref, Collections.singletonList(entry.getValue())); RemoveValueCommand rmCmd = new RemoveValueCommand(rmVa); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("From handling parent : Remove ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(entry.getValue())); stringBuilder.append(" from ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(targetElement)); stringBuilder.append(" value ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(entry.getValue()));// rmCmd.setLabel(stringBuilder.toString()); if (rmCmd != null) { cc.compose(rmCmd); } } // } } } } /* * Set semantic * If the EObject has not been already handle as graphical children */ for (Entry entry : request.getParentEReferenceMap().entries()) { EReference ref = entry.getKey(); if (ref != null) { EReference eOpposite = ref.getEOpposite(); if (eOpposite != null && !eOpposite.isContainment() && !ref.isContainment()) { SetDeferredRequest setRq = new SetDeferredRequest(request.getHostRequest().getEditingDomain(), request.getTargetElement(), ref, entry.getValue()); DeferredSetValueCommand setCmd = new DeferredSetValueCommand(setRq); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("From handling parent : Set deferred ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(ref)); stringBuilder.append(" from ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(request.getTargetElement())); stringBuilder.append(" value ");////$NON-NLS-1$ stringBuilder.append(Utils.getCorrectLabel(entry.getValue()));// setCmd.setLabel(stringBuilder.toString()); if (setCmd != null) { cc.compose(setCmd); } } } } } /** * Return a list of all IGroupRequestListenner which can be children of the target of the request * * @param request * @return */ protected Multimap fillRequestWithAllPossibleChildren(IGroupRequest request) { final Multimap result = fillReqestWithReferendedElement(request, false, false); /** * TODO filter graphical parent which currently moving * I1 in ActPart1 * ActPart1 move into ActPart2 * I1 should only reference ActPart1 */ /* * Debug */ DebugUtils.displayMultipmapDebug(CHILDREN_REFERENCES_ARE, request.getChildrenEReferenceMap()); return result; } public EObject getPossibleModelParent(IGroupRequest request) { Multimap parentsMap = fillReqestWithReferendedElement(request, true, true); List parents = Lists.newArrayList(parentsMap.values()); Collections.sort(parents); if (!parents.isEmpty()) { return parents.get(0).getEObject(); } return request.getHostRequest().resolveSemanticElement(); } /** * Return only current displayed listener * * @author adaussy * */ private static class ActiveListener implements Predicate { private Diagram currentDiagramDisplayed; public ActiveListener(Diagram currentDiagramDisplayed) { super(); this.currentDiagramDisplayed = currentDiagramDisplayed; Assert.isNotNull(currentDiagramDisplayed); } @Override public boolean apply(IGroupNotifier input) { IGraphicalEditPart host = input.getHostEditPart(); if (host != null) { View primaryView = host.getPrimaryView(); if (primaryView != null) { return currentDiagramDisplayed.equals(primaryView.getDiagram()); } } return false; } } /** * Get all the element in references which are included or include (depending of the parameter include) * * @param request * {@link IGroupRequest} * @param newBounds * New bounds of the elements * @param references * All references to take into account * @param eReferenceMapToFillInRequest * Map in the request to fill * @param result * {@link Map} which link a {@link EReference} to a {@link IGroupNotifier} * @param containementOnly * true if we are looking for containing references only */ protected void getReferenceElements(IGroupRequest request, final Rectangle newBounds, final List references, Multimap eReferenceMapToFillInRequest, Multimap result, boolean include, boolean containementOnly, Map parentOpositeFeature) { Iterable activeListeners = Iterables.filter(getListenerRegistry().values(), new ActiveListener(getCurrentlyDisplayedDiagram(request))); for (IGroupNotifier input : activeListeners) { EObject inputEObject = input.getEObject(); if (inputEObject == null || !(inputEObject instanceof Element)) { continue; } Object adapter = request.getTargetElement().getAdapter(EObject.class); // EObject targetElement = null; // if(adapter instanceof EObject) { // targetElement = (EObject)adapter; // } if (inputEObject.equals(adapter)) { continue; } EReference refenceFounded = null; for (EReference ref : references) { EClass refType = ref.getEReferenceType(); EClass eoBjectType = inputEObject.eClass(); if (refType.isSuperTypeOf(eoBjectType)) { refenceFounded = ref; break; } } if (refenceFounded != null) { if ((include && input.includes(newBounds)) || (!include && input.isIncludedIn(newBounds))) { if (containementOnly && parentOpositeFeature.get(refenceFounded) instanceof EReference && !((EReference) parentOpositeFeature.get(refenceFounded)).isContainment()) { continue; } eReferenceMapToFillInRequest.put(refenceFounded, (Element) inputEObject); result.put(refenceFounded, input); } } } } /** * Return the currently displayed diagram * * @param request * @return */ protected Diagram getCurrentlyDisplayedDiagram(IGroupRequest request) { IGraphicalEditPart graph = request.getHostRequest(); if (graph != null) { Object m = graph.getModel(); if (m instanceof View) { View v = (View) m; return v.getDiagram(); } } throw new RuntimeException("Unable to get the current diagram displayed");////$NON-NLS-1$ } /** * Return the list of all {@link IGroupNotifier} which can be parent of the target of the request * * @param request * @return */ protected Multimap fillRequestWithAllPossibleParent(IGroupRequest request) { final Multimap result = fillReqestWithReferendedElement(request, true, false); /* * Debug */ DebugUtils.displayMultipmapDebug(ALL_PARENT_REFERENCES_ARE, request.getParentEReferenceMap()); return result; } protected Multimap fillReqestWithReferendedElement(IGroupRequest request, boolean lookingForParent, boolean onlyContainment) { final Rectangle newBounds = getInitalTargetRequestNewBounds(request); final Multimap result = ArrayListMultimap.create(); if (request.getNodeDescpitor() == null) { return result; } List references = null; if (lookingForParent) { references = request.getNodeDescpitor().getParentReferences(); } else { references = request.getNodeDescpitor().getChildrenReferences(); } final Multimap auxResult = ArrayListMultimap.create(); final Multimap eReferenceLookedForMap = ArrayListMultimap.create(); getReferenceElements(request, newBounds, references, eReferenceLookedForMap, auxResult, lookingForParent, onlyContainment, lookingForParent ? request.getNodeDescpitor().getParentEOppositeReferences() : null); /* * Filter ancestors */ for (EReference ref : eReferenceLookedForMap.keySet()) { /* * Filter descendant * Example : * 1 - ActPart1 include in Act1 then Act1 disappear * 2 - ActPart1 include in ActPart2 then ActPart1 disappear */ Object adapter = request.getTargetElement().getAdapter(EObject.class); if (adapter instanceof Element) { Element element = (Element) adapter; Predicate composedPredicate = Predicates.and(new SameContainerFilter(element), lookingForParent ? new DescendantsFilter(eReferenceLookedForMap.values()) : new AncestorFilter(eReferenceLookedForMap.values())); Collection filteredCollection = Collections2.filter(eReferenceLookedForMap.get(ref), composedPredicate); if (lookingForParent) { request.getParentEReferenceMap().putAll(ref, filteredCollection); } else { request.getChildrenEReferenceMap().putAll(ref, filteredCollection); } } } for (EReference ref : auxResult.keySet()) { /* * Filter descendant * Example : * 1 - ActPart1 include in Act1 then Act1 disappear * 2 - ActPart1 include in ActPart2 then ActPart1 disappear */ Iterable resultCollection = Iterables.filter(auxResult.get(ref), new DescendantsFilterIGroupNotifier(auxResult.values())); result.putAll(ref, resultCollection); } return result; } /** * Get the absolute bounds of the target of the request * * @param request * @return */ public static Rectangle getInitalTargetRequestNewBounds(final IGroupRequest request) { Request initialRequest = request.getInitialRequest(); if (initialRequest instanceof ChangeBoundsRequest) { return Utils.getAbslotueRequestBounds((ChangeBoundsRequest) initialRequest, request.getHostRequest()); } else if (initialRequest instanceof CreateViewRequest) { return Utils.getAbslotueRequestBounds((CreateViewRequest) initialRequest); } throw new RuntimeException(UNABLE_TO_GET_THE_INTIAL_TARGET_REQUEST_BOUNDS); } /** * Convenience method to get a list of workspaces files associated with eObject. * * @param eObject * the model object, may be null * @return the list of {@link IFile}s */ protected static List getWorkspaceFiles(EObject eObject) { List result = new ArrayList(); if (eObject != null) { Resource resource = eObject.eResource(); if (resource != null) { IFile file = WorkspaceSynchronizer.getFile(resource); if (file != null) { result.add(file); } } } return result; } /** * Convenience method to get a list of workspaces files associated with {@link EObject}s in eObject. * * @param eObjects * the list of model object * @return the list of {@link IFile}s */ protected static List getWorkspaceFiles(List eObjects) { List result = new ArrayList(); for (Iterator i = eObjects.iterator(); i.hasNext();) { Object next = i.next(); if (next instanceof EObject) { Resource resource = ((EObject) next).eResource(); if (resource != null) { IFile file = WorkspaceSynchronizer.getFile(resource); if (file != null) { result.add(file); } } } } return result; } /** * @return the listenners */ @Override public Multimap getListenerRegistry() { return listenners; } }