moel@345: using System;
moel@345: using System.Collections.Generic;
moel@345: using System.Text;
moel@345: using System.Collections.ObjectModel;
moel@345: 
moel@345: namespace Aga.Controls.Tree
moel@345: {
moel@345: 	/// <summary>
moel@345: 	/// Provides a simple ready to use implementation of <see cref="ITreeModel"/>. Warning: this class is not optimized 
moel@345: 	/// to work with big amount of data. In this case create you own implementation of <c>ITreeModel</c>, and pay attention
moel@345: 	/// on GetChildren and IsLeaf methods.
moel@345: 	/// </summary>
moel@345: 	public class TreeModel : ITreeModel
moel@345: 	{
moel@345: 		private Node _root;
moel@345: 		public Node Root
moel@345: 		{
moel@345: 			get { return _root; }
moel@345: 		}
moel@345: 
moel@345: 		public Collection<Node> Nodes
moel@345: 		{
moel@345: 			get { return _root.Nodes; }
moel@345: 		}
moel@345: 
moel@345: 		public TreeModel()
moel@345: 		{
moel@345: 			_root = new Node();
moel@345: 			_root.Model = this;
moel@345: 		}
moel@345: 
moel@345: 		public TreePath GetPath(Node node)
moel@345: 		{
moel@345: 			if (node == _root)
moel@345: 				return TreePath.Empty;
moel@345: 			else
moel@345: 			{
moel@345: 				Stack<object> stack = new Stack<object>();
moel@345: 				while (node != _root)
moel@345: 				{
moel@345: 					stack.Push(node);
moel@345: 					node = node.Parent;
moel@345: 				}
moel@345: 				return new TreePath(stack.ToArray());
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		public Node FindNode(TreePath path)
moel@345: 		{
moel@345: 			if (path.IsEmpty())
moel@345: 				return _root;
moel@345: 			else
moel@345: 				return FindNode(_root, path, 0);
moel@345: 		}
moel@345: 
moel@345: 		private Node FindNode(Node root, TreePath path, int level)
moel@345: 		{
moel@345: 			foreach (Node node in root.Nodes)
moel@345: 				if (node == path.FullPath[level])
moel@345: 				{
moel@345: 					if (level == path.FullPath.Length - 1)
moel@345: 						return node;
moel@345: 					else
moel@345: 						return FindNode(node, path, level + 1);
moel@345: 				}
moel@345: 			return null;
moel@345: 		}
moel@345: 
moel@345: 		#region ITreeModel Members
moel@345: 
moel@345: 		public System.Collections.IEnumerable GetChildren(TreePath treePath)
moel@345: 		{
moel@345: 			Node node = FindNode(treePath);
moel@345: 			if (node != null)
moel@345: 				foreach (Node n in node.Nodes)
moel@345: 					yield return n;
moel@345: 			else
moel@345: 				yield break;
moel@345: 		}
moel@345: 
moel@345: 		public bool IsLeaf(TreePath treePath)
moel@345: 		{
moel@345: 			Node node = FindNode(treePath);
moel@345: 			if (node != null)
moel@345: 				return node.IsLeaf;
moel@345: 			else
moel@345: 				throw new ArgumentException("treePath");
moel@345: 		}
moel@345: 
moel@345: 		public event EventHandler<TreeModelEventArgs> NodesChanged;
moel@345: 		internal void OnNodesChanged(TreeModelEventArgs args)
moel@345: 		{
moel@345: 			if (NodesChanged != null)
moel@345: 				NodesChanged(this, args);
moel@345: 		}
moel@345: 
moel@345: 		public event EventHandler<TreePathEventArgs> StructureChanged;
moel@345: 		public void OnStructureChanged(TreePathEventArgs args)
moel@345: 		{
moel@345: 			if (StructureChanged != null)
moel@345: 				StructureChanged(this, args);
moel@345: 		}
moel@345: 
moel@345: 		public event EventHandler<TreeModelEventArgs> NodesInserted;
moel@345: 		internal void OnNodeInserted(Node parent, int index, Node node)
moel@345: 		{
moel@345: 			if (NodesInserted != null)
moel@345: 			{
moel@345: 				TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node });
moel@345: 				NodesInserted(this, args);
moel@345: 			}
moel@345: 
moel@345: 		}
moel@345: 
moel@345: 		public event EventHandler<TreeModelEventArgs> NodesRemoved;
moel@345: 		internal void OnNodeRemoved(Node parent, int index, Node node)
moel@345: 		{
moel@345: 			if (NodesRemoved != null)
moel@345: 			{
moel@345: 				TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node });
moel@345: 				NodesRemoved(this, args);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		#endregion
moel@345: 	}
moel@345: }