/* * 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$ } }