diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index b8985b3af6..c7fcb49a57 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -77,6 +77,7 @@
- https://github.com/eclipse-sirius/sirius-components/issues/1026[#1026] [compatibility] Add support for `OperationAction`. The action are converted to regular tools available in the palette of the frontend
- https://github.com/eclipse-sirius/sirius-components/issues/937[#937] [diagram] Add the ability to export diagram as SVG images
- https://github.com/eclipse-sirius/sirius-components/issues/779[#779] [diagram] Add support for tools preconditions
+- https://github.com/eclipse-sirius/sirius-components/issues/781[#781] [diagram] Add support for multiline labels
== v2022.01.0
diff --git a/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/export/svg/DiagramElementExportService.java b/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/export/svg/DiagramElementExportService.java
index 56532edaa3..43b9433f15 100644
--- a/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/export/svg/DiagramElementExportService.java
+++ b/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/export/svg/DiagramElementExportService.java
@@ -54,7 +54,7 @@ public StringBuilder exportLabel(Label label) {
labelExport.append(this.exportImageElement(style.getIconURL(), -20, -12, Optional.empty()));
}
- labelExport.append(this.exportTextElement(label.getText(), style));
+ labelExport.append(this.exportTextElement(label.getText(), label.getType(), style));
return labelExport.append(""); //$NON-NLS-1$
}
@@ -109,16 +109,32 @@ private StringBuilder addSizeParam(Size size) {
return sizeParam.append("height=\"" + size.getHeight() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
}
- private StringBuilder exportTextElement(String text, LabelStyle labelStyle) {
+ private StringBuilder exportTextElement(String text, String type, LabelStyle labelStyle) {
StringBuilder textExport = new StringBuilder();
textExport.append(""); //$NON-NLS-1$
- textExport.append(text);
+ String[] lines = text.split("\\n", -1); //$NON-NLS-1$
+ if (lines.length == 1) {
+ textExport.append(text);
+ } else {
+ textExport.append("" + lines[0] + ""); //$NON-NLS-1$//$NON-NLS-2$
+ double fontSize = labelStyle.getFontSize();
+ for (int i = 1; i < lines.length; i++) {
+ if (lines[i].isEmpty()) {
+ // avoid tspan to be ignored if there is only a line return
+ lines[i] = " "; //$NON-NLS-1$
+ }
+ textExport.append("" + lines[i] + ""); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
return textExport.append(""); //$NON-NLS-1$
}
diff --git a/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/handlers/EditTextfieldEventHandler.java b/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/handlers/EditTextfieldEventHandler.java
index 64461cef72..3985ceea50 100644
--- a/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/handlers/EditTextfieldEventHandler.java
+++ b/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/handlers/EditTextfieldEventHandler.java
@@ -13,6 +13,7 @@
package org.eclipse.sirius.components.collaborative.forms.handlers;
import java.util.Objects;
+import java.util.function.Function;
import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
@@ -26,6 +27,7 @@
import org.eclipse.sirius.components.core.api.ErrorPayload;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.forms.Form;
+import org.eclipse.sirius.components.forms.Textarea;
import org.eclipse.sirius.components.forms.Textfield;
import org.eclipse.sirius.components.representations.Failure;
import org.eclipse.sirius.components.representations.IStatus;
@@ -78,11 +80,16 @@ public void handle(One payloadSink, Many changeDesc
EditTextfieldInput input = (EditTextfieldInput) formInput;
// @formatter:off
- var optionalTextfield = this.formQueryService.findWidget(form, input.getTextfieldId())
- .filter(Textfield.class::isInstance)
- .map(Textfield.class::cast);
-
- IStatus status = optionalTextfield.map(Textfield::getNewValueHandler)
+ IStatus status = this.formQueryService.findWidget(form, input.getTextfieldId())
+ .map(widget -> {
+ Function handlerFunction = null;
+ if (widget instanceof Textfield) {
+ handlerFunction = ((Textfield) widget).getNewValueHandler();
+ } else if (widget instanceof Textarea) {
+ handlerFunction = ((Textarea) widget).getNewValueHandler();
+ }
+ return handlerFunction;
+ })
.map(handler -> handler.apply(input.getNewValue()))
.orElse(new Failure("")); //$NON-NLS-1$
// @formatter:on
diff --git a/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/ELKDiagramConverter.java b/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/ELKDiagramConverter.java
index b2da021861..ba6d6f8364 100644
--- a/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/ELKDiagramConverter.java
+++ b/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/ELKDiagramConverter.java
@@ -320,8 +320,8 @@ private void convertNode(Node node, ElkNode parent, Map childNodes = this.getLayoutedNodes(node.getChildNodes(), id2ElkGraphElements);
List borderNodes = this.getLayoutedNodes(node.getBorderNodes(), id2ElkGraphElements);
+ // @formatter:off
return Node.newNode(node)
.label(label)
.size(size)
diff --git a/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/IncrementalLayoutEngine.java b/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/IncrementalLayoutEngine.java
index 118b16842b..cb648135fa 100644
--- a/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/IncrementalLayoutEngine.java
+++ b/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/IncrementalLayoutEngine.java
@@ -152,11 +152,11 @@ private void layoutNode(Optional optionalDiagramElementEvent, Nod
// update the border node once the current node bounds are updated
Bounds newBounds = Bounds.newBounds().position(node.getPosition()).size(node.getSize()).build();
- this.layoutBorderNodes(optionalDiagramElementEvent, node.getBorderNodes(), initialNodeBounds, newBounds, layoutConfigurator);
+ List borderNodesOnSide = this.layoutBorderNodes(optionalDiagramElementEvent, node.getBorderNodes(), initialNodeBounds, newBounds, layoutConfigurator);
// recompute the label
if (node.getLabel() != null) {
- node.getLabel().setPosition(this.nodeLabelPositionProvider.getPosition(node, node.getLabel()));
+ node.getLabel().setPosition(this.nodeLabelPositionProvider.getPosition(node, node.getLabel(), borderNodesOnSide));
}
}
@@ -164,8 +164,9 @@ private void layoutNode(Optional optionalDiagramElementEvent, Nod
* Update the border nodes position according to the side length change where it is located.
* The aim is to keep the positioning ratio of the border node on its side.
*/
- private void layoutBorderNodes(Optional optionalDiagramElementEvent, List borderNodesLayoutData, Bounds initialNodeBounds, Bounds newNodeBounds,
+ private List layoutBorderNodes(Optional optionalDiagramElementEvent, List borderNodesLayoutData, Bounds initialNodeBounds, Bounds newNodeBounds,
ISiriusWebLayoutConfigurator layoutConfigurator) {
+ List borderNodesPerSide = new ArrayList<>();
if (!borderNodesLayoutData.isEmpty()) {
for (NodeLayoutData nodeLayoutData : borderNodesLayoutData) {
// 1- update the position of the border node if it has been explicitly moved
@@ -179,7 +180,7 @@ private void layoutBorderNodes(Optional optionalDiagramElementEve
}
// 2- recompute the border node
- List borderNodesPerSide = this.snapBorderNodes(borderNodesLayoutData, initialNodeBounds.getSize(), layoutConfigurator);
+ borderNodesPerSide = this.snapBorderNodes(borderNodesLayoutData, initialNodeBounds.getSize(), layoutConfigurator);
// 3 - move the border node along the side according to the side change
this.updateBorderNodeAccordingParentResize(optionalDiagramElementEvent, initialNodeBounds, newNodeBounds, borderNodesPerSide, borderNodesLayoutData.get(0).getParent().getId());
@@ -187,6 +188,7 @@ private void layoutBorderNodes(Optional optionalDiagramElementEve
// 4- set the label position if the border is newly created
this.updateBorderNodeLabel(optionalDiagramElementEvent, borderNodesPerSide);
}
+ return borderNodesPerSide;
}
private void updateBorderNodeLabel(Optional optionalDiagramElementEvent, List borderNodesPerSideList) {
diff --git a/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/provider/NodeLabelPositionProvider.java b/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/provider/NodeLabelPositionProvider.java
index 59d71555e9..719f7acd6b 100644
--- a/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/provider/NodeLabelPositionProvider.java
+++ b/backend/sirius-components-diagrams-layout/src/main/java/org/eclipse/sirius/components/diagrams/layout/incremental/provider/NodeLabelPositionProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2021 THALES GLOBAL SERVICES.
+ * Copyright (c) 2021, 2022 THALES GLOBAL SERVICES.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -13,6 +13,7 @@
package org.eclipse.sirius.components.diagrams.layout.incremental.provider;
import java.util.EnumSet;
+import java.util.List;
import java.util.Objects;
import org.eclipse.elk.core.math.ElkPadding;
@@ -21,8 +22,10 @@
import org.eclipse.sirius.components.diagrams.NodeType;
import org.eclipse.sirius.components.diagrams.Position;
import org.eclipse.sirius.components.diagrams.layout.ISiriusWebLayoutConfigurator;
+import org.eclipse.sirius.components.diagrams.layout.incremental.BorderNodesOnSide;
import org.eclipse.sirius.components.diagrams.layout.incremental.data.LabelLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.data.NodeLayoutData;
+import org.eclipse.sirius.components.diagrams.layout.incremental.utils.RectangleSide;
/**
* Provides the position to apply to a Node Label.
@@ -37,7 +40,7 @@ public NodeLabelPositionProvider(ISiriusWebLayoutConfigurator layoutConfigurator
this.layoutConfigurator = Objects.requireNonNull(layoutConfigurator);
}
- public Position getPosition(NodeLayoutData node, LabelLayoutData label) {
+ public Position getPosition(NodeLayoutData node, LabelLayoutData label, List borderNodesOnSide) {
double x = 0d;
double y = 0d;
@@ -49,7 +52,7 @@ public Position getPosition(NodeLayoutData node, LabelLayoutData label) {
}
break;
default:
- x = this.getHorizontalPosition(node, label);
+ x = this.getHorizontalPosition(node, label, borderNodesOnSide);
y = this.getVerticalPosition(node, label);
break;
}
@@ -57,7 +60,7 @@ public Position getPosition(NodeLayoutData node, LabelLayoutData label) {
return Position.at(x, y);
}
- private double getHorizontalPosition(NodeLayoutData node, LabelLayoutData label) {
+ private double getHorizontalPosition(NodeLayoutData node, LabelLayoutData label, List borderNodesOnSides) {
double x = 0d;
EnumSet nodeLabelPlacementSet = this.layoutConfigurator.configureByType(node.getNodeType()).getProperty(CoreOptions.NODE_LABELS_PLACEMENT);
ElkPadding nodeLabelsPadding = this.layoutConfigurator.configureByType(node.getNodeType()).getProperty(CoreOptions.NODE_LABELS_PADDING);
@@ -79,7 +82,21 @@ private double getHorizontalPosition(NodeLayoutData node, LabelLayoutData label)
}
break;
case H_CENTER:
- x = (node.getSize().getWidth() - label.getTextBounds().getSize().getWidth()) / 2;
+ // The label is positioned at the center of the node and the front-end will apply a "'text-anchor':
+ // 'middle'" property.
+ int shiftToEast = 0;
+ int shiftToWest = 0;
+ for (BorderNodesOnSide borderNodesOnSide : borderNodesOnSides) {
+ if (RectangleSide.WEST.equals(borderNodesOnSide.getSide())) {
+ shiftToEast = 1;
+ } else if (RectangleSide.EAST.equals(borderNodesOnSide.getSide())) {
+ shiftToWest = 1;
+ }
+ }
+ double portOffset = this.layoutConfigurator.configureByType(node.getNodeType()).getProperty(CoreOptions.PORT_BORDER_OFFSET).doubleValue();
+ double offSetAccordingToBorderNodes = -portOffset / 2 * (shiftToEast - shiftToWest);
+
+ x = node.getSize().getWidth() / 2 + offSetAccordingToBorderNodes;
break;
case H_RIGHT:
if (outside) {
diff --git a/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/incremental/NodeLabelPositionProviderTests.java b/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/incremental/NodeLabelPositionProviderTests.java
index 48145afe18..29528ed6ef 100644
--- a/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/incremental/NodeLabelPositionProviderTests.java
+++ b/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/incremental/NodeLabelPositionProviderTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2021 THALES GLOBAL SERVICES.
+ * Copyright (c) 2021, 2022 THALES GLOBAL SERVICES.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -14,6 +14,7 @@
import static org.assertj.core.api.Assertions.assertThat;
+import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -61,8 +62,8 @@ public void testNodeImageLabelBoundsPosition() {
NodeLabelPositionProvider labelBoundsProvider = new NodeLabelPositionProvider(new LayoutConfiguratorRegistry(List.of()).getDefaultLayoutConfigurator());
LabelLayoutData labelLayoutData = this.createLabelLayoutData();
- Position position = labelBoundsProvider.getPosition(nodeLayoutData, labelLayoutData);
- assertThat(position).extracting(Position::getX).isEqualTo(Double.valueOf(42.5390625));
+ Position position = labelBoundsProvider.getPosition(nodeLayoutData, labelLayoutData, new ArrayList<>());
+ assertThat(position).extracting(Position::getX).isEqualTo(Double.valueOf(DEFAULT_NODE_SIZE.getWidth() / 2));
assertThat(position).extracting(Position::getY).isEqualTo(Double.valueOf(-23.3984375));
}
@@ -72,8 +73,8 @@ public void testNodeRectangleLabelBoundsPosition() {
NodeLayoutData nodeLayoutData = this.createNodeLayoutData(Position.at(0, 0), DEFAULT_NODE_SIZE, createDiagramLayoutData, NodeType.NODE_RECTANGLE);
NodeLabelPositionProvider labelBoundsProvider = new NodeLabelPositionProvider(new LayoutConfiguratorRegistry(List.of()).getDefaultLayoutConfigurator());
LabelLayoutData labelLayoutData = this.createLabelLayoutData();
- Position position = labelBoundsProvider.getPosition(nodeLayoutData, labelLayoutData);
- assertThat(position).extracting(Position::getX).isEqualTo(Double.valueOf(42.5390625));
+ Position position = labelBoundsProvider.getPosition(nodeLayoutData, labelLayoutData, new ArrayList<>());
+ assertThat(position).extracting(Position::getX).isEqualTo(Double.valueOf(DEFAULT_NODE_SIZE.getWidth() / 2));
assertThat(position).extracting(Position::getY).isEqualTo(Double.valueOf(5));
}
diff --git a/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/DiagramELKLayoutTest.java b/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/DiagramELKLayoutTest.java
new file mode 100644
index 0000000000..3bfed03598
--- /dev/null
+++ b/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/DiagramELKLayoutTest.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Obeo.
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.components.diagrams.layout.services;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.eclipse.sirius.components.core.api.IEditingContext;
+import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService;
+import org.eclipse.sirius.components.diagrams.Diagram;
+import org.eclipse.sirius.components.diagrams.Node;
+import org.eclipse.sirius.components.diagrams.Position;
+import org.eclipse.sirius.components.diagrams.Size;
+import org.eclipse.sirius.components.diagrams.description.DiagramDescription;
+import org.eclipse.sirius.components.diagrams.layout.ELKDiagramConverter;
+import org.eclipse.sirius.components.diagrams.layout.ELKLayoutedDiagramProvider;
+import org.eclipse.sirius.components.diagrams.layout.LayoutConfiguratorRegistry;
+import org.eclipse.sirius.components.diagrams.layout.LayoutService;
+import org.eclipse.sirius.components.diagrams.layout.TextBoundsService;
+import org.eclipse.sirius.components.diagrams.layout.incremental.IncrementalLayoutDiagramConverter;
+import org.eclipse.sirius.components.diagrams.layout.incremental.IncrementalLayoutEngine;
+import org.eclipse.sirius.components.diagrams.layout.incremental.IncrementalLayoutedDiagramProvider;
+import org.eclipse.sirius.components.diagrams.layout.incremental.provider.ImageSizeProvider;
+import org.eclipse.sirius.components.diagrams.layout.incremental.provider.NodeSizeProvider;
+import org.eclipse.sirius.components.diagrams.tests.builder.JsonBasedEditingContext;
+import org.eclipse.sirius.components.diagrams.tests.builder.TestLayoutDiagramBuilder;
+import org.eclipse.sirius.components.representations.IRepresentationDescription;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Used to test the diagram full layout.
+ *
+ * @author lfasani
+ */
+public class DiagramELKLayoutTest {
+
+ private TestLayoutObjectService objectService = new TestLayoutObjectService();
+
+ private DefaultTestDiagramDescriptionProvider defaultTestDiagramDescriptionProvider = new DefaultTestDiagramDescriptionProvider(this.objectService);
+
+ private Optional getNode(List nodes, String targetObjectId) {
+ Optional optionalNode = Optional.empty();
+ List deeperNode = new ArrayList<>();
+
+ Iterator nodeIt = nodes.iterator();
+ while (optionalNode.isEmpty() && nodeIt.hasNext()) {
+ Node node = nodeIt.next();
+ if (targetObjectId.equals(node.getTargetObjectId())) {
+ optionalNode = Optional.of(node);
+ } else {
+ deeperNode.addAll(node.getChildNodes());
+ }
+ }
+
+ if (optionalNode.isEmpty() && !deeperNode.isEmpty()) {
+ optionalNode = this.getNode(deeperNode, targetObjectId);
+ }
+
+ return optionalNode;
+ }
+
+ private TestDiagramCreationService createDiagramCreationService(Diagram diagram) {
+ IRepresentationDescriptionSearchService.NoOp representationDescriptionSearchService = new IRepresentationDescriptionSearchService.NoOp() {
+ @Override
+ public Optional findById(IEditingContext editingContext, UUID representationDescriptionId) {
+ DiagramDescription diagramDescription = DiagramELKLayoutTest.this.defaultTestDiagramDescriptionProvider.getDefaultDiagramDescription(diagram);
+ return Optional.of(diagramDescription);
+ }
+ };
+
+ NodeSizeProvider nodeSizeProvider = new NodeSizeProvider(new ImageSizeProvider());
+ IncrementalLayoutEngine incrementalLayoutEngine = new IncrementalLayoutEngine(nodeSizeProvider);
+
+ LayoutService layoutService = new LayoutService(new ELKDiagramConverter(new TextBoundsService(), new ImageSizeProvider()), new IncrementalLayoutDiagramConverter(),
+ new LayoutConfiguratorRegistry(List.of()), new ELKLayoutedDiagramProvider(), new IncrementalLayoutedDiagramProvider(), representationDescriptionSearchService, incrementalLayoutEngine);
+
+ return new TestDiagramCreationService(this.objectService, representationDescriptionSearchService, layoutService);
+ }
+
+ @Test
+ public void testNodeLayoutWithMultilineLabel() throws IOException {
+ String nodeLabelWithMultiple = "First LineAAAAAAAA\nSecond LineBBBBBBBBB"; //$NON-NLS-1$
+ String firstChildTargetObjectId = "First child"; //$NON-NLS-1$
+
+ // @formatter:off
+ Diagram diagram = TestLayoutDiagramBuilder.diagram("Root") //$NON-NLS-1$
+ .nodes()
+ .rectangleNode(nodeLabelWithMultiple).at(10, 10).of(10, 10)
+ .childNodes()
+ .rectangleNode(firstChildTargetObjectId).at(10, 10).of(50, 50).and()
+ .and()
+ .and()
+ .and()
+ .build();
+ // @formatter:on
+
+ Path path = Paths.get("src", "test", "resources", "editing-contexts", "testNodeLayoutWithMultilineLabel"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ //$NON-NLS-5$
+ JsonBasedEditingContext editingContext = new JsonBasedEditingContext(path);
+
+ TestDiagramCreationService diagramCreationService = this.createDiagramCreationService(diagram);
+
+ Diagram layoutedDiagram = diagramCreationService.performElKLayout(editingContext, diagram);
+
+ Node firstParent = layoutedDiagram.getNodes().get(0);
+
+ // Check that the parent node and the label have the right size
+ assertThat(firstParent.getSize()).isEqualTo(Size.of(195.8818359375, 131.197265625));
+ assertThat(firstParent.getLabel().getSize()).isEqualTo(Size.of(161.8818359375, 32.197265625));
+
+ // Check that the inner node is under the multi line label area
+ assertThat(firstParent.getChildNodes().get(0).getPosition()).isEqualTo(Position.at(12, 49.197265625));
+ }
+}
diff --git a/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/TestDiagramCreationService.java b/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/TestDiagramCreationService.java
index 3d1c6c3ae2..80f447f9bc 100644
--- a/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/TestDiagramCreationService.java
+++ b/backend/sirius-components-diagrams-layout/src/test/java/org/eclipse/sirius/components/diagrams/layout/services/TestDiagramCreationService.java
@@ -94,4 +94,8 @@ public Diagram performLayout(IEditingContext editingContext, Diagram diagram, ID
return this.layoutService.incrementalLayout(editingContext, diagram, Optional.of(diagramEvent));
}
+ public Diagram performElKLayout(IEditingContext editingContext, Diagram diagram) {
+ return this.layoutService.layout(editingContext, diagram);
+ }
+
}
diff --git a/backend/sirius-components-diagrams-layout/src/test/resources/editing-contexts/testNodeLayoutWithMultilineLabel b/backend/sirius-components-diagrams-layout/src/test/resources/editing-contexts/testNodeLayoutWithMultilineLabel
new file mode 100644
index 0000000000..639795d459
--- /dev/null
+++ b/backend/sirius-components-diagrams-layout/src/test/resources/editing-contexts/testNodeLayoutWithMultilineLabel
@@ -0,0 +1,3 @@
+{
+ "name": "diag:Root"
+}
\ No newline at end of file
diff --git a/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/TextBoundsProvider.java b/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/TextBoundsProvider.java
index 66da40e2e0..c9111deb2d 100644
--- a/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/TextBoundsProvider.java
+++ b/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/TextBoundsProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2021 THALES GLOBAL SERVICES.
+ * Copyright (c) 2021, 2022 THALES GLOBAL SERVICES.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -41,7 +41,8 @@ public class TextBoundsProvider {
private static String fontName;
/**
- * Computes the text bounds for a label with the given text.
+ * Computes the text bounds for a label with the given text.
+ * The text bounds take into account the line return contained in text.
*
* @param labelStyle
* the label style
@@ -50,18 +51,29 @@ public class TextBoundsProvider {
* @return the text bounds
*/
public TextBounds computeBounds(LabelStyle labelStyle, String text) {
- int fontStyle = Font.PLAIN;
- if (labelStyle.isBold()) {
- fontStyle = fontStyle | Font.BOLD;
- }
- if (labelStyle.isItalic()) {
- fontStyle = fontStyle | Font.ITALIC;
+ Font font = this.getFont(labelStyle);
+
+ String[] lines = text.split("\\n", -1); //$NON-NLS-1$
+ Rectangle2D labelBounds = null;
+ if (lines.length == 0) {
+ labelBounds = font.getStringBounds("", FONT_RENDER_CONTEXT); //$NON-NLS-1$
+ } else {
+ labelBounds = font.getStringBounds(lines[0], FONT_RENDER_CONTEXT);
+ if (lines.length > 1) {
+ for (int i = 1; i < lines.length; i++) {
+ String line = lines[i];
+
+ Rectangle2D lineBounds = font.getStringBounds(line, FONT_RENDER_CONTEXT);
+ // shift the rectangle under the previous line
+ lineBounds.setFrame(lineBounds.getX(), lineBounds.getY() + labelBounds.getHeight(), lineBounds.getWidth(), lineBounds.getHeight());
+
+ labelBounds = labelBounds.createUnion(lineBounds);
+ }
+ }
}
- Font font = new Font(this.getFontName(), fontStyle, labelStyle.getFontSize());
- Rectangle2D stringBounds = font.getStringBounds(text, FONT_RENDER_CONTEXT);
- double width = stringBounds.getWidth();
- double height = stringBounds.getHeight();
+ double height = labelBounds.getHeight();
+ double width = labelBounds.getWidth();
double iconWidth = 0;
double iconHeight = 0;
if (!labelStyle.getIconURL().isEmpty()) {
@@ -74,11 +86,22 @@ public TextBounds computeBounds(LabelStyle labelStyle, String text) {
Size size = Size.of(width + iconWidth, height + iconHeight);
// Sprotty needs the inverse of the x and y for the alignment, so it's "0 - x" and "0 - y" on purpose
- Position alignment = Position.at(0 - stringBounds.getX() + iconWidth, 0 - stringBounds.getY());
+ Position alignment = Position.at(0 - labelBounds.getX() + iconWidth, 0 - labelBounds.getY());
return new TextBounds(size, alignment);
}
+ private Font getFont(LabelStyle labelStyle) {
+ int fontStyle = Font.PLAIN;
+ if (labelStyle.isBold()) {
+ fontStyle = fontStyle | Font.BOLD;
+ }
+ if (labelStyle.isItalic()) {
+ fontStyle = fontStyle | Font.ITALIC;
+ }
+ return new Font(this.getFontName(), fontStyle, labelStyle.getFontSize());
+ }
+
private String getFontName() {
if (fontName == null) {
if (this.isDefaultFontAvailable()) {
diff --git a/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/LabelType.java b/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/LabelType.java
index 45ea94141f..d6cde43d91 100644
--- a/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/LabelType.java
+++ b/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/LabelType.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2021 Obeo.
+ * Copyright (c) 2021, 2022 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -19,6 +19,7 @@
*/
public enum LabelType {
+ OUTSIDE("label:outside"), //$NON-NLS-1$
INSIDE_CENTER("label:inside-center"), //$NON-NLS-1$
OUTSIDE_CENTER("label:outside-center"), //$NON-NLS-1$
EDGE_BEGIN("label:edge-begin"), //$NON-NLS-1$
diff --git a/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/NodeComponent.java b/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/NodeComponent.java
index fa64a054f8..24747a8bfd 100644
--- a/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/NodeComponent.java
+++ b/backend/sirius-components-diagrams/src/main/java/org/eclipse/sirius/components/diagrams/components/NodeComponent.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019, 2021 Obeo and others.
+ * Copyright (c) 2019, 2022 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -136,7 +136,9 @@ private Element doRender(VariableManager nodeVariableManager, String targetObjec
nodeVariableManager.put(LabelDescription.OWNER_ID, nodeId);
LabelType nodeLabelType = LabelType.INSIDE_CENTER;
- if (NodeType.NODE_IMAGE.equals(type)) {
+ if (containmentKind == NodeContainmentKind.BORDER_NODE) {
+ nodeLabelType = LabelType.OUTSIDE;
+ } else if (NodeType.NODE_IMAGE.equals(type)) {
nodeLabelType = LabelType.OUTSIDE_CENTER;
}
diff --git a/backend/sirius-components-emf/src/main/java/org/eclipse/sirius/components/emf/compatibility/properties/EStringIfDescriptionProvider.java b/backend/sirius-components-emf/src/main/java/org/eclipse/sirius/components/emf/compatibility/properties/EStringIfDescriptionProvider.java
index 5036f29119..619723a3a7 100644
--- a/backend/sirius-components-emf/src/main/java/org/eclipse/sirius/components/emf/compatibility/properties/EStringIfDescriptionProvider.java
+++ b/backend/sirius-components-emf/src/main/java/org/eclipse/sirius/components/emf/compatibility/properties/EStringIfDescriptionProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019, 2021 Obeo.
+ * Copyright (c) 2019, 2022 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -25,7 +25,7 @@
import org.eclipse.sirius.components.compatibility.forms.WidgetIdProvider;
import org.eclipse.sirius.components.emf.compatibility.properties.api.IPropertiesValidationProvider;
import org.eclipse.sirius.components.forms.description.IfDescription;
-import org.eclipse.sirius.components.forms.description.TextfieldDescription;
+import org.eclipse.sirius.components.forms.description.TextareaDescription;
import org.eclipse.sirius.components.representations.Failure;
import org.eclipse.sirius.components.representations.IStatus;
import org.eclipse.sirius.components.representations.Success;
@@ -39,7 +39,7 @@
public class EStringIfDescriptionProvider {
private static final String IF_DESCRIPTION_ID = "EString"; //$NON-NLS-1$
- private static final String TEXTFIELD_DESCRIPTION_ID = "Textfield"; //$NON-NLS-1$
+ private static final String TEXTAREA_DESCRIPTION_ID = "Textarea"; //$NON-NLS-1$
private final ComposedAdapterFactory composedAdapterFactory;
@@ -54,7 +54,7 @@ public IfDescription getIfDescription() {
// @formatter:off
return IfDescription.newIfDescription(IF_DESCRIPTION_ID)
.predicate(this.getPredicate())
- .widgetDescription(this.getTextfieldDescription())
+ .widgetDescription(this.getTextareaDescription())
.build();
// @formatter:on
}
@@ -69,9 +69,9 @@ private Function getPredicate() {
};
}
- private TextfieldDescription getTextfieldDescription() {
+ private TextareaDescription getTextareaDescription() {
// @formatter:off
- return TextfieldDescription.newTextfieldDescription(TEXTFIELD_DESCRIPTION_ID)
+ return TextareaDescription.newTextareaDescription(TEXTAREA_DESCRIPTION_ID)
.idProvider(new WidgetIdProvider())
.labelProvider(this.getLabelProvider())
.valueProvider(this.getValueProvider())
diff --git a/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Textarea.java b/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Textarea.java
index 480efc75bd..3c62479f78 100644
--- a/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Textarea.java
+++ b/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Textarea.java
@@ -15,9 +15,11 @@
import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
+import java.util.function.Function;
import org.eclipse.sirius.components.annotations.Immutable;
import org.eclipse.sirius.components.forms.validation.Diagnostic;
+import org.eclipse.sirius.components.representations.IStatus;
/**
* The text area widget.
@@ -30,6 +32,8 @@ public final class Textarea extends AbstractWidget {
private String value;
+ private Function newValueHandler;
+
private Textarea() {
// Prevent instantiation
}
@@ -42,6 +46,10 @@ public String getValue() {
return this.value;
}
+ public Function getNewValueHandler() {
+ return this.newValueHandler;
+ }
+
public static Builder newTextarea(String id) {
return new Builder(id);
}
@@ -59,13 +67,14 @@ public String toString() {
*/
@SuppressWarnings("checkstyle:HiddenField")
public static final class Builder {
-
private String id;
private String label;
private String value;
+ private Function newValueHandler;
+
private List diagnostics;
private Builder(String id) {
@@ -82,6 +91,11 @@ public Builder value(String value) {
return this;
}
+ public Builder newValueHandler(Function newValueHandler) {
+ this.newValueHandler = Objects.requireNonNull(newValueHandler);
+ return this;
+ }
+
public Builder diagnostics(List diagnostics) {
this.diagnostics = Objects.requireNonNull(diagnostics);
return this;
@@ -92,6 +106,7 @@ public Textarea build() {
textarea.id = Objects.requireNonNull(this.id);
textarea.label = Objects.requireNonNull(this.label);
textarea.value = Objects.requireNonNull(this.value);
+ textarea.newValueHandler = Objects.requireNonNull(this.newValueHandler);
textarea.diagnostics = Objects.requireNonNull(this.diagnostics);
return textarea;
}
diff --git a/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java b/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java
index 712ac8010a..c0c1fcde79 100644
--- a/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java
+++ b/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019, 2021 Obeo.
+ * Copyright (c) 2019, 2022 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
@@ -193,6 +193,7 @@ private Textarea instantiateTextarea(TextareaElementProps props, List