/*************************************************************************** * Copyright (c) 2007 Conselleria de Infraestructuras y Transporte, * Generalitat de la Comunitat Valenciana . 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: Mario Cervera Ubeda (Integranova) * Marc Gil Sendra (Prodevelop) * ******************************************************************************/ package org.eclipse.papyrus.uml.diagram.common.actions.handlers; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.command.CopyToClipboardCommand; import org.eclipse.emf.edit.command.PasteFromClipboardCommand; import org.eclipse.emf.edit.command.RemoveCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.transaction.util.TransactionUtil; import org.eclipse.gef.EditPart; import org.eclipse.gef.Request; import org.eclipse.gef.RequestConstants; import org.eclipse.gef.requests.GroupRequest; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.common.ui.action.global.GlobalActionId; import org.eclipse.gmf.runtime.common.ui.services.action.global.IGlobalActionContext; import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; import org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.papyrus.commands.wrappers.EMFtoGMFCommandWrapper; import org.eclipse.papyrus.commands.wrappers.GEFtoEMFCommandWrapper; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.uml.diagram.common.commands.AbstractCommonTransactionalCommmand; import org.eclipse.papyrus.uml.diagram.common.commands.AddEObjectReferencesToDiagram; import org.eclipse.papyrus.uml.diagram.common.editpolicies.ViewAndFeatureResolver; import org.eclipse.papyrus.uml.diagram.common.util.DiagramEditPartsUtil; import org.eclipse.papyrus.uml.diagram.common.util.MDTUtil; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; /** * The Class ClipboardActionHandler. */ public/* abstract */class ClipboardActionHandler extends DiagramGlobalActionHandler { /* * Specifies whether the last executed action was a cut action or not. This * is needed because the paste action will vary depending on it */ /** The is cut. */ private static boolean isCut = false; /* Container of the objects in the clipboard */ /** The container. */ private static EObject container = null; /* Objects in the clipboard */ /** The clipboard. */ protected static List<EObject> clipboard = new ArrayList<EObject>(); /* Edit parts of the objects in the clipboard */ /** The edit parts in clipboard. */ protected static List<EditPart> editPartsInClipboard = new ArrayList<EditPart>(); // @unused protected static List<Object> clipboardElements = new ArrayList<Object>(); // @unused public void setContainer(EObject container) { ClipboardActionHandler.container = container; } public EObject getContainer() { return ClipboardActionHandler.container; } // @unused public boolean getIsCut() { return isCut; } // @unused public void setIsCut(boolean isCut) { ClipboardActionHandler.isCut = isCut; } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler * #canCopy(org.eclipse.gmf.runtime.common.ui.services.action.global. * IGlobalActionContext) */ @Override protected boolean canCopy(IGlobalActionContext cntxt) { if(cntxt.getSelection() instanceof StructuredSelection) { Object firstElement = ((StructuredSelection)cntxt.getSelection()).getFirstElement(); if(firstElement instanceof IGraphicalEditPart) { EObject eobject = ((IGraphicalEditPart)firstElement).resolveSemanticElement(); if(eobject != null) { List elements = ((StructuredSelection)cntxt.getSelection()).toList(); List<EObject> eobjects = new ArrayList<EObject>(); for(Object o : elements) { EObject eobj = ((IGraphicalEditPart)o).resolveSemanticElement(); eobjects.add(eobj); } if(!allElementsSameType(eobjects, eobject)) { return false; } IEditorPart editorPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); if(editorPart instanceof DiagramEditor) { if(((DiagramEditor)editorPart).getDiagram().getElement().equals(eobject)) { return false; } } return true; } } } return false; } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler * #canCut(org.eclipse.gmf.runtime.common.ui.services.action.global. * IGlobalActionContext) */ @Override protected boolean canCut(IGlobalActionContext cntxt) { return canCopy(cntxt); } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler * #canPaste(org.eclipse.gmf.runtime.common.ui.services.action.global. * IGlobalActionContext) */ @Override protected boolean canPaste(IGlobalActionContext cntxt) { if(cntxt.getSelection() instanceof StructuredSelection) { Object firstElement = ((StructuredSelection)cntxt.getSelection()).getFirstElement(); if(firstElement instanceof IGraphicalEditPart) { IGraphicalEditPart pasteDestination = ((IGraphicalEditPart)firstElement); if(pasteDestination != null && pasteDestination.resolveSemanticElement() != null && (!pasteDestination.resolveSemanticElement().equals(container) || !isCut)) { TransactionalEditingDomain domain = pasteDestination.getEditingDomain(); if(domain.getClipboard() != null && domain.getClipboard().size() > 0) { // All the elements in the clipboard are of the same // type Object[] objects = domain.getClipboard().toArray(); EObject firstObjectToBePasted = (EObject)objects[0]; EStructuralFeature feature = getFeature(firstObjectToBePasted, pasteDestination); if(feature != null) { if(feature.getEType().getInstanceClass().isInstance(firstObjectToBePasted)) { return true; } } } } } } return false; } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler * #getCommand(org.eclipse.gmf.runtime.common.ui.services.action.global. * IGlobalActionContext) */ @Override public ICommand getCommand(IGlobalActionContext cntxt) { IWorkbenchPart part = cntxt.getActivePart(); if(!(part instanceof IDiagramWorkbenchPart)) { return null; } /* Get the model operation context */ IDiagramWorkbenchPart diagramPart = (IDiagramWorkbenchPart)part; String actionId = cntxt.getActionId(); if(actionId.equals(GlobalActionId.COPY)) { isCut = false; return getCopyCommand(cntxt, diagramPart, false); } else if(actionId.equals(GlobalActionId.CUT)) { isCut = true; return getCutCommand(cntxt, diagramPart); } else if(actionId.equals(GlobalActionId.PASTE)) { if(isCut) { isCut = false; return getExecutePasteAfterCutCommand(cntxt); } else { isCut = false; return getExecutePasteAfterCopyCommand(cntxt); } } return super.getCommand(cntxt); } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler * #getCopyCommand(org.eclipse.gmf.runtime.common.ui.services.action.global. * IGlobalActionContext, * org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart, boolean) */ @Override protected ICommand getCopyCommand(IGlobalActionContext cntxt, IDiagramWorkbenchPart diagramPart, boolean isUndoable) { if(cntxt.getSelection() instanceof StructuredSelection) { // All the elements in the selection are supposed to be of the same // time // We couldn't have got here otherwise Object firstElement = ((StructuredSelection)cntxt.getSelection()).getFirstElement(); EObject eobject = ((IGraphicalEditPart)firstElement).resolveSemanticElement(); TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(eobject); List elements = ((StructuredSelection)cntxt.getSelection()).toList(); List<EObject> eobjects = new ArrayList<EObject>(); editPartsInClipboard.clear(); for(Object o : elements) { EObject eobj = ((IGraphicalEditPart)o).resolveSemanticElement(); eobjects.add(eobj); container = eobj.eContainer(); for(Object view : DiagramEditPartsUtil.getEObjectViews(eobj)) { if(view instanceof View) { EditPart editpart = DiagramEditPartsUtil.getEditPartFromView((View)view, (EditPart)firstElement); editPartsInClipboard.add(editpart); } } } clipboard.clear(); clipboard.addAll(eobjects); final List<EObject> eobjects2 = eobjects; Command copyCommand = new CopyToClipboardCommand(domain, eobjects) { @Override public void doExecute() { /** * @author mgil : Don't use a different command to copy * every element, use the copy function from * EcoreUtil */ ArrayList<Object> list = new ArrayList<Object>(); for(EObject eobj : eobjects2) { EObject eo = EcoreUtil.copy(eobj); list.add(eo); } oldClipboard = domain.getClipboard(); domain.setClipboard(list); } }; if(copyCommand != null) { return new EMFtoGMFCommandWrapper(copyCommand); } } return super.getCopyCommand(cntxt, diagramPart, isUndoable); } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.providers.DiagramGlobalActionHandler * #getCutCommand(org.eclipse.gmf.runtime.common.ui.services.action.global. * IGlobalActionContext, * org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart) */ @Override protected ICommand getCutCommand(IGlobalActionContext cntxt, IDiagramWorkbenchPart diagramPart) { if(cntxt.getSelection() instanceof StructuredSelection) { // All the elements in the selection are supposed to be of the same // type // We couldn't have got here otherwise Object firstElement = ((StructuredSelection)cntxt.getSelection()).getFirstElement(); EObject eobject = ((IGraphicalEditPart)firstElement).resolveSemanticElement(); TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(eobject); List elements = ((StructuredSelection)cntxt.getSelection()).toList(); List<EObject> eobjects = new ArrayList<EObject>(); editPartsInClipboard.clear(); for(Object o : elements) { EObject eobj = ((IGraphicalEditPart)o).resolveSemanticElement(); eobjects.add(eobj); container = eobj.eContainer(); for(Object view : DiagramEditPartsUtil.getEObjectViews(eobj)) { if(view instanceof View) { EditPart editpart = DiagramEditPartsUtil.getEditPartFromView((View)view, (EditPart)firstElement); editPartsInClipboard.add(editpart); } } } clipboard.clear(); clipboard.addAll(eobjects); final List<EObject> eobjects2 = eobjects; Command cutCommand = new CopyToClipboardCommand(domain, eobjects) { @Override public void doExecute() { /** * @author mgil : Don't use a different command to copy * every element, use the copy function from * EcoreUtil */ ArrayList<Object> list = new ArrayList<Object>(); for(EObject eobj : eobjects2) { list.add(eobj); } oldClipboard = domain.getClipboard(); domain.setClipboard(list); } }; if(cutCommand != null) { return new EMFtoGMFCommandWrapper(cutCommand); } } return super.getCutCommand(cntxt, diagramPart); } /** * Do something with the copied EObject * * @param eo */ protected void prepareEObject(EObject eObject) { } /** * Execute paste after copy. * * @param cntxt * the cntxt */ protected ICommand getExecutePasteAfterCopyCommand(IGlobalActionContext cntxt) { if(!(cntxt.getSelection() instanceof StructuredSelection)) { return null; } Object first = ((StructuredSelection)cntxt.getSelection()).getFirstElement(); if(!(first instanceof IGraphicalEditPart)) { return null; } IGraphicalEditPart pasteDestination = ((IGraphicalEditPart)first); TransactionalEditingDomain editingDomain = pasteDestination.getEditingDomain(); final Object firstElement = first; final IGraphicalEditPart editPart = pasteDestination; final TransactionalEditingDomain domain = editingDomain; AbstractCommonTransactionalCommmand command = new AbstractCommonTransactionalCommmand(editingDomain, "Paste after copy", null) { @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if(domain.getClipboard() != null && domain.getClipboard().size() > 0) { // All the objects in the clipboard are supposed to // be of the same type Object[] objects = domain.getClipboard().toArray(); EObject firstObjectToBePasted = (EObject)objects[0]; EStructuralFeature feature = getFeature(firstObjectToBePasted, editPart); // Execute paste Command pasteCommand = PasteFromClipboardCommand.create(domain, editPart.resolveSemanticElement(), feature); domain.getCommandStack().execute(pasteCommand); // The new elements must be shown on the diagram List<EObject> eobjects = new ArrayList<EObject>(); for(Object o : pasteCommand.getAffectedObjects()) { if(o instanceof EObject) { prepareEObject((EObject)o); eobjects.add((EObject)o); } } ICommand command = new AddEObjectReferencesToDiagram(domain, DiagramEditPartsUtil.findDiagramFromEditPart((IGraphicalEditPart)firstElement), eobjects); domain.getCommandStack().execute(new GMFtoEMFCommandWrapper(command)); // refresh the affected EditPart DiagramEditPartsUtil.updateEditPart(editPart); return CommandResult.newOKCommandResult(); } return CommandResult.newCancelledCommandResult(); } }; return command.canExecute() ? command : null; } /** * Execute paste after cut. * * @param cntxt * the cntxt */ protected ICommand getExecutePasteAfterCutCommand(IGlobalActionContext cntxt) { if(!(cntxt.getSelection() instanceof StructuredSelection)) { return null; } Object first = ((StructuredSelection)cntxt.getSelection()).getFirstElement(); if(!(first instanceof IGraphicalEditPart)) { return null; } IGraphicalEditPart pasteDestination = ((IGraphicalEditPart)first); TransactionalEditingDomain editingDomain = pasteDestination.getEditingDomain(); final Object firstElement = first; final IGraphicalEditPart editPart = pasteDestination; final TransactionalEditingDomain domain = editingDomain; AbstractCommonTransactionalCommmand command = new AbstractCommonTransactionalCommmand(editingDomain, "Paste after cut", null) { @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if(domain.getClipboard() != null && domain.getClipboard().size() > 0) { // All the objects in the clipboard are supposed to be of // the // same type Object[] objects = domain.getClipboard().toArray(); EObject firstObjectToBePasted = (EObject)objects[0]; EStructuralFeature feature = getFeature(firstObjectToBePasted, editPart); // Execute paste CompoundCommand cc = new CompoundCommand("Paste"); Command removeCommand = RemoveCommand.create(domain, container, feature, clipboard); if(!removeCommand.canExecute()) { return CommandResult.newCancelledCommandResult(); } cc.append(removeCommand); for(EditPart ep : editPartsInClipboard) { Command c = getDeleteViewCommand(ep); if(c != null && !c.canExecute()) { return CommandResult.newCancelledCommandResult(); } cc.append(c); } for(Object obj : domain.getClipboard()) { Command addCommand = AddCommand.create(domain, editPart.resolveSemanticElement(), feature, obj); if(!addCommand.canExecute()) { return CommandResult.newCancelledCommandResult(); } cc.append(addCommand); } // The new elements must be shown on the diagram List<EObject> eobjects = new ArrayList<EObject>(); for(Object o : domain.getClipboard()) { if(o instanceof EObject) { eobjects.add((EObject)o); } } ICommand command = new AddEObjectReferencesToDiagram(domain, DiagramEditPartsUtil.findDiagramFromEditPart((IGraphicalEditPart)firstElement), eobjects); if(!command.canExecute()) { return CommandResult.newCancelledCommandResult(); } cc.append(new GMFtoEMFCommandWrapper(command)); if(!cc.canExecute()) { return CommandResult.newCancelledCommandResult(); } domain.getCommandStack().execute(cc); // Empty the clipboard domain.setClipboard(new ArrayList<Object>()); clipboard.clear(); editPartsInClipboard.clear(); // Refresh the diagram DiagramEditPartsUtil.updateEditPart(editPart); return CommandResult.newOKCommandResult(); } return CommandResult.newCancelledCommandResult(); } }; return command.canExecute() ? command : null; } /** * Gets the diagram preferences hint. * * @param editPart * the edit part * * @return the diagram preferences hint */ // @unused private PreferencesHint getDiagramPreferencesHint(IGraphicalEditPart editPart) { return editPart.getDiagramPreferencesHint(); } /* * Checks if all the objects contained in the list are of the same type than * the eobject passed as parameter */ /** * All elements same type. * * @param eobjects * the eobjects * @param eobject * the eobject * * @return true, if successful */ private boolean allElementsSameType(List<EObject> eobjects, EObject eobject) { for(EObject o : eobjects) { if(o != null) { if(!o.eClass().equals(eobject.eClass())) { return false; } } else { return false; } } return true; } /** * Gets the delete view command. * * @param editPart * the edit part * * @return the delete view command */ protected Command getDeleteViewCommand(EditPart editPart) { if(editPart == null) { return null; } Request deleteViewRequest = new GroupRequest(RequestConstants.REQ_DELETE); org.eclipse.gef.commands.Command command = editPart.getCommand(deleteViewRequest); return new GEFtoEMFCommandWrapper(command); } /** * Gets the edits the parts in clipboard. * * @param clipboard * the clipboard * * @return the edits the parts in clipboard */ // @unused protected Collection<EditPart> getEditPartsInClipboard(Collection<Object> clipboard) { if(clipboard != null && clipboard.size() > 0) { Collection<EditPart> editParts = new ArrayList<EditPart>(); for(Object object : clipboard) { if(object instanceof EditPart) { editParts.add((EditPart)object); } } return editParts; } return Collections.EMPTY_LIST; } /** * Gets the feature. * * @param objectToBePasted * the object to be pasted * @param pasteDestination * the paste destination * * @return the feature */ public EStructuralFeature getFeature(EObject objectToBePasted, EditPart pasteDestination) { if(objectToBePasted == null || pasteDestination == null) { return null; } EObject element = MDTUtil.resolveSemantic(pasteDestination); return getFeature(element, objectToBePasted, pasteDestination); } /** * Gets the feature. * * @param element * the element * @param objectToBePasted * the object to be pasted * @param editPart * the edit part * * @return the feature */ protected EStructuralFeature getFeature(EObject element, EObject objectToBePasted, EditPart editPart) { if(!(element == MDTUtil.resolveSemantic(editPart))) { return null; } EStructuralFeature feature = null; Object adapter = editPart.getAdapter(ViewAndFeatureResolver.class); ViewAndFeatureResolver resolver = null; if(adapter instanceof ViewAndFeatureResolver) { resolver = (ViewAndFeatureResolver)adapter; } if(resolver != null) { feature = resolver.getEStructuralFeatureForEClass(objectToBePasted.eClass()); } if(feature == null) { for(Object child : editPart.getChildren()) { if(child instanceof EditPart) { feature = getFeature(element, objectToBePasted, (EditPart)child); } if(feature != null) { break; } } } return feature; } }