From 521e197145afb4814faf724553c967fbf04ddf7d Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 17 Oct 2022 09:22:36 +0200 Subject: [PATCH 01/27] Relative Constraints: Migrated jep implementation. --- .../gson_utils/KGraphTypeAdapterUtil.xtend | 14 +- .../lsp/interactive/InteractiveUtil.xtend | 146 ++++++++- .../RelativeConstraintProperty.xtend | 28 ++ .../lsp/interactive/layered/Actions.xtend | 99 ++++++ .../layered/ILPredOfConstraint.xtend | 26 ++ .../layered/ILSuccOfConstraint.xtend | 26 ++ .../LayeredConstraintReevaluation.xtend | 47 ++- .../LayeredInteractiveActionHandler.xtend | 31 +- ...edInteractiveLanguageServerExtension.xtend | 282 ++++++++++++++++-- .../RelativeConstraintReevaluation.xtend | 147 +++++++++ 10 files changed, 808 insertions(+), 38 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index d866d90ee..706b099b6 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2018-2021 by + * Copyright 2018-2022 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -18,9 +18,14 @@ package de.cau.cs.kieler.klighd.lsp.gson_utils import com.google.gson.GsonBuilder import de.cau.cs.kieler.klighd.SynthesisOption +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteILPredOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteILSuccOfConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteLayerConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeletePositionConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteRelativeConstraintsAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteStaticConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetILPredOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetILSuccOfConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetLayerConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetPositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetStaticConstraintAction @@ -61,6 +66,13 @@ class KGraphTypeAdapterUtil { addActionKind(DeleteStaticConstraintAction.KIND, DeleteStaticConstraintAction) addActionKind(DeletePositionConstraintAction.KIND, DeletePositionConstraintAction) addActionKind(DeleteLayerConstraintAction.KIND, DeleteLayerConstraintAction) + //relative constraints + addActionKind(SetILPredOfConstraintAction.KIND, SetILPredOfConstraintAction) + addActionKind(SetILSuccOfConstraintAction.KIND, SetILSuccOfConstraintAction) + addActionKind(DeleteRelativeConstraintsAction.KIND, DeleteRelativeConstraintsAction) + addActionKind(DeleteILPredOfConstraintAction.KIND, DeleteILPredOfConstraintAction) + addActionKind(DeleteILSuccOfConstraintAction.KIND, DeleteILSuccOfConstraintAction) + // Interactive rectpacking actions addActionKind(RectpackingSetPositionConstraintAction.KIND, RectpackingSetPositionConstraintAction) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 8cbb6526d..4b0376519 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -8,11 +8,7 @@ * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 + * This code is provided under the terms of the Eclipse Public License (EPL). */ package de.cau.cs.kieler.klighd.lsp.interactive @@ -24,6 +20,9 @@ import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions import org.eclipse.elk.core.options.CoreOptions import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty +//import de.cau.cs.kieler.annotations.Annotatable +//import de.cau.cs.kieler.annotations.TypedStringAnnotation +//import de.cau.cs.kieler.annotations.AnnotationsFactory /** * Provides utility methods for interactive layout. @@ -82,6 +81,45 @@ class InteractiveUtil { } } } + + /** + * Copies an arbitrary IProperty of a KNode to a State if the value on the KNode + * is different to the value on the State. + * If the new value on the KNode was the default value of the property + * then the property is set to null on the State. + * @param state The target sate + * @param kNode The source KNode of the property + * @param annotation The annotation that should be set + * @param prop Determines which IProperty should be copied + */ + // FIXME +// static def copyConstraintAnnotations(Annotatable state, KNode kNode, String annotation, IProperty prop) { +// val String value = "" + kNode.getProperty(prop) +// +// val anns = state.getAnnotations().filter(TypedStringAnnotation) +// +// // remove old annotation if it exists +// var TypedStringAnnotation removeA = null +// for (ann : anns) { +// if (ann.type.equals(annotation)) { +// removeA = ann +// } +// } +// if (removeA !== null) { +// state.annotations.remove(removeA) +// } +// +// // add annotation with new value if the value is not the default one +// if (kNode.getProperty(prop) !== null && !kNode.getProperty(prop).equals(prop.^default)) { +// var newA = AnnotationsFactory::eINSTANCE.createTypedStringAnnotation => [ +// it.name = "layout" +// it.type = annotation +// it.values += value +// ] +// state.annotations.add(newA) +// } +// +// } /** * Copies constraint properties depending on the algorithm from kNode to elkNode @@ -90,23 +128,46 @@ class InteractiveUtil { * @param elkNode The target ElkNode * @param kNode The source KNode of the property */ - static def copyAllConstraints(ElkNode elkNode, KNode kNode) { + static def copyAllConstraints(Object node, KNode kNode) { val algorithm = kNode.parent.getProperty(CoreOptions.ALGORITHM) + var List> props = #[] - if(algorithm === null || algorithm == 'layered') { + var List annos = #[] + if(algorithm === null || algorithm == 'layered' || algorithm == 'org.eclipse.elk.layered') { props = #[ LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, - LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT + LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, + LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, + LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF + ] + annos = #[ + "layering.layerChoiceConstraint", + "crossingMinimization.positionChoiceConstraint", + "crossingMinimization.inLayerPredOf", + "crossingMinimization.inLayerSuccOf" ] } else if ("rectpacking".equals(algorithm)) { props = #[ RectPackingOptions.DESIRED_POSITION, RectPackingOptions.ASPECT_RATIO ] + annos = #[ + "desiredPosition", + "aspectRatio" + ] } - for (prop : props) { - copyConstraintProp(elkNode, kNode, prop) + + if (node instanceof ElkNode) { + for (prop : props) { + copyConstraintProp(node, kNode, prop) + } } + // FIXME +// else if (node instanceof Annotatable) { +// for (var i = 0; i< annos.size; i++) { +// copyConstraintAnnotations(node, kNode, annos.get(i), props.get(i)) +// } +// } } /** @@ -122,4 +183,69 @@ class InteractiveUtil { } return parent } + + /** + * Determines the nodes that are connected to {@code node} by relative constraints. + * The returned list of nodes is sorted based on the position of the nodes. + * + * @param node One node of the chain + * @param layerNodes Nodes that are in the same layer as {@code node} + */ + static def getChain(KNode node, List layerNodes) { + var pos = layerNodes.indexOf(node) + var chainNodes = new ArrayList(); + chainNodes.add(node) + + // from node to the start + for (var i = pos - 1; i >= 0; i--) { + if (layerNodes.get(i).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF) !== null + || layerNodes.get(i + 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) !== null) { + chainNodes.add(0, layerNodes.get(i)) + } else { + i = -1 + } + } + + // count from node to the end + for (var i = pos + 1; i < layerNodes.size; i++) { + if (layerNodes.get(i).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) !== null + || layerNodes.get(i - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF) !== null) { + chainNodes.add(layerNodes.get(i)) + } else { + i = layerNodes.size + } + } + + return chainNodes + } + + + /** + * Checks whether the nodes of {@code chain1} and the nodes {@code chain2} can be merged to one chain + * + * @param chain1 One of the two chains. + * @param chain2 Other one of the two chains. + */ + static def isMergeImpossible(List chain1, List chain2) { + var connectedNodes = new ArrayList() + for (n : chain1) { + var edges = n.outgoingEdges + for (e : edges) { + connectedNodes.add(e.target) + } + edges = n.incomingEdges + for (e : edges) { + connectedNodes.add(e.source) + } + } + + for (n : connectedNodes) { + if (chain2.contains(n)) { + return true + } + } + + return false + } + } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend new file mode 100644 index 000000000..2b6dc52f8 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend @@ -0,0 +1,28 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive + +import org.eclipse.xtend.lib.annotations.Data +import de.cau.cs.kieler.klighd.kgraph.KNode +import org.eclipse.elk.graph.properties.IProperty + +/** + * A data class for the layered interactive relative constraints sent from client to server. + * + * @author jep + */ +@Data +class RelativeConstraintProperty { + KNode kNode + IProperty property +} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend index 42c32dcba..8171978db 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend @@ -140,4 +140,103 @@ class DeleteLayerConstraintAction implements Action { new(Consumer initializer) { initializer.accept(this) } +}/** + * Sets a 'in layer predecessor of'-constraint for a node. + * + * @author jet + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +class SetILPredOfConstraintAction implements Action { + public static val KIND = 'setILPredOfConstraint' + String kind = KIND + + ILPredOfConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} + +/** + * Sets a 'in layer successor of'-constraint for a node. + * + * @author jet + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +class SetILSuccOfConstraintAction implements Action { + public static val KIND = 'setILSuccOfConstraint' + String kind = KIND + + ILSuccOfConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } } + +/** + * Deletes the relative constraints on the node that is identified by the given id. + * + * @author jet + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +class DeleteRelativeConstraintsAction implements Action { + public static val KIND = 'deleteRelativeConstraints' + String kind = KIND + + DeleteConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} + +/** + * Deletes the iLPredOf constraint on the node that is identified by the given id. + * + * @author jet + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +class DeleteILPredOfConstraintAction implements Action { + public static val KIND = 'deleteILPredOfConstraint' + String kind = KIND + + DeleteConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} + +/** + * Deletes the iLSuccOf constraint on the node that is identified by the given id. + * + * @author jet + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +class DeleteILSuccOfConstraintAction implements Action { + public static val KIND = 'deleteILSuccOfConstraint' + String kind = KIND + + DeleteConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} + diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend new file mode 100644 index 000000000..bf1a2ed90 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend @@ -0,0 +1,26 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive.layered + +import org.eclipse.xtend.lib.annotations.Data + +/** + * Data class for a 'in layer predecessor of'-constraint. + * + * @author jep + */ +@Data +class ILPredOfConstraint { + String id + String otherNode +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend new file mode 100644 index 000000000..d6b05e05e --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend @@ -0,0 +1,26 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive.layered + +import org.eclipse.xtend.lib.annotations.Data + +/** + * Data class for a 'in layer successor of'-constraint. + * + * @author jep + */ +@Data +class ILSuccOfConstraint { + String id + String otherNode +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index d94b1ded8..591ec89a0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2019, 2020 by + * Copyright 2019-2022 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -29,7 +29,7 @@ import org.eclipse.xtend.lib.annotations.Accessors * Class to reevaluate constraint set for the layered algorithm since they may become obsolete or have to be changed * if some node is moved. * - * @author cos, sdo + * @author cos, sdo, jep */ class LayeredConstraintReevaluation { @@ -53,15 +53,15 @@ class LayeredConstraintReevaluation { */ def reevaluatePositionConstraintsAfterLayerSwap(List newNodesOfLayer, List oldNodesOfLayer, KNode target, int newPos) { - + val chainLength = InteractiveUtil.getChain(target, oldNodesOfLayer).size // formerLayer != newLayer -- should always be true - it doesn't cause errors if it's not, though. // The node is "deleted" from its old layer if it had a position constraint the old layer // needs to be reevaluated - offsetPosConstraintsOfLayerFrom(oldNodesOfLayer, -1, + offsetPosConstraintsOfLayerFrom(oldNodesOfLayer, -chainLength, target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID), target) // The node is added at the new position in the new layer. - offsetPosConstraintsOfLayerFrom(newNodesOfLayer, 1, newPos, target) + offsetPosConstraintsOfLayerFrom(newNodesOfLayer, chainLength, newPos, target) } /** @@ -74,15 +74,16 @@ class LayeredConstraintReevaluation { def reevaluatePositionConstraintsAfterPosChangeInLayer(List nodesOfLayer, KNode target, int newPos) { val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + val chainLength = InteractiveUtil.getChain(target, nodesOfLayer).size if (newPos < oldPos) { // new position constraint is above the old position // increment all position constraints of nodes that weren't below the target beforehand - offsetPosConstraintsOfLayerFromTo(nodesOfLayer, 1, newPos, oldPos, target) + offsetPosConstraintsOfLayerFromTo(nodesOfLayer, chainLength, newPos, oldPos, target) } else { // oldPos < newPos new position constraint is below the old position // Decrement all position constraints of nodes that weren't above the target beforehand - offsetPosConstraintsOfLayerFromTo(nodesOfLayer, -1, oldPos, newPos, target) + offsetPosConstraintsOfLayerFromTo(nodesOfLayer, -chainLength, oldPos, newPos, target) } } @@ -232,4 +233,36 @@ class LayeredConstraintReevaluation { def private offsetPosConstraintsOfLayerFrom(List layer, int offset, int startPos, KNode target) { offsetPosConstraintsOfLayerFromTo(layer, offset, startPos, layer.length - 1, target) } + + /** + * Updates position constraints of the moved node and the one in its chain. + * + * @param node The moved node. + * @param newPos The new position of the moved node + * @param chain The chain of {@code node} + */ + def reevaluatePosConsInChain(KNode node, int newPos, List chain) { + val offset = chain.indexOf(node) + for (var i = 0; i < chain.size; i++) { + val n = chain.get(i) + if (n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) !== -1) { + val pos = newPos - (offset - i) + changedNodes.put(new ConstraintProperty(n, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), pos) + } + } + } + + /** + * Updates layer constraint of the moved node and all other nodes in the chain to the layer of the target. + * + * @param layer New value of the layer constraints + * @chain Nodes of the chain the moved node is in + */ + def reevaluateLayerConstraintsInChain(int layer, List chain) { + for (n : chain) { + if (n.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) != -1) { + changedNodes.put(new ConstraintProperty(n, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), layer) + } + } + } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend index 67e18d96a..0bf74f07b 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2019, 2020 by + * Copyright 2019-2022 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -24,7 +24,7 @@ import org.eclipse.sprotty.Action /** * Handles all sprotty actions for the layered interactive algorithm. * - * @author sdo + * @author sdo, jep */ class LayeredInteractiveActionHandler extends AbstractActionHandler { @@ -38,7 +38,12 @@ class LayeredInteractiveActionHandler extends AbstractActionHandler { SetLayerConstraintAction.KIND -> SetLayerConstraintAction, DeleteStaticConstraintAction.KIND -> DeleteStaticConstraintAction, DeletePositionConstraintAction.KIND -> DeletePositionConstraintAction, - DeleteLayerConstraintAction.KIND -> DeleteLayerConstraintAction + DeleteLayerConstraintAction.KIND -> DeleteLayerConstraintAction, + SetILPredOfConstraintAction.KIND -> SetILPredOfConstraintAction, + SetILSuccOfConstraintAction.KIND -> SetILSuccOfConstraintAction, + DeleteRelativeConstraintsAction.KIND -> DeleteRelativeConstraintsAction, + DeleteILPredOfConstraintAction.KIND -> DeleteILPredOfConstraintAction, + DeleteILSuccOfConstraintAction.KIND -> DeleteILSuccOfConstraintAction ) } @@ -67,6 +72,26 @@ class LayeredInteractiveActionHandler extends AbstractActionHandler { synchronized (server.modelLock) { constraintLS.deleteLayerConstraint(action.constraint, clientId) } + } else if (action instanceof SetILPredOfConstraintAction) { + synchronized (server.modelLock) { + constraintLS.setILPredOfConstraint(action.constraint, clientId) + } + } else if (action instanceof SetILSuccOfConstraintAction) { + synchronized (server.modelLock) { + constraintLS.setILSuccOfConstraint(action.constraint, clientId) + } + } else if (action instanceof DeleteRelativeConstraintsAction) { + synchronized (server.modelLock) { + constraintLS.deleteRelativeConstraints(action.constraint, clientId) + } + } else if (action instanceof DeleteILPredOfConstraintAction) { + synchronized (server.modelLock) { + constraintLS.deleteILPredOfConstraint(action.constraint, clientId) + } + } else if (action instanceof DeleteILSuccOfConstraintAction) { + synchronized (server.modelLock) { + constraintLS.deleteILSuccOfConstraint(action.constraint, clientId) + } } else { throw new IllegalArgumentException("Action " + action.kind + " not supported by handler " + this.class.simpleName) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index fa9819f16..75a0655dd 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2019, 2020 by + * Copyright 2019-2022 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -39,6 +39,8 @@ import org.eclipse.lsp4j.TextEdit import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension +import de.cau.cs.kieler.klighd.lsp.interactive.RelativeConstraintProperty +//import de.cau.cs.kieler.sccharts.impl.StateImpl /** * Language server extension to change the layered algorithm in the interactive mode. @@ -60,6 +62,157 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens // Not implemented, since it is not needed. } + /** + * Sets a 'in layer predecessor'-constraint. + * @param cons the constraint + * @param clientId the client id + */ + def setILPredOfConstraint(ILPredOfConstraint cons, String clientId) { + val uri = diagramState.getURIString(clientId) + setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, uri, cons.id, + cons.otherNode) + } + + /** + * Sets a 'in layer successor'-constraint. + * @param cons the constraint + * @param clientId the client id + */ + def setILSuccOfConstraint(ILSuccOfConstraint cons, String clientId) { + val uri = diagramState.getURIString(clientId) + setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, uri, cons.id, + cons.otherNode) + } + + /** + * Delete relative constraints. + * @param dc the constraint to delete + * @param clientId the client id + */ + def deleteRelativeConstraints(DeleteConstraint dc, String clientId) { + val uri = diagramState.getURIString(clientId) + val kNode = getKNode(uri, dc.id) + if (kNode !== null) { + val changedNodes = newHashMap() + changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) + changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) + refreshModelInEditorForRC(changedNodes, uri) + } + } + + /** + * Delete iLPredOf constraints. + * @param dc the constraint to delete + * @param clientId the client id + */ + def deleteILPredOfConstraint(DeleteConstraint dc, String clientId) { + val uri = diagramState.getURIString(clientId) + val kNode = getKNode(uri, dc.id) + if (kNode !== null) { + val changedNodes = newHashMap() + changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) + refreshModelInEditorForRC(changedNodes, uri) + } + } + + /** + * Delete iLSuccOf constraints. + * @param dc the constraint to delete + * @param clientId the client id + */ + def deleteILSuccOfConstraint(DeleteConstraint dc, String clientId) { + val uri = diagramState.getURIString(clientId) + val kNode = getKNode(uri, dc.id) + if (kNode !== null) { + val changedNodes = newHashMap() + changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) + refreshModelInEditorForRC(changedNodes, uri) + } + } + + /** + * sets a relative constraint with a chosen {@code value} on the node that is specified by the {@code targetID}. + * + * @param PropID the type of constraint that should be set (ILPredOfConstraint or ILSuccOfConstraint) + * The IProperty class is expected. + * @param uri The uri of the diagram/file. + * @param targetId The id of the node on which the constraint should be set. + * @param node the id of the node to which the relation should be set. + */ + private def setRelativeConstraint(IProperty property, String uri, String targetId, String node) { + val kNode = LSPUtil.getKNode(diagramState, uri, targetId) + val parentOfNode = kNode.parent + + // get the actual label of the node + val otherNode = LSPUtil.getKNode(diagramState, uri, node) + + val test = otherNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + var value = "" + // FIXME +// if (test instanceof StateImpl) { +// value = test.name +// } else + if (test instanceof ElkNode) { + value = otherNode.labels.get(0).text + } + + if (kNode !== null && parentOfNode !== null) { + var layerID = otherNode.getProperty(LayeredOptions.LAYERING_LAYER_ID); + var posID = otherNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID); + if (layerID === kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) + && posID > kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + posID--; + } + if (property === LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) { + posID++; + } + var layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) + var oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children) + + // update position constraints + val layerSwap = layerID !== kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) + var relReval = new RelativeConstraintReevaluation(kNode) + var reval = new LayeredConstraintReevaluation(kNode) + + kNode.setProperty(property, null); + var List chain = InteractiveUtil.getChain(kNode, oldLayerNodes) + + if (layerSwap) { + reval.reevaluatePositionConstraintsAfterLayerSwap(layerNodes, oldLayerNodes, kNode, posID) + reval.reevaluateLayerConstraintsInChain(layerID, chain) + } else { + if (posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + && chain.contains(otherNode) + && posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + && posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + // node is moved within its chain + relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) + } + reval.reevaluatePositionConstraintsAfterPosChangeInLayer(layerNodes, kNode, posID) + } + + var posCons = posID + if (layerSwap || posID < kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + // posID must be increased by the number of predecessors + posCons = posID + chain.indexOf(kNode) + } + + reval.reevaluatePosConsInChain(kNode, posCons, chain) + if (!reval.changedNodes.isEmpty) { + refreshModelInEditor(reval.changedNodes, uri) + } + + // update relative constraints + if (layerSwap || posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + relReval.checkRelCons(kNode, posID, layerNodes, oldLayerNodes, property) + relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) + } + val relChangedNodes = relReval.changedNodes + relChangedNodes.put(new RelativeConstraintProperty(kNode, property), value) + refreshModelInEditorForRC(relChangedNodes, uri) + } + } + /** * Sets a layer constraint. * @param lc the layer constraint @@ -103,15 +256,18 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens */ var allNodes = parentOfNode.children var newLayerId = sc.layer - val newPosId = sc.position - val newPosCons = sc.posCons var newLayerCons = sc.layerCons val layerId = kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) var targetLayerNodes = InteractiveUtil.getNodesOfLayer(newLayerId, allNodes) var oldLayerNodes = InteractiveUtil.getNodesOfLayer(layerId, allNodes) - + + val chain = InteractiveUtil.getChain(kNode, oldLayerNodes) + // posID must be increased by the number of predecessors + val newPosId = sc.position + chain.indexOf(kNode) + val newPosCons = sc.posCons + chain.indexOf(kNode) + // Reevaluate insertion of node to target layer var reval = new LayeredConstraintReevaluation(kNode) @@ -119,12 +275,22 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens newLayerCons-- } reval.reevaluatePositionConstraintsAfterLayerSwap(targetLayerNodes, oldLayerNodes, kNode, newPosId) + reval.reevaluateLayerConstraintsInChain(newLayerCons, chain) + reval.reevaluatePosConsInChain(kNode, newPosCons, chain) var changedNodes = reval.changedNodes changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), newPosCons) changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), newLayerCons) // Update source code of the model refreshModelInEditor(changedNodes, uri) + + // update relative constraints + var relReval = new RelativeConstraintReevaluation(kNode) + relReval.reevaluateRelCons(kNode, newPosId, targetLayerNodes, oldLayerNodes) + val relChangedNodes = relReval.changedNodes + if (!relChangedNodes.isEmpty) { + refreshModelInEditorForRC(relChangedNodes, uri) + } } } @@ -190,18 +356,54 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens if (kNode !== null && parentOfNode !== null) { var layerID = kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) - var List residingLayer - residingLayer = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) - + var posID = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT); + if (property === LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) { + layerID = valueId + } + + var List layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) + val oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children) + var newValueCons = valueCons + var newValueId = valueId + val oldPos = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + + var relReval = new RelativeConstraintReevaluation(kNode) + val chain = InteractiveUtil.getChain(kNode, oldLayerNodes) + if (property === LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) { + posID = valueId + if (posID != -1 && posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + && posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + // node is moved within its chain + relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) + } else if (posID < oldPos) { + // posID must be increased by the number of predecessors + newValueCons += chain.indexOf(kNode) + newValueId += chain.indexOf(kNode) + } + } + var reval = new LayeredConstraintReevaluation(kNode) switch (property) { - case LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT: - reval.reevaluatePositionConstraintsAfterPosChangeInLayer(residingLayer, kNode, valueId) + case LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT: { + reval.reevaluatePositionConstraintsAfterPosChangeInLayer(layerNodes, kNode, newValueId) + reval.reevaluatePosConsInChain(kNode, newValueCons, chain) + } + case LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT: + reval.reevaluateLayerConstraintsInChain(layerID, chain) } var changedNodes = reval.changedNodes - changedNodes.put(new ConstraintProperty(kNode, property), valueCons) + changedNodes.put(new ConstraintProperty(kNode, property), newValueCons) refreshModelInEditor(changedNodes, uri) + + // update relative constraints + if (posID != -1) { + relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) + val relChangedNodes = relReval.changedNodes + if (!relChangedNodes.isEmpty) { + refreshModelInEditorForRC(relChangedNodes, uri) + } + } } } @@ -237,22 +439,68 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens var changed = false for (entry : changedNodes.keySet) { - // set Property of corresponding elkNode + // set Property/annotation of corresponding model element val kNode = entry.KNode - val elkNode = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - - if (elkNode instanceof ElkNode) { + val node = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + + if (node instanceof ElkNode /*FIXME || node instanceof StateImpl*/) { val value = changedNodes.get(entry) if (kNode.getProperty(entry.property) !== value) { kNode.setProperty(entry.property, value) - InteractiveUtil.copyAllConstraints(elkNode, kNode) + InteractiveUtil.copyAllConstraints(node, kNode) changed = true; } } } - val elkNode = changedNodes.keySet().head.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (elkNode instanceof ElkNode && changed) { + if (changed) { + val Map> changes = newHashMap + + // Get changed file as String + outputStream = new ByteArrayOutputStream + resource.save(outputStream, emptyMap) + val String codeAfter = outputStream.toString().trim + // The range is the length of the previous file. + val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) + val TextEdit textEdit = new TextEdit(range, codeAfter) + changes.put(uri, #[textEdit]); + this.client.replaceContentInFile(uri, codeAfter, range) + return + } else { + languageServer.updateDiagram(uri) + } + } + + + /** + * Sends request to the client to update the file according to the property changes. + * + * @param changedNodes list of all changes to nodes + * @param uri uri of resource + */ + def refreshModelInEditorForRC(HashMap changedNodes, String uri) { + val resource = languageServer.getResource(uri) + + // Get previous file content as String + var outputStream = new ByteArrayOutputStream + resource.save(outputStream, emptyMap) + val codeBefore = outputStream.toString + + var changed = false + for (entry : changedNodes.keySet) { + // set Property/annotation of corresponding model element + val kNode = entry.KNode + val node = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + // FIXME + if (node instanceof ElkNode /*|| node instanceof StateImpl*/) { + val value = changedNodes.get(entry) + kNode.setProperty(entry.property, value) + InteractiveUtil.copyAllConstraints(node, kNode) + changed = true; + } + } + + if (changed) { val Map> changes = newHashMap // Get changed file as String diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend new file mode 100644 index 000000000..dc10afa8b --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend @@ -0,0 +1,147 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive.layered + +import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil +import de.cau.cs.kieler.klighd.lsp.interactive.RelativeConstraintProperty +import java.util.HashMap +import java.util.List +import org.eclipse.elk.alg.layered.options.LayeredOptions +import org.eclipse.elk.graph.properties.IProperty +import org.eclipse.xtend.lib.annotations.Accessors + +/** + * @author jep + */ +class RelativeConstraintReevaluation { + + IProperty predProp = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF + IProperty succProp = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF + + @Accessors(PUBLIC_GETTER) + HashMap changedNodes = newHashMap() + + @Accessors(PUBLIC_GETTER) + KNode target + + new(KNode target) { + this.target = target + } + + /** + * When a node is moved between two other nodes, the relative constraints of them must be updated. + * + * @param target The moved node + * @param newPos The position {@code target} is moved to + * @param newLayerNodes Nodes of the layer {@code target} is moved to + * @param oldLayerNodes Nodes of the layer {@code target} was original in + */ + def reevaluateRelCons(KNode target, int newPos, List newLayerNodes, List oldLayerNodes) { + val chainNodes = InteractiveUtil.getChain(target, oldLayerNodes) + var startOfChain = chainNodes.get(0) + var endOfChain = chainNodes.get(chainNodes.size - 1) + var pos = newPos + // determine pos of new successor + if (newLayerNodes.contains(target)) { + val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + if (newPos > oldPos) { + pos++ + } + } + + if (pos > 0 && pos < newLayerNodes.size) { + // update rel cons of the new pred and succ + val predNode = newLayerNodes.get(pos - 1) + val succNode = newLayerNodes.get(pos) + if (predNode.getProperty(predProp) !== null) { + changedNodes.put(new RelativeConstraintProperty(predNode, predProp), startOfChain.labels.get(0).text) + } + if (succNode.getProperty(succProp) !== null) { + changedNodes.put(new RelativeConstraintProperty(succNode, succProp), endOfChain.labels.get(0).text) + } + } + } + + /** + * Updates relative constraints that have the moved node as target and of the target. + * + * @param target The moved node + * @param newPos The position {@code target} is moved to + * @param newLayerNodes Nodes of the layer {@code target} is moved to + * @param oldLayerNodes Nodes of the layer {@code target} was original in + */ + def checkRelCons(KNode target, int newPos, List newLayerNodes, List oldLayerNodes, IProperty prop) { + val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + var forbidden = false + // delete relative constraints that are overwritten by new rel cons of the target + switch(prop) { + case predProp: { + if (oldPos + 1 < oldLayerNodes.size) { + changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) + } + // if the chains can not be merged, delete old rel cons and only merge moved node with chain + val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos), newLayerNodes) + forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) + if (forbidden) { + if (oldPos - 1 >= 0) { + changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) + } + changedNodes.put(new RelativeConstraintProperty(target, succProp), null) + } + } + case succProp: { + if (oldPos - 1 >= 0) { + changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) + } + // if the chains can not be merged, delete old rel cons and only merge moved node with chain + val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos - 1), newLayerNodes) + forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) + if (forbidden) { + if (oldPos + 1 < oldLayerNodes.size) { + changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) + } + changedNodes.put(new RelativeConstraintProperty(target, predProp), null) + } + } + } + } + + /** + * Reevaluates relative constraints after a node is moved within its chain. + * @param target The moved node + * @param layerNodes The nodes that are in the same layer as {@code target} + */ + def reevaluateRCAfterSwapInChain(KNode target, List layerNodes) { + // remove rel cons of target + changedNodes.put(new RelativeConstraintProperty(target, predProp), null) + changedNodes.put(new RelativeConstraintProperty(target, succProp), null) + // must be done in order for correct calculation of the chain in later reevaluation + target.setProperty(predProp, null) + target.setProperty(succProp, null) + + // remove rel cons of pred and succ that could have the moved node as target + val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + if (oldPos - 1 >= 0) { + val oldPred = layerNodes.get(oldPos - 1) + oldPred.setProperty(predProp, null) + changedNodes.put(new RelativeConstraintProperty(oldPred, predProp), null) + } + if (oldPos + 1 < layerNodes.size) { + val oldSucc = layerNodes.get(oldPos + 1) + changedNodes.put(new RelativeConstraintProperty(oldSucc, succProp), null) + oldSucc.setProperty(succProp, null) + } + } + +} \ No newline at end of file From 5f964c7ecd4c631881abc976fa93d9f94ec989f7 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Thu, 20 Oct 2022 16:37:29 +0200 Subject: [PATCH 02/27] Readded serialization of constraint for ElkNodes. --- ...ighd.lsp.interactive.IConstraintSerializer | 1 + .../lsp/ElkGraphConstraintSerializer.xtend | 77 +++++++ .../lsp/interactive/ConstraintProperty.xtend | 4 +- .../interactive/IConstraintSerializer.xtend | 42 ++++ .../RelativeConstraintProperty.xtend | 28 --- .../LayeredConstraintReevaluation.xtend | 2 +- ...edInteractiveLanguageServerExtension.xtend | 212 ++++++++---------- .../RelativeConstraintReevaluation.xtend | 28 +-- 8 files changed, 229 insertions(+), 165 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend delete mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer new file mode 100644 index 000000000..e09a76c3d --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer @@ -0,0 +1 @@ +de.cau.cs.kieler.klighd.lsp.ElkGraphConstraintSerializer \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend new file mode 100644 index 000000000..a2b441e56 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend @@ -0,0 +1,77 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp + +import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty +import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer +import java.io.ByteArrayOutputStream +import java.util.HashMap +import java.util.List +import java.util.Map +import org.eclipse.elk.graph.ElkNode +import org.eclipse.lsp4j.Position +import org.eclipse.lsp4j.Range +import org.eclipse.lsp4j.TextEdit + +/** + * Serializes constraint for an ELK graph by just adding the corresponding properties. + * + * @author sdo + * + */ +class ElkGraphConstraintSerializer implements IConstraintSerializer { + + override canHandle(Object graph) { + return graph instanceof ElkNode + } + + override serializeConstraints(HashMap, Integer> changedNodes, + HashMap, String> relChangedNodes, + Object graph, + String uri, + KGraphLanguageServerExtension ls, + KGraphLanguageClient client + ) { + changedNodes.forEach[c, index| + val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) as ElkNode + elkNode.setProperty(c.property, index) + ] + relChangedNodes.forEach[c, index| + val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) as ElkNode + elkNode.setProperty(c.property, index) + ] + // Serialize model into given uri. + val resource = ls.getResource(uri) + + // Get previous file content as String + var outputStream = new ByteArrayOutputStream + resource.save(outputStream, emptyMap) + val codeBefore = outputStream.toString + val Map> changes = newHashMap + // Get changed file as String + outputStream = new ByteArrayOutputStream + resource.save(outputStream, emptyMap) + val String codeAfter = outputStream.toString().trim + + // The range is the length of the previous file. + // Just make sure the range is big enough + val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length * 2, 0)) + val TextEdit textEdit = new TextEdit(range, codeAfter) + changes.put(uri, #[textEdit]); + client.replaceContentInFile(uri, codeAfter, range) + } + +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend index 68f6cc5e9..d66075245 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend @@ -26,7 +26,7 @@ import de.cau.cs.kieler.klighd.kgraph.KNode * @author sdo */ @Data -class ConstraintProperty { +class ConstraintProperty { KNode kNode - IProperty property + IProperty property } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend new file mode 100644 index 000000000..fa08e93d6 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend @@ -0,0 +1,42 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive + +import java.util.HashMap +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient + +/** + * Service interface for implementions that serialize a set constraint in the model. + * E.g. for ElkGraphs a property is added and the graph serialized, + * for SCCharts an Annotation with a layout constraint is added and the graph serialized. + * + * @author sdo + * + */ +interface IConstraintSerializer { + /** + * Checks whether this serializer can handle a graph type + * + * @param graph The graph to serialize + * @return true if the graph can be serialized + */ + def boolean canHandle(Object graph); + + /** + * @param + */ + def void serializeConstraints(HashMap, Integer> changedNodes, + HashMap, String> relChangedNodes, Object graph, String uri, + KGraphLanguageServerExtension ls, KGraphLanguageClient client); +} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend deleted file mode 100644 index 2b6dc52f8..000000000 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/RelativeConstraintProperty.xtend +++ /dev/null @@ -1,28 +0,0 @@ -/* - * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * - * http://rtsys.informatik.uni-kiel.de/kieler - * - * Copyright 2022 by - * + Kiel University - * + Department of Computer Science - * + Real-Time and Embedded Systems Group - * - * This code is provided under the terms of the Eclipse Public License (EPL). - */ -package de.cau.cs.kieler.klighd.lsp.interactive - -import org.eclipse.xtend.lib.annotations.Data -import de.cau.cs.kieler.klighd.kgraph.KNode -import org.eclipse.elk.graph.properties.IProperty - -/** - * A data class for the layered interactive relative constraints sent from client to server. - * - * @author jep - */ -@Data -class RelativeConstraintProperty { - KNode kNode - IProperty property -} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index 591ec89a0..f54321e20 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -34,7 +34,7 @@ import org.eclipse.xtend.lib.annotations.Accessors class LayeredConstraintReevaluation { @Accessors(PUBLIC_GETTER) - HashMap changedNodes = newHashMap() + HashMap, Integer> changedNodes = newHashMap() @Accessors(PUBLIC_GETTER) KNode target diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index 75a0655dd..933faa02a 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -19,27 +19,27 @@ package de.cau.cs.kieler.klighd.lsp.interactive.layered import com.google.inject.Inject import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil import de.cau.cs.kieler.klighd.lsp.KGraphDiagramState import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.LSPUtil import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil -import java.io.ByteArrayOutputStream import java.util.HashMap import java.util.List -import java.util.Map import javax.inject.Singleton import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty -import org.eclipse.lsp4j.Position -import org.eclipse.lsp4j.Range -import org.eclipse.lsp4j.TextEdit import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension -import de.cau.cs.kieler.klighd.lsp.interactive.RelativeConstraintProperty +import org.eclipse.xtext.util.CancelIndicator +import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer +import java.util.ServiceLoader +import de.cau.cs.kieler.klighd.KlighdDataManager + //import de.cau.cs.kieler.sccharts.impl.StateImpl /** @@ -70,7 +70,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens def setILPredOfConstraint(ILPredOfConstraint cons, String clientId) { val uri = diagramState.getURIString(clientId) setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, uri, cons.id, - cons.otherNode) + cons.otherNode, clientId) } /** @@ -81,7 +81,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens def setILSuccOfConstraint(ILSuccOfConstraint cons, String clientId) { val uri = diagramState.getURIString(clientId) setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, uri, cons.id, - cons.otherNode) + cons.otherNode, clientId) } /** @@ -94,9 +94,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val kNode = getKNode(uri, dc.id) if (kNode !== null) { val changedNodes = newHashMap() - changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) - changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) - refreshModelInEditorForRC(changedNodes, uri) + changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) + changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) + refreshModelInEditor(newHashMap, changedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -110,8 +110,8 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val kNode = getKNode(uri, dc.id) if (kNode !== null) { val changedNodes = newHashMap() - changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) - refreshModelInEditorForRC(changedNodes, uri) + changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) + refreshModelInEditor(newHashMap, changedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -125,8 +125,8 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val kNode = getKNode(uri, dc.id) if (kNode !== null) { val changedNodes = newHashMap() - changedNodes.put(new RelativeConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) - refreshModelInEditorForRC(changedNodes, uri) + changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) + refreshModelInEditor(newHashMap, changedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -139,7 +139,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param targetId The id of the node on which the constraint should be set. * @param node the id of the node to which the relation should be set. */ - private def setRelativeConstraint(IProperty property, String uri, String targetId, String node) { + private def setRelativeConstraint(IProperty property, String uri, String targetId, String node, String clientId) { val kNode = LSPUtil.getKNode(diagramState, uri, targetId) val parentOfNode = kNode.parent @@ -149,6 +149,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val test = otherNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) var value = "" // FIXME + // Add service interface to get id of node // if (test instanceof StateImpl) { // value = test.name // } else @@ -198,9 +199,6 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens } reval.reevaluatePosConsInChain(kNode, posCons, chain) - if (!reval.changedNodes.isEmpty) { - refreshModelInEditor(reval.changedNodes, uri) - } // update relative constraints if (layerSwap || posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { @@ -208,8 +206,8 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) } val relChangedNodes = relReval.changedNodes - relChangedNodes.put(new RelativeConstraintProperty(kNode, property), value) - refreshModelInEditorForRC(relChangedNodes, uri) + relChangedNodes.put(new ConstraintProperty(kNode, property), value) + refreshModelInEditor(reval.changedNodes, relChangedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -220,7 +218,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens */ def setLayerConstraint(LayerConstraint lc, String clientId) { val uri = diagramState.getURIString(clientId) - setConstraint(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, uri, lc.id, lc.layer, lc.layerCons) + setConstraint(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, uri, lc.id, lc.layer, lc.layerCons, clientId) } /** @@ -231,7 +229,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens def setPositionConstraint(PositionConstraint pc, String clientId) { val uri = diagramState.getURIString(clientId) setConstraint(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, uri, pc.id, - pc.position, pc.posCons) + pc.position, pc.posCons, clientId) } /** @@ -282,15 +280,12 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), newPosCons) changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), newLayerCons) // Update source code of the model - refreshModelInEditor(changedNodes, uri) // update relative constraints var relReval = new RelativeConstraintReevaluation(kNode) relReval.reevaluateRelCons(kNode, newPosId, targetLayerNodes, oldLayerNodes) val relChangedNodes = relReval.changedNodes - if (!relChangedNodes.isEmpty) { - refreshModelInEditorForRC(relChangedNodes, uri) - } + refreshModelInEditor(changedNodes, relChangedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -306,7 +301,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val changedNodes = newHashMap() changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), null) changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), null) - refreshModelInEditor(changedNodes, uri) + refreshModelInEditor(changedNodes, newHashMap, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -321,7 +316,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens if (kNode !== null) { val changedNodes = newHashMap() changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), null) - refreshModelInEditor(changedNodes, uri) + refreshModelInEditor(changedNodes, newHashMap, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -336,7 +331,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens if (kNode !== null) { val changedNodes = newHashMap() changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), null) - refreshModelInEditor(changedNodes, uri) + refreshModelInEditor(changedNodes, newHashMap, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -350,7 +345,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param targetId The id of the node on which the constraint should be set. * @param value Either the id of the position or the id of the layer. */ - private def setConstraint(IProperty property, String uri, String targetId, int valueId, int valueCons) { + private def setConstraint(IProperty property, String uri, String targetId, int valueId, int valueCons, String clientId) { val kNode = LSPUtil.getKNode(diagramState, uri, targetId) val parentOfNode = kNode.parent @@ -394,16 +389,14 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens var changedNodes = reval.changedNodes changedNodes.put(new ConstraintProperty(kNode, property), newValueCons) - refreshModelInEditor(changedNodes, uri) // update relative constraints + var relChangedNodes = newHashMap if (posID != -1) { relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) - val relChangedNodes = relReval.changedNodes - if (!relChangedNodes.isEmpty) { - refreshModelInEditorForRC(relChangedNodes, uri) - } + relChangedNodes = relReval.changedNodes } + refreshModelInEditor(changedNodes, relChangedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) } } @@ -429,92 +422,71 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param changedNodes list of all changes to nodes * @param uri uri of resource */ - def refreshModelInEditor(HashMap changedNodes, String uri) { - val resource = languageServer.getResource(uri) - - // Get previous file content as String - var outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeBefore = outputStream.toString - - var changed = false - for (entry : changedNodes.keySet) { - // set Property/annotation of corresponding model element - val kNode = entry.KNode - val node = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - - if (node instanceof ElkNode /*FIXME || node instanceof StateImpl*/) { - val value = changedNodes.get(entry) - if (kNode.getProperty(entry.property) !== value) { - kNode.setProperty(entry.property, value) - InteractiveUtil.copyAllConstraints(node, kNode) - changed = true; - } - } - } - - if (changed) { - val Map> changes = newHashMap - - // Get changed file as String - outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val String codeAfter = outputStream.toString().trim - // The range is the length of the previous file. - val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) - val TextEdit textEdit = new TextEdit(range, codeAfter) - changes.put(uri, #[textEdit]); - this.client.replaceContentInFile(uri, codeAfter, range) - return - } else { - languageServer.updateDiagram(uri) - } - } - - - /** - * Sends request to the client to update the file according to the property changes. - * - * @param changedNodes list of all changes to nodes - * @param uri uri of resource - */ - def refreshModelInEditorForRC(HashMap changedNodes, String uri) { - val resource = languageServer.getResource(uri) - - // Get previous file content as String - var outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeBefore = outputStream.toString - - var changed = false - for (entry : changedNodes.keySet) { - // set Property/annotation of corresponding model element - val kNode = entry.KNode - val node = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - // FIXME - if (node instanceof ElkNode /*|| node instanceof StateImpl*/) { - val value = changedNodes.get(entry) - kNode.setProperty(entry.property, value) - InteractiveUtil.copyAllConstraints(node, kNode) - changed = true; + def refreshModelInEditor(HashMap, Integer> changedNodes, + HashMap, String> relChangedNodes, + KNode model, String uri, String clientId + ) { + changedNodes.forEach[constraint, index| + val KNode kNode = constraint.KNode + kNode.setProperty(constraint.property, index) + ] + relChangedNodes.forEach[constraint, id| + val KNode kNode = constraint.KNode + kNode.setProperty(constraint.property, id) + ] + var serializer = false + for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, + KlighdDataManager.getClassLoader())) { + val sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + if (cs.canHandle(sourceModel)) { + changedNodes.forEach[c, i |] + cs.serializeConstraints(changedNodes, relChangedNodes, model, uri, languageServer, client) + serializer = true } } - - if (changed) { - val Map> changes = newHashMap - - // Get changed file as String - outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val String codeAfter = outputStream.toString().trim - // The range is the length of the previous file. - val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) - val TextEdit textEdit = new TextEdit(range, codeAfter) - changes.put(uri, #[textEdit]); - this.client.replaceContentInFile(uri, codeAfter, range) - return - } else { - languageServer.updateDiagram(uri) + if (!serializer) { + languageServer.updateLayout(uri) } +// languageServer.showSnapshot(uri, clientId, model, CancelIndicator.NullImpl, true) +// val resource = languageServer.getResource(uri) +// +// // Get previous file content as String +// var outputStream = new ByteArrayOutputStream +// resource.save(outputStream, emptyMap) +// val codeBefore = outputStream.toString +// +// var changed = false +// for (entry : changedNodes.keySet) { +// // set Property/annotation of corresponding model element +// val kNode = entry.KNode +// val node = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) +// +// if (node instanceof ElkNode /*FIXME || node instanceof StateImpl*/) { +// val value = changedNodes.get(entry) +// if (kNode.getProperty(entry.property) !== value) { +// kNode.setProperty(entry.property, value) +// InteractiveUtil.copyAllConstraints(node, kNode) +// changed = true; +// } +// } +// } +// +// if (changed) { +// val Map> changes = newHashMap +// +// // Get changed file as String +// outputStream = new ByteArrayOutputStream +// resource.save(outputStream, emptyMap) +// val String codeAfter = outputStream.toString().trim +// // The range is the length of the previous file. +// val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) +// val TextEdit textEdit = new TextEdit(range, codeAfter) +// changes.put(uri, #[textEdit]); +// this.client.replaceContentInFile(uri, codeAfter, range) +// return +// } else { +// languageServer.updateDiagram(uri) +// } + return } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend index dc10afa8b..4751b132f 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend @@ -13,8 +13,8 @@ package de.cau.cs.kieler.klighd.lsp.interactive.layered import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil -import de.cau.cs.kieler.klighd.lsp.interactive.RelativeConstraintProperty import java.util.HashMap import java.util.List import org.eclipse.elk.alg.layered.options.LayeredOptions @@ -30,7 +30,7 @@ class RelativeConstraintReevaluation { IProperty succProp = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF @Accessors(PUBLIC_GETTER) - HashMap changedNodes = newHashMap() + HashMap, String> changedNodes = newHashMap() @Accessors(PUBLIC_GETTER) KNode target @@ -65,10 +65,10 @@ class RelativeConstraintReevaluation { val predNode = newLayerNodes.get(pos - 1) val succNode = newLayerNodes.get(pos) if (predNode.getProperty(predProp) !== null) { - changedNodes.put(new RelativeConstraintProperty(predNode, predProp), startOfChain.labels.get(0).text) + changedNodes.put(new ConstraintProperty(predNode, predProp), startOfChain.labels.get(0).text) } if (succNode.getProperty(succProp) !== null) { - changedNodes.put(new RelativeConstraintProperty(succNode, succProp), endOfChain.labels.get(0).text) + changedNodes.put(new ConstraintProperty(succNode, succProp), endOfChain.labels.get(0).text) } } } @@ -88,30 +88,30 @@ class RelativeConstraintReevaluation { switch(prop) { case predProp: { if (oldPos + 1 < oldLayerNodes.size) { - changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) + changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) } // if the chains can not be merged, delete old rel cons and only merge moved node with chain val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos), newLayerNodes) forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) if (forbidden) { if (oldPos - 1 >= 0) { - changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) + changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) } - changedNodes.put(new RelativeConstraintProperty(target, succProp), null) + changedNodes.put(new ConstraintProperty(target, succProp), null) } } case succProp: { if (oldPos - 1 >= 0) { - changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) + changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) } // if the chains can not be merged, delete old rel cons and only merge moved node with chain val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos - 1), newLayerNodes) forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) if (forbidden) { if (oldPos + 1 < oldLayerNodes.size) { - changedNodes.put(new RelativeConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) + changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) } - changedNodes.put(new RelativeConstraintProperty(target, predProp), null) + changedNodes.put(new ConstraintProperty(target, predProp), null) } } } @@ -124,8 +124,8 @@ class RelativeConstraintReevaluation { */ def reevaluateRCAfterSwapInChain(KNode target, List layerNodes) { // remove rel cons of target - changedNodes.put(new RelativeConstraintProperty(target, predProp), null) - changedNodes.put(new RelativeConstraintProperty(target, succProp), null) + changedNodes.put(new ConstraintProperty(target, predProp), null) + changedNodes.put(new ConstraintProperty(target, succProp), null) // must be done in order for correct calculation of the chain in later reevaluation target.setProperty(predProp, null) target.setProperty(succProp, null) @@ -135,11 +135,11 @@ class RelativeConstraintReevaluation { if (oldPos - 1 >= 0) { val oldPred = layerNodes.get(oldPos - 1) oldPred.setProperty(predProp, null) - changedNodes.put(new RelativeConstraintProperty(oldPred, predProp), null) + changedNodes.put(new ConstraintProperty(oldPred, predProp), null) } if (oldPos + 1 < layerNodes.size) { val oldSucc = layerNodes.get(oldPos + 1) - changedNodes.put(new RelativeConstraintProperty(oldSucc, succProp), null) + changedNodes.put(new ConstraintProperty(oldSucc, succProp), null) oldSucc.setProperty(succProp, null) } } From c4cb1818f29b28cc3e2f45a8d8f29444980101dd Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Thu, 20 Oct 2022 18:03:10 +0200 Subject: [PATCH 03/27] Refactored constraints. --- .../lsp/ElkGraphConstraintSerializer.xtend | 11 +- .../lsp/interactive/ConstraintProperty.xtend | 1 + .../interactive/IConstraintSerializer.xtend | 8 +- .../lsp/interactive/InteractiveUtil.xtend | 45 ------ .../LayeredConstraintReevaluation.xtend | 12 +- ...edInteractiveLanguageServerExtension.xtend | 137 ++++++------------ .../RelativeConstraintReevaluation.xtend | 27 ++-- ...ngInteractiveLanguageServerExtension.xtend | 85 ++++------- 8 files changed, 105 insertions(+), 221 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend index a2b441e56..9f0f05eea 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend @@ -38,20 +38,15 @@ class ElkGraphConstraintSerializer implements IConstraintSerializer { return graph instanceof ElkNode } - override serializeConstraints(HashMap, Integer> changedNodes, - HashMap, String> relChangedNodes, + override serializeConstraints(List> changedNodes, Object graph, String uri, KGraphLanguageServerExtension ls, KGraphLanguageClient client ) { - changedNodes.forEach[c, index| + changedNodes.forEach[c| val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) as ElkNode - elkNode.setProperty(c.property, index) - ] - relChangedNodes.forEach[c, index| - val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) as ElkNode - elkNode.setProperty(c.property, index) + elkNode.setProperty(c.property, c.value) ] // Serialize model into given uri. val resource = ls.getResource(uri) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend index d66075245..a7de3a3c0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ConstraintProperty.xtend @@ -29,4 +29,5 @@ import de.cau.cs.kieler.klighd.kgraph.KNode class ConstraintProperty { KNode kNode IProperty property + T value } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend index fa08e93d6..3c2337c69 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend @@ -12,9 +12,10 @@ */ package de.cau.cs.kieler.klighd.lsp.interactive -import java.util.HashMap -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import java.util.HashMap +import java.util.List /** * Service interface for implementions that serialize a set constraint in the model. @@ -36,7 +37,6 @@ interface IConstraintSerializer { /** * @param */ - def void serializeConstraints(HashMap, Integer> changedNodes, - HashMap, String> relChangedNodes, Object graph, String uri, + def void serializeConstraints(List> changedNodes, Object graph, String uri, KGraphLanguageServerExtension ls, KGraphLanguageClient client); } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 4b0376519..7d9f74c14 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -81,45 +81,6 @@ class InteractiveUtil { } } } - - /** - * Copies an arbitrary IProperty of a KNode to a State if the value on the KNode - * is different to the value on the State. - * If the new value on the KNode was the default value of the property - * then the property is set to null on the State. - * @param state The target sate - * @param kNode The source KNode of the property - * @param annotation The annotation that should be set - * @param prop Determines which IProperty should be copied - */ - // FIXME -// static def copyConstraintAnnotations(Annotatable state, KNode kNode, String annotation, IProperty prop) { -// val String value = "" + kNode.getProperty(prop) -// -// val anns = state.getAnnotations().filter(TypedStringAnnotation) -// -// // remove old annotation if it exists -// var TypedStringAnnotation removeA = null -// for (ann : anns) { -// if (ann.type.equals(annotation)) { -// removeA = ann -// } -// } -// if (removeA !== null) { -// state.annotations.remove(removeA) -// } -// -// // add annotation with new value if the value is not the default one -// if (kNode.getProperty(prop) !== null && !kNode.getProperty(prop).equals(prop.^default)) { -// var newA = AnnotationsFactory::eINSTANCE.createTypedStringAnnotation => [ -// it.name = "layout" -// it.type = annotation -// it.values += value -// ] -// state.annotations.add(newA) -// } -// -// } /** * Copies constraint properties depending on the algorithm from kNode to elkNode @@ -162,12 +123,6 @@ class InteractiveUtil { copyConstraintProp(node, kNode, prop) } } - // FIXME -// else if (node instanceof Annotatable) { -// for (var i = 0; i< annos.size; i++) { -// copyConstraintAnnotations(node, kNode, annos.get(i), props.get(i)) -// } -// } } /** diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index f54321e20..67711b1b3 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -34,7 +34,7 @@ import org.eclipse.xtend.lib.annotations.Accessors class LayeredConstraintReevaluation { @Accessors(PUBLIC_GETTER) - HashMap, Integer> changedNodes = newHashMap() + List> changedNodes = newLinkedList() @Accessors(PUBLIC_GETTER) KNode target @@ -124,7 +124,7 @@ class LayeredConstraintReevaluation { for (node : nodes) { val layerCons = ConstraintsUtils.getLayerConstraint(node) if (layerCons >= originalLayerIndex) { - changedNodes.put(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), layerCons - 1) + changedNodes.add(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layerCons - 1)) } } @@ -192,7 +192,7 @@ class LayeredConstraintReevaluation { // Reevaluate the position constraints in the source and target layer accordingly // Also examine the position constraint of the target node if (posCons > 0 && posCons >= posIndexOfShifted) { - changedNodes.put(new ConstraintProperty(targetNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), posCons - 1) + changedNodes.add(new ConstraintProperty(targetNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, posCons - 1)) } } @@ -215,7 +215,7 @@ class LayeredConstraintReevaluation { val posChoiceCons = ConstraintsUtils.getPosConstraint(node) if (node != target && posChoiceCons !== -1) { - changedNodes.put(new ConstraintProperty(node, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), posChoiceCons + offset) + changedNodes.add(new ConstraintProperty(node, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, posChoiceCons + offset)) } } } @@ -247,7 +247,7 @@ class LayeredConstraintReevaluation { val n = chain.get(i) if (n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) !== -1) { val pos = newPos - (offset - i) - changedNodes.put(new ConstraintProperty(n, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), pos) + changedNodes.add(new ConstraintProperty(n, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, pos)) } } } @@ -261,7 +261,7 @@ class LayeredConstraintReevaluation { def reevaluateLayerConstraintsInChain(int layer, List chain) { for (n : chain) { if (n.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) != -1) { - changedNodes.put(new ConstraintProperty(n, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), layer) + changedNodes.add(new ConstraintProperty(n, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layer)) } } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index 933faa02a..acbe64ca9 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -17,6 +17,7 @@ package de.cau.cs.kieler.klighd.lsp.interactive.layered import com.google.inject.Inject +import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil @@ -25,9 +26,11 @@ import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.LSPUtil import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty +import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil -import java.util.HashMap +import java.util.LinkedList import java.util.List +import java.util.ServiceLoader import javax.inject.Singleton import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.graph.ElkNode @@ -35,10 +38,6 @@ import org.eclipse.elk.graph.properties.IProperty import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension -import org.eclipse.xtext.util.CancelIndicator -import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer -import java.util.ServiceLoader -import de.cau.cs.kieler.klighd.KlighdDataManager //import de.cau.cs.kieler.sccharts.impl.StateImpl @@ -93,10 +92,10 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val uri = diagramState.getURIString(clientId) val kNode = getKNode(uri, dc.id) if (kNode !== null) { - val changedNodes = newHashMap() - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) - refreshModelInEditor(newHashMap, changedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = new LinkedList> + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, null)) + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, null)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -109,9 +108,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val uri = diagramState.getURIString(clientId) val kNode = getKNode(uri, dc.id) if (kNode !== null) { - val changedNodes = newHashMap() - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF), null) - refreshModelInEditor(newHashMap, changedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = new LinkedList> + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, null)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -124,9 +123,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val uri = diagramState.getURIString(clientId) val kNode = getKNode(uri, dc.id) if (kNode !== null) { - val changedNodes = newHashMap() - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF), null) - refreshModelInEditor(newHashMap, changedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = new LinkedList> + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, null)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -205,9 +204,10 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens relReval.checkRelCons(kNode, posID, layerNodes, oldLayerNodes, property) relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) } - val relChangedNodes = relReval.changedNodes - relChangedNodes.put(new ConstraintProperty(kNode, property), value) - refreshModelInEditor(reval.changedNodes, relChangedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = reval.changedNodes + changedNodes.addAll(relReval.changedNodes) + changedNodes.add(new ConstraintProperty(kNode, property, value)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -277,15 +277,15 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens reval.reevaluatePosConsInChain(kNode, newPosCons, chain) var changedNodes = reval.changedNodes - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), newPosCons) - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), newLayerCons) + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, newPosCons)) + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, newLayerCons)) // Update source code of the model // update relative constraints var relReval = new RelativeConstraintReevaluation(kNode) relReval.reevaluateRelCons(kNode, newPosId, targetLayerNodes, oldLayerNodes) - val relChangedNodes = relReval.changedNodes - refreshModelInEditor(changedNodes, relChangedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + changedNodes.addAll(relReval.changedNodes) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -298,10 +298,10 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val uri = diagramState.getURIString(clientId) val kNode = getKNode(uri, dc.id) if (kNode !== null) { - val changedNodes = newHashMap() - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), null) - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), null) - refreshModelInEditor(changedNodes, newHashMap, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = new LinkedList> + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, null)) + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, null)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -314,9 +314,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val uri = diagramState.getURIString(clientId) val kNode = getKNode(uri, dc.id) if (kNode !== null) { - val changedNodes = newHashMap() - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT), null) - refreshModelInEditor(changedNodes, newHashMap, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = new LinkedList> + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, null)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -329,9 +329,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val uri = diagramState.getURIString(clientId) val kNode = getKNode(uri, dc.id) if (kNode !== null) { - val changedNodes = newHashMap() - changedNodes.put(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT), null) - refreshModelInEditor(changedNodes, newHashMap, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + val changedNodes = new LinkedList> + changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, null)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -388,15 +388,14 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens } var changedNodes = reval.changedNodes - changedNodes.put(new ConstraintProperty(kNode, property), newValueCons) + changedNodes.add(new ConstraintProperty(kNode, property, newValueCons)) // update relative constraints - var relChangedNodes = newHashMap if (posID != -1) { relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) - relChangedNodes = relReval.changedNodes - } - refreshModelInEditor(changedNodes, relChangedNodes, KGraphUtil.getRootNodeOf(kNode), uri, clientId) + changedNodes.addAll(relReval.changedNodes) + }; + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -420,73 +419,33 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * Sends request to the client to update the file according to the property changes. * * @param changedNodes list of all changes to nodes + * @param relConstraints list of all changed to nodes with relative constraints + * @param model The main kNode * @param uri uri of resource */ - def refreshModelInEditor(HashMap, Integer> changedNodes, - HashMap, String> relChangedNodes, - KNode model, String uri, String clientId + def refreshModelInEditor(List> changedNodes, + KNode model, String uri ) { - changedNodes.forEach[constraint, index| - val KNode kNode = constraint.KNode - kNode.setProperty(constraint.property, index) - ] - relChangedNodes.forEach[constraint, id| + changedNodes.forEach[constraint| val KNode kNode = constraint.KNode - kNode.setProperty(constraint.property, id) + kNode.setProperty(constraint.property, constraint.value) ] var serializer = false + + var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMEMT)) { + sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + } for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, KlighdDataManager.getClassLoader())) { - val sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) if (cs.canHandle(sourceModel)) { - changedNodes.forEach[c, i |] - cs.serializeConstraints(changedNodes, relChangedNodes, model, uri, languageServer, client) + cs.serializeConstraints(changedNodes, model, uri, languageServer, client) serializer = true } } if (!serializer) { languageServer.updateLayout(uri) } -// languageServer.showSnapshot(uri, clientId, model, CancelIndicator.NullImpl, true) -// val resource = languageServer.getResource(uri) -// -// // Get previous file content as String -// var outputStream = new ByteArrayOutputStream -// resource.save(outputStream, emptyMap) -// val codeBefore = outputStream.toString -// -// var changed = false -// for (entry : changedNodes.keySet) { -// // set Property/annotation of corresponding model element -// val kNode = entry.KNode -// val node = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) -// -// if (node instanceof ElkNode /*FIXME || node instanceof StateImpl*/) { -// val value = changedNodes.get(entry) -// if (kNode.getProperty(entry.property) !== value) { -// kNode.setProperty(entry.property, value) -// InteractiveUtil.copyAllConstraints(node, kNode) -// changed = true; -// } -// } -// } -// -// if (changed) { -// val Map> changes = newHashMap -// -// // Get changed file as String -// outputStream = new ByteArrayOutputStream -// resource.save(outputStream, emptyMap) -// val String codeAfter = outputStream.toString().trim -// // The range is the length of the previous file. -// val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) -// val TextEdit textEdit = new TextEdit(range, codeAfter) -// changes.put(uri, #[textEdit]); -// this.client.replaceContentInFile(uri, codeAfter, range) -// return -// } else { -// languageServer.updateDiagram(uri) -// } return } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend index 4751b132f..57d721791 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend @@ -15,7 +15,6 @@ package de.cau.cs.kieler.klighd.lsp.interactive.layered import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil -import java.util.HashMap import java.util.List import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.graph.properties.IProperty @@ -30,7 +29,7 @@ class RelativeConstraintReevaluation { IProperty succProp = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF @Accessors(PUBLIC_GETTER) - HashMap, String> changedNodes = newHashMap() + List> changedNodes = newLinkedList() @Accessors(PUBLIC_GETTER) KNode target @@ -65,10 +64,10 @@ class RelativeConstraintReevaluation { val predNode = newLayerNodes.get(pos - 1) val succNode = newLayerNodes.get(pos) if (predNode.getProperty(predProp) !== null) { - changedNodes.put(new ConstraintProperty(predNode, predProp), startOfChain.labels.get(0).text) + changedNodes.add(new ConstraintProperty(predNode, predProp, startOfChain.labels.get(0).text)) } if (succNode.getProperty(succProp) !== null) { - changedNodes.put(new ConstraintProperty(succNode, succProp), endOfChain.labels.get(0).text) + changedNodes.add(new ConstraintProperty(succNode, succProp, endOfChain.labels.get(0).text)) } } } @@ -88,30 +87,30 @@ class RelativeConstraintReevaluation { switch(prop) { case predProp: { if (oldPos + 1 < oldLayerNodes.size) { - changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp, null)) } // if the chains can not be merged, delete old rel cons and only merge moved node with chain val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos), newLayerNodes) forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) if (forbidden) { if (oldPos - 1 >= 0) { - changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp, null)) } - changedNodes.put(new ConstraintProperty(target, succProp), null) + changedNodes.add(new ConstraintProperty(target, succProp, null)) } } case succProp: { if (oldPos - 1 >= 0) { - changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp), null) + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp, null)) } // if the chains can not be merged, delete old rel cons and only merge moved node with chain val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos - 1), newLayerNodes) forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) if (forbidden) { if (oldPos + 1 < oldLayerNodes.size) { - changedNodes.put(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp), null) + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp, null)) } - changedNodes.put(new ConstraintProperty(target, predProp), null) + changedNodes.add(new ConstraintProperty(target, predProp, null)) } } } @@ -124,8 +123,8 @@ class RelativeConstraintReevaluation { */ def reevaluateRCAfterSwapInChain(KNode target, List layerNodes) { // remove rel cons of target - changedNodes.put(new ConstraintProperty(target, predProp), null) - changedNodes.put(new ConstraintProperty(target, succProp), null) + changedNodes.add(new ConstraintProperty(target, predProp, null)) + changedNodes.add(new ConstraintProperty(target, succProp, null)) // must be done in order for correct calculation of the chain in later reevaluation target.setProperty(predProp, null) target.setProperty(succProp, null) @@ -135,11 +134,11 @@ class RelativeConstraintReevaluation { if (oldPos - 1 >= 0) { val oldPred = layerNodes.get(oldPos - 1) oldPred.setProperty(predProp, null) - changedNodes.put(new ConstraintProperty(oldPred, predProp), null) + changedNodes.add(new ConstraintProperty(oldPred, predProp, null)) } if (oldPos + 1 < layerNodes.size) { val oldSucc = layerNodes.get(oldPos + 1) - changedNodes.put(new ConstraintProperty(oldSucc, succProp), null) + changedNodes.add(new ConstraintProperty(oldSucc, succProp, null)) oldSucc.setProperty(succProp, null) } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend index b7c7bd35a..e818751e0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend @@ -17,17 +17,22 @@ package de.cau.cs.kieler.klighd.lsp.interactive.rectpacking import com.google.inject.Inject +import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil import de.cau.cs.kieler.klighd.lsp.KGraphDiagramState import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.LSPUtil -import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil +import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty +import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer import java.io.ByteArrayOutputStream import java.util.Arrays +import java.util.HashMap import java.util.List import java.util.Map +import java.util.ServiceLoader import javax.inject.Singleton import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions import org.eclipse.elk.core.options.CoreOptions @@ -99,8 +104,8 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx } } } - kNode.setProperty(RectPackingOptions.DESIRED_POSITION, desiredPosition) - refreshModelInEditor(changedNodes, uri) +// kNode.setProperty(RectPackingOptions.DESIRED_POSITION, desiredPosition) + refreshModelInEditor(new ConstraintProperty(kNode, RectPackingOptions.DESIRED_POSITION, desiredPosition), KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -143,7 +148,7 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx } } kNode.setProperty(RectPackingOptions.DESIRED_POSITION, null) - refreshModelInEditor(changedNodes, uri) + refreshModelInEditor(new ConstraintProperty(kNode, RectPackingOptions.DESIRED_POSITION, null), KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -157,69 +162,39 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx def setAspectRatio(SetAspectRatio constraint, String clientId) { val uri = diagramState.getURIString(clientId) val kNode = LSPUtil.getKNode(diagramState, uri, constraint.id) - kNode.setProperty(RectPackingOptions.ASPECT_RATIO, Double.valueOf(constraint.aspectRatio)) - val resource = languageServer.getResource(uri); - - // Get previous file content as String - var outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeBefore = outputStream.toString - - val elkNode = kNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (elkNode instanceof ElkNode) { - val Map> changes = newHashMap - elkNode.setProperty(RectPackingOptions.ASPECT_RATIO, constraint.aspectRatio) - - // Get changed file as String - outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeAfter = outputStream.toString - - // The range is the length of the previous file. - val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) - val TextEdit textEdit = new TextEdit(range, codeAfter) - changes.put(uri, #[textEdit]); - this.client.replaceContentInFile(uri, codeAfter, range) - return - } + refreshModelInEditor(new ConstraintProperty(kNode, RectPackingOptions.ASPECT_RATIO, Double.valueOf(constraint.aspectRatio)), + KGraphUtil.getRootNodeOf(kNode), uri + ) } /** * Applies property changes to the file given by the uri by sending by notifying the client to execute the changes. * * @param changedNodes The KNodes that changed. + * @param model The main KNode * @param uri uri of resource */ - def refreshModelInEditor(List changedNodes, String uri) { - val resource = languageServer.getResource(uri); - - // Get previous file content as String - var outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeBefore = outputStream.toString + def refreshModelInEditor(ConstraintProperty constraint, KNode model, String uri) { + val KNode kNode = constraint.KNode + kNode.setProperty(constraint.property, constraint.value) + var serializer = false - for (node : changedNodes) { - val elkNode = node.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (elkNode instanceof ElkNode) { - InteractiveUtil.copyAllConstraints(elkNode, node) + var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMEMT)) { + sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + } + for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, + KlighdDataManager.getClassLoader())) { + if (cs.canHandle(sourceModel)) { + val constraints = newLinkedList(constraint) + cs.serializeConstraints(constraints, model, uri, languageServer, client) + serializer = true } } - val elkNode = changedNodes.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (elkNode instanceof ElkNode) { - val Map> changes = newHashMap - - // Get changed file as String - outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeAfter = outputStream.toString().trim() - - // The range is the length of the previous file. - val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length, 0)) - val TextEdit textEdit = new TextEdit(range, codeAfter) - changes.put(uri, #[textEdit]); - this.client.replaceContentInFile(uri, codeAfter, range) - return + if (!serializer) { + languageServer.updateLayout(uri) } + return } } From 6135a6bdf0007261411e9e9d0755d8bdeab69bdc Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 21 Oct 2022 13:14:07 +0200 Subject: [PATCH 04/27] Klighd.lsp: Interactive: Added NodeIdProvider. --- ...ler.klighd.lsp.interactive.INodeIdProvider | 1 + .../lsp/ElkGraphConstraintSerializer.xtend | 3 -- .../klighd/lsp/ElkGraphNodeIdProvider.xtend | 34 +++++++++++++++++ .../lsp/interactive/INodeIdProvider.xtend | 37 ++++++++++++++++++ .../lsp/interactive/InteractiveUtil.xtend | 30 +++++++++++++-- ...edInteractiveLanguageServerExtension.xtend | 38 +++++-------------- ...ngInteractiveLanguageServerExtension.xtend | 31 +-------------- 7 files changed, 110 insertions(+), 64 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider new file mode 100644 index 000000000..2f1a688f2 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider @@ -0,0 +1 @@ +de.cau.cs.kieler.klighd.lsp.ElkGraphNodeIdProvider \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend index 9f0f05eea..e49351d3b 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend @@ -13,12 +13,9 @@ package de.cau.cs.kieler.klighd.lsp import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer import java.io.ByteArrayOutputStream -import java.util.HashMap import java.util.List import java.util.Map import org.eclipse.elk.graph.ElkNode diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend new file mode 100644 index 000000000..40c52307b --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend @@ -0,0 +1,34 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp + +import de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider +import org.eclipse.elk.graph.ElkNode + +/** + * Service class that returns the id of ELK nodes. + * + * @author sdo + * + */ +class ElkGraphNodeIdProvider implements INodeIdProvider { + + override canHandle(Object graph) { + return graph instanceof ElkNode + } + + override getNodeId(Object element) { + return (element as ElkNode).labels.get(0).text + } + +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend new file mode 100644 index 000000000..774f6febd --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend @@ -0,0 +1,37 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive + +/** + * Service interface that can provide a node id for a given graph element. + * + * @author sdo + * + */ +interface INodeIdProvider { + /** + * Checks whether this serializer can handle a graph type + * + * @param graph The graph + * @return true if the node provider supports the given graph + */ + def boolean canHandle(Object graph); + + /** + * Returns an id string of a given graph element + * + * @param element The graph element + * @return An id string + */ + def String getNodeId(Object element); +} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 7d9f74c14..d9962d054 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -12,17 +12,19 @@ */ package de.cau.cs.kieler.klighd.lsp.interactive +import de.cau.cs.kieler.klighd.KlighdDataManager +import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KNode import java.util.ArrayList import java.util.List +import java.util.ServiceLoader import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions import org.eclipse.elk.core.options.CoreOptions import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty -//import de.cau.cs.kieler.annotations.Annotatable -//import de.cau.cs.kieler.annotations.TypedStringAnnotation -//import de.cau.cs.kieler.annotations.AnnotationsFactory +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient /** * Provides utility methods for interactive layout. @@ -203,4 +205,26 @@ class InteractiveUtil { return false } + static def serializeConstraints(List> changedNodes, KNode model, String uri, + KGraphLanguageServerExtension languageServer, KGraphLanguageClient client + ) { + var serializer = false + + var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMEMT)) { + sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + } + for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, + KlighdDataManager.getClassLoader())) { + if (cs.canHandle(sourceModel)) { + cs.serializeConstraints(changedNodes, model, uri, languageServer, client) + serializer = true + } + } + if (!serializer) { + languageServer.updateLayout(uri) + } + return + } + } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index acbe64ca9..c44193e59 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -26,7 +26,6 @@ import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.LSPUtil import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty -import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil import java.util.LinkedList import java.util.List @@ -38,6 +37,7 @@ import org.eclipse.elk.graph.properties.IProperty import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension +import de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider //import de.cau.cs.kieler.sccharts.impl.StateImpl @@ -145,15 +145,13 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens // get the actual label of the node val otherNode = LSPUtil.getKNode(diagramState, uri, node) - val test = otherNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + val modelElement = otherNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) var value = "" - // FIXME - // Add service interface to get id of node -// if (test instanceof StateImpl) { -// value = test.name -// } else - if (test instanceof ElkNode) { - value = otherNode.labels.get(0).text + for (INodeIdProvider ip : ServiceLoader.load(INodeIdProvider, + KlighdDataManager.getClassLoader())) { + if (ip.canHandle(modelElement)) { + value = ip.getNodeId(modelElement) + } } if (kNode !== null && parentOfNode !== null) { @@ -419,33 +417,15 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * Sends request to the client to update the file according to the property changes. * * @param changedNodes list of all changes to nodes - * @param relConstraints list of all changed to nodes with relative constraints * @param model The main kNode * @param uri uri of resource */ - def refreshModelInEditor(List> changedNodes, - KNode model, String uri - ) { + def refreshModelInEditor(List> changedNodes, KNode model, String uri) { changedNodes.forEach[constraint| val KNode kNode = constraint.KNode kNode.setProperty(constraint.property, constraint.value) ] - var serializer = false - - var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMEMT)) { - sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - } - for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, - KlighdDataManager.getClassLoader())) { - if (cs.canHandle(sourceModel)) { - cs.serializeConstraints(changedNodes, model, uri, languageServer, client) - serializer = true - } - } - if (!serializer) { - languageServer.updateLayout(uri) - } + InteractiveUtil.serializeConstraints(changedNodes, model, uri, this.languageServer, this.client) return } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend index e818751e0..49dc46a3b 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend @@ -17,8 +17,6 @@ package de.cau.cs.kieler.klighd.lsp.interactive.rectpacking import com.google.inject.Inject -import de.cau.cs.kieler.klighd.KlighdDataManager -import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil import de.cau.cs.kieler.klighd.lsp.KGraphDiagramState @@ -26,20 +24,12 @@ import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import de.cau.cs.kieler.klighd.lsp.LSPUtil import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty -import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer -import java.io.ByteArrayOutputStream +import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil import java.util.Arrays -import java.util.HashMap import java.util.List -import java.util.Map -import java.util.ServiceLoader import javax.inject.Singleton import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions import org.eclipse.elk.core.options.CoreOptions -import org.eclipse.elk.graph.ElkNode -import org.eclipse.lsp4j.Position -import org.eclipse.lsp4j.Range -import org.eclipse.lsp4j.TextEdit import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension @@ -104,7 +94,6 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx } } } -// kNode.setProperty(RectPackingOptions.DESIRED_POSITION, desiredPosition) refreshModelInEditor(new ConstraintProperty(kNode, RectPackingOptions.DESIRED_POSITION, desiredPosition), KGraphUtil.getRootNodeOf(kNode), uri) } @@ -177,23 +166,7 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx def refreshModelInEditor(ConstraintProperty constraint, KNode model, String uri) { val KNode kNode = constraint.KNode kNode.setProperty(constraint.property, constraint.value) - var serializer = false - - var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMEMT)) { - sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - } - for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, - KlighdDataManager.getClassLoader())) { - if (cs.canHandle(sourceModel)) { - val constraints = newLinkedList(constraint) - cs.serializeConstraints(constraints, model, uri, languageServer, client) - serializer = true - } - } - if (!serializer) { - languageServer.updateLayout(uri) - } + InteractiveUtil.serializeConstraints(#[constraint], model, uri, this.languageServer, this.client) return } From 6b43a310b100e9dad394599ffcde824b6bf47240 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 21 Oct 2022 17:02:27 +0200 Subject: [PATCH 05/27] Handle negative layer constraint. --- .../LayeredConstraintReevaluation.xtend | 19 ++++--- ...edInteractiveLanguageServerExtension.xtend | 57 +++++++++++++++++-- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index 67711b1b3..eec0e2526 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -97,7 +97,7 @@ class LayeredConstraintReevaluation { // Offset all positional constraint greater or equal to the new one in order to conserve the // established subsequence of nodes below the removed node val formerPosCons = ConstraintsUtils.getPosConstraint(removedNode) - if (formerPosCons !== -1) { + if (formerPosCons !== null) { offsetPosConstraintsOfLayerFrom(nodesOfLayer, -1, formerPosCons, removedNode) } } @@ -114,7 +114,12 @@ class LayeredConstraintReevaluation { val layerConstraintTarget = ConstraintsUtils.getLayerConstraint(target) val layerId = target.getProperty(LayeredOptions.LAYERING_LAYER_ID) - val originalLayerIndex = if (layerConstraintTarget > layerId) layerConstraintTarget else layerId + var originalLayerIndex = 0 + if (layerConstraintTarget === null || layerConstraintTarget <= layerId) { + originalLayerIndex = layerId + } else { + originalLayerIndex = layerConstraintTarget + } val originalLayer = InteractiveUtil.getNodesOfLayer(originalLayerIndex, nodes) if (originalLayer.length == 1) { @@ -123,7 +128,7 @@ class LayeredConstraintReevaluation { * the disappeared layer need to be decremented*/ for (node : nodes) { val layerCons = ConstraintsUtils.getLayerConstraint(node) - if (layerCons >= originalLayerIndex) { + if (layerCons !== null && layerCons >= originalLayerIndex) { changedNodes.add(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layerCons - 1)) } } @@ -183,7 +188,7 @@ class LayeredConstraintReevaluation { // Get the position of the shiftedNode - it's the same position on which it will end up in its new layer val posIndexOfShifted = shiftedNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) val posConsShifted = ConstraintsUtils.getPosConstraint(shiftedNode) - if (posConsShifted !== -1) { + if (posConsShifted !== null) { reevaluatePositionConstraintsAfterLayerSwap(originLayer, targetLayer, shiftedNode, posConsShifted) } else { @@ -214,7 +219,7 @@ class LayeredConstraintReevaluation { val node = layer.get(i) val posChoiceCons = ConstraintsUtils.getPosConstraint(node) - if (node != target && posChoiceCons !== -1) { + if (node != target && posChoiceCons !== null) { changedNodes.add(new ConstraintProperty(node, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, posChoiceCons + offset)) } } @@ -245,7 +250,7 @@ class LayeredConstraintReevaluation { val offset = chain.indexOf(node) for (var i = 0; i < chain.size; i++) { val n = chain.get(i) - if (n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) !== -1) { + if (n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) !== null) { val pos = newPos - (offset - i) changedNodes.add(new ConstraintProperty(n, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, pos)) } @@ -260,7 +265,7 @@ class LayeredConstraintReevaluation { */ def reevaluateLayerConstraintsInChain(int layer, List chain) { for (n : chain) { - if (n.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) != -1) { + if (n.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) !== null) { changedNodes.add(new ConstraintProperty(n, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layer)) } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index c44193e59..a2185cde9 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -253,7 +253,28 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens var allNodes = parentOfNode.children var newLayerId = sc.layer var newLayerCons = sc.layerCons - + val List> changedNodes = newLinkedList; + // If layerId is -1 all other nodes need to have their layerId and layerChoiceId increased. + if (newLayerCons == -1) { + newLayerId++ + newLayerCons++ + allNodes.forEach[node | + if (node.hasProperty(LayeredOptions.LAYERING_LAYER_ID)) { + node.setProperty(LayeredOptions.LAYERING_LAYER_ID, + node.getProperty(LayeredOptions.LAYERING_LAYER_ID) + 1 + ) + } + if (node != kNode && node.hasProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT)) { + node.setProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, + node.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) + 1 + ) + changedNodes.add(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, + node.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) + )) + } + ] + } + val layerId = kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) var targetLayerNodes = InteractiveUtil.getNodesOfLayer(newLayerId, allNodes) @@ -274,7 +295,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens reval.reevaluateLayerConstraintsInChain(newLayerCons, chain) reval.reevaluatePosConsInChain(kNode, newPosCons, chain) - var changedNodes = reval.changedNodes + changedNodes.addAll(reval.changedNodes) changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, newPosCons)) changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, newLayerCons)) // Update source code of the model @@ -353,11 +374,35 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens if (property === LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) { layerID = valueId } + var newValueCons = valueCons + var newValueId = valueId + + val List> changedNodes = newLinkedList; + // If layerId is -1 all other nodes need to have their layerId and layerChoiceId increased. + if (valueId == -1) { + layerID++ + newValueId++ + newValueCons++ + parentOfNode.children.forEach[node | + if (node.hasProperty(LayeredOptions.LAYERING_LAYER_ID)) { + node.setProperty(LayeredOptions.LAYERING_LAYER_ID, + node.getProperty(LayeredOptions.LAYERING_LAYER_ID) + 1 + ) + } + if (node != kNode && node.hasProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT)) { + node.setProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, + node.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) + 1 + ) + changedNodes.add(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, + node.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) + )) + } + ] + } var List layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) val oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children) - var newValueCons = valueCons - var newValueId = valueId + val oldPos = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) var relReval = new RelativeConstraintReevaluation(kNode) @@ -385,11 +430,11 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens reval.reevaluateLayerConstraintsInChain(layerID, chain) } - var changedNodes = reval.changedNodes + changedNodes.addAll(reval.changedNodes) changedNodes.add(new ConstraintProperty(kNode, property, newValueCons)) // update relative constraints - if (posID != -1) { + if (posID !== null) { relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) changedNodes.addAll(relReval.changedNodes) }; From 8e9aafffe7996c13c9a92256e97f226d26ea9b98 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 24 Oct 2022 15:16:01 +0200 Subject: [PATCH 06/27] klighd.lsp.interactive: Use KIdentifier to get id. --- ...ler.klighd.lsp.interactive.INodeIdProvider | 1 - .../klighd/lsp/ElkGraphNodeIdProvider.xtend | 34 ------------------- ...edInteractiveLanguageServerExtension.xtend | 17 +++------- 3 files changed, 5 insertions(+), 47 deletions(-) delete mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider delete mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider deleted file mode 100644 index 2f1a688f2..000000000 --- a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider +++ /dev/null @@ -1 +0,0 @@ -de.cau.cs.kieler.klighd.lsp.ElkGraphNodeIdProvider \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend deleted file mode 100644 index 40c52307b..000000000 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphNodeIdProvider.xtend +++ /dev/null @@ -1,34 +0,0 @@ -/* - * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * - * http://rtsys.informatik.uni-kiel.de/kieler - * - * Copyright 2022 by - * + Kiel University - * + Department of Computer Science - * + Real-Time and Embedded Systems Group - * - * This code is provided under the terms of the Eclipse Public License (EPL). - */ -package de.cau.cs.kieler.klighd.lsp - -import de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider -import org.eclipse.elk.graph.ElkNode - -/** - * Service class that returns the id of ELK nodes. - * - * @author sdo - * - */ -class ElkGraphNodeIdProvider implements INodeIdProvider { - - override canHandle(Object graph) { - return graph instanceof ElkNode - } - - override getNodeId(Object element) { - return (element as ElkNode).labels.get(0).text - } - -} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index a2185cde9..97400281c 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -17,8 +17,7 @@ package de.cau.cs.kieler.klighd.lsp.interactive.layered import com.google.inject.Inject -import de.cau.cs.kieler.klighd.KlighdDataManager -import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties +import de.cau.cs.kieler.klighd.kgraph.KIdentifier import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil import de.cau.cs.kieler.klighd.lsp.KGraphDiagramState @@ -29,15 +28,12 @@ import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil import java.util.LinkedList import java.util.List -import java.util.ServiceLoader import javax.inject.Singleton import org.eclipse.elk.alg.layered.options.LayeredOptions -import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension -import de.cau.cs.kieler.klighd.lsp.interactive.INodeIdProvider //import de.cau.cs.kieler.sccharts.impl.StateImpl @@ -145,13 +141,10 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens // get the actual label of the node val otherNode = LSPUtil.getKNode(diagramState, uri, node) - val modelElement = otherNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - var value = "" - for (INodeIdProvider ip : ServiceLoader.load(INodeIdProvider, - KlighdDataManager.getClassLoader())) { - if (ip.canHandle(modelElement)) { - value = ip.getNodeId(modelElement) - } + var value = kNode.toString + val id = otherNode.getData(KIdentifier) + if (id !== null) { + value = id.id } if (kNode !== null && parentOfNode !== null) { From 0b94b3430aa5c365c8562c20c258d356d55ce53c Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 4 Nov 2022 10:57:44 +0100 Subject: [PATCH 07/27] klighd.lsp: Interactive SCCharts: Fixed documentation and license. --- .../lsp/ElkGraphConstraintSerializer.xtend | 6 +- .../interactive/IConstraintSerializer.xtend | 7 +- .../lsp/interactive/INodeIdProvider.xtend | 37 ----------- .../lsp/interactive/InteractiveUtil.xtend | 66 +++++-------------- .../lsp/interactive/layered/Actions.xtend | 8 +-- .../layered/ConstraintsUtils.xtend | 2 +- .../layered/DeleteConstraint.xtend | 2 +- .../layered/ILPredOfConstraint.xtend | 8 ++- .../layered/ILSuccOfConstraint.xtend | 8 ++- .../interactive/layered/LayerConstraint.xtend | 2 +- ...edInteractiveLanguageServerExtension.xtend | 52 +++++++++------ .../layered/PositionConstraint.xtend | 2 +- .../RelativeConstraintReevaluation.xtend | 9 ++- .../layered/StaticConstraint.xtend | 2 +- 14 files changed, 89 insertions(+), 122 deletions(-) delete mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend index e49351d3b..bc5a02906 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend @@ -8,7 +8,11 @@ * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This code is provided under the terms of the Eclipse Public License (EPL). + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend index 3c2337c69..d531b2f08 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend @@ -8,13 +8,16 @@ * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This code is provided under the terms of the Eclipse Public License (EPL). + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension -import java.util.HashMap import java.util.List /** diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend deleted file mode 100644 index 774f6febd..000000000 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/INodeIdProvider.xtend +++ /dev/null @@ -1,37 +0,0 @@ -/* - * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * - * http://rtsys.informatik.uni-kiel.de/kieler - * - * Copyright 2022 by - * + Kiel University - * + Department of Computer Science - * + Real-Time and Embedded Systems Group - * - * This code is provided under the terms of the Eclipse Public License (EPL). - */ -package de.cau.cs.kieler.klighd.lsp.interactive - -/** - * Service interface that can provide a node id for a given graph element. - * - * @author sdo - * - */ -interface INodeIdProvider { - /** - * Checks whether this serializer can handle a graph type - * - * @param graph The graph - * @return true if the node provider supports the given graph - */ - def boolean canHandle(Object graph); - - /** - * Returns an id string of a given graph element - * - * @param element The graph element - * @return An id string - */ - def String getNodeId(Object element); -} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index d9962d054..7d31ecdc5 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -3,28 +3,30 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2020 by + * Copyright 2022 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This code is provided under the terms of the Eclipse Public License (EPL). + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import java.util.ArrayList import java.util.List import java.util.ServiceLoader import org.eclipse.elk.alg.layered.options.LayeredOptions -import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions -import org.eclipse.elk.core.options.CoreOptions import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient /** * Provides utility methods for interactive layout. @@ -84,49 +86,6 @@ class InteractiveUtil { } } - /** - * Copies constraint properties depending on the algorithm from kNode to elkNode - * by using {@code copyConstraintProp()}. - * - * @param elkNode The target ElkNode - * @param kNode The source KNode of the property - */ - static def copyAllConstraints(Object node, KNode kNode) { - val algorithm = kNode.parent.getProperty(CoreOptions.ALGORITHM) - - var List> props = #[] - var List annos = #[] - if(algorithm === null || algorithm == 'layered' || algorithm == 'org.eclipse.elk.layered') { - props = #[ - LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, - LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, - LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, - LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF - ] - annos = #[ - "layering.layerChoiceConstraint", - "crossingMinimization.positionChoiceConstraint", - "crossingMinimization.inLayerPredOf", - "crossingMinimization.inLayerSuccOf" - ] - } else if ("rectpacking".equals(algorithm)) { - props = #[ - RectPackingOptions.DESIRED_POSITION, - RectPackingOptions.ASPECT_RATIO - ] - annos = #[ - "desiredPosition", - "aspectRatio" - ] - } - - if (node instanceof ElkNode) { - for (prop : props) { - copyConstraintProp(node, kNode, prop) - } - } - } - /** * Determines the root of the given node. * @@ -147,6 +106,7 @@ class InteractiveUtil { * * @param node One node of the chain * @param layerNodes Nodes that are in the same layer as {@code node} + * @returnAll nodes of the relative constraint chain of the given node present in the given layer nodes. */ static def getChain(KNode node, List layerNodes) { var pos = layerNodes.indexOf(node) @@ -182,6 +142,7 @@ class InteractiveUtil { * * @param chain1 One of the two chains. * @param chain2 Other one of the two chains. + * @return Returns true if the chains can be merged. */ static def isMergeImpossible(List chain1, List chain2) { var connectedNodes = new ArrayList() @@ -205,6 +166,13 @@ class InteractiveUtil { return false } + /** + * Calls serializer for corresponding model type if one was bound. + * + * @param changedNodes List of {@code ConstraintProperty} that represent the changed nodes. + * @param model The KNode that has to be changed. + * @param uri The uri of the model file that will be rewritten if a serializer exists. + */ static def serializeConstraints(List> changedNodes, KNode model, String uri, KGraphLanguageServerExtension languageServer, KGraphLanguageClient client ) { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend index 8171978db..8460e5e16 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend @@ -143,7 +143,7 @@ class DeleteLayerConstraintAction implements Action { }/** * Sets a 'in layer predecessor of'-constraint for a node. * - * @author jet + * @author jep */ @Accessors @EqualsHashCode @@ -163,7 +163,7 @@ class SetILPredOfConstraintAction implements Action { /** * Sets a 'in layer successor of'-constraint for a node. * - * @author jet + * @author jep */ @Accessors @EqualsHashCode @@ -183,7 +183,7 @@ class SetILSuccOfConstraintAction implements Action { /** * Deletes the relative constraints on the node that is identified by the given id. * - * @author jet + * @author jep */ @Accessors @EqualsHashCode @@ -203,7 +203,7 @@ class DeleteRelativeConstraintsAction implements Action { /** * Deletes the iLPredOf constraint on the node that is identified by the given id. * - * @author jet + * @author jep */ @Accessors @EqualsHashCode diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend index 430035bdd..1aa45f535 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend @@ -22,7 +22,7 @@ import org.eclipse.elk.alg.layered.options.LayeredOptions /** * Provides a set of utility methods that is used in the constraints package. * - * @author jet, cos, sdo + * @author jep, cos, sdo */ class ConstraintsUtils { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/DeleteConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/DeleteConstraint.xtend index e899ea896..df4a2ee0e 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/DeleteConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/DeleteConstraint.xtend @@ -21,7 +21,7 @@ import org.eclipse.xtend.lib.annotations.Data /** * Data class for a delete constraint. * - * @author jet, cos, sdo + * @author jep, cos, sdo */ @Data class DeleteConstraint { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend index bf1a2ed90..17d85d3e3 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend @@ -1,6 +1,6 @@ /* * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * + * * http://rtsys.informatik.uni-kiel.de/kieler * * Copyright 2022 by @@ -8,7 +8,11 @@ * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This code is provided under the terms of the Eclipse Public License (EPL). + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive.layered diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend index d6b05e05e..693333237 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend @@ -1,6 +1,6 @@ /* * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * + * * http://rtsys.informatik.uni-kiel.de/kieler * * Copyright 2022 by @@ -8,7 +8,11 @@ * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This code is provided under the terms of the Eclipse Public License (EPL). + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive.layered diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend index c4c5f07c5..ae8f96535 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend @@ -21,7 +21,7 @@ import org.eclipse.xtend.lib.annotations.Data /** * Data class for a layer constraint. * - * @author jet, cos, sdo + * @author jep, cos, sdo */ @Data class LayerConstraint { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index 97400281c..d8e0d7297 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -35,12 +35,10 @@ import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.ide.server.ILanguageServerAccess import org.eclipse.xtext.ide.server.ILanguageServerExtension -//import de.cau.cs.kieler.sccharts.impl.StateImpl - /** * Language server extension to change the layered algorithm in the interactive mode. * - * @author jet, cos, sdo + * @author jep, cos, sdo */ @Singleton class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtension { @@ -134,7 +132,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param targetId The id of the node on which the constraint should be set. * @param node the id of the node to which the relation should be set. */ - private def setRelativeConstraint(IProperty property, String uri, String targetId, String node, String clientId) { + private def setRelativeConstraint(IProperty property, String uri, String targetId, String node, + String clientId + ) { val kNode = LSPUtil.getKNode(diagramState, uri, targetId) val parentOfNode = kNode.parent @@ -158,7 +158,8 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens posID++; } var layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) - var oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children) + var oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), + parentOfNode.children) // update position constraints val layerSwap = layerID !== kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) @@ -172,12 +173,12 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens reval.reevaluatePositionConstraintsAfterLayerSwap(layerNodes, oldLayerNodes, kNode, posID) reval.reevaluateLayerConstraintsInChain(layerID, chain) } else { - if (posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - && chain.contains(otherNode) - && posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - && posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + if (posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && + chain.contains(otherNode) && + posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && + posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { // node is moved within its chain - relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) + relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) } reval.reevaluatePositionConstraintsAfterPosChangeInLayer(layerNodes, kNode, posID) } @@ -289,8 +290,11 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens reval.reevaluatePosConsInChain(kNode, newPosCons, chain) changedNodes.addAll(reval.changedNodes) - changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, newPosCons)) - changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, newLayerCons)) + changedNodes.add( + new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, + newPosCons)) + changedNodes.add( + new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, newLayerCons)) // Update source code of the model // update relative constraints @@ -311,7 +315,8 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val kNode = getKNode(uri, dc.id) if (kNode !== null) { val changedNodes = new LinkedList> - changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, null)) + changedNodes.add( + new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, null)) changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, null)) refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } @@ -327,7 +332,11 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val kNode = getKNode(uri, dc.id) if (kNode !== null) { val changedNodes = new LinkedList> - changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, null)) + changedNodes.add(new ConstraintProperty( + kNode, + LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, + null + )) refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } @@ -357,7 +366,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param targetId The id of the node on which the constraint should be set. * @param value Either the id of the position or the id of the layer. */ - private def setConstraint(IProperty property, String uri, String targetId, int valueId, int valueCons, String clientId) { + private def setConstraint(IProperty property, String uri, String targetId, int valueId, int valueCons, + String clientId + ) { val kNode = LSPUtil.getKNode(diagramState, uri, targetId) val parentOfNode = kNode.parent @@ -394,7 +405,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens } var List layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) - val oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children) + val oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), + parentOfNode.children + ) val oldPos = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) @@ -402,10 +415,11 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val chain = InteractiveUtil.getChain(kNode, oldLayerNodes) if (property === LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) { posID = valueId - if (posID != -1 && posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - && posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + if (posID != -1 && + posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && + posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { // node is moved within its chain - relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) + relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) } else if (posID < oldPos) { // posID must be increased by the number of predecessors newValueCons += chain.indexOf(kNode) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend index 85229d444..32523c1a9 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend @@ -21,7 +21,7 @@ import org.eclipse.xtend.lib.annotations.Data /** * Data class for a position constraint. * - * @author jet, cos, sdo + * @author jep, cos, sdo */ @Data class PositionConstraint { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend index 57d721791..a19f691b1 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend @@ -8,7 +8,11 @@ * + Department of Computer Science * + Real-Time and Embedded Systems Group * - * This code is provided under the terms of the Eclipse Public License (EPL). + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive.layered @@ -21,6 +25,9 @@ import org.eclipse.elk.graph.properties.IProperty import org.eclipse.xtend.lib.annotations.Accessors /** + * Class to reevaluate relative constraint set for the layered algorithm since they may become obsolete or have to be + * changed if some node is moved. + * * @author jep */ class RelativeConstraintReevaluation { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend index d25812b6c..e62561558 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend @@ -21,7 +21,7 @@ import org.eclipse.xtend.lib.annotations.Data /** * Data class for a combined position and layer constraint. * - * @author jet, cos, sdo + * @author jep, cos, sdo */ @Data class StaticConstraint { From 3d4d950fad5a279880e23212b7b2279b824dd98c Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 7 Nov 2022 13:25:32 +0100 Subject: [PATCH 08/27] klighd.lsp: Interactive rectpacking: Still update the layout if request is invalid. --- .../RectpackingInteractiveLanguageServerExtension.xtend | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend index 49dc46a3b..6d22647a8 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend @@ -96,6 +96,8 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx } refreshModelInEditor(new ConstraintProperty(kNode, RectPackingOptions.DESIRED_POSITION, desiredPosition), KGraphUtil.getRootNodeOf(kNode), uri) + } else { + languageServer.updateLayout(uri) } } @@ -139,6 +141,8 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx kNode.setProperty(RectPackingOptions.DESIRED_POSITION, null) refreshModelInEditor(new ConstraintProperty(kNode, RectPackingOptions.DESIRED_POSITION, null), KGraphUtil.getRootNodeOf(kNode), uri) + } else { + languageServer.updateLayout(uri) } } From b5c533ebc7473b80e56f9210627e4a8566454846 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 7 Nov 2022 13:56:41 +0100 Subject: [PATCH 09/27] Klighd.lsp: Enforce minimum position constraint of 0 in layer. --- .../interactive/layered/LayeredConstraintReevaluation.xtend | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index eec0e2526..f24625876 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -220,7 +220,9 @@ class LayeredConstraintReevaluation { val posChoiceCons = ConstraintsUtils.getPosConstraint(node) if (node != target && posChoiceCons !== null) { - changedNodes.add(new ConstraintProperty(node, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, posChoiceCons + offset)) + changedNodes.add( + new ConstraintProperty(node, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, + Math.max(0, posChoiceCons + offset))) } } } From 09e2e46c16747424305adfab932991c091374a9c Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 7 Nov 2022 14:09:17 +0100 Subject: [PATCH 10/27] Renamed interactive type attributes. --- .../klighd/lsp/interactive/layered/Actions.xtend | 4 ++-- ...tend => InLayerPredecessorOfConstraint.xtend} | 4 ++-- ....xtend => InLayerSuccessorOfConstraint.xtend} | 4 ++-- .../interactive/layered/LayerConstraint.xtend | 2 +- ...yeredInteractiveLanguageServerExtension.xtend | 16 ++++++++-------- .../interactive/layered/PositionConstraint.xtend | 2 +- .../interactive/layered/StaticConstraint.xtend | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) rename plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/{ILPredOfConstraint.xtend => InLayerPredecessorOfConstraint.xtend} (91%) rename plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/{ILSuccOfConstraint.xtend => InLayerSuccessorOfConstraint.xtend} (91%) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend index 8460e5e16..eab4e5d6e 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend @@ -152,7 +152,7 @@ class SetILPredOfConstraintAction implements Action { public static val KIND = 'setILPredOfConstraint' String kind = KIND - ILPredOfConstraint constraint + InLayerPredecessorOfConstraint constraint new() {} new(Consumer initializer) { @@ -172,7 +172,7 @@ class SetILSuccOfConstraintAction implements Action { public static val KIND = 'setILSuccOfConstraint' String kind = KIND - ILSuccOfConstraint constraint + InLayerSuccessorOfConstraint constraint new() {} new(Consumer initializer) { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/InLayerPredecessorOfConstraint.xtend similarity index 91% rename from plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend rename to plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/InLayerPredecessorOfConstraint.xtend index 17d85d3e3..83c11118c 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILPredOfConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/InLayerPredecessorOfConstraint.xtend @@ -24,7 +24,7 @@ import org.eclipse.xtend.lib.annotations.Data * @author jep */ @Data -class ILPredOfConstraint { +class InLayerPredecessorOfConstraint { String id - String otherNode + String referencedNode } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/InLayerSuccessorOfConstraint.xtend similarity index 91% rename from plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend rename to plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/InLayerSuccessorOfConstraint.xtend index 693333237..a1e3a7da7 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ILSuccOfConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/InLayerSuccessorOfConstraint.xtend @@ -24,7 +24,7 @@ import org.eclipse.xtend.lib.annotations.Data * @author jep */ @Data -class ILSuccOfConstraint { +class InLayerSuccessorOfConstraint { String id - String otherNode + String referencedNode } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend index ae8f96535..2c0256207 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayerConstraint.xtend @@ -27,5 +27,5 @@ import org.eclipse.xtend.lib.annotations.Data class LayerConstraint { String id int layer - int layerCons + int layerConstraint } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index d8e0d7297..2706ab656 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -60,10 +60,10 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param cons the constraint * @param clientId the client id */ - def setILPredOfConstraint(ILPredOfConstraint cons, String clientId) { + def setILPredOfConstraint(InLayerPredecessorOfConstraint cons, String clientId) { val uri = diagramState.getURIString(clientId) setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, uri, cons.id, - cons.otherNode, clientId) + cons.getReferencedNode, clientId) } /** @@ -71,10 +71,10 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * @param cons the constraint * @param clientId the client id */ - def setILSuccOfConstraint(ILSuccOfConstraint cons, String clientId) { + def setILSuccOfConstraint(InLayerSuccessorOfConstraint cons, String clientId) { val uri = diagramState.getURIString(clientId) setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, uri, cons.id, - cons.otherNode, clientId) + cons.getReferencedNode, clientId) } /** @@ -210,7 +210,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens */ def setLayerConstraint(LayerConstraint lc, String clientId) { val uri = diagramState.getURIString(clientId) - setConstraint(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, uri, lc.id, lc.layer, lc.layerCons, clientId) + setConstraint(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, uri, lc.id, lc.layer, lc.getLayerConstraint, clientId) } /** @@ -221,7 +221,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens def setPositionConstraint(PositionConstraint pc, String clientId) { val uri = diagramState.getURIString(clientId) setConstraint(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, uri, pc.id, - pc.position, pc.posCons, clientId) + pc.position, pc.getPositionConstraint, clientId) } /** @@ -246,7 +246,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens */ var allNodes = parentOfNode.children var newLayerId = sc.layer - var newLayerCons = sc.layerCons + var newLayerCons = sc.getLayerConstraint val List> changedNodes = newLinkedList; // If layerId is -1 all other nodes need to have their layerId and layerChoiceId increased. if (newLayerCons == -1) { @@ -277,7 +277,7 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val chain = InteractiveUtil.getChain(kNode, oldLayerNodes) // posID must be increased by the number of predecessors val newPosId = sc.position + chain.indexOf(kNode) - val newPosCons = sc.posCons + chain.indexOf(kNode) + val newPosCons = sc.getPositionConstraint + chain.indexOf(kNode) // Reevaluate insertion of node to target layer var reval = new LayeredConstraintReevaluation(kNode) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend index 32523c1a9..c87a98868 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/PositionConstraint.xtend @@ -27,5 +27,5 @@ import org.eclipse.xtend.lib.annotations.Data class PositionConstraint { String id int position - int posCons + int positionConstraint } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend index e62561558..f58a5007a 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/StaticConstraint.xtend @@ -44,11 +44,11 @@ class StaticConstraint { /** * Value for the layer constraint */ - int layerCons + int layerConstraint /** * Value for the position constraint */ - int posCons + int positionConstraint } From 5bec88d9c278f73a84d14d98e49be85e2fe1fe1e Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 7 Nov 2022 16:58:24 +0100 Subject: [PATCH 11/27] klighd.lsp: Renmaing, comments and Javadoc. --- .../klighd/lsp/KGraphDiagramGenerator.xtend | 1 - .../gson_utils/KGraphTypeAdapterUtil.xtend | 16 +- .../lsp/interactive/InteractiveUtil.xtend | 2 +- .../lsp/interactive/layered/Actions.xtend | 20 +- .../layered/ConstraintsUtils.xtend | 22 +- .../LayeredConstraintReevaluation.xtend | 206 +++++----- .../LayeredInteractiveActionHandler.xtend | 22 +- ...edInteractiveLanguageServerExtension.xtend | 367 ++++++++++-------- .../RelativeConstraintReevaluation.xtend | 128 +++--- 9 files changed, 412 insertions(+), 372 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend index 12ef9c2cc..ee0dcc115 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramGenerator.xtend @@ -49,7 +49,6 @@ import java.util.HashSet import java.util.List import org.apache.log4j.Logger import org.eclipse.elk.alg.layered.options.LayeredOptions -import org.eclipse.elk.alg.rectpacking.options.RectPackingOptions import org.eclipse.elk.core.options.CoreOptions import org.eclipse.emf.ecore.EObject import org.eclipse.sprotty.Dimension diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index 706b099b6..914ffe723 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -18,14 +18,10 @@ package de.cau.cs.kieler.klighd.lsp.gson_utils import com.google.gson.GsonBuilder import de.cau.cs.kieler.klighd.SynthesisOption -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteILPredOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteILSuccOfConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteLayerConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeletePositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteRelativeConstraintsAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteStaticConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetILPredOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetILSuccOfConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetLayerConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetPositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetStaticConstraintAction @@ -41,6 +37,10 @@ import de.cau.cs.kieler.klighd.lsp.model.SetSynthesisAction import java.awt.geom.Point2D import org.eclipse.emf.ecore.EObject import org.eclipse.sprotty.server.json.ActionTypeAdapter +import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerPredecessorOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerSuccessorOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerSuccessorOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerPredecessorOfConstraintAction /** * Static util class to configure needed gson type adapters for KGraph serialization. @@ -67,11 +67,11 @@ class KGraphTypeAdapterUtil { addActionKind(DeletePositionConstraintAction.KIND, DeletePositionConstraintAction) addActionKind(DeleteLayerConstraintAction.KIND, DeleteLayerConstraintAction) //relative constraints - addActionKind(SetILPredOfConstraintAction.KIND, SetILPredOfConstraintAction) - addActionKind(SetILSuccOfConstraintAction.KIND, SetILSuccOfConstraintAction) + addActionKind(SetInLayerPredecessorOfConstraintAction.KIND, SetInLayerPredecessorOfConstraintAction) + addActionKind(SetInLayerSuccessorOfConstraintAction.KIND, SetInLayerSuccessorOfConstraintAction) addActionKind(DeleteRelativeConstraintsAction.KIND, DeleteRelativeConstraintsAction) - addActionKind(DeleteILPredOfConstraintAction.KIND, DeleteILPredOfConstraintAction) - addActionKind(DeleteILSuccOfConstraintAction.KIND, DeleteILSuccOfConstraintAction) + addActionKind(DeleteInLayerPredecessorOfConstraintAction.KIND, DeleteInLayerPredecessorOfConstraintAction) + addActionKind(DeleteInLayerSuccessorOfConstraintAction.KIND, DeleteInLayerSuccessorOfConstraintAction) // Interactive rectpacking actions diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 7d31ecdc5..91a3c5786 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -106,7 +106,7 @@ class InteractiveUtil { * * @param node One node of the chain * @param layerNodes Nodes that are in the same layer as {@code node} - * @returnAll nodes of the relative constraint chain of the given node present in the given layer nodes. + * @return All nodes of the relative constraint chain of the given node present in the given layer nodes. */ static def getChain(KNode node, List layerNodes) { var pos = layerNodes.indexOf(node) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend index eab4e5d6e..aaf3636f8 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend @@ -140,7 +140,9 @@ class DeleteLayerConstraintAction implements Action { new(Consumer initializer) { initializer.accept(this) } -}/** +} + +/** * Sets a 'in layer predecessor of'-constraint for a node. * * @author jep @@ -148,14 +150,14 @@ class DeleteLayerConstraintAction implements Action { @Accessors @EqualsHashCode @ToString(skipNulls = true) -class SetILPredOfConstraintAction implements Action { +class SetInLayerPredecessorOfConstraintAction implements Action { public static val KIND = 'setILPredOfConstraint' String kind = KIND InLayerPredecessorOfConstraint constraint new() {} - new(Consumer initializer) { + new(Consumer initializer) { initializer.accept(this) } } @@ -168,14 +170,14 @@ class SetILPredOfConstraintAction implements Action { @Accessors @EqualsHashCode @ToString(skipNulls = true) -class SetILSuccOfConstraintAction implements Action { +class SetInLayerSuccessorOfConstraintAction implements Action { public static val KIND = 'setILSuccOfConstraint' String kind = KIND InLayerSuccessorOfConstraint constraint new() {} - new(Consumer initializer) { + new(Consumer initializer) { initializer.accept(this) } } @@ -208,14 +210,14 @@ class DeleteRelativeConstraintsAction implements Action { @Accessors @EqualsHashCode @ToString(skipNulls = true) -class DeleteILPredOfConstraintAction implements Action { +class DeleteInLayerPredecessorOfConstraintAction implements Action { public static val KIND = 'deleteILPredOfConstraint' String kind = KIND DeleteConstraint constraint new() {} - new(Consumer initializer) { + new(Consumer initializer) { initializer.accept(this) } } @@ -228,14 +230,14 @@ class DeleteILPredOfConstraintAction implements Action { @Accessors @EqualsHashCode @ToString(skipNulls = true) -class DeleteILSuccOfConstraintAction implements Action { +class DeleteInLayerSuccessorOfConstraintAction implements Action { public static val KIND = 'deleteILSuccOfConstraint' String kind = KIND DeleteConstraint constraint new() {} - new(Consumer initializer) { + new(Consumer initializer) { initializer.accept(this) } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend index 1aa45f535..8759b9021 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/ConstraintsUtils.xtend @@ -33,17 +33,17 @@ class ConstraintsUtils { /** * Returns the value of the position constraint that is set on the node. * - * @param node the instance of KNode of which you want the constraint value + * @param node The instance of KNode of which you want the constraint value * @return The position constraint of the given node. */ - def static getPosConstraint(KNode node) { + def static getPositionConstraint(KNode node) { return node.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) } /** * Returns the value of the layer constraint that is set on the node. * - * @param node the instance of KNode of which you want the constraint value + * @param node The instance of KNode of which you want the constraint value * @return The layer constraint of the given node. */ def static getLayerConstraint(KNode node) { @@ -54,17 +54,17 @@ class ConstraintsUtils { * Sets the value of the position constraint that is set on the node. * * @param node The instance of KNode of which you want the constraint value - * @param pos The new desired position of the node. + * @param position The new desired position of the node. */ - def static setPosConstraint(KNode node, int pos) { - node.setProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, pos) + def static setPositionConstraint(KNode node, int position) { + node.setProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, position) } /** * Sets the value of the layer constraint that is set on the node. * - * @param node the instance of KNode that should get the constraint. - * @param layer the value for the layer constraint + * @param node The instance of KNode that should get the constraint. + * @param layer The value for the layer constraint. */ def static setLayerConstraint(KNode node, int layer) { node.setProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layer) @@ -74,7 +74,7 @@ class ConstraintsUtils { * Sets the value of the layer constraint to null. * This procedure effectively deletes the constraint from the node. * - * @param node the instance of KNode of which the layer constraint is set to null + * @param node The instance of KNode of which the layer constraint is set to null */ def static nullifyLayerConstraint(KNode node) { node.setProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, null) @@ -84,9 +84,9 @@ class ConstraintsUtils { * Sets the value of the position constraint to null. * This procedure effectively deletes the constraint from the node. * - * @param node the instance of KNode of which the position constraint is set to null. + * @param node The instance of KNode of which the position constraint is set to null. */ - def static nullifyPosConstraint(KNode node) { + def static nullifyPositionConstraint(KNode node) { node.setProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, null) } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index f24625876..20873ad00 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -20,7 +20,6 @@ import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil -import java.util.HashMap import java.util.List import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.xtend.lib.annotations.Accessors @@ -46,69 +45,71 @@ class LayeredConstraintReevaluation { /** * Adjusts position constraints in a layer after one node has been introduced to it. * - * @param newNodesOfLayer nodes of the new layer - * @param oldNodesOfLayer the nodes of old layer - * @param target the moved node - * @param newPos the new position of the node + * @param newNodesOfLayer The nodes of the new layer. + * @param oldNodesOfLayer The nodes of old layer. + * @param target The moved node. + * @param newPosition The new position of the node. */ - def reevaluatePositionConstraintsAfterLayerSwap(List newNodesOfLayer, List oldNodesOfLayer, KNode target, - int newPos) { + def reevaluatePositionConstraintsAfterLayerSwap(List newNodesOfLayer, List oldNodesOfLayer, + KNode target, int newPosition) { val chainLength = InteractiveUtil.getChain(target, oldNodesOfLayer).size // formerLayer != newLayer -- should always be true - it doesn't cause errors if it's not, though. // The node is "deleted" from its old layer if it had a position constraint the old layer - // needs to be reevaluated - offsetPosConstraintsOfLayerFrom(oldNodesOfLayer, -chainLength, + // needs to be reevaluated. + offsetPositionConstraintsOfLayerFrom(oldNodesOfLayer, -chainLength, target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID), target) // The node is added at the new position in the new layer. - offsetPosConstraintsOfLayerFrom(newNodesOfLayer, chainLength, newPos, target) + offsetPositionConstraintsOfLayerFrom(newNodesOfLayer, chainLength, newPosition, target) } /** * Adjusts position constraints in a layer after one node has been introduced to it. * - * @param nodesOfLayer the nodes of the layer - * @param target the moved node - * @param newPos the new position of the node + * @param nodesOfLayer The nodes of the layer. + * @param target The moved node. + * @param newPosition The new position of the node. */ - def reevaluatePositionConstraintsAfterPosChangeInLayer(List nodesOfLayer, KNode target, int newPos) { - val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + def reevaluatePositionConstraintsAfterPositionChangeInLayer(List nodesOfLayer, KNode target, + int newPosition) { + val oldPosition = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) val chainLength = InteractiveUtil.getChain(target, nodesOfLayer).size - if (newPos < oldPos) { - // new position constraint is above the old position - // increment all position constraints of nodes that weren't below the target beforehand - offsetPosConstraintsOfLayerFromTo(nodesOfLayer, chainLength, newPos, oldPos, target) + if (newPosition < oldPosition) { + // New position constraint is above the old position + // increment all position constraints of nodes that weren't below the target beforehand. + offsetPositionConstraintsOfLayerFromTo(nodesOfLayer, chainLength, newPosition, oldPosition, target) } else { - // oldPos < newPos new position constraint is below the old position - // Decrement all position constraints of nodes that weren't above the target beforehand - offsetPosConstraintsOfLayerFromTo(nodesOfLayer, -chainLength, oldPos, newPos, target) + // oldPos < newPos: New position constraint is below the old position. + // Decrement all position constraints of nodes that weren't above the target beforehand. + offsetPositionConstraintsOfLayerFromTo(nodesOfLayer, -chainLength, oldPosition, newPosition, target) } } /** * Reevaluates position constraints in a layer after a node is removed. * - * @param nodesOfLayer the nodes in the layer - * @param removedNode the removed node + * @param nodesOfLayer The nodes in the layer. + * @param removedNode The removed node. */ def reevaluatePositionConstraintsAfterRemoval(List nodesOfLayer, KNode removedNode) { - // Offset all positional constraint greater or equal to the new one in order to conserve the - // established subsequence of nodes below the removed node - val formerPosCons = ConstraintsUtils.getPosConstraint(removedNode) - if (formerPosCons !== null) { - offsetPosConstraintsOfLayerFrom(nodesOfLayer, -1, formerPosCons, removedNode) + // Offset all position constraints greater or equal to the new one in order to conserve the + // established subsequence of nodes below the removed node. + val formerPositionConstraint = ConstraintsUtils.getPositionConstraint(removedNode) + if (formerPositionConstraint !== null) { + offsetPositionConstraintsOfLayerFrom(nodesOfLayer, -1, formerPositionConstraint, removedNode) } } /** - * Optional reevaluation when emptying a layer should lead to its disappearance. + * Optional: Reevaluation when emptying a layer should lead to its disappearance. * Adjust layer constraints in the graph if a new layer constraint empties a layer and lets it disappear. * - * @param target the removed node - * @param targetLayer the layer id - * @param nodes the nodes in the graph + * @param target The removed node. + * @param targetLayer The layer id. + * @param nodes The nodes in the graph. + * @return True, if layers were deleted such that the targetLayer is out of bounds. */ def reevaluateAfterEmptyingALayer(KNode target, int targetLayer, List nodes) { @@ -123,13 +124,13 @@ class LayeredConstraintReevaluation { val originalLayer = InteractiveUtil.getNodesOfLayer(originalLayerIndex, nodes) if (originalLayer.length == 1) { - /* If a layer is emptied and disappears from the drawing - * then all LayerConstraints with a value higher or equal than - * the disappeared layer need to be decremented*/ + // If a layer is emptied and disappears from the drawing + // then all layer constraint with a value higher or equal than + // the disappeared layer need to be decremented. for (node : nodes) { - val layerCons = ConstraintsUtils.getLayerConstraint(node) - if (layerCons !== null && layerCons >= originalLayerIndex) { - changedNodes.add(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layerCons - 1)) + val layerConstraint = ConstraintsUtils.getLayerConstraint(node) + if (layerConstraint !== null && layerConstraint >= originalLayerIndex) { + changedNodes.add(new ConstraintProperty(node, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layerConstraint - 1)) } } @@ -141,18 +142,20 @@ class LayeredConstraintReevaluation { } /** - * Shifting-Reevaluation + * Shifting-Reevaluation: * Simulates the shifting of nodes in order to adjust layer and position constraints. * - * @param insertedNode the node that is the target of the constraints - * @param posCons the value of the position constraint for insertedNode - * @param layerCons the value of the layer constraint for insertedNode - * @param oldLayerNodes The origin layer of insertedNode - * @param newLayerNodes The target layer of insertedNode - * @param nodes All nodes of the current graph + * @param insertedNode The node that is the target of the constraints. + * @param newLayerId The id of the new layer. + * @param layerConstraint The value of the layer constraint for insertedNode. + * @param newPositionId The new position in the layer. + * @param positionConstraint The value of the position constraint for insertedNode. + * @param oldLayerNodes The origin layer of insertedNode. + * @param newLayerNodes The target layer of insertedNode. + * @param nodes All nodes of the current graph. */ - def void shiftIfNecessary(KNode insertedNode, int newLayerId, int layerCons, int newPosId, int posCons, - List oldLayerNodes, List newLayerNodes, List nodes) { + def void shiftIfNecessary(KNode insertedNode, int newLayerId, int layerConstraint, int newPositionId, + int positionConstraint, List oldLayerNodes, List newLayerNodes, List nodes) { val adjacentNodes = KGraphUtil.getAdjacentNodes(insertedNode) @@ -160,44 +163,48 @@ class LayeredConstraintReevaluation { for (n : adjacentNodes) { if (newLayerNodes.contains(n)) { - // If the shifted node has a layer constraint. It needs to be incremented else the shift would have no effect. + // If the shifted node has a layer constraint. + // It needs to be incremented else the shift would have no effect. shiftedNodes.add(n) // Test whether the shift leads to more shifts in the next layer. val nextNextLayerNodes = InteractiveUtil.getNodesOfLayer(newLayerId + 1, nodes) - val nPosId = n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - val nPosCons = ConstraintsUtils.getPosConstraint(n) + val nPositionId = n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + val nPositionConstraint = ConstraintsUtils.getPositionConstraint(n) - shiftIfNecessary(n, newLayerId + 1, layerCons + 1, nPosId, nPosCons, newLayerNodes, nextNextLayerNodes, nodes) + shiftIfNecessary(n, newLayerId + 1, layerConstraint + 1, nPositionId, nPositionConstraint, + newLayerNodes, nextNextLayerNodes, nodes) } } } /** - * Position Reevaluation for Blockshifting + * Position Reevaluation for Blockshifting. * Adjusts positional constraints in the source and target layer after one node has been shifted. * - * @param shiftedNode the shifted node - * @param targetNode the node that might be changed - * @param posCons the layer the target node - * @param originLayer the previous layer of the node - * @param targetLayer the new layer of the node + * @param shiftedNode The shifted node. + * @param targetNode The node that might be changed. + * @param positionConstraint The layer the target node. + * @param oldLayer The previous layer of the node. + * @param targetLayer The new layer of the node. */ - def reevaluateAfterShift(KNode shiftedNode, KNode targetNode, int posCons, List originLayer, + def reevaluateAfterShift(KNode shiftedNode, KNode targetNode, int positionConstraint, List oldLayer, List targetLayer) { // Currently, we only shift from left to right. - // Get the position of the shiftedNode - it's the same position on which it will end up in its new layer - val posIndexOfShifted = shiftedNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - val posConsShifted = ConstraintsUtils.getPosConstraint(shiftedNode) - if (posConsShifted !== null) { - reevaluatePositionConstraintsAfterLayerSwap(originLayer, targetLayer, shiftedNode, posConsShifted) + // Get the position of the shiftedNode - it's the same position on which it will end up in its new layer. + val positionIndexOfShifted = shiftedNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + val positionConstraintOfShifted = ConstraintsUtils.getPositionConstraint(shiftedNode) + if (positionConstraintOfShifted !== null) { + reevaluatePositionConstraintsAfterLayerSwap(oldLayer, targetLayer, shiftedNode, positionConstraintOfShifted) } else { - reevaluatePositionConstraintsAfterLayerSwap(originLayer, targetLayer, shiftedNode, posIndexOfShifted) + reevaluatePositionConstraintsAfterLayerSwap(oldLayer, targetLayer, shiftedNode, positionIndexOfShifted) } - // Reevaluate the position constraints in the source and target layer accordingly - // Also examine the position constraint of the target node - if (posCons > 0 && posCons >= posIndexOfShifted) { - changedNodes.add(new ConstraintProperty(targetNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, posCons - 1)) + // Reevaluate the position constraints in the source and target layer accordingly. + // Also examine the position constraint of the target node. + if (positionConstraint > 0 && positionConstraint >= positionIndexOfShifted) { + changedNodes.add( + new ConstraintProperty(targetNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, + positionConstraint - 1)) } } @@ -206,23 +213,23 @@ class LayeredConstraintReevaluation { * than {@code startPos} and smaller than {@code endPos}. * * @param layer The layer to examine as a list including its nodes ordered by position. - * @param offset The offset that should be applied on the position constraints - * @param startPos The smallest position of the layer - * @param endPos The biggest position of the layer - * @param target The target node + * @param offset The offset that should be applied on the position constraints. + * @param startPosition The smallest position of the layer. + * @param endPosition The biggest position of the layer. + * @param target The target node. */ - def private offsetPosConstraintsOfLayerFromTo(List layer, int offset, int startPos, int endPos, - KNode target) { + def private offsetPositionConstraintsOfLayerFromTo(List layer, int offset, int startPosition, + int endPosition, KNode target) { if (!layer.empty) { - for (var i = startPos; i < endPos + 1; i++) { - val node = layer.get(i) - val posChoiceCons = ConstraintsUtils.getPosConstraint(node) + for (var currentPosition = startPosition; currentPosition < endPosition + 1; currentPosition++) { + val node = layer.get(currentPosition) + val positionConstraint = ConstraintsUtils.getPositionConstraint(node) - if (node != target && posChoiceCons !== null) { + if (node != target && positionConstraint !== null) { changedNodes.add( new ConstraintProperty(node, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, - Math.max(0, posChoiceCons + offset))) + Math.max(0, positionConstraint + offset))) } } } @@ -230,31 +237,33 @@ class LayeredConstraintReevaluation { /** * Offsets all nodes in a layer by {@code offset} that own a positional constraint that is greater or equal - * than {@code startPos}. + * than {@code startPosition}. * * @param layer The layer to examine as a list including its nodes ordered by position. - * @param The offset that should be applied on the position constraints - * @param startPos The smallest position of the layer - * @param target The target node + * @param offset The offset that should be applied on the position constraints. + * @param startPosition The smallest position of the layer. + * @param target The target node. */ - def private offsetPosConstraintsOfLayerFrom(List layer, int offset, int startPos, KNode target) { - offsetPosConstraintsOfLayerFromTo(layer, offset, startPos, layer.length - 1, target) + def private offsetPositionConstraintsOfLayerFrom(List layer, int offset, int startPosition, KNode target) { + offsetPositionConstraintsOfLayerFromTo(layer, offset, startPosition, layer.length - 1, target) } /** * Updates position constraints of the moved node and the one in its chain. * * @param node The moved node. - * @param newPos The new position of the moved node - * @param chain The chain of {@code node} + * @param newPosition The new position of the moved node. + * @param chain The chain of {@code node}. */ - def reevaluatePosConsInChain(KNode node, int newPos, List chain) { + def reevaluatePositionConstraintInChain(KNode node, int newPosition, List chain) { val offset = chain.indexOf(node) for (var i = 0; i < chain.size; i++) { - val n = chain.get(i) - if (n.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) !== null) { - val pos = newPos - (offset - i) - changedNodes.add(new ConstraintProperty(n, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, pos)) + val chainedNode = chain.get(i) + if (chainedNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) !== null) { + val currentPosition = newPosition - (offset - i) + changedNodes.add( + new ConstraintProperty(chainedNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, + currentPosition)) } } } @@ -262,13 +271,14 @@ class LayeredConstraintReevaluation { /** * Updates layer constraint of the moved node and all other nodes in the chain to the layer of the target. * - * @param layer New value of the layer constraints - * @chain Nodes of the chain the moved node is in + * @param layer New value of the layer constraints. + * @param chain Nodes of the chain the moved node is in. */ def reevaluateLayerConstraintsInChain(int layer, List chain) { - for (n : chain) { - if (n.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) !== null) { - changedNodes.add(new ConstraintProperty(n, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, layer)) + for (chainedNode : chain) { + if (chainedNode.getProperty(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) !== null) { + changedNodes.add(new ConstraintProperty(chainedNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, + layer)) } } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend index 0bf74f07b..6057c6301 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveActionHandler.xtend @@ -39,11 +39,11 @@ class LayeredInteractiveActionHandler extends AbstractActionHandler { DeleteStaticConstraintAction.KIND -> DeleteStaticConstraintAction, DeletePositionConstraintAction.KIND -> DeletePositionConstraintAction, DeleteLayerConstraintAction.KIND -> DeleteLayerConstraintAction, - SetILPredOfConstraintAction.KIND -> SetILPredOfConstraintAction, - SetILSuccOfConstraintAction.KIND -> SetILSuccOfConstraintAction, + SetInLayerPredecessorOfConstraintAction.KIND -> SetInLayerPredecessorOfConstraintAction, + SetInLayerSuccessorOfConstraintAction.KIND -> SetInLayerSuccessorOfConstraintAction, DeleteRelativeConstraintsAction.KIND -> DeleteRelativeConstraintsAction, - DeleteILPredOfConstraintAction.KIND -> DeleteILPredOfConstraintAction, - DeleteILSuccOfConstraintAction.KIND -> DeleteILSuccOfConstraintAction + DeleteInLayerPredecessorOfConstraintAction.KIND -> DeleteInLayerPredecessorOfConstraintAction, + DeleteInLayerSuccessorOfConstraintAction.KIND -> DeleteInLayerSuccessorOfConstraintAction ) } @@ -72,23 +72,23 @@ class LayeredInteractiveActionHandler extends AbstractActionHandler { synchronized (server.modelLock) { constraintLS.deleteLayerConstraint(action.constraint, clientId) } - } else if (action instanceof SetILPredOfConstraintAction) { + } else if (action instanceof SetInLayerPredecessorOfConstraintAction) { synchronized (server.modelLock) { - constraintLS.setILPredOfConstraint(action.constraint, clientId) + constraintLS.setInLayerPredecessorOfConstraint(action.constraint, clientId) } - } else if (action instanceof SetILSuccOfConstraintAction) { + } else if (action instanceof SetInLayerSuccessorOfConstraintAction) { synchronized (server.modelLock) { - constraintLS.setILSuccOfConstraint(action.constraint, clientId) + constraintLS.setInLayerSuccessorOfConstraint(action.constraint, clientId) } } else if (action instanceof DeleteRelativeConstraintsAction) { synchronized (server.modelLock) { constraintLS.deleteRelativeConstraints(action.constraint, clientId) } - } else if (action instanceof DeleteILPredOfConstraintAction) { + } else if (action instanceof DeleteInLayerPredecessorOfConstraintAction) { synchronized (server.modelLock) { - constraintLS.deleteILPredOfConstraint(action.constraint, clientId) + constraintLS.deleteInLayerPredecessorOfConstraint(action.constraint, clientId) } - } else if (action instanceof DeleteILSuccOfConstraintAction) { + } else if (action instanceof DeleteInLayerSuccessorOfConstraintAction) { synchronized (server.modelLock) { constraintLS.deleteILSuccOfConstraint(action.constraint, clientId) } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index 2706ab656..36c11357f 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -57,34 +57,37 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens /** * Sets a 'in layer predecessor'-constraint. - * @param cons the constraint - * @param clientId the client id + * + * @param constraint The constraint. + * @param clientId The client id. */ - def setILPredOfConstraint(InLayerPredecessorOfConstraint cons, String clientId) { + def setInLayerPredecessorOfConstraint(InLayerPredecessorOfConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, uri, cons.id, - cons.getReferencedNode, clientId) + setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, uri, constraint.id, + constraint.getReferencedNode, clientId) } /** * Sets a 'in layer successor'-constraint. - * @param cons the constraint - * @param clientId the client id + * + * @param constraint The constraint. + * @param clientId The client id. */ - def setILSuccOfConstraint(InLayerSuccessorOfConstraint cons, String clientId) { + def setInLayerSuccessorOfConstraint(InLayerSuccessorOfConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, uri, cons.id, - cons.getReferencedNode, clientId) + setRelativeConstraint(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, uri, constraint.id, + constraint.getReferencedNode, clientId) } /** * Delete relative constraints. - * @param dc the constraint to delete - * @param clientId the client id + * + * @param constraint The constraint to delete. + * @param clientId The client id. */ - def deleteRelativeConstraints(DeleteConstraint dc, String clientId) { + def deleteRelativeConstraints(DeleteConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = getKNode(uri, dc.id) + val kNode = getKNode(uri, constraint.id) if (kNode !== null) { val changedNodes = new LinkedList> changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, null)) @@ -94,13 +97,14 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens } /** - * Delete iLPredOf constraints. - * @param dc the constraint to delete - * @param clientId the client id + * Delete in-layer-predecessor-of constraints. + * + * @param constraint The constraint to delete. + * @param clientId The client id. */ - def deleteILPredOfConstraint(DeleteConstraint dc, String clientId) { + def deleteInLayerPredecessorOfConstraint(DeleteConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = getKNode(uri, dc.id) + val kNode = getKNode(uri, constraint.id) if (kNode !== null) { val changedNodes = new LinkedList> changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF, null)) @@ -109,13 +113,14 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens } /** - * Delete iLSuccOf constraints. - * @param dc the constraint to delete - * @param clientId the client id + * Delete in-layer-successor-of constraints. + * + * @param constraint The constraint to delete. + * @param clientId The client id. */ - def deleteILSuccOfConstraint(DeleteConstraint dc, String clientId) { + def deleteILSuccOfConstraint(DeleteConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = getKNode(uri, dc.id) + val kNode = getKNode(uri, constraint.id) if (kNode !== null) { val changedNodes = new LinkedList> changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF, null)) @@ -124,134 +129,149 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens } /** - * sets a relative constraint with a chosen {@code value} on the node that is specified by the {@code targetID}. + * Sets a relative constraint with a chosen {@code value} on the node that is specified by the {@code targetId}. * - * @param PropID the type of constraint that should be set (ILPredOfConstraint or ILSuccOfConstraint) - * The IProperty class is expected. + * @param property The IProperty class of constraint that should be set. * @param uri The uri of the diagram/file. * @param targetId The id of the node on which the constraint should be set. - * @param node the id of the node to which the relation should be set. + * @param referencedId The id of the node to which the relation should be set. + * @param clientId The client id. */ - private def setRelativeConstraint(IProperty property, String uri, String targetId, String node, + private def setRelativeConstraint( + IProperty property, + String uri, + String targetId, + String referencedId, String clientId ) { - val kNode = LSPUtil.getKNode(diagramState, uri, targetId) - val parentOfNode = kNode.parent - - // get the actual label of the node - val otherNode = LSPUtil.getKNode(diagramState, uri, node) - - var value = kNode.toString - val id = otherNode.getData(KIdentifier) + val targetNode = LSPUtil.getKNode(diagramState, uri, targetId) + val parentOfNode = targetNode.parent + + // Get the actual label of the node + val referencedNode = LSPUtil.getKNode(diagramState, uri, referencedId) + + var nameStringOfReferenceNode = targetNode.toString + val id = referencedNode.getData(KIdentifier) if (id !== null) { - value = id.id + nameStringOfReferenceNode = id.id } - - if (kNode !== null && parentOfNode !== null) { - var layerID = otherNode.getProperty(LayeredOptions.LAYERING_LAYER_ID); - var posID = otherNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID); - if (layerID === kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) - && posID > kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { - posID--; + + if (targetNode !== null && parentOfNode !== null) { + var referenceLayer = referencedNode.getProperty(LayeredOptions.LAYERING_LAYER_ID); + var targetPosition = referencedNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID); + + // Update target position depending on the constraint that should be set. + if (referenceLayer === targetNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) && + targetPosition > targetNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + targetPosition--; } if (property === LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) { - posID++; + targetPosition++; } - var layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) - var oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), - parentOfNode.children) - - // update position constraints - val layerSwap = layerID !== kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) - var relReval = new RelativeConstraintReevaluation(kNode) - var reval = new LayeredConstraintReevaluation(kNode) - - kNode.setProperty(property, null); - var List chain = InteractiveUtil.getChain(kNode, oldLayerNodes) - + + var layerNodes = InteractiveUtil.getNodesOfLayer(referenceLayer, parentOfNode.children) + var oldLayerNodes = InteractiveUtil.getNodesOfLayer( + targetNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children) + + // Update position constraints. + val layerSwap = referenceLayer !== targetNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) + var relativeConstraintReevaluation = new RelativeConstraintReevaluation(targetNode) + var absoluteConstraintReevaluation = new LayeredConstraintReevaluation(targetNode) + + targetNode.setProperty(property, null); + var List chain = InteractiveUtil.getChain(targetNode, oldLayerNodes) + if (layerSwap) { - reval.reevaluatePositionConstraintsAfterLayerSwap(layerNodes, oldLayerNodes, kNode, posID) - reval.reevaluateLayerConstraintsInChain(layerID, chain) + absoluteConstraintReevaluation. + reevaluatePositionConstraintsAfterLayerSwap(layerNodes, oldLayerNodes, targetNode, targetPosition) + absoluteConstraintReevaluation.reevaluateLayerConstraintsInChain(referenceLayer, chain) } else { - if (posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && - chain.contains(otherNode) && - posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && - posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { - // node is moved within its chain - relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) + if (targetPosition !== targetNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && + chain.contains(referencedNode) && + targetPosition >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && + targetPosition <= + chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + // Node is moved within its chain. + relativeConstraintReevaluation.reevaluateRelativeConstraintAfterSwapInChain(targetNode, oldLayerNodes) } - reval.reevaluatePositionConstraintsAfterPosChangeInLayer(layerNodes, kNode, posID) + absoluteConstraintReevaluation. + reevaluatePositionConstraintsAfterPositionChangeInLayer(layerNodes, targetNode, targetPosition) } - - var posCons = posID - if (layerSwap || posID < kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { - // posID must be increased by the number of predecessors - posCons = posID + chain.indexOf(kNode) + + var posCons = targetPosition + if (layerSwap || + targetPosition < targetNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + // Position ids must be increased by the number of predecessors. + posCons = targetPosition + chain.indexOf(targetNode) } - reval.reevaluatePosConsInChain(kNode, posCons, chain) - - // update relative constraints - if (layerSwap || posID !== kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { - relReval.checkRelCons(kNode, posID, layerNodes, oldLayerNodes, property) - relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) + absoluteConstraintReevaluation.reevaluatePositionConstraintInChain(targetNode, posCons, chain) + + // Update relative constraints. + if (layerSwap || + targetPosition !== targetNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + relativeConstraintReevaluation.checkRelativeConstraints(targetNode, targetPosition, layerNodes, oldLayerNodes, + property) + relativeConstraintReevaluation.reevaluateRelativeConstraints(targetNode, targetPosition, layerNodes, oldLayerNodes) } - val changedNodes = reval.changedNodes - changedNodes.addAll(relReval.changedNodes) - changedNodes.add(new ConstraintProperty(kNode, property, value)) - refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) + val changedNodes = absoluteConstraintReevaluation.changedNodes + changedNodes.addAll(relativeConstraintReevaluation.changedNodes) + changedNodes.add(new ConstraintProperty(targetNode, property, nameStringOfReferenceNode)) + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(targetNode), uri) } } /** * Sets a layer constraint. - * @param lc the layer constraint - * @param clientId the client id + * + * @param constraint The layer constraint. + * @param clientId The client id. */ - def setLayerConstraint(LayerConstraint lc, String clientId) { + def setLayerConstraint(LayerConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - setConstraint(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, uri, lc.id, lc.layer, lc.getLayerConstraint, clientId) + setConstraint(LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, uri, constraint.id, constraint.layer, + constraint.getLayerConstraint, clientId) } /** * Sets a position constraint. - * @param pc the position constraint - * @param clientId the client id + * + * @param constraint The position constraint. + * @param clientId The client id. */ - def setPositionConstraint(PositionConstraint pc, String clientId) { + def setPositionConstraint(PositionConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - setConstraint(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, uri, pc.id, - pc.position, pc.getPositionConstraint, clientId) + setConstraint(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, uri, constraint.id, + constraint.position, constraint.getPositionConstraint, clientId) } /** * Sets a layer constraint and a positional constraint that * are encapsulated in an instance of StaticConstraint. - * @param sc the constraint - * @param clientId the client id + * + * @param constraint The constraint. + * @param clientId The client id. */ - def setStaticConstraint(StaticConstraint sc, String clientId) { + def setStaticConstraint(StaticConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = LSPUtil.getKNode(diagramState, uri, sc.id) + val kNode = LSPUtil.getKNode(diagramState, uri, constraint.id) val parentOfNode = kNode.parent // In case that the interactive mode is active, the viewContext is not null // and the element is actually a KNode. Carry on. if (kNode !== null && parentOfNode !== null) { - /* - * As long as no increased pos constraint is present in the target layer - * and no increased layer constraint is present left to the target layer - * newLayerId === newLayer Cons && newPosCons = newPosId - * In the other cases both values can differ. - */ + // As long as no increased position constraint is present in the target layer + // and no increased layer constraint is present left to the target layer + // newLayerId === newLayerConstraint && newPosCons = newPosId + // In the other cases both values can differ. var allNodes = parentOfNode.children - var newLayerId = sc.layer - var newLayerCons = sc.getLayerConstraint + var newLayerId = constraint.layer + var newLayerConstraint = constraint.getLayerConstraint val List> changedNodes = newLinkedList; // If layerId is -1 all other nodes need to have their layerId and layerChoiceId increased. - if (newLayerCons == -1) { + if (newLayerConstraint == -1) { newLayerId++ - newLayerCons++ + newLayerConstraint++ allNodes.forEach[node | if (node.hasProperty(LayeredOptions.LAYERING_LAYER_ID)) { node.setProperty(LayeredOptions.LAYERING_LAYER_ID, @@ -276,43 +296,45 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val chain = InteractiveUtil.getChain(kNode, oldLayerNodes) // posID must be increased by the number of predecessors - val newPosId = sc.position + chain.indexOf(kNode) - val newPosCons = sc.getPositionConstraint + chain.indexOf(kNode) + val newPositionId = constraint.position + chain.indexOf(kNode) + val newPositionConstraint = constraint.getPositionConstraint + chain.indexOf(kNode) // Reevaluate insertion of node to target layer - var reval = new LayeredConstraintReevaluation(kNode) + var absoluteConstraintReevaluation = new LayeredConstraintReevaluation(kNode) - if (reval.reevaluateAfterEmptyingALayer(kNode, newLayerCons, allNodes)) { - newLayerCons-- + if (absoluteConstraintReevaluation.reevaluateAfterEmptyingALayer(kNode, newLayerConstraint, allNodes)) { + newLayerConstraint-- } - reval.reevaluatePositionConstraintsAfterLayerSwap(targetLayerNodes, oldLayerNodes, kNode, newPosId) - reval.reevaluateLayerConstraintsInChain(newLayerCons, chain) - reval.reevaluatePosConsInChain(kNode, newPosCons, chain) + absoluteConstraintReevaluation. + reevaluatePositionConstraintsAfterLayerSwap(targetLayerNodes, oldLayerNodes, kNode, newPositionId) + absoluteConstraintReevaluation.reevaluateLayerConstraintsInChain(newLayerConstraint, chain) + absoluteConstraintReevaluation.reevaluatePositionConstraintInChain(kNode, newPositionConstraint, chain) - changedNodes.addAll(reval.changedNodes) + changedNodes.addAll(absoluteConstraintReevaluation.changedNodes) changedNodes.add( new ConstraintProperty(kNode, LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT, - newPosCons)) + newPositionConstraint)) changedNodes.add( - new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, newLayerCons)) - // Update source code of the model + new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, newLayerConstraint)) - // update relative constraints - var relReval = new RelativeConstraintReevaluation(kNode) - relReval.reevaluateRelCons(kNode, newPosId, targetLayerNodes, oldLayerNodes) - changedNodes.addAll(relReval.changedNodes) + // Update relative constraints. + var relativeCOnstraintReevaluation = new RelativeConstraintReevaluation(kNode) + relativeCOnstraintReevaluation.reevaluateRelativeConstraints(kNode, newPositionId, targetLayerNodes, oldLayerNodes) + changedNodes.addAll(relativeCOnstraintReevaluation.changedNodes) + // Update source code of the model. refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } } /** * Delete a constraint. - * @param dc the constraint o delete - * @param clientId the client id + * + * @param constraint The constraint to delete. + * @param clientId The client id. */ - def deleteStaticConstraint(DeleteConstraint dc, String clientId) { + def deleteStaticConstraint(DeleteConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = getKNode(uri, dc.id) + val kNode = getKNode(uri, constraint.id) if (kNode !== null) { val changedNodes = new LinkedList> changedNodes.add( @@ -324,12 +346,13 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens /** * Delete a position constraint. - * @param dc the position constraint o delete - * @param clientId the client id + * + * @param constraint The position constraint to delete. + * @param clientId The client id. */ - def deletePositionConstraint(DeleteConstraint dc, String clientId) { + def deletePositionConstraint(DeleteConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = getKNode(uri, dc.id) + val kNode = getKNode(uri, constraint.id) if (kNode !== null) { val changedNodes = new LinkedList> changedNodes.add(new ConstraintProperty( @@ -343,12 +366,13 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens /** * Delete a layer constraint. - * @param dc the layer constraint o delete - * @param clientId the client id + * + * @param constraint The layer constraint to delete. + * @param clientId The client id. */ - def deleteLayerConstraint(DeleteConstraint dc, String clientId) { + def deleteLayerConstraint(DeleteConstraint constraint, String clientId) { val uri = diagramState.getURIString(clientId) - val kNode = getKNode(uri, dc.id) + val kNode = getKNode(uri, constraint.id) if (kNode !== null) { val changedNodes = new LinkedList> changedNodes.add(new ConstraintProperty(kNode, LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT, null)) @@ -360,33 +384,34 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * Sets a layer or position constraint with a chosen {@code value} on the node * that is specified by the {@code targetID}. * - * @param PropID the type of constraint that should be set (LayerConstraint or PositionConstraint) - * The IProperty class is expected. + * @param property The IProperty of constraint that should be set (LayerConstraint or PositionConstraint). * @param uri The uri of the diagram/file. * @param targetId The id of the node on which the constraint should be set. - * @param value Either the id of the position or the id of the layer. + * @param oldValue Either the id of the position or the id of the layer. + * @param newValue Either the value if the position constraint or the layer constraint. + * @param cliendId The client id. */ - private def setConstraint(IProperty property, String uri, String targetId, int valueId, int valueCons, + private def setConstraint(IProperty property, String uri, String targetId, int oldValue, int newValue, String clientId ) { val kNode = LSPUtil.getKNode(diagramState, uri, targetId) val parentOfNode = kNode.parent if (kNode !== null && parentOfNode !== null) { - var layerID = kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) - var posID = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT); + var layerId = kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID) + var positionId = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT); if (property === LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT) { - layerID = valueId + layerId = oldValue } - var newValueCons = valueCons - var newValueId = valueId + var newValueConstraint = newValue + var newValueId = oldValue val List> changedNodes = newLinkedList; // If layerId is -1 all other nodes need to have their layerId and layerChoiceId increased. - if (valueId == -1) { - layerID++ + if (oldValue == -1) { + layerId++ newValueId++ - newValueCons++ + newValueConstraint++ parentOfNode.children.forEach[node | if (node.hasProperty(LayeredOptions.LAYERING_LAYER_ID)) { node.setProperty(LayeredOptions.LAYERING_LAYER_ID, @@ -404,46 +429,46 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens ] } - var List layerNodes = InteractiveUtil.getNodesOfLayer(layerID, parentOfNode.children) + var List layerNodes = InteractiveUtil.getNodesOfLayer(layerId, parentOfNode.children) val oldLayerNodes = InteractiveUtil.getNodesOfLayer(kNode.getProperty(LayeredOptions.LAYERING_LAYER_ID), parentOfNode.children ) - val oldPos = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + val oldPosition = kNode.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - var relReval = new RelativeConstraintReevaluation(kNode) + var relativeConstraintReevaluation = new RelativeConstraintReevaluation(kNode) val chain = InteractiveUtil.getChain(kNode, oldLayerNodes) if (property === LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT) { - posID = valueId - if (posID != -1 && - posID >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && - posID <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { + positionId = oldValue + if (positionId != -1 && + positionId >= chain.get(0).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) && + positionId <= chain.get(chain.size - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID)) { // node is moved within its chain - relReval.reevaluateRCAfterSwapInChain(kNode, oldLayerNodes) - } else if (posID < oldPos) { + relativeConstraintReevaluation.reevaluateRelativeConstraintAfterSwapInChain(kNode, oldLayerNodes) + } else if (positionId < oldPosition) { // posID must be increased by the number of predecessors - newValueCons += chain.indexOf(kNode) + newValueConstraint += chain.indexOf(kNode) newValueId += chain.indexOf(kNode) } } - var reval = new LayeredConstraintReevaluation(kNode) + var absoluteConstraintReevalution = new LayeredConstraintReevaluation(kNode) switch (property) { case LayeredOptions.CROSSING_MINIMIZATION_POSITION_CHOICE_CONSTRAINT: { - reval.reevaluatePositionConstraintsAfterPosChangeInLayer(layerNodes, kNode, newValueId) - reval.reevaluatePosConsInChain(kNode, newValueCons, chain) + absoluteConstraintReevalution.reevaluatePositionConstraintsAfterPositionChangeInLayer(layerNodes, kNode, newValueId) + absoluteConstraintReevalution.reevaluatePositionConstraintInChain(kNode, newValueConstraint, chain) } case LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT: - reval.reevaluateLayerConstraintsInChain(layerID, chain) + absoluteConstraintReevalution.reevaluateLayerConstraintsInChain(layerId, chain) } - changedNodes.addAll(reval.changedNodes) - changedNodes.add(new ConstraintProperty(kNode, property, newValueCons)) + changedNodes.addAll(absoluteConstraintReevalution.changedNodes) + changedNodes.add(new ConstraintProperty(kNode, property, newValueConstraint)) - // update relative constraints - if (posID !== null) { - relReval.reevaluateRelCons(kNode, posID, layerNodes, oldLayerNodes) - changedNodes.addAll(relReval.changedNodes) + // Update relative constraints. + if (positionId !== null) { + relativeConstraintReevaluation.reevaluateRelativeConstraints(kNode, positionId, layerNodes, oldLayerNodes) + changedNodes.addAll(relativeConstraintReevaluation.changedNodes) }; refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) } @@ -457,9 +482,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens * This version of getKNode retrieves the root itself. If you already have retrieved the root, * then you should use the other variant. * - * @param uri The resource's uri - * @param nodeId The Id of the requested KNode - * @return The requested node + * @param uri The resource's uri. + * @param nodeId The Id of the requested KNode. + * @return The requested node. */ private def getKNode(String uri, String nodeId) { return LSPUtil.getKNode(diagramState, uri, nodeId) @@ -468,9 +493,9 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens /** * Sends request to the client to update the file according to the property changes. * - * @param changedNodes list of all changes to nodes - * @param model The main kNode - * @param uri uri of resource + * @param changedNodes The list of all changes to nodes. + * @param model The main kNode. + * @param uri The uri of resource. */ def refreshModelInEditor(List> changedNodes, KNode model, String uri) { changedNodes.forEach[constraint| diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend index a19f691b1..d021737c5 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/RelativeConstraintReevaluation.xtend @@ -32,8 +32,8 @@ import org.eclipse.xtend.lib.annotations.Accessors */ class RelativeConstraintReevaluation { - IProperty predProp = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF - IProperty succProp = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF + IProperty predecessorProperty = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF + IProperty successorProperty = LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF @Accessors(PUBLIC_GETTER) List> changedNodes = newLinkedList() @@ -48,33 +48,33 @@ class RelativeConstraintReevaluation { /** * When a node is moved between two other nodes, the relative constraints of them must be updated. * - * @param target The moved node - * @param newPos The position {@code target} is moved to - * @param newLayerNodes Nodes of the layer {@code target} is moved to - * @param oldLayerNodes Nodes of the layer {@code target} was original in + * @param target The moved node. + * @param newPosition The position {@code target} is moved to. + * @param newLayerNodes Nodes of the layer {@code target} is moved to. + * @param oldLayerNodes Nodes of the layer {@code target} was original in. */ - def reevaluateRelCons(KNode target, int newPos, List newLayerNodes, List oldLayerNodes) { + def reevaluateRelativeConstraints(KNode target, int newPosition, List newLayerNodes, List oldLayerNodes) { val chainNodes = InteractiveUtil.getChain(target, oldLayerNodes) var startOfChain = chainNodes.get(0) var endOfChain = chainNodes.get(chainNodes.size - 1) - var pos = newPos - // determine pos of new successor + var position = newPosition + // Determine newPosition of new successor. if (newLayerNodes.contains(target)) { val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - if (newPos > oldPos) { - pos++ + if (newPosition > oldPos) { + position++ } } - if (pos > 0 && pos < newLayerNodes.size) { - // update rel cons of the new pred and succ - val predNode = newLayerNodes.get(pos - 1) - val succNode = newLayerNodes.get(pos) - if (predNode.getProperty(predProp) !== null) { - changedNodes.add(new ConstraintProperty(predNode, predProp, startOfChain.labels.get(0).text)) + if (position > 0 && position < newLayerNodes.size) { + // Update relative constraint of the new predecessor and successor. + val predecessor = newLayerNodes.get(position - 1) + val successor = newLayerNodes.get(position) + if (predecessor.getProperty(predecessorProperty) !== null) { + changedNodes.add(new ConstraintProperty(predecessor, predecessorProperty, startOfChain.labels.get(0).text)) } - if (succNode.getProperty(succProp) !== null) { - changedNodes.add(new ConstraintProperty(succNode, succProp, endOfChain.labels.get(0).text)) + if (successor.getProperty(successorProperty) !== null) { + changedNodes.add(new ConstraintProperty(successor, successorProperty, endOfChain.labels.get(0).text)) } } } @@ -82,42 +82,45 @@ class RelativeConstraintReevaluation { /** * Updates relative constraints that have the moved node as target and of the target. * - * @param target The moved node - * @param newPos The position {@code target} is moved to - * @param newLayerNodes Nodes of the layer {@code target} is moved to - * @param oldLayerNodes Nodes of the layer {@code target} was original in + * @param target The moved node. + * @param newPosition The position {@code target} is moved to. + * @param newLayerNodes Nodes of the layer {@code target} is moved to. + * @param oldLayerNodes Nodes of the layer {@code target} was original in. + * @param property The property to check. */ - def checkRelCons(KNode target, int newPos, List newLayerNodes, List oldLayerNodes, IProperty prop) { - val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + def checkRelativeConstraints(KNode target, int newPosition, List newLayerNodes, List oldLayerNodes, + IProperty property + ) { + val oldPosition = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) var forbidden = false - // delete relative constraints that are overwritten by new rel cons of the target - switch(prop) { - case predProp: { - if (oldPos + 1 < oldLayerNodes.size) { - changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp, null)) + // Delete relative constraints that are overwritten by new relative constraint of the target. + switch(property) { + case predecessorProperty: { + if (oldPosition + 1 < oldLayerNodes.size) { + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPosition + 1), successorProperty, null)) } - // if the chains can not be merged, delete old rel cons and only merge moved node with chain - val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos), newLayerNodes) + // If the chains can not be merged, delete old relative constraint and only merge moved node with chain. + val chain = InteractiveUtil.getChain(newLayerNodes.get(newPosition), newLayerNodes) forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) if (forbidden) { - if (oldPos - 1 >= 0) { - changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp, null)) + if (oldPosition - 1 >= 0) { + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPosition - 1), predecessorProperty, null)) } - changedNodes.add(new ConstraintProperty(target, succProp, null)) + changedNodes.add(new ConstraintProperty(target, successorProperty, null)) } } - case succProp: { - if (oldPos - 1 >= 0) { - changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos - 1), predProp, null)) + case successorProperty: { + if (oldPosition - 1 >= 0) { + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPosition - 1), predecessorProperty, null)) } - // if the chains can not be merged, delete old rel cons and only merge moved node with chain - val chain = InteractiveUtil.getChain(newLayerNodes.get(newPos - 1), newLayerNodes) + // If the chains can not be merged, delete old relative constraint and only merge moved node with chain. + val chain = InteractiveUtil.getChain(newLayerNodes.get(newPosition - 1), newLayerNodes) forbidden = InteractiveUtil.isMergeImpossible(InteractiveUtil.getChain(target, oldLayerNodes), chain) if (forbidden) { - if (oldPos + 1 < oldLayerNodes.size) { - changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPos + 1), succProp, null)) + if (oldPosition + 1 < oldLayerNodes.size) { + changedNodes.add(new ConstraintProperty(oldLayerNodes.get(oldPosition + 1), successorProperty, null)) } - changedNodes.add(new ConstraintProperty(target, predProp, null)) + changedNodes.add(new ConstraintProperty(target, predecessorProperty, null)) } } } @@ -125,28 +128,29 @@ class RelativeConstraintReevaluation { /** * Reevaluates relative constraints after a node is moved within its chain. - * @param target The moved node - * @param layerNodes The nodes that are in the same layer as {@code target} + * + * @param target The moved node. + * @param layerNodes The nodes that are in the same layer as {@code target}. */ - def reevaluateRCAfterSwapInChain(KNode target, List layerNodes) { - // remove rel cons of target - changedNodes.add(new ConstraintProperty(target, predProp, null)) - changedNodes.add(new ConstraintProperty(target, succProp, null)) - // must be done in order for correct calculation of the chain in later reevaluation - target.setProperty(predProp, null) - target.setProperty(succProp, null) + def reevaluateRelativeConstraintAfterSwapInChain(KNode target, List layerNodes) { + // Remove relative constraint of target. + changedNodes.add(new ConstraintProperty(target, predecessorProperty, null)) + changedNodes.add(new ConstraintProperty(target, successorProperty, null)) + // Must be done in order for correct calculation of the chain in later reevaluation. + target.setProperty(predecessorProperty, null) + target.setProperty(successorProperty, null) - // remove rel cons of pred and succ that could have the moved node as target - val oldPos = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) - if (oldPos - 1 >= 0) { - val oldPred = layerNodes.get(oldPos - 1) - oldPred.setProperty(predProp, null) - changedNodes.add(new ConstraintProperty(oldPred, predProp, null)) + // Remove relative constraint of predecessor and successor that could have the moved node as target. + val oldPosition = target.getProperty(LayeredOptions.CROSSING_MINIMIZATION_POSITION_ID) + if (oldPosition - 1 >= 0) { + val oldPredecessor = layerNodes.get(oldPosition - 1) + oldPredecessor.setProperty(predecessorProperty, null) + changedNodes.add(new ConstraintProperty(oldPredecessor, predecessorProperty, null)) } - if (oldPos + 1 < layerNodes.size) { - val oldSucc = layerNodes.get(oldPos + 1) - changedNodes.add(new ConstraintProperty(oldSucc, succProp, null)) - oldSucc.setProperty(succProp, null) + if (oldPosition + 1 < layerNodes.size) { + val oldSuccessor = layerNodes.get(oldPosition + 1) + changedNodes.add(new ConstraintProperty(oldSuccessor, successorProperty, null)) + oldSuccessor.setProperty(successorProperty, null) } } From 64379152d4395f275509f9c8cafcc7cfc5938029 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Mon, 7 Nov 2022 17:15:14 +0100 Subject: [PATCH 12/27] klighd.lsp: Added more Javadoc. --- .../klighd/lsp/interactive/IConstraintSerializer.xtend | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend index d531b2f08..019576534 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend @@ -21,7 +21,7 @@ import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import java.util.List /** - * Service interface for implementions that serialize a set constraint in the model. + * Service interface for implementations that serialize a set constraint in the model. * E.g. for ElkGraphs a property is added and the graph serialized, * for SCCharts an Annotation with a layout constraint is added and the graph serialized. * @@ -38,7 +38,11 @@ interface IConstraintSerializer { def boolean canHandle(Object graph); /** - * @param + * @param changedNodes The added constraints. + * @param graph The model, e.g. SCChart or ElkGraph. + * @param uri The uri of the main source file. + * @param ls The language server. + * @param client The language client. */ def void serializeConstraints(List> changedNodes, Object graph, String uri, KGraphLanguageServerExtension ls, KGraphLanguageClient client); From 851fa8175b7b355c45a1f582e16b4996cc027a6e Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Tue, 8 Nov 2022 17:14:14 +0100 Subject: [PATCH 13/27] Initial interactive MrTree commit. --- .../META-INF/MANIFEST.MF | 2 + .../klighd/lsp/KGraphDiagramServer.xtend | 7 ++ .../gson_utils/KGraphTypeAdapterUtil.xtend | 13 +- .../lsp/interactive/mrtree/Actions.xtend | 81 ++++++++++++ .../mrtree/MrTreeActionHandler.xtend | 56 +++++++++ .../MrTreeDeletePositionConstraint.xtend | 31 +++++ ...eeInteractiveLanguageServerExtension.xtend | 119 ++++++++++++++++++ .../mrtree/MrTreeInteractiveUtil.xtend | 104 +++++++++++++++ .../mrtree/MrTreeSetPositionConstraint.xtend | 31 +++++ .../PositionConstraintReevaluation.xtend | 76 +++++++++++ .../interactive/mrtree/SetAspectRatio.xtend | 30 +++++ 11 files changed, 546 insertions(+), 4 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraint.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/SetAspectRatio.xtend diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/MANIFEST.MF b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/MANIFEST.MF index e0e0efef2..2a9c4b90c 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/MANIFEST.MF +++ b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Export-Package: de.cau.cs.kieler.klighd.lsp, de.cau.cs.kieler.klighd.lsp.gson_utils, de.cau.cs.kieler.klighd.lsp.interactive, de.cau.cs.kieler.klighd.lsp.interactive.layered, + de.cau.cs.kieler.klighd.lsp.interactive.mrtree, de.cau.cs.kieler.klighd.lsp.interactive.rectpacking, de.cau.cs.kieler.klighd.lsp.launch, de.cau.cs.kieler.klighd.lsp.model, @@ -26,6 +27,7 @@ Require-Bundle: de.cau.cs.kieler.kgraph.text, com.google.inject;bundle-version="3.0.0", org.apache.log4j;bundle-version="1.2.15", org.eclipse.elk.alg.layered, + org.eclipse.elk.alg.mrtree, org.eclipse.elk.alg.rectpacking, org.eclipse.elk.core, org.eclipse.elk.graph, diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend index d4c4cdf67..39ae8f2e0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend @@ -27,6 +27,7 @@ import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.ViewContext import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.lsp.interactive.layered.LayeredInteractiveActionHandler +import de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeActionHandler import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingInteractiveActionHandler import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer import de.cau.cs.kieler.klighd.lsp.model.CheckImagesAction @@ -87,6 +88,10 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { @Inject protected LayeredInteractiveActionHandler constraintActionHandler + + @Inject + protected MrTreeActionHandler mrTreeActionHandler + @Inject protected RectpackingInteractiveActionHandler rectpackingActionHandler @@ -253,6 +258,8 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { handle(action as RequestDiagramPieceAction) } else if (constraintActionHandler.canHandleAction(action.getKind)) { constraintActionHandler.handle(action, clientId, this) + } else if (mrTreeActionHandler.canHandleAction(action.getKind)) { + mrTreeActionHandler.handle(action, clientId, this) } else if (rectpackingActionHandler.canHandleAction(action.getKind)) { rectpackingActionHandler.handle(action, clientId, this) } else { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index 914ffe723..3f9c852eb 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -18,13 +18,18 @@ package de.cau.cs.kieler.klighd.lsp.gson_utils import com.google.gson.GsonBuilder import de.cau.cs.kieler.klighd.SynthesisOption +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerPredecessorOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerSuccessorOfConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteLayerConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeletePositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteRelativeConstraintsAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteStaticConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerPredecessorOfConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerSuccessorOfConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetLayerConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetPositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetStaticConstraintAction +import de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeSetPositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingDeletePositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingSetPositionConstraintAction import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.SetAspectRatioAction @@ -37,10 +42,6 @@ import de.cau.cs.kieler.klighd.lsp.model.SetSynthesisAction import java.awt.geom.Point2D import org.eclipse.emf.ecore.EObject import org.eclipse.sprotty.server.json.ActionTypeAdapter -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerPredecessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerSuccessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerSuccessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerPredecessorOfConstraintAction /** * Static util class to configure needed gson type adapters for KGraph serialization. @@ -81,6 +82,10 @@ class KGraphTypeAdapterUtil { // Incremental topdown actions addActionKind(RequestDiagramPieceAction.KIND, RequestDiagramPieceAction) + + // Interactive mrtree actions + addActionKind(MrTreeSetPositionConstraintAction.KIND, MrTreeSetPositionConstraintAction) + ] ) .registerTypeAdapter(Point2D, new Point2DTypeAdapter) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend new file mode 100644 index 000000000..0e6f92f39 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend @@ -0,0 +1,81 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import java.util.function.Consumer +import org.eclipse.sprotty.Action +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtend.lib.annotations.EqualsHashCode +import org.eclipse.xtend.lib.annotations.ToString + +/** + * Sets the order of a node for the MrTree algorithm. + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +public class MrTreeSetPositionConstraintAction implements Action { + public static val KIND = 'treeSetPositionConstraint' + String kind = KIND + + MrTreeSetPositionConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} + +/** + * Deletes the constraint on the node that is identified by the given id. + * + * @author sdo + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +public class MrTreeDeletePositionConstraintAction implements Action { + public static val KIND = 'treeDeletePositionConstraint' + String kind = KIND + + MrTreeDeletePositionConstraint constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} + +/** + * Deletes the constraint on the node that is identified by the given id. + * + * @author sdo + */ +@Accessors +@EqualsHashCode +@ToString(skipNulls = true) +public class SetAspectRatioAction implements Action { + public static val KIND = 'setAspectRatio' + String kind = KIND + + SetAspectRatio constraint + + new() {} + new(Consumer initializer) { + initializer.accept(this) + } +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend new file mode 100644 index 000000000..bbdbcdb49 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend @@ -0,0 +1,56 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This code is provided under the terms of the Eclipse Public License (EPL). + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import com.google.inject.Inject +import de.cau.cs.kieler.klighd.lsp.AbstractActionHandler +import de.cau.cs.kieler.klighd.lsp.KGraphDiagramServer +import org.eclipse.sprotty.Action + +/** + * This class handles all sprotty actions for the interactive mrtree algorithm. + * + * @author sdo + * + */ +class MrTreeActionHandler extends AbstractActionHandler { + + @Inject + MrTreeInteractiveLanguageServerExtension lsExtension + + new() { + this.supportedMessages = newHashMap( + MrTreeSetPositionConstraintAction.KIND -> MrTreeSetPositionConstraintAction, + MrTreeDeletePositionConstraintAction.KIND -> MrTreeDeletePositionConstraintAction, + SetAspectRatioAction.KIND -> SetAspectRatioAction) + } + + override handle(Action action, String clientId, KGraphDiagramServer server) { + if (action instanceof MrTreeSetPositionConstraintAction) { + synchronized((server as KGraphDiagramServer).modelLock) { + lsExtension.setPositionConstraint(action.constraint, clientId) + } + } else if (action instanceof MrTreeDeletePositionConstraintAction) { + synchronized((server as KGraphDiagramServer).modelLock) { + lsExtension.deletePositionConstraint(action.constraint, clientId) + } + } else if (action instanceof SetAspectRatioAction) { + synchronized((server as KGraphDiagramServer).modelLock) { + lsExtension.setAspectRatio(action.constraint, clientId) + } + } else { + throw new IllegalArgumentException("Action " + action.kind + " not supported by handler " + this.class.simpleName) + } + } + +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend new file mode 100644 index 000000000..db2439acf --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend @@ -0,0 +1,31 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import org.eclipse.xtend.lib.annotations.Data + +/** + * Message send if an order constraint is deleted. + * Only the node id is required to do so, since it has its previous position saved together with its actual position. + * + * @author sdo + * + */ +@Data +class MrTreeDeletePositionConstraint { + String id +} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend new file mode 100644 index 000000000..c4c497da3 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend @@ -0,0 +1,119 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import com.google.inject.Inject +import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil +import de.cau.cs.kieler.klighd.lsp.KGraphDiagramState +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import de.cau.cs.kieler.klighd.lsp.LSPUtil +import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty +import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil +import java.util.List +import javax.inject.Singleton +import org.eclipse.elk.alg.mrtree.options.MrTreeOptions +import org.eclipse.elk.graph.properties.IProperty +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtext.ide.server.ILanguageServerAccess +import org.eclipse.xtext.ide.server.ILanguageServerExtension + +/** + * Language server extension to change the mrtree algorithm in the interactive mode. + * @author sdo + * + */ +@Singleton +class MrTreeInteractiveLanguageServerExtension implements ILanguageServerExtension { + + @Accessors KGraphLanguageClient client; + + @Inject + KGraphDiagramState diagramState + + @Inject + KGraphLanguageServerExtension languageServer + + override initialize(ILanguageServerAccess access) { + } + + /** + * Set order constraint of node specified by node id. + * This changes all order values of all constraints of a previous layout run. + * + * @param constraint constraint to be set + * @param clientId identifier of diagram + */ + def setPositionConstraint(MrTreeSetPositionConstraint pc, String clientId) { + val uri = diagramState.getURIString(clientId) + setConstraint(MrTreeOptions.POSITION_CONSTRAINT, uri, pc.id, + pc.position, pc.positionConstraint) + } + + def deletePositionConstraint(MrTreeDeletePositionConstraint constraint, String clientId) { + // Not implemented + } + + /** + * Sets the aspect ratio. + */ + def setAspectRatio(SetAspectRatio constraint, String clientId) { + // Not implemented + } + + /** + * Sets a layer or position constraint with a chosen {@code value} on the node + * that is specified by the {@code targetID}. + * + * @param PropID the type of constraint that should be set (LayerConstraint or PositionConstraint) + * The IProperty class is expected. + * @param uri The uri of the diagram/file. + * @param targetID The id of the node on which the constraint should be set. + * @param value Either the id of the position or the id of the layer. + */ + private def setConstraint(IProperty property, String uri, String targetID, int valueId, int valueCons) { + val kNode = LSPUtil.getKNode(diagramState, uri, targetID) + val parentOfNode = kNode.parent + + if (kNode !== null && parentOfNode !== null) { + val reeval = new PositionConstraintReevaluation(kNode) + reeval.reevaluatePositionConstraintsAfterPosChangeInLayer(parentOfNode, kNode, valueId) + + var changedNodes = reeval.changedNodes + refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(kNode), uri) + } + } + + + + /** + * Sends request to the client to update the file according to the property changes. + * + * @param changedNodes The list of all changes to nodes. + * @param model The main kNode. + * @param uri The uri of resource. + */ + def refreshModelInEditor(List> changedNodes, KNode model, String uri) { + changedNodes.forEach[constraint| + val KNode kNode = constraint.KNode + kNode.setProperty(constraint.property, constraint.value) + ] + InteractiveUtil.serializeConstraints(changedNodes, model, uri, this.languageServer, this.client) + return + } +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend new file mode 100644 index 000000000..20b6270db --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend @@ -0,0 +1,104 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import de.cau.cs.kieler.klighd.kgraph.KEdge +import de.cau.cs.kieler.klighd.kgraph.KNode +import java.util.ArrayList +import java.util.Comparator +import java.util.List +import java.util.stream.Collectors +import org.eclipse.elk.alg.mrtree.options.MrTreeOptions +import org.eclipse.elk.core.math.KVector +import org.eclipse.elk.core.options.Direction + +/** + * Provides utility methods for the interactive mrtree algorithm. + * + * @author sdo + * + */ +class MrTreeInteractiveUtil { + /** + * Sets the required options for the non interactive layout run. + */ + static def void setRequiredInteractiveOptions(KNode root) { + // TODO: Implement if needed + } + + static def List getSiblings(KNode n, KNode parent) { + val lowestParent = getLowestParent(n, parent); + if (lowestParent === null) + return new ArrayList(); + val siblings = parent.children.stream. + filter[x | lowestParent == getLowestParent(x, parent)].collect(Collectors.toList) + return siblings + } + + static def KNode getLowestParent(KNode n, KNode parent) { + val dirVec = getDirectionVector(parent); + if (n.incomingEdges.size == 0) + return null + val sources = n.incomingEdges.stream().map[x | x.source].collect(Collectors.toList) + val parents = parent.children.stream.filter[x | sources.contains(x)].collect(Collectors.toList) + + if (parents.size < 1) + return null + else if (parents.size == 1) + return parents.get(0) + else { + val lowestParentPos = parents.stream. + map[x | new KVector(x.xpos + x.width / 2, x.ypos + x.height / 2).dotProduct(dirVec)]. + max(Comparator.naturalOrder).get + val lowestParent = parents.stream. + filter[x | new KVector(x.xpos + x.width / 2, x.ypos + x.height / 2).dotProduct(dirVec) == lowestParentPos]. + findFirst.get + + return lowestParent; + } + } + + /** + * Gets a KVector which faces in the direction of the layout direction of parent + * @param parent the parent node of the graph + * @return the KVector + */ + static def KVector getDirectionVector(KNode parent) { + val direction = parent.getProperty(MrTreeOptions.DIRECTION) + if (direction == Direction.LEFT) + return new KVector(-1, 0) + else if (direction == Direction.RIGHT) + return new KVector(1, 0) + else if (direction == Direction.UP) + return new KVector(0, -1) + else + return new KVector(0, 1) + } + + /** + * Get the child nodes of n within a tree. + * @param n the n + * @return the child nodes of n within a tree + */ + static def List getChildren(KNode n) { + var re = new ArrayList(); + for (KEdge out : n.getOutgoingEdges()) { + re.add(out.getTarget()); + } + return re.stream().distinct().collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraint.xtend new file mode 100644 index 000000000..5700b26f1 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraint.xtend @@ -0,0 +1,31 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import org.eclipse.xtend.lib.annotations.Data + +/** + * Data class for a position constraint sent from client to server for the mrtree algorithm. + * + * @author sdo + */ +@Data +class MrTreeSetPositionConstraint { + String id + int position + int positionConstraint +} diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend new file mode 100644 index 000000000..55953edd9 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend @@ -0,0 +1,76 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import de.cau.cs.kieler.klighd.kgraph.KNode +import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty +import java.util.LinkedList +import org.eclipse.elk.alg.mrtree.options.MrTreeOptions +import org.eclipse.xtend.lib.annotations.Accessors + +/** + * Class to reevalute position constraints for MrTree. + * + * @author jnc, sdo + */ +class PositionConstraintReevaluation { + @Accessors(PUBLIC_GETTER) + KNode target + + @Accessors(PUBLIC_GETTER) + LinkedList> changedNodes = newLinkedList() + + new(KNode target) { + this.target = target + } + + /** + * Adjusts position constraints in a layer after one node has been introduced to it. + * @param nodesOfLayer the nodes of the layer + * @param target the moved node + * @param newPosition the new position of the node + */ + def reevaluatePositionConstraintsAfterPosChangeInLayer(KNode parent, KNode target, int newPosition) { + var targetSiblings = MrTreeInteractiveUtil.getSiblings(target, parent) + + // There is no point in sorting a list with less than 2 elements. + if (targetSiblings.size <= 1) { + return + } + + // Sort list by node positions. + if (parent.getProperty(MrTreeOptions.DIRECTION).horizontal) + targetSiblings = targetSiblings.sortBy[ypos] + else + targetSiblings = targetSiblings.sortBy[xpos] + + // Set target node to its target position. + val newPositionInBounds = + if (newPosition >= targetSiblings.length) targetSiblings.length - 1 + else newPosition + if (newPositionInBounds == targetSiblings.indexOf(target)) { + return + } + targetSiblings.remove(target); + targetSiblings.add(newPositionInBounds, target); + + // Set node position constraint to its list index. + for (var i = 0; i < targetSiblings.length; i++) { + changedNodes.add(new ConstraintProperty(targetSiblings.get(i), MrTreeOptions.POSITION_CONSTRAINT, i)) + } + } +} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/SetAspectRatio.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/SetAspectRatio.xtend new file mode 100644 index 000000000..6c1e68719 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/SetAspectRatio.xtend @@ -0,0 +1,30 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package de.cau.cs.kieler.klighd.lsp.interactive.mrtree + +import org.eclipse.xtend.lib.annotations.Data + +/** + * Data class to set a new aspect ratio which is sent from client to server for the mrtree algorithm. + * + * @author sdo + */ +@Data +class SetAspectRatio { + String id + Double aspectRatio +} From 3f80be6b6baa8e89f8f645d560d8b8cad3ba08ac Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 11 Nov 2022 15:59:41 +0100 Subject: [PATCH 14/27] klighd.lsp: mrtree: Cleanup --- .../mrtree/MrTreeActionHandler.xtend | 13 +----- .../MrTreeDeletePositionConstraint.xtend | 31 -------------- ...eeInteractiveLanguageServerExtension.xtend | 11 ----- ...> MrTreeSetPositionConstraintAction.xtend} | 40 ------------------- 4 files changed, 1 insertion(+), 94 deletions(-) delete mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend rename plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/{Actions.xtend => MrTreeSetPositionConstraintAction.xtend} (56%) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend index bbdbcdb49..a6c39d756 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeActionHandler.xtend @@ -29,10 +29,7 @@ class MrTreeActionHandler extends AbstractActionHandler { MrTreeInteractiveLanguageServerExtension lsExtension new() { - this.supportedMessages = newHashMap( - MrTreeSetPositionConstraintAction.KIND -> MrTreeSetPositionConstraintAction, - MrTreeDeletePositionConstraintAction.KIND -> MrTreeDeletePositionConstraintAction, - SetAspectRatioAction.KIND -> SetAspectRatioAction) + this.supportedMessages = newHashMap(MrTreeSetPositionConstraintAction.KIND -> MrTreeSetPositionConstraintAction) } override handle(Action action, String clientId, KGraphDiagramServer server) { @@ -40,14 +37,6 @@ class MrTreeActionHandler extends AbstractActionHandler { synchronized((server as KGraphDiagramServer).modelLock) { lsExtension.setPositionConstraint(action.constraint, clientId) } - } else if (action instanceof MrTreeDeletePositionConstraintAction) { - synchronized((server as KGraphDiagramServer).modelLock) { - lsExtension.deletePositionConstraint(action.constraint, clientId) - } - } else if (action instanceof SetAspectRatioAction) { - synchronized((server as KGraphDiagramServer).modelLock) { - lsExtension.setAspectRatio(action.constraint, clientId) - } } else { throw new IllegalArgumentException("Action " + action.kind + " not supported by handler " + this.class.simpleName) } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend deleted file mode 100644 index db2439acf..000000000 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeDeletePositionConstraint.xtend +++ /dev/null @@ -1,31 +0,0 @@ -/* - * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * - * http://rtsys.informatik.uni-kiel.de/kieler - * - * Copyright 2022 by - * + Kiel University - * + Department of Computer Science - * + Real-Time and Embedded Systems Group - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - */ -package de.cau.cs.kieler.klighd.lsp.interactive.mrtree - -import org.eclipse.xtend.lib.annotations.Data - -/** - * Message send if an order constraint is deleted. - * Only the node id is required to do so, since it has its previous position saved together with its actual position. - * - * @author sdo - * - */ -@Data -class MrTreeDeletePositionConstraint { - String id -} \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend index c4c497da3..e5ef7c37d 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend @@ -64,17 +64,6 @@ class MrTreeInteractiveLanguageServerExtension implements ILanguageServerExtensi setConstraint(MrTreeOptions.POSITION_CONSTRAINT, uri, pc.id, pc.position, pc.positionConstraint) } - - def deletePositionConstraint(MrTreeDeletePositionConstraint constraint, String clientId) { - // Not implemented - } - - /** - * Sets the aspect ratio. - */ - def setAspectRatio(SetAspectRatio constraint, String clientId) { - // Not implemented - } /** * Sets a layer or position constraint with a chosen {@code value} on the node diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraintAction.xtend similarity index 56% rename from plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend rename to plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraintAction.xtend index 0e6f92f39..f860449ab 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeSetPositionConstraintAction.xtend @@ -39,43 +39,3 @@ public class MrTreeSetPositionConstraintAction implements Action { initializer.accept(this) } } - -/** - * Deletes the constraint on the node that is identified by the given id. - * - * @author sdo - */ -@Accessors -@EqualsHashCode -@ToString(skipNulls = true) -public class MrTreeDeletePositionConstraintAction implements Action { - public static val KIND = 'treeDeletePositionConstraint' - String kind = KIND - - MrTreeDeletePositionConstraint constraint - - new() {} - new(Consumer initializer) { - initializer.accept(this) - } -} - -/** - * Deletes the constraint on the node that is identified by the given id. - * - * @author sdo - */ -@Accessors -@EqualsHashCode -@ToString(skipNulls = true) -public class SetAspectRatioAction implements Action { - public static val KIND = 'setAspectRatio' - String kind = KIND - - SetAspectRatio constraint - - new() {} - new(Consumer initializer) { - initializer.accept(this) - } -} From 75b94886d4d8d22b874d6c28be0b4b915441c44d Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 16 Dec 2022 10:59:05 +0100 Subject: [PATCH 15/27] Fix chain empties layer after setStatic. THis should also be fixed when setting a relative constraint that empties a layer. --- .../interactive/layered/LayeredConstraintReevaluation.xtend | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend index 20873ad00..32a7ad6e0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredConstraintReevaluation.xtend @@ -116,6 +116,7 @@ class LayeredConstraintReevaluation { val layerConstraintTarget = ConstraintsUtils.getLayerConstraint(target) val layerId = target.getProperty(LayeredOptions.LAYERING_LAYER_ID) var originalLayerIndex = 0 + // Calculate previous desired layer of target. if (layerConstraintTarget === null || layerConstraintTarget <= layerId) { originalLayerIndex = layerId } else { @@ -123,7 +124,7 @@ class LayeredConstraintReevaluation { } val originalLayer = InteractiveUtil.getNodesOfLayer(originalLayerIndex, nodes) - if (originalLayer.length == 1) { + if (originalLayer.length == InteractiveUtil.getChain(target, originalLayer).size()) { // If a layer is emptied and disappears from the drawing // then all layer constraint with a value higher or equal than // the disappeared layer need to be decremented. From 44e211fadf3e252665d6b6249062a9a96118bfd8 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 16 Dec 2022 13:12:46 +0100 Subject: [PATCH 16/27] interactive: layered: Setting constraints checks for empty layer. --- .../lsp/interactive/InteractiveUtil.xtend | 24 +++++++++++++++---- ...edInteractiveLanguageServerExtension.xtend | 15 +++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 91a3c5786..16b30a04f 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -18,6 +18,7 @@ package de.cau.cs.kieler.klighd.lsp.interactive import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties +import de.cau.cs.kieler.klighd.kgraph.KIdentifier import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension @@ -115,8 +116,8 @@ class InteractiveUtil { // from node to the start for (var i = pos - 1; i >= 0; i--) { - if (layerNodes.get(i).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF) !== null - || layerNodes.get(i + 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) !== null) { + if (layerNodes.get(i).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF) == getIdOfNode(layerNodes.get(i + 1)) + || layerNodes.get(i + 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) == getIdOfNode(layerNodes.get(i))) { chainNodes.add(0, layerNodes.get(i)) } else { i = -1 @@ -125,8 +126,8 @@ class InteractiveUtil { // count from node to the end for (var i = pos + 1; i < layerNodes.size; i++) { - if (layerNodes.get(i).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) !== null - || layerNodes.get(i - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF) !== null) { + if (layerNodes.get(i).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_SUCC_OF) == getIdOfNode(layerNodes.get(i - 1)) + || layerNodes.get(i - 1).getProperty(LayeredOptions.CROSSING_MINIMIZATION_IN_LAYER_PRED_OF) == getIdOfNode(layerNodes.get(i))) { chainNodes.add(layerNodes.get(i)) } else { i = layerNodes.size @@ -195,4 +196,19 @@ class InteractiveUtil { return } + /** + * Returns id of a node. + * + * @param node The node. + * @returns The id string of the node. + */ + static def String getIdOfNode(KNode node) { + var nameStringOfReferenceNode = node.toString + val id = node.getData(KIdentifier) + if (id !== null) { + nameStringOfReferenceNode = id.id + } + return nameStringOfReferenceNode + } + } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend index 36c11357f..56f874a0d 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/LayeredInteractiveLanguageServerExtension.xtend @@ -217,6 +217,15 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens val changedNodes = absoluteConstraintReevaluation.changedNodes changedNodes.addAll(relativeConstraintReevaluation.changedNodes) changedNodes.add(new ConstraintProperty(targetNode, property, nameStringOfReferenceNode)) + if (layerSwap) { + // Already apply changes to be able to correctly identify if a chain is split because of the new + // relative constraint. + changedNodes.forEach[constraint| + val KNode kNode = constraint.KNode + kNode.setProperty(constraint.property, constraint.value) + ] + absoluteConstraintReevaluation.reevaluateAfterEmptyingALayer(targetNode, referenceLayer, parentOfNode.children) + } refreshModelInEditor(changedNodes, KGraphUtil.getRootNodeOf(targetNode), uri) } } @@ -458,8 +467,12 @@ class LayeredInteractiveLanguageServerExtension implements ILanguageServerExtens absoluteConstraintReevalution.reevaluatePositionConstraintsAfterPositionChangeInLayer(layerNodes, kNode, newValueId) absoluteConstraintReevalution.reevaluatePositionConstraintInChain(kNode, newValueConstraint, chain) } - case LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT: + case LayeredOptions.LAYERING_LAYER_CHOICE_CONSTRAINT: { absoluteConstraintReevalution.reevaluateLayerConstraintsInChain(layerId, chain) + if (absoluteConstraintReevalution.reevaluateAfterEmptyingALayer(kNode, newValueConstraint, parentOfNode.children)) { + newValueConstraint-- + } + } } changedNodes.addAll(absoluteConstraintReevalution.changedNodes) From 5c1d02bd2cc4b7f7dd26ed604438c2262a3942e5 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Thu, 7 Mar 2024 15:42:52 +0100 Subject: [PATCH 17/27] javax-> google Singleton --- .../mrtree/MrTreeInteractiveLanguageServerExtension.xtend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend index e5ef7c37d..920772086 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend @@ -17,6 +17,7 @@ package de.cau.cs.kieler.klighd.lsp.interactive.mrtree import com.google.inject.Inject +import com.google.inject.Singleton import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil import de.cau.cs.kieler.klighd.lsp.KGraphDiagramState @@ -26,7 +27,6 @@ import de.cau.cs.kieler.klighd.lsp.LSPUtil import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty import de.cau.cs.kieler.klighd.lsp.interactive.InteractiveUtil import java.util.List -import javax.inject.Singleton import org.eclipse.elk.alg.mrtree.options.MrTreeOptions import org.eclipse.elk.graph.properties.IProperty import org.eclipse.xtend.lib.annotations.Accessors From 24205870dd0318136945487029c07788475d78e0 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Thu, 7 Mar 2024 18:24:11 +0100 Subject: [PATCH 18/27] Fixed order for serialize to get correct text. --- .../kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend | 8 ++++---- .../kieler/klighd/lsp/interactive/InteractiveUtil.xtend | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend index bc5a02906..1f5252df6 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend @@ -45,10 +45,6 @@ class ElkGraphConstraintSerializer implements IConstraintSerializer { KGraphLanguageServerExtension ls, KGraphLanguageClient client ) { - changedNodes.forEach[c| - val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) as ElkNode - elkNode.setProperty(c.property, c.value) - ] // Serialize model into given uri. val resource = ls.getResource(uri) @@ -56,6 +52,10 @@ class ElkGraphConstraintSerializer implements IConstraintSerializer { var outputStream = new ByteArrayOutputStream resource.save(outputStream, emptyMap) val codeBefore = outputStream.toString + changedNodes.forEach[c| + val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMENT) as ElkNode + elkNode.setProperty(c.property, c.value) + ] val Map> changes = newHashMap // Get changed file as String outputStream = new ByteArrayOutputStream diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 16b30a04f..24f111737 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -179,9 +179,9 @@ class InteractiveUtil { ) { var serializer = false - var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMEMT) - if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMEMT)) { - sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMEMT) + var sourceModel = model.getProperty(KlighdInternalProperties.MODEL_ELEMENT) + if (!model.hasProperty(KlighdInternalProperties.MODEL_ELEMENT)) { + sourceModel = model.children.get(0).getProperty(KlighdInternalProperties.MODEL_ELEMENT) } for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, KlighdDataManager.getClassLoader())) { From a9592a98ffa39cb8e8583fbb20dfefa86a14db49 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Fri, 8 Mar 2024 08:35:03 +0100 Subject: [PATCH 19/27] lsp-interaction: Fixed javadoc errors. --- .../cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend | 2 +- .../mrtree/MrTreeInteractiveLanguageServerExtension.xtend | 2 +- .../lsp/interactive/mrtree/PositionConstraintReevaluation.xtend | 2 +- .../RectpackingInteractiveLanguageServerExtension.xtend | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index 24f111737..f450cb878 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -200,7 +200,7 @@ class InteractiveUtil { * Returns id of a node. * * @param node The node. - * @returns The id string of the node. + * @return The id string of the node. */ static def String getIdOfNode(KNode node) { var nameStringOfReferenceNode = node.toString diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend index 920772086..6832940c1 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveLanguageServerExtension.xtend @@ -56,7 +56,7 @@ class MrTreeInteractiveLanguageServerExtension implements ILanguageServerExtensi * Set order constraint of node specified by node id. * This changes all order values of all constraints of a previous layout run. * - * @param constraint constraint to be set + * @param pc constraint to be set * @param clientId identifier of diagram */ def setPositionConstraint(MrTreeSetPositionConstraint pc, String clientId) { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend index 55953edd9..dced571fd 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/PositionConstraintReevaluation.xtend @@ -40,7 +40,7 @@ class PositionConstraintReevaluation { /** * Adjusts position constraints in a layer after one node has been introduced to it. - * @param nodesOfLayer the nodes of the layer + * @param parent the nodes of the layer * @param target the moved node * @param newPosition the new position of the node */ diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend index c15fc6846..f7ab13f42 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/rectpacking/RectpackingInteractiveLanguageServerExtension.xtend @@ -163,7 +163,7 @@ class RectpackingInteractiveLanguageServerExtension implements ILanguageServerEx /** * Applies property changes to the file given by the uri by sending by notifying the client to execute the changes. * - * @param changedNodes The KNodes that changed. + * @param constraint The constraint to serialize * @param model The main KNode * @param uri uri of resource */ From 7fd0f6746f2ac81d43951020747fd68bdae1ba1f Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Tue, 12 Mar 2024 13:27:19 +0100 Subject: [PATCH 20/27] Use actionhandler service interface for interactive layout handlers. --- ...de.cau.cs.kieler.klighd.lsp.IActionHandler | 3 ++ .../klighd/lsp/AbstractActionHandler.xtend | 20 +++++--- .../cs/kieler/klighd/lsp/IActionHandler.xtend | 5 ++ .../klighd/lsp/KGraphDiagramServer.xtend | 40 ++++++++------- .../gson_utils/KGraphTypeAdapterUtil.xtend | 51 +++++-------------- .../klighd/lsp/launch/AbstractLsCreator.xtend | 2 +- 6 files changed, 57 insertions(+), 64 deletions(-) create mode 100644 plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler new file mode 100644 index 000000000..6e03b9500 --- /dev/null +++ b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler @@ -0,0 +1,3 @@ +de.cau.cs.kieler.klighd.lsp.interactive.layered.LayeredInteractiveActionHandler +de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingInteractiveActionHandler +de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeActionHandler \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend index 0c3d93bb4..738cadec9 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend @@ -16,8 +16,8 @@ */ package de.cau.cs.kieler.klighd.lsp -import java.util.HashMap -import org.eclipse.xtend.lib.annotations.Accessors +import java.util.Map +import org.eclipse.sprotty.Action /** * Abstract class to handle Sprotty actions. @@ -26,11 +26,17 @@ import org.eclipse.xtend.lib.annotations.Accessors */ abstract class AbstractActionHandler implements IActionHandler { - @Accessors(PUBLIC_GETTER, PROTECTED_SETTER) - HashMap> supportedMessages = newHashMap + Map> supportedMessages + + override Map> getSupportedMessages() { + return supportedMessages + } + + def setSupportedMessages(Map> messages) { + this.supportedMessages = messages + } override canHandleAction(String kind) { - return supportedMessages.containsKey(kind) - - } + return supportedMessages.containsKey(kind) + } } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend index 56aa23794..da17fabc2 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend @@ -17,6 +17,7 @@ package de.cau.cs.kieler.klighd.lsp import org.eclipse.sprotty.Action +import java.util.Map /** * Service Interface for ActionHandler. @@ -24,6 +25,10 @@ import org.eclipse.sprotty.Action * @author sdo */ interface IActionHandler { + + + def Map> getSupportedMessages(); + /** * Checks and returns true if this ActionHandler can handle this action. * @param kind String identifier of action diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend index 26168d214..459b816a0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend @@ -20,15 +20,13 @@ import com.google.common.base.Strings import com.google.common.base.Throwables import com.google.common.io.ByteStreams import com.google.inject.Inject +import com.google.inject.Injector import de.cau.cs.kieler.klighd.IAction import de.cau.cs.kieler.klighd.IAction.ActionContext import de.cau.cs.kieler.klighd.Klighd import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.ViewContext import de.cau.cs.kieler.klighd.kgraph.KNode -import de.cau.cs.kieler.klighd.lsp.interactive.layered.LayeredInteractiveActionHandler -import de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeActionHandler -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingInteractiveActionHandler import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer import de.cau.cs.kieler.klighd.lsp.model.CheckImagesAction import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction @@ -50,8 +48,11 @@ import java.io.InputStream import java.util.ArrayList import java.util.Base64 import java.util.Collection +import java.util.HashMap import java.util.List import java.util.Map +import java.util.ServiceLoader +import java.util.Set import java.util.concurrent.CompletableFuture import org.apache.log4j.Logger import org.eclipse.core.runtime.Platform @@ -91,15 +92,9 @@ import org.eclipse.xtend.lib.annotations.Accessors class KGraphDiagramServer extends LanguageAwareDiagramServer { static val LOG = Logger.getLogger(KGraphDiagramServer) - @Inject - protected LayeredInteractiveActionHandler constraintActionHandler - - @Inject - protected MrTreeActionHandler mrTreeActionHandler + @Inject protected Injector injector - - @Inject - protected RectpackingInteractiveActionHandler rectpackingActionHandler + Map handlers = new HashMap @Inject protected KGraphDiagramState diagramState @@ -149,6 +144,13 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { currentRoot = new SModelRoot(); currentRoot.setType("NONE"); currentRoot.setId("ROOT"); + // Create map of registered action kinds and handlers. + ServiceLoader.load(IActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | + val Set kindsSupported = handler.supportedMessages.keySet + for (kind : kindsSupported) { + handlers.put(kind, handler); + } + ] } /** @@ -261,14 +263,16 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { handle(action as RefreshLayoutAction) } else if (action.getKind === RequestDiagramPieceAction.KIND) { handle(action as RequestDiagramPieceAction) - } else if (constraintActionHandler.canHandleAction(action.getKind)) { - constraintActionHandler.handle(action, clientId, this) - } else if (mrTreeActionHandler.canHandleAction(action.getKind)) { - mrTreeActionHandler.handle(action, clientId, this) - } else if (rectpackingActionHandler.canHandleAction(action.getKind)) { - rectpackingActionHandler.handle(action, clientId, this) } else { - super.accept(message) + val handlerInstance = handlers.get(action.kind) + if (handlerInstance !== null) { + // Even though we have an instance, it is not yet populated with all injected things. + val handler = injector.getInstance(handlers.get(action.kind).class) + handler.handle(action, clientId, this) + } else { + // If no handler is registered for this message. Let the default super class handle it. + super.accept(message) + } } } } catch (Exception e) { diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index 3f9c852eb..c75a48d86 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -17,22 +17,10 @@ package de.cau.cs.kieler.klighd.lsp.gson_utils import com.google.gson.GsonBuilder +import com.google.inject.Injector +import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.SynthesisOption -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerPredecessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteInLayerSuccessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteLayerConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeletePositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteRelativeConstraintsAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.DeleteStaticConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerPredecessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetInLayerSuccessorOfConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetLayerConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetPositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.layered.SetStaticConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.mrtree.MrTreeSetPositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingDeletePositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.RectpackingSetPositionConstraintAction -import de.cau.cs.kieler.klighd.lsp.interactive.rectpacking.SetAspectRatioAction +import de.cau.cs.kieler.klighd.lsp.IActionHandler import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction import de.cau.cs.kieler.klighd.lsp.model.PerformActionAction import de.cau.cs.kieler.klighd.lsp.model.RefreshDiagramAction @@ -40,16 +28,17 @@ import de.cau.cs.kieler.klighd.lsp.model.RefreshLayoutAction import de.cau.cs.kieler.klighd.lsp.model.RequestDiagramPieceAction import de.cau.cs.kieler.klighd.lsp.model.SetSynthesisAction import java.awt.geom.Point2D +import java.util.ServiceLoader import org.eclipse.emf.ecore.EObject import org.eclipse.sprotty.server.json.ActionTypeAdapter /** * Static util class to configure needed gson type adapters for KGraph serialization. * - * @author nre + * @author nre, sdo */ class KGraphTypeAdapterUtil { - def static GsonBuilder configureGson(GsonBuilder gsonBuilder) { + def static GsonBuilder configureGson(GsonBuilder gsonBuilder, Injector injector) { gsonBuilder .registerTypeAdapterFactory( new ActionTypeAdapter.Factory => [ @@ -60,31 +49,17 @@ class KGraphTypeAdapterUtil { addActionKind(RefreshDiagramAction.KIND, RefreshDiagramAction) addActionKind(RefreshLayoutAction.KIND, RefreshLayoutAction) - // Interactive layered actions - addActionKind(SetStaticConstraintAction.KIND, SetStaticConstraintAction) - addActionKind(SetPositionConstraintAction.KIND, SetPositionConstraintAction) - addActionKind(SetLayerConstraintAction.KIND, SetLayerConstraintAction) - addActionKind(DeleteStaticConstraintAction.KIND, DeleteStaticConstraintAction) - addActionKind(DeletePositionConstraintAction.KIND, DeletePositionConstraintAction) - addActionKind(DeleteLayerConstraintAction.KIND, DeleteLayerConstraintAction) - //relative constraints - addActionKind(SetInLayerPredecessorOfConstraintAction.KIND, SetInLayerPredecessorOfConstraintAction) - addActionKind(SetInLayerSuccessorOfConstraintAction.KIND, SetInLayerSuccessorOfConstraintAction) - addActionKind(DeleteRelativeConstraintsAction.KIND, DeleteRelativeConstraintsAction) - addActionKind(DeleteInLayerPredecessorOfConstraintAction.KIND, DeleteInLayerPredecessorOfConstraintAction) - addActionKind(DeleteInLayerSuccessorOfConstraintAction.KIND, DeleteInLayerSuccessorOfConstraintAction) - - - // Interactive rectpacking actions - addActionKind(RectpackingSetPositionConstraintAction.KIND, RectpackingSetPositionConstraintAction) - addActionKind(RectpackingDeletePositionConstraintAction.KIND, RectpackingDeletePositionConstraintAction) - addActionKind(SetAspectRatioAction.KIND, SetAspectRatioAction) + // Load all registered action handlers and add their actions. + ServiceLoader.load(IActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | + val handlerInstance = injector.getInstance(handler.class) + handlerInstance.supportedMessages.keySet.forEach[kind | + addActionKind(kind, handlerInstance.supportedMessages.get(kind)) + ] + ] // Incremental topdown actions addActionKind(RequestDiagramPieceAction.KIND, RequestDiagramPieceAction) - // Interactive mrtree actions - addActionKind(MrTreeSetPositionConstraintAction.KIND, MrTreeSetPositionConstraintAction) ] ) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend index 246644a01..efd04e19c 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/launch/AbstractLsCreator.xtend @@ -124,7 +124,7 @@ abstract class AbstractLsCreator implements ILsCreator { // TypeAdapter is needed to be able to send recursive data in json val Consumer configureGson = [ gsonBuilder | - KGraphTypeAdapterUtil.configureGson(gsonBuilder) + KGraphTypeAdapterUtil.configureGson(gsonBuilder, injector) ] // Get all LSExtensions to use them as local services val localServices = newArrayList From 624aa90f4872ce50298d4fcf38423d4f7b50be2f Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 14:36:42 +0100 Subject: [PATCH 21/27] Moved ElkGraph serializer to klighd.lsp.interactive. --- ...u.cs.kieler.klighd.lsp.interactive.IConstraintSerializer | 2 +- .../{ => interactive}/ElkGraphConstraintSerializer.xtend | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/{ => interactive}/ElkGraphConstraintSerializer.xtend (93%) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer index e09a76c3d..67775785d 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer +++ b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer @@ -1 +1 @@ -de.cau.cs.kieler.klighd.lsp.ElkGraphConstraintSerializer \ No newline at end of file +de.cau.cs.kieler.klighd.lsp.interactive.ElkGraphConstraintSerializer \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend similarity index 93% rename from plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend rename to plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend index 1f5252df6..301d96c89 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend @@ -14,11 +14,11 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package de.cau.cs.kieler.klighd.lsp +package de.cau.cs.kieler.klighd.lsp.interactive import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties -import de.cau.cs.kieler.klighd.lsp.interactive.ConstraintProperty -import de.cau.cs.kieler.klighd.lsp.interactive.IConstraintSerializer +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient +import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import java.io.ByteArrayOutputStream import java.util.List import java.util.Map From 86280216080022c10598a3d59cb1bfc1dfdbfe12 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 14:36:56 +0100 Subject: [PATCH 22/27] Added mrtree to klighd.lsp pom. --- plugins/de.cau.cs.kieler.klighd.lsp/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/pom.xml b/plugins/de.cau.cs.kieler.klighd.lsp/pom.xml index 01029cca8..f674dc6cf 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/pom.xml +++ b/plugins/de.cau.cs.kieler.klighd.lsp/pom.xml @@ -79,6 +79,11 @@ org.eclipse.elk.alg.layered ${elk-version} + + org.eclipse.elk + org.eclipse.elk.alg.mrtree + ${elk-version} + org.eclipse.elk org.eclipse.elk.alg.rectpacking From 9d678967c56d6356a18c4abbca1156cb62449181 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 15:57:11 +0100 Subject: [PATCH 23/27] Renamed IActionHandler to ISprottyActionHandler. --- ...er => de.cau.cs.kieler.klighd.lsp.ISprottyActionHandler} | 0 .../de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend | 4 +--- .../{IActionHandler.xtend => ISprottyActionHandler.xtend} | 6 ++---- .../de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend | 4 ++-- .../klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend | 4 ++-- 5 files changed, 7 insertions(+), 11 deletions(-) rename plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/{de.cau.cs.kieler.klighd.lsp.IActionHandler => de.cau.cs.kieler.klighd.lsp.ISprottyActionHandler} (100%) rename plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/{IActionHandler.xtend => ISprottyActionHandler.xtend} (93%) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler b/plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.ISprottyActionHandler similarity index 100% rename from plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.IActionHandler rename to plugins/de.cau.cs.kieler.klighd.lsp/META-INF/services/de.cau.cs.kieler.klighd.lsp.ISprottyActionHandler diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend index 738cadec9..eb5a81bce 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/AbstractActionHandler.xtend @@ -21,10 +21,8 @@ import org.eclipse.sprotty.Action /** * Abstract class to handle Sprotty actions. - * - * @author sdo */ -abstract class AbstractActionHandler implements IActionHandler { +abstract class AbstractActionHandler implements ISprottyActionHandler { Map> supportedMessages diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ISprottyActionHandler.xtend similarity index 93% rename from plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend rename to plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ISprottyActionHandler.xtend index da17fabc2..875198c82 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/IActionHandler.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/ISprottyActionHandler.xtend @@ -20,11 +20,9 @@ import org.eclipse.sprotty.Action import java.util.Map /** - * Service Interface for ActionHandler. - * - * @author sdo + * Service interface for Sprotty action handlers. */ -interface IActionHandler { +interface ISprottyActionHandler { def Map> getSupportedMessages(); diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend index 459b816a0..277c9f398 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend @@ -94,7 +94,7 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { @Inject protected Injector injector - Map handlers = new HashMap + Map handlers = new HashMap @Inject protected KGraphDiagramState diagramState @@ -145,7 +145,7 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { currentRoot.setType("NONE"); currentRoot.setId("ROOT"); // Create map of registered action kinds and handlers. - ServiceLoader.load(IActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | + ServiceLoader.load(ISprottyActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | val Set kindsSupported = handler.supportedMessages.keySet for (kind : kindsSupported) { handlers.put(kind, handler); diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend index c75a48d86..b0bdcc778 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/gson_utils/KGraphTypeAdapterUtil.xtend @@ -20,7 +20,7 @@ import com.google.gson.GsonBuilder import com.google.inject.Injector import de.cau.cs.kieler.klighd.KlighdDataManager import de.cau.cs.kieler.klighd.SynthesisOption -import de.cau.cs.kieler.klighd.lsp.IActionHandler +import de.cau.cs.kieler.klighd.lsp.ISprottyActionHandler import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction import de.cau.cs.kieler.klighd.lsp.model.PerformActionAction import de.cau.cs.kieler.klighd.lsp.model.RefreshDiagramAction @@ -50,7 +50,7 @@ class KGraphTypeAdapterUtil { addActionKind(RefreshLayoutAction.KIND, RefreshLayoutAction) // Load all registered action handlers and add their actions. - ServiceLoader.load(IActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | + ServiceLoader.load(ISprottyActionHandler, KlighdDataManager.getClassLoader()).forEach[handler | val handlerInstance = injector.getInstance(handler.class) handlerInstance.supportedMessages.keySet.forEach[kind | addActionKind(kind, handlerInstance.supportedMessages.get(kind)) From df1af441fc69fdfbc73d4f316535087606f3d262 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 15:59:15 +0100 Subject: [PATCH 24/27] Corrected author to jep. --- .../cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend index aaf3636f8..b352af9e0 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/layered/Actions.xtend @@ -225,7 +225,7 @@ class DeleteInLayerPredecessorOfConstraintAction implements Action { /** * Deletes the iLSuccOf constraint on the node that is identified by the given id. * - * @author jet + * @author jep */ @Accessors @EqualsHashCode From 2c49cff51e1429a3a5e3654ccf76d892266327ce Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 16:00:36 +0100 Subject: [PATCH 25/27] lsp.interactive: Removed unnecessary method for mrtree. --- .../lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend index 20b6270db..4505b73f5 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/mrtree/MrTreeInteractiveUtil.xtend @@ -33,12 +33,6 @@ import org.eclipse.elk.core.options.Direction * */ class MrTreeInteractiveUtil { - /** - * Sets the required options for the non interactive layout run. - */ - static def void setRequiredInteractiveOptions(KNode root) { - // TODO: Implement if needed - } static def List getSiblings(KNode n, KNode parent) { val lowestParent = getLowestParent(n, parent); From 0d7b948d9ad2a5297e9d3d5b8c7a0c04d259a1e9 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 16:47:55 +0100 Subject: [PATCH 26/27] lsp.interative: Removed ls and lsClient from constraint serializer. --- .../ElkGraphConstraintSerializer.xtend | 51 ++++++------------- .../interactive/IConstraintSerializer.xtend | 12 ++--- .../lsp/interactive/InteractiveUtil.xtend | 39 +++++++++++++- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend index 301d96c89..7c22d0c31 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend @@ -1,6 +1,6 @@ /* * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * + * * http://rtsys.informatik.uni-kiel.de/kieler * * Copyright 2022 by @@ -11,63 +11,42 @@ * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. - * + * * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension -import java.io.ByteArrayOutputStream import java.util.List -import java.util.Map import org.eclipse.elk.graph.ElkNode -import org.eclipse.lsp4j.Position -import org.eclipse.lsp4j.Range -import org.eclipse.lsp4j.TextEdit +import org.eclipse.emf.ecore.resource.Resource /** * Serializes constraint for an ELK graph by just adding the corresponding properties. * * @author sdo - * + * */ class ElkGraphConstraintSerializer implements IConstraintSerializer { - + override canHandle(Object graph) { return graph instanceof ElkNode } - - override serializeConstraints(List> changedNodes, + + override serializeConstraints( + List> changedNodes, Object graph, - String uri, - KGraphLanguageServerExtension ls, - KGraphLanguageClient client + Resource resource ) { - // Serialize model into given uri. - val resource = ls.getResource(uri) - - // Get previous file content as String - var outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeBefore = outputStream.toString - changedNodes.forEach[c| + val codeBefore = InteractiveUtil.serializeResource(resource) + changedNodes.forEach [ c | val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMENT) as ElkNode elkNode.setProperty(c.property, c.value) ] - val Map> changes = newHashMap - // Get changed file as String - outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val String codeAfter = outputStream.toString().trim - // The range is the length of the previous file. - // Just make sure the range is big enough - val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length * 2, 0)) - val TextEdit textEdit = new TextEdit(range, codeAfter) - changes.put(uri, #[textEdit]); - client.replaceContentInFile(uri, codeAfter, range) + val codeAfter = InteractiveUtil.serializeResource(resource) + + return InteractiveUtil.calculateTextEdit(codeBefore, codeAfter) } - + } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend index 019576534..db5002235 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend @@ -16,9 +16,9 @@ */ package de.cau.cs.kieler.klighd.lsp.interactive -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import java.util.List +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.lsp4j.TextEdit /** * Service interface for implementations that serialize a set constraint in the model. @@ -40,10 +40,8 @@ interface IConstraintSerializer { /** * @param changedNodes The added constraints. * @param graph The model, e.g. SCChart or ElkGraph. - * @param uri The uri of the main source file. - * @param ls The language server. - * @param client The language client. + * @param resource The resource to change + * @return The TextEdit to send to the client consisting of the new text and a range. */ - def void serializeConstraints(List> changedNodes, Object graph, String uri, - KGraphLanguageServerExtension ls, KGraphLanguageClient client); + def TextEdit serializeConstraints(List> changedNodes, Object graph, Resource resource); } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index f450cb878..add8e671d 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -22,12 +22,17 @@ import de.cau.cs.kieler.klighd.kgraph.KIdentifier import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import java.io.ByteArrayOutputStream import java.util.ArrayList import java.util.List import java.util.ServiceLoader import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.lsp4j.Position +import org.eclipse.lsp4j.Range +import org.eclipse.lsp4j.TextEdit /** * Provides utility methods for interactive layout. @@ -186,16 +191,48 @@ class InteractiveUtil { for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, KlighdDataManager.getClassLoader())) { if (cs.canHandle(sourceModel)) { - cs.serializeConstraints(changedNodes, model, uri, languageServer, client) + val resource = languageServer.getResource(uri) + val textEdit = cs.serializeConstraints(changedNodes, model, resource) + // Send changes to the client. + client.replaceContentInFile(uri, textEdit.newText, textEdit.range) + // If a serializer is registered, we do not need to update the layout since the diagram will update + // since the model changes. serializer = true } } + // If there is no serializer that changes the textual model (which will cause a refresh model action), + // we have to update the layout (not refresh the layout) to update based on the changed via model. if (!serializer) { languageServer.updateLayout(uri) } return } + /** + * Creates a string of a model resource by saving the resource and returning the output string. + * + * @param resource Resource to get the string for. + */ + static def String serializeResource(Resource resource) { + var outputStream = new ByteArrayOutputStream + resource.save(outputStream, emptyMap) + return outputStream.toString + } + + /** + * Creates a TextEdit based on the before and after text. + * + * @param codeBefore The whole text before + * @param codeAfter The new text + * @return A TextEdit that assumes that the whole code before will ne replaced. + */ + static def TextEdit calculateTextEdit(String codeBefore, String codeAfter) { + val lines = codeBefore.split("\r\n|\r|\n") + val lastLineLength = lines.get(lines.size - 1).length + val Range range = new Range(new Position(0, 0), new Position(lines.length, lastLineLength)) + return new TextEdit(range, codeAfter) + } + /** * Returns id of a node. * From 4a6ad2158e9c404b21c07b865a3e4e99326f22d2 Mon Sep 17 00:00:00 2001 From: Soeren Domroes Date: Wed, 13 Mar 2024 16:53:17 +0100 Subject: [PATCH 27/27] lsp.interactive: Removed unnecessary get. --- .../src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend index 277c9f398..16516a6bd 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramServer.xtend @@ -267,7 +267,7 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer { val handlerInstance = handlers.get(action.kind) if (handlerInstance !== null) { // Even though we have an instance, it is not yet populated with all injected things. - val handler = injector.getInstance(handlers.get(action.kind).class) + val handler = injector.getInstance(handlerInstance.class) handler.handle(action, clientId, this) } else { // If no handler is registered for this message. Let the default super class handle it.