Skip to content
This repository has been archived by the owner on Jul 22, 2020. It is now read-only.

Commit

Permalink
Add support for changing the label of references
Browse files Browse the repository at this point in the history
These changes make it possible to rename references and to change the multiplicity.

Resolves: #72
Signed-off-by: leodennis <[email protected]>

Added support for literal editing

Added subclasses of SLabelNode for attributes and literals.
Changed EcoreLabelOperationHandler to support server side editing.
Resolves:#61
Signed-off-by: leodennis <[email protected]>

Fix two Typos in the Create New Ecore Command.

Change of structure

Signed-off-by: leodennis <[email protected]>
  • Loading branch information
leodennis authored and eneufeld committed Jan 9, 2020
1 parent 50d00db commit 6896767
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 56 deletions.
3 changes: 2 additions & 1 deletion client/sprotty-ecore/src/di.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export default (containerId: string) => {
configureModelElement(context, 'node:enum', LabeledNode, ClassNodeView);
configureModelElement(context, 'node:datatype', LabeledNode, ClassNodeView);
configureModelElement(context, 'label:name', SEditableLabel, SLabelView);
configureModelElement(context, 'label:edge', SLabel, SLabelView);
configureModelElement(context, 'label:edge-name', SEditableLabel, SLabelView);
configureModelElement(context, 'label:edge-multiplicity', SEditableLabel, SLabelView);
configureModelElement(context, 'node:attribute', SLabelNodeAttribute, LabelNodeView);
configureModelElement(context, 'node:enumliteral', SLabelNodeLiteral, LabelNodeView);
configureModelElement(context, 'node:operation', SNode, RectangularNodeView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public Map<String, EClass> getTypeMappings() {

mappings.put(Types.LABEL_NAME, GraphPackage.Literals.GLABEL);
mappings.put(Types.LABEL_TEXT, GraphPackage.Literals.GLABEL);
mappings.put(Types.LABEL_EDGE, GraphPackage.Literals.GLABEL);
mappings.put(Types.LABEL_EDGE_NAME, GraphPackage.Literals.GLABEL);
mappings.put(Types.LABEL_EDGE_MULTIPLICITY, GraphPackage.Literals.GLABEL);
mappings.put(Types.COMP, GraphPackage.Literals.GCOMPARTMENT);
mappings.put(Types.COMP_HEADER, GraphPackage.Literals.GCOMPARTMENT);
mappings.put(Types.LABEL_ICON, GraphPackage.Literals.GCOMPARTMENT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,10 @@ private List<GModelElement> createEdges(EClass eClass) {
}

public GEdge create(EReference eReference) {
String label = String.format("[%s..%s] %s", eReference.getLowerBound(),
eReference.getUpperBound() == -1 ? "*" : eReference.getUpperBound(), eReference.getName());
String labelMultiplicity = String.format("[%s..%s]", eReference.getLowerBound(),
eReference.getUpperBound() == -1 ? "*" : eReference.getUpperBound());
String labelName = eReference.getName();

String source = toId(eReference.getEContainingClass());

String target = toId(eReference.getEReferenceType());
Expand All @@ -113,15 +115,24 @@ public GEdge create(EReference eReference) {
.id(id) //
.addCssClass(CSS.ECORE_EDGE) //
.addCssClass(eReference.isContainment() ? CSS.COMPOSITION : null) //
.add(new GLabelBuilder(Types.LABEL_EDGE) //
.add(new GLabelBuilder(Types.LABEL_EDGE_MULTIPLICITY) //
.edgePlacement(new GEdgePlacementBuilder()//
.side(GConstants.EdgeSide.TOP)//
.side(GConstants.EdgeSide.BOTTOM)//
.position(0.5d)//
.offset(0) //
.offset(2d) //
.rotate(false) //
.build())//
.id(id + "_label") //
.text(label).build())
.id(id + "_label_multiplicity") //
.text(labelMultiplicity).build())
.add(new GLabelBuilder(Types.LABEL_EDGE_NAME) //
.edgePlacement(new GEdgePlacementBuilder()//
.side(GConstants.EdgeSide.TOP)//
.position(0.5d)//
.offset(2d) //
.rotate(false) //
.build())//
.id(id + "_label_name") //
.text(labelName).build())
.sourceId(source) //
.targetId(target) //
.routerKind(GConstants.RouterKind.MANHATTAN)//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.TreeIterator;
Expand All @@ -28,19 +30,24 @@
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcorePackage;

import com.eclipsesource.glsp.api.action.Action;
import com.eclipsesource.glsp.api.action.kind.AbstractOperationAction;
import com.eclipsesource.glsp.api.action.kind.ApplyLabelEditOperationAction;
import com.eclipsesource.glsp.api.handler.OperationHandler;
import com.eclipsesource.glsp.api.jsonrpc.GLSPServerException;
import com.eclipsesource.glsp.api.model.GraphicalModelState;
import com.eclipsesource.glsp.ecore.EcoreFacade;
import com.eclipsesource.glsp.ecore.EcoreModelIndex;
import com.eclipsesource.glsp.ecore.ResourceManager;
import com.eclipsesource.glsp.ecore.enotation.Shape;
import com.eclipsesource.glsp.ecore.model.EcoreModelState;
import com.eclipsesource.glsp.graph.GEdge;
import com.eclipsesource.glsp.graph.GModelElement;
import com.eclipsesource.glsp.graph.GNode;
import com.eclipsesource.glsp.ecore.util.EcoreConfig.Types;

public class EcoreLabelEditOperationHandler implements OperationHandler {

Expand All @@ -55,52 +62,83 @@ public void execute(AbstractOperationAction action, GraphicalModelState graphica
EcoreFacade facade = EcoreModelState.getEcoreFacade(graphicalModelState);
EcoreModelIndex index = EcoreModelState.getModelState(graphicalModelState).getIndex();

// If we edit a Label Node (e.g. EAttribute, EEnumLiteral...), eObject will be
// defined.
// Otherwise, we're editing a Label that isn't a separate semantic element (e.g.
// Classifier Name Label),
// and we'll need to retrieve the top-level semantic element
EObject eObject = index.getSemantic(editLabelAction.getLabelId()).orElse(null);
if (eObject != null) { // Label Node (List Item)
if (eObject instanceof EAttribute) {
String inputText = editLabelAction.getText();
String attributeName;
if (inputText.contains(":")) {
String[] split = inputText.split(":");
attributeName = split[0].trim();

Optional<EClassifier> type = parseStringToEType(split[1].trim(),
EcoreModelState.getResourceManager(graphicalModelState));
if (type.isPresent()) {
((EAttribute) eObject).setEType(type.get());
Optional<String> type = index.findElementByClass(editLabelAction.getLabelId(), GModelElement.class).map(e -> e.getType());
if (type.isPresent()) {
switch (type.get()) {
case Types.LABEL_NAME:
GNode node = getOrThrow(index.findElementByClass(editLabelAction.getLabelId(), GNode.class),
"No parent Node for element with id " + editLabelAction.getLabelId() + " found");

EObject node_semantic = getOrThrow(index.getSemantic(node),
"No semantic element for labelContainer with id " + node.getId() + " found");

Shape shape = getOrThrow(index.getNotation(node_semantic), Shape.class,
"No shape element for label with id " + editLabelAction.getLabelId() + " found");

if (node_semantic instanceof EClassifier) {
((EClassifier) node_semantic).setName(editLabelAction.getText().trim());
// nameChange== uri change so we have to recreate the proxy here
shape.setSemanticElement(facade.createProxy(node_semantic));
}
break;

case Types.ATTRIBUTE:
EAttribute attribute_semantic = (EAttribute) getOrThrow(index.getSemantic(editLabelAction.getLabelId()),
"No semantic element for label with id " + editLabelAction.getLabelId() + " found");

String inputText = editLabelAction.getText();
String attributeName;
if (inputText.contains(":")) {
String[] split = inputText.split(":");
attributeName = split[0].trim();

Optional<EClassifier> datatype = parseStringToEType(split[1].trim(),
EcoreModelState.getResourceManager(graphicalModelState));
if (datatype.isPresent()) {
attribute_semantic.setEType(datatype.get());
}
} else {
attributeName = inputText.trim();
}
} else {
attributeName = inputText.trim();
}
if (!attributeName.isEmpty()) {
((EAttribute) eObject).setName(attributeName);
}
} else if (eObject instanceof EEnumLiteral) {
String inputText = editLabelAction.getText().trim();

if (!inputText.isEmpty()) {
((EEnumLiteral) eObject).setName(inputText);
}
}
} else { // Main Label of a Node
GNode node = getOrThrow(index.findElementByClass(editLabelAction.getLabelId(), GNode.class),
"No label container for label with id " + editLabelAction.getLabelId() + " found");

eObject = getOrThrow(index.getSemantic(node),
"No semantic element for labelContainer with id " + node.getId() + " found");

Shape shape = getOrThrow(index.getNotation(eObject), Shape.class,
"No shape element for label with id " + editLabelAction.getLabelId() + " found");
if (!inputText.isEmpty()) {
attribute_semantic.setName(attributeName);
}
break;

case Types.ENUMLITERAL:
EEnumLiteral literal_semantic = (EEnumLiteral) getOrThrow(index.getSemantic(editLabelAction.getLabelId()),
"No semantic element for label with id " + editLabelAction.getLabelId() + " found");
String text = editLabelAction.getText().trim();
if (!text.isEmpty()) {
literal_semantic.setName(text);
}
break;

case Types.LABEL_EDGE_NAME:
GEdge edge = getOrThrow(index.findElementByClass(editLabelAction.getLabelId(), GEdge.class),
"No edge for label with id " + editLabelAction.getLabelId() + " found");
EReference reference_semantic = (EReference) getOrThrow(index.getSemantic(edge),
"No semantic element for labelContainer with id " + edge.getId() + " found");
reference_semantic.setName(editLabelAction.getText().trim());
break;

case Types.LABEL_EDGE_MULTIPLICITY:
edge = getOrThrow(index.findElementByClass(editLabelAction.getLabelId(), GEdge.class),
"No edge for label with id " + editLabelAction.getLabelId() + " found");
reference_semantic = (EReference) getOrThrow(index.getSemantic(edge),
"No semantic element for labelContainer with id " + edge.getId() + " found");
Pattern pattern = Pattern.compile("\\s*\\[\\s*(\\d+)\\s*\\.+\\s*(\\*|\\d+|\\-1)\\s*\\]\\s*");
Matcher matcher = pattern.matcher(editLabelAction.getText());
if (matcher.matches()) {
String lowerBound = matcher.group(1);
String upperBound = matcher.group(2);
reference_semantic.setLowerBound((lowerBound.equals("*")) ? -1 : Integer.valueOf(lowerBound));
reference_semantic.setUpperBound((upperBound.equals("*")) ? -1 : Integer.valueOf(upperBound));
} else {
throw new GLSPServerException("Multiplicity of reference with id " + editLabelAction.getLabelId() + " has a wrong input format", new IllegalArgumentException());
}
break;

if (eObject instanceof EClassifier) {
((EClassifier) eObject).setName(editLabelAction.getText().trim());
// nameChange== uri change so we have to recreate the proxy here
shape.setSemanticElement(facade.createProxy(eObject));
}
}
}
Expand Down Expand Up @@ -131,5 +169,4 @@ public static List<EClassifier> getAllEAttributeTypes(ResourceManager resManager
public String getLabel(AbstractOperationAction action) {
return "Apply label";
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public static final class Types {

public static final String LABEL_NAME = "label:name";
public static final String LABEL_TEXT = "label:text";
public static final String LABEL_EDGE = "label:edge";
public static final String LABEL_EDGE_NAME = "label:edge-name";
public static final String LABEL_EDGE_MULTIPLICITY = "label:edge-multiplicity";
public static final String COMP = "comp:comp";
public static final String COMP_HEADER = "comp:header";
public static final String ICON_CLASS = "icon:class";
Expand Down

0 comments on commit 6896767

Please sign in to comment.