Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#738: Add route data to ComputedBoundsAction #181

Merged
merged 1 commit into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2021 EclipseSource and others.
* Copyright (c) 2021-2022 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -18,8 +18,13 @@
import java.util.Map;
import java.util.Optional;

import org.eclipse.emf.common.util.EMap;
import org.eclipse.glsp.graph.GPoint;

public final class GArguments {
public static final String KEY_EDGE_PADDING = "edgePadding";
public static final String KEY_EDGE_SOURCE_POINT = "edgeSourcePoint";
public static final String KEY_EDGE_TARGET_POINT = "edgeTargetPoint";

public static final String KEY_RADIUS_TOP_LEFT = "radiusTopLeft";
public static final String KEY_RADIUS_TOP_RIGHT = "radiusTopRight";
Expand Down Expand Up @@ -52,6 +57,14 @@ public static Optional<Double> getEdgePadding(final Map<String, Object> argument
return getDouble(arguments, KEY_EDGE_PADDING);
}

public static Optional<GPoint> getEdgeSourcePoint(final Map<String, Object> arguments) {
return get(arguments, KEY_EDGE_SOURCE_POINT, GPoint.class);
}

public static Optional<GPoint> getEdgeTargetPoint(final Map<String, Object> arguments) {
return get(arguments, KEY_EDGE_TARGET_POINT, GPoint.class);
}

public static Optional<Double> getDouble(final Map<String, Object> arguments, final String key) {
return getNumber(arguments, key).map(Number::doubleValue);
}
Expand All @@ -61,17 +74,56 @@ public static Optional<Integer> getInteger(final Map<String, Object> arguments,
}

public static Optional<Number> getNumber(final Map<String, Object> arguments, final String key) {
Object value = arguments.get(key);
return value instanceof Number ? Optional.of((Number) value) : Optional.empty();
return get(arguments, key, Number.class);
}

public static Optional<Boolean> getBoolean(final Map<String, Object> arguments, final String key) {
Object value = arguments.get(key);
return value instanceof Boolean ? Optional.of((Boolean) value) : Optional.empty();
return get(arguments, key, Boolean.class);
}

public static Optional<String> getString(final Map<String, Object> arguments, final String key) {
return get(arguments, key, String.class);
}

public static <T> Optional<T> get(final Map<String, Object> arguments, final String key, final Class<T> clazz) {
Object value = arguments.get(key);
return clazz.isInstance(value) ? Optional.of(clazz.cast(value)) : Optional.empty();
}

public static Optional<Double> getEdgePadding(final EMap<String, Object> arguments) {
return getDouble(arguments, KEY_EDGE_PADDING);
}

public static Optional<GPoint> getEdgeSourcePoint(final EMap<String, Object> arguments) {
return get(arguments, KEY_EDGE_SOURCE_POINT, GPoint.class);
}

public static Optional<GPoint> getEdgeTargetPoint(final EMap<String, Object> arguments) {
return get(arguments, KEY_EDGE_TARGET_POINT, GPoint.class);
}

public static Optional<Double> getDouble(final EMap<String, Object> arguments, final String key) {
return getNumber(arguments, key).map(Number::doubleValue);
}

public static Optional<Integer> getInteger(final EMap<String, Object> arguments, final String key) {
return getNumber(arguments, key).map(Number::intValue);
}

public static Optional<Number> getNumber(final EMap<String, Object> arguments, final String key) {
return get(arguments, key, Number.class);
}

public static Optional<Boolean> getBoolean(final EMap<String, Object> arguments, final String key) {
return get(arguments, key, Boolean.class);
}

public static Optional<String> getString(final EMap<String, Object> arguments, final String key) {
return get(arguments, key, String.class);
}

public static <T> Optional<T> get(final EMap<String, Object> arguments, final String key, final Class<T> clazz) {
Object value = arguments.get(key);
return value instanceof String ? Optional.of((String) value) : Optional.empty();
return clazz.isInstance(value) ? Optional.of(clazz.cast(value)) : Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019-2021 EclipseSource and others.
* Copyright (c) 2019-2022 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -22,26 +22,30 @@
import org.eclipse.glsp.server.actions.Action;
martin-fleck-at marked this conversation as resolved.
Show resolved Hide resolved
import org.eclipse.glsp.server.types.ElementAndAlignment;
import org.eclipse.glsp.server.types.ElementAndBounds;
import org.eclipse.glsp.server.types.ElementAndRoutingPoints;

public class ComputedBoundsAction extends Action {

public static final String KIND = "computedBounds";

private List<ElementAndBounds> bounds;
private List<ElementAndAlignment> alignments;
private List<ElementAndRoutingPoints> routes;
private int revision;

public ComputedBoundsAction() {
super(KIND);
this.bounds = new ArrayList<>();
this.alignments = new ArrayList<>();
this.routes = new ArrayList<>();
}

public ComputedBoundsAction(final List<ElementAndBounds> bounds, final List<ElementAndAlignment> alignments,
final int revision) {
final List<ElementAndRoutingPoints> route, final int revision) {
super(KIND);
this.bounds = bounds;
this.alignments = alignments;
this.routes = route;
this.revision = revision;
}

Expand All @@ -53,6 +57,10 @@ public ComputedBoundsAction(final List<ElementAndBounds> bounds, final List<Elem

public void setAlignments(final List<ElementAndAlignment> alignments) { this.alignments = alignments; }

public List<ElementAndRoutingPoints> getRoutes() { return routes; }

public void setRoutes(final List<ElementAndRoutingPoints> routes) { this.routes = routes; }

public Optional<Integer> getRevision() { return Optional.ofNullable(revision); }

public void setRevision(final int revision) { this.revision = revision; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,11 @@
********************************************************************************/
package org.eclipse.glsp.server.gmodel;
martin-fleck-at marked this conversation as resolved.
Show resolved Hide resolved

import static org.eclipse.glsp.server.types.GLSPServerException.getOrThrow;

import org.eclipse.emf.common.util.EList;
import org.eclipse.glsp.graph.GEdge;
import org.eclipse.glsp.graph.GModelIndex;
import org.eclipse.glsp.graph.GPoint;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.AbstractOperationHandler;
import org.eclipse.glsp.server.operations.ChangeRoutingPointsOperation;
import org.eclipse.glsp.server.types.ElementAndRoutingPoints;
import org.eclipse.glsp.server.utils.LayoutUtil;

import com.google.inject.Inject;

Expand All @@ -38,24 +33,11 @@ public class GModelChangeRoutingPointsHandler extends AbstractOperationHandler<C

@Override
protected void executeOperation(final ChangeRoutingPointsOperation operation) {

// check for null-values
if (operation.getNewRoutingPoints() == null) {
throw new IllegalArgumentException("Incomplete change routingPoints action");
}

// check for existence of matching elements
GModelIndex index = modelState.getIndex();

for (ElementAndRoutingPoints ear : operation.getNewRoutingPoints()) {
GEdge edge = getOrThrow(index.findElementByClass(ear.getElementId(), GEdge.class),
"Invalid edge: edge ID " + ear.getElementId());

// reroute
EList<GPoint> routingPoints = edge.getRoutingPoints();
routingPoints.clear();
routingPoints.addAll(ear.getNewRoutingPoints());
}

operation.getNewRoutingPoints().forEach(routingPoints -> LayoutUtil.applyRoutingPoints(routingPoints, index));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

import static org.eclipse.glsp.server.types.GLSPServerException.getOrThrow;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.glsp.graph.GAlignable;
import org.eclipse.glsp.graph.GBounds;
Expand All @@ -31,11 +34,14 @@
import org.eclipse.glsp.graph.GModelRoot;
import org.eclipse.glsp.graph.GPoint;
import org.eclipse.glsp.graph.GraphFactory;
import org.eclipse.glsp.graph.builder.impl.GArguments;
import org.eclipse.glsp.graph.util.GraphUtil;
import org.eclipse.glsp.server.features.core.model.ComputedBoundsAction;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.types.ElementAndAlignment;
import org.eclipse.glsp.server.types.ElementAndBounds;
import org.eclipse.glsp.server.types.ElementAndRoutingPoints;
import org.eclipse.glsp.server.types.GLSPServerException;

public final class LayoutUtil {

Expand All @@ -51,27 +57,108 @@ private LayoutUtil() {}
public static void applyBounds(final GModelRoot root, final ComputedBoundsAction action,
final GModelState modelState) {
GModelIndex index = modelState.getIndex();
for (ElementAndBounds b : action.getBounds()) {
GModelElement element = getOrThrow(index.get(b.getElementId()),
"Model element not found! ID: " + b.getElementId());
if (element instanceof GBoundsAware) {
GBoundsAware bae = (GBoundsAware) element;
if (b.getNewPosition() != null) {
bae.setPosition(GraphUtil.copy(b.getNewPosition()));
}
if (b.getNewSize() != null) {
bae.setSize(GraphUtil.copy(b.getNewSize()));
}
action.getBounds().forEach(bounds -> applyBounds(bounds, index));
action.getAlignments().forEach(alignment -> applyAlignment(alignment, index));
action.getRoutes().forEach(route -> applyRoute(route, index));
}

/**
* Applies the new bounds to the model.
*
* @param bounds The new bounds.
* @param index The model index.
* @return The changed element.
*/
public static Optional<GBoundsAware> applyBounds(final ElementAndBounds bounds, final GModelIndex index) {
GModelElement element = getOrThrow(index.get(bounds.getElementId()),
"Model element not found! ID: " + bounds.getElementId());
if (element instanceof GBoundsAware) {
GBoundsAware bae = (GBoundsAware) element;
if (bounds.getNewPosition() != null) {
bae.setPosition(GraphUtil.copy(bounds.getNewPosition()));
}
}
for (ElementAndAlignment a : action.getAlignments()) {
GModelElement element = getOrThrow(index.get(a.getElementId()),
"Model element not found! ID: " + a.getElementId());
if (element instanceof GAlignable) {
GAlignable alignable = (GAlignable) element;
alignable.setAlignment(a.getNewAlignment());
if (bounds.getNewSize() != null) {
bae.setSize(GraphUtil.copy(bounds.getNewSize()));
}
return Optional.of(bae);
}
return Optional.empty();
}

/**
* Applies the new alignment to the model.
*
* @param alignment The new alignment.
* @param index The model index.
* @return The changed element.
*/
public static Optional<GAlignable> applyAlignment(final ElementAndAlignment alignment, final GModelIndex index) {
GModelElement element = getOrThrow(index.get(alignment.getElementId()),
"Model element not found! ID: " + alignment.getElementId());
if (element instanceof GAlignable) {
GAlignable alignable = (GAlignable) element;
alignable.setAlignment(alignment.getNewAlignment());
return Optional.of(alignable);
}
return Optional.empty();
}

/**
* Applies the new route to the model.
*
* @param route The new route.
* @param index The model index.
* @return The changed element.
*/
public static GEdge applyRoute(final ElementAndRoutingPoints route, final GModelIndex index) {
List<GPoint> routingPoints = route.getNewRoutingPoints();
if (routingPoints.size() < 2) {
throw new GLSPServerException("Invalid Route!");
}
// first and last point mark the source and target point
GEdge edge = applyRoutingPoints(route, index);
EList<GPoint> edgeRoutingPoints = edge.getRoutingPoints();
edge.getArgs().put(GArguments.KEY_EDGE_SOURCE_POINT, edgeRoutingPoints.remove(0));
edge.getArgs().put(GArguments.KEY_EDGE_TARGET_POINT, edgeRoutingPoints.remove(edgeRoutingPoints.size() - 1));
return edge;
}

/**
* Returns the complete route of the given edge. The route, as opposed to the routing points, also contain the source
* and target point.
*
* @param edge The edge from which we get the route
* @return complete edge route
*/
public static ElementAndRoutingPoints getRoute(final GEdge edge) {
Optional<GPoint> sourcePoint = GArguments.getEdgeSourcePoint(edge.getArgs());
if (sourcePoint.isEmpty()) {
throw new GLSPServerException("Cannot get route without source point!");
}
Optional<GPoint> targetPoint = GArguments.getEdgeTargetPoint(edge.getArgs());
if (targetPoint.isEmpty()) {
throw new GLSPServerException("Cannot get route without target point!");
}
List<GPoint> route = new ArrayList<>(EcoreUtil.copyAll(edge.getRoutingPoints()));
route.add(0, sourcePoint.get());
route.add(targetPoint.get());
return new ElementAndRoutingPoints(edge.getId(), route);
}

/**
* Applies the new routing points to the model.
*
* @param routingPoints The new routing points.
* @param index The model index.
* @return The changed element.
*/
public static GEdge applyRoutingPoints(final ElementAndRoutingPoints routingPoints, final GModelIndex index) {
GEdge edge = getOrThrow(index.findElementByClass(routingPoints.getElementId(), GEdge.class),
"Model element not found! ID: " + routingPoints.getElementId());
EList<GPoint> edgeRoutingPoints = edge.getRoutingPoints();
edgeRoutingPoints.clear();
edgeRoutingPoints.addAll(routingPoints.getNewRoutingPoints());
return edge;
}

/**
Expand Down