/******************************************************************************* * Copyright (c) 2010-2015 Henshin developers. 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: * TU Berlin, University of Luxembourg, SES S.A. *******************************************************************************/ package de.tub.tfs.henshin.tggeditor.clipboard; import java.io.ByteArrayInputStream; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.emf.ecore.EAttribute; 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.EcorePackage; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.henshin.model.Attribute; import org.eclipse.emf.henshin.model.Edge; import org.eclipse.emf.henshin.model.Graph; import org.eclipse.emf.henshin.model.Node; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gmf.runtime.emf.clipboard.core.AbstractClipboardSupport; import org.eclipse.gmf.runtime.emf.clipboard.core.ClipboardUtil; import org.eclipse.gmf.runtime.emf.clipboard.core.IClipboardSupport; import org.eclipse.gmf.runtime.emf.clipboard.core.ObjectInfo; import org.eclipse.gmf.runtime.emf.clipboard.core.OverridePasteChildOperation; import org.eclipse.gmf.runtime.emf.clipboard.core.PasteAction; import org.eclipse.gmf.runtime.emf.clipboard.core.PasteChildOperation; import org.eclipse.gmf.runtime.emf.clipboard.core.PasteTarget; import org.eclipse.gmf.runtime.emf.clipboard.core.PostPasteChildOperation; import org.eclipse.gmf.runtime.emf.clipboard.core.internal.IClipboardSupport2; import org.eclipse.gmf.runtime.emf.clipboard.core.internal.LoadingEMFResource; import org.eclipse.gmf.runtime.emf.clipboard.core.internal.ObjectCopyType; import org.eclipse.gmf.runtime.emf.clipboard.core.internal.PasteIntoParentOperation; import org.eclipse.gmf.runtime.emf.clipboard.core.internal.PasteOperation; import org.eclipse.gmf.runtime.emf.clipboard.core.internal.ResourceInfoProcessor; import de.tub.tfs.henshin.tgg.TggPackage; import de.tub.tfs.henshin.tgg.interpreter.util.RuleUtil; import de.tub.tfs.henshin.tggeditor.commands.create.rule.MarkAttributeCommand; import de.tub.tfs.henshin.tggeditor.commands.create.rule.MarkCommand; import de.tub.tfs.henshin.tggeditor.commands.create.rule.MarkEdgeCommand; import de.tub.tfs.muvitor.actions.GenericPasteAction; import de.tub.tfs.muvitor.actions.GenericPasteAction.IPasteRule; public class TGGClipboardSupport extends AbstractClipboardSupport implements IClipboardSupport2 { private final class LoadingEMFResourceExtension extends LoadingEMFResource { private PasteIntoParentOperation op; private LoadingEMFResourceExtension(ResourceSet rset, String encoding, Map defaultLoadOptions, IClipboardSupport clipboardOperationHelper,PasteIntoParentOperation op) { super(rset, encoding, defaultLoadOptions, clipboardOperationHelper); this.op = op; } @Override protected void doUnload() { CompoundCommand nodeCommands = new CompoundCommand(); CompoundCommand edgeCommands = new CompoundCommand(); CompoundCommand attrCommands = new CompoundCommand(); for (Object pasted : op.getPastedElementSet()) { if (pasted instanceof EObject){ if (((EObject) pasted).eClass().getEPackage().equals(TggPackage.eINSTANCE)) { EStructuralFeature marker = ((EObject) pasted).eClass().getEStructuralFeature("markerType"); if (marker != null){ String markerString = (String) ((EObject) pasted).eGet(marker); if (!RuleUtil.NEW.equals(markerString) && !RuleUtil.TR_UNSPECIFIED.equals(markerString)){ EObject eContainer = ((EObject) pasted).eContainer(); if (eContainer instanceof Graph){ Graph containingGraph = (Graph) eContainer; if (containingGraph.isLhs() || containingGraph.isRhs()){ if (pasted instanceof Node){ ((EObject) pasted).eSet(marker, RuleUtil.NEW); MarkCommand cmd = new MarkCommand((Node) pasted); nodeCommands.add(cmd); } else if (pasted instanceof Edge){ ((EObject) pasted).eSet(marker, RuleUtil.NEW); MarkEdgeCommand cmd = new MarkEdgeCommand((Edge) pasted); edgeCommands.add(cmd); } else if (pasted instanceof Attribute){ ((EObject) pasted).eSet(marker, RuleUtil.NEW); MarkAttributeCommand cmd = new MarkAttributeCommand((Attribute) pasted); attrCommands.add(cmd); } } } } } } EObject p = (EObject) pasted; EObject container = p.eContainer(); EStructuralFeature cont = ((EObject) pasted).eContainingFeature(); this.getContents().remove(pasted); Object c = container.eGet(cont); if (cont.isMany()){ ((List)c).add(p); } else { container.eSet(cont, p); } } } nodeCommands.execute(); edgeCommands.execute(); attrCommands.execute(); super.doUnload(); } } protected EAttribute getNameAttribute(EClass eClass) { return eClass.getEIDAttribute(); } public PasteAction getPasteCollisionAction(EClass eClass) { return super.getPasteCollisionAction(eClass); } public boolean isCopyAlways(EObject context, EReference eReference, Object value) { return super.isCopyAlways(context, eReference, value); } @Override public boolean shouldOverrideChildPasteOperation(EObject parentElement, EObject childEObject) { return true; } @Override public OverridePasteChildOperation getOverrideChildPasteOperation( final PasteChildOperation overriddenChildPasteOperation) { // TODO Auto-generated method stub return new OverridePasteChildOperation(overriddenChildPasteOperation) { private Map embeddedCopyParentObjectInfoMap = new HashMap(); /** * Copy from org.eclipse.gmf.runtime.emf.clipboard.core.PasteChildOperation * @return * @throws Exception */ private ObjectInfo makeEmbeddedCopyParentObjectInfo( EObject embeddedCopyParent) { ObjectInfo objectInfo = (ObjectInfo) embeddedCopyParentObjectInfoMap .get(embeddedCopyParent); if (objectInfo == null) { objectInfo = new ObjectInfo(); objectInfo.objCopyType = ObjectCopyType.OBJ_COPY_TYPE_PARENT; objectInfo.objId = getLoadedEObjectID(embeddedCopyParent); objectInfo.containerId = getLoadedEObjectID(embeddedCopyParent .eContainer()); objectInfo.containerClass = embeddedCopyParent.eContainer() .eClass().getInstanceClassName(); if (objectInfo.objId.equals(getChildObjectInfo().copyParentId) == false) { objectInfo.copyParentId = getChildObjectInfo().copyParentId; } else { objectInfo.copyParentId = ResourceInfoProcessor.NONE; } objectInfo.hints = ResourceInfoProcessor.NONE; //cache it embeddedCopyParentObjectInfoMap.put(embeddedCopyParent, objectInfo); } return objectInfo; } /** * Copy from org.eclipse.gmf.runtime.emf.clipboard.core.PasteChildOperation * @return * @throws Exception */ private EObject doPasteIntoCopyParent(ObjectInfo theCopyParentObjectInfo) throws Exception { PasteChildOperation copyParentProcess = getAuxiliaryChildPasteProcess(theCopyParentObjectInfo); copyParentProcess.paste(); EObject pastedCopyParent = copyParentProcess.getPastedElement(); if (pastedCopyParent != null) { //the direct copy parent should have been pasted correctly by now return doPasteInto(getPastedDirectCopyParent()); } return null; } /** * Copy from org.eclipse.gmf.runtime.emf.clipboard.core.PasteChildOperation * @return * @throws Exception */ private EObject doPasteIntoNearestCopyParent( EObject topMostCopyParentEObject) throws Exception { EObject nearestParent = getLoadedEObject(getChildObjectInfo().containerId); while (nearestParent.equals(topMostCopyParentEObject) == false) { EObject parentElement = doPasteIntoCopyParent(makeEmbeddedCopyParentObjectInfo(nearestParent)); if (parentElement != null) { return parentElement; } nearestParent = nearestParent.eContainer(); } return null; } /** * Copy from org.eclipse.gmf.runtime.emf.clipboard.core.PasteChildOperation * @return * @throws Exception */ private EObject doPasteIntoCopyParent() throws Exception { //check if copyParentEObject exists in the target model already //try matching direct copy parent ID. EObject existingCopyParentEObject = getEObject(getChildObjectInfo().containerId); if (existingCopyParentEObject != null) { return doPasteInto(existingCopyParentEObject); } //check if the copy-parent has been //pasted already by a sibling paste operation that executed before us? EObject pastedDirectCopyParent = getPastedDirectCopyParent(); if (pastedDirectCopyParent != null) { //the direct copy parent should have been pasted correctly already return doPasteInto(pastedDirectCopyParent); } EObject nearestParent = null; if (isCopyParentDirectParent() == false) { nearestParent = getLoadedEObject(getChildObjectInfo().containerId); EObject perent = nearestParent.eContainer(); EObject root = getCopyParentEObject(); while ((perent != null) && (perent.equals(root) == false)) { existingCopyParentEObject = getPastedEObject(perent); if (existingCopyParentEObject != null) { break; } nearestParent = perent; perent = nearestParent.eContainer(); } if (existingCopyParentEObject == null) { //check the root itself existingCopyParentEObject = getPastedEObject(root); } } if (existingCopyParentEObject != null) { //the nearestParent copy parent should have been pasted correctly // already //paste the nearest-parent itself first, the paste the child into // it afterwards return doPasteIntoCopyParent(makeEmbeddedCopyParentObjectInfo(nearestParent)); } else { //no parent with same ID, and the copy-parent not pasted already, //then try other ways to match a parent PasteTarget possibleParent = getSuitableParentUsingAncestry(getLoadedDirectContainerEObject() .eClass().getInstanceClassName()); if (possibleParent != null) { return doPasteInto(possibleParent); } else { //no suitable exisiting parent then the copy-parent itself //needs to be pasted first EObject element = doPasteIntoNearestCopyParent(getCopyParentEObject()); if (element != null) { //found a nearest copy parent and pasted it successfully return element; } //now final try: use the root copy Parent? return doPasteIntoCopyParent(getCopyParentObjectInfo()); } } } @Override public void paste() throws Exception { if (hasCopyParent()) { setPastedElement(doPasteIntoCopyParent()); } else { EObject element = null; //either it is not a copyAlways, or it is a copyAlways // whose //original parent didn't resolve, thus, proceed normally //by trying to paste in target obj element = doPasteInto(getParentTarget()); if (element == null) { /*------------- //failed to copy in target parent...then check if it is a copy-always and its // original parent resolves in target model if (isCopyAlways()) { EObject resolvedCopyAlwaysParent = getEObject(getChildObjectInfo().containerId); if (resolvedCopyAlwaysParent != null) { //found original parent for this copyAlways object, // then use it, //instead of user selected parent element = doPasteInto(resolvedCopyAlwaysParent); } } -------------*/ if ((element == null) && ((getChildObjectInfo() .hasHint(ClipboardUtil.PASTE_TO_TARGET_PARENT)) || (isCopyAlways()))) { PasteTarget possibleParent = getSuitableParentUsingAncestry(getChildObjectInfo().containerClass); if (possibleParent != null) { element = doPasteInto(possibleParent); } } } setPastedElement(element); } //did we succeed? if (getPastedElement() != null) { addPastedElement(getPastedElement()); } else { addPasteFailuresObject(getEObject()); } } @Override public PasteChildOperation getPostPasteOperation() { // TODO Auto-generated method stub return new PostPasteChildOperation(overriddenChildPasteOperation,Arrays.asList(new PasteChildOperation(getParentPasteProcess(), getChildObjectInfo()){ @Override public void paste() throws Exception { super.paste(); performPostPasteProcessing(getPastedElement(),getParentEObject()); } @Override public PasteChildOperation getPostPasteOperation() { return null; } }) ); } }; } private void performPostPasteProcessing(EObject copy, EObject pasteIntoEObject) { if (copy == null) return; final LinkedList<EClass> copySuperTypes = new LinkedList<EClass>( copy.eClass().getEAllSuperTypes()); copySuperTypes.add(EcorePackage.Literals.EOBJECT); copySuperTypes.add(copy.eClass()); for (final Entry<EClass, IPasteRule> entry : GenericPasteAction.pasteRules.entrySet()) { if (copySuperTypes.contains(entry.getKey())) { entry.getValue().afterPaste(copy, copy.eContainer()); } } } @Override public void performPostPasteProcessing(Set pastedEObjects) { Set<EObject> pasted = pastedEObjects; for (final EObject copy : pasted) { //performPostPasteProcessing(copy, copy.eContainer()); } } @Override public boolean shouldOverridePasteIntoParentOperation( PasteTarget pasteTarget, Map hintsMap) { // TODO Auto-generated method stub return true; } @Override public PasteIntoParentOperation getPasteIntoParentOperation( PasteOperation pasteOperation, PasteTarget pasteTarget, Map hintsMap) throws Exception { // TODO Auto-generated method stub return new PasteIntoParentOperation(pasteOperation, pasteTarget, hintsMap){ @Override protected LoadingEMFResource loadEObjects() throws Exception { ByteArrayInputStream inputStream = new ByteArrayInputStream( getResourceInfo().data.getBytes(getResourceInfo().encoding)); LoadingEMFResource resource = new LoadingEMFResourceExtension(getParentResource().getResourceSet(), getResourceInfo().encoding, getLoadOptionsMap(), getClipboardOperationHelper(),this); resource.load(inputStream, null); return resource; } }; } }