moel@345: using System;
moel@345: using System.Collections.Generic;
moel@345: using System.Text;
moel@345: using System.Windows.Forms;
moel@345: using System.Drawing;
moel@345: using Aga.Controls.Tree.NodeControls;
moel@345: using System.Drawing.Imaging;
moel@345: using System.Threading;
moel@345: 
moel@345: namespace Aga.Controls.Tree
moel@345: {
moel@345: 	public partial class TreeViewAdv
moel@345: 	{
moel@345: 		#region Keys
moel@345: 
moel@345: 		protected override bool IsInputChar(char charCode)
moel@345: 		{
moel@345: 			return true;
moel@345: 		}
moel@345: 
moel@345: 		protected override bool IsInputKey(Keys keyData)
moel@345: 		{
moel@345: 			if (((keyData & Keys.Up) == Keys.Up)
moel@345: 				|| ((keyData & Keys.Down) == Keys.Down)
moel@345: 				|| ((keyData & Keys.Left) == Keys.Left)
moel@345: 				|| ((keyData & Keys.Right) == Keys.Right))
moel@345: 				return true;
moel@345: 			else
moel@345: 				return base.IsInputKey(keyData);
moel@345: 		}
moel@345: 
moel@345: 		internal void ChangeInput()
moel@345: 		{
moel@345: 			if ((ModifierKeys & Keys.Shift) == Keys.Shift)
moel@345: 			{
moel@345: 				if (!(Input is InputWithShift))
moel@345: 					Input = new InputWithShift(this);
moel@345: 			}
moel@345: 			else if ((ModifierKeys & Keys.Control) == Keys.Control)
moel@345: 			{
moel@345: 				if (!(Input is InputWithControl))
moel@345: 					Input = new InputWithControl(this);
moel@345: 			}
moel@345: 			else
moel@345: 			{
moel@345: 				if (!(Input.GetType() == typeof(NormalInputState)))
moel@345: 					Input = new NormalInputState(this);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnKeyDown(KeyEventArgs e)
moel@345: 		{
moel@345: 			base.OnKeyDown(e);
moel@345: 			if (!e.Handled)
moel@345: 			{
moel@345: 				if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey)
moel@345: 					ChangeInput();
moel@345: 				Input.KeyDown(e);
moel@345: 				if (!e.Handled)
moel@345: 				{
moel@345: 					foreach (NodeControlInfo item in GetNodeControls(CurrentNode))
moel@345: 					{
moel@345: 						item.Control.KeyDown(e);
moel@345: 						if (e.Handled)
moel@345: 							break;
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnKeyUp(KeyEventArgs e)
moel@345: 		{
moel@345: 			base.OnKeyUp(e);
moel@345: 			if (!e.Handled)
moel@345: 			{
moel@345: 				if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey)
moel@345: 					ChangeInput();
moel@345: 				if (!e.Handled)
moel@345: 				{
moel@345: 					foreach (NodeControlInfo item in GetNodeControls(CurrentNode))
moel@345: 					{
moel@345: 						item.Control.KeyUp(e);
moel@345: 						if (e.Handled)
moel@345: 							return;
moel@345: 					}
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnKeyPress(KeyPressEventArgs e)
moel@345: 		{
moel@345: 			base.OnKeyPress(e);
moel@345: 			if (!e.Handled)
moel@345: 				_search.Search(e.KeyChar);
moel@345: 		}
moel@345: 
moel@345: 		#endregion
moel@345: 
moel@345: 		#region Mouse
moel@345: 
moel@345: 		private TreeNodeAdvMouseEventArgs CreateMouseArgs(MouseEventArgs e)
moel@345: 		{
moel@345: 			TreeNodeAdvMouseEventArgs args = new TreeNodeAdvMouseEventArgs(e);
moel@345: 			args.ViewLocation = new Point(e.X + OffsetX,
moel@345: 				e.Y + _rowLayout.GetRowBounds(FirstVisibleRow).Y - ColumnHeaderHeight);
moel@345: 			args.ModifierKeys = ModifierKeys;
moel@345: 			args.Node = GetNodeAt(e.Location);
moel@345: 			NodeControlInfo info = GetNodeControlInfoAt(args.Node, e.Location);
moel@345: 			args.ControlBounds = info.Bounds;
moel@345: 			args.Control = info.Control;
moel@345: 			return args;
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseWheel(MouseEventArgs e)
moel@345: 		{
moel@345: 			_search.EndSearch();
moel@345: 			if (SystemInformation.MouseWheelScrollLines > 0)
moel@345: 			{
moel@345: 				int lines = e.Delta / 120 * SystemInformation.MouseWheelScrollLines;
moel@345: 				int newValue = _vScrollBar.Value - lines;
moel@345: 				newValue = Math.Min(_vScrollBar.Maximum - _vScrollBar.LargeChange + 1, newValue);
moel@345: 				newValue = Math.Min(_vScrollBar.Maximum, newValue);
moel@345: 				_vScrollBar.Value = Math.Max(_vScrollBar.Minimum, newValue);
moel@345: 			}
moel@345: 			base.OnMouseWheel(e);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseDown(MouseEventArgs e)
moel@345: 		{
moel@345: 			if (CurrentEditorOwner != null)
moel@345: 			{
moel@345: 				CurrentEditorOwner.EndEdit(true);
moel@345: 				return;
moel@345: 			}
moel@345: 
moel@345: 			if (!Focused)
moel@345: 				Focus();
moel@345: 
moel@345: 			_search.EndSearch();
moel@345: 			if (e.Button == MouseButtons.Left)
moel@345: 			{
moel@345: 				TreeColumn c;
moel@345: 				c = GetColumnDividerAt(e.Location);
moel@345: 				if (c != null)
moel@345: 				{
moel@345: 					Input = new ResizeColumnState(this, c, e.Location);
moel@345: 					return;
moel@345: 				}
moel@345: 				c = GetColumnAt(e.Location);
moel@345: 				if (c != null)
moel@345: 				{
moel@345: 					Input = new ClickColumnState(this, c, e.Location);
moel@345: 					UpdateView();
moel@345: 					return;
moel@345: 				}
moel@345: 			}
moel@345: 
moel@345: 			ChangeInput();
moel@345: 			TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
moel@345: 
moel@345: 			if (args.Node != null && args.Control != null)
moel@345: 				args.Control.MouseDown(args);
moel@345: 
moel@345: 			if (!args.Handled)
moel@345: 				Input.MouseDown(args);
moel@345: 
moel@345: 			base.OnMouseDown(e);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseClick(MouseEventArgs e)
moel@345: 		{
moel@345: 			//TODO: Disable when click on plusminus icon
moel@345: 			TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
moel@345: 			if (args.Node != null)
moel@345: 				OnNodeMouseClick(args);
moel@345: 
moel@345: 			base.OnMouseClick(e);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseDoubleClick(MouseEventArgs e)
moel@345: 		{
moel@345: 			TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
moel@345: 
moel@345: 			if (args.Node != null && args.Control != null)
moel@345: 				args.Control.MouseDoubleClick(args);
moel@345: 
moel@345: 			if (!args.Handled)
moel@345: 			{
moel@345: 				if (args.Node != null)
moel@345: 					OnNodeMouseDoubleClick(args);
moel@345: 				else
moel@345: 					Input.MouseDoubleClick(args);
moel@345: 
moel@345: 				if (!args.Handled)
moel@345: 				{
moel@345: 					if (args.Node != null && args.Button == MouseButtons.Left)
moel@345: 						args.Node.IsExpanded = !args.Node.IsExpanded;
moel@345: 				}
moel@345: 			}
moel@345: 
moel@345: 			base.OnMouseDoubleClick(e);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseUp(MouseEventArgs e)
moel@345: 		{
moel@345: 			TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
moel@345: 			if (Input is ResizeColumnState)
moel@345: 				Input.MouseUp(args);
moel@345: 			else
moel@345: 			{
moel@345: 				if (args.Node != null && args.Control != null)
moel@345: 					args.Control.MouseUp(args);
moel@345: 				if (!args.Handled)
moel@345: 					Input.MouseUp(args);
moel@345: 
moel@345: 				base.OnMouseUp(e);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseMove(MouseEventArgs e)
moel@345: 		{
moel@345: 			if (Input.MouseMove(e))
moel@345: 				return;
moel@345: 
moel@345: 			base.OnMouseMove(e);
moel@345: 			SetCursor(e);
moel@345: 			UpdateToolTip(e);
moel@345: 			if (ItemDragMode && Dist(e.Location, ItemDragStart) > ItemDragSensivity
moel@345: 				&& CurrentNode != null && CurrentNode.IsSelected)
moel@345: 			{
moel@345: 				ItemDragMode = false;
moel@345: 				_toolTip.Active = false;
moel@345: 				OnItemDrag(e.Button, Selection.ToArray());
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnMouseLeave(EventArgs e)
moel@345: 		{
moel@345: 			_hotColumn = null;
moel@345: 			UpdateHeaders();
moel@345: 			base.OnMouseLeave(e);
moel@345: 		}
moel@345: 
moel@345: 		private void SetCursor(MouseEventArgs e)
moel@345: 		{
moel@345: 			TreeColumn col;
moel@345: 			col = GetColumnDividerAt(e.Location);
moel@345: 			if (col == null)
moel@345: 				_innerCursor = null;
moel@345: 			else
moel@345: 			{
moel@345: 				if (col.Width == 0)
moel@345: 					_innerCursor = ResourceHelper.DVSplitCursor;
moel@345: 				else
moel@345: 					_innerCursor = Cursors.VSplit;
moel@345: 			}
moel@345: 
moel@345: 			col = GetColumnAt(e.Location);
moel@345: 			if (col != _hotColumn)
moel@345: 			{
moel@345: 				_hotColumn = col;
moel@345: 				UpdateHeaders();
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		internal TreeColumn GetColumnAt(Point p)
moel@345: 		{
moel@345: 			if (p.Y > ColumnHeaderHeight)
moel@345: 				return null;
moel@345: 
moel@345: 			int x = -OffsetX;
moel@345: 			foreach (TreeColumn col in Columns)
moel@345: 			{
moel@345: 				if (col.IsVisible)
moel@345: 				{
moel@345: 					Rectangle rect = new Rectangle(x, 0, col.Width, ColumnHeaderHeight);
moel@345: 					x += col.Width;
moel@345: 					if (rect.Contains(p))
moel@345: 						return col;
moel@345: 				}
moel@345: 			}
moel@345: 			return null;
moel@345: 		}
moel@345: 
moel@345: 		internal int GetColumnX(TreeColumn column)
moel@345: 		{
moel@345: 			int x = -OffsetX;
moel@345: 			foreach (TreeColumn col in Columns)
moel@345: 			{
moel@345: 				if (col.IsVisible)
moel@345: 				{
moel@345: 					if (column == col)
moel@345: 						return x;
moel@345: 					else
moel@345: 						x += col.Width;
moel@345: 				}
moel@345: 			}
moel@345: 			return x;
moel@345: 		}
moel@345: 
moel@345: 		internal TreeColumn GetColumnDividerAt(Point p)
moel@345: 		{
moel@345: 			if (p.Y > ColumnHeaderHeight)
moel@345: 				return null;
moel@345: 
moel@345: 			int x = -OffsetX;
moel@345: 			TreeColumn prevCol = null;
moel@345: 			Rectangle left, right;
moel@345: 			foreach (TreeColumn col in Columns)
moel@345: 			{
moel@345: 				if (col.IsVisible)
moel@345: 				{
moel@345: 					if (col.Width > 0)
moel@345: 					{
moel@345: 						left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight);
moel@345: 						right = new Rectangle(x + col.Width - (DividerWidth / 2), 0, DividerWidth / 2, ColumnHeaderHeight);
moel@345: 						if (left.Contains(p) && prevCol != null)
moel@345: 							return prevCol;
moel@345: 						else if (right.Contains(p))
moel@345: 							return col;
moel@345: 					}
moel@345: 					prevCol = col;
moel@345: 					x += col.Width;
moel@345: 				}
moel@345: 			}
moel@345: 
moel@345: 			left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight);
moel@345: 			if (left.Contains(p) && prevCol != null)
moel@345: 				return prevCol;
moel@345: 
moel@345: 			return null;
moel@345: 		}
moel@345: 
moel@345: 		TreeColumn _tooltipColumn;
moel@345: 		private void UpdateToolTip(MouseEventArgs e)
moel@345: 		{
moel@345: 			TreeColumn col = GetColumnAt(e.Location);
moel@345: 			if (col != null)
moel@345: 			{
moel@345: 				if (col != _tooltipColumn)
moel@345: 					SetTooltip(col.TooltipText);
moel@345: 			}
moel@345: 			else
moel@345: 				DisplayNodesTooltip(e);
moel@345: 			_tooltipColumn = col;
moel@345: 		}
moel@345: 
moel@345: 		TreeNodeAdv _hotNode;
moel@345: 		NodeControl _hotControl;
moel@345: 		private void DisplayNodesTooltip(MouseEventArgs e)
moel@345: 		{
moel@345: 			if (ShowNodeToolTips)
moel@345: 			{
moel@345: 				TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
moel@345: 				if (args.Node != null && args.Control != null)
moel@345: 				{
moel@345: 					if (args.Node != _hotNode || args.Control != _hotControl)
moel@345: 						SetTooltip(GetNodeToolTip(args));
moel@345: 				}
moel@345: 				else
moel@345: 					_toolTip.SetToolTip(this, null);
moel@345: 
moel@345: 				_hotControl = args.Control;
moel@345: 				_hotNode = args.Node;
moel@345: 			}
moel@345: 			else
moel@345: 				_toolTip.SetToolTip(this, null);
moel@345: 		}
moel@345: 
moel@345: 		private void SetTooltip(string text)
moel@345: 		{
moel@345: 			if (!String.IsNullOrEmpty(text))
moel@345: 			{
moel@345: 				_toolTip.Active = false;
moel@345: 				_toolTip.SetToolTip(this, text);
moel@345: 				_toolTip.Active = true;
moel@345: 			}
moel@345: 			else
moel@345: 				_toolTip.SetToolTip(this, null);
moel@345: 		}
moel@345: 
moel@345: 		private string GetNodeToolTip(TreeNodeAdvMouseEventArgs args)
moel@345: 		{
moel@345: 			string msg = args.Control.GetToolTip(args.Node);
moel@345: 
moel@345: 			BaseTextControl btc = args.Control as BaseTextControl;
moel@345: 			if (btc != null && btc.DisplayHiddenContentInToolTip && String.IsNullOrEmpty(msg))
moel@345: 			{
moel@345: 				Size ms = btc.GetActualSize(args.Node, _measureContext);
moel@345: 				if (ms.Width > args.ControlBounds.Size.Width || ms.Height > args.ControlBounds.Size.Height
moel@345: 					|| args.ControlBounds.Right - OffsetX > DisplayRectangle.Width)
moel@345: 					msg = btc.GetLabel(args.Node);
moel@345: 			}
moel@345: 
moel@345: 			if (String.IsNullOrEmpty(msg) && DefaultToolTipProvider != null)
moel@345: 				msg = DefaultToolTipProvider.GetToolTip(args.Node, args.Control);
moel@345: 
moel@345: 			return msg;
moel@345: 		}
moel@345: 
moel@345: 		#endregion
moel@345: 
moel@345: 		#region DragDrop
moel@345: 
moel@345: 		private bool _dragAutoScrollFlag = false;
moel@345: 		private Bitmap _dragBitmap = null;
moel@345: 		private System.Threading.Timer _dragTimer;
moel@345: 
moel@345: 		private void StartDragTimer()
moel@345: 		{
moel@345: 			if (_dragTimer == null)
moel@345: 				_dragTimer = new System.Threading.Timer(new TimerCallback(DragTimerTick), null, 0, 100);
moel@345: 		}
moel@345: 
moel@345: 		private void StopDragTimer()
moel@345: 		{
moel@345: 			if (_dragTimer != null)
moel@345: 			{
moel@345: 				_dragTimer.Dispose();
moel@345: 				_dragTimer = null;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void SetDropPosition(Point pt)
moel@345: 		{
moel@345: 			TreeNodeAdv node = GetNodeAt(pt);
moel@345: 			OnDropNodeValidating(pt, ref node);
moel@345: 			_dropPosition.Node = node;
moel@345: 			if (node != null)
moel@345: 			{
moel@345: 				Rectangle first = _rowLayout.GetRowBounds(FirstVisibleRow);
moel@345: 				Rectangle bounds = _rowLayout.GetRowBounds(node.Row);
moel@345: 				float pos = (pt.Y + first.Y - ColumnHeaderHeight - bounds.Y) / (float)bounds.Height;
moel@345: 				if (pos < TopEdgeSensivity)
moel@345: 					_dropPosition.Position = NodePosition.Before;
moel@345: 				else if (pos > (1 - BottomEdgeSensivity))
moel@345: 					_dropPosition.Position = NodePosition.After;
moel@345: 				else
moel@345: 					_dropPosition.Position = NodePosition.Inside;
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void DragTimerTick(object state)
moel@345: 		{
moel@345: 			_dragAutoScrollFlag = true;
moel@345: 		}
moel@345: 
moel@345: 		private void DragAutoScroll()
moel@345: 		{
moel@345: 			_dragAutoScrollFlag = false;
moel@345: 			Point pt = PointToClient(MousePosition);
moel@345: 			if (pt.Y < 20 && _vScrollBar.Value > 0)
moel@345: 				_vScrollBar.Value--;
moel@345: 			else if (pt.Y > Height - 20 && _vScrollBar.Value <= _vScrollBar.Maximum - _vScrollBar.LargeChange)
moel@345: 				_vScrollBar.Value++;
moel@345: 		}
moel@345: 
moel@345: 		public void DoDragDropSelectedNodes(DragDropEffects allowedEffects)
moel@345: 		{
moel@345: 			if (SelectedNodes.Count > 0)
moel@345: 			{
moel@345: 				TreeNodeAdv[] nodes = new TreeNodeAdv[SelectedNodes.Count];
moel@345: 				SelectedNodes.CopyTo(nodes, 0);
moel@345: 				DoDragDrop(nodes, allowedEffects);
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		private void CreateDragBitmap(IDataObject data)
moel@345: 		{
moel@345: 			if (UseColumns || !DisplayDraggingNodes)
moel@345: 				return;
moel@345: 
moel@345: 			TreeNodeAdv[] nodes = data.GetData(typeof(TreeNodeAdv[])) as TreeNodeAdv[];
moel@345: 			if (nodes != null && nodes.Length > 0)
moel@345: 			{
moel@345: 				Rectangle rect = DisplayRectangle;
moel@345: 				Bitmap bitmap = new Bitmap(rect.Width, rect.Height);
moel@345: 				using (Graphics gr = Graphics.FromImage(bitmap))
moel@345: 				{
moel@345: 					gr.Clear(BackColor);
moel@345: 					DrawContext context = new DrawContext();
moel@345: 					context.Graphics = gr;
moel@345: 					context.Font = Font;
moel@345: 					context.Enabled = true;
moel@345: 					int y = 0;
moel@345: 					int maxWidth = 0;
moel@345: 					foreach (TreeNodeAdv node in nodes)
moel@345: 					{
moel@345: 						if (node.Tree == this)
moel@345: 						{
moel@345: 							int x = 0;
moel@345: 							int height = _rowLayout.GetRowBounds(node.Row).Height;
moel@345: 							foreach (NodeControl c in NodeControls)
moel@345: 							{
moel@345: 								Size s = c.GetActualSize(node, context);
moel@345: 								if (!s.IsEmpty)
moel@345: 								{
moel@345: 									int width = s.Width;
moel@345: 									rect = new Rectangle(x, y, width, height);
moel@345: 									x += (width + 1);
moel@345: 									context.Bounds = rect;
moel@345: 									c.Draw(node, context);
moel@345: 								}
moel@345: 							}
moel@345: 							y += height;
moel@345: 							maxWidth = Math.Max(maxWidth, x);
moel@345: 						}
moel@345: 					}
moel@345: 
moel@345: 					if (maxWidth > 0 && y > 0)
moel@345: 					{
moel@345: 						_dragBitmap = new Bitmap(maxWidth, y, PixelFormat.Format32bppArgb);
moel@345: 						using (Graphics tgr = Graphics.FromImage(_dragBitmap))
moel@345: 							tgr.DrawImage(bitmap, Point.Empty);
moel@345: 						BitmapHelper.SetAlphaChanelValue(_dragBitmap, 150);
moel@345: 					}
moel@345: 					else
moel@345: 						_dragBitmap = null;
moel@345: 				}
moel@345: 			}
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnDragOver(DragEventArgs drgevent)
moel@345: 		{
moel@345: 			ItemDragMode = false;
moel@345: 			Point pt = PointToClient(new Point(drgevent.X, drgevent.Y));
moel@345: 			if (_dragAutoScrollFlag)
moel@345: 				DragAutoScroll();
moel@345: 			SetDropPosition(pt);
moel@345: 			UpdateView();
moel@345: 			base.OnDragOver(drgevent);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnDragEnter(DragEventArgs drgevent)
moel@345: 		{
moel@345: 			_search.EndSearch();
moel@345: 			DragMode = true;
moel@345: 			CreateDragBitmap(drgevent.Data);
moel@345: 			base.OnDragEnter(drgevent);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnDragLeave(EventArgs e)
moel@345: 		{
moel@345: 			DragMode = false;
moel@345: 			UpdateView();
moel@345: 			base.OnDragLeave(e);
moel@345: 		}
moel@345: 
moel@345: 		protected override void OnDragDrop(DragEventArgs drgevent)
moel@345: 		{
moel@345: 			DragMode = false;
moel@345: 			UpdateView();
moel@345: 			base.OnDragDrop(drgevent);
moel@345: 		}
moel@345: 
moel@345: 		#endregion
moel@345: 	}
moel@345: }