/****************************************************************************
**
** 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; }
}
}
}