moel@345: using System;
moel@345: using System.Collections.Generic;
moel@345: using System.Text;
moel@345: using Aga.Controls.Tree.NodeControls;
moel@345: using System.ComponentModel;
moel@345: using System.Drawing;
moel@345: using System.Windows.Forms;
moel@345: 
moel@345: namespace Aga.Controls.Tree
moel@345: {
moel@345: 	internal class IncrementalSearch
moel@345: 	{
moel@345: 		private const int SearchTimeout = 300; //end of incremental search timeot in msec
moel@345: 
moel@345: 		private TreeViewAdv _tree;
moel@345: 		private TreeNodeAdv _currentNode;
moel@345: 		private string _searchString = "";
moel@345: 		private DateTime _lastKeyPressed = DateTime.Now;
moel@345: 
moel@345: 		public IncrementalSearch(TreeViewAdv tree)
moel@345: 		{
moel@345: 			_tree = tree;
moel@345: 		}
moel@345: 
moel@345: 		public void Search(Char value)
moel@345: 		{
moel@345: 			if (!Char.IsControl(value))
moel@345: 			{
moel@345: 				Char ch = Char.ToLowerInvariant(value);
moel@345: 				DateTime dt = DateTime.Now;
moel@345: 				TimeSpan ts = dt - _lastKeyPressed;
moel@345: 				_lastKeyPressed = dt;
moel@345: 				if (ts.TotalMilliseconds < SearchTimeout)
moel@345: 				{
moel@345: 					if (_searchString == value.ToString())
moel@345: 						FirstCharSearch(ch);
moel@345: 					else
moel@345: 						ContinuousSearch(ch);
moel@345: 				}
moel@345: 				else
moel@345: 				{
moel@345: 					FirstCharSearch(ch);
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void ContinuousSearch(Char value)
moel@345: 		{
moel@345: 			if (value == ' ' && String.IsNullOrEmpty(_searchString))
moel@345: 				return; //Ingnore leading space
moel@345: 
moel@345: 			_searchString += value;
moel@345: 			DoContinuousSearch();
moel@345: 		}
moel@345: 
moel@345: 		private void FirstCharSearch(Char value)
moel@345: 		{
moel@345: 			if (value == ' ')
moel@345: 				return;
moel@345: 
moel@345: 			_searchString = value.ToString();
moel@345: 			TreeNodeAdv node = null;
moel@345: 			if (_tree.SelectedNode != null)
moel@345: 				node = _tree.SelectedNode.NextVisibleNode;
moel@345: 			if (node == null)
moel@345: 				node = _tree.Root.NextVisibleNode;
moel@345: 
moel@345: 			if (node != null)
moel@345: 				foreach (string label in IterateNodeLabels(node))
moel@345: 				{
moel@345: 					if (label.StartsWith(_searchString))
moel@345: 					{
moel@345: 						_tree.SelectedNode = _currentNode;
moel@345: 						return;
moel@345: 					}
moel@345: 				}
moel@345: 		}
moel@345: 
moel@345: 		public virtual void EndSearch()
moel@345: 		{
moel@345: 			_currentNode = null;
moel@345: 			_searchString = "";
moel@345: 		}
moel@345: 
moel@345: 		protected IEnumerable<string> IterateNodeLabels(TreeNodeAdv start)
moel@345: 		{
moel@345: 			_currentNode = start;
moel@345: 			while(_currentNode != null)
moel@345: 			{
moel@345: 				foreach (string label in GetNodeLabels(_currentNode))
moel@345: 					yield return label;
moel@345: 
moel@345: 				_currentNode = _currentNode.NextVisibleNode;
moel@345: 				if (_currentNode == null)
moel@345: 					_currentNode = _tree.Root;
moel@345: 
moel@345: 				if (start == _currentNode)
moel@345: 					break;
moel@345: 			} 
moel@345: 		}
moel@345: 
moel@345: 		private IEnumerable<string> GetNodeLabels(TreeNodeAdv node)
moel@345: 		{
moel@345: 			foreach (NodeControl nc in _tree.NodeControls)
moel@345: 			{
moel@345: 				BindableControl bc = nc as BindableControl;
moel@345: 				if (bc != null && bc.IncrementalSearchEnabled)
moel@345: 				{
moel@345: 					object obj = bc.GetValue(node);
moel@345: 					if (obj != null)
moel@345: 						yield return obj.ToString().ToLowerInvariant();
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private bool DoContinuousSearch()
moel@345: 		{
moel@345: 			bool found = false;
moel@345: 			if (!String.IsNullOrEmpty(_searchString))
moel@345: 			{
moel@345: 				TreeNodeAdv node = null;
moel@345: 				if (_tree.SelectedNode != null)
moel@345: 					node = _tree.SelectedNode;
moel@345: 				if (node == null)
moel@345: 					node = _tree.Root.NextVisibleNode;
moel@345: 
moel@345: 				if (!String.IsNullOrEmpty(_searchString))
moel@345: 				{
moel@345: 					foreach (string label in IterateNodeLabels(node))
moel@345: 					{
moel@345: 						if (label.StartsWith(_searchString))
moel@345: 						{
moel@345: 							found = true;
moel@345: 							_tree.SelectedNode = _currentNode;
moel@345: 							break;
moel@345: 						}
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 			return found;
moel@345: 		}
moel@345: 
moel@345: 	}
moel@345: }