/**************************************************************************** ** ** This file is part of yFiles FLEX 1.6. ** ** yWorks proprietary/confidential. Use is subject to license terms. ** ** Unauthorized redistribution of this file or of a byte-code version ** of this file is strictly forbidden. ** ** Copyright (c) 2006 - 2011 by yWorks GmbH, Vor dem Kreuzberg 28, ** 72070 Tuebingen, Germany. All rights reserved. ** ***************************************************************************/ using System; using System.Web; using yWorks.yFiles.Graph.Web; using yWorks.Canvas.Geometry; using yWorks.yFiles.UI.Model; using yWorks.Canvas.Model; using System.Collections.Generic; using y.layout.hierarchic; using y.layout.hierarchic.incremental; using y.layout; using System.Text; using yWorks.yFiles.UI.Drawing; namespace yWorks.yFiles.Graph.Web.Demo.Hierarchic { /// /// Handler for AuxComponentDemo: adds children, siblings and parents to a selected node and /// performs a hierarchical layout. /// public class HierarchicRoundtripHandler : IHttpHandler { public const String ACTION_ADD_PARENT = "addParent"; public const String ACTION_ADD_CHILD = "addChild"; public const String ACTION_ADD_SIBLING = "addSibling"; private GraphRoundtripSupport support = new GraphRoundtripSupport(); private static readonly Size NODE_SIZE = new Size(160, 60); /// /// Processes the service request. /// /// public void ProcessRequest(HttpContext context) { // Read the parameters of the request String action = context.Request.Params["action"]; String nodeId = context.Request.Params["nodeId"]; String label = context.Request.Params["label"]; //TODO decode UTF-8 label = context.Server.UrlDecode(label); // needs a node ID if (null == nodeId) { return; } support.AdjustFontSize = true; // Font metrics are different in .NET and Flex // create and read the graph IGraph graph = createLayoutGraph(); // set label style even though it is not read at the client: // the preferred size will be calculated using that style graph.DefaultNodeLabelStyle = new SimpleLabelStyle(new System.Drawing.Font("Time New Roman", 16f)); if (support.ReadGraph(context.Request, graph)) { // get the selected node INode node = getNode(nodeId, graph); if (null == node) { support.SendError("Wrong node id: " + nodeId, context); return; } INode created = null; if (ACTION_ADD_CHILD.Equals(action)) { ///////////////// add child ///////////// List allParents = new List(); // list with all parents for the new node List children = new List(); // list with all children of the current node foreach (IEdge childEdge in ((DefaultGraph)graph).OutEdges(node)) { children.Add(childEdge.TargetPort.Owner as INode); } if (children.Count > 0) { // create the parent list with the first child foreach (IEdge parentEdge in ((DefaultGraph)graph).InEdges(children[0])) { allParents.Add(parentEdge.SourcePort.Owner as INode); } } else { // if the current node has no siblings: the node is allParents only item allParents.Add(node); } // create the new node created = graph.CreateNode(); graph.SetBounds(created, 0, 0, NODE_SIZE.Width, NODE_SIZE.Height); //create edges between the new node and all parents foreach (INode parent in allParents) { graph.CreateEdge(parent, created); } } else if (ACTION_ADD_PARENT.Equals(action)) { ///////////////// add parent ///////////// List parents = new List(); // list with all parents of the selected node List siblings = new List(); // list with all siblings of the selected node foreach (IEdge parentEdge in ((DefaultGraph)graph).InEdges(node)) { parents.Add(parentEdge.SourcePort.Owner as INode); } // The siblings are the children of the first parent // (or the selected node if there are no parents) if (parents.Count > 0) { foreach (IEdge siblingEdge in ((DefaultGraph)graph).OutEdges(parents[0])) { siblings.Add(siblingEdge.TargetPort.Owner as INode); } } else { siblings.Add(node); } // create the new node created = graph.CreateNode(); graph.SetBounds(created, 0, 0, NODE_SIZE.Width, NODE_SIZE.Height); // create edges between the created node and all siblings of the selected node foreach (INode sibling in siblings) { graph.CreateEdge(created, sibling); } } else if (ACTION_ADD_SIBLING.Equals(action)) { ///////////////// add sibling ///////////// // create the new node created = graph.CreateNode(); graph.SetBounds(created, 0, 0, NODE_SIZE.Width, NODE_SIZE.Height); // create edges between the new node and all parents of the selected node foreach (IEdge parentEdge in ((DefaultGraph)graph).InEdges(node)) { graph.CreateEdge(parentEdge.SourcePort.Owner as INode, created); } // create edges between the new node and all children of the selected node foreach (IEdge childEdge in ((DefaultGraph)graph).OutEdges(node)) { graph.CreateEdge(created, childEdge.TargetPort.Owner as INode); } } // add the label to the created node if (null != created) { ILabel createdLabel = graph.AddLabel(created, InteriorStretchLabelModel.North, label); } // create the bus style grouping of the edges: // for all nodes, collect all parents, // create id from all parents, // assign edge grouping ids IMapperRegistry reg = graph.Lookup(typeof(IMapperRegistry)) as IMapperRegistry; if (reg != null) { // use the node IDs to create the group IDs IMapper idMap = reg.GetMapper(GraphRoundtripSupport.Node2IdMapperKey); IMapper targetGroupMap = new DictionaryMapper(); IMapper sourceGroupMap = new DictionaryMapper(); // for all nodes foreach (INode n in graph.Nodes) { List parents = new List(); // parent nodes of the current node List children = new List(); // child nodes of the current node foreach (IEdge parentEdge in ((DefaultGraph)graph).InEdges(n)) { parents.Add(parentEdge.SourcePort.Owner as INode); } foreach (IEdge childEdge in ((DefaultGraph)graph).OutEdges(n)) { children.Add(childEdge.TargetPort.Owner as INode); } // targetID: all IDs of the parent nodes StringBuilder targetID = new StringBuilder(); foreach (INode parent in parents) { targetID.Append(idMap.GetValue(parent)); } // sourceID: all IDs of the child nodes StringBuilder sourceID = new StringBuilder(); foreach (INode child in children) { sourceID.Append(idMap.GetValue(child)); } // for all edges with the target port at the current node: // set the targetID in the targetGroupMap foreach (IEdge parentEdge in ((DefaultGraph)graph).InEdges(n)) { targetGroupMap.SetValue(parentEdge, targetID.ToString()); } // for all edges with the source port at the current node: // set the sourceID in the sourceGroupMap foreach (IEdge childEdge in ((DefaultGraph)graph).OutEdges(n)) { sourceGroupMap.SetValue(childEdge, sourceID.ToString()); } } // add source and target group maps with the GROUPID key to the mapper registry // (will be copied when the CopiedLayoutIGraph is created) reg.AddMapper(LayoutConstants.TARGET_GROUPID_KEY, targetGroupMap); reg.AddMapper(LayoutConstants.SOURCE_GROUPID_KEY, sourceGroupMap); } // Set up the hierarchic layouter IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter(); EdgeLayoutDescriptor eld = ihl.getEdgeLayoutDescriptor(); eld.setOrthogonallyRouted(true); eld.setMinimumFirstSegmentLength(30); eld.setMinimumLastSegmentLength(30); // ihl.setIntegratedEdgeLabelingEnabled(true); // ihl.setLabelLayouterEnabled(true); //ihl.setConsiderNodeLabelsEnabled(true); ihl.setLayoutOrientation(LayoutConstants.LEFT_TO_RIGHT); ihl.setMinimumLayerDistance(100); ihl.setNodeToNodeDistance(70); ihl.getNodeLayoutDescriptor().setNodeLabelMode(NodeLayoutDescriptor.NODE_LABEL_MODE_CONSIDER_FOR_DRAWING); // copy the layout graph CopiedLayoutIGraph copiedGraph = new CopiedLayoutIGraph(graph); // do the layout BufferedLayouter layouter = new BufferedLayouter(ihl); layouter.doLayout(copiedGraph); // write the copied layout back copiedGraph.commitLayoutToOriginalGraph(); // send the graph to the server support.SendGraph(graph, context.Response); } } /// /// Create the Graph using GraphRoundtripSupport /// /// private IGraph createLayoutGraph() { support.FoldedGraph = false; IGraph layoutGraph = support.CreateRoundtripGraph(); return layoutGraph; } /// /// Get the node with the given ID. /// /// The ID to get the node for. /// The graph to search in. /// private INode getNode(String id, IGraph graph) { IMapperRegistry reg = graph.Lookup(typeof(IMapperRegistry)) as IMapperRegistry; if (reg != null) { IMapper dataProvider = reg.GetMapper(GraphRoundtripSupport.Node2IdMapperKey); if (dataProvider != null) { // return the first node with matching ID. foreach (INode node in graph.Nodes) { Object nodeId = dataProvider.GetValue(node); if (id != null && id.Equals(nodeId)) { return node; } } } } return null; } public bool IsReusable { get { return true; } } } }