moel@345: using System;
moel@345: using System.Collections.Generic;
moel@345: using System.Collections.ObjectModel;
moel@345: using System.ComponentModel;
moel@345: using System.Drawing;
moel@345: using System.Security.Permissions;
moel@345: using System.Threading;
moel@345: using System.Windows.Forms;
moel@345: using System.Collections;
moel@345: 
moel@345: using Aga.Controls.Tree.NodeControls;
moel@345: using Aga.Controls.Threading;
moel@345: 
moel@345: 
moel@345: namespace Aga.Controls.Tree
moel@345: {
moel@345: 	/// <summary>
moel@345: 	/// Extensible advanced <see cref="TreeView"/> implemented in 100% managed C# code.
moel@345: 	/// Features: Model/View architecture. Multiple column per node. Ability to select
moel@345: 	/// multiple tree nodes. Different types of controls for each node column: 
moel@345: 	/// <see cref="CheckBox"/>, Icon, Label... Drag and Drop highlighting. Load on
moel@345: 	/// demand of nodes. Incremental search of nodes.
moel@345: 	/// </summary>
moel@345: 	public partial class TreeViewAdv : Control
moel@345: 	{
moel@345: 		private const int LeftMargin = 7;
moel@345: 		internal const int ItemDragSensivity = 4;
moel@345: 		private readonly int _columnHeaderHeight;
moel@345: 		private const int DividerWidth = 9;
moel@345: 		private const int DividerCorrectionGap = -2;
moel@345: 
moel@345: 		private Pen _linePen;
moel@345: 		private Pen _markPen;
moel@345: 		private bool _suspendUpdate;
moel@345: 		private bool _needFullUpdate;
moel@345: 		private bool _fireSelectionEvent;
moel@345: 		private NodePlusMinus _plusMinus;
moel@345: 		private ToolTip _toolTip;
moel@345: 		private DrawContext _measureContext;
moel@345: 		private TreeColumn _hotColumn;
moel@345: 		private IncrementalSearch _search;
moel@345: 		private List<TreeNodeAdv> _expandingNodes = new List<TreeNodeAdv>();
moel@345: 		private AbortableThreadPool _threadPool = new AbortableThreadPool();
moel@345: 
moel@345: 		#region Public Events
moel@345: 
moel@345: 		[Category("Action")]
moel@345: 		public event ItemDragEventHandler ItemDrag;
moel@345: 		private void OnItemDrag(MouseButtons buttons, object item)
moel@345: 		{
moel@345: 			if (ItemDrag != null)
moel@345: 				ItemDrag(this, new ItemDragEventArgs(buttons, item));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseClick;
moel@345: 		private void OnNodeMouseClick(TreeNodeAdvMouseEventArgs args)
moel@345: 		{
moel@345: 			if (NodeMouseClick != null)
moel@345: 				NodeMouseClick(this, args);
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseDoubleClick;
moel@345: 		private void OnNodeMouseDoubleClick(TreeNodeAdvMouseEventArgs args)
moel@345: 		{
moel@345: 			if (NodeMouseDoubleClick != null)
moel@345: 				NodeMouseDoubleClick(this, args);
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeColumnEventArgs> ColumnWidthChanged;
moel@345: 		internal void OnColumnWidthChanged(TreeColumn column)
moel@345: 		{
moel@345: 			if (ColumnWidthChanged != null)
moel@345: 				ColumnWidthChanged(this, new TreeColumnEventArgs(column));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeColumnEventArgs> ColumnReordered;
moel@345: 		internal void OnColumnReordered(TreeColumn column)
moel@345: 		{
moel@345: 			if (ColumnReordered != null)
moel@345: 				ColumnReordered(this, new TreeColumnEventArgs(column));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeColumnEventArgs> ColumnClicked;
moel@345: 		internal void OnColumnClicked(TreeColumn column)
moel@345: 		{
moel@345: 			if (ColumnClicked != null)
moel@345: 				ColumnClicked(this, new TreeColumnEventArgs(column));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler SelectionChanged;
moel@345: 		internal void OnSelectionChanged()
moel@345: 		{
moel@345: 			if (SuspendSelectionEvent)
moel@345: 				_fireSelectionEvent = true;
moel@345: 			else
moel@345: 			{
moel@345: 				_fireSelectionEvent = false;
moel@345: 				if (SelectionChanged != null)
moel@345: 					SelectionChanged(this, EventArgs.Empty);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeViewAdvEventArgs> Collapsing;
moel@345: 		private void OnCollapsing(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (Collapsing != null)
moel@345: 				Collapsing(this, new TreeViewAdvEventArgs(node));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeViewAdvEventArgs> Collapsed;
moel@345: 		private void OnCollapsed(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (Collapsed != null)
moel@345: 				Collapsed(this, new TreeViewAdvEventArgs(node));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeViewAdvEventArgs> Expanding;
moel@345: 		private void OnExpanding(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (Expanding != null)
moel@345: 				Expanding(this, new TreeViewAdvEventArgs(node));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeViewAdvEventArgs> Expanded;
moel@345: 		private void OnExpanded(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (Expanded != null)
moel@345: 				Expanded(this, new TreeViewAdvEventArgs(node));
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler GridLineStyleChanged;
moel@345: 		private void OnGridLineStyleChanged()
moel@345: 		{
moel@345: 			if (GridLineStyleChanged != null)
moel@345: 				GridLineStyleChanged(this, EventArgs.Empty);
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event ScrollEventHandler Scroll;
moel@345: 		protected virtual void OnScroll(ScrollEventArgs e)
moel@345: 		{
moel@345: 			if (Scroll != null)
moel@345: 				Scroll(this, e);
moel@345: 		}
moel@345: 
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<TreeViewRowDrawEventArgs> RowDraw;
moel@345: 		protected virtual void OnRowDraw(PaintEventArgs e, TreeNodeAdv node, DrawContext context, int row, Rectangle rowRect)
moel@345: 		{
moel@345: 			if (RowDraw != null)
moel@345: 			{
moel@345: 				TreeViewRowDrawEventArgs args = new TreeViewRowDrawEventArgs(e.Graphics, e.ClipRectangle, node, context, row, rowRect);
moel@345: 				RowDraw(this, args);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		/// <summary>
moel@345: 		/// Fires when control is going to draw. Can be used to change text or back color
moel@345: 		/// </summary>
moel@345: 		[Category("Behavior")]
moel@345: 		public event EventHandler<DrawEventArgs> DrawControl;
moel@345: 
moel@345: 		internal bool DrawControlMustBeFired()
moel@345: 		{
moel@345: 			return DrawControl != null;
moel@345: 		}
moel@345: 
moel@345: 		internal void FireDrawControl(DrawEventArgs args)
moel@345: 		{
moel@345: 			OnDrawControl(args);
moel@345: 		}
moel@345: 
moel@345: 		protected virtual void OnDrawControl(DrawEventArgs args)
moel@345: 		{
moel@345: 			if (DrawControl != null)
moel@345: 				DrawControl(this, args);
moel@345: 		}
moel@345: 
moel@345: 
moel@345: 		[Category("Drag Drop")]
moel@345: 		public event EventHandler<DropNodeValidatingEventArgs> DropNodeValidating;
moel@345: 		protected virtual void OnDropNodeValidating(Point point, ref TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (DropNodeValidating != null)
moel@345: 			{
moel@345: 				DropNodeValidatingEventArgs args = new DropNodeValidatingEventArgs(point, node);
moel@345: 				DropNodeValidating(this, args);
moel@345: 				node = args.Node;
moel@345: 			}
moel@345: 		}
moel@345: 		#endregion
moel@345: 
moel@345: 		public TreeViewAdv()
moel@345: 		{
moel@345: 			InitializeComponent();
moel@345: 			SetStyle(ControlStyles.AllPaintingInWmPaint
moel@345: 				| ControlStyles.UserPaint
moel@345: 				| ControlStyles.OptimizedDoubleBuffer
moel@345: 				| ControlStyles.ResizeRedraw
moel@345: 				| ControlStyles.Selectable
moel@345: 				, true);
moel@345: 
moel@345: 
moel@345: 			if (Application.RenderWithVisualStyles)
moel@345: 				_columnHeaderHeight = 20;
moel@345: 			else
moel@345: 				_columnHeaderHeight = 17;
moel@345: 
moel@345: 			//BorderStyle = BorderStyle.Fixed3D;
moel@345: 			_hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight;
moel@345: 			_vScrollBar.Width = SystemInformation.VerticalScrollBarWidth;
moel@345: 			_rowLayout = new FixedRowHeightLayout(this, RowHeight);
moel@345: 			_rowMap = new List<TreeNodeAdv>();
moel@345: 			_selection = new List<TreeNodeAdv>();
moel@345: 			_readonlySelection = new ReadOnlyCollection<TreeNodeAdv>(_selection);
moel@345: 			_columns = new TreeColumnCollection(this);
moel@345: 			_toolTip = new ToolTip();
moel@345: 
moel@345: 			_measureContext = new DrawContext();
moel@345: 			_measureContext.Font = Font;
moel@345: 			_measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1));
moel@345: 
moel@345: 			Input = new NormalInputState(this);
moel@345: 			_search = new IncrementalSearch(this);
moel@345: 			CreateNodes();
moel@345: 			CreatePens();
moel@345: 
moel@345: 			ArrangeControls();
moel@345: 
moel@345: 			_plusMinus = new NodePlusMinus();
moel@345: 			_controls = new NodeControlsCollection(this);
moel@345: 
moel@345: 			Font = _font;
moel@345: 			ExpandingIcon.IconChanged += ExpandingIconChanged;
moel@345: 		}
moel@345: 
moel@345: 		void ExpandingIconChanged(object sender, EventArgs e)
moel@345: 		{
moel@345: 			if (IsHandleCreated && !IsDisposed)
moel@345: 				BeginInvoke(new MethodInvoker(DrawIcons));
moel@345: 		}
moel@345: 
moel@345: 		private void DrawIcons()
moel@345: 		{
moel@345: 			using (Graphics gr = Graphics.FromHwnd(this.Handle))
moel@345: 			{
moel@345: 				//Apply the same Graphics Transform logic as used in OnPaint.
moel@345: 				int y = 0;
moel@345: 				if (UseColumns)
moel@345: 				{
moel@345: 					y += ColumnHeaderHeight;
moel@345: 					if (Columns.Count == 0)
moel@345: 						return;
moel@345: 				}
moel@345: 				int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y;
moel@345: 				y -= firstRowY;
moel@345: 				gr.ResetTransform();
moel@345: 				gr.TranslateTransform(-OffsetX, y);
moel@345: 
moel@345: 				DrawContext context = new DrawContext();
moel@345: 				context.Graphics = gr;
moel@345: 				for (int i = 0; i < _expandingNodes.Count; i++)
moel@345: 				{
moel@345: 					foreach (NodeControlInfo item in GetNodeControls(_expandingNodes[i]))
moel@345: 					{
moel@345: 						if (item.Control is ExpandingIcon)
moel@345: 						{
moel@345: 							Rectangle bounds = item.Bounds;
moel@345: 							if (item.Node.Parent == null && UseColumns)
moel@345: 								bounds.Location = Point.Empty; // display root expanding icon at 0,0
moel@345: 
moel@345: 							context.Bounds = bounds;
moel@345: 							item.Control.Draw(item.Node, context);
moel@345: 						}
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		#region Public Methods
moel@345: 
moel@345: 		public TreePath GetPath(TreeNodeAdv 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 && node != null)
moel@345: 				{
moel@345: 					stack.Push(node.Tag);
moel@345: 					node = node.Parent;
moel@345: 				}
moel@345: 				return new TreePath(stack.ToArray());
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		public TreeNodeAdv GetNodeAt(Point point)
moel@345: 		{
moel@345: 			NodeControlInfo info = GetNodeControlInfoAt(point);
moel@345: 			return info.Node;
moel@345: 		}
moel@345: 
moel@345: 		public NodeControlInfo GetNodeControlInfoAt(Point point)
moel@345: 		{
moel@345: 			if (point.X < 0 || point.Y < 0)
moel@345: 				return NodeControlInfo.Empty;
moel@345: 
moel@345: 			int row = _rowLayout.GetRowAt(point);
moel@345: 			if (row < RowCount && row >= 0)
moel@345: 				return GetNodeControlInfoAt(RowMap[row], point);
moel@345: 			else
moel@345: 				return NodeControlInfo.Empty;
moel@345: 		}
moel@345: 
moel@345: 		private NodeControlInfo GetNodeControlInfoAt(TreeNodeAdv node, Point point)
moel@345: 		{
moel@345: 			Rectangle rect = _rowLayout.GetRowBounds(FirstVisibleRow);
moel@345: 			point.Y += (rect.Y - ColumnHeaderHeight);
moel@345: 			point.X += OffsetX;
moel@345: 			foreach (NodeControlInfo info in GetNodeControls(node))
moel@345: 				if (info.Bounds.Contains(point))
moel@345: 					return info;
moel@345: 
moel@345: 			if (FullRowSelect)
moel@345: 				return new NodeControlInfo(null, Rectangle.Empty, node);
moel@345: 			else
moel@345: 				return NodeControlInfo.Empty;
moel@345: 		}
moel@345: 
moel@345: 		public void BeginUpdate()
moel@345: 		{
moel@345: 			_suspendUpdate = true;
moel@345: 			SuspendSelectionEvent = true;
moel@345: 		}
moel@345: 
moel@345: 		public void EndUpdate()
moel@345: 		{
moel@345: 			_suspendUpdate = false;
moel@345: 			if (_needFullUpdate)
moel@345: 				FullUpdate();
moel@345: 			else
moel@345: 				UpdateView();
moel@345: 			SuspendSelectionEvent = false;
moel@345: 		}
moel@345: 
moel@345: 		public void ExpandAll()
moel@345: 		{
moel@345: 			_root.ExpandAll();
moel@345: 		}
moel@345: 
moel@345: 		public void CollapseAll()
moel@345: 		{
moel@345: 			_root.CollapseAll();
moel@345: 		}
moel@345: 
moel@345: 		/// <summary>
moel@345: 		/// Expand all parent nodes, andd scroll to the specified node
moel@345: 		/// </summary>
moel@345: 		public void EnsureVisible(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (node == null)
moel@345: 				throw new ArgumentNullException("node");
moel@345: 
moel@345: 			if (!IsMyNode(node))
moel@345: 				throw new ArgumentException();
moel@345: 
moel@345: 			TreeNodeAdv parent = node.Parent;
moel@345: 			while (parent != _root)
moel@345: 			{
moel@345: 				parent.IsExpanded = true;
moel@345: 				parent = parent.Parent;
moel@345: 			}
moel@345: 			ScrollTo(node);
moel@345: 		}
moel@345: 
moel@345: 		/// <summary>
moel@345: 		/// Make node visible, scroll if needed. All parent nodes of the specified node must be expanded
moel@345: 		/// </summary>
moel@345: 		/// <param name="node"></param>
moel@345: 		public void ScrollTo(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (node == null)
moel@345: 				throw new ArgumentNullException("node");
moel@345: 
moel@345: 			if (!IsMyNode(node))
moel@345: 				throw new ArgumentException();
moel@345: 
moel@345: 			if (node.Row < 0)
moel@345: 				CreateRowMap();
moel@345: 
moel@345: 			int row = -1;
moel@345: 
moel@345: 			if (node.Row < FirstVisibleRow)
moel@345: 				row = node.Row;
moel@345: 			else
moel@345: 			{
moel@345: 				int pageStart = _rowLayout.GetRowBounds(FirstVisibleRow).Top;
moel@345: 				int rowBottom = _rowLayout.GetRowBounds(node.Row).Bottom;
moel@345: 				if (rowBottom > pageStart + DisplayRectangle.Height - ColumnHeaderHeight)
moel@345: 					row = _rowLayout.GetFirstRow(node.Row);
moel@345: 			}
moel@345: 
moel@345: 			if (row >= _vScrollBar.Minimum && row <= _vScrollBar.Maximum)
moel@345: 				_vScrollBar.Value = row;
moel@345: 		}
moel@345: 
moel@345: 		public void ClearSelection()
moel@345: 		{
moel@345: 			BeginUpdate();
moel@345: 			try
moel@345: 			{
moel@345: 				ClearSelectionInternal();
moel@345: 			}
moel@345: 			finally
moel@345: 			{
moel@345: 				EndUpdate();
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		internal void ClearSelectionInternal()
moel@345: 		{
moel@345: 			while (Selection.Count > 0)
moel@345: 			{
moel@345: 				var t = Selection[0];
moel@345: 				t.IsSelected = false;
moel@345: 				Selection.Remove(t); //hack
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		#endregion
moel@345: 
moel@345: 		protected override void OnSizeChanged(EventArgs e)
moel@345: 		{
moel@345: 			ArrangeControls();
moel@345: 			SafeUpdateScrollBars();
moel@345: 			base.OnSizeChanged(e);
moel@345: 		}
moel@345: 
moel@345: 		private void ArrangeControls()
moel@345: 		{
moel@345: 			int hBarSize = _hScrollBar.Height;
moel@345: 			int vBarSize = _vScrollBar.Width;
moel@345: 			Rectangle clientRect = ClientRectangle;
moel@345: 
moel@345: 			_hScrollBar.SetBounds(clientRect.X, clientRect.Bottom - hBarSize,
moel@345: 				clientRect.Width - vBarSize, hBarSize);
moel@345: 
moel@345: 			_vScrollBar.SetBounds(clientRect.Right - vBarSize, clientRect.Y,
moel@345: 				vBarSize, clientRect.Height - hBarSize);
moel@345: 		}
moel@345: 
moel@345: 		private void SafeUpdateScrollBars()
moel@345: 		{
moel@345: 			if (InvokeRequired)
moel@345: 				BeginInvoke(new MethodInvoker(UpdateScrollBars));
moel@345: 			else
moel@345: 				UpdateScrollBars();
moel@345: 		}
moel@345: 
moel@345: 		private void UpdateScrollBars()
moel@345: 		{
moel@345: 			UpdateVScrollBar();
moel@345: 			UpdateHScrollBar();
moel@345: 			UpdateVScrollBar();
moel@345: 			UpdateHScrollBar();
moel@345: 			_hScrollBar.Width = DisplayRectangle.Width;
moel@345: 			_vScrollBar.Height = DisplayRectangle.Height;
moel@345: 		}
moel@345: 
moel@345: 		private void UpdateHScrollBar()
moel@345: 		{
moel@345: 			_hScrollBar.Maximum = ContentWidth;
moel@345: 			_hScrollBar.LargeChange = Math.Max(DisplayRectangle.Width, 0);
moel@345: 			_hScrollBar.SmallChange = 5;
moel@345: 			_hScrollBar.Visible = _hScrollBar.LargeChange < _hScrollBar.Maximum;
moel@345: 			_hScrollBar.Value = Math.Min(_hScrollBar.Value, _hScrollBar.Maximum - _hScrollBar.LargeChange + 1);
moel@345: 		}
moel@345: 
moel@345: 		private void UpdateVScrollBar()
moel@345: 		{
moel@345: 			_vScrollBar.Maximum = Math.Max(RowCount - 1, 0);
moel@345: 			_vScrollBar.LargeChange = _rowLayout.PageRowCount;
moel@345: 			_vScrollBar.Visible = (RowCount > 0) && (_vScrollBar.LargeChange <= _vScrollBar.Maximum);
moel@345: 			_vScrollBar.Value = Math.Min(_vScrollBar.Value, _vScrollBar.Maximum - _vScrollBar.LargeChange + 1);
moel@345: 		}
moel@345: 
moel@345: 		protected override CreateParams CreateParams
moel@345: 		{
moel@345: 			[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
moel@345: 			get
moel@345: 			{
moel@345: 				CreateParams res = base.CreateParams;
moel@345: 				switch (BorderStyle)
moel@345: 				{
moel@345: 					case BorderStyle.FixedSingle:
moel@345: 						res.Style |= 0x800000;
moel@345: 						break;
moel@345: 					case BorderStyle.Fixed3D:
moel@345: 						res.ExStyle |= 0x200;
moel@345: 						break;
moel@345: 				}
moel@345: 				return res;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnGotFocus(EventArgs e)
moel@345: 		{
moel@345: 			UpdateView();
moel@345: 			ChangeInput();
moel@345: 			base.OnGotFocus(e);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnFontChanged(EventArgs e)
moel@345: 		{
moel@345: 			base.OnFontChanged(e);
moel@345: 			_measureContext.Font = Font;
moel@345: 			FullUpdate();
moel@345: 		}
moel@345: 
moel@345: 		internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (node == null)
moel@345: 				yield break;
moel@345: 			Rectangle rowRect = _rowLayout.GetRowBounds(node.Row);
moel@345: 			foreach (NodeControlInfo n in GetNodeControls(node, rowRect))
moel@345: 				yield return n;
moel@345: 		}
moel@345: 
moel@345: 		internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node, Rectangle rowRect)
moel@345: 		{
moel@345: 			if (node == null)
moel@345: 				yield break;
moel@345: 
moel@345: 			int y = rowRect.Y;
moel@345: 			int x = (node.Level - 1) * _indent + LeftMargin;
moel@345: 			int width = 0;
moel@345: 			if (node.Row == 0 && ShiftFirstNode)
moel@345: 				x -= _indent;
moel@345: 			Rectangle rect = Rectangle.Empty;
moel@345: 
moel@345: 			if (ShowPlusMinus)
moel@345: 			{
moel@345: 				width = _plusMinus.GetActualSize(node, _measureContext).Width;
moel@345: 				rect = new Rectangle(x, y, width, rowRect.Height);
moel@345: 				if (UseColumns && Columns.Count > 0 && Columns[0].Width < rect.Right)
moel@345: 					rect.Width = Columns[0].Width - x;
moel@345: 
moel@345: 				yield return new NodeControlInfo(_plusMinus, rect, node);
moel@345: 				x += width;
moel@345: 			}
moel@345: 
moel@345: 			if (!UseColumns)
moel@345: 			{
moel@345: 				foreach (NodeControl c in NodeControls)
moel@345: 				{
moel@345: 					Size s = c.GetActualSize(node, _measureContext);
moel@345: 					if (!s.IsEmpty)
moel@345: 					{
moel@345: 						width = s.Width;
moel@345: 						rect = new Rectangle(x, y, width, rowRect.Height);
moel@345: 						x += rect.Width;
moel@345: 						yield return new NodeControlInfo(c, rect, node);
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 			else
moel@345: 			{
moel@345: 				int right = 0;
moel@345: 				foreach (TreeColumn col in Columns)
moel@345: 				{
moel@345: 					if (col.IsVisible && col.Width > 0)
moel@345: 					{
moel@345: 						right += col.Width;
moel@345: 						for (int i = 0; i < NodeControls.Count; i++)
moel@345: 						{
moel@345: 							NodeControl nc = NodeControls[i];
moel@345: 							if (nc.ParentColumn == col)
moel@345: 							{
moel@345: 								Size s = nc.GetActualSize(node, _measureContext);
moel@345: 								if (!s.IsEmpty)
moel@345: 								{
moel@345: 									bool isLastControl = true;
moel@345: 									for (int k = i + 1; k < NodeControls.Count; k++)
moel@345: 										if (NodeControls[k].ParentColumn == col)
moel@345: 										{
moel@345: 											isLastControl = false;
moel@345: 											break;
moel@345: 										}
moel@345: 
moel@345: 									width = right - x;
moel@345: 									if (!isLastControl)
moel@345: 										width = s.Width;
moel@345: 									int maxWidth = Math.Max(0, right - x);
moel@345: 									rect = new Rectangle(x, y, Math.Min(maxWidth, width), rowRect.Height);
moel@345: 									x += width;
moel@345: 									yield return new NodeControlInfo(nc, rect, node);
moel@345: 								}
moel@345: 							}
moel@345: 						}
moel@345: 						x = right;
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		internal static double Dist(Point p1, Point p2)
moel@345: 		{
moel@345: 			return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
moel@345: 		}
moel@345: 
moel@345: 		public void FullUpdate()
moel@345: 		{
moel@345: 			HideEditor();
moel@345: 			if (InvokeRequired)
moel@345: 				BeginInvoke(new MethodInvoker(UnsafeFullUpdate));
moel@345: 			else
moel@345: 				UnsafeFullUpdate();
moel@345: 		}
moel@345: 
moel@345: 		private void UnsafeFullUpdate()
moel@345: 		{
moel@345: 			_rowLayout.ClearCache();
moel@345: 			CreateRowMap();
moel@345: 			SafeUpdateScrollBars();
moel@345: 			UpdateView();
moel@345: 			_needFullUpdate = false;
moel@345: 		}
moel@345: 
moel@345: 		internal void UpdateView()
moel@345: 		{
moel@345: 			if (!_suspendUpdate)
moel@345: 				Invalidate(false);
moel@345: 		}
moel@345: 
moel@345: 		internal void UpdateHeaders()
moel@345: 		{
moel@345: 			Invalidate(new Rectangle(0, 0, Width, ColumnHeaderHeight));
moel@345: 		}
moel@345: 
moel@345: 		internal void UpdateColumns()
moel@345: 		{
moel@345: 			FullUpdate();
moel@345: 		}
moel@345: 
moel@345: 		private void CreateNodes()
moel@345: 		{
moel@345: 			Selection.Clear();
moel@345: 			SelectionStart = null;
moel@345: 			_root = new TreeNodeAdv(this, null);
moel@345: 			_root.IsExpanded = true;
moel@345: 			if (_root.Nodes.Count > 0)
moel@345: 				CurrentNode = _root.Nodes[0];
moel@345: 			else
moel@345: 				CurrentNode = null;
moel@345: 		}
moel@345: 
moel@345: 		internal void ReadChilds(TreeNodeAdv parentNode)
moel@345: 		{
moel@345: 			ReadChilds(parentNode, false);
moel@345: 		}
moel@345: 
moel@345: 		internal void ReadChilds(TreeNodeAdv parentNode, bool performFullUpdate)
moel@345: 		{
moel@345: 			if (!parentNode.IsLeaf)
moel@345: 			{
moel@345: 				parentNode.IsExpandedOnce = true;
moel@345: 				parentNode.Nodes.Clear();
moel@345: 
moel@345: 				if (Model != null)
moel@345: 				{
moel@345: 					IEnumerable items = Model.GetChildren(GetPath(parentNode));
moel@345: 					if (items != null)
moel@345: 						foreach (object obj in items)
moel@345: 						{
moel@345: 							AddNewNode(parentNode, obj, -1);
moel@345: 							if (performFullUpdate)
moel@345: 								FullUpdate();
moel@345: 						}
moel@345: 				}
moel@345: 
moel@345: 				if (parentNode.AutoExpandOnStructureChanged)
moel@345: 					parentNode.ExpandAll();
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void AddNewNode(TreeNodeAdv parent, object tag, int index)
moel@345: 		{
moel@345: 			TreeNodeAdv node = new TreeNodeAdv(this, tag);
moel@345: 			AddNode(parent, index, node);
moel@345: 		}
moel@345: 
moel@345: 		private void AddNode(TreeNodeAdv parent, int index, TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (index >= 0 && index < parent.Nodes.Count)
moel@345: 				parent.Nodes.Insert(index, node);
moel@345: 			else
moel@345: 				parent.Nodes.Add(node);
moel@345: 
moel@345: 			node.IsLeaf = Model.IsLeaf(GetPath(node));
moel@345: 			if (node.IsLeaf)
moel@345: 				node.Nodes.Clear();
moel@345: 			if (!LoadOnDemand || node.IsExpandedOnce)
moel@345: 				ReadChilds(node);
moel@345: 		}
moel@345: 
moel@345: 		private struct ExpandArgs
moel@345: 		{
moel@345: 			public TreeNodeAdv Node;
moel@345: 			public bool Value;
moel@345: 			public bool IgnoreChildren;
moel@345: 		}
moel@345: 
moel@345: 		public void AbortBackgroundExpandingThreads()
moel@345: 		{
moel@345: 			_threadPool.CancelAll(true);
moel@345: 			for (int i = 0; i < _expandingNodes.Count; i++)
moel@345: 				_expandingNodes[i].IsExpandingNow = false;
moel@345: 			_expandingNodes.Clear();
moel@345: 			Invalidate();
moel@345: 		}
moel@345: 
moel@345: 		internal void SetIsExpanded(TreeNodeAdv node, bool value, bool ignoreChildren)
moel@345: 		{
moel@345: 			ExpandArgs eargs = new ExpandArgs();
moel@345: 			eargs.Node = node;
moel@345: 			eargs.Value = value;
moel@345: 			eargs.IgnoreChildren = ignoreChildren;
moel@345: 
moel@345: 			if (AsyncExpanding && LoadOnDemand && !_threadPool.IsMyThread(Thread.CurrentThread))
moel@345: 			{
moel@345: 				WaitCallback wc = delegate(object argument) { SetIsExpanded((ExpandArgs)argument); };
moel@345: 				_threadPool.QueueUserWorkItem(wc, eargs);
moel@345: 			}
moel@345: 			else
moel@345: 				SetIsExpanded(eargs);
moel@345: 		}
moel@345: 
moel@345: 		private void SetIsExpanded(ExpandArgs eargs)
moel@345: 		{
moel@345: 			bool update = !eargs.IgnoreChildren && !AsyncExpanding;
moel@345: 			if (update)
moel@345: 				BeginUpdate();
moel@345: 			try
moel@345: 			{
moel@345: 				if (IsMyNode(eargs.Node) && eargs.Node.IsExpanded != eargs.Value)
moel@345: 					SetIsExpanded(eargs.Node, eargs.Value);
moel@345: 
moel@345: 				if (!eargs.IgnoreChildren)
moel@345: 					SetIsExpandedRecursive(eargs.Node, eargs.Value);
moel@345: 			}
moel@345: 			finally
moel@345: 			{
moel@345: 				if (update)
moel@345: 					EndUpdate();
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		internal void SetIsExpanded(TreeNodeAdv node, bool value)
moel@345: 		{
moel@345: 			if (Root == node && !value)
moel@345: 				return; //Can't collapse root node
moel@345: 
moel@345: 			if (value)
moel@345: 			{
moel@345: 				OnExpanding(node);
moel@345: 				node.OnExpanding();
moel@345: 			}
moel@345: 			else
moel@345: 			{
moel@345: 				OnCollapsing(node);
moel@345: 				node.OnCollapsing();
moel@345: 			}
moel@345: 
moel@345: 			if (value && !node.IsExpandedOnce)
moel@345: 			{
moel@345: 				if (AsyncExpanding && LoadOnDemand)
moel@345: 				{
moel@345: 					AddExpandingNode(node);
moel@345: 					node.AssignIsExpanded(true);
moel@345: 					Invalidate();
moel@345: 				}
moel@345: 				ReadChilds(node, AsyncExpanding);
moel@345: 				RemoveExpandingNode(node);
moel@345: 			}
moel@345: 			node.AssignIsExpanded(value);
moel@345: 			SmartFullUpdate();
moel@345: 
moel@345: 			if (value)
moel@345: 			{
moel@345: 				OnExpanded(node);
moel@345: 				node.OnExpanded();
moel@345: 			}
moel@345: 			else
moel@345: 			{
moel@345: 				OnCollapsed(node);
moel@345: 				node.OnCollapsed();
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void RemoveExpandingNode(TreeNodeAdv node)
moel@345: 		{
moel@345: 			node.IsExpandingNow = false;
moel@345: 			_expandingNodes.Remove(node);
moel@345: 			if (_expandingNodes.Count <= 0)
moel@345: 				ExpandingIcon.Stop();
moel@345: 		}
moel@345: 
moel@345: 		private void AddExpandingNode(TreeNodeAdv node)
moel@345: 		{
moel@345: 			node.IsExpandingNow = true;
moel@345: 			_expandingNodes.Add(node);
moel@345: 			ExpandingIcon.Start();
moel@345: 		}
moel@345: 
moel@345: 		internal void SetIsExpandedRecursive(TreeNodeAdv root, bool value)
moel@345: 		{
moel@345: 			for (int i = 0; i < root.Nodes.Count; i++)
moel@345: 			{
moel@345: 				TreeNodeAdv node = root.Nodes[i];
moel@345: 				node.IsExpanded = value;
moel@345: 				SetIsExpandedRecursive(node, value);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void CreateRowMap()
moel@345: 		{
moel@345: 			RowMap.Clear();
moel@345: 			int row = 0;
moel@345: 			_contentWidth = 0;
moel@345: 			foreach (TreeNodeAdv node in VisibleNodes)
moel@345: 			{
moel@345: 				node.Row = row;
moel@345: 				RowMap.Add(node);
moel@345: 				if (!UseColumns)
moel@345: 				{
moel@345: 					_contentWidth = Math.Max(_contentWidth, GetNodeWidth(node));
moel@345: 				}
moel@345: 				row++;
moel@345: 			}
moel@345: 			if (UseColumns)
moel@345: 			{
moel@345: 				_contentWidth = 0;
moel@345: 				foreach (TreeColumn col in _columns)
moel@345: 					if (col.IsVisible)
moel@345: 						_contentWidth += col.Width;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private int GetNodeWidth(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (node.RightBounds == null)
moel@345: 			{
moel@345: 				Rectangle res = GetNodeBounds(GetNodeControls(node, Rectangle.Empty));
moel@345: 				node.RightBounds = res.Right;
moel@345: 			}
moel@345: 			return node.RightBounds.Value;
moel@345: 		}
moel@345: 
moel@345: 		internal Rectangle GetNodeBounds(TreeNodeAdv node)
moel@345: 		{
moel@345: 			return GetNodeBounds(GetNodeControls(node));
moel@345: 		}
moel@345: 
moel@345: 		private Rectangle GetNodeBounds(IEnumerable<NodeControlInfo> nodeControls)
moel@345: 		{
moel@345: 			Rectangle res = Rectangle.Empty;
moel@345: 			foreach (NodeControlInfo info in nodeControls)
moel@345: 			{
moel@345: 				if (res == Rectangle.Empty)
moel@345: 					res = info.Bounds;
moel@345: 				else
moel@345: 					res = Rectangle.Union(res, info.Bounds);
moel@345: 			}
moel@345: 			return res;
moel@345: 		}
moel@345: 
moel@345: 		private void _vScrollBar_ValueChanged(object sender, EventArgs e)
moel@345: 		{
moel@345: 			FirstVisibleRow = _vScrollBar.Value;
moel@345: 		}
moel@345: 
moel@345: 		private void _hScrollBar_ValueChanged(object sender, EventArgs e)
moel@345: 		{
moel@345: 			OffsetX = _hScrollBar.Value;
moel@345: 		}
moel@345: 
moel@345: 		private void _vScrollBar_Scroll(object sender, ScrollEventArgs e)
moel@345: 		{
moel@345: 			OnScroll(e);
moel@345: 		}
moel@345: 
moel@345: 		private void _hScrollBar_Scroll(object sender, ScrollEventArgs e)
moel@345: 		{
moel@345: 			OnScroll(e);
moel@345: 		}
moel@345: 
moel@345: 		internal void SmartFullUpdate()
moel@345: 		{
moel@345: 			if (_suspendUpdate)
moel@345: 				_needFullUpdate = true;
moel@345: 			else
moel@345: 				FullUpdate();
moel@345: 		}
moel@345: 
moel@345: 		internal bool IsMyNode(TreeNodeAdv node)
moel@345: 		{
moel@345: 			if (node == null)
moel@345: 				return false;
moel@345: 
moel@345: 			if (node.Tree != this)
moel@345: 				return false;
moel@345: 
moel@345: 			while (node.Parent != null)
moel@345: 				node = node.Parent;
moel@345: 
moel@345: 			return node == _root;
moel@345: 		}
moel@345: 
moel@345: 		internal void UpdateSelection()
moel@345: 		{
moel@345: 			bool flag = false;
moel@345: 
moel@345: 			if (!IsMyNode(CurrentNode))
moel@345: 				CurrentNode = null;
moel@345: 			if (!IsMyNode(_selectionStart))
moel@345: 				_selectionStart = null;
moel@345: 
moel@345: 			for (int i = Selection.Count - 1; i >= 0; i--)
moel@345: 				if (!IsMyNode(Selection[i]))
moel@345: 				{
moel@345: 					flag = true;
moel@345: 					Selection.RemoveAt(i);
moel@345: 				}
moel@345: 
moel@345: 			if (flag)
moel@345: 				OnSelectionChanged();
moel@345: 		}
moel@345: 
moel@345: 		internal void ChangeColumnWidth(TreeColumn column)
moel@345: 		{
moel@345: 			if (!(_input is ResizeColumnState))
moel@345: 			{
moel@345: 				FullUpdate();
moel@345: 				OnColumnWidthChanged(column);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		public TreeNodeAdv FindNode(TreePath path)
moel@345: 		{
moel@345: 			return FindNode(path, false);
moel@345: 		}
moel@345: 
moel@345: 		public TreeNodeAdv FindNode(TreePath path, bool readChilds)
moel@345: 		{
moel@345: 			if (path.IsEmpty())
moel@345: 				return _root;
moel@345: 			else
moel@345: 				return FindNode(_root, path, 0, readChilds);
moel@345: 		}
moel@345: 
moel@345: 		private TreeNodeAdv FindNode(TreeNodeAdv root, TreePath path, int level, bool readChilds)
moel@345: 		{
moel@345: 			if (!root.IsExpandedOnce && readChilds)
moel@345: 				ReadChilds(root);
moel@345: 
moel@345: 			for (int i = 0; i < root.Nodes.Count; i++)
moel@345: 			{
moel@345: 				TreeNodeAdv node = root.Nodes[i];
moel@345: 				if (node.Tag == 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, readChilds);
moel@345: 				}
moel@345: 			}
moel@345: 			return null;
moel@345: 		}
moel@345: 
moel@345: 		public TreeNodeAdv FindNodeByTag(object tag)
moel@345: 		{
moel@345: 			return FindNodeByTag(_root, tag);
moel@345: 		}
moel@345: 
moel@345: 		private TreeNodeAdv FindNodeByTag(TreeNodeAdv root, object tag)
moel@345: 		{
moel@345: 			foreach (TreeNodeAdv node in root.Nodes)
moel@345: 			{
moel@345: 				if (node.Tag == tag)
moel@345: 					return node;
moel@345: 				TreeNodeAdv res = FindNodeByTag(node, tag);
moel@345: 				if (res != null)
moel@345: 					return res;
moel@345: 			}
moel@345: 			return null;
moel@345: 		}
moel@345: 
moel@345: 		public void SelectAllNodes()
moel@345: 		{
moel@345: 			SuspendSelectionEvent = true;
moel@345: 			try
moel@345: 			{
moel@345: 				if (SelectionMode == TreeSelectionMode.MultiSameParent)
moel@345: 				{
moel@345: 					if (CurrentNode != null)
moel@345: 					{
moel@345: 						foreach (TreeNodeAdv n in CurrentNode.Parent.Nodes)
moel@345: 							n.IsSelected = true;
moel@345: 					}
moel@345: 				}
moel@345: 				else if (SelectionMode == TreeSelectionMode.Multi)
moel@345: 				{
moel@345: 					SelectNodes(Root.Nodes);
moel@345: 				}
moel@345: 			}
moel@345: 			finally
moel@345: 			{
moel@345: 				SuspendSelectionEvent = false;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void SelectNodes(Collection<TreeNodeAdv> nodes)
moel@345: 		{
moel@345: 			foreach (TreeNodeAdv n in nodes)
moel@345: 			{
moel@345: 				n.IsSelected = true;
moel@345: 				if (n.IsExpanded)
moel@345: 					SelectNodes(n.Nodes);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		#region ModelEvents
moel@345: 		private void BindModelEvents()
moel@345: 		{
moel@345: 			_model.NodesChanged += new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
moel@345: 			_model.NodesInserted += new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
moel@345: 			_model.NodesRemoved += new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
moel@345: 			_model.StructureChanged += new EventHandler<TreePathEventArgs>(_model_StructureChanged);
moel@345: 		}
moel@345: 
moel@345: 		private void UnbindModelEvents()
moel@345: 		{
moel@345: 			_model.NodesChanged -= new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
moel@345: 			_model.NodesInserted -= new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
moel@345: 			_model.NodesRemoved -= new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
moel@345: 			_model.StructureChanged -= new EventHandler<TreePathEventArgs>(_model_StructureChanged);
moel@345: 		}
moel@345: 
moel@345: 		private void _model_StructureChanged(object sender, TreePathEventArgs e)
moel@345: 		{
moel@345: 			if (e.Path == null)
moel@345: 				throw new ArgumentNullException();
moel@345: 
moel@345: 			TreeNodeAdv node = FindNode(e.Path);
moel@345: 			if (node != null)
moel@345: 			{
moel@345: 				if (node != Root)
moel@345: 					node.IsLeaf = Model.IsLeaf(GetPath(node));
moel@345: 
moel@345: 				var list = new Dictionary<object, object>();
moel@345: 				SaveExpandedNodes(node, list);
moel@345: 				ReadChilds(node);
moel@345: 				RestoreExpandedNodes(node, list);
moel@345: 
moel@345: 				UpdateSelection();
moel@345: 				SmartFullUpdate();
moel@345: 			}
moel@345: 			//else 
moel@345: 			//	throw new ArgumentException("Path not found");
moel@345: 		}
moel@345: 
moel@345: 		private void RestoreExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
moel@345: 		{
moel@345: 			if (node.Tag != null && list.ContainsKey(node.Tag))
moel@345: 			{
moel@345: 				node.IsExpanded = true;
moel@345: 				foreach (var child in node.Children)
moel@345: 					RestoreExpandedNodes(child, list);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void SaveExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
moel@345: 		{
moel@345: 			if (node.IsExpanded && node.Tag != null)
moel@345: 			{
moel@345: 				list.Add(node.Tag, null);
moel@345: 				foreach (var child in node.Children)
moel@345: 					SaveExpandedNodes(child, list);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void _model_NodesRemoved(object sender, TreeModelEventArgs e)
moel@345: 		{
moel@345: 			TreeNodeAdv parent = FindNode(e.Path);
moel@345: 			if (parent != null)
moel@345: 			{
moel@345: 				if (e.Indices != null)
moel@345: 				{
moel@345: 					List<int> list = new List<int>(e.Indices);
moel@345: 					list.Sort();
moel@345: 					for (int n = list.Count - 1; n >= 0; n--)
moel@345: 					{
moel@345: 						int index = list[n];
moel@345: 						if (index >= 0 && index <= parent.Nodes.Count)
moel@345: 							parent.Nodes.RemoveAt(index);
moel@345: 						else
moel@345: 							throw new ArgumentOutOfRangeException("Index out of range");
moel@345: 					}
moel@345: 				}
moel@345: 				else
moel@345: 				{
moel@345: 					for (int i = parent.Nodes.Count - 1; i >= 0; i--)
moel@345: 					{
moel@345: 						for (int n = 0; n < e.Children.Length; n++)
moel@345: 							if (parent.Nodes[i].Tag == e.Children[n])
moel@345: 							{
moel@345: 								parent.Nodes.RemoveAt(i);
moel@345: 								break;
moel@345: 							}
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 			UpdateSelection();
moel@345: 			SmartFullUpdate();
moel@345: 		}
moel@345: 
moel@345: 		private void _model_NodesInserted(object sender, TreeModelEventArgs e)
moel@345: 		{
moel@345: 			if (e.Indices == null)
moel@345: 				throw new ArgumentNullException("Indices");
moel@345: 
moel@345: 			TreeNodeAdv parent = FindNode(e.Path);
moel@345: 			if (parent != null)
moel@345: 			{
moel@345: 				for (int i = 0; i < e.Children.Length; i++)
moel@345: 					AddNewNode(parent, e.Children[i], e.Indices[i]);
moel@345: 			}
moel@345: 			SmartFullUpdate();
moel@345: 		}
moel@345: 
moel@345: 		private void _model_NodesChanged(object sender, TreeModelEventArgs e)
moel@345: 		{
moel@345: 			TreeNodeAdv parent = FindNode(e.Path);
moel@345: 			if (parent != null && parent.IsVisible && parent.IsExpanded)
moel@345: 			{
moel@345: 				if (InvokeRequired)
moel@345: 					BeginInvoke(new UpdateContentWidthDelegate(ClearNodesSize), e, parent);
moel@345: 				else
moel@345: 					ClearNodesSize(e, parent);
moel@345: 				SmartFullUpdate();
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private delegate void UpdateContentWidthDelegate(TreeModelEventArgs e, TreeNodeAdv parent);
moel@345: 		private void ClearNodesSize(TreeModelEventArgs e, TreeNodeAdv parent)
moel@345: 		{
moel@345: 			if (e.Indices != null)
moel@345: 			{
moel@345: 				foreach (int index in e.Indices)
moel@345: 				{
moel@345: 					if (index >= 0 && index < parent.Nodes.Count)
moel@345: 					{
moel@345: 						TreeNodeAdv node = parent.Nodes[index];
moel@345: 						node.Height = node.RightBounds = null;
moel@345: 					}
moel@345: 					else
moel@345: 						throw new ArgumentOutOfRangeException("Index out of range");
moel@345: 				}
moel@345: 			}
moel@345: 			else
moel@345: 			{
moel@345: 				foreach (TreeNodeAdv node in parent.Nodes)
moel@345: 				{
moel@345: 					foreach (object obj in e.Children)
moel@345: 						if (node.Tag == obj)
moel@345: 						{
moel@345: 							node.Height = node.RightBounds = null;
moel@345: 						}
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 		#endregion
moel@345: 	}
moel@345: }