/******************************************************************************* * Copyright (c) 2008 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.papyrus.uml.diagram.activity.edit.commands; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.EditPart; import org.eclipse.gef.commands.Command; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.diagram.core.commands.SetPropertyCommand; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; 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.internal.properties.Properties; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest; import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.Edge; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ActivityDiagramEditPart; import org.eclipse.papyrus.uml.diagram.activity.part.UMLDiagramUpdater; import org.eclipse.papyrus.uml.diagram.activity.part.UMLLinkDescriptor; import org.eclipse.papyrus.uml.diagram.activity.part.UMLVisualIDRegistry; import org.eclipse.papyrus.uml.diagram.common.util.CommandUtil; /** * Restore related links to selected element * * @author <a href="mailto:jerome.benois@obeo.fr">Jerome Benois</a> */ // Inspired from EcoreTools source code public class RestoreRelatedLinksCommand extends AbstractTransactionalCommand { protected List<?> adapters; protected Diagram diagram; protected DiagramEditPart host; public RestoreRelatedLinksCommand(DiagramEditPart diagramEditPart, List<?> selection) { super(diagramEditPart.getEditingDomain(), "Restore related links", null); this.host = diagramEditPart; this.diagram = host.getDiagramView(); this.adapters = selection; } private void cleanAdd(Collection<UMLLinkDescriptor> result, View view, List<?> descriptors) { for(Object object : descriptors) { if(false == object instanceof UMLLinkDescriptor) { continue; } UMLLinkDescriptor descriptor = (UMLLinkDescriptor)object; if(cleanContains(result, descriptor)) { continue; } // check owner if(!isOwner(view, descriptor)) { continue; } result.add(descriptor); } } /** * Detect if similar descriptor already exist in given collection. * * @param collection * the collection of unique ingoing and outgoing links * descriptors * @param umlLinkDescriptor * the descriptor to search * @return true if already exist */ private boolean cleanContains(Collection<? extends UMLLinkDescriptor> collection, UMLLinkDescriptor umlLinkDescriptor) { for(Object object : collection) { if(object instanceof UMLLinkDescriptor) { UMLLinkDescriptor descriptor = (UMLLinkDescriptor)object; if(descriptor.getModelElement() == umlLinkDescriptor.getModelElement() && descriptor.getSource() == umlLinkDescriptor.getSource() && descriptor.getDestination() == umlLinkDescriptor.getDestination() && descriptor.getVisualID() == umlLinkDescriptor.getVisualID()) { return true; } } } return false; } /** * Collects all related links for view * * @param view * @param domain2NotationMap * * @return linkdescriptors */ protected Collection<? extends UMLLinkDescriptor> collectPartRelatedLinks(View view, Map<EObject, View> domain2NotationMap) { Collection<UMLLinkDescriptor> result = new LinkedList<UMLLinkDescriptor>(); if(!domain2NotationMap.containsKey(view.getElement())) { // We must prevent duplicate descriptors List<?> outgoingDescriptors = UMLDiagramUpdater.getOutgoingLinks(view); cleanAdd(result, view, outgoingDescriptors); List<?> incomingDescriptors = UMLDiagramUpdater.getIncomingLinks(view); cleanAdd(result, view, incomingDescriptors); } if(!domain2NotationMap.containsKey(view.getElement()) || view.getEAnnotation("Shortcut") == null) { //$NON-NLS-1$ domain2NotationMap.put(view.getElement(), view); } return result; } /** * Create related links corresponding to linkDescriptions * * @param linkDescriptors * @param domain2NotationMap */ protected void createRelatedLinks(Collection<? extends UMLLinkDescriptor> linkDescriptors, Map<EObject, View> domain2NotationMap) { // map diagram mapModel(diagram, domain2NotationMap); for(UMLLinkDescriptor nextLinkDescriptor : linkDescriptors) { EditPart sourceEditPart = getEditPart(nextLinkDescriptor.getSource(), domain2NotationMap); EditPart targetEditPart = getEditPart(nextLinkDescriptor.getDestination(), domain2NotationMap); // If the parts are still null... if(sourceEditPart == null || targetEditPart == null) { continue; } CreateConnectionViewRequest.ConnectionViewDescriptor descriptor = new CreateConnectionViewRequest.ConnectionViewDescriptor(nextLinkDescriptor.getSemanticAdapter(), null, ViewUtil.APPEND, false, host.getDiagramPreferencesHint()); CreateConnectionViewRequest ccr = new CreateConnectionViewRequest(descriptor); ccr.setType(RequestConstants.REQ_CONNECTION_START); ccr.setSourceEditPart(sourceEditPart); sourceEditPart.getCommand(ccr); ccr.setTargetEditPart(targetEditPart); ccr.setType(RequestConstants.REQ_CONNECTION_END); Command cmd = targetEditPart.getCommand(ccr); if(cmd != null && cmd.canExecute()) { CommandUtil.executeCommand(cmd, host); } } } /** * * @see org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand#doExecuteWithResult(org.eclipse.core.runtime.IProgressMonitor, * org.eclipse.core.runtime.IAdaptable) */ @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { // To register all EditPart in the global visualIDRegistry host().refresh(); for(Object object : adapters) { if(object instanceof IAdaptable) { IAdaptable ad = (IAdaptable)object; View view = (View)ad.getAdapter(View.class); if(view != null) { refreshRelatedLinks(view); } } else if(object instanceof View) { refreshRelatedLinks((View)object); } } return CommandResult.newOKCommandResult(); } /** * Retrieves editpart corresponding to domainModelElement * * @param domainModelElement * @param domain2NotationMap */ protected EditPart getEditPart(EObject domainModelElement, Map<? extends EObject, ? extends View> domain2NotationMap) { View view = domain2NotationMap.get(domainModelElement); if(view != null) { return (EditPart)host.getViewer().getEditPartRegistry().get(view); } return null; } /** * Get linkdescriptors of the related links for graphicalEditPart * * @param graphicalEditPart * @param domain2NotationMap * * @return linkDescritors */ protected Collection<? extends UMLLinkDescriptor> getLinkDescriptorToProcess(View notationView, Map<EObject, View> domain2NotationMap) { // Collect all related link from semantic model Collection<? extends UMLLinkDescriptor> linkDescriptors = collectPartRelatedLinks(notationView, domain2NotationMap); // Collect all related link from graphical model Collection<Edge> existingLinks = new LinkedList<Edge>(); for(Object edge : notationView.getTargetEdges()) { if(edge instanceof Edge && false == existingLinks.contains(edge)) { existingLinks.add((Edge)edge); } } for(Object edge : notationView.getSourceEdges()) { if(edge instanceof Edge && false == existingLinks.contains(edge)) { existingLinks.add((Edge)edge); } } // Set all existing related link visible setViewVisible(existingLinks); // Remove already existing links for(Iterator<Edge> linksIterator = existingLinks.iterator(); linksIterator.hasNext();) { Edge nextDiagramLink = linksIterator.next(); int diagramLinkVisualID = UMLVisualIDRegistry.getVisualID(nextDiagramLink); if(diagramLinkVisualID == -1) { if(nextDiagramLink.getSource() != null && nextDiagramLink.getTarget() != null) { linksIterator.remove(); } continue; } EObject diagramLinkObject = nextDiagramLink.getElement(); EObject diagramLinkSrc = nextDiagramLink.getSource().getElement(); EObject diagramLinkDst = nextDiagramLink.getTarget().getElement(); for(Iterator<? extends UMLLinkDescriptor> LinkDescriptorsIterator = linkDescriptors.iterator(); LinkDescriptorsIterator.hasNext();) { UMLLinkDescriptor nextLinkDescriptor = LinkDescriptorsIterator.next(); if(diagramLinkObject == nextLinkDescriptor.getModelElement() && diagramLinkSrc == nextLinkDescriptor.getSource() && diagramLinkDst == nextLinkDescriptor.getDestination() && diagramLinkVisualID == nextLinkDescriptor.getVisualID()) { linksIterator.remove(); LinkDescriptorsIterator.remove(); } } } return linkDescriptors; } /** * @return <code>(IGraphicalEditPart)host()</code>. */ protected final IGraphicalEditPart host() { return host; } private boolean isOwner(View view, UMLLinkDescriptor descriptor) { EObject source = descriptor.getSource(); EObject dest = descriptor.getDestination(); if(source != null && source.equals(view.getElement())) { return true; } if(dest != null && dest.equals(view.getElement())) { return true; } return false; } /** * Maps view * * @param view * @param domain2NotationMap */ protected void mapModel(View view, Map<EObject, View> domain2NotationMap) { if(!ActivityDiagramEditPart.MODEL_ID.equals(UMLVisualIDRegistry.getModelID(view))) { return; } // register the view if its type allows incoming or outgoing links if(!UMLDiagramUpdater.getOutgoingLinks(view).isEmpty() || !UMLDiagramUpdater.getIncomingLinks(view).isEmpty()) { if(!domain2NotationMap.containsKey(view.getElement()) || view.getEAnnotation("Shortcut") == null) { domain2NotationMap.put(view.getElement(), view); } } @SuppressWarnings("unchecked") EList<View> children = view.getChildren(); for(View child : children) { mapModel(child, domain2NotationMap); } @SuppressWarnings("unchecked") EList<View> sourceEdges = view.getSourceEdges(); for(View edge : sourceEdges) { mapModel(edge, domain2NotationMap); } } /** * Refresh related links for graphicalEditPart * * @param graphicalEditPart */ protected void refreshRelatedLinks(View notationView) { Map<EObject, View> domain2NotationMap = new HashMap<EObject, View>(); // Create related links Collection<? extends UMLLinkDescriptor> linkDescriptors = getLinkDescriptorToProcess(notationView, domain2NotationMap); createRelatedLinks(linkDescriptors, domain2NotationMap); } /** * Set view visible * * @param part * @param views */ protected void setViewVisible(Collection<? extends View> views) { for(View view : views) { if(view.isVisible()) { continue; } SetPropertyCommand cmd = new SetPropertyCommand(host.getEditingDomain(), "Restore related linksCommand show view", new EObjectAdapter(view), Properties.ID_ISVISIBLE, Boolean.TRUE); if(cmd != null && cmd.canExecute()) { CommandUtil.executeCommand(new ICommandProxy(cmd), host); } } } }