External/Aga.Controls/Tree/TreeViewAdv.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
     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 }