External/Aga.Controls/Tree/TreeViewAdv.cs
author Stephane Lenclud
Sat, 30 Jan 2016 23:01:51 +0100
branchMiniDisplay
changeset 454 f84878f52cd9
permissions -rw-r--r--
Disabling Nuvoton NCT6791D because of fan full speed bug on Asus Z97 WS.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Collections.ObjectModel;
     4 using System.ComponentModel;
     5 using System.Drawing;
     6 using System.Security.Permissions;
     7 using System.Threading;
     8 using System.Windows.Forms;
     9 using System.Collections;
    10 
    11 using Aga.Controls.Tree.NodeControls;
    12 using Aga.Controls.Threading;
    13 
    14 
    15 namespace Aga.Controls.Tree
    16 {
    17 	/// <summary>
    18 	/// Extensible advanced <see cref="TreeView"/> implemented in 100% managed C# code.
    19 	/// Features: Model/View architecture. Multiple column per node. Ability to select
    20 	/// multiple tree nodes. Different types of controls for each node column: 
    21 	/// <see cref="CheckBox"/>, Icon, Label... Drag and Drop highlighting. Load on
    22 	/// demand of nodes. Incremental search of nodes.
    23 	/// </summary>
    24 	public partial class TreeViewAdv : Control
    25 	{
    26 		private const int LeftMargin = 7;
    27 		internal const int ItemDragSensivity = 4;
    28 		private readonly int _columnHeaderHeight;
    29 		private const int DividerWidth = 9;
    30 		private const int DividerCorrectionGap = -2;
    31 
    32 		private Pen _linePen;
    33 		private Pen _markPen;
    34 		private bool _suspendUpdate;
    35 		private bool _needFullUpdate;
    36 		private bool _fireSelectionEvent;
    37 		private NodePlusMinus _plusMinus;
    38 		private ToolTip _toolTip;
    39 		private DrawContext _measureContext;
    40 		private TreeColumn _hotColumn;
    41 		private IncrementalSearch _search;
    42 		private List<TreeNodeAdv> _expandingNodes = new List<TreeNodeAdv>();
    43 		private AbortableThreadPool _threadPool = new AbortableThreadPool();
    44 
    45 		#region Public Events
    46 
    47 		[Category("Action")]
    48 		public event ItemDragEventHandler ItemDrag;
    49 		private void OnItemDrag(MouseButtons buttons, object item)
    50 		{
    51 			if (ItemDrag != null)
    52 				ItemDrag(this, new ItemDragEventArgs(buttons, item));
    53 		}
    54 
    55 		[Category("Behavior")]
    56 		public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseClick;
    57 		private void OnNodeMouseClick(TreeNodeAdvMouseEventArgs args)
    58 		{
    59 			if (NodeMouseClick != null)
    60 				NodeMouseClick(this, args);
    61 		}
    62 
    63 		[Category("Behavior")]
    64 		public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseDoubleClick;
    65 		private void OnNodeMouseDoubleClick(TreeNodeAdvMouseEventArgs args)
    66 		{
    67 			if (NodeMouseDoubleClick != null)
    68 				NodeMouseDoubleClick(this, args);
    69 		}
    70 
    71 		[Category("Behavior")]
    72 		public event EventHandler<TreeColumnEventArgs> ColumnWidthChanged;
    73 		internal void OnColumnWidthChanged(TreeColumn column)
    74 		{
    75 			if (ColumnWidthChanged != null)
    76 				ColumnWidthChanged(this, new TreeColumnEventArgs(column));
    77 		}
    78 
    79 		[Category("Behavior")]
    80 		public event EventHandler<TreeColumnEventArgs> ColumnReordered;
    81 		internal void OnColumnReordered(TreeColumn column)
    82 		{
    83 			if (ColumnReordered != null)
    84 				ColumnReordered(this, new TreeColumnEventArgs(column));
    85 		}
    86 
    87 		[Category("Behavior")]
    88 		public event EventHandler<TreeColumnEventArgs> ColumnClicked;
    89 		internal void OnColumnClicked(TreeColumn column)
    90 		{
    91 			if (ColumnClicked != null)
    92 				ColumnClicked(this, new TreeColumnEventArgs(column));
    93 		}
    94 
    95 		[Category("Behavior")]
    96 		public event EventHandler SelectionChanged;
    97 		internal void OnSelectionChanged()
    98 		{
    99 			if (SuspendSelectionEvent)
   100 				_fireSelectionEvent = true;
   101 			else
   102 			{
   103 				_fireSelectionEvent = false;
   104 				if (SelectionChanged != null)
   105 					SelectionChanged(this, EventArgs.Empty);
   106 			}
   107 		}
   108 
   109 		[Category("Behavior")]
   110 		public event EventHandler<TreeViewAdvEventArgs> Collapsing;
   111 		private void OnCollapsing(TreeNodeAdv node)
   112 		{
   113 			if (Collapsing != null)
   114 				Collapsing(this, new TreeViewAdvEventArgs(node));
   115 		}
   116 
   117 		[Category("Behavior")]
   118 		public event EventHandler<TreeViewAdvEventArgs> Collapsed;
   119 		private void OnCollapsed(TreeNodeAdv node)
   120 		{
   121 			if (Collapsed != null)
   122 				Collapsed(this, new TreeViewAdvEventArgs(node));
   123 		}
   124 
   125 		[Category("Behavior")]
   126 		public event EventHandler<TreeViewAdvEventArgs> Expanding;
   127 		private void OnExpanding(TreeNodeAdv node)
   128 		{
   129 			if (Expanding != null)
   130 				Expanding(this, new TreeViewAdvEventArgs(node));
   131 		}
   132 
   133 		[Category("Behavior")]
   134 		public event EventHandler<TreeViewAdvEventArgs> Expanded;
   135 		private void OnExpanded(TreeNodeAdv node)
   136 		{
   137 			if (Expanded != null)
   138 				Expanded(this, new TreeViewAdvEventArgs(node));
   139 		}
   140 
   141 		[Category("Behavior")]
   142 		public event EventHandler GridLineStyleChanged;
   143 		private void OnGridLineStyleChanged()
   144 		{
   145 			if (GridLineStyleChanged != null)
   146 				GridLineStyleChanged(this, EventArgs.Empty);
   147 		}
   148 
   149 		[Category("Behavior")]
   150 		public event ScrollEventHandler Scroll;
   151 		protected virtual void OnScroll(ScrollEventArgs e)
   152 		{
   153 			if (Scroll != null)
   154 				Scroll(this, e);
   155 		}
   156 
   157 		[Category("Behavior")]
   158 		public event EventHandler<TreeViewRowDrawEventArgs> RowDraw;
   159 		protected virtual void OnRowDraw(PaintEventArgs e, TreeNodeAdv node, DrawContext context, int row, Rectangle rowRect)
   160 		{
   161 			if (RowDraw != null)
   162 			{
   163 				TreeViewRowDrawEventArgs args = new TreeViewRowDrawEventArgs(e.Graphics, e.ClipRectangle, node, context, row, rowRect);
   164 				RowDraw(this, args);
   165 			}
   166 		}
   167 
   168 		/// <summary>
   169 		/// Fires when control is going to draw. Can be used to change text or back color
   170 		/// </summary>
   171 		[Category("Behavior")]
   172 		public event EventHandler<DrawEventArgs> DrawControl;
   173 
   174 		internal bool DrawControlMustBeFired()
   175 		{
   176 			return DrawControl != null;
   177 		}
   178 
   179 		internal void FireDrawControl(DrawEventArgs args)
   180 		{
   181 			OnDrawControl(args);
   182 		}
   183 
   184 		protected virtual void OnDrawControl(DrawEventArgs args)
   185 		{
   186 			if (DrawControl != null)
   187 				DrawControl(this, args);
   188 		}
   189 
   190 
   191 		[Category("Drag Drop")]
   192 		public event EventHandler<DropNodeValidatingEventArgs> DropNodeValidating;
   193 		protected virtual void OnDropNodeValidating(Point point, ref TreeNodeAdv node)
   194 		{
   195 			if (DropNodeValidating != null)
   196 			{
   197 				DropNodeValidatingEventArgs args = new DropNodeValidatingEventArgs(point, node);
   198 				DropNodeValidating(this, args);
   199 				node = args.Node;
   200 			}
   201 		}
   202 		#endregion
   203 
   204 		public TreeViewAdv()
   205 		{
   206 			InitializeComponent();
   207 			SetStyle(ControlStyles.AllPaintingInWmPaint
   208 				| ControlStyles.UserPaint
   209 				| ControlStyles.OptimizedDoubleBuffer
   210 				| ControlStyles.ResizeRedraw
   211 				| ControlStyles.Selectable
   212 				, true);
   213 
   214 
   215 			if (Application.RenderWithVisualStyles)
   216 				_columnHeaderHeight = 20;
   217 			else
   218 				_columnHeaderHeight = 17;
   219 
   220 			//BorderStyle = BorderStyle.Fixed3D;
   221 			_hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight;
   222 			_vScrollBar.Width = SystemInformation.VerticalScrollBarWidth;
   223 			_rowLayout = new FixedRowHeightLayout(this, RowHeight);
   224 			_rowMap = new List<TreeNodeAdv>();
   225 			_selection = new List<TreeNodeAdv>();
   226 			_readonlySelection = new ReadOnlyCollection<TreeNodeAdv>(_selection);
   227 			_columns = new TreeColumnCollection(this);
   228 			_toolTip = new ToolTip();
   229 
   230 			_measureContext = new DrawContext();
   231 			_measureContext.Font = Font;
   232 			_measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1));
   233 
   234 			Input = new NormalInputState(this);
   235 			_search = new IncrementalSearch(this);
   236 			CreateNodes();
   237 			CreatePens();
   238 
   239 			ArrangeControls();
   240 
   241 			_plusMinus = new NodePlusMinus();
   242 			_controls = new NodeControlsCollection(this);
   243 
   244 			Font = _font;
   245 			ExpandingIcon.IconChanged += ExpandingIconChanged;
   246 		}
   247 
   248 		void ExpandingIconChanged(object sender, EventArgs e)
   249 		{
   250 			if (IsHandleCreated && !IsDisposed)
   251 				BeginInvoke(new MethodInvoker(DrawIcons));
   252 		}
   253 
   254 		private void DrawIcons()
   255 		{
   256 			using (Graphics gr = Graphics.FromHwnd(this.Handle))
   257 			{
   258 				//Apply the same Graphics Transform logic as used in OnPaint.
   259 				int y = 0;
   260 				if (UseColumns)
   261 				{
   262 					y += ColumnHeaderHeight;
   263 					if (Columns.Count == 0)
   264 						return;
   265 				}
   266 				int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y;
   267 				y -= firstRowY;
   268 				gr.ResetTransform();
   269 				gr.TranslateTransform(-OffsetX, y);
   270 
   271 				DrawContext context = new DrawContext();
   272 				context.Graphics = gr;
   273 				for (int i = 0; i < _expandingNodes.Count; i++)
   274 				{
   275 					foreach (NodeControlInfo item in GetNodeControls(_expandingNodes[i]))
   276 					{
   277 						if (item.Control is ExpandingIcon)
   278 						{
   279 							Rectangle bounds = item.Bounds;
   280 							if (item.Node.Parent == null && UseColumns)
   281 								bounds.Location = Point.Empty; // display root expanding icon at 0,0
   282 
   283 							context.Bounds = bounds;
   284 							item.Control.Draw(item.Node, context);
   285 						}
   286 					}
   287 				}
   288 			}
   289 		}
   290 
   291 		#region Public Methods
   292 
   293 		public TreePath GetPath(TreeNodeAdv node)
   294 		{
   295 			if (node == _root)
   296 				return TreePath.Empty;
   297 			else
   298 			{
   299 				Stack<object> stack = new Stack<object>();
   300 				while (node != _root && node != null)
   301 				{
   302 					stack.Push(node.Tag);
   303 					node = node.Parent;
   304 				}
   305 				return new TreePath(stack.ToArray());
   306 			}
   307 		}
   308 
   309 		public TreeNodeAdv GetNodeAt(Point point)
   310 		{
   311 			NodeControlInfo info = GetNodeControlInfoAt(point);
   312 			return info.Node;
   313 		}
   314 
   315 		public NodeControlInfo GetNodeControlInfoAt(Point point)
   316 		{
   317 			if (point.X < 0 || point.Y < 0)
   318 				return NodeControlInfo.Empty;
   319 
   320 			int row = _rowLayout.GetRowAt(point);
   321 			if (row < RowCount && row >= 0)
   322 				return GetNodeControlInfoAt(RowMap[row], point);
   323 			else
   324 				return NodeControlInfo.Empty;
   325 		}
   326 
   327 		private NodeControlInfo GetNodeControlInfoAt(TreeNodeAdv node, Point point)
   328 		{
   329 			Rectangle rect = _rowLayout.GetRowBounds(FirstVisibleRow);
   330 			point.Y += (rect.Y - ColumnHeaderHeight);
   331 			point.X += OffsetX;
   332 			foreach (NodeControlInfo info in GetNodeControls(node))
   333 				if (info.Bounds.Contains(point))
   334 					return info;
   335 
   336 			if (FullRowSelect)
   337 				return new NodeControlInfo(null, Rectangle.Empty, node);
   338 			else
   339 				return NodeControlInfo.Empty;
   340 		}
   341 
   342 		public void BeginUpdate()
   343 		{
   344 			_suspendUpdate = true;
   345 			SuspendSelectionEvent = true;
   346 		}
   347 
   348 		public void EndUpdate()
   349 		{
   350 			_suspendUpdate = false;
   351 			if (_needFullUpdate)
   352 				FullUpdate();
   353 			else
   354 				UpdateView();
   355 			SuspendSelectionEvent = false;
   356 		}
   357 
   358 		public void ExpandAll()
   359 		{
   360 			_root.ExpandAll();
   361 		}
   362 
   363 		public void CollapseAll()
   364 		{
   365 			_root.CollapseAll();
   366 		}
   367 
   368 		/// <summary>
   369 		/// Expand all parent nodes, andd scroll to the specified node
   370 		/// </summary>
   371 		public void EnsureVisible(TreeNodeAdv node)
   372 		{
   373 			if (node == null)
   374 				throw new ArgumentNullException("node");
   375 
   376 			if (!IsMyNode(node))
   377 				throw new ArgumentException();
   378 
   379 			TreeNodeAdv parent = node.Parent;
   380 			while (parent != _root)
   381 			{
   382 				parent.IsExpanded = true;
   383 				parent = parent.Parent;
   384 			}
   385 			ScrollTo(node);
   386 		}
   387 
   388 		/// <summary>
   389 		/// Make node visible, scroll if needed. All parent nodes of the specified node must be expanded
   390 		/// </summary>
   391 		/// <param name="node"></param>
   392 		public void ScrollTo(TreeNodeAdv node)
   393 		{
   394 			if (node == null)
   395 				throw new ArgumentNullException("node");
   396 
   397 			if (!IsMyNode(node))
   398 				throw new ArgumentException();
   399 
   400 			if (node.Row < 0)
   401 				CreateRowMap();
   402 
   403 			int row = -1;
   404 
   405 			if (node.Row < FirstVisibleRow)
   406 				row = node.Row;
   407 			else
   408 			{
   409 				int pageStart = _rowLayout.GetRowBounds(FirstVisibleRow).Top;
   410 				int rowBottom = _rowLayout.GetRowBounds(node.Row).Bottom;
   411 				if (rowBottom > pageStart + DisplayRectangle.Height - ColumnHeaderHeight)
   412 					row = _rowLayout.GetFirstRow(node.Row);
   413 			}
   414 
   415 			if (row >= _vScrollBar.Minimum && row <= _vScrollBar.Maximum)
   416 				_vScrollBar.Value = row;
   417 		}
   418 
   419 		public void ClearSelection()
   420 		{
   421 			BeginUpdate();
   422 			try
   423 			{
   424 				ClearSelectionInternal();
   425 			}
   426 			finally
   427 			{
   428 				EndUpdate();
   429 			}
   430 		}
   431 
   432 		internal void ClearSelectionInternal()
   433 		{
   434 			while (Selection.Count > 0)
   435 			{
   436 				var t = Selection[0];
   437 				t.IsSelected = false;
   438 				Selection.Remove(t); //hack
   439 			}
   440 		}
   441 
   442 		#endregion
   443 
   444 		protected override void OnSizeChanged(EventArgs e)
   445 		{
   446 			ArrangeControls();
   447 			SafeUpdateScrollBars();
   448 			base.OnSizeChanged(e);
   449 		}
   450 
   451 		private void ArrangeControls()
   452 		{
   453 			int hBarSize = _hScrollBar.Height;
   454 			int vBarSize = _vScrollBar.Width;
   455 			Rectangle clientRect = ClientRectangle;
   456 
   457 			_hScrollBar.SetBounds(clientRect.X, clientRect.Bottom - hBarSize,
   458 				clientRect.Width - vBarSize, hBarSize);
   459 
   460 			_vScrollBar.SetBounds(clientRect.Right - vBarSize, clientRect.Y,
   461 				vBarSize, clientRect.Height - hBarSize);
   462 		}
   463 
   464 		private void SafeUpdateScrollBars()
   465 		{
   466 			if (InvokeRequired)
   467 				BeginInvoke(new MethodInvoker(UpdateScrollBars));
   468 			else
   469 				UpdateScrollBars();
   470 		}
   471 
   472 		private void UpdateScrollBars()
   473 		{
   474 			UpdateVScrollBar();
   475 			UpdateHScrollBar();
   476 			UpdateVScrollBar();
   477 			UpdateHScrollBar();
   478 			_hScrollBar.Width = DisplayRectangle.Width;
   479 			_vScrollBar.Height = DisplayRectangle.Height;
   480 		}
   481 
   482 		private void UpdateHScrollBar()
   483 		{
   484 			_hScrollBar.Maximum = ContentWidth;
   485 			_hScrollBar.LargeChange = Math.Max(DisplayRectangle.Width, 0);
   486 			_hScrollBar.SmallChange = 5;
   487 			_hScrollBar.Visible = _hScrollBar.LargeChange < _hScrollBar.Maximum;
   488 			_hScrollBar.Value = Math.Min(_hScrollBar.Value, _hScrollBar.Maximum - _hScrollBar.LargeChange + 1);
   489 		}
   490 
   491 		private void UpdateVScrollBar()
   492 		{
   493 			_vScrollBar.Maximum = Math.Max(RowCount - 1, 0);
   494 			_vScrollBar.LargeChange = _rowLayout.PageRowCount;
   495 			_vScrollBar.Visible = (RowCount > 0) && (_vScrollBar.LargeChange <= _vScrollBar.Maximum);
   496 			_vScrollBar.Value = Math.Min(_vScrollBar.Value, _vScrollBar.Maximum - _vScrollBar.LargeChange + 1);
   497 		}
   498 
   499 		protected override CreateParams CreateParams
   500 		{
   501 			[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
   502 			get
   503 			{
   504 				CreateParams res = base.CreateParams;
   505 				switch (BorderStyle)
   506 				{
   507 					case BorderStyle.FixedSingle:
   508 						res.Style |= 0x800000;
   509 						break;
   510 					case BorderStyle.Fixed3D:
   511 						res.ExStyle |= 0x200;
   512 						break;
   513 				}
   514 				return res;
   515 			}
   516 		}
   517 
   518 		protected override void OnGotFocus(EventArgs e)
   519 		{
   520 			UpdateView();
   521 			ChangeInput();
   522 			base.OnGotFocus(e);
   523 		}
   524 
   525 		protected override void OnFontChanged(EventArgs e)
   526 		{
   527 			base.OnFontChanged(e);
   528 			_measureContext.Font = Font;
   529 			FullUpdate();
   530 		}
   531 
   532 		internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node)
   533 		{
   534 			if (node == null)
   535 				yield break;
   536 			Rectangle rowRect = _rowLayout.GetRowBounds(node.Row);
   537 			foreach (NodeControlInfo n in GetNodeControls(node, rowRect))
   538 				yield return n;
   539 		}
   540 
   541 		internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node, Rectangle rowRect)
   542 		{
   543 			if (node == null)
   544 				yield break;
   545 
   546 			int y = rowRect.Y;
   547 			int x = (node.Level - 1) * _indent + LeftMargin;
   548 			int width = 0;
   549 			if (node.Row == 0 && ShiftFirstNode)
   550 				x -= _indent;
   551 			Rectangle rect = Rectangle.Empty;
   552 
   553 			if (ShowPlusMinus)
   554 			{
   555 				width = _plusMinus.GetActualSize(node, _measureContext).Width;
   556 				rect = new Rectangle(x, y, width, rowRect.Height);
   557 				if (UseColumns && Columns.Count > 0 && Columns[0].Width < rect.Right)
   558 					rect.Width = Columns[0].Width - x;
   559 
   560 				yield return new NodeControlInfo(_plusMinus, rect, node);
   561 				x += width;
   562 			}
   563 
   564 			if (!UseColumns)
   565 			{
   566 				foreach (NodeControl c in NodeControls)
   567 				{
   568 					Size s = c.GetActualSize(node, _measureContext);
   569 					if (!s.IsEmpty)
   570 					{
   571 						width = s.Width;
   572 						rect = new Rectangle(x, y, width, rowRect.Height);
   573 						x += rect.Width;
   574 						yield return new NodeControlInfo(c, rect, node);
   575 					}
   576 				}
   577 			}
   578 			else
   579 			{
   580 				int right = 0;
   581 				foreach (TreeColumn col in Columns)
   582 				{
   583 					if (col.IsVisible && col.Width > 0)
   584 					{
   585 						right += col.Width;
   586 						for (int i = 0; i < NodeControls.Count; i++)
   587 						{
   588 							NodeControl nc = NodeControls[i];
   589 							if (nc.ParentColumn == col)
   590 							{
   591 								Size s = nc.GetActualSize(node, _measureContext);
   592 								if (!s.IsEmpty)
   593 								{
   594 									bool isLastControl = true;
   595 									for (int k = i + 1; k < NodeControls.Count; k++)
   596 										if (NodeControls[k].ParentColumn == col)
   597 										{
   598 											isLastControl = false;
   599 											break;
   600 										}
   601 
   602 									width = right - x;
   603 									if (!isLastControl)
   604 										width = s.Width;
   605 									int maxWidth = Math.Max(0, right - x);
   606 									rect = new Rectangle(x, y, Math.Min(maxWidth, width), rowRect.Height);
   607 									x += width;
   608 									yield return new NodeControlInfo(nc, rect, node);
   609 								}
   610 							}
   611 						}
   612 						x = right;
   613 					}
   614 				}
   615 			}
   616 		}
   617 
   618 		internal static double Dist(Point p1, Point p2)
   619 		{
   620 			return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
   621 		}
   622 
   623 		public void FullUpdate()
   624 		{
   625 			HideEditor();
   626 			if (InvokeRequired)
   627 				BeginInvoke(new MethodInvoker(UnsafeFullUpdate));
   628 			else
   629 				UnsafeFullUpdate();
   630 		}
   631 
   632 		private void UnsafeFullUpdate()
   633 		{
   634 			_rowLayout.ClearCache();
   635 			CreateRowMap();
   636 			SafeUpdateScrollBars();
   637 			UpdateView();
   638 			_needFullUpdate = false;
   639 		}
   640 
   641 		internal void UpdateView()
   642 		{
   643 			if (!_suspendUpdate)
   644 				Invalidate(false);
   645 		}
   646 
   647 		internal void UpdateHeaders()
   648 		{
   649 			Invalidate(new Rectangle(0, 0, Width, ColumnHeaderHeight));
   650 		}
   651 
   652 		internal void UpdateColumns()
   653 		{
   654 			FullUpdate();
   655 		}
   656 
   657 		private void CreateNodes()
   658 		{
   659 			Selection.Clear();
   660 			SelectionStart = null;
   661 			_root = new TreeNodeAdv(this, null);
   662 			_root.IsExpanded = true;
   663 			if (_root.Nodes.Count > 0)
   664 				CurrentNode = _root.Nodes[0];
   665 			else
   666 				CurrentNode = null;
   667 		}
   668 
   669 		internal void ReadChilds(TreeNodeAdv parentNode)
   670 		{
   671 			ReadChilds(parentNode, false);
   672 		}
   673 
   674 		internal void ReadChilds(TreeNodeAdv parentNode, bool performFullUpdate)
   675 		{
   676 			if (!parentNode.IsLeaf)
   677 			{
   678 				parentNode.IsExpandedOnce = true;
   679 				parentNode.Nodes.Clear();
   680 
   681 				if (Model != null)
   682 				{
   683 					IEnumerable items = Model.GetChildren(GetPath(parentNode));
   684 					if (items != null)
   685 						foreach (object obj in items)
   686 						{
   687 							AddNewNode(parentNode, obj, -1);
   688 							if (performFullUpdate)
   689 								FullUpdate();
   690 						}
   691 				}
   692 
   693 				if (parentNode.AutoExpandOnStructureChanged)
   694 					parentNode.ExpandAll();
   695 			}
   696 		}
   697 
   698 		private void AddNewNode(TreeNodeAdv parent, object tag, int index)
   699 		{
   700 			TreeNodeAdv node = new TreeNodeAdv(this, tag);
   701 			AddNode(parent, index, node);
   702 		}
   703 
   704 		private void AddNode(TreeNodeAdv parent, int index, TreeNodeAdv node)
   705 		{
   706 			if (index >= 0 && index < parent.Nodes.Count)
   707 				parent.Nodes.Insert(index, node);
   708 			else
   709 				parent.Nodes.Add(node);
   710 
   711 			node.IsLeaf = Model.IsLeaf(GetPath(node));
   712 			if (node.IsLeaf)
   713 				node.Nodes.Clear();
   714 			if (!LoadOnDemand || node.IsExpandedOnce)
   715 				ReadChilds(node);
   716 		}
   717 
   718 		private struct ExpandArgs
   719 		{
   720 			public TreeNodeAdv Node;
   721 			public bool Value;
   722 			public bool IgnoreChildren;
   723 		}
   724 
   725 		public void AbortBackgroundExpandingThreads()
   726 		{
   727 			_threadPool.CancelAll(true);
   728 			for (int i = 0; i < _expandingNodes.Count; i++)
   729 				_expandingNodes[i].IsExpandingNow = false;
   730 			_expandingNodes.Clear();
   731 			Invalidate();
   732 		}
   733 
   734 		internal void SetIsExpanded(TreeNodeAdv node, bool value, bool ignoreChildren)
   735 		{
   736 			ExpandArgs eargs = new ExpandArgs();
   737 			eargs.Node = node;
   738 			eargs.Value = value;
   739 			eargs.IgnoreChildren = ignoreChildren;
   740 
   741 			if (AsyncExpanding && LoadOnDemand && !_threadPool.IsMyThread(Thread.CurrentThread))
   742 			{
   743 				WaitCallback wc = delegate(object argument) { SetIsExpanded((ExpandArgs)argument); };
   744 				_threadPool.QueueUserWorkItem(wc, eargs);
   745 			}
   746 			else
   747 				SetIsExpanded(eargs);
   748 		}
   749 
   750 		private void SetIsExpanded(ExpandArgs eargs)
   751 		{
   752 			bool update = !eargs.IgnoreChildren && !AsyncExpanding;
   753 			if (update)
   754 				BeginUpdate();
   755 			try
   756 			{
   757 				if (IsMyNode(eargs.Node) && eargs.Node.IsExpanded != eargs.Value)
   758 					SetIsExpanded(eargs.Node, eargs.Value);
   759 
   760 				if (!eargs.IgnoreChildren)
   761 					SetIsExpandedRecursive(eargs.Node, eargs.Value);
   762 			}
   763 			finally
   764 			{
   765 				if (update)
   766 					EndUpdate();
   767 			}
   768 		}
   769 
   770 		internal void SetIsExpanded(TreeNodeAdv node, bool value)
   771 		{
   772 			if (Root == node && !value)
   773 				return; //Can't collapse root node
   774 
   775 			if (value)
   776 			{
   777 				OnExpanding(node);
   778 				node.OnExpanding();
   779 			}
   780 			else
   781 			{
   782 				OnCollapsing(node);
   783 				node.OnCollapsing();
   784 			}
   785 
   786 			if (value && !node.IsExpandedOnce)
   787 			{
   788 				if (AsyncExpanding && LoadOnDemand)
   789 				{
   790 					AddExpandingNode(node);
   791 					node.AssignIsExpanded(true);
   792 					Invalidate();
   793 				}
   794 				ReadChilds(node, AsyncExpanding);
   795 				RemoveExpandingNode(node);
   796 			}
   797 			node.AssignIsExpanded(value);
   798 			SmartFullUpdate();
   799 
   800 			if (value)
   801 			{
   802 				OnExpanded(node);
   803 				node.OnExpanded();
   804 			}
   805 			else
   806 			{
   807 				OnCollapsed(node);
   808 				node.OnCollapsed();
   809 			}
   810 		}
   811 
   812 		private void RemoveExpandingNode(TreeNodeAdv node)
   813 		{
   814 			node.IsExpandingNow = false;
   815 			_expandingNodes.Remove(node);
   816 			if (_expandingNodes.Count <= 0)
   817 				ExpandingIcon.Stop();
   818 		}
   819 
   820 		private void AddExpandingNode(TreeNodeAdv node)
   821 		{
   822 			node.IsExpandingNow = true;
   823 			_expandingNodes.Add(node);
   824 			ExpandingIcon.Start();
   825 		}
   826 
   827 		internal void SetIsExpandedRecursive(TreeNodeAdv root, bool value)
   828 		{
   829 			for (int i = 0; i < root.Nodes.Count; i++)
   830 			{
   831 				TreeNodeAdv node = root.Nodes[i];
   832 				node.IsExpanded = value;
   833 				SetIsExpandedRecursive(node, value);
   834 			}
   835 		}
   836 
   837 		private void CreateRowMap()
   838 		{
   839 			RowMap.Clear();
   840 			int row = 0;
   841 			_contentWidth = 0;
   842 			foreach (TreeNodeAdv node in VisibleNodes)
   843 			{
   844 				node.Row = row;
   845 				RowMap.Add(node);
   846 				if (!UseColumns)
   847 				{
   848 					_contentWidth = Math.Max(_contentWidth, GetNodeWidth(node));
   849 				}
   850 				row++;
   851 			}
   852 			if (UseColumns)
   853 			{
   854 				_contentWidth = 0;
   855 				foreach (TreeColumn col in _columns)
   856 					if (col.IsVisible)
   857 						_contentWidth += col.Width;
   858 			}
   859 		}
   860 
   861 		private int GetNodeWidth(TreeNodeAdv node)
   862 		{
   863 			if (node.RightBounds == null)
   864 			{
   865 				Rectangle res = GetNodeBounds(GetNodeControls(node, Rectangle.Empty));
   866 				node.RightBounds = res.Right;
   867 			}
   868 			return node.RightBounds.Value;
   869 		}
   870 
   871 		internal Rectangle GetNodeBounds(TreeNodeAdv node)
   872 		{
   873 			return GetNodeBounds(GetNodeControls(node));
   874 		}
   875 
   876 		private Rectangle GetNodeBounds(IEnumerable<NodeControlInfo> nodeControls)
   877 		{
   878 			Rectangle res = Rectangle.Empty;
   879 			foreach (NodeControlInfo info in nodeControls)
   880 			{
   881 				if (res == Rectangle.Empty)
   882 					res = info.Bounds;
   883 				else
   884 					res = Rectangle.Union(res, info.Bounds);
   885 			}
   886 			return res;
   887 		}
   888 
   889 		private void _vScrollBar_ValueChanged(object sender, EventArgs e)
   890 		{
   891 			FirstVisibleRow = _vScrollBar.Value;
   892 		}
   893 
   894 		private void _hScrollBar_ValueChanged(object sender, EventArgs e)
   895 		{
   896 			OffsetX = _hScrollBar.Value;
   897 		}
   898 
   899 		private void _vScrollBar_Scroll(object sender, ScrollEventArgs e)
   900 		{
   901 			OnScroll(e);
   902 		}
   903 
   904 		private void _hScrollBar_Scroll(object sender, ScrollEventArgs e)
   905 		{
   906 			OnScroll(e);
   907 		}
   908 
   909 		internal void SmartFullUpdate()
   910 		{
   911 			if (_suspendUpdate)
   912 				_needFullUpdate = true;
   913 			else
   914 				FullUpdate();
   915 		}
   916 
   917 		internal bool IsMyNode(TreeNodeAdv node)
   918 		{
   919 			if (node == null)
   920 				return false;
   921 
   922 			if (node.Tree != this)
   923 				return false;
   924 
   925 			while (node.Parent != null)
   926 				node = node.Parent;
   927 
   928 			return node == _root;
   929 		}
   930 
   931 		internal void UpdateSelection()
   932 		{
   933 			bool flag = false;
   934 
   935 			if (!IsMyNode(CurrentNode))
   936 				CurrentNode = null;
   937 			if (!IsMyNode(_selectionStart))
   938 				_selectionStart = null;
   939 
   940 			for (int i = Selection.Count - 1; i >= 0; i--)
   941 				if (!IsMyNode(Selection[i]))
   942 				{
   943 					flag = true;
   944 					Selection.RemoveAt(i);
   945 				}
   946 
   947 			if (flag)
   948 				OnSelectionChanged();
   949 		}
   950 
   951 		internal void ChangeColumnWidth(TreeColumn column)
   952 		{
   953 			if (!(_input is ResizeColumnState))
   954 			{
   955 				FullUpdate();
   956 				OnColumnWidthChanged(column);
   957 			}
   958 		}
   959 
   960 		public TreeNodeAdv FindNode(TreePath path)
   961 		{
   962 			return FindNode(path, false);
   963 		}
   964 
   965 		public TreeNodeAdv FindNode(TreePath path, bool readChilds)
   966 		{
   967 			if (path.IsEmpty())
   968 				return _root;
   969 			else
   970 				return FindNode(_root, path, 0, readChilds);
   971 		}
   972 
   973 		private TreeNodeAdv FindNode(TreeNodeAdv root, TreePath path, int level, bool readChilds)
   974 		{
   975 			if (!root.IsExpandedOnce && readChilds)
   976 				ReadChilds(root);
   977 
   978 			for (int i = 0; i < root.Nodes.Count; i++)
   979 			{
   980 				TreeNodeAdv node = root.Nodes[i];
   981 				if (node.Tag == path.FullPath[level])
   982 				{
   983 					if (level == path.FullPath.Length - 1)
   984 						return node;
   985 					else
   986 						return FindNode(node, path, level + 1, readChilds);
   987 				}
   988 			}
   989 			return null;
   990 		}
   991 
   992 		public TreeNodeAdv FindNodeByTag(object tag)
   993 		{
   994 			return FindNodeByTag(_root, tag);
   995 		}
   996 
   997 		private TreeNodeAdv FindNodeByTag(TreeNodeAdv root, object tag)
   998 		{
   999 			foreach (TreeNodeAdv node in root.Nodes)
  1000 			{
  1001 				if (node.Tag == tag)
  1002 					return node;
  1003 				TreeNodeAdv res = FindNodeByTag(node, tag);
  1004 				if (res != null)
  1005 					return res;
  1006 			}
  1007 			return null;
  1008 		}
  1009 
  1010 		public void SelectAllNodes()
  1011 		{
  1012 			SuspendSelectionEvent = true;
  1013 			try
  1014 			{
  1015 				if (SelectionMode == TreeSelectionMode.MultiSameParent)
  1016 				{
  1017 					if (CurrentNode != null)
  1018 					{
  1019 						foreach (TreeNodeAdv n in CurrentNode.Parent.Nodes)
  1020 							n.IsSelected = true;
  1021 					}
  1022 				}
  1023 				else if (SelectionMode == TreeSelectionMode.Multi)
  1024 				{
  1025 					SelectNodes(Root.Nodes);
  1026 				}
  1027 			}
  1028 			finally
  1029 			{
  1030 				SuspendSelectionEvent = false;
  1031 			}
  1032 		}
  1033 
  1034 		private void SelectNodes(Collection<TreeNodeAdv> nodes)
  1035 		{
  1036 			foreach (TreeNodeAdv n in nodes)
  1037 			{
  1038 				n.IsSelected = true;
  1039 				if (n.IsExpanded)
  1040 					SelectNodes(n.Nodes);
  1041 			}
  1042 		}
  1043 
  1044 		#region ModelEvents
  1045 		private void BindModelEvents()
  1046 		{
  1047 			_model.NodesChanged += new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
  1048 			_model.NodesInserted += new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
  1049 			_model.NodesRemoved += new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
  1050 			_model.StructureChanged += new EventHandler<TreePathEventArgs>(_model_StructureChanged);
  1051 		}
  1052 
  1053 		private void UnbindModelEvents()
  1054 		{
  1055 			_model.NodesChanged -= new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
  1056 			_model.NodesInserted -= new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
  1057 			_model.NodesRemoved -= new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
  1058 			_model.StructureChanged -= new EventHandler<TreePathEventArgs>(_model_StructureChanged);
  1059 		}
  1060 
  1061 		private void _model_StructureChanged(object sender, TreePathEventArgs e)
  1062 		{
  1063 			if (e.Path == null)
  1064 				throw new ArgumentNullException();
  1065 
  1066 			TreeNodeAdv node = FindNode(e.Path);
  1067 			if (node != null)
  1068 			{
  1069 				if (node != Root)
  1070 					node.IsLeaf = Model.IsLeaf(GetPath(node));
  1071 
  1072 				var list = new Dictionary<object, object>();
  1073 				SaveExpandedNodes(node, list);
  1074 				ReadChilds(node);
  1075 				RestoreExpandedNodes(node, list);
  1076 
  1077 				UpdateSelection();
  1078 				SmartFullUpdate();
  1079 			}
  1080 			//else 
  1081 			//	throw new ArgumentException("Path not found");
  1082 		}
  1083 
  1084 		private void RestoreExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
  1085 		{
  1086 			if (node.Tag != null && list.ContainsKey(node.Tag))
  1087 			{
  1088 				node.IsExpanded = true;
  1089 				foreach (var child in node.Children)
  1090 					RestoreExpandedNodes(child, list);
  1091 			}
  1092 		}
  1093 
  1094 		private void SaveExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
  1095 		{
  1096 			if (node.IsExpanded && node.Tag != null)
  1097 			{
  1098 				list.Add(node.Tag, null);
  1099 				foreach (var child in node.Children)
  1100 					SaveExpandedNodes(child, list);
  1101 			}
  1102 		}
  1103 
  1104 		private void _model_NodesRemoved(object sender, TreeModelEventArgs e)
  1105 		{
  1106 			TreeNodeAdv parent = FindNode(e.Path);
  1107 			if (parent != null)
  1108 			{
  1109 				if (e.Indices != null)
  1110 				{
  1111 					List<int> list = new List<int>(e.Indices);
  1112 					list.Sort();
  1113 					for (int n = list.Count - 1; n >= 0; n--)
  1114 					{
  1115 						int index = list[n];
  1116 						if (index >= 0 && index <= parent.Nodes.Count)
  1117 							parent.Nodes.RemoveAt(index);
  1118 						else
  1119 							throw new ArgumentOutOfRangeException("Index out of range");
  1120 					}
  1121 				}
  1122 				else
  1123 				{
  1124 					for (int i = parent.Nodes.Count - 1; i >= 0; i--)
  1125 					{
  1126 						for (int n = 0; n < e.Children.Length; n++)
  1127 							if (parent.Nodes[i].Tag == e.Children[n])
  1128 							{
  1129 								parent.Nodes.RemoveAt(i);
  1130 								break;
  1131 							}
  1132 					}
  1133 				}
  1134 			}
  1135 			UpdateSelection();
  1136 			SmartFullUpdate();
  1137 		}
  1138 
  1139 		private void _model_NodesInserted(object sender, TreeModelEventArgs e)
  1140 		{
  1141 			if (e.Indices == null)
  1142 				throw new ArgumentNullException("Indices");
  1143 
  1144 			TreeNodeAdv parent = FindNode(e.Path);
  1145 			if (parent != null)
  1146 			{
  1147 				for (int i = 0; i < e.Children.Length; i++)
  1148 					AddNewNode(parent, e.Children[i], e.Indices[i]);
  1149 			}
  1150 			SmartFullUpdate();
  1151 		}
  1152 
  1153 		private void _model_NodesChanged(object sender, TreeModelEventArgs e)
  1154 		{
  1155 			TreeNodeAdv parent = FindNode(e.Path);
  1156 			if (parent != null && parent.IsVisible && parent.IsExpanded)
  1157 			{
  1158 				if (InvokeRequired)
  1159 					BeginInvoke(new UpdateContentWidthDelegate(ClearNodesSize), e, parent);
  1160 				else
  1161 					ClearNodesSize(e, parent);
  1162 				SmartFullUpdate();
  1163 			}
  1164 		}
  1165 
  1166 		private delegate void UpdateContentWidthDelegate(TreeModelEventArgs e, TreeNodeAdv parent);
  1167 		private void ClearNodesSize(TreeModelEventArgs e, TreeNodeAdv parent)
  1168 		{
  1169 			if (e.Indices != null)
  1170 			{
  1171 				foreach (int index in e.Indices)
  1172 				{
  1173 					if (index >= 0 && index < parent.Nodes.Count)
  1174 					{
  1175 						TreeNodeAdv node = parent.Nodes[index];
  1176 						node.Height = node.RightBounds = null;
  1177 					}
  1178 					else
  1179 						throw new ArgumentOutOfRangeException("Index out of range");
  1180 				}
  1181 			}
  1182 			else
  1183 			{
  1184 				foreach (TreeNodeAdv node in parent.Nodes)
  1185 				{
  1186 					foreach (object obj in e.Children)
  1187 						if (node.Tag == obj)
  1188 						{
  1189 							node.Height = node.RightBounds = null;
  1190 						}
  1191 				}
  1192 			}
  1193 		}
  1194 		#endregion
  1195 	}
  1196 }