From 1dc8b7dc7e88345f2c0f0e2be5d107240f85c4cb Mon Sep 17 00:00:00 2001 From: Niklas Rentz Date: Mon, 30 Sep 2024 20:15:20 +0200 Subject: [PATCH] Split preparing rendering IDs to happen right after model generation (specifically, before any layout stuff) --- .../klighd/lsp/KGraphDiagramUpdater.xtend | 2 + .../klighd/lsp/KGraphLayoutEngine.xtend | 2 +- .../klighd/lsp/utils/RenderingPreparer.xtend | 118 ++++++++++++++---- 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend index 7c6905338..cf9501e9c 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphDiagramUpdater.xtend @@ -30,6 +30,7 @@ import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer import de.cau.cs.kieler.klighd.lsp.model.RequestDiagramPieceAction import de.cau.cs.kieler.klighd.lsp.model.SKGraph import de.cau.cs.kieler.klighd.lsp.utils.KGraphMappingUtil +import de.cau.cs.kieler.klighd.lsp.utils.RenderingPreparer import de.cau.cs.kieler.klighd.util.KlighdSynthesisProperties import java.util.HashSet import java.util.List @@ -316,6 +317,7 @@ class KGraphDiagramUpdater extends DiagramUpdater { var SGraph sGraph = null; synchronized (diagramState) { sGraph = diagramGenerator.toSGraph(viewContext.viewModel, uri, cancelIndicator) + RenderingPreparer.prepareRenderingIDs(viewContext.viewModel, diagramGenerator.getKGraphToSModelElementMap) } if (incrementalDiagramGenerator) { val requestManager = new KGraphDiagramPieceRequestManager(diagramGenerator as KGraphIncrementalDiagramGenerator) diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphLayoutEngine.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphLayoutEngine.xtend index c600be067..23f119011 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphLayoutEngine.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/KGraphLayoutEngine.xtend @@ -87,7 +87,7 @@ class KGraphLayoutEngine extends ElkLayoutEngine { synchronized (kGraphContext.viewModel) { lightDiagramLayoutConfig.performLayout - RenderingPreparer.prepareRendering(kGraphContext.viewModel, diagramState.getKGraphToSModelElementMap(uri)) + RenderingPreparer.prepareRenderingLayout(kGraphContext.viewModel, diagramState.getKGraphToSModelElementMap(uri)) } } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/RenderingPreparer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/RenderingPreparer.xtend index 6a3f8c20f..dc45e9e14 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/RenderingPreparer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/utils/RenderingPreparer.xtend @@ -64,6 +64,93 @@ import static extension de.cau.cs.kieler.klighd.lsp.utils.SprottyProperties.* * @author nre */ final class RenderingPreparer { + + /** + * Prepares the rendering IDs of a KGraph to be generated for an external viewer. + * + * + * @param element The parent element containing the graph to calculate all rendering IDs for. + * @param kGraphToSGraph A map for identifying the SGraph element for each KGraph element in this graph. + */ + static def void prepareRenderingIDs(KGraphElement element, Map kGraphToSGraph) { + // calculate the IDs of all renderings: + for (var int i = 0; i < element.data.size; i++) { + val data = element.data.get(i) + switch(data) { + KRenderingLibrary: { + // The library needs to generate ids for all later KRenderingRefs to refer to. + for (var int j = 0; j < data.renderings.size; j++) { + val rendering = data.renderings.get(j) + if (rendering instanceof KRendering) { + KRenderingIdGenerator.generateIdsRecursive(rendering, "$$lib$$", j) + } + } + } + KRenderingRef: { + // rendering refs refer to the referred ID + data.renderingId = kGraphToSGraph.get(element)?.id + data.rendering.renderingId + } + KRendering: { + // every rendering needs an ID, generate it here + KRenderingIdGenerator.generateIdsRecursive(data, kGraphToSGraph.get(element)?.id + "$$", i) + } + } + } + + // Recursively call this method for every child KGraphElement of this. + // (all labels, child nodes, outgoing edges and ports) + + if (element instanceof KLabeledGraphElement) { + for (label : element.labels) { + prepareRenderingIDs(label, kGraphToSGraph) + } + } + if (element instanceof KNode) { + // Do not recurse generating IDs if the element is not expanded, as there won't be any SGraph generated for + // it. + var boolean isExpanded + val renderingContextData = RenderingContextData.get(element) + if (renderingContextData.hasProperty(SprottyProperties.EXPANDED)) { + isExpanded = renderingContextData.getProperty(SprottyProperties.EXPANDED) + } else { + // If the expanded property does not exist yet, use the initial expansion. + isExpanded = element.getProperty(KlighdProperties.EXPAND) + } + + if (isExpanded) { + for (node : element.children) { + prepareRenderingIDs(node, kGraphToSGraph) + } + } + for (edge : element.outgoingEdges) { + // not expanded => edge must not have the target node inside the non-expanded + if (isExpanded || !KGraphUtil.isDescendant(edge.target, element)) { + prepareRenderingIDs(edge, kGraphToSGraph) + } + } + for (port : element.ports) { + prepareRenderingIDs(port, kGraphToSGraph) + } + } + + // Also prepare the IDs of all proxy-renderings + val proxyRendering = element.getProperty(KlighdProperties.PROXY_VIEW_PROXY_RENDERING) + if (element.getProperty(KlighdProperties.PROXY_VIEW_RENDER_NODE_AS_PROXY) && proxyRendering !== null) { + for (var int i = 0; i < proxyRendering.size; i++) { + val data = proxyRendering.get(i) + switch(data) { + KRenderingRef: { + // rendering refs refer to the referred ID + data.renderingId = kGraphToSGraph.get(element)?.id + data.rendering.renderingId + } + KRendering: { + // every rendering needs an ID, generate it here + KRenderingIdGenerator.generateIdsRecursive(data, kGraphToSGraph.get(element)?.id + "$$", i) + } + } + } + } + } /** * Prepares a KGraphElement to be rendered in an external viewer. @@ -74,29 +161,18 @@ final class RenderingPreparer { * In case of a {@link KRenderingRef} the bounds and decoration are persisted for every referenced rendering as a map * inside the properties of the reference. * For example: <id of the rendering in the library: bounds in this instance> - * Furthermore, for every rendering a unique ID is generated. * Finally, modifiable styles defined by the synthesis are processed for the rendering. * * @param element The parent element containing the graph to calculate all rendering bounds for. * @param kGraphToSGraph A map for identifying the SGraph element for each KGraph element in this graph. */ - static def void prepareRendering(KGraphElement element, Map kGraphToSGraph) { + static def void prepareRenderingLayout(KGraphElement element, Map kGraphToSGraph) { // calculate the sizes of all renderings: for (var int i = 0; i < element.data.size; i++) { val data = element.data.get(i) switch(data) { - KRenderingLibrary: { - // The library needs to generate ids for all later KRenderingRefs to refer to, but no own bounds, - // since these are generic renderings. - for (var int j = 0; j < data.renderings.size; j++) { - val rendering = data.renderings.get(j) - if (rendering instanceof KRendering) { - KRenderingIdGenerator.generateIdsRecursive(rendering, "$$lib$$", j) - } - } - } KRenderingRef: { - // all references to KRenderings need to place a map with the ids of the renderings and their + // all references to KRenderings need to place a map with their // sizes and their decoration in this case in the properties of the reference. var boundsMap = new HashMap var decorationMap = new HashMap @@ -105,12 +181,8 @@ final class RenderingPreparer { data.properties.put(CALCULATED_BOUNDS_MAP, boundsMap) // and the decorationMap data.properties.put(CALCULATED_DECORATION_MAP, decorationMap) - // remember the id of the rendering in the reference - data.renderingId = kGraphToSGraph.get(element)?.id + data.rendering.renderingId } KRendering: { - // every rendering needs an ID, generate it here - KRenderingIdGenerator.generateIdsRecursive(data, kGraphToSGraph.get(element)?.id + "$$", i) handleKRendering(element, data, null, null) } } @@ -121,7 +193,7 @@ final class RenderingPreparer { if (element instanceof KLabeledGraphElement) { for (label : element.labels) { - prepareRendering(label, kGraphToSGraph) + prepareRenderingLayout(label, kGraphToSGraph) } } if (element instanceof KNode) { @@ -138,17 +210,17 @@ final class RenderingPreparer { if (isExpanded) { for (node : element.children) { - prepareRendering(node, kGraphToSGraph) + prepareRenderingLayout(node, kGraphToSGraph) } } for (edge : element.outgoingEdges) { // not expanded => edge must not have the target node inside the non-expanded if (isExpanded || !KGraphUtil.isDescendant(edge.target, element)) { - prepareRendering(edge, kGraphToSGraph) + prepareRenderingLayout(edge, kGraphToSGraph) } } for (port : element.ports) { - prepareRendering(port, kGraphToSGraph) + prepareRenderingLayout(port, kGraphToSGraph) } } @@ -168,13 +240,9 @@ final class RenderingPreparer { data.properties.put(CALCULATED_BOUNDS_MAP, boundsMap) // and the decorationMap data.properties.put(CALCULATED_DECORATION_MAP, decorationMap) - // remember the id of the rendering in the reference - data.renderingId = kGraphToSGraph.get(element)?.id + data.rendering.renderingId } KRendering: { - // every rendering needs an ID, generate it here - KRenderingIdGenerator.generateIdsRecursive(data, kGraphToSGraph.get(element)?.id + "$$", i) if (data.eContainer instanceof KNode) { // Calculate the size and layout of the proxy first. val parent = data.eContainer as KNode