Exemplo n.º 1
0
		/// <summary>
		/// Performs the arrangement.
		/// </summary>
		public virtual bool Arrange(FlowChart chart)
		{
			if (_ignoreArrowDirection && _root == null)
				return false;

			chart.UndoManager.onStartLayout("Tree layout");

			// Build the graph
			FCGraph graph = null;
			if (_reversedArrows)
			{
				graph = new ReversedFCGraph(chart,
					_keepGroupLayout, _ignoreArrowDirection);
			}
			else
			{
				graph = new FCGraph(chart,
					_keepGroupLayout, _ignoreArrowDirection);
			}

			// Get the root node within the graph
			Layout.INode rootNode = null;
			if (_root != null)
			{
				foreach (FCNode node in graph.Nodes)
				{
					if (node.Node == _root)
					{
						rootNode = node;
						break;
					}
				}
			}

			CalculateAnchors();

			// Split graph to subgraphs
			Layout.IGraph[] subgraphs =
				Layout.GraphSplitter.Split(graph,
				new FCGraphBuilder(chart, _reversedArrows));

			float xOffset = this.XGap;
			foreach (FCGraph subgraph in subgraphs)
			{
				Layout.INode theRoot = null;
				if (subgraph.Nodes.Contains(rootNode))
				{
					// The root node of the user is within this
					// subgraph - respect the user's wishes
					theRoot = rootNode;
				}
				else
				{
					// If the user specified a root node,
					// arrange only the graph, containing
					// that node
					if (rootNode != null)
						continue;

					// If the subgraph has root node, use it,
					// otherwise select the first node as root
					Layout.INode subRoot = subgraph.Root;

					if (subRoot == null)
						theRoot = subgraph.Nodes[0];
					else
						theRoot = subRoot;
				}

				// Check if the root is layoutable
				if ((theRoot as FCNode).Node.Frozen)
					continue;

				Layout.LayoutProgress progress = null;
				if (_progress != null)
					progress = new Layout.LayoutProgress(
						this.OnLayoutProgress);

				Layout.TreeLayoutInfo info = 
					new Layout.TreeLayoutInfo();
				info.Direction = (Layout.TreeLayoutDirection)this.Direction;
				info.KeepRootPosition = this.KeepRootPosition;
				info.LevelDistance = this.LevelDistance;
				info.NodeDistance = this.NodeDistance;
				info.StretchFactor = this.StretchFactor;
				info.XGap = this.XGap;
				info.YGap = this.YGap;

				if (_layoutNode != null)
				{
					// remember the old positions
					foreach (FCNode node in subgraph.Nodes)
						node.Node.setData(Constants.OLD_BOUNDS, node.Node.BoundingRect);
				}

				// Arrange the subgraph
				switch (_type)
				{

					case TreeLayoutType.Cascading:
						new Layout.BorderTreeLayout().Arrange(
							theRoot, info, progress);
						break;

					case TreeLayoutType.Centered:
						new Layout.CenterTreeLayout().Arrange(
							theRoot, info, progress);
						break;

					case TreeLayoutType.Radial:
						new Layout.RadialTreeLayout().Arrange(
							theRoot, info, progress);
						break;

				}

				// If the root is not at fixed position, translate the whole tree
				if (!this.KeepRootPosition)
				{
					RectangleF graphBounds = subgraph.GetBounds(false);
					float xToMove = xOffset - graphBounds.X;
					float yToMove = this.YGap - graphBounds.Y;

					foreach (FCNode node in subgraph.Nodes)
					{
						RectangleF nodeBounds = node.Bounds;
						nodeBounds.X += xToMove;
						nodeBounds.Y += yToMove;
						node.Bounds = nodeBounds;
					}

					xOffset += graphBounds.Width + this.XGap;
				}

				if (_layoutNode != null)
				{
					// raise the LayoutNode event for each node
					foreach (FCNode node in subgraph.Nodes)
						_layoutNode(node.Node, (RectangleF)node.Node.getData(Constants.OLD_BOUNDS));
					chart.clearRuntimeData(Constants.OLD_BOUNDS);
				}

				// Update the arrows in this particular subgraph
				ArrayList visitedLinks = new ArrayList();
				ArrayList nodes = new ArrayList();

				nodes.Add(theRoot);

				while (nodes.Count > 0)
				{
					FCNode node = nodes[0] as FCNode;
					nodes.RemoveAt(0);

					if (node.Node.Frozen)
						continue;

					foreach (FCLink link in node.OutLinks)
					{
						if (!visitedLinks.Contains(link))
						{
							visitedLinks.Add(link);

							if (!link.Arrow.IgnoreLayout)
							{
								if (link.Destination == node)
								{
									UpdateArrow(link.Arrow, true);
									nodes.Add(link.Origin);
								}
								else
								{
									UpdateArrow(link.Arrow, false);
									nodes.Add(link.Destination);
								}

								if (_layoutLink != null)
									_layoutLink(link.Arrow);
							}
						}
					}
				}
			}

			chart.Invalidate();
			chart.UndoManager.onEndLayout();

			return true;
		}