package fr.inria.atlanmod.collaboro.ui.views.notation.builder;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.util.DOMUtilities;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;
import fr.inria.atlanmod.collaboro.history.AbstractSyntaxElement;
import fr.inria.atlanmod.collaboro.history.ConcreteSyntaxElement;
import fr.inria.atlanmod.collaboro.history.ExistingAbstractSyntaxElement;
import fr.inria.atlanmod.collaboro.history.History;
import fr.inria.atlanmod.collaboro.history.HistoryPackage;
import fr.inria.atlanmod.collaboro.history.ModelChange;
import fr.inria.atlanmod.collaboro.history.NewAbstractSyntaxElement;
import fr.inria.atlanmod.collaboro.history.Proposal;
import fr.inria.atlanmod.collaboro.history.Solution;
import fr.inria.atlanmod.collaboro.notation.AttributeValue;
import fr.inria.atlanmod.collaboro.notation.Composite;
import fr.inria.atlanmod.collaboro.notation.Definition;
import fr.inria.atlanmod.collaboro.notation.Keyword;
import fr.inria.atlanmod.collaboro.notation.NotationElement;
import fr.inria.atlanmod.collaboro.notation.NotationPackage;
import fr.inria.atlanmod.collaboro.notation.ReferenceValue;
import fr.inria.atlanmod.collaboro.notation.SyntaxOf;
import fr.inria.atlanmod.collaboro.notation.TextualElement;
import fr.inria.atlanmod.collaboro.notation.Token;
import fr.inria.atlanmod.collaboro.ui.Controller;
public class SVGBuilder {
// Default starting coordinates, fonts and so on
private static int START_X = 10;
private static int START_Y = 20;
private static int VERTICAL_SEP = 23;
private static int TAB = 20;
private static int CHAR_SEP = 8;
private static String DEFAULT_FONT_SIZE = "12px";
private static String DEFAULT_FONT_FAMILY = "monospace";
/**
* Inner class to represent shown boxes.
*
* @author Javier Canovas (javier.canovas@inria.fr)
*
*/
private class Box {
private int width, height;
private int x, y;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Box(int width, int height, int x, int y) {
super();
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
}
/**
* Builds the SVG for the corresponding notationElement. The representation is for
* the abstract syntax element.
*
* @param notationElement
* @return
*/
public SVGDocument buildSVG(NotationElement notationElement) {
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null);
buildSVG(notationElement, doc, START_X, START_Y);
return doc;
}
/**
* Builds the SVG for the corresponding notationElement and particularizes the
* representation with the model element instance.
*
* @param instanceModelElement
* @param notationElement
* @return
*/
public SVGDocument buildSVG(EObject instanceModelElement, NotationElement notationElement) {
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null);
buildSVG(instanceModelElement, notationElement, doc, START_X, START_Y);
return doc;
}
/**
* Builds the SVG for the corresponding notationElement. The representation is for
* the abstract syntax element.
*
* @param notationElement
* @param doc
* @param x
* @param y
*/
private Box buildSVG(NotationElement notationElement, SVGDocument doc, int x, int y) {
Element svgRoot = doc.getDocumentElement();
Box result = new Box(0, 0, x, y);
if (notationElement instanceof Composite) {
Composite composite = (Composite) notationElement;
result.setX(x);
int oldX = x;
for(NotationElement subElement : composite.getSubElements()) {
if (subElement instanceof Composite) {
x = oldX + TAB;
y = y + VERTICAL_SEP;
}
Box subBox = buildSVG(subElement, doc, x, y);
if ((subElement instanceof Composite) || (subElement instanceof SyntaxOf)) {
x = oldX;
y = y + subBox.getHeight();
if(result.getWidth() < subBox.getWidth()) result.setWidth(subBox.getWidth());
result.setHeight(result.getHeight() + subBox.getHeight());
} else {
x = x + subBox.getWidth();
result.setWidth(result.getWidth() + subBox.getWidth());
if(result.getHeight() < subBox.getHeight()) result.setHeight(subBox.getHeight());
}
}
} else if (notationElement instanceof TextualElement) {
TextualElement textualElement = (TextualElement) notationElement;
Element text = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "text");
text.setAttributeNS(null, "x", String.valueOf(x));
text.setAttributeNS(null, "y", String.valueOf(y));
text.setAttributeNS(null, "font-size", DEFAULT_FONT_SIZE);
text.setAttributeNS(null, "font-family", DEFAULT_FONT_FAMILY);
String value = "";
if (textualElement instanceof Keyword) {
Keyword keyword = (Keyword) notationElement;
text.setAttributeNS(null, "font-weight", "bold");
text.setAttributeNS(null, "fill", "green");
text.setAttributeNS(null, "stroke", "none");
value = keyword.getId();
} else if (textualElement instanceof Token) {
Token token = (Token) notationElement;
text.setAttributeNS(null, "fill", "black");
text.setAttributeNS(null, "stroke", "none");
value = token.getId();
} else if (textualElement instanceof AttributeValue) {
AttributeValue attributeValue = (AttributeValue) notationElement;
text.setAttributeNS(null, "fill", "orange");
value = "<value of '" + attributeValue.getAttribute().getName() + "' attribute>";
} else if (textualElement instanceof ReferenceValue) {
ReferenceValue referenceValue = (ReferenceValue) notationElement;
text.setAttributeNS(null, "fill", "orange");
value = "<value of '" + referenceValue.getReference().getName() + "' reference>";
}
result.setWidth(value.length() * CHAR_SEP + CHAR_SEP);
result.setHeight(VERTICAL_SEP);
text.setTextContent(value);
svgRoot.appendChild(text);
} else if (notationElement instanceof SyntaxOf) {
SyntaxOf syntaxOf = (SyntaxOf) notationElement;
Element text = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "text");
text.setAttributeNS(null, "x", String.valueOf(x));
text.setAttributeNS(null, "y", String.valueOf(y));
text.setAttributeNS(null, "font-size", DEFAULT_FONT_SIZE);
text.setAttributeNS(null, "font-family", DEFAULT_FONT_FAMILY);
text.setAttributeNS(null, "fill", "blue");
String value = "<syntax of '" + syntaxOf.getReference().getName() + "' reference>";
text.setTextContent(value);
result.setWidth(value.length() * CHAR_SEP + CHAR_SEP);
result.setHeight(VERTICAL_SEP);
svgRoot.appendChild(text);
}
return result;
}
/**
* Builds the SVG for the corresponding notationElement and particularizes the
* representation with the model element instance.
*
* @param eObject
* @param notationElement
* @param doc
* @param x
* @param y
* @return
*/
public Box buildSVG(EObject eObject, NotationElement notationElement, SVGDocument doc, int x, int y) {
Element svgRoot = doc.getDocumentElement();
Box result = new Box(0, 0, x, y);
if (notationElement instanceof Composite) {
Composite composite = (Composite) notationElement;
result.setX(x);
int oldX = x;
for(NotationElement subElement : composite.getSubElements()) {
if (subElement instanceof Composite) {
x = oldX + TAB;
y = y + VERTICAL_SEP;
}
Box subBox = buildSVG(eObject, subElement, doc, x, y);
if ((subElement instanceof Composite) || (subElement instanceof SyntaxOf)) {
x = oldX;
y = y + subBox.getHeight();
if(result.getWidth() < subBox.getWidth()) result.setWidth(subBox.getWidth());
result.setHeight(result.getHeight() + subBox.getHeight());
} else {
x = x + subBox.getWidth();
result.setWidth(result.getWidth() + subBox.getWidth());
if(result.getHeight() < subBox.getHeight()) result.setHeight(subBox.getHeight());
}
}
} else if (notationElement instanceof TextualElement) {
TextualElement textualElement = (TextualElement) notationElement;
Element text = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "text");
text.setAttributeNS(null, "x", String.valueOf(x));
text.setAttributeNS(null, "y", String.valueOf(y));
text.setAttributeNS(null, "font-size", DEFAULT_FONT_SIZE);
text.setAttributeNS(null, "font-family", DEFAULT_FONT_FAMILY);
String value = "";
if (textualElement instanceof Keyword) {
Keyword keyword = (Keyword) notationElement;
text.setAttributeNS(null, "font-weight", "bold");
text.setAttributeNS(null, "fill", keyword.getFill().getLiteral());
text.setAttributeNS(null, "stroke", "none");
value = keyword.getId();
} else if (textualElement instanceof Token) {
Token token = (Token) notationElement;
text.setAttributeNS(null, "fill", token.getFill().getLiteral());
text.setAttributeNS(null, "stroke", "none");
value = token.getId();
} else if (textualElement instanceof AttributeValue) {
AttributeValue attributeValue = (AttributeValue) notationElement;
text.setAttributeNS(null, "fill", attributeValue.getFill().getLiteral());
EAttribute eAttribute = attributeValue.getAttribute();
value = convert(eObject.eGet(eObject.eClass().getEStructuralFeature(eAttribute.getName())));
// value = convert(eObject.eGet(eAttribute));
} else if (textualElement instanceof ReferenceValue) {
ReferenceValue referenceValue = (ReferenceValue) notationElement;
text.setAttributeNS(null, "fill", referenceValue.getFill().getLiteral());
EReference eReference = referenceValue.getReference();
EAttribute eAttribute = referenceValue.getAttribute();
String separator = referenceValue.getSeparator();
Object referredObjs = eObject.eGet(eObject.eClass().getEStructuralFeature(eReference.getName()));
// Object referredObjs = eObject.eGet(eReference);
if (referredObjs instanceof EList) {
EList<EObject> eReferenceList = (EList<EObject>) referredObjs;
for(EObject elementList : eReferenceList) {
// Object attributeValue = elementList.eGet(eAttribute);
Object attributeValue = elementList.eGet(elementList.eClass().getEStructuralFeature(eAttribute.getName()));
value += convert(attributeValue);
if(eReferenceList.indexOf(elementList) != eReferenceList.size() - 1) {
value += separator;
}
}
} else if (referredObjs instanceof EObject) {
EObject elementList = (EObject) referredObjs;
// Object attributeValue = elementList.eGet(eAttribute);
Object attributeValue = elementList.eGet(elementList.eClass().getEStructuralFeature(eAttribute.getName()));
value += convert(attributeValue);
}
}
result.setWidth(value.length() * CHAR_SEP + CHAR_SEP);
result.setHeight(VERTICAL_SEP);
text.setTextContent(value);
svgRoot.appendChild(text);
} else if (notationElement instanceof SyntaxOf) {
SyntaxOf syntaxOf = (SyntaxOf) notationElement;
EReference eReference = syntaxOf.getReference();
Object referredObjs = eObject.eGet(eObject.eClass().getEStructuralFeature(eReference.getName()));
// Object referredObjs = eObject.eGet(eReference);
if (referredObjs instanceof EList) {
EList<EObject> eReferenceList = (EList<EObject>) referredObjs;
if(eReferenceList.size() > 0) {
int oldX = x;
for(EObject elementList : eReferenceList) {
NotationElement subNotationElement = Controller.INSTANCE.getNotation(elementList.eClass());
if(subNotationElement != null) {
Box subBox = buildSVG(elementList, subNotationElement, doc, x, y);
x = oldX;
y = y + subBox.getHeight();
if(result.getWidth() < subBox.getWidth()) result.setWidth(subBox.getWidth());
result.setHeight(result.getHeight() + subBox.getHeight());
}
}
}
}
}
return result;
}
/**
* Obtains the string representation of the value
*
* @param value
* @return
*/
protected String convert(Object value) {
String result = "ND";
if (value instanceof String) {
result = (String) value;
} else if (value instanceof EEnumLiteral) {
EEnumLiteral literal = (EEnumLiteral) value;
result = literal.toString();
}
return result;
}
private void serialize(SVGDocument image, String location) {
try {
String replaceFirst = location.substring(6);
FileWriter fileWriter = new FileWriter(replaceFirst);
DOMUtilities.writeDocument(image, fileWriter);
fileWriter.close();
ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (IOException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
}
/**
* Looks for a ConcreteSyntaxElement linked with the Eclassifier received
*
* @param modelElement
* @return
*/
public NotationElement getNotation(History history, int historyTracked, int versionTracked, EClassifier modelElement) {
List<Proposal> proposals = history.getHistories().get(historyTracked).getVersions().get(versionTracked).getProposals();
for(Proposal proposal : proposals) {
List<Solution> solutions = proposal.getSols();
for(Solution solution : solutions) {
List<ModelChange> changes = solution.getChanges();
for(ModelChange change : changes) {
if(change.getReferredElement() instanceof AbstractSyntaxElement && change.getTarget() instanceof ConcreteSyntaxElement) {
EModelElement refModelElement = null;
if (change.getReferredElement() instanceof ExistingAbstractSyntaxElement) {
refModelElement = ((ExistingAbstractSyntaxElement) change.getReferredElement()).getElement();
}
if (change.getReferredElement() instanceof NewAbstractSyntaxElement) {
refModelElement = ((NewAbstractSyntaxElement) change.getReferredElement()).getElement();
}
if(refModelElement != null) {
if (refModelElement instanceof EClassifier) {
EClassifier classifier = (EClassifier) refModelElement;
if(classifier.getName().equals(modelElement.getName())) {
ConcreteSyntaxElement concreteElement = (ConcreteSyntaxElement) change.getTarget();
NotationElement result = concreteElement.getElement();
return result;
}
}
}
}
}
}
}
return null;
}
public static void main(String[] args) {
SVGBuilder builder = new SVGBuilder();
File ecoreModelFile = new File("C:\\Users\\useradm\\git\\collaboro\\examples\\fr.inria.atlanmod.collaboro.examples.workflow\\model\\ModiscoWorkflow.ecore");
File notationModelFile = new File("C:\\Users\\useradm\\git\\collaboro\\examples\\fr.inria.atlanmod.collaboro.examples.workflow\\model\\ModiscoWorkflow.notation");
File historyModelFile = new File("C:\\Users\\useradm\\git\\collaboro\\examples\\fr.inria.atlanmod.collaboro.examples.workflow\\model\\ModiscoWorkflow.history");
File modelExample = new File("C:\\Users\\useradm\\git\\collaboro\\examples\\fr.inria.atlanmod.collaboro.examples.workflow\\examples\\example1.xmi");
// Preparing the resource
ResourceSet rset = null;
rset = new ResourceSetImpl();
rset.getPackageRegistry().put(HistoryPackage.eNS_URI, HistoryPackage.eINSTANCE);
rset.getPackageRegistry().put(NotationPackage.eNS_URI, NotationPackage.eINSTANCE);
rset.getPackageRegistry().put(EcorePackage.eNS_URI, EcorePackage.eINSTANCE);
rset.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new EcoreResourceFactoryImpl());
rset.getResourceFactoryRegistry().getExtensionToFactoryMap().put("history", new EcoreResourceFactoryImpl());
rset.getResourceFactoryRegistry().getExtensionToFactoryMap().put("notation", new EcoreResourceFactoryImpl());
rset.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
// Loading the history model
Resource res1 = rset.getResource(URI.createFileURI(historyModelFile.getAbsolutePath()), true);
try {
res1.load(null);
} catch (IOException e) {
e.printStackTrace();
}
History historyModel = (History) res1.getContents().get(0);
// Loading the ecore model (abstract syntax)
Resource res2 = rset.getResource(URI.createFileURI(ecoreModelFile.getAbsolutePath()), true);
try {
res2.load(null);
} catch (IOException e) {
e.printStackTrace();
}
EPackage ecoreModel = (EPackage) res2.getContents().get(0);
// Loading the notation model (concrete syntax)
Resource res3 = rset.getResource(URI.createFileURI(notationModelFile.getAbsolutePath()), true);
try {
res3.load(null);
} catch (IOException e) {
e.printStackTrace();
}
Definition notationModel = (Definition) res3.getContents().get(0);
// Loading model
Resource res4 = rset.getResource(URI.createFileURI(modelExample.getAbsolutePath()), true);
try {
res4.load(null);
} catch (IOException e) {
e.printStackTrace();
}
EObject instanceModelElement = res4.getContents().get(0);
EClassifier modelElement = instanceModelElement.eClass();
NotationElement notationElement = builder.getNotation(historyModel, 0, 0, modelElement);
SVGDocument document = builder.buildSVG(instanceModelElement, notationElement);
builder.serialize(document, "test.svg");
}
}