/*
* Copyright (c) 2007 Borland Software Corporation
*
* 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:
* Dmitry Stadnik (Borland) - initial API and implementation
*/
package org.eclipse.gmf.internal.sketch.transformer;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.codegen.ecore.genmodel.GenClass;
import org.eclipse.emf.codegen.ecore.genmodel.GenFeature;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
import org.eclipse.emf.common.util.UniqueEList;
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.gmf.codegen.gmfgen.ElementType;
import org.eclipse.gmf.codegen.gmfgen.FeatureLabelModelFacet;
import org.eclipse.gmf.codegen.gmfgen.FeatureLinkModelFacet;
import org.eclipse.gmf.codegen.gmfgen.FigureViewmap;
import org.eclipse.gmf.codegen.gmfgen.GMFGenFactory;
import org.eclipse.gmf.codegen.gmfgen.GenChildContainer;
import org.eclipse.gmf.codegen.gmfgen.GenChildLabelNode;
import org.eclipse.gmf.codegen.gmfgen.GenChildNode;
import org.eclipse.gmf.codegen.gmfgen.GenCommonBase;
import org.eclipse.gmf.codegen.gmfgen.GenCompartment;
import org.eclipse.gmf.codegen.gmfgen.GenCustomPropertyTab;
import org.eclipse.gmf.codegen.gmfgen.GenDiagram;
import org.eclipse.gmf.codegen.gmfgen.GenDiagramUpdater;
import org.eclipse.gmf.codegen.gmfgen.GenEditorGenerator;
import org.eclipse.gmf.codegen.gmfgen.GenEditorView;
import org.eclipse.gmf.codegen.gmfgen.GenLabel;
import org.eclipse.gmf.codegen.gmfgen.GenLink;
import org.eclipse.gmf.codegen.gmfgen.GenLinkLabel;
import org.eclipse.gmf.codegen.gmfgen.GenNode;
import org.eclipse.gmf.codegen.gmfgen.GenNodeLabel;
import org.eclipse.gmf.codegen.gmfgen.GenPlugin;
import org.eclipse.gmf.codegen.gmfgen.GenPropertySheet;
import org.eclipse.gmf.codegen.gmfgen.GenPropertyTab;
import org.eclipse.gmf.codegen.gmfgen.GenTopLevelNode;
import org.eclipse.gmf.codegen.gmfgen.MetamodelType;
import org.eclipse.gmf.codegen.gmfgen.Palette;
import org.eclipse.gmf.codegen.gmfgen.SpecializationType;
import org.eclipse.gmf.codegen.gmfgen.ToolEntry;
import org.eclipse.gmf.codegen.gmfgen.ToolGroup;
import org.eclipse.gmf.codegen.gmfgen.TypeLinkModelFacet;
import org.eclipse.gmf.codegen.gmfgen.TypeModelFacet;
import org.eclipse.gmf.codegen.gmfgen.TypeTabFilter;
import org.eclipse.gmf.internal.bridge.genmodel.GenModelMatcher;
import org.eclipse.gmf.internal.bridge.genmodel.RuntimeGenModelAccess;
import org.eclipse.gmf.internal.common.reconcile.Reconciler;
import org.eclipse.gmf.internal.sketch.transformer.reconcile.SketchReconcilerConfig;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.sketch.SketchCompartment;
import org.eclipse.gmf.sketch.SketchDiagram;
import org.eclipse.gmf.sketch.SketchDiagramElement;
import org.eclipse.gmf.sketch.SketchLabel;
import org.eclipse.gmf.sketch.SketchLink;
import org.eclipse.gmf.sketch.SketchLinkEnd;
import org.eclipse.gmf.sketch.SketchNode;
import org.eclipse.jface.operation.IRunnableWithProgress;
/**
* @author dstadnik
*/
public class SketchTransformer implements IRunnableWithProgress {
private SketchDiagram diagram;
private GenEditorGenerator editorGen;
private IStatus status;
private Map<SketchNode, GenNode> boundNodes = new HashMap<SketchNode, GenNode>();
private Map<SketchCompartment, GenCompartment> boundCompartments = new HashMap<SketchCompartment, GenCompartment>();
private Map<EClass, MetamodelType> boundMetamodelTypes = new HashMap<EClass, MetamodelType>();
private GenModelMatcher genModelMatcher;
private GenClass ntDiagram;
private GenClass ntNode;
private GenClass ntEdge;
private VisualIDsDispenser visualIDsDispenser;
private NamesHelper namesHelper = new NamesHelper();
public SketchTransformer(SketchDiagram diagram, GenModel genModel) {
assert diagram != null;
this.diagram = diagram;
if (genModel != null) {
this.genModelMatcher = new GenModelMatcher(genModel);
}
initNotationModel();
visualIDsDispenser = new VisualIDsDispenser(diagram);
}
protected void initNotationModel() {
RuntimeGenModelAccess runtimeAccess = new RuntimeGenModelAccess();
runtimeAccess.ensure();
GenPackage gp = runtimeAccess.genPackage();
for (GenClass genClass : gp.getGenClasses()) {
if (NotationPackage.eINSTANCE.getNode().getName().equals(genClass.getName())) {
ntNode = genClass;
} else if (NotationPackage.eINSTANCE.getEdge().getName().equals(genClass.getName())) {
ntEdge = genClass;
} else if (NotationPackage.eINSTANCE.getDiagram().getName().equals(genClass.getName())) {
ntDiagram = genClass;
}
}
assert ntDiagram != null;
assert ntNode != null;
assert ntEdge != null;
}
public final SketchDiagram getSource() {
return diagram;
}
public final IStatus getStatus() {
return status;
}
public final GenEditorGenerator getResult() {
return editorGen;
}
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
if (diagram == null) {
status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SketchTransformer_NoCanvas);
return;
}
try {
transformSketch();
} finally {
boundNodes.clear();
boundCompartments.clear();
boundMetamodelTypes.clear();
}
status = Status.OK_STATUS;
}
public void reconcile(GenEditorGenerator existingEditorGen) {
new Reconciler(new SketchReconcilerConfig()).reconcileTree(editorGen, existingEditorGen);
}
protected void transformSketch() {
createEditor();
for (SketchNode node : boundNodes.keySet()) {
if (!node.getReferencedNodes().isEmpty()) {
addReferencedNodes(boundNodes.get(node), node.getReferencedNodes());
}
}
for (SketchCompartment compartment : boundCompartments.keySet()) {
if (!compartment.getReferencedNodes().isEmpty()) {
addReferencedNodes(boundCompartments.get(compartment), compartment.getReferencedNodes());
}
}
}
protected void addReferencedNodes(GenChildContainer genContainer, List<SketchNode> referencedNodes) {
for (SketchNode referencedNode : referencedNodes) {
GenNode referencedGenNode = boundNodes.get(referencedNode);
if (referencedGenNode == null) {
Activator.logWarning(Messages.SketchTransformer_RefNodeNotResolved);
continue;
}
if (!(referencedGenNode instanceof GenChildNode)) {
Activator.logWarning(Messages.SketchTransformer_RefNodeNotChild);
}
genContainer.getChildNodes().add((GenChildNode) referencedGenNode);
}
}
protected void createEditor() {
editorGen = GMFGenFactory.eINSTANCE.createGenEditorGenerator();
if (genModelMatcher != null) {
editorGen.setDomainGenModel(genModelMatcher.getGenModel());
}
createDiagram();
GenPlugin plugin = GMFGenFactory.eINSTANCE.createGenPlugin();
editorGen.setPlugin(plugin);
GenEditorView view = GMFGenFactory.eINSTANCE.createGenEditorView();
editorGen.setEditor(view);
GenDiagramUpdater updater = GMFGenFactory.eINSTANCE.createGenDiagramUpdater();
editorGen.setDiagramUpdater(updater);
createProperties();
}
protected void createProperties() {
GenPropertySheet properties = GMFGenFactory.eINSTANCE.createGenPropertySheet();
editorGen.setPropertySheet(properties);
GenPropertyTab tabAppearance = GMFGenFactory.eINSTANCE.createGenStandardPropertyTab();
tabAppearance.setID("appearance"); //$NON-NLS-1$
tabAppearance.setLabel("Appearance"); //$NON-NLS-1$
properties.getTabs().add(tabAppearance);
GenPropertyTab tabGridRulers = GMFGenFactory.eINSTANCE.createGenStandardPropertyTab();
tabGridRulers.setID("diagram"); //$NON-NLS-1$
tabGridRulers.setLabel("Rulers & Grid"); //$NON-NLS-1$
properties.getTabs().add(tabGridRulers);
GenCustomPropertyTab tabDomainModel = GMFGenFactory.eINSTANCE.createGenCustomPropertyTab();
tabDomainModel.setID("domain_model"); //$NON-NLS-1$
tabDomainModel.setLabel("Domain Model"); //$NON-NLS-1$
properties.getTabs().add(tabDomainModel);
TypeTabFilter filter = GMFGenFactory.eINSTANCE.createTypeTabFilter();
filter.getTypes().add("org.eclipse.gef.EditPart"); //$NON-NLS-1$
filter.getTypes().add("org.eclipse.gmf.runtime.notation.View"); //$NON-NLS-1$
tabDomainModel.setFilter(filter);
}
protected void createDiagram() {
GenDiagram genDiagram = GMFGenFactory.eINSTANCE.createGenDiagram();
genDiagram.setDiagramRunTimeClass(ntDiagram);
genDiagram.setViewmap(createViewmap(diagram.getShape(), genDiagram));
EClass type = diagram.getType();
ElementType elementType;
if (type != null) {
elementType = GMFGenFactory.eINSTANCE.createMetamodelType();
genDiagram.setDomainDiagramElement(genModelMatcher.findGenClass(type));
boundMetamodelTypes.put(type, (MetamodelType) elementType);
} else {
elementType = GMFGenFactory.eINSTANCE.createNotationType();
}
genDiagram.setElementType(elementType);
genDiagram.setVisualID(visualIDsDispenser.get(diagram));
namesHelper.fix(genDiagram, diagram.getName());
editorGen.setDiagram(genDiagram);
Palette palette = GMFGenFactory.eINSTANCE.createPalette();
genDiagram.setPalette(palette);
ToolGroup group = GMFGenFactory.eINSTANCE.createToolGroup();
String groupTitle = diagram.getName();
if (groupTitle == null && type != null) {
groupTitle = type.getName();
}
group.setTitle(groupTitle);
palette.getGroups().add(group);
for (SketchNode node : diagram.getNodes()) {
createNode(node, group);
}
for (SketchLink link : diagram.getLinks()) {
createLink(link, group);
}
}
protected void createNode(SketchNode node, ToolGroup group) {
GenTopLevelNode genNode = GMFGenFactory.eINSTANCE.createGenTopLevelNode();
editorGen.getDiagram().getTopLevelNodes().add(genNode);
if (!node.getAttributes().isEmpty()) {
Activator.logWarning(Messages.SketchTransformer_TopNodeAttrsIgnored);
}
if (node.isOnBorder()) {
Activator.logWarning(Messages.SketchTransformer_TopNodeOnBorder);
}
createNodeHelper(node, group, genNode, diagram.getType());
}
protected void createChildNode(SketchNode node, ToolGroup group, GenChildContainer genContainer, EClass containerType) {
GenChildNode genNode;
if (!node.getAttributes().isEmpty()) {
genNode = GMFGenFactory.eINSTANCE.createGenChildLabelNode();
((GenChildLabelNode) genNode).setLabelModelFacet(createFeatureLabelModelFacet(node.getAttributes()));
} else if (node.isOnBorder()) {
genNode = GMFGenFactory.eINSTANCE.createGenChildSideAffixedNode();
} else {
genNode = GMFGenFactory.eINSTANCE.createGenChildNode();
}
editorGen.getDiagram().getChildNodes().add(genNode);
genContainer.getChildNodes().add(genNode);
createNodeHelper(node, group, genNode, containerType);
}
protected void createNodeHelper(SketchNode node, ToolGroup group, GenNode genNode, EClass containerType) {
genNode.setDiagramRunTimeClass(ntNode);
genNode.setViewmap(createViewmap(node.getShape(), genNode));
EClass type = node.getType();
ElementType elementType;
if (type != null) {
elementType = createElementType(type);
TypeModelFacet modelFacet = GMFGenFactory.eINSTANCE.createTypeModelFacet();
modelFacet.setMetaClass(genModelMatcher.findGenClass(type));
if (containerType != null) {
EReference containmentRef = findReference(containerType, type, true);
modelFacet.setContainmentMetaFeature(genModelMatcher.findGenFeature(containmentRef));
}
genNode.setModelFacet(modelFacet);
} else {
elementType = GMFGenFactory.eINSTANCE.createNotationType();
}
genNode.setElementType(elementType);
genNode.setVisualID(visualIDsDispenser.get(node));
namesHelper.fix(genNode, node.getName());
boundNodes.put(node, genNode);
ToolEntry tool = addTool(node, group);
tool.getGenNodes().add(genNode);
if (tool.getTitle() == null) {
tool.setTitle(type != null ? type.getName() : "Node" + genNode.getVisualID()); //$NON-NLS-1$
}
for (SketchNode childNode : node.getNodes()) {
createChildNode(childNode, group, genNode, type);
}
for (SketchCompartment compartment : node.getCompartments()) {
createCompartment(compartment, group, genNode, type);
}
if (!(genNode instanceof GenChildLabelNode)) {
for (SketchLabel label : node.getLabels()) {
GenNodeLabel genLabel = label.isExternal() ? GMFGenFactory.eINSTANCE.createGenExternalNodeLabel() : GMFGenFactory.eINSTANCE.createGenNodeLabel();
initLabel(label, genLabel);
genNode.getLabels().add(genLabel);
}
}
}
protected void createCompartment(SketchCompartment compartment, ToolGroup group, GenNode parentGenNode, EClass containerType) {
GenCompartment genCompartment = GMFGenFactory.eINSTANCE.createGenCompartment();
genCompartment.setDiagramRunTimeClass(ntNode);
genCompartment.setViewmap(createViewmap(compartment.getShape(), genCompartment));
genCompartment.setVisualID(visualIDsDispenser.get(compartment));
namesHelper.fix(genCompartment, compartment.getName());
editorGen.getDiagram().getCompartments().add(genCompartment);
parentGenNode.getCompartments().add(genCompartment);
boundCompartments.put(compartment, genCompartment);
for (SketchNode childNode : compartment.getNodes()) {
createChildNode(childNode, group, genCompartment, containerType);
}
}
protected void createLink(SketchLink link, ToolGroup group) {
if (link.getSource().isEmpty()) {
Activator.logWarning(Messages.SketchTransformer_NoLinkSource);
return;
}
if (link.getTarget().isEmpty()) {
Activator.logWarning(Messages.SketchTransformer_NoLinkTarget);
return;
}
GenLink genLink = GMFGenFactory.eINSTANCE.createGenLink();
genLink.setDiagramRunTimeClass(ntEdge);
genLink.setViewmap(createViewmap(link.getShape(), genLink));
EClass sourceType = getType(link.getSource());
EClass targetType = getType(link.getTarget());
EClass type = link.getType();
ElementType elementType;
if (type != null) {
// class-based link
elementType = createElementType(type);
TypeLinkModelFacet modelFacet = GMFGenFactory.eINSTANCE.createTypeLinkModelFacet();
modelFacet.setMetaClass(genModelMatcher.findGenClass(type));
for (EObject element = link.getSource().iterator().next();; element = element.eContainer()) {
EClass containerType = null;
if (element instanceof SketchNode) {
containerType = ((SketchNode) element).getType();
} else if (element instanceof SketchLink) {
containerType = ((SketchLink) element).getType();
} else if (element instanceof SketchDiagram) {
containerType = ((SketchDiagram) element).getType();
} else {
break;
}
if (containerType != null) {
EReference containmentReference = findReference(containerType, type, true);
if (containmentReference != null) {
modelFacet.setContainmentMetaFeature(genModelMatcher.findGenFeature(containmentReference));
break;
}
}
}
if (sourceType != null) {
EReference sourceReference = findReference(type, sourceType, false);
modelFacet.setSourceMetaFeature(genModelMatcher.findGenFeature(sourceReference));
}
if (targetType != null) {
EReference targetReference = findReference(type, targetType, false);
modelFacet.setTargetMetaFeature(genModelMatcher.findGenFeature(targetReference));
}
genLink.setModelFacet(modelFacet);
} else {
if (sourceType != null && targetType != null) {
// ref-based link
EReference linkReference = findReference(sourceType, targetType, false);
if (linkReference != null) {
elementType = GMFGenFactory.eINSTANCE.createSpecializationType();
FeatureLinkModelFacet modelFacet = GMFGenFactory.eINSTANCE.createFeatureLinkModelFacet();
modelFacet.setMetaFeature(genModelMatcher.findGenFeature(linkReference));
genLink.setModelFacet(modelFacet);
} else {
elementType = GMFGenFactory.eINSTANCE.createNotationType();
}
} else {
elementType = GMFGenFactory.eINSTANCE.createNotationType();
}
}
genLink.setElementType(elementType);
genLink.setVisualID(visualIDsDispenser.get(link));
namesHelper.fix(genLink, link.getName());
ToolEntry tool = addTool(link, group);
tool.getGenLinks().add(genLink);
if (tool.getTitle() == null) {
tool.setTitle(type != null ? type.getName() : "Link" + genLink.getVisualID()); //$NON-NLS-1$
}
editorGen.getDiagram().getLinks().add(genLink);
for (SketchLabel label : link.getLabels()) {
GenLinkLabel genLabel = GMFGenFactory.eINSTANCE.createGenLinkLabel();
initLabel(label, genLabel);
genLink.getLabels().add(genLabel);
}
}
/*
* Finds common type; returns null if there is no such a type.
*/
protected EClass getType(List<SketchLinkEnd> ends) {
UniqueEList<EClass> types = new UniqueEList<EClass>();
for (SketchLinkEnd end : ends) {
types.add(getType(end));
}
return types.size() == 1 ? types.get(0) : null;
}
protected EClass getType(SketchLinkEnd end) {
if (end instanceof SketchNode) {
return ((SketchNode) end).getType();
} else if (end instanceof SketchLink) {
return ((SketchLink) end).getType();
}
return null;
}
protected void initLabel(SketchLabel label, GenLabel genLabel) {
genLabel.setDiagramRunTimeClass(ntNode);
genLabel.setViewmap(createViewmap(label.getShape(), genLabel));
genLabel.setVisualID(visualIDsDispenser.get(label));
namesHelper.fix(genLabel, label.getName());
if (!label.getAttributes().isEmpty()) {
genLabel.setModelFacet(createFeatureLabelModelFacet(label.getAttributes()));
}
}
protected FeatureLabelModelFacet createFeatureLabelModelFacet(List<EAttribute> attributes) {
FeatureLabelModelFacet labelFacet = GMFGenFactory.eINSTANCE.createFeatureLabelModelFacet();
for (EAttribute attribute : attributes) {
GenFeature genFeature = genModelMatcher.findGenFeature(attribute);
if (genFeature != null) {
labelFacet.getMetaFeatures().add(genFeature);
} else {
Activator.logWarning(String.format(Messages.SketchTransformer_NoGenFeatureForAttr, attribute.getName()));
}
}
return labelFacet;
}
protected ElementType createElementType(EClass type) {
if (boundMetamodelTypes.containsKey(type)) {
SpecializationType elementType = GMFGenFactory.eINSTANCE.createSpecializationType();
elementType.setMetamodelType(boundMetamodelTypes.get(type));
return elementType;
} else {
MetamodelType elementType = GMFGenFactory.eINSTANCE.createMetamodelType();
boundMetamodelTypes.put(type, elementType);
return elementType;
}
}
protected ToolEntry addTool(SketchDiagramElement element, ToolGroup group) {
ToolEntry tool = GMFGenFactory.eINSTANCE.createToolEntry();
if (element.getName() != null) {
tool.setTitle(element.getName());
}
group.getEntries().add(tool);
return tool;
}
protected EReference findReference(EClass container, EClass type, boolean containment) {
EReference bestRef = null;
for (EReference ref : container.getEAllReferences()) {
if (ref.isContainment() != containment) {
continue;
}
if (ref.getEReferenceType() == type) {
return ref; // perfect match
}
if (ref.getEReferenceType().isSuperTypeOf(type)) {
bestRef = ref;
}
}
return bestRef;
}
protected FigureViewmap createViewmap(String shape, GenCommonBase genElement) {
FigureViewmap viewmap = GMFGenFactory.eINSTANCE.createFigureViewmap();
viewmap.setFigureQualifiedClassName(shape == null ? getDefaultShape(genElement) : shape);
return viewmap;
}
protected String getDefaultShape(GenCommonBase genElement) {
if (genElement instanceof GenDiagram) {
return "org.eclipse.draw2d.FreeformLayer"; //$NON-NLS-1$
} else if (genElement instanceof GenChildLabelNode || genElement instanceof GenLabel) {
return "org.eclipse.gmf.runtime.draw2d.ui.figures.WrappingLabel"; //$NON-NLS-1$
} else if (genElement instanceof GenNode || genElement instanceof GenCompartment) {
return "org.eclipse.draw2d.RectangleFigure"; //$NON-NLS-1$
} else if (genElement instanceof GenLink) {
return "org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx"; //$NON-NLS-1$
}
return "org.eclipse.draw2d.Figure"; //$NON-NLS-1$
}
}