blob: bb231965bc11606b34471d525a26d9b62f02e1b3 [file] [log] [blame]
[%
// If the root EPackage has a @constraints(file="foo.evl")
// annotation, parse the constraints into an EVL module
var module = getValidationModule();
// Compute the set of classes to be shown in this diagram
var main = getMainClass();
var classes = getVisibleClasses();
var subgraphs : Sequence;
var unclusteredClasses : Sequence;
unclusteredClasses.addAll(classes);
var visibleReferences = getVisibleReferences();
if (clusters.isDefined()) {
for (cluster in clusters) {
var clusterClasses = unclusteredClasses.select(c|cluster.contains(c.name));
unclusteredClasses.removeAll(clusterClasses);
subgraphs.add(clusterClasses);
}
}
subgraphs.add(unclusteredClasses);
%]
digraph G {
graph[splines=ortho, nodesep=0.6[%if (K.isDefined()){%],K=[%=K%][%}%]]
node[fontname=Tahoma, fontsize=10, shape=record]
edge[fontname=Tahoma, fontsize=10, arrowsize=0.7]
[%for (subgraph in subgraphs){%]
[*If tehre's only one subgraph, we don't need subgraphs*]
[%if (subgraphs.size() > 1){%]
subgraph cluster_[%=loopCount%] {
style=invis;
[%}%]
[% var message = validate(); if (message.isDefined()){%]
__ValidationMessage[label="[%=message.toMultiline()%]", style=filled, fillcolor="mistyrose"];
[%}%]
[%for (c in subgraph) { %]
[** Create a node for the class **]
[%=c.getNodeName()%][shape=none, margin=0, label = <[%=c.getLabel()%]>]
[%if ((main.isDefined() and c == main) or main.isUndefined()){%]
[** Create nodes for all the constraints of the class*]
[%if (constraintsVisible() and module.constraintContexts.exists(ctx|ctx.typeName=c.name)){%]
[%=c.getNodeName()%]_Constraints[shape=none, margin=0, label=<[%=c.getConstraintsLabel()%]>]
[%=c.getNodeName()%]_Constraints->[%=c.getNodeName()%][arrowhead=none, style=dashed, name="[%=c.getNodeName()%]_Constraints"]
{rank=same;[%=c.getNodeName()%]_Constraints;[%=c.getNodeName()%]}
[%}%]
[** Create node for all the documentation annotations of the class*]
[%if (isLayerActive("documentation")){%]
[%var documentation = c.getAnnotationValue("http://www.eclipse.org/emf/2002/GenModel", "documentation");%]
[%if (documentation.isDefined()){%]
[%=c.getNodeName()%]_Documentation[shape="note", label="[%=documentation.toMultiline()%]", style="filled", fillcolor="azure"]
[%=c.getNodeName()%]_Documentation->[%=c.getNodeName()%][arrowhead=none, style=dashed, name="[%=c.getNodeName()%]_Documentation"];
[%}%]
[%}%]
[%}%]
[%if (rerank.isUndefined() or rerank == "true"){%]
[%for (other in subgraph.select(other|c.hasSameRank(other))){%]
[%if (isLayerActive("referenceLabels")){%]
[%for (r in getUnidirectionalReferences().includingAll(getBidirectionalReferences()).select(r|r.eContainer = c and r.eType = other)){%]
{rank=same;[%=c.getNodeName()%];[%=other.getNodeName()%];[%=r.getNodeName()%]}
[%}%]
[%}else{%]
{rank=same;[%=c.getNodeName()%];[%=other.getNodeName()%]}
[%}%]
[%}%]
[%}%]
[%if (isLayerActive("referenceLabels")){%]
[%for (r in getBidirectionalReferences().select(r|r.eContainer = c)){%]
[%=r.getNodeName()%][label="[%=r.getEdgeLabel()%]/\n[%=r.eOpposite.getEdgeLabel()%]", shape=plaintext, margin=0,width=0,height=0]
[%}%]
[%for (r in getUnidirectionalReferences().select(r|r.eContainer = c)){%]
[%=r.getNodeName()%][label="[%=r.getEdgeLabel()%]", shape=plaintext, margin=0,width=0,height=0]
[%}%]
[%}%]
[%}%]
[*If tehre's only one subgraph, we don't need subgraphs*]
[%if (subgraphs.size() > 1){%]
}
[%}%]
[%}%]
[%for (c in classes) { %]
[%if ((main.isDefined() and c == main) or main.isUndefined()){%]
[** Create edges for the supertypes of the class **]
[%if (isLayerActive("supertypes")){%]
[%for (s in c.eSuperTypes.select(s|classes.includes(s))){%]
[%if (isInheritanceVisible(c, s)){%][%=s.getNodeName()%]->[%=c.getNodeName()%][name="[%=s.getNodeName()%]-isSuperTypeOf-[%=c.getNodeName()%]", arrowtail="empty", dir="back", arrowsize=0.9][%}%]
[%}%]
[%}%]
[** ... and for its subtypes **]
[%if (isLayerActive("subtypes") and main.isDefined()){%]
[%for (s in classes.select(cl|cl.eSuperTypes.includes(c))){%]
[%if (isInheritanceVisible(s, c)){%][%=c.getNodeName()%]->[%=s.getNodeName()%][name="[%=c.getNodeName()%]-isSuperTypeOf-[%=s.getNodeName()%]", arrowtail="empty", dir="back", arrowsize=0.9][%}%]
[%}%]
[%}%]
[%}%]
[%}%]
[* ... and for its references *]
[%if (isLayerActive("referenceLabels")){%] [* ... if reference labels layers is active*]
[%for (r in getUnidirectionalReferences()) {%]
[%var c = r.eContainer;%]
[%if (r.containment){%]
[%=c.getNodeName()%]->[%=r.getNodeName()%][arrowtail=[%=r.getArrowTail()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]_headFragment", dir=back];
[%=r.getNodeName()%]->[%=r.eType.getNodeName()%][name="[%=r.getIdentifier()%]_tailFragment"]
[%}else{%]
[%=c.getNodeName()%]->[%=r.getNodeName()%][arrowhead=none, name="[%=r.getIdentifier()%]_headFragment"]
[%=r.getNodeName()%]->[%=r.eType.getNodeName()%][arrowhead=[%=r.getArrowHead()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]_tailFragment"];
[%}%]
[%}%]
[%for (r in getBidirectionalReferences()) {%]
[%var c = r.eContainer;%]
[%=c.getNodeName()%]->[%=r.getNodeName()%][arrowhead=[%=r.getArrowTail()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]", dir=back];
[%=r.getNodeName()%]->[%=r.eType.getNodeName()%][arrowtail=[%=r.getArrowHead()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]"];
[%}%]
[%}else{%] [* ... if reference labels layers is inactive*]
[%for (r in getUnidirectionalReferences()) {%]
[%var c = r.eContainer;%]
[%if (r.containment){%]
[%=c.getNodeName()%]->[%=r.eType.getNodeName()%][arrowtail=[%=r.getArrowTail()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]", dir=back];
[%}else{%]
[%=c.getNodeName()%]->[%=r.eType.getNodeName()%][arrowhead=[%=r.getArrowHead()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]"];
[%}%]
[%}%]
[%for (r in getBidirectionalReferences()) {%]
[%var c = r.eContainer;%]
[%=c.getNodeName()%]->[%=r.eType.getNodeName()%][arrowtail=[%=r.getArrowHead()%],arrowhead=[%=r.getArrowTail()%],tooltip="[%=r.name%]",name="[%=r.getIdentifier()%]", dir=both];
[%}%]
[%}%]
}
[%
operation EReference getEdgeLabel() {
var label = "";
if (self.isDerived()) label = "/" + label;
label += self.name + self.getEdgeMultiplicityLabel();
return label;
}
operation EReference getEdgeMultiplicityLabel() {
if (self.isMany()) {
return self.getMultiplicityLabel();
}
else {
return "[" + self.lowerBound + ".." + self.upperBound + "]";
}
}
operation EStructuralFeature getMultiplicityLabel() {
var label = "";
if (self.isMany) {
label += "[";
if (self.lowerBound <> 0) label += self.lowerBound + "..";
if (self.upperBound == -1) {
label += "*";
}
else {
label += self.upperBound;
}
label += "]";
}
return label;
}
operation EClass getLabel() {
var fillcolor = "#fffcdc"; if (self==main) fillcolor="#c8f0a1";
var label = "<table cellspacing='0' cellborder='0' cellpadding='1' bgcolor='" + fillcolor + "'>";
var features = self.eStructuralFeatures;
if (isLayerActive("inherited")) {
features = self.eAllStructuralFeatures.select(sf|not self.eSuperTypes.exists(st|classes.contains(st) and st.eAllStructuralFeatures.includes(sf)));
}
if (not isLayerActive("derived")) features = features.reject(f|f.isDerived);
if (self.eSuperTypes.includes(main)) features = features.excludingAll(main.eAllStructuralFeatures);
var javascript = "javascript:top.showView(['Model', 'Classes', '" + self.name + "'])";
var tooltip = "Show class diagram for " + self.name;
if (self==main) {
javascript = "javascript:top.showElement('" + self.id + "','" + self.eResource.uri + "')";
tooltip = "Go to " + self.name + " in the Ecore editor";
}
label += "<tr><td sides='B' colspan='2' border='1'>" +
"<table border='0' cellspacing='0' cellborder='0' cellpading='0'>" +
"<tr><td align='right' valign='middle'><img src='" + self.getIcon()+ "'></img></td>" +
"<td align='left' valign='middle' href=\""+javascript+"\" tooltip='" + tooltip + "'>" + self.name + "</td></tr></table></td></tr>";
label += "<tr><td></td><td></td></tr>";
// Remove features that shouldn't be shown
if (not isLayerActive("features")) features = new Sequence;
else features = features.excludingAll(getHiddenFeatures());
if (not isLayerActive("inlineReferences")) features = features.select(f|f.isTypeOf(EAttribute));
for (f in features.sortBy(f|f.name.toLowerCase())) {
label += "<tr>";
label += "<td><img src='" + f.getIcon() + "'></img></td><td align='left'>" + f.getLabel() + "</td>";
label += "</tr>";
}
if (features.isEmpty()){
label += "<tr>";
label += "<td> </td><td> </td>";
label += "</tr>";
}
if (isLayerActive("operations")){
for (op in self.eOperations) {
var border = "";
if (loopCount == 1) border = "sides='T' border='1'";
label += "<tr>";
label += "<td " + border + "><img src='" + op.getIcon() + "'></img></td><td align='left' " + border + ">" + op.getLabel() + "</td>";
label += "</tr>";
}
if (self.eOperations.isEmpty()){
label += "<tr>";
label += "<td sides='T' border='1'> </td><td sides='T' border='1'> </td>";
label += "</tr>";
}
}
label += "</table>";
return label;
}
operation EClass getConstraintsLabel() {
var label = "<table border='1' cellspacing='0' cellborder='0' cellpadding='4'>";
for (constraint in
module.constraintContexts.select(ctx|ctx.typeName=self.name).
collect(ctx|ctx.constraints).flatten()) {
label+="<tr><td bgcolor='" + constraint.getConstraintColour() + "'>" + constraint.getConstraintLabel() + "</td></tr>";
}
label += "</table>";
return label;
}
operation EStructuralFeature getLabel() {
var label = self.name;
if (self.isDerived()) label = "/" + label;
if (self.eType.isDefined()) label += " : " + self.eType.name;
label += self.getMultiplicityLabel();
label += " ";
return label;
}
operation EOperation getLabel() {
var label = self.name + "(" + self.eParameters.collect(p|p.getLabel()).concat(", ") + ")";
if (self.eType.isDefined()) {
label += " : " + self.eType.name;
if (self.isMany) {
label += "["+"*"+"]";
}
}
return label;
}
operation EParameter getLabel() {
var label = self.name;
if (self.eType.isDefined()) {
label += " : " + self.eType.name;
if (self.isMany) {
label += "["+"*"+"]";
}
}
return label;
}
operation EReference getArrowHead() {
if (self.eOpposite.isDefined() and self.eOpposite.containment) {
return "diamond";
}
return "open";
}
operation EReference getArrowTail() {
if (self.containment) {
return "diamond";
}
else {
if (self.eOpposite.isDefined()) {
return "open";
}
else {
return "none";
}
}
}
operation EReference getIdentifier() {
return self.eContainingClass.name + "_" + self.name;
}
operation Any getConstraintLabel() {
var label = "";
if (isLayerActive("constraintNames")) label += self.name;
if (self.comments.notEmpty() and isLayerActive("constraintDescriptions")) {
if (isLayerActive("constraintNames")) label += ": ";
label += self.comments.first();
}
return "<table cellspacing='0' border='0' cellpadding='0'><tr><td align='left'>" +
label.toMultiline("</td></tr><tr><td align='left'>") +
"</td></tr></table>";
}
operation Any getConstraintColour() {
if (self.isCritique()) return "khaki1";
else return "mistyrose";
}
operation getVisibleClasses() {
var main = getMainClass();
if (main.isDefined()) {
var classes : OrderedSet;
classes.add(main);
if (isLayerActive("supertypes")) classes.addAll(main.eSuperTypes); // All its supertypes
if (isLayerActive("subtypes")) classes.addAll(EClass.all.select(o|o.eSuperTypes.includes(main))); // All its subtypes
classes.addAll(getVisibleReferences().eType);
return classes;
}
else {
return EClass.all.select(c|classNames.includes(c.name));
}
}
@cached
operation getMainClass() {
if (mainClassName.isDefined()) {
return EClass.all.selectOne(c|c.name = mainClassName);
}
}
@cached
operation getUnidirectionalReferences() {
var bidirectionalReferences = getBidirectionalReferences();
return getVisibleReferences().excludingAll(bidirectionalReferences).
excludingAll(bidirectionalReferences.eOpposite);
}
@cached
operation getBidirectionalReferences() {
var references = getVisibleReferences();
return references.select(r|r.eOpposite.isDefined() and references.indexOf(r) < references.indexOf(r.eOpposite));
}
@cached
operation getVisibleReferences() {
var visibleReferences : OrderedSet;
var main = getMainClass();
if (main.isDefined()){
visibleReferences.addAll(main.eReferences);
visibleReferences.addAll(main.eReferences.eOpposite);
visibleReferences.remove(null);
}
else {
visibleReferences.addAll(classes.eReferences.flatten().select(r|classes.includes(r.eType)));
}
if (not isLayerActive("referencesToSelf")) visibleReferences = visibleReferences.reject(r|r.eType = r.eContainer);
if (not isLayerActive("derived")) visibleReferences = visibleReferences.reject(r|r.isDerived);
// Remove explicitly hidden features
visibleReferences = visibleReferences.excludingAll(getHiddenFeatures());
return visibleReferences;
}
@cached
operation getHiddenFeatures() {
var hiddenFeatures : Sequence;
if (hide.isDefined()) {
for (item in hide) {
var parts = item.split("\\.");
if (parts.size() == 2) {
var eClass = EClass.all.selectOne(c|c.name = parts.at(0));
if (eClass.isDefined()) {
hiddenFeatures.addAll(eClass.eStructuralFeatures.select(sf|sf.isHidden(parts.at(0), parts.at(1))));
}
}
}
}
return hiddenFeatures;
}
operation EStructuralFeature isHidden(hiddenClass : String, hiddenFeature : String) {
return self.eContainer.name = hiddenClass and (hiddenFeature == "*" or hiddenFeature == self.name);
}
operation getValidationModule() {
var module = new Native("org.eclipse.epsilon.evl.EvlModule");
var constraints = EPackage.all.first().getAnnotationValue("constraints", "file");
if (not constraints.isDefined()) return module;
var constraintsUrl = new Native("java.net.URL")(new Native("java.net.URL")(M.resource.uri.toString()), constraints);
module.parse(constraintsUrl.toURI());
return module;
}
operation EModelElement getAnnotationValue(name : String, detail : String) : Any {
var ann = self.eAnnotations.selectOne(a|a.source = name);
var det;
if (ann.isDefined()) {
det = ann.details.selectOne(d|d.key = detail);
}
if (det.isDefined()) {
return det.value;
}
return det;
}
operation String toMultiline() : String {
return self.toMultiline("\\l");
}
operation String toMultiline(newline : String) : String {
var multiline = "";
for (line in self.split("\\n")) {
var length = 0;
for (part in line.split(" ")) {
multiline += part + " ";
if (length > 30) {
multiline += newline;
length = 0;
}
else {
length += part.length();
}
}
if (not multiline.endsWith(newline)) multiline += newline;
if (hasMore) multiline += "\\n";
}
if (not multiline.endsWith(newline)) multiline += newline;
multiline = multiline.replaceAll('"', '\\\\"');
return multiline;
}
operation EClass getNodeName() {
return "_" + self.name;
}
operation EReference getNodeName() {
return "_" + self.eContainer.name + "_" + self.name;
}
operation isLayerActive(id : String) {
var layer = layers.selectOne(l|l.id = id);
if (layer.isDefined()) {
return layer.active;
}
else {
return true;
}
}
operation Any getIcon() {
return getImage("icons/" + self.eClass.name + ".gif");
}
operation constraintsVisible() {
return isLayerActive("constraintNames") or isLayerActive("constraintDescriptions");
}
operation EClassifier inSameSubgraph(other : EClass) {
return subgraphs.exists(s|s.includes(self) and s.includes(other));
}
operation EClassifier hasSameRank(other : EClass) {
var ref = self.eReferences.reject(r|getVisibleReferences().excludes(r)).selectOne(r|(not r.containment) and r.eType=other);
return ref.isDefined();
}
operation isInheritanceVisible(sub : EClass, super : EClass) {
if (hide.isDefined()) {
for (item in hide) {
var parts = item.split("-");
if (parts.size() == 2) {
if (sub.name == parts.at(0) and super.name == parts.at(1)) return false;
}
}
}
return true;
}
operation validate() {
var message = "";
var missingClasses = classNames.excludingAll(EClass.all.name);
if (missingClasses.notEmpty()) {
if (missingClasses.size() == 1) message = "Referenced class " + missingClasses.concat(", ") + " does not exist. ";
else message = "Referenced classes " + missingClasses.concat(", ") + " do not exist. ";
}
if (clusters.isDefined()) {
var missingClasses = clusters.flatten().asSet().excludingAll(getVisibleClasses().name);
if (missingClasses.notEmpty()) {
if (missingClasses.size() == 1) message += "Class " + missingClasses.concat(", ") + " is not in the view.";
else message += "Classes " + missingClasses.concat(", ") + " are not in the view.";
}
}
return message;
}
%]