package org.yakindu.sct.ui.editor.providers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.ui.action.actions.global.ClipboardManager;
import org.eclipse.gmf.runtime.common.ui.util.CustomData;
import org.eclipse.gmf.runtime.common.ui.util.CustomDataTransfer;
import org.eclipse.gmf.runtime.common.ui.util.ICustomData;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.internal.commands.CopyCommand;
import org.eclipse.gmf.runtime.emf.clipboard.core.ClipboardUtil;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.View;
import org.yakindu.sct.model.sgraph.Region;
import org.yakindu.sct.model.sgraph.State;
import org.yakindu.sct.model.sgraph.Vertex;
import org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil;
/**
* Copy command that also copies the corresponding sub diagram for a state, if existing.
*
* @author kutz
*
*/
@SuppressWarnings({"restriction", "rawtypes"})
public class SubdiagramAwareCopyCommand extends CopyCommand implements ICommand {
public SubdiagramAwareCopyCommand(TransactionalEditingDomain editingDomain, String label, View viewContext,
List source) {
super(editingDomain, label, viewContext, source);
}
@Override
protected void copyToClipboard(List source) {
/* Check if the source has elements */
if (source == null || source.size() == 0) {
return;
}
CustomData data = copyViews(source);
addToClipboardManager(data);
}
protected void addToClipboardManager(CustomData data) {
if (data != null) {
ClipboardManager.getInstance().addToCache(new ICustomData[]{data}, CustomDataTransfer.getInstance());
}
}
protected CustomData copyViews(List<EObject> source) {
String copy = copyWithSubdiagrams(source);
return new CustomData(DRAWING_SURFACE, copy.getBytes());
}
/**
* This is basically a copy of
* {@link org.eclipse.gmf.runtime.diagram.ui.internal.commands.ClipboardCommand.copyViewsToString(List)}
* which is static and therefore not exchangeable. Only difference is adding of sub diagrams.
*/
protected String copyWithSubdiagrams(List<EObject> views) {
Assert.isNotNull(views);
Assert.isTrue(views.size() > 0);
List<EObject> selection = new ArrayList<EObject>();
Iterator iter = views.iterator();
while (iter.hasNext()) {
EObject viewElement = (View) iter.next();
if (viewElement != null) {
selection.add(viewElement);
}
}
/*
* We must append all inner edges of a node being copied. Edges are
* non-containment references, hence they won't be copied for free.
* Therefore, we add them here to the list of views to copy.
*/
selection.addAll(getInnerEdges(views));
// add the measurement unit in an annotation. Put it in the last
// position
// to work around a limitation in the copy/paste infrastructure, that
// selects the ClipboardSupportFactory based on the first element in
// the copy list. If the annotation is first, then we get the wrong
// clipboard support instance
selection.add(getMeasurementUnitAnnotation(views));
// PATCH START
// add all sub diagrams of selected states
selection.addAll(getSubDiagrams(views));
// PATCH END
/* Copy the selection to the string */
return ClipboardUtil.copyElementsToString(selection, new HashMap(), new NullProgressMonitor());
}
protected EAnnotation getMeasurementUnitAnnotation(List<EObject> views) {
View firstView = (View) views.get(0);
Diagram dgrm = firstView.getDiagram();
EAnnotation measureUnitAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
measureUnitAnnotation.setSource(dgrm.getMeasurementUnit().getName());
return measureUnitAnnotation;
}
protected List<Edge> getInnerEdges(List views) {
List<Edge> innerEdges = new LinkedList<Edge>();
for (Iterator itr = views.iterator(); itr.hasNext();) {
View view = (View) itr.next();
if (!(view instanceof Diagram)) {
innerEdges.addAll(ViewUtil.getAllInnerEdges(view));
}
}
return innerEdges;
}
protected List<Diagram> getSubDiagrams(List views) {
List<Diagram> subDiagrams = new ArrayList<Diagram>();
Iterator iter = views.iterator();
while (iter.hasNext()) {
View viewElement = (View) iter.next();
if (viewElement != null) {
EObject semanticElement = viewElement.getElement();
if (semanticElement instanceof State) {
collectSubdiagramsInState(subDiagrams, (State) semanticElement);
} else if (semanticElement instanceof Region) {
collectSubdiagramsInRegion(subDiagrams, (Region) semanticElement);
}
}
}
return subDiagrams;
}
protected void collectSubdiagramsInRegion(List<Diagram> subDiagrams, Region region) {
for (Vertex vertex : region.getVertices()) {
if (vertex instanceof State) {
collectSubdiagramsInState(subDiagrams, (State) vertex);
}
}
}
protected void collectSubdiagramsInState(List<Diagram> subDiagrams, State state) {
if (state.isComposite()) {
subDiagrams.addAll(getAllSubDiagrams(state));
}
}
protected Collection<? extends Diagram> getAllSubDiagrams(State semanticState) {
List<Diagram> subDiagrams = new ArrayList<>();
addSubDiagram(semanticState, subDiagrams);
TreeIterator<EObject> iter = semanticState.eAllContents();
while (iter.hasNext()) {
EObject next = iter.next();
if (next instanceof State) {
State subState = (State) next;
if (subState.isComposite()) {
addSubDiagram(subState, subDiagrams);
} else {
iter.prune();
}
}
}
return subDiagrams;
}
protected void addSubDiagram(State semanticState, List<Diagram> subDiagrams) {
Diagram subDiagram = DiagramPartitioningUtil.getSubDiagram(semanticState);
if (subDiagram != null) {
subDiagrams.add(subDiagram);
}
}
}