use of org.eclipse.elk.core.service.LayoutMapping in project elk by eclipse.
the class GmfDiagramLayoutConnector method buildLayoutGraph.
@Override
public LayoutMapping buildLayoutGraph(final IWorkbenchPart workbenchPart, final Object diagramPart) {
// get the diagram editor part
DiagramEditor diagramEditor = getDiagramEditor(workbenchPart);
// choose the layout root edit part
IGraphicalEditPart layoutRootPart = null;
List<ShapeNodeEditPart> selectedParts = null;
if (diagramPart instanceof ShapeNodeEditPart || diagramPart instanceof DiagramEditPart) {
layoutRootPart = (IGraphicalEditPart) diagramPart;
} else if (diagramPart instanceof IGraphicalEditPart) {
EditPart tgEditPart = ((IGraphicalEditPart) diagramPart).getTopGraphicEditPart();
if (tgEditPart instanceof ShapeNodeEditPart) {
layoutRootPart = (IGraphicalEditPart) tgEditPart;
}
} else if (diagramPart instanceof Collection) {
Collection<?> selection = (Collection<?>) diagramPart;
// determine the layout root part from the selection
for (Object object : selection) {
if (object instanceof IGraphicalEditPart) {
if (layoutRootPart != null) {
EditPart parent = commonParent(layoutRootPart, (EditPart) object);
if (parent != null && !(parent instanceof RootEditPart)) {
layoutRootPart = (IGraphicalEditPart) parent;
}
} else if (!(object instanceof ConnectionEditPart)) {
layoutRootPart = (IGraphicalEditPart) object;
}
}
}
// build a list of edit parts that shall be layouted completely
if (layoutRootPart != null) {
selectedParts = new ArrayList<ShapeNodeEditPart>(selection.size());
for (Object object : selection) {
if (object instanceof IGraphicalEditPart) {
EditPart editPart = (EditPart) object;
while (editPart != null && editPart.getParent() != layoutRootPart) {
editPart = editPart.getParent();
}
if (editPart instanceof ShapeNodeEditPart && editPartFilter.filter(editPart) && !selectedParts.contains(editPart)) {
selectedParts.add((ShapeNodeEditPart) editPart);
}
}
}
}
}
if (layoutRootPart == null && diagramEditor != null) {
layoutRootPart = diagramEditor.getDiagramEditPart();
}
if (layoutRootPart == null) {
throw new IllegalArgumentException("Not supported by this layout connector: Workbench part " + workbenchPart + ", Edit part " + diagramPart);
}
// create the mapping
LayoutMapping mapping = buildLayoutGraph(layoutRootPart, selectedParts, workbenchPart);
return mapping;
}
use of org.eclipse.elk.core.service.LayoutMapping in project elk by eclipse.
the class GmfDiagramLayoutConnector method buildLayoutGraph.
/**
* Creates the actual mapping given an edit part which functions as the root for the layout.
*
* @param layoutRootPart the layout root edit part
* @param selection a selection of contained edit parts to process, or {@code null} if the whole
* content shall be processed
* @param workbenchPart the workbench part, or {@code null}
* @return a layout graph mapping
*/
protected LayoutMapping buildLayoutGraph(final IGraphicalEditPart layoutRootPart, final List<ShapeNodeEditPart> selection, final IWorkbenchPart workbenchPart) {
LayoutMapping mapping = new LayoutMapping(workbenchPart);
mapping.setProperty(CONNECTIONS, new LinkedList<ConnectionEditPart>());
mapping.setParentElement(layoutRootPart);
// find the diagram edit part
mapping.setProperty(DIAGRAM_EDIT_PART, getDiagramEditPart(layoutRootPart));
ElkNode topNode;
if (layoutRootPart instanceof ShapeNodeEditPart) {
// start with a specific node as root for layout
topNode = createNode(mapping, (ShapeNodeEditPart) layoutRootPart, null, null, null);
} else {
// start with the whole diagram as root for layout
topNode = ElkGraphUtil.createGraph();
Rectangle rootBounds = layoutRootPart.getFigure().getBounds();
if (layoutRootPart instanceof DiagramEditPart) {
String labelText = ((DiagramEditPart) layoutRootPart).getDiagramView().getName();
if (labelText.length() > 0) {
ElkLabel label = ElkGraphUtil.createLabel(topNode);
label.setText(labelText);
}
} else {
topNode.setLocation(rootBounds.x, rootBounds.y);
}
topNode.setDimensions(rootBounds.width, rootBounds.height);
mapping.getGraphMap().put(topNode, layoutRootPart);
}
mapping.setLayoutGraph(topNode);
if (selection != null && !selection.isEmpty()) {
// layout only the selected elements
double minx = Integer.MAX_VALUE;
double miny = Integer.MAX_VALUE;
Maybe<ElkPadding> kinsets = new Maybe<>();
for (ShapeNodeEditPart editPart : selection) {
ElkNode node = createNode(mapping, editPart, layoutRootPart, topNode, kinsets);
minx = Math.min(minx, node.getX());
miny = Math.min(miny, node.getY());
buildLayoutGraphRecursively(mapping, editPart, node, editPart);
}
mapping.setProperty(COORDINATE_OFFSET, new KVector(minx, miny));
} else {
// traverse all children of the layout root part
buildLayoutGraphRecursively(mapping, layoutRootPart, topNode, layoutRootPart);
}
// transform all connections in the selected area
processConnections(mapping);
return mapping;
}
use of org.eclipse.elk.core.service.LayoutMapping in project osate2 by osate.
the class DiagramElementLayoutUtil method applyConnectionLayout.
private static void applyConnectionLayout(final LayoutMapping mapping, final DiagramModification m) {
// Modify Connections
for (Entry<ElkGraphElement, Object> e : mapping.getGraphMap().entrySet()) {
final ElkGraphElement elkElement = e.getKey();
final Object mappedValue = e.getValue();
if (!(elkElement instanceof ElkEdge)) {
continue;
}
final ElkEdge edge = (ElkEdge) elkElement;
// Ignore edges which do not have exactly one section. This is usually the case where it is a long hierarchical connection that has 0 sections
if (edge.getSections().size() != 1) {
continue;
}
final ElkEdgeSection edgeSection = edge.getSections().get(0);
if (!(mappedValue instanceof DiagramElement)) {
continue;
}
final DiagramElement de = (DiagramElement) mappedValue;
if (!(de.getGraphic() instanceof AgeConnection)) {
continue;
}
final AgeConnection connection = (AgeConnection) de.getGraphic();
// Flow indicators have a position representing where the indicator ends.
if (connection.isFlowIndicator && edge.getTargets().size() == 1) {
final ElkPort flowIndicatorEndPort = (ElkPort) edge.getTargets().get(0);
final ElkShape flowIndicatorEndPortShape = (ElkShape) flowIndicatorEndPort.eContainer();
m.setPosition(de, new Point(flowIndicatorEndPortShape.getX(), flowIndicatorEndPortShape.getY()));
}
// Don't update connections if it wasn't updated. This prevents updating bendpoints to invalid values if an edge is not layed out.
if (edgeSection.eIsSet(ElkGraphPackage.eINSTANCE.getElkEdgeSection_StartX()) && edgeSection.eIsSet(ElkGraphPackage.eINSTANCE.getElkEdgeSection_EndX())) {
final List<Point> bendpointsInParentCoordinateSystem = edgeSection.getBendPoints().stream().map(bp -> new Point(bp.getX(), bp.getY())).collect(Collectors.toCollection(LinkedList::new));
//
// Set bendpoints
//
// Add the start and end points to the bendpoints list if the the start/end element is not a port.
// For ports the start and end points are unnecessary and will actually be located inside the port graphic.
final boolean srcIsPort = edge.getSources().size() == 1 ? edge.getSources().get(0) instanceof ElkPort : false;
final boolean dstIsPort = edge.getTargets().size() == 1 ? edge.getTargets().get(0) instanceof ElkPort : false;
if (!srcIsPort) {
bendpointsInParentCoordinateSystem.add(0, new Point(edgeSection.getStartX(), edgeSection.getStartY()));
}
if (!dstIsPort) {
bendpointsInParentCoordinateSystem.add(new Point(edgeSection.getEndX(), edgeSection.getEndY()));
}
// Adjust newly added bendpoints so that the connection arrows will face the appropriate direction
if (!srcIsPort && bendpointsInParentCoordinateSystem.size() >= 2) {
bendpointsInParentCoordinateSystem.set(0, getAdjacentPoint(bendpointsInParentCoordinateSystem.get(0), bendpointsInParentCoordinateSystem.get(1), START_AND_END_BENDPOINT_DISTANCE));
}
if (!dstIsPort && bendpointsInParentCoordinateSystem.size() >= 2) {
bendpointsInParentCoordinateSystem.set(bendpointsInParentCoordinateSystem.size() - 1, getAdjacentPoint(bendpointsInParentCoordinateSystem.get(bendpointsInParentCoordinateSystem.size() - 1), bendpointsInParentCoordinateSystem.get(bendpointsInParentCoordinateSystem.size() - 2), START_AND_END_BENDPOINT_DISTANCE));
}
// Get the absolute coordinate in the diagram of the edge's ELK container.
final Point elkContainerPosition;
if (edge.getContainingNode() == mapping.getLayoutGraph()) {
// Node available. Use the first and only child of the top level ELK node.
if (mapping.getLayoutGraph().getChildren().size() == 1) {
final ElkNode topLayoutElkNode = mapping.getLayoutGraph().getChildren().get(0);
final Point topLayoutElkNodePosition = getAbsolutePosition((DiagramNode) mapping.getGraphMap().get(topLayoutElkNode));
elkContainerPosition = new Point(topLayoutElkNodePosition.x - topLayoutElkNode.getX(), topLayoutElkNodePosition.y - topLayoutElkNode.getY());
} else {
elkContainerPosition = new Point(0, 0);
}
} else {
elkContainerPosition = getAbsolutePosition((DiagramNode) mapping.getGraphMap().get(edge.getContainingNode()));
}
final List<Point> bendpointsInAbsoluteCoordinateSystem = bendpointsInParentCoordinateSystem.stream().map(p -> new Point(p.x + elkContainerPosition.x, p.y + elkContainerPosition.y)).collect(Collectors.toList());
m.setBendpoints(de, bendpointsInAbsoluteCoordinateSystem);
// For the midpoint calculation, the start and end points are needed. Add them if they have not already been added.
if (srcIsPort) {
bendpointsInParentCoordinateSystem.add(0, new Point(edgeSection.getStartX(), edgeSection.getStartY()));
}
if (dstIsPort) {
bendpointsInParentCoordinateSystem.add(new Point(edgeSection.getEndX(), edgeSection.getEndY()));
}
// Set Label Positions
setLabelPositionsForEdge(mapping, m, edge, findMidpoint(bendpointsInParentCoordinateSystem));
}
}
}
use of org.eclipse.elk.core.service.LayoutMapping in project osate2 by osate.
the class DiagramElementLayoutUtil method applyProperties.
/**
* Sets the ELK properties of elements in the specified layout mapping based on the layout options.
* @param layoutMapping
*/
private static void applyProperties(final DiagramNode rootDiagramNode, final LayoutMapping layoutMapping) {
// Set the minimum node size based on the ports and their assigned sides.
final IGraphElementVisitor minNodeSizeVisitor = element -> {
if (element instanceof ElkNode) {
final ElkNode n = (ElkNode) element;
final double maxLabelWidth = n.getLabels().stream().mapToDouble(l -> l.getWidth()).max().orElse(0.0);
final double labelHeightSum = n.getLabels().stream().mapToDouble(l -> l.getHeight()).sum();
// Determine max width for ports on the left and right sides
final double maxLeftPortWidth = n.getPorts().stream().filter(p -> p.getProperty(CoreOptions.PORT_SIDE) == PortSide.WEST).mapToDouble(p -> p.getWidth()).max().orElse(0.0);
final double maxRightPortWidth = n.getPorts().stream().filter(p -> p.getProperty(CoreOptions.PORT_SIDE) == PortSide.EAST).mapToDouble(p -> p.getWidth()).max().orElse(0.0);
final DiagramNode dn = (DiagramNode) layoutMapping.getGraphMap().get(n);
double minWidth = 0;
if (n.getProperty(CoreOptions.NODE_LABELS_PLACEMENT).contains(NodeLabelPlacement.H_CENTER)) {
// Ensure the minimum width is such that the label can be centered without overlapping with ports.
// This happens because ports are inside the node due to the PORT_BORDER_OFFSET and ELK centers the labels in the remaining space.
final double widthForPorts = 2 * Math.max(maxLeftPortWidth, maxRightPortWidth);
minWidth = Math.max(40, maxLabelWidth + widthForPorts + PORT_WIDTH_PADDING);
} else {
final double widthForPorts = maxLeftPortWidth + maxRightPortWidth + PORT_WIDTH_PADDING;
minWidth = Math.max(40, Math.max(maxLabelWidth, widthForPorts));
}
double minHeight = Math.max(35, labelHeightSum);
if (dn instanceof DiagramElement) {
final DiagramElement de = ((DiagramElement) dn);
// Special min height handling for initial modes
final Graphic graphic = de.getGraphic();
if (graphic instanceof AgeShape && !((AgeShape) graphic).isResizeable() && de.hasSize()) {
final Dimension dim = de.getSize();
minHeight = dim.height;
minWidth = dim.width;
// Adjust size constraints for fixed sized shapes which do not have contents.
if (n.getChildren().size() == 0 || n.getLabels().size() == 0 && n.getPorts().size() == 0) {
final EnumSet<SizeConstraint> nodeSizeConstraints = EnumSet.of(SizeConstraint.MINIMUM_SIZE);
n.setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, nodeSizeConstraints);
}
}
if (graphic instanceof ModeGraphic && ((ModeGraphic) graphic).isInitialMode) {
minHeight += ModeGraphic.INITIAL_MODE_AREA_HEIGHT;
}
// Special min size handling for elements shown as image
final Style style = de.getStyle();
if (style != null && Boolean.TRUE.equals(style.getShowAsImage())) {
final Dimension dim = ((DiagramElement) dn).getSize();
minHeight = dim.height;
minWidth = dim.width;
}
}
// Increase min width and min height for top level nodes.
if (dn != null && dn.getParent() instanceof AgeDiagram) {
minWidth = Math.max(minWidth, 200);
minHeight = Math.max(minHeight, 100);
}
n.setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(minWidth, minHeight));
}
};
ElkUtil.applyVisitors(layoutMapping.getLayoutGraph(), minNodeSizeVisitor);
// If the top level element has a size set, don't shrink it.
if (rootDiagramNode instanceof DiagramElement) {
final DiagramElement rootDiagramElement = (DiagramElement) rootDiagramNode;
final ElkGraphElement rootGraphElement = layoutMapping.getGraphMap().inverse().get(rootDiagramNode);
if (rootGraphElement != null && rootDiagramElement.hasSize() && DiagramElementPredicates.isResizeable(rootDiagramElement)) {
final KVector minSize = rootGraphElement.getProperty(CoreOptions.NODE_SIZE_MINIMUM);
final double newMinWidth = Math.max(rootDiagramElement.getWidth(), minSize == null ? 0.0 : minSize.x);
final double newMinHeight = Math.max(rootDiagramElement.getHeight(), minSize == null ? 0.0 : minSize.y);
rootGraphElement.setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(newMinWidth, newMinHeight));
}
}
}
use of org.eclipse.elk.core.service.LayoutMapping in project osate2 by osate.
the class ElkGraphBuilder method createPort.
/**
* @param parent
* @param side
* @param dockedElement
* @param portBorderOffset additional offset from the border. Used to set the ELK port border offset for nested ports.
* @param mapping
* @return
*/
private ElkPort createPort(final ElkNode parent, final PortSide side, final DiagramElement dockedElement, final double portBorderOffset, final LayoutMapping mapping) {
final List<DiagramElement> dockedChildren = getDockedChildren(dockedElement);
final Dimension untransformedGraphicSize = layoutInfoProvider.getPortGraphicSize(dockedElement);
final Dimension transformedGraphicSize = transformDimension(untransformedGraphicSize, side);
final Dimension untransformedLabelsSize = layoutInfoProvider.getDockedElementLabelsSize(dockedElement);
final Dimension transformedLabelsSize = transformDimension(untransformedLabelsSize, side);
// Create child ports and sort them by the size of the dimension parallel to the docked side
final List<ElkPort> childPorts = dockedChildren.stream().map(ce -> createPort(parent, side, ce, getOrthogonalSize(transformedGraphicSize, side), mapping)).sorted((p1, p2) -> Double.compare(getSize(p1, side), getSize(p1, side))).collect(Collectors.toCollection(ArrayList::new));
// If the port has child ports, then we assume it is a feature group.
// The child ports are split into two bins and positioned such that they do not overlap the center of the feature group.
// The parent port will be sized accordingly.
final double maxChildBinSize;
if (childPorts.size() > 0) {
// Split the ports into two lists which have roughly equal heights/widths(depending on the docked side)
double[] binSize = { 0.0, 0.0 };
@SuppressWarnings("unchecked") final List<ElkPort>[] binLists = new ArrayList[] { new ArrayList<>(), new ArrayList<>() };
for (final ElkPort childPort : childPorts) {
final double size = getSize(childPort, side);
final int binIndex = binSize[0] <= binSize[1] ? 0 : 1;
binLists[binIndex].add(childPort);
binSize[binIndex] += size + paddingSize;
}
// Determine the total size of the feature
maxChildBinSize = Math.max(binSize[0], binSize[1]);
// Set the position of the port relative to its parent because the size and position of the parent will be selected after its children are sized.
for (int i = 0; i < 2; i++) {
double childPosition = transformedLabelsSize.height + i * (maxChildBinSize + transformedGraphicSize.height);
for (final ElkPort childPort : binLists[i]) {
setPositionAlongSide(childPort, side, childPosition);
childPosition += getSize(childPort, side) + paddingSize;
}
}
} else {
maxChildBinSize = 0.0;
}
// Size the parent port based on the bin size.
final double newGraphicSize = 2.0 * maxChildBinSize + transformedGraphicSize.height;
final double totalSize = transformedLabelsSize.height + newGraphicSize;
final ElkPort newPort = ElkGraphUtil.createPort(parent);
mapping.getGraphMap().put(newPort, dockedElement);
newPort.setProperty(CoreOptions.PORT_SIDE, side);
// Determine max orthogonal size of children
double maxChildOrthogonalSize = 0;
for (final ElkPort childPort : childPorts) {
maxChildOrthogonalSize = Math.max(maxChildOrthogonalSize, getOrthogonalSize(childPort, side));
}
// Determine size and position
final Dimension newSize;
if (DiagramElementPredicates.isResizeable(dockedElement)) {
newSize = new Dimension(Math.max(untransformedLabelsSize.width, maxChildOrthogonalSize + getOrthogonalSize(transformedGraphicSize, side)), totalSize);
} else {
newSize = new Dimension(Math.max(untransformedLabelsSize.width, untransformedGraphicSize.width), transformedLabelsSize.height + untransformedGraphicSize.height);
}
// final graph.
if (omitNestedPorts) {
for (final ElkPort childPort : childPorts) {
mapping.getGraphMap().remove(childPort);
EcoreUtil.remove(childPort);
}
}
final Dimension transformedNewSize = transformDimension(newSize, side);
newPort.setWidth(transformedNewSize.width);
newPort.setHeight(transformedNewSize.height);
// Set port border offset
if (PortSide.SIDES_NORTH_SOUTH.contains(side)) {
newPort.setProperty(CoreOptions.PORT_BORDER_OFFSET, -newPort.getHeight() - portBorderOffset);
} else {
newPort.setProperty(CoreOptions.PORT_BORDER_OFFSET, -newPort.getWidth() - portBorderOffset);
}
// Set the port anchor based on where the actual graphic will be.
final Dimension transformedPortAnchor = transformDimension(new Dimension(untransformedGraphicSize.width / 2, transformedLabelsSize.height + maxChildBinSize + untransformedGraphicSize.height / 2.0), side);
newPort.setProperty(CoreOptions.PORT_ANCHOR, new KVector(transformedPortAnchor.width, transformedPortAnchor.height));
return newPort;
}
Aggregations