diff --git a/Kieker.WebGUI/bin/data/Advanced Example/meta.dat b/Kieker.WebGUI/bin/data/Advanced Example/meta.dat index ea9e2b7913cd08e7a25b88b92b94515b5aa0d5ce..27e9ee8b9b840ade89e05538c5eca9136a784c6c 100644 --- a/Kieker.WebGUI/bin/data/Advanced Example/meta.dat +++ b/Kieker.WebGUI/bin/data/Advanced Example/meta.dat @@ -1,3 +1,5 @@ # -#Mon Dec 03 14:49:14 CET 2012 +#Wed Apr 10 14:08:23 CEST 2013 owner=Kieker-Administrator +layout=0 -675 -138 192 72;1 -379 -138 312 72;2 -21 -149 276 132;3 287 -137 252 108;4 983 -149 468 96;5 1841 -102 816 144;6 915 110 876 84;7 1837 98 840 120;8 2505 128 288 72;9 2499 -174 360 72;10 2917 -174 348 72;\#1.2 2.6 -191.5 -126.5 -191.5 -101.5;1.2 2.5 -191.5 -126.5 -191.5 -125.5;3.12 6.20 444.5 -137.5 444.5 121.5;4.0 10.R 1384.5 -155.5 1384.5 -256.5 2710.5 -256.5 2710.5 -162.5;4.15 5.16 1384.5 -119.5 1384.5 -90.5;5.1 10.R 2288.5 -132.5 2288.5 -256.5 2710.5 -256.5 2710.5 -162.5;5.17 8.26 2298.5 -96.5 2298.5 139.5;7.2 10.R 2288.5 79.5 2288.5 -93.5 2710.5 -93.5 2710.5 -162.5;8.3 10.R 2710.5 139.5 2710.5 -162.5; +last\ user=Kieker-Administrator diff --git a/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat b/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat index ea9e2b7913cd08e7a25b88b92b94515b5aa0d5ce..947fe9f9e480db0df5fc447b51dbe3d5abce33ef 100644 --- a/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat +++ b/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat @@ -1,3 +1,5 @@ # -#Mon Dec 03 14:49:14 CET 2012 +#Wed Apr 10 14:08:04 CEST 2013 owner=Kieker-Administrator +layout=0 -675 -155 192 72;1 -59 -167 336 84;2 651 -69 276 72;3 311 -57 276 84;4 311 -197 252 84;5 -403 -155 264 84;6 639 -201 252 72;\#1.2 4.8 140.5 -167.5 140.5 -185.5;1.3 3.5 140.5 -143.5 140.5 -45.5;4.9 6.14 480.5 -197.5 480.5 -189.5; +last\ user=Kieker-Administrator diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java index 15ea03a27efc60d30ba146674dd1c7e6aa1b8c66..5f8a6780affdf5846bbbccd7cb81b9fd9715251d 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java @@ -18,7 +18,6 @@ package kieker.webgui.service.impl; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -46,16 +45,17 @@ import de.cau.cs.kieler.kiml.util.KimlUtil; import de.cau.cs.kieler.klay.layered.LayeredLayoutProvider; /** - * This is a utility class providing a method to layout a graph from the graph flow editor. The method accepts two strings (one for the nodes, one for the edges) - * which are the result of specific javascript functions of the graph. For further information look into the API description of the flow editor itself. + * This class provides a single method to perform an auto layout on a given graph from the GraphFlow. The JavaScript GraphFlow throws an "autoLayout"-Event upon + * using the function autoLayout(). This event provides two Strings which may be used by this class' layoutGraph(nodes, edges) method. The return value can then be + * used as an argument for the GraphFlow's loadPositionsFromLayout(positions) function. * - * @author row, Nils Christian Ehmke + * @author Robin Weiss, Nils Christian Ehmke */ @Service public final class GraphLayoutServiceImpl implements IGraphLayoutService { /** - * Default constructor. <b>Do not use this constructor. This bean is Spring managed.</b> + * Default constructor. */ public GraphLayoutServiceImpl() { // No code necessary @@ -69,488 +69,377 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService { @Override public String layoutGraph(final String nodes, final String edges) throws GraphLayoutException { try { - final LayoutInformation layoutInformation = GraphLayoutServiceImpl.assembleLayoutInformation(nodes, edges); + // Convert the given nodes and edges to a graph + final LayoutInformation layoutInformation = new LayoutInformation(nodes, edges); - // Create a progress monitor + // Perform the auto layout on the given graph. final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor(); - - // Create the layout provider final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider(); - - // Perform layout on the created graph layoutProvider.doLayout(layoutInformation.getGraph(), progressMonitor); - // convert layouted graph positions to String - final String layoutedGraph = GraphLayoutServiceImpl.getPositions(layoutInformation); - final String bendPoints = GraphLayoutServiceImpl.getBendPoints(layoutInformation); - - final StringBuilder sb = new StringBuilder("autoLayout#"); - sb.append(layoutedGraph); - sb.append("#"); - sb.append(bendPoints); + // Convert the layouted graph back into a string representation + final String layoutedGraph = layoutInformation.getPositions(); + final String bendPoints = layoutInformation.getBendPoints(); + final StringBuilder sb = new StringBuilder(); + sb.append("autoLayout").append("#").append(layoutedGraph).append("#").append(bendPoints); return sb.toString(); - } catch (final NumberFormatException e) { - throw new GraphLayoutException("Invalid number format", e); - } catch (final Exception e) { // NOCS - throw new GraphLayoutException("Unknown Error!", e); - } - } - - /** - * Assembles the necessary layout information using the given parameters. - * - * @param nodesStr - * The string containing the information about the nodes. - * @param edgesStr - * The string containing the information about the edges. - * - * @return An object containing the layout information for the graph. - */ - private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) throws NumberFormatException, GraphLayoutException { - final int firstSemicolon = nodesStr.indexOf(';'); - // if there is no semicolon, we got an empty graph - if (firstSemicolon < 0) { - throw new GraphLayoutException("Empty Graph"); + } catch (final NumberFormatException ex) { + throw new GraphLayoutException("Invalid Graph Information String!", ex); + } catch (final Exception ex) { // NOCS + throw new GraphLayoutException("Unknown Error!", ex); } - - final int scale = Integer.parseInt(nodesStr.substring(0, firstSemicolon)); - - final String[] nodeInfo = GraphLayoutServiceImpl.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";")); - final String[] edgeInfo = GraphLayoutServiceImpl.correctEmptyArray(edgesStr.split(";")); - - final Map<String, List<Object>> children = new HashMap<String, List<Object>>(); - final Object[][] edges = new Object[edgeInfo.length][5]; - final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges); - - GraphLayoutServiceImpl.addNodes(scale, nodeInfo, layoutInformation); - GraphLayoutServiceImpl.addEdges(edgeInfo, layoutInformation); - return layoutInformation; } /** - * Parses a String array, building a graph with nodes and fixed ports. - * - * @param scale - * The scale factor of the graph. - * @param nodeInfo - * Information about the nodes: isItCustom?, width, height, parent, portInformation - * @param layoutInformation - * The necessary information about the graph. + * A container for the layout information which will be assembled during the layout process. * - * @throws NumberFormatException - * The nodeInfo should mostly be space separated numbers. If it is however invalid, this - * Exception will be thrown + * @author Robin Weiss, Nils Christian Ehmke */ - private static void addNodes(final int scale, final String[] nodeInfo, final LayoutInformation layoutInformation) throws NumberFormatException { - // define node HashMap port list - final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts(); - List<Object> nodeAndPortList; - - // retrieve size modifier - final int dimHalf = scale; - final int dim = dimHalf * 2; - - // loop variables // - String[] nodeProps; - KNode node; - String parentId; - KNode parent; - KPort port; - KShapeLayout layout; - - boolean isNodeFamily; - int width; - int height; - int portCount; - int portType; - int portX; - int portY; - - int i; - int n; - int p; - int lp; - final int l = nodeInfo.length; - - // nodeID : KNode, ParentID - - // -- 1. Define nodes by the properties, given in the string -- - for (n = 0; n < l; n++) { - - // i is our property array-pointer - i = 0; - nodeProps = nodeInfo[n].split(" "); - - // add entry to map - nodeAndPortList = new ArrayList<Object>(); - nodesAndPorts.put(nodeProps[i++], nodeAndPortList); - // create empty node - node = KimlUtil.createInitializedNode(); - nodeAndPortList.add(node); - - // get parentID - parentId = nodeProps[i++]; - if ("-1".equals(parentId)) { - parentId = ""; - node.setParent(layoutInformation.getGraph()); - } - nodeAndPortList.add(parentId); + private static final class LayoutInformation { - // get width and height - width = Integer.parseInt(nodeProps[i++]); - height = Integer.parseInt(nodeProps[i++]); + private final KNode graph; + private final Map<String, List<Object>> children; + private final Object[][] edges; - // get Custom Node tag - isNodeFamily = "f".equals(nodeProps[i++]); + /** + * Creates a new instance of this class. + * + * @param nodesStr + * The string containing the nodes. + * @param edgesStr + * The string containing the edges. + * + * @throws GraphLayoutException + * If the given graph is empty or invalid. + */ + public LayoutInformation(final String nodesStr, final String edgesStr) throws GraphLayoutException { + final int firstSemicolon = nodesStr.indexOf(';'); - // set width and height of KNode - layout = node.getData(KShapeLayout.class); - layout.setWidth(width); - layout.setHeight(height); + // if there is no semicolon, we got an empty graph + if (firstSemicolon < 0) { + throw new GraphLayoutException("Empty Graph"); + } - // if node is a NodeFamily, go on and look for ports - if (isNodeFamily) { + final int scale = Integer.parseInt(nodesStr.substring(0, firstSemicolon)); - // nodeFamily size is fixed - layout.setProperty(LayoutOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS); - portX = -dimHalf; + final String[] nodeInfo = LayoutInformation.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";")); + final String[] edgeInfo = LayoutInformation.correctEmptyArray(edgesStr.split(";")); - // add Ports - for (portType = 0; portType < 3; portType++) { - // determine port x-position - if (portType == 1) { - portX = width - dimHalf; - } + this.children = new HashMap<String, List<Object>>(); + this.edges = new Object[edgeInfo.length][5]; + this.graph = KimlUtil.createInitializedNode(); - portCount = Integer.parseInt(nodeProps[i++]); - portY = Integer.parseInt(nodeProps[i++]); + this.addNodes(scale, nodeInfo); + this.addEdges(edgeInfo); - for (p = 0, lp = portCount; p < lp; p++) { + // set graph layout options + final KShapeLayout layout = this.graph.getData(KShapeLayout.class); + // layout.setProperty(LayoutOptions.LAYOUT_HIERARCHY, true); + layout.setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL); + } - // create port - port = KimlUtil.createInitializedPort(); - port.setNode(node); - nodeAndPortList.add(port); + public KNode getGraph() { + return this.graph; + } - // set layout for Port - layout = port.getData(KShapeLayout.class); + /** + * Reads the (layouted) positions of a constructed KGraph and writes them as integers to a string, separating each number with a space. + * + * @return The constructed string. + */ + public String getPositions() { + final StringBuilder sb = new StringBuilder(); + + for (final Entry<String, List<Object>> entry : this.children.entrySet()) { + final String id = entry.getKey(); + final List<Object> nodeAndPortList = entry.getValue(); + + // Extract the position and size of the node + final KShapeLayout layout = ((KNode) nodeAndPortList.get(0)).getData(KShapeLayout.class); + + final int x = Math.round(layout.getXpos() + (layout.getWidth() / 2)); + final int y; + // HotFix: wrong nodeFamily position: needs to be half the height lower + if (nodeAndPortList.size() > 2) { + y = Math.round(layout.getYpos() + (layout.getHeight())); + } else { + y = Math.round(layout.getYpos() + (layout.getHeight() / 2)); + } - // set position and dimension of port - layout.setWidth(dim); - layout.setHeight(dimHalf); - layout.setYpos(portY); - layout.setXpos(portX); + final int width = Math.round(layout.getWidth()); + final int height = Math.round(layout.getHeight()); - portY += dim; - } - } + // Add the node's information to our string + sb.append(id).append(' ').append(x).append(' ').append(y).append(' ').append(width).append(' ').append(height).append(';'); } + + return sb.toString(); } - // -- 2. resolve stored parentIDs to actual parents - final Iterator<Entry<String, List<Object>>> it = nodesAndPorts.entrySet().iterator(); - while (it.hasNext()) { - nodeAndPortList = (List<Object>) ((Entry) it.next()).getValue(); + /** + * This method iterates through all edges and creates a semicolon separated String containing bend points of all edges. + * + * @return The string containing the bend points. + */ + public String getBendPoints() { + final StringBuilder sb = new StringBuilder(); - // get KNode and its parentID - node = (KNode) nodeAndPortList.get(0); - parentId = nodeAndPortList.get(1).toString(); + int e; - // set other KNode as parent - if (!parentId.isEmpty()) { - parent = (KNode) nodesAndPorts.get(parentId).get(0); - node.setParent(parent); - } - } - } + final int len = this.edges.length; + final int el = 4; - /** - * Parses an array which must contain quadruples of numbers.<br/> - * The first number must be the index of the children-array, where - * the source node is located.<br/> - * The second number must be the index of the children-array, where - * the target node is located.<br/> - * The third number must be the index of the source node List, where - * the source port is located.<br/> - * The fourth number must be the index of the target node List, where - * the target port is located. - * - * @param edgeInfo - * The single elements for the edges. - * @param layoutInformation - * The necessary information about the graph. - * @throws UninitializedGraphException - * If the graph has not yet been initialized. - */ - private static void addEdges(final String[] edgeInfo, final LayoutInformation layoutInformation) throws NumberFormatException { - final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts(); + // Iterate through all edges. + for (int i = 0; i < len; i++) { + e = 0; + final KEdge edge = (KEdge) this.edges[i][e]; - // set up loop variables - String[] edgeProps; - KEdge edge; + final KEdgeLayout layout = edge.getData(KEdgeLayout.class); + final EList<KPoint> bendPoints = layout.getBendPoints(); - String id; - boolean hasSourcePort; - Object[] edgeList; + // add IDs and portIndices + while (++e < el) { + sb.append(this.edges[i][e].toString()); + sb.append(" "); + } + sb.append(this.edges[i][4].toString()); - KNode sourceNode; - int sourcePortIndex; - KPort sourcePort = null; - List<Object> sourceList; + // iterate bend points + final int bl = bendPoints.size(); + KPoint point; - int targetPortIndex; - KPort targetPort; - List<Object> targetList; + if (bl > 0) { + point = bendPoints.get(0); + sb.append(' '); + sb.append(Math.round(point.getX())); + sb.append(' '); + sb.append(Math.round(point.getY())); - int ea = 0; - int p; - int epl; + for (int b = 1; b < bl; b++) { + sb.append(' '); + point = bendPoints.get(b); + sb.append(Math.round(point.getX())); + sb.append(' '); + sb.append(Math.round(point.getY())); + } + } + sb.append(';'); + } - // read from String - for (final String element : edgeInfo) { + return sb.toString(); + } - // get edge info of a single source - edgeList = layoutInformation.getEdges()[ea++]; - edgeProps = element.split(" "); - p = 0; + /** + * Parses a String array, building a graph with nodes and fixed ports. + * + * @param scale + * The scale factor of the graph. + * @param nodeInfo + * Information about the nodes: isItCustom?, width, height, parent, portInformation + * + * @throws NumberFormatException + * The nodeInfo should mostly be space separated numbers. If it is however invalid, this Exception will be thrown + */ + private void addNodes(final int scale, final String[] nodeInfo) throws NumberFormatException { + + // retrieve size modifier + final int dimHalf = scale; + final int dim = dimHalf * 2; + + // loop variables // + KNode node; + String parentId; + KNode parent; + KPort port; + KShapeLayout layout; + + final int l = nodeInfo.length; + + // nodeID : KNode, ParentID + + // -- 1. Define nodes by the properties, given in the string -- + for (int n = 0; n < l; n++) { + + // i is our property array-pointer + int i = 0; + final String[] nodeProps = nodeInfo[n].split(" "); + + // add entry to map + final List<Object> nodeAndPortList = new ArrayList<Object>(); + this.children.put(nodeProps[i++], nodeAndPortList); + // create empty node + node = KimlUtil.createInitializedNode(); + nodeAndPortList.add(node); + + // get parentID + parentId = nodeProps[i++]; + if ("-1".equals(parentId)) { + parentId = ""; + node.setParent(this.getGraph()); + } + nodeAndPortList.add(parentId); - // get source index and port - id = edgeProps[p++]; - sourceList = nodesAndPorts.get(id); - sourceNode = (KNode) sourceList.get(0); + // get width and height + final int width = Integer.parseInt(nodeProps[i++]); + final int height = Integer.parseInt(nodeProps[i++]); - sourcePortIndex = Integer.parseInt(edgeProps[p++]); - edgeList[2] = sourcePortIndex; + // get Custom Node tag + final boolean isNodeFamily = "f".equals(nodeProps[i++]); - hasSourcePort = ++sourcePortIndex != 0; + // set width and height of KNode + layout = node.getData(KShapeLayout.class); + layout.setWidth(width); + layout.setHeight(height); - if (hasSourcePort) { - sourcePort = (KPort) sourceList.get(++sourcePortIndex); - } + // if node is a NodeFamily, go on and look for ports + if (isNodeFamily) { - // get target ports - epl = edgeProps.length; - while (p < epl) { + // nodeFamily size is fixed + layout.setProperty(LayoutOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS); + int portX = -dimHalf; - // init edge - edge = KimlUtil.createInitializedEdge(); - edgeList[0] = edge; - edgeList[1] = id; + // add Ports + for (int portType = 0; portType < 3; portType++) { + // determine port x-position + if (portType == 1) { + portX = width - dimHalf; + } - // get target index and port - id = edgeProps[p++]; - edgeList[3] = id; - targetList = nodesAndPorts.get(id); + final int portCount = Integer.parseInt(nodeProps[i++]); + int portY = Integer.parseInt(nodeProps[i++]); - // select connected nodes - edge.setSource(sourceNode); - edge.setTarget((KNode) targetList.get(0)); + for (int p = 0; p < portCount; p++) { - targetPortIndex = Integer.parseInt(edgeProps[p++]); - edgeList[4] = targetPortIndex; + // create port + port = KimlUtil.createInitializedPort(); + port.setNode(node); + nodeAndPortList.add(port); - if (++targetPortIndex != 0) { - targetPort = (KPort) targetList.get(++targetPortIndex); + // set layout for Port + layout = port.getData(KShapeLayout.class); - // set target port of edge - edge.setTargetPort(targetPort); - targetPort.getEdges().add(edge); - } + // set position and dimension of port + layout.setWidth(dim); + layout.setHeight(dimHalf); + layout.setYpos(portY); + layout.setXpos(portX); - if (hasSourcePort) { - // set source port of edge - edge.setSourcePort(sourcePort); - sourcePort.getEdges().add(edge); + portY += dim; + } + } } - } - } - } + // -- 2. resolve stored parentIDs to actual parents + for (final List<Object> nodeAndPortList : this.children.values()) { + // get KNode and its parentID + node = (KNode) nodeAndPortList.get(0); + parentId = nodeAndPortList.get(1).toString(); - private static String[] correctEmptyArray(final String[] arr) { - if ((arr.length == 1) && arr[0].isEmpty()) { - return new String[0]; - } else { - return arr; - } - } - - /** - * Reads the (layouted) positions of a constructed KGraph and writes them as integers to a string, seperating each number with a space. - * - * @param layoutInformation - * The object containing the necessary information about the graph. - * - * @return The constructed string. - */ - private static String getPositions(final LayoutInformation layoutInformation) { - final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts(); - final StringBuilder sb = new StringBuilder(); - - // Run through all available entries - for (final Map.Entry<String, List<Object>> entry : nodesAndPorts.entrySet()) { - final String id = entry.getKey(); - final List<Object> nodeAndPortList = entry.getValue(); - - final KShapeLayout layout = ((KNode) nodeAndPortList.get(0)).getData(KShapeLayout.class); - - // Get the position of the node - final int posX = Math.round(layout.getXpos() + (layout.getWidth() / 2)); - final int posY; - // HotFix: wrong nodeFamily position: needs to be half the height lower - if (nodeAndPortList.size() > 2) { - posY = Math.round(layout.getYpos() + (layout.getHeight())); - } else { - posY = Math.round(layout.getYpos() + (layout.getHeight() / 2)); + // set other KNode as parent + if (!parentId.isEmpty()) { + parent = (KNode) this.children.get(parentId).get(0); + node.setParent(parent); + } } - - // Get the size of the node - final int width = Math.round(layout.getWidth()); - final int height = Math.round(layout.getHeight()); - - // Put everything into the string - sb.append(id); - sb.append(" "); - sb.append(posX); - sb.append(" "); - sb.append(posY); - sb.append(" "); - sb.append(width); - sb.append(" "); - sb.append(height); - sb.append(";"); } - return sb.toString(); - } - - /** - * This method iterates through all edges of the given object and creates a semicolon separated String containing bend points of all edges. - * - * @param layoutInformation - * The object containing the information about the graph and the layout. - * @return The string containing the bend points. - */ - private static String getBendPoints(final LayoutInformation layoutInformation) { - final StringBuilder sb = new StringBuilder(); - final Object[][] edges = layoutInformation.getEdges(); + /** + * Parses an array which must contain quadruples of numbers.<br/> + * The first number must be the index of the children-array, where + * the source node is located.<br/> + * The second number must be the index of the children-array, where + * the target node is located.<br/> + * The third number must be the index of the source node List, where + * the source port is located.<br/> + * The fourth number must be the index of the target node List, where + * the target port is located. + * + * @param edgeInfo + * The single elements for the edges. + * + * @throws NumberFormatException + * If the given graph is invalid. + */ + private void addEdges(final String[] edgeInfo) throws NumberFormatException { + // Set up some loop variables + String id; + int sourcePortIndex; + int targetPortIndex; + int ea = 0; + int p; + + // read from String + for (final String element : edgeInfo) { + + // get edge info of a single source + final Object[] edgeList = this.edges[ea++]; + final String[] edgeProps = element.split(" "); + p = 0; + + // get source index and port + id = edgeProps[p++]; + final List<Object> sourceList = this.children.get(id); + final KNode sourceNode = (KNode) sourceList.get(0); - KEdge edge; - int e; + sourcePortIndex = Integer.parseInt(edgeProps[p++]); + edgeList[2] = sourcePortIndex; - final int l = edges.length; - final int el = 4; + final boolean hasSourcePort = ++sourcePortIndex != 0; + final KPort sourcePort; + if (hasSourcePort) { + sourcePort = (KPort) sourceList.get(++sourcePortIndex); + } else { + sourcePort = null; + } - // iterate edges - for (int i = 0; i < l; i++) { - e = 0; - edge = (KEdge) edges[i][e]; + // get target ports + final int epl = edgeProps.length; + while (p < epl) { + // init edge + final KEdge edge = KimlUtil.createInitializedEdge(); + edgeList[0] = edge; + edgeList[1] = id; - final KEdgeLayout layout = edge.getData(KEdgeLayout.class); - final EList<KPoint> bendPoints = layout.getBendPoints(); + // get target index and port + id = edgeProps[p++]; + edgeList[3] = id; + final List<Object> targetList = this.children.get(id); - // add IDs and portIndices - while (++e < el) { - sb.append(edges[i][e].toString()); - sb.append(" "); - } - sb.append(edges[i][4].toString()); + // select connected nodes + edge.setSource(sourceNode); + edge.setTarget((KNode) targetList.get(0)); - // iterate bend points - final int bl = bendPoints.size(); - KPoint point; + targetPortIndex = Integer.parseInt(edgeProps[p++]); + edgeList[4] = targetPortIndex; - if (bl > 0) { + if (++targetPortIndex != 0) { + final KPort targetPort = (KPort) targetList.get(++targetPortIndex); - point = bendPoints.get(0); - sb.append(" "); - sb.append(Math.round(point.getX())); - sb.append(" "); - sb.append(Math.round(point.getY())); + // set target port of edge + edge.setTargetPort(targetPort); + targetPort.getEdges().add(edge); + } - for (int b = 1; b < bl; b++) { - sb.append(" "); - point = bendPoints.get(b); - sb.append(Math.round(point.getX())); - sb.append(" "); - sb.append(Math.round(point.getY())); + if (hasSourcePort) { + // set source port of edge + edge.setSourcePort(sourcePort); + sourcePort.getEdges().add(edge); + } } - } - sb.append(";"); - } - - return sb.toString(); - } - - /** - * A container for the layout information which will be assembled during the layout process. - * - * @author Nils Christian Ehmke - */ - private static class LayoutInformation { - private final KNode graph; - /** - * An array containing the child node and the ports from left to right. - */ - private final Map<String, List<Object>> children; - /** - * An array containing edges. This way we can return edge information in the same order. - */ - private final Object[][] edges; - - /** - * Creates a new instance of this class. - * - * @param graph - * The graph itself. - * @param children - * The child notes and the ports. - * @param edges - * The edges of the graph. - */ - public LayoutInformation(final KNode graph, final Map<String, List<Object>> children, final Object[][] edges) { // NOPMD (array) - this.graph = graph; - this.children = children; - this.edges = edges; - - // set graph layout options - final KShapeLayout layout = graph.getData(KShapeLayout.class); - // layout.setProperty(LayoutOptions.LAYOUT_HIERARCHY, true); - layout.setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL); - - } - - /** - * Getter for the property {@link LayoutInformation#graph}. - * - * @return The current value of the property. - */ - public KNode getGraph() { - return this.graph; - } - - /** - * Getter for the property {@link LayoutInformation#children}. - * - * @return The current value of the property. - */ - public Map<String, List<Object>> getNodesAndPorts() { - return this.children; + } } - /** - * Getter for the property {@link LayoutInformation#edges}. - * - * @return The current value of the property. - */ - public Object[][] getEdges() { - return this.edges; // NOPMD (array) + private static String[] correctEmptyArray(final String[] arr) { + if ((arr.length == 1) && arr[0].isEmpty()) { + return new String[0]; + } else { + return arr; + } } - } }