TreeView.cs
上传用户:hbhltzc
上传日期:2022-06-04
资源大小:1925k
文件大小:78k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Text;
  3. using System.Windows.Forms;
  4. using System.Collections;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.Diagnostics;
  8. using System.Collections.Generic;
  9. using System.ComponentModel;
  10. using System.IO;
  11. namespace XmlNotepad {
  12.     // This file contains a new implementation of TreeView that virtualizes the storage of the
  13.     // tree node data so it can come from a separate model, for example, an XmlDocument.
  14.     // It also removes some limitations that TreeView has like maximum of height of 32k pixels.
  15.     public class TreeView : UserControl, IEditableView {
  16.         ImageList imageList;
  17.         bool editable;
  18.         TreeNode focus;
  19.         ArrayList selection = new ArrayList();
  20.         TreeNodeCollection nodes;
  21.         Color lineColor = SystemColors.ControlDark;
  22.         int treeIndent = 30;
  23.         TypeToFindHandler ttf;
  24.         private TextEditorOverlay editor;
  25.         internal TreeViewDropFeedback dff;
  26.         Timer timer = new Timer();
  27.         int mouseDownEditDelay = 400;
  28.         Point scrollPosition;
  29.         AccessibleTree acc;
  30.         
  31.         /// <summary> 
  32.         /// Required designer variable.
  33.         /// </summary>
  34.         private System.ComponentModel.IContainer components = null;
  35.         public event EventHandler<NodeLabelEditEventArgs> BeforeLabelEdit;
  36.         public event EventHandler<NodeLabelEditEventArgs> AfterLabelEdit;
  37.         public event EventHandler<TreeViewEventArgs> BeforeCollapse;
  38.         public event EventHandler<TreeViewEventArgs> AfterCollapse;
  39.         public event EventHandler<TreeViewEventArgs> BeforeExpand;
  40.         public event EventHandler<TreeViewEventArgs> AfterExpand;
  41.         public event EventHandler<TreeViewEventArgs> AfterSelect;
  42.         public event EventHandler AfterBatchUpdate;
  43.         public event ItemDragEventHandler ItemDrag;
  44.         public TreeView() {
  45.             SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  46.             SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
  47.             SetStyle(ControlStyles.ResizeRedraw, true);
  48.             SetStyle(ControlStyles.UserPaint, true);
  49.             SetStyle(ControlStyles.Selectable, true);
  50.             InitializeComponent();
  51.             this.SuspendLayout();
  52.             this.editor = new TextEditorOverlay(this);
  53.             this.editor.AutoSize = true;
  54.             this.editor.CommitEdit += new EventHandler<TextEditorEventArgs>(OnCommitEdit);
  55.             this.editor.LayoutEditor += new EventHandler<TextEditorLayoutEventArgs>(OnLayoutEditor);
  56.             ttf = new TypeToFindHandler(this, 2000);
  57.             ttf.FindString += new TypeToFindEventHandler(FindString);
  58.             timer.Tick += new EventHandler(timer_Tick);
  59.             this.AccessibleRole = AccessibleRole.List;
  60.             this.AccessibleName = "TreeView";
  61.             this.ResumeLayout();
  62.         }
  63.         #region Component Designer generated code
  64.         /// <summary> 
  65.         /// Clean up any resources being used.
  66.         /// </summary>
  67.         /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  68.         protected override void Dispose(bool disposing) {
  69.             if (disposing && (components != null)) {
  70.                 components.Dispose();
  71.             }
  72.             if (this.ttf != null) {
  73.                 this.ttf.Dispose();
  74.                 this.ttf = null;
  75.             }
  76.             base.Dispose(disposing);
  77.         }
  78.         /// <summary> 
  79.         /// Required method for Designer support - do not modify 
  80.         /// the contents of this method with the code editor.
  81.         /// </summary>
  82.         private void InitializeComponent() {
  83.             this.components = new System.ComponentModel.Container();
  84.             this.SuspendLayout();
  85.             this.AccessibleRole = AccessibleRole.List;
  86.             this.Name = this.AccessibleName = "TreeView";
  87.             
  88.             this.ResumeLayout(false);
  89.         }
  90.         #endregion
  91.         public void Close() {
  92.             this.editor.Dispose();
  93.         }
  94.         public void SetSite(ISite site) {
  95.             this.Site = this.editor.Site = site;
  96.         }
  97.         public Point ScrollPosition {
  98.             get { return this.scrollPosition; }
  99.             set {
  100.                 this.scrollPosition = value;
  101.                 Invalidate();
  102.             }
  103.         }
  104.         public TextEditorOverlay Editor {
  105.             get { return this.editor; }
  106.         }
  107.         public void StartIncrementalSearch() {
  108.             ttf.StartIncrementalSearch();
  109.         }
  110.         void FindString(object sender, string toFind) {
  111.             TreeNode node = this.SelectedNode;
  112.             if (node == null) node = this.FirstVisibleNode;
  113.             TreeNode start = node;
  114.             while (node != null) {
  115.                 string s = node.Label;
  116.                 if (s != null && s.StartsWith(toFind, StringComparison.CurrentCultureIgnoreCase)) {
  117.                     this.SelectedNode = node;
  118.                     return;
  119.                 }
  120.                 node = node.NextVisibleNode;
  121.                 if (node == null) node = this.FirstVisibleNode;
  122.                 if (node == start)
  123.                     break;
  124.             }
  125.         }
  126.         public int MouseDownEditDelay {
  127.             get { return this.mouseDownEditDelay; }
  128.             set { this.mouseDownEditDelay = value; }
  129.         }
  130.         internal void OnRemoveNode(TreeNode node) {
  131.             if (node != null && this.SelectedNode != null &&
  132.                 (node == this.SelectedNode || node.Contains(this.SelectedNode))) {
  133.                 TreeNodeCollection col = (node.Parent == null) ? this.Nodes : node.Parent.Nodes;
  134.                 if (col != null) {
  135.                     int count = col.Count;
  136.                     TreeNode selected = null;
  137.                     if (node.Index == count - 1) {
  138.                         selected = node.PrevVisibleNode;
  139.                     } else {
  140.                         // get next visible node after this one (and after all it's children).
  141.                         TreeNode next = col[node.Index + 1];
  142.                         selected = (!next.IsVisible) ? next.NextVisibleNode : next;
  143.                     }
  144.                     this.SelectedNode = selected;
  145.                 } else {
  146.                     this.SelectedNode = null;
  147.                 }
  148.             }
  149.             InvalidateLayout();
  150.         }
  151.         internal void OnBeforeExpand(TreeNode node) {
  152.             if (this.BeforeExpand != null) this.BeforeExpand(this, new TreeViewEventArgs(node, TreeViewAction.Expanded));
  153.         }
  154.         internal void OnAfterExpand(TreeNode node) {
  155.             if (this.AfterExpand != null) this.AfterExpand(this, new TreeViewEventArgs(node, TreeViewAction.Expanded));
  156.         }
  157.         internal void OnBeforeCollapse(TreeNode node) {
  158.             if (this.BeforeCollapse != null) this.BeforeCollapse(this, new TreeViewEventArgs(node, TreeViewAction.Collapsed));
  159.         }
  160.         internal void OnAfterCollapse(TreeNode node) {
  161.             if (this.AfterCollapse != null) this.AfterCollapse(this, new TreeViewEventArgs(node, TreeViewAction.Collapsed));
  162.             TreeNode sel = this.SelectedNode;
  163.             if (sel != null && node.Contains(sel)) {
  164.                 this.SelectedNode = node;
  165.             }
  166.         }
  167.         public TreeNodeCollection Nodes {
  168.             get { return this.nodes; }
  169.             set {
  170.                 ClearSelection();
  171.                 this.nodes = value;
  172.                 PerformLayout();
  173.             }
  174.         }
  175.         public TreeNode SelectedNode {
  176.             get { return selection.Count > 0 ? (TreeNode)selection[0] : null; }
  177.             set {
  178.                 if (this.SelectedNode != value) {
  179.                     if (this.InBatchUpdate && this.selection.Count == 1) {
  180.                         if (value == null) {
  181.                             this.selection.Clear();
  182.                             this.focus = null;
  183.                         } else {
  184.                             this.selection[0] = value;
  185.                             this.focus = value;
  186.                         }
  187.                     } else {
  188.                         ClearSelection();
  189.                         if (value != null) {
  190.                             selection.Add(value);
  191.                         }
  192.                         SetFocus(value);
  193.                         OnSelectionChanged();
  194.                     }
  195.                 }
  196.             }
  197.         }
  198.         public void OnSelectionChanged() {
  199.             if (AfterSelect != null) AfterSelect(this, new TreeViewEventArgs(this.SelectedNode, TreeViewAction.None));
  200.         }
  201.         protected override void OnGotFocus(EventArgs e) {
  202.             if (this.SelectedNode == null) {
  203.                 SelectedNode = this.FirstVisibleNode;
  204.             }
  205.             Invalidate();
  206.         }
  207.         protected override void OnLostFocus(EventArgs e) {
  208.             Invalidate();
  209.         }
  210.         Point mouseDown;
  211.         Point lastMousePos;
  212.         TreeNode downSel;
  213.         TreeNode downNode; 
  214.         TreeNode hitNode;
  215.         public Point ApplyScrollOffset(int x, int y) {
  216.             return new Point(x - this.scrollPosition.X, y - this.scrollPosition.Y);
  217.         }
  218.         public Point ApplyScrollOffset(Point p) {
  219.             return new Point(p.X - this.scrollPosition.X, p.Y - this.scrollPosition.Y);
  220.         }
  221.         protected override void OnMouseDown(MouseEventArgs e) {
  222.             base.OnMouseDown(e);
  223.             CurrentEvent.Event = e;
  224.             EndEdit(false);
  225.             if (this.downNode != null) return; // work around for unit testing problem...
  226.             Point p = ApplyScrollOffset(e.X, e.Y);
  227.             int x = p.X; int y = p.Y;
  228.             bool wasFocussed = this.Focused;
  229.             this.Focus();
  230.             TreeNode node = this.FindNodeAt(x, y);
  231.             TreeNode sel = this.SelectedNode;
  232.             this.SelectedNode = node;
  233.             this.downSel = this.downNode = null;
  234.             this.hitNode = null;
  235.             if (e.Button == MouseButtons.Left) {
  236.                 if (node != null) {
  237.                     Size imgSize = GetImageSize();
  238.                     if (e.Clicks > 1) {
  239.                         node.Toggle();
  240.                     } else if (wasFocussed && node.LabelAndImageBounds(imgSize, TreeIndent).Contains(x, y)) {
  241.                         this.hitNode = node;
  242.                         if (node.LabelBounds.Contains(x, y)) {
  243.                             this.downSel = sel;
  244.                             this.downNode = node;
  245.                             mouseDown = new Point(x, y);                     
  246.                         }
  247.                     } else {
  248.                         Rectangle r = GetBoxBounds(this.Margin.Left + (imgSize.Width / 2), node.LabelBounds.Top, this.ItemHeight, node.Depth, TreeIndent);
  249.                         int slop = (this.ItemHeight - r.Height) / 2;
  250.                         r.Inflate(slop, slop); // make it a bit easier to hit.
  251.                         if (r.Contains(x, y)) {
  252.                             node.Toggle();
  253.                         }
  254.                     }
  255.                 }
  256.             }
  257.         }
  258. #if !WHIDBEY
  259.         Rectangle Margin = new Rectangle(3,3,3,3);
  260. #endif
  261.         const int DragThreshold = 5;
  262.         protected override void OnMouseMove(MouseEventArgs e) {
  263.             base.OnMouseMove(e);
  264.             Point pt = ApplyScrollOffset(e.X, e.Y);
  265.             this.lastMousePos = pt;
  266.             bool left = e.Button == MouseButtons.Left;
  267.             if (left && hitNode != null) {
  268.                 int dx = pt.X - mouseDown.X;
  269.                 int dy = pt.Y - mouseDown.Y;
  270.                 if (Math.Sqrt(dx * dx + dy * dy) > DragThreshold) {
  271.                     if (this.ItemDrag != null) {
  272.                         this.ItemDrag(this, new ItemDragEventArgs(e.Button, hitNode));
  273.                     }
  274.                     this.downNode = this.downSel = null;                    
  275.                 }
  276.             }
  277.         }
  278.         protected override void OnMouseUp(MouseEventArgs e) {
  279.             base.OnMouseUp(e);
  280.             if (e.Button == MouseButtons.Left && this.downSel != null) {
  281.                 Point p = ApplyScrollOffset(e.X, e.Y);
  282.                 int x = p.X; int y = p.Y;
  283.                 TreeNode node = this.FindNodeAt(x, y);
  284.                 if (node != null && node.LabelBounds.Contains(x, y)) {
  285.                     mouseDown = new Point(e.X, e.Y);
  286.                     if (this.downSel == node) {
  287.                         timer.Interval = this.mouseDownEditDelay;
  288.                         timer.Start();
  289.                         timer.Enabled = true;
  290.                         return;
  291.                     }
  292.                 }
  293.                 this.downSel = null;
  294.             }
  295.             this.downNode = null;
  296.             this.hitNode = null;
  297.         }
  298.         void timer_Tick(object sender, EventArgs e) {
  299.             timer.Stop();
  300.             if (this.downSel != null && this.downSel == this.SelectedNode && this.downSel.LabelBounds.Contains(this.lastMousePos)) {
  301.                 this.BeginEdit(null);
  302.             }
  303.             this.downSel = null;
  304.             this.downNode = null;
  305.             this.hitNode = null;
  306.         }
  307.         protected override bool IsInputKey(Keys keyData) {
  308.             Keys key = (keyData & ~Keys.Modifiers);
  309.             switch (key) {
  310.                 case Keys.Home:
  311.                 case Keys.End:
  312.                 case Keys.Down:
  313.                 case Keys.Up:
  314.                 case Keys.PageDown:
  315.                 case Keys.PageUp:
  316.                 case Keys.Right:
  317.                 case Keys.Left:
  318.                     return true;
  319.             }
  320.             return base.IsInputKey(keyData);
  321.         }
  322.         protected override void OnKeyDown(KeyEventArgs e) {
  323.             CurrentEvent.Event = e;
  324.             base.OnKeyDown(e);
  325.             if (!e.Handled) {
  326.                 HandleKeyDown(e);
  327.             }
  328.         }
  329.         public void BubbleKeyDown(KeyEventArgs e) {
  330.             base.OnKeyDown(e);
  331.         }
  332.         public void HandleKeyDown(KeyEventArgs e) {
  333.             TreeNode sel = this.SelectedNode;
  334.             bool isLetterOrDigit = ((e.KeyCode >= Keys.A && e.KeyCode <= Keys.Z) ||
  335.                                    (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9)) && 
  336.                                    (e.Modifiers == Keys.Shift || e.Modifiers == 0);
  337.             if (e.Modifiers == Keys.Control && (e.KeyCode == Keys.Home || e.KeyCode == Keys.End)) {
  338.                 // drop through in this case.
  339.             } else if (e.Modifiers != 0 && !isLetterOrDigit) {
  340.                 // Reserve use of modifiers for other things, like multi-select expansion and so on.
  341.                 return;
  342.             }
  343.             TreeNode n =this.SelectedNode;
  344.             switch (e.KeyCode) {
  345.                 case Keys.Left:
  346.                     if (sel != null) {
  347.                         if (sel.IsExpanded) {
  348.                             sel.Collapse();
  349.                         } else if (sel.Parent != null) {
  350.                             this.SelectedNode = sel.Parent;
  351.                         }
  352.                     }
  353.                     e.Handled = true;
  354.                     break;
  355.                 case Keys.Right:
  356.                     if (sel != null && !sel.IsExpanded) {
  357.                         sel.Expand();
  358.                     }
  359.                     e.Handled = true;
  360.                     break;
  361.                 case Keys.Up:
  362.                     if (sel != null) {
  363.                         TreeNode prev = sel.PrevVisibleNode;
  364.                         if (prev != null) {
  365.                             this.SelectedNode = prev;
  366.                         }
  367.                     } else {
  368.                         this.SelectedNode = this.LastVisibleNode;
  369.                     }
  370.                     e.Handled = true;
  371.                     break;
  372.                 case Keys.Down:
  373.                     if (sel != null) {
  374.                         TreeNode next = sel.NextVisibleNode;
  375.                         if (next != null) {
  376.                             this.SelectedNode = next;
  377.                         }
  378.                     } else {
  379.                         this.SelectedNode = this.FirstVisibleNode;
  380.                     }
  381.                     e.Handled = true;
  382.                     break;
  383.                 case Keys.Home:
  384.                     this.SelectedNode = this.FirstVisibleNode;
  385.                     e.Handled = true;
  386.                     break;
  387.                 case Keys.End:
  388.                     this.SelectedNode = this.LastVisibleNode;
  389.                     e.Handled = true;
  390.                     break;
  391.                 case Keys.PageDown:
  392.                     this.HandlePageDown();
  393.                     e.Handled = true;
  394.                     return;
  395.                 case Keys.PageUp:
  396.                     this.HandlePageUp();
  397.                     e.Handled = true;
  398.                     return;
  399.                 case Keys.Multiply:
  400.                     if (n != null) {
  401.                         n.ExpandAll();
  402.                         e.Handled = true;
  403.                     }
  404.                     return;
  405.                 case Keys.Add:
  406.                     if (n != null) {
  407.                         n.Expand();
  408.                         e.Handled = true;
  409.                     }
  410.                     return;
  411.                 case Keys.Subtract:
  412.                     if (n != null) {
  413.                         n.Collapse();
  414.                         e.Handled = true;
  415.                     }
  416.                     break;
  417.                 default:
  418.                     if (isLetterOrDigit && !e.Handled && this.ContainsFocus) {
  419.                         if (ttf.Started) {
  420.                             e.Handled = true;
  421.                         } else if (!this.IsEditing) {
  422.                             char ch = Convert.ToChar(e.KeyValue);
  423.                             if (!e.Shift) ch = Char.ToLower(ch);
  424.                             if (Char.IsLetter(ch) && this.BeginEdit(ch.ToString())) {
  425.                                 this.editor.SelectEnd();
  426.                                 e.Handled = true;
  427.                             }
  428.                         }
  429.                     }
  430.                     break;
  431.             }
  432.         }
  433.         public void HandlePageDown() {
  434.             int visibleRows = VisibleRows;
  435.             TreeNode sel = this.SelectedNode;
  436.             if (sel == null) {
  437.                 sel = this.FirstVisibleNode;
  438.             }
  439.             if (sel != null) {
  440.                 TreeNode n = sel.NextVisibleNode;
  441.                 while (n != null && visibleRows > 0) {
  442.                     if (n.NextVisibleNode == null)
  443.                         break;
  444.                     n = n.NextVisibleNode;
  445.                     visibleRows--;
  446.                 }
  447.                 if (n != null) {
  448.                     this.SelectedNode = n;
  449.                 }
  450.             }
  451.         }
  452.         public void HandlePageUp() {
  453.             int visibleRows = VisibleRows;
  454.             TreeNode sel = this.SelectedNode;
  455.             if (sel == null)
  456.                 sel = this.LastVisibleNode;
  457.             if (sel != null) {
  458.                 TreeNode n = sel;
  459.                 while (n != null && visibleRows > 0) {
  460.                     if (n.PrevVisibleNode == null)
  461.                         break;
  462.                     n = n.PrevVisibleNode;
  463.                     visibleRows--;
  464.                 }
  465.                 if (n != null) {
  466.                     this.SelectedNode = n;
  467.                 }
  468.             }
  469.         }
  470.         public int VisibleRows {
  471.             get {
  472.                 return this.ClientRectangle.Height / this.ItemHeight;
  473.             }
  474.         }
  475.         void OnLayoutEditor(object sender, TextEditorLayoutEventArgs args) {
  476.             if (this.SelectedNode == null)
  477.                 return;
  478.             Rectangle r = this.SelectedNode.LabelBounds;
  479.             r.Offset(this.scrollPosition);
  480.             args.PreferredBounds = r;
  481.             r.Width = this.Width - r.Left + this.Left - 20;
  482.             args.MaxBounds = r;
  483.         }
  484.         #region IEditableView
  485.         public bool BeginEdit(string value) {
  486.             TreeNode sel = this.SelectedNode;
  487.             if (this.editable && sel != null && sel.IsLabelEditable) {
  488.                 string text = value != null ? value : sel.Label;
  489.                 if (this.BeforeLabelEdit != null) {
  490.                     NodeLabelEditEventArgs args = new NodeLabelEditEventArgs(sel, text);
  491.                     this.BeforeLabelEdit(this, args);
  492.                     if (args.CancelEdit)
  493.                         return false;
  494.                 }
  495.                 IIntellisenseProvider provider = this.GetService(typeof(IIntellisenseProvider)) as IIntellisenseProvider;
  496.                 if (provider != null) {
  497.                     provider.SetContextNode(sel);
  498.                     if (!provider.IsNameEditable)
  499.                         return false;
  500.                 }
  501.                 this.editor.BeginEdit(text, provider, EditMode.Name, sel.ForeColor, this.Focused);
  502.                 return true;
  503.             }
  504.             return false;
  505.         }
  506.         public bool IsEditing {
  507.             get {
  508.                 return this.editor.IsEditing;
  509.             }
  510.         }
  511.         public void SelectText(int index, int length) {
  512.             if (this.editor.IsEditing) {
  513.                 this.editor.Select(index, length);
  514.             }
  515.         }
  516.         public bool ReplaceText(int index, int length, string replacement) {
  517.             if (this.editor.IsEditing) {
  518.                 return this.editor.Replace(index, length, replacement);
  519.             }
  520.             return false;
  521.         }
  522.         public Rectangle EditorBounds {
  523.             get {
  524.                 return this.editor.Bounds;
  525.             }
  526.         }
  527.         public bool EndEdit(bool cancel) {
  528.             return this.editor.EndEdit(cancel);
  529.         }
  530.         public int SelectionStart { get { return this.editor.SelectionStart; } }
  531.         public int SelectionLength { get { return this.editor.SelectionLength; } }
  532.         #endregion
  533.         void OnCommitEdit(object sender, TextEditorEventArgs args) {
  534.             TreeNode sel = this.SelectedNode;
  535.             if (sel != null && this.IsEditing) {
  536.                 //string text = sel.Label;
  537.                 bool cancel = args.Cancelled;
  538.                 if (this.AfterLabelEdit != null) {
  539.                     NodeLabelEditEventArgs a = new NodeLabelEditEventArgs(sel, args.Text);
  540.                     a.CancelEdit = cancel;
  541.                     this.AfterLabelEdit(this, a);
  542.                     cancel = args.Cancelled = a.CancelEdit;
  543.                 }
  544.                 if (!cancel) {
  545.                     sel.Label = args.Text;
  546.                     // [chris] this breaks the find dialog...
  547.                     //this.Focus();
  548.                 }
  549.                 InvalidateLayout(); // LabelBounds needs recalculating.
  550.                 InvalidateNode(sel);
  551.             }
  552.         }
  553.         void ClearSelection() {
  554.             EndEdit(true);
  555.             EndEdit(false);
  556.             this.focus = null;
  557.             foreach (TreeNode node in selection) {
  558.                 InvalidateNode(node);
  559.             }
  560.             selection.Clear();
  561.         }
  562.         void SetFocus(TreeNode node) {
  563.             if (this.focus != node) {
  564.                 InvalidateNode(this.focus);
  565.                 this.focus = node;
  566.                 InvalidateNode(node);
  567.                 EnsureVisible(node);
  568.             }
  569.         }
  570.         public static void EnsureVisible(TreeNode node) {
  571.             TreeNode p = node.Parent;
  572.             while (p != null) {
  573.                 if (!p.IsExpanded) {
  574.                     p.Expand();
  575.                 }
  576.                 p = p.Parent;
  577.             }
  578.         }
  579.         public void InvalidateNode(TreeNode node) {
  580.             if (node != null) {
  581.                 Rectangle r = new Rectangle(0, node.LabelBounds.Top, this.Width, this.ItemHeight);
  582.                 r.Offset(this.scrollPosition);
  583.                 Invalidate(r);
  584.             }
  585.         }
  586.         public TreeNode[] GetSelectedNodes() {
  587.             return (TreeNode[])selection.ToArray(typeof(TreeNode));
  588.         }
  589.         public void SetSelectedNodes(TreeNode[] value) {
  590.             ClearSelection();
  591.             if (value != null) {
  592.                 selection = new ArrayList(value);
  593.                 foreach (TreeNode node in value) {
  594.                     InvalidateNode(node);
  595.                 }
  596.             }
  597.             this.OnSelectionChanged();
  598.         }
  599.         public bool IsSelected(TreeNode node) {
  600.             return this.selection != null && this.selection.Contains(node);
  601.         }
  602.         public int ItemHeight {
  603.             get {
  604.                 return this.Font.Height;
  605.             }
  606.         }
  607.         // Dead code
  608.         //public TreeNode GetTopNode(Rectangle bounds) {
  609.         //    int y = 0;
  610.         //    return this.FindTopNode(this.nodes, bounds, ref y);
  611.         //}
  612.         public bool LabelEdit {
  613.             get { return this.editable; }
  614.             set { this.editable = value; }
  615.         }
  616.         public ImageList ImageList {
  617.             get { return this.imageList; }
  618.             set { this.imageList = value; }
  619.         }
  620.         public TreeNode FirstVisibleNode {
  621.             get {
  622.                 if (this.nodes == null) return null;
  623.                 foreach (TreeNode node in this.nodes) {
  624.                     if (node.IsVisible) {
  625.                         return node;
  626.                     }
  627.                 }
  628.                 return null;
  629.             }
  630.         }
  631.         public TreeNode LastVisibleNode {
  632.             get {
  633.                 return TreeNode.GetLastVisibleNode(this.Nodes);                
  634.             }
  635.         }
  636.         int updateDepth;
  637.         public void InvalidateLayout() {
  638.             if (updateDepth == 0) {
  639.                 this.PerformLayout();
  640.                 Invalidate();
  641.             }
  642.         }
  643.         public bool InBatchUpdate {
  644.             get { return this.updateDepth > 0; }
  645.         }
  646.         public void BeginUpdate() {
  647.             this.updateDepth++;
  648.         }
  649.         public void EndUpdate() {
  650.             this.updateDepth--;
  651.             if (updateDepth == 0) {
  652.                 TreeNode node = this.SelectedNode;
  653.                 // fix up selection & layout.
  654.                 ClearSelection();
  655.                 selection.Add(node);
  656.                 SetFocus(node);
  657.                 OnSelectionChanged();
  658.                 this.PerformLayout();
  659.                 Invalidate();
  660.             }
  661.             if (AfterBatchUpdate != null)
  662.                 AfterBatchUpdate(this, EventArgs.Empty);
  663.         }
  664.         public void ExpandAll() {
  665.             ExpandAll(this, this.Nodes);
  666.         }
  667.         public virtual void ExpandAll(TreeView view, TreeNodeCollection nodes) {
  668.             if (nodes == null || nodes.Count == 0) return;
  669.             if (view != null) view.BeginUpdate();
  670.             try {
  671.                 foreach (TreeNode n in nodes) {
  672.                     if (n.Nodes.Count > 0 && n.CanExpandAll) {
  673.                         if (!n.IsExpanded) n.Expand();
  674.                         ExpandAll(view, n.Nodes);
  675.                     }
  676.                 }
  677.             } finally {
  678.                 if (view != null) view.EndUpdate();
  679.             }
  680.         }
  681.         public void CollapseAll() {
  682.             CollapseAll(this, this.Nodes);
  683.         }
  684.         public virtual void CollapseAll(TreeView view, TreeNodeCollection nodes) {
  685.             if (nodes == null) return;
  686.             if (view != null) view.BeginUpdate();
  687.             try {
  688.                 foreach (TreeNode n in nodes) {
  689.                     if (n.IsExpanded) {
  690.                         CollapseAll(view, n.Nodes);
  691.                         n.Collapse();
  692.                     }
  693.                 }
  694.             } finally {
  695.                 if (view != null) view.EndUpdate();
  696.             }
  697.         }
  698.         public int TreeIndent {
  699.             get { return this.treeIndent; }
  700.             set { this.treeIndent = value; }
  701.         }
  702.         public Color LineColor {
  703.             get { return this.lineColor; }
  704.             set { this.lineColor = value; }
  705.         }
  706.         Pen linePen;
  707.         Pen plusPen;
  708.         Pen boxPen;
  709.         Brush backBrush;
  710.         protected override void OnPaint(PaintEventArgs e) {
  711.             //PerfTimer t = new PerfTimer();
  712.             //t.Start();
  713.             //base.OnPaint(e);
  714.             if (this.nodes == null) return;
  715.             Graphics g = e.Graphics;
  716.             //g.SmoothingMode = SmoothingMode.AntiAlias;
  717.             RectangleF clipF = g.ClipBounds;
  718.             Matrix m = g.Transform;
  719.             m.Translate(this.scrollPosition.X, this.scrollPosition.Y);
  720.             g.Transform = m;
  721.             this.linePen = new Pen(this.LineColor, 1);
  722.             this.linePen.DashStyle = DashStyle.Dot;
  723.             this.linePen.LineJoin = LineJoin.Round;
  724.             this.plusPen = new Pen(this.ForeColor);
  725.             this.plusPen.Alignment = PenAlignment.Center;
  726.             this.boxPen = new Pen(this.LineColor);
  727.             this.boxPen.Alignment = PenAlignment.Inset;
  728.             this.backBrush = new SolidBrush(this.BackColor);
  729.             Rectangle clip = new Rectangle((int)clipF.X - this.scrollPosition.X, (int)clipF.Y - this.scrollPosition.Y, (int)clipF.Width, (int)clipF.Height);
  730.             g.FillRectangle(backBrush, clip);
  731.             //Trace.WriteLine("MyTreeView: clip="+clip.ToString());
  732.             DrawNodes(g, ref clip, new LineStates(), TreeIndent, 0, this.nodes);
  733.             if (this.focus != null && !this.editor.IsEditing) {
  734.                 Rectangle r = this.focus.LabelBounds;
  735.                 if (clip.IntersectsWith(r)) {
  736.                     Pen focusPen = new Pen(Color.Black, 1);
  737.                     focusPen.DashStyle = DashStyle.Dot;
  738.                     using (focusPen) {
  739.                         g.DrawRectangle(focusPen, r.Left, r.Top, r.Width - 1, r.Height - 1);
  740.                     }
  741.                 }
  742.             }
  743.             if (dff != null) {
  744.                 dff.Draw(g);
  745.             }
  746.             linePen.Dispose();
  747.             linePen = null;
  748.             plusPen.Dispose();
  749.             plusPen = null;
  750.             boxPen.Dispose();
  751.             boxPen = null;
  752.             backBrush.Dispose();
  753.             backBrush = null;
  754.             //t.Stop();
  755.             //Trace.WriteLine("MyTreeView.OnPaint: " + t.GetDuration());
  756.         }
  757.         int DrawNodes(Graphics g, ref Rectangle clip, LineStates state, int indent, int y, TreeNodeCollection nodes) {
  758.             if (nodes == null) return y;
  759.             Font f = this.Font;
  760.             Size imgSize = GetImageSize();
  761.             int count = nodes.Count;
  762.             int pos = 0;
  763.             int h = this.ItemHeight;
  764.             //int w = this.Width;
  765.             int x = this.Margin.Left;
  766.             foreach (TreeNode node in nodes) {
  767.                 if (node.IsVisible) {
  768.                     LineState ls = LineState.None;
  769.                     if (pos == 0) ls |= LineState.First;
  770.                     if (pos + 1 == count) ls |= LineState.Last;
  771.                     state.Push(ls);
  772.                     //Rectangle bounds = new Rectangle(0, y, w, h);                    
  773.                     bool visible = (y + h) >= clip.Top && y <= clip.Bottom; // clip.IntersectsWith(bounds);
  774.                     if (visible) {
  775.                         int index = node.ImageIndex;
  776.                         Image img = index < 0 ? null : this.imageList.Images[index];
  777.                         bool isSelected = this.IsSelected(node);
  778.                         node.Draw(g, f, linePen, state, h, indent, x, y, ref imgSize, img, isSelected);
  779.                     }
  780.                     int y2 = y;
  781.                     y += h;
  782.                     if (node.Nodes.Count > 0) {
  783.                         int depth = state.Depth - 1;
  784.                         if (node.IsExpanded) {
  785.                             y = DrawNodes(g, ref clip, state, indent, y, node.Nodes);
  786.                             // Draw boxes on the way out.
  787.                             if (visible) {
  788.                                 DrawPlusMinus(g, x + (imgSize.Width / 2), y2, h, depth, indent, false);
  789.                             }
  790.                         } else {
  791.                             if (visible) {
  792.                                 DrawPlusMinus(g, x + (imgSize.Width / 2), y2, h, depth, indent, true);
  793.                             }
  794.                         }
  795.                     }
  796.                     state.Pop();
  797.                     if (y > clip.Bottom)
  798.                         return y; // no point continuing...
  799.                 }
  800.                 pos++;
  801.             }
  802.             return y;
  803.         }
  804.         // Plus minux box dimensions.
  805.         const int BoxWidth = 8;
  806.         const int BoxHeight = 8;
  807.         const int PlusWidth = 4;
  808.         const int PlusHeight = 4;
  809.         static Rectangle GetBoxBounds(int margin, int y, int height, int depth, int indent) {
  810.             int x = margin + (depth * indent) - (BoxWidth / 2);
  811.             y = y + (height - BoxHeight) / 2; // center it vertically.
  812.             return new Rectangle(x, y, BoxWidth, BoxHeight);
  813.         }
  814.         void DrawPlusMinus(Graphics g, int x, int y, int height, int depth, int indent, bool plus) {
  815.             // todo: scale box based on font size?
  816.             Rectangle box = GetBoxBounds(x, y, height, depth, indent);
  817.             x = box.Left;
  818.             y = box.Top;
  819.             int dx = (BoxWidth - PlusWidth) / 2;
  820.             int dy = (BoxHeight - PlusHeight) / 2;
  821.             int y2 = y + (BoxHeight / 2);
  822.             int x2 = x + (BoxWidth / 2);
  823.             g.FillRectangle(this.backBrush, box);
  824.             g.DrawRectangle(this.boxPen, box);
  825.             g.DrawLine(this.plusPen, x + dx, y2, x + dx + PlusWidth, y2);
  826.             if (plus) {
  827.                 g.DrawLine(this.plusPen, x2, y + dy, x2, y + dy + PlusHeight);
  828.             }
  829.         }
  830.         protected override void OnLayout(LayoutEventArgs levent) {
  831.             this.virtualHeight = 0;
  832.             if (this.nodes != null) {
  833.                 Graphics g = this.CreateGraphics();
  834.                 using (g) {
  835.                     int w = this.virtualWidth;
  836.                     this.virtualWidth = 0;
  837.                     this.virtualHeight = LayoutNodes(g, TreeIndent, 1, 0, this.Nodes);
  838.                     if (w != this.virtualWidth) {
  839.                         this.Parent.PerformLayout();
  840.                     }
  841.                 }
  842.             }
  843.         }
  844.         int virtualHeight;
  845.         public int VirtualHeight {
  846.             get { return virtualHeight; }
  847.             set { virtualHeight = value; }
  848.         }
  849.         int virtualWidth;
  850.         public int VirtualWidth {
  851.             get { return virtualWidth; }
  852.             set { virtualWidth = value; }
  853.         }
  854.         int LayoutNodes(Graphics g, int indent, int depth, int y, TreeNodeCollection nodes) {
  855.             Size imgSize = new Size();
  856.             if (this.imageList != null) {
  857.                 imgSize = this.imageList.ImageSize;
  858.             }
  859.             int x = this.Margin.Left;
  860.             int h = this.ItemHeight;
  861.             Font f = this.Font;
  862.             foreach (TreeNode node in nodes) {
  863.                 if (node.IsVisible) {
  864.                     node.Layout(g, f, h, x, indent, depth, y, imgSize);
  865.                     y += h;
  866.                     this.virtualWidth = Math.Max(this.virtualWidth, node.LabelBounds.Right);
  867.                     if (node.IsExpanded && node.Nodes.Count > 0) {
  868.                         y = LayoutNodes(g, indent, depth + 1, y, node.Nodes);
  869.                     }
  870.                     node.bottom = y;
  871.                 }
  872.             }
  873.             return y;
  874.         }
  875.         // Dead code!
  876.         //TreeNode FindTopNode(TreeNodeCollection nodes, Rectangle visibleBounds, ref int y) {
  877.         //    if (nodes == null) return null;
  878.         //    int h = this.ItemHeight;
  879.         //    int w = this.Width;
  880.         //    foreach (TreeNode node in this.nodes) {
  881.         //        if (node.IsVisible) {
  882.         //            Rectangle bounds = new Rectangle(0, y, w, h);
  883.         //            if (visibleBounds.IntersectsWith(bounds)) {
  884.         //                return node;
  885.         //            }
  886.         //            if (node.IsExpanded && node.Nodes.Count > 0) {
  887.         //                TreeNode child = FindTopNode(node.Nodes, visibleBounds, ref y);
  888.         //                if (child != null) return child;
  889.         //            }
  890.         //            y += h;
  891.         //        }
  892.         //    }
  893.         //    return null;
  894.         //}
  895.         Size GetImageSize() {
  896.             Size imgSize = new Size();
  897.             if (this.imageList != null) {
  898.                 imgSize = this.imageList.ImageSize;
  899.                 int imgHeight = imgSize.Height;
  900.                 int imgWidth = imgSize.Width;
  901.                 int h = this.ItemHeight;
  902.                 if (imgHeight > h) {
  903.                     // scale image down to fit.
  904.                     imgWidth = (imgWidth * h) / imgHeight;
  905.                     imgHeight = h;
  906.                     imgSize = new Size(imgWidth, imgHeight);
  907.                 }
  908.             }
  909.             return imgSize;
  910.         }
  911.         public TreeNode FindNodeAt(int x, int y) {
  912.             return FindNodeAt(this.Nodes, x, y);
  913.         }
  914.         TreeNode FindNodeAt(TreeNodeCollection nodes, int x, int y) {
  915.             if (nodes != null) {
  916.                 foreach (TreeNode n in nodes) {
  917.                     if (n.IsVisible) {
  918.                         Rectangle r = new Rectangle(0, n.LabelBounds.Top, this.Width, this.ItemHeight);
  919.                         if (r.Contains(x, y)) {
  920.                             return n;
  921.                         }
  922.                         if (n.IsExpanded && n.LabelBounds.Top <= y && n.bottom >= y) {
  923.                             TreeNode result = FindNodeAt(n.Nodes, x, y);
  924.                             if (result != null) return result;
  925.                         }
  926.                     }
  927.                 }
  928.             }
  929.             return null;
  930.         }
  931.         protected override AccessibleObject CreateAccessibilityInstance() {
  932.             if (this.acc == null) this.acc = new AccessibleTree(this);
  933.             return this.acc;
  934.         }
  935.         protected override AccessibleObject GetAccessibilityObjectById(int objectId) {
  936.             return base.GetAccessibilityObjectById(objectId);
  937.         }
  938.     }
  939.     // MyTreeNode is an abstract wrapper on the tree data that keeps track of UI state.
  940.     public abstract class TreeNode  {
  941.         TreeNode parent;
  942.         bool visible = true;
  943.         bool expanded;
  944.         bool selected;        
  945.         Rectangle labelBounds; // for hit testing
  946.         TreeView view;
  947.         internal int bottom; // Y coordinate of bottom of last grandchild.
  948.         AccessibleObject acc;
  949.         protected TreeNode() {
  950.         }
  951.         protected TreeNode(TreeNode parent) {
  952.             this.parent = parent;
  953.         }
  954.  
  955.         public int Index {
  956.             get {
  957.                 if (this.parent != null) {
  958.                     return this.parent.Nodes.GetIndex(this);
  959.                 } else if (this.view != null) {
  960.                     return this.view.Nodes.GetIndex(this);
  961.                 }
  962.                 return -1;
  963.             }
  964.         }
  965.         public AccessibleObject AccessibleObject {
  966.             get {
  967.                 if (this.acc == null) this.acc = new AccessibleNode(this);
  968.                 return this.acc;
  969.             }
  970.         }
  971.         public abstract string Label { get ; set; }
  972.         public abstract bool IsLabelEditable { get; }
  973.         public abstract TreeNodeCollection Nodes { get; }
  974.         public abstract int ImageIndex { get; }        
  975.         public abstract Color ForeColor { get; }
  976.         public abstract string Text { get; set; }
  977.         TreeNodeCollection ParentCollection {
  978.             get {
  979.                 TreeNode parent = this.parent;
  980.                 return parent == null ? (view != null ? view.Nodes : null) : parent.Nodes;
  981.             }
  982.         }
  983.         public TreeNode PrevNode {
  984.             get {
  985.                 TreeNodeCollection col = ParentCollection;
  986.                 if (col == null) return null;
  987.                 int i = col.GetIndex(this) - 1;
  988.                 if (i >= 0) {
  989.                     TreeNode n = col[i];
  990.                     return n;
  991.                 }
  992.                 return parent;
  993.             }
  994.         }
  995.         public TreeNode NextSiblingNode {
  996.             get {
  997.                 if(this.ParentCollection!=null && 
  998.                     this.ParentCollection.Count >  this.Index+1) {
  999.                     return this.ParentCollection[this.Index+1];
  1000.                 }
  1001.                 else {
  1002.                     return null;
  1003.                 }
  1004.             }
  1005.         }
  1006.         public TreeNode NextNode {
  1007.             get {
  1008.                 TreeNode child = GetFirstVisibleChild(this);
  1009.                 if (child != this) return child;
  1010.                 TreeNode parent = this.parent;
  1011.                 TreeNode node = this;
  1012.                 do {
  1013.                     TreeNodeCollection col = parent == null ? (view != null ? view.Nodes : null) : parent.Nodes;
  1014.                     int i = col.GetIndex(node) + 1;
  1015.                     int count = col.Count;
  1016.                     if (i < count) {
  1017.                         TreeNode n = col[i];
  1018.                         return n;
  1019.                     }
  1020.                     node = parent;
  1021.                     if (parent != null) parent = parent.Parent;
  1022.                 } while (node != null);
  1023.                 return null;
  1024.             }
  1025.         }
  1026.         public TreeView TreeView  {
  1027.             get {
  1028.                 return this.view;
  1029.             }
  1030.             set {
  1031.                 this.view = value;
  1032.             }
  1033.         }
  1034.         public virtual void RemoveChildren() {
  1035.             TreeView view = this.view;
  1036.             if (view != null) view.BeginUpdate();
  1037.             try {
  1038.                 List<TreeNode>  snapshot = new List<TreeNode>(this.Nodes);
  1039.                 foreach (TreeNode child in snapshot) {
  1040.                     child.Remove();
  1041.                 }
  1042.             } finally {
  1043.                 if (view != null) view.EndUpdate();
  1044.             }
  1045.         }
  1046.         public virtual void Remove() {
  1047.             TreeNode parent = this.Parent;
  1048.             TreeNodeCollection pc = this.ParentCollection;
  1049.             TreeView view = this.view;
  1050.             if (view != null) view.BeginUpdate();
  1051.             try {
  1052.                 if (view != null) {
  1053.                     view.OnRemoveNode(this);
  1054.                     this.view = null;
  1055.                 }
  1056.                 pc.Remove(this);
  1057.                 if (parent != null && parent.Nodes.Count == 0 && this.parent.IsExpanded) {
  1058.                     this.parent.Collapse();
  1059.                 }
  1060.             } finally {
  1061.                 if (view != null) view.EndUpdate();
  1062.             }
  1063.         }
  1064.         public virtual TreeNode Parent {
  1065.             get { return this.parent; }
  1066.             set { this.parent = value; }
  1067.         }
  1068.         public bool IsExpanded {
  1069.             get { return this.expanded; }
  1070.         }
  1071.         // Whether to allow this node to be expanded during expand-all.
  1072.         public virtual bool CanExpandAll {
  1073.             get { return true; }
  1074.         }
  1075.         public bool IsVisible {
  1076.             get { return this.visible; }
  1077.             set {
  1078.                 if (this.visible != value) {
  1079.                     this.visible = value;
  1080.                     if (this.view != null) this.view.InvalidateLayout();
  1081.                 }
  1082.             }
  1083.         }
  1084.         public bool Selected {
  1085.             get { return this.selected; }
  1086.             set { this.selected = value; }
  1087.         }
  1088.         public Rectangle LabelBounds {
  1089.             get { return this.labelBounds; }
  1090.             set { this.labelBounds = value; }
  1091.         }
  1092.         public void ExpandAll() {
  1093.             if (!this.IsExpanded) this.Expand();
  1094.             this.view.ExpandAll(this.view, this.Nodes);
  1095.         }
  1096.         
  1097.         public void CollapseAll() {
  1098.             this.view.CollapseAll(this.view, this.Nodes);            
  1099.             if (this.IsExpanded) {
  1100.                 this.Collapse();
  1101.             }
  1102.         }
  1103.         internal void Draw(Graphics g, Font f, Pen pen, LineStates state, int lineHeight, int indent, int x, int y, ref Size imgSize, Image img, bool selected) {
  1104.             int startX = x;
  1105.             Debug.Assert(this.view != null);
  1106.             for (int i = 0; i < state.Depth; i++) {
  1107.                 LineState ls = state[i];
  1108.                 int x2 = x + (imgSize.Width / 2);
  1109.                 int x3 = x + indent;
  1110.                 int y2 = y + lineHeight / 2;
  1111.                 int y3 = y + lineHeight;
  1112.                 bool leaf = i + 1 == state.Depth;
  1113.                 if (leaf) {
  1114.                     g.DrawLine(pen, x2, y2, x3, y2); // horizontal bar
  1115.                 }
  1116.                 if ((ls & LineState.Last) == LineState.Last) {
  1117.                     if (((ls & LineState.HasParent) == LineState.HasParent || 
  1118.                         ((ls & LineState.First) == 0 && (ls & LineState.Last) == LineState.Last)) && leaf) {
  1119.                         g.DrawLine(pen, x2, y, x2, y2); // half vertical bar connecting to parent.
  1120.                     }
  1121.                 } else if ((ls & LineState.HasParent) == LineState.HasParent || ((ls & LineState.First) == 0)) {
  1122.                     g.DrawLine(pen, x2, y, x2, y3); // full vertical bar
  1123.                 } else if ((ls & LineState.First) == LineState.First ){ // we know it's also not the last, so
  1124.                     g.DrawLine(pen, x2, y2, x2, y3); // half vertical bar connecting to next child.
  1125.                 }
  1126.                 x += indent;
  1127.             }
  1128.             // draw +/- box
  1129.             // draw node image.
  1130.             
  1131.             int imgWidth =imgSize.Width;
  1132.             int imgHeight = imgSize.Height;
  1133.             if (img != null) {
  1134.                 int iy = y;
  1135.                 if (imgHeight < lineHeight) {
  1136.                     iy += (lineHeight - imgHeight) / 2; // center it
  1137.                 }
  1138.                 Rectangle rect = new Rectangle(x, iy, imgWidth, imgHeight);
  1139.                 g.DrawImage(img, rect);
  1140.             }
  1141.             string text = this.Label;
  1142.             if (text != null && view != null) {
  1143.                 Brush brush = null;
  1144.                 if (selected && view.IsEditing) {
  1145.                     return;
  1146.                 }
  1147.                 if (selected && view.Focused) {
  1148.                     brush = Utilities.HighlightTextBrush(this.ForeColor);
  1149.                     g.FillRectangle(SystemBrushes.Highlight, this.labelBounds);
  1150.                 } else {
  1151.                     brush = new SolidBrush(this.ForeColor);
  1152.                 }
  1153.                 Layout(g, f, lineHeight, startX, indent, state.Depth, y, imgSize);
  1154.                 g.DrawString(text, f, brush, this.labelBounds.Left, this.labelBounds.Top, StringFormat.GenericTypographic);
  1155.                 brush.Dispose();
  1156.             }
  1157.         }
  1158.         public void Layout(Graphics g, Font f, int lineHeight, int x, int indent, int depth, int y, Size imgSize) {
  1159.             int width = 10;
  1160.             if (this.Label != null) {
  1161.                 SizeF s = g.MeasureString(this.Label, f);
  1162.                 width = Math.Max(width, (int)s.Width);
  1163.             }
  1164.             int gap = imgSize.Width + GetGap(indent); // small gap
  1165.             this.LabelBounds = new Rectangle(x + (indent * depth) + gap, y, width, lineHeight);
  1166.         }
  1167.         internal static int GetGap(int indent) {
  1168.             return indent / 5;
  1169.         }
  1170.         public void Toggle() {
  1171.             if (this.IsExpanded) {
  1172.                 this.Collapse();
  1173.             } else {
  1174.                 this.Expand();
  1175.             }
  1176.         }
  1177.         public TreeNode PrevVisibleNode {
  1178.             get {
  1179.                 for (TreeNode n = this.PrevNode; n != null; n = n.PrevNode) {
  1180.                     if (n.IsVisible) {
  1181.                         if (n == this.parent) return n;
  1182.                         return GetLastVisibleChild(n);
  1183.                     }
  1184.                 }
  1185.                 return null;
  1186.             }
  1187.         }
  1188.         public static TreeNode GetLastVisibleNode(TreeNodeCollection nodes) {
  1189.             if (nodes == null) return null;
  1190.             for (int i = (nodes.Count - 1); i >= 0; i--) {
  1191.                 TreeNode child = nodes[i];
  1192.                 if (child.IsVisible) {
  1193.                     if (!child.IsExpanded) return child;
  1194.                     return GetLastVisibleNode(child.Nodes);
  1195.                 }
  1196.             }
  1197.             return null;
  1198.         }
  1199.         internal TreeNode GetLastVisibleChild(TreeNode n) {
  1200.             TreeNode last = n;
  1201.             if (n.IsExpanded && n.Nodes.Count > 0) {
  1202.                 TreeNode child = GetLastVisibleNode(n.Nodes);
  1203.                 if (child != null) last = child;
  1204.             }
  1205.             return last;
  1206.         }
  1207.         internal static TreeNode GetFirstVisibleChild(TreeNode n) {
  1208.             if (n.IsExpanded && n.Nodes.Count > 0) {
  1209.                 foreach (TreeNode child in n.Nodes) {
  1210.                     if (child.IsVisible) {
  1211.                         return child;
  1212.                     }
  1213.                 }
  1214.             }
  1215.             return n;
  1216.         }
  1217.         public TreeNode NextVisibleNode {
  1218.             get {
  1219.                 for (TreeNode n = this.NextNode; n != null; n = n.NextNode) {
  1220.                     if (n.IsVisible) {
  1221.                         return n;
  1222.                     }
  1223.                 }
  1224.                 return null;
  1225.             }
  1226.         }
  1227.         public void BeginEdit() {
  1228.             Debug.Assert(this.view != null);
  1229.             if (this.view != null) {
  1230.                 this.view.SelectedNode = this;
  1231.                 this.view.BeginEdit(null);
  1232.             }
  1233.         }
  1234.         
  1235.         // dead code.
  1236.         //public void BeginEdit(string name) {
  1237.         //    Debug.Assert(this.view != null);
  1238.         //    if (this.view != null) {
  1239.         //        this.view.SelectedNode = this;
  1240.         //        this.view.BeginEdit(name);
  1241.         //    }
  1242.         //}
  1243.         public bool EndEdit(bool cancel) {
  1244.             Debug.Assert(this.view != null);
  1245.             if (this.view != null) {
  1246.                 return this.view.EndEdit(cancel);
  1247.             }
  1248.             return true;
  1249.         }
  1250.         public bool IsEditing {
  1251.             get { return this.view != null && this.view.IsEditing; }
  1252.         }
  1253.         public virtual void Expand() {
  1254.             if (this.Nodes.Count > 0) {
  1255.                 if (this.view != null) this.view.OnBeforeExpand(this);
  1256.                 this.expanded = true;
  1257.                 Invalidate();
  1258.                 if (this.view != null) this.view.OnAfterExpand(this);
  1259.             }
  1260.         }
  1261.         public virtual void Collapse() {
  1262.             if (this.expanded) {
  1263.                 if (this.view != null) this.view.OnBeforeCollapse(this);
  1264.                 this.expanded = false;
  1265.                 Invalidate();
  1266.                 if (this.view != null) this.view.OnAfterCollapse(this);
  1267.             }
  1268.         }
  1269.         public virtual void Invalidate() {
  1270.             if (this.view != null) this.view.InvalidateLayout();
  1271.         }
  1272.         public int Depth {
  1273.             get {
  1274.                 int depth = 0;
  1275.                 TreeNode parent = this.parent;
  1276.                 while (parent != null) {
  1277.                     depth++;
  1278.                     parent = parent.parent;
  1279.                 }
  1280.                 return depth;
  1281.             }
  1282.         }
  1283.         public bool Contains(TreeNode node) {
  1284.             TreeNode parent = node.Parent;
  1285.             while (parent != null) {
  1286.                 if (parent == this) return true;
  1287.                 parent = parent.Parent;
  1288.             }
  1289.             return false;
  1290.         }
  1291.         internal Rectangle LabelAndImageBounds( Size imgSize, int indent) {
  1292.             int gap = GetGap(indent);
  1293.             return new Rectangle(this.LabelBounds.Left - imgSize.Width - gap, this.LabelBounds.Top, this.LabelBounds.Width + imgSize.Width, this.LabelBounds.Height);
  1294.         }
  1295.     }
  1296.     public abstract class TreeNodeCollection : IEnumerable<TreeNode> {
  1297.         public abstract int Count { get; }
  1298.         public abstract void Add(TreeNode node);
  1299.         public abstract void Insert(int i, TreeNode node);
  1300.         public abstract void Remove(TreeNode child);
  1301.         public abstract TreeNode this[int i] { get; }
  1302.         public abstract int GetIndex(TreeNode node);
  1303.         public abstract IEnumerator<TreeNode> GetEnumerator();
  1304.         IEnumerator IEnumerable.GetEnumerator() {
  1305.             return ((IEnumerable<TreeNode>)this).GetEnumerator();
  1306.         }
  1307.     }
  1308.     public class NodeLabelEditEventArgs : EventArgs {
  1309.         TreeNode node;
  1310.         bool cancel;
  1311.         string label;
  1312.         public NodeLabelEditEventArgs(TreeNode node, string label) {
  1313.             this.node = node;
  1314.             this.label = label;
  1315.         }
  1316.         public string Label { get { return this.label; } }
  1317.         public TreeNode Node { get { return this.node; } }
  1318.         public bool CancelEdit { 
  1319.             get { return this.cancel; }
  1320.             set { this.cancel = value; }
  1321.         }
  1322.     }
  1323.     public enum TreeViewAction { None, Expanded, Collapsed }
  1324.     public class TreeViewEventArgs : EventArgs {
  1325.         TreeNode node;
  1326.         TreeViewAction action;
  1327.         public TreeViewEventArgs(TreeNode node, TreeViewAction action) {
  1328.             this.node = node;
  1329.             this.action = action;
  1330.         }
  1331.         public TreeViewAction Action { get { return this.action; } }
  1332.         public TreeNode Node { get { return this.node; } }
  1333.     }    
  1334.     class AccessibleTree : Control.ControlAccessibleObject {
  1335.         TreeView tree;
  1336.         public AccessibleTree(TreeView view) : base(view) {
  1337.             this.tree = view;
  1338.         }
  1339.         public override Rectangle Bounds {
  1340.             get {
  1341.                 return tree.RectangleToScreen(tree.ClientRectangle);
  1342.             }
  1343.         }
  1344.         public override string DefaultAction {
  1345.             get {
  1346.                 return "Toggle";
  1347.             }
  1348.         }
  1349.         public override void DoDefaultAction() {
  1350.             if (tree.SelectedNode != null) {
  1351.                 tree.SelectedNode.Toggle();
  1352.             }
  1353.         }
  1354.         public override int GetChildCount() {
  1355.             return tree.Nodes.Count;
  1356.         }
  1357.         public override AccessibleObject GetChild(int index) {
  1358.             return tree.Nodes[index].AccessibleObject;
  1359.         }
  1360.         public override AccessibleObject GetFocused() {
  1361.             return GetSelected();
  1362.         }
  1363.         public override int GetHelpTopic(out string fileName) {
  1364.             fileName = "TBD";
  1365.             return 0;
  1366.         }
  1367.         public override AccessibleObject GetSelected() {           
  1368.             if (tree.SelectedNode != null) {
  1369.                 return tree.SelectedNode.AccessibleObject;
  1370.             }
  1371.             return this;
  1372.         }
  1373.         public override AccessibleObject HitTest(int x, int y) {
  1374.             Point pt = tree.PointToClient(new Point(x, y));
  1375.             pt = tree.ApplyScrollOffset(pt);
  1376.             TreeNode node = tree.FindNodeAt(pt.X, pt.Y);
  1377.             if (node != null) {
  1378.                 return node.AccessibleObject;
  1379.             }
  1380.             return this;
  1381.         }
  1382.         public override AccessibleObject Navigate(AccessibleNavigation navdir) {
  1383.             TreeNode node = null;
  1384.             TreeNodeCollection children = tree.Nodes;
  1385.             int count = children.Count;
  1386.             switch (navdir) {
  1387.                 case AccessibleNavigation.Down:
  1388.                 case AccessibleNavigation.FirstChild:
  1389.                 case AccessibleNavigation.Left:
  1390.                     if (count > 0) node = children[0];
  1391.                     break;
  1392.                 case AccessibleNavigation.LastChild:
  1393.                     return tree.Editor.CompletionSet.AccessibilityObject;                    
  1394.                 case AccessibleNavigation.Next:
  1395.                 case AccessibleNavigation.Previous:
  1396.                 case AccessibleNavigation.Right:
  1397.                 case AccessibleNavigation.Up:
  1398.                     if (count > 0) node = children[count-1];
  1399.                     break;
  1400.             }
  1401.             if (node != null) {
  1402.                 return node.AccessibleObject;
  1403.             }
  1404.             return null;
  1405.         }
  1406.         public override AccessibleObject Parent {
  1407.             get {
  1408.                 return tree.Parent.AccessibilityObject;
  1409.             }
  1410.         }
  1411.         public override AccessibleRole Role {
  1412.             get {
  1413.                 return tree.AccessibleRole;
  1414.             }
  1415.         }
  1416.         public override void Select(AccessibleSelection flags) {
  1417.             this.tree.Focus();
  1418.         }
  1419.         public override AccessibleStates State {
  1420.             get {
  1421.                 AccessibleStates result = AccessibleStates.Focusable | AccessibleStates.Selectable |
  1422.                     AccessibleStates.Sizeable;
  1423.                 if (tree.Focused) result |= AccessibleStates.Focused;
  1424.                 if (!tree.Visible) result |= AccessibleStates.Invisible;
  1425.                 return result;
  1426.             }
  1427.         }
  1428.         public override string Value {
  1429.             get {
  1430.                 return "";
  1431.             }
  1432.             set {
  1433.                 //???
  1434.             }
  1435.         }
  1436.     }
  1437.     class AccessibleNode : AccessibleObject {
  1438.         TreeNode node;
  1439.         public AccessibleNode(TreeNode node) {
  1440.             this.node = node;
  1441.         }
  1442.         public override Rectangle Bounds {
  1443.             get {
  1444.                 Rectangle bounds = node.LabelBounds;
  1445.                 bounds.Offset(node.TreeView.ScrollPosition);
  1446.                 return node.TreeView.RectangleToScreen(bounds);
  1447.             }
  1448.         }
  1449.         public override string DefaultAction {
  1450.             get {
  1451.                 return "Toggle";
  1452.             }
  1453.         }
  1454.         public override string Description {
  1455.             get {
  1456.                 return "TreeNode";
  1457.             }
  1458.         }
  1459.         public override void DoDefaultAction() {
  1460.             node.Toggle();
  1461.         }
  1462.         public override int GetChildCount() {
  1463.             return node.Nodes.Count;
  1464.         }
  1465.         public override AccessibleObject GetChild(int index) {
  1466.             return node.Nodes[index].AccessibleObject;
  1467.         }
  1468.         public override AccessibleObject GetFocused() {
  1469.             return GetSelected();
  1470.         }
  1471.         public override int GetHelpTopic(out string fileName) {
  1472.             fileName = "TBD";
  1473.             return 0;
  1474.         }
  1475.         public override AccessibleObject GetSelected() {
  1476.             if (node.Selected) {
  1477.                 return this;
  1478.             }
  1479.             return node.TreeView.AccessibilityObject.GetSelected();
  1480.         }
  1481.         public override string Help {
  1482.             get {
  1483.                 return "TBD";
  1484.             }
  1485.         }
  1486.         public override AccessibleObject HitTest(int x, int y) {
  1487.             return node.TreeView.AccessibilityObject.HitTest(x, y);
  1488.         }
  1489.         public override string KeyboardShortcut {
  1490.             get {
  1491.                 return "???";
  1492.             }
  1493.         }
  1494.         public override string Name {
  1495.             get {
  1496.                 return node.Label;
  1497.             }
  1498.             set {
  1499.                 // hack alert - this is breaking architectural layering!
  1500.                 XmlTreeNode xnode = (XmlTreeNode)node;
  1501.                 xnode.XmlTreeView.UndoManager.Push(new EditNodeName(xnode, value));
  1502.             }
  1503.         }
  1504.         public override AccessibleObject Navigate(AccessibleNavigation navdir) {
  1505.             TreeNode result = null;
  1506.             TreeNodeCollection children = node.Nodes;
  1507.             int count = children.Count;
  1508.             switch (navdir) {
  1509.                 case AccessibleNavigation.Down:
  1510.                 case AccessibleNavigation.Next:
  1511.                     result = node.NextVisibleNode;
  1512.                     if (result == null) {
  1513.                         return node.TreeView.Editor.CompletionSet.AccessibilityObject;
  1514.                     }
  1515.                     break;
  1516.                 case AccessibleNavigation.FirstChild:
  1517.                     if (count > 0) result = children[0];
  1518.                     if (!node.IsExpanded) node.Expand();
  1519.                     break;
  1520.                 case AccessibleNavigation.Left:
  1521.                     // like the left key, this navigates up the parent hierarchy.
  1522.                     return node.Parent.AccessibleObject;
  1523.                 case AccessibleNavigation.Right:
  1524.                     // hack - this breaks architectural layering!!!
  1525.                     // but it's such a cool feature to be able to navigate via accessibility
  1526.                     // over to the NodeTextView.
  1527.                     if (node is XmlTreeNode) {
  1528.                         XmlTreeNode xn = (XmlTreeNode)node;
  1529.                         AccessibleNodeTextView av = (AccessibleNodeTextView)xn.XmlTreeView.NodeTextView.AccessibilityObject;
  1530.                         return av.Wrap(node);
  1531.                     }
  1532.                     break;
  1533.                 case AccessibleNavigation.LastChild:
  1534.                     if (count > 0) result = children[count - 1];
  1535.                     if (!node.IsExpanded) node.Expand();
  1536.                     break;
  1537.                 case AccessibleNavigation.Previous:
  1538.                 case AccessibleNavigation.Up:
  1539.                     result = node.PrevVisibleNode;
  1540.                     break;
  1541.             }
  1542.             if (result != null) {
  1543.                 return result.AccessibleObject;
  1544.             }
  1545.             return this;
  1546.         }
  1547.         public override AccessibleObject Parent {
  1548.             get {
  1549.                 if (node.Parent != null) {
  1550.                     return node.Parent.AccessibleObject;
  1551.                 } else {
  1552.                     return node.TreeView.AccessibilityObject;
  1553.                 }
  1554.             }
  1555.         }
  1556.         public override AccessibleRole Role {
  1557.             get {
  1558.                 return AccessibleRole.ListItem;
  1559.             }
  1560.         }
  1561.         public override void Select(AccessibleSelection flags) {
  1562.             node.TreeView.Focus();
  1563.             if ((flags & AccessibleSelection.TakeSelection) != 0 ||
  1564.                 (flags & AccessibleSelection.AddSelection) != 0) {
  1565.                 node.TreeView.SelectedNode = node;
  1566.             } else if ((flags & AccessibleSelection.RemoveSelection) != 0) {
  1567.                 if (node.TreeView.SelectedNode == this.node) {
  1568.                     node.TreeView.SelectedNode = null;
  1569.                 }
  1570.             }
  1571.         }
  1572.         public override AccessibleStates State {
  1573.             get {
  1574.                 AccessibleStates result = AccessibleStates.Focusable | AccessibleStates.Selectable;
  1575.                 if (node.Selected) result |= AccessibleStates.Focused | AccessibleStates.Selected;
  1576.                 if (!node.IsVisible) result |= AccessibleStates.Invisible | AccessibleStates.Collapsed ;
  1577.                 else if (node.IsExpanded) result |= AccessibleStates.Expanded;                
  1578.                 return result;
  1579.             }
  1580.         }
  1581.         public override string Value {
  1582.             get {
  1583.                 string s = node.Text;
  1584.                 if (s == null) s = "";
  1585.                 return s;
  1586.             }
  1587.             set {
  1588.                 // hack alert - this is breaking architectural layering!
  1589.                 XmlTreeNode xnode = (XmlTreeNode)node;
  1590.                 XmlTreeView xview = xnode.XmlTreeView;
  1591.                 xview.UndoManager.Push(new EditNodeValue(xview, xnode, value));
  1592.             }
  1593.         }
  1594.     }
  1595.     internal enum LineState { None = 0, First = 1, Last = 2, HasParent = 4 }
  1596.     internal class LineStates {
  1597.         LineState[] states = new LineState[10];
  1598.         int used;
  1599.         public void Push(LineState state) {
  1600.             if (used > 0) state |= LineState.HasParent;
  1601.             if (states.Length == used) {
  1602.                 LineState[] na = new LineState[used * 2];
  1603.                 Array.Copy(states, na, used);
  1604.                 states = na;
  1605.             }
  1606.             states[used++] = state;
  1607.         }
  1608.         public void Pop() {
  1609.             Debug.Assert(used > 0);
  1610.             if (used > 0) used--;
  1611.         }
  1612.         public LineState this[int depth] {
  1613.             get {
  1614.                 Debug.Assert(depth < used);
  1615.                 return (depth < used) ? states[depth] : LineState.None;
  1616.             }
  1617.         }
  1618.         public int Depth { get { return this.used; } }
  1619.     }
  1620.     public class TreeViewDropFeedback : IDisposable {
  1621.         TreeView treeView;
  1622.         TreeNode start;
  1623.         Point position;
  1624.         int indent;
  1625.         Pen pen;
  1626.         Brush brush;
  1627.         GraphicsPath shape;
  1628.         int count;
  1629.         Point lastPos;
  1630.         TreeNode toggled;
  1631.         TreeNode lastNode;
  1632.         // This indicates where the user has chosen to do the drop, either before the "before"
  1633.         // node or "after" the after node.
  1634.         TreeNode after;
  1635.         TreeNode before;
  1636.         Rectangle bounds;
  1637.         public Rectangle Bounds {
  1638.             get { return this.bounds; }
  1639.             set {
  1640.                 Invalidate();
  1641.                 this.bounds = value;
  1642.                 Invalidate();
  1643.             }
  1644.         }
  1645.         public TreeNode After {
  1646.             get { return after; }
  1647.             set { after = value; }
  1648.         }
  1649.         public TreeNode Before {
  1650.             get { return before; }
  1651.             set { before = value; }
  1652.         }
  1653.         public Point Location {
  1654.             get { return this.Bounds.Location; }
  1655.             set {
  1656.                 Invalidate();
  1657.                 this.bounds.Location = value;
  1658.                 Invalidate();
  1659.             }
  1660.         }
  1661.         bool visible;
  1662.         public bool Visible {
  1663.             get {
  1664.                 return this.visible;
  1665.             }
  1666.             set {
  1667.                 if (this.visible != value) {
  1668.                     this.visible = value;
  1669.                     Invalidate();
  1670.                 }
  1671.             }
  1672.         }
  1673.         void Invalidate() {
  1674.             if (this.treeView != null) {
  1675.                 Rectangle r = Bounds;
  1676.                 r.Offset(this.treeView.ScrollPosition);
  1677.                 this.treeView.Invalidate(r);
  1678.             }
  1679.         }
  1680.         public TreeViewDropFeedback(){
  1681.             pen = new Pen(Color.Navy);
  1682.             pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
  1683.             brush = new SolidBrush(Color.FromArgb(50, Color.Navy));
  1684.             this.Visible = false;
  1685.         }
  1686.         ~TreeViewDropFeedback() {
  1687.             Dispose(false);
  1688.         }
  1689.         public void Dispose(){
  1690.             Dispose(true);
  1691.             GC.SuppressFinalize(this);
  1692.         }
  1693.         protected virtual void Dispose(bool disposing) {
  1694.             if (pen != null){
  1695.                 pen.Dispose();
  1696.                 pen = null;
  1697.             }
  1698.             if (brush != null) {
  1699.                 brush.Dispose();
  1700.                 brush = null;
  1701.             }
  1702.             if (shape != null){
  1703.                 shape.Dispose();
  1704.                 shape = null;
  1705.             }
  1706.         }
  1707.         public void Cancel(){
  1708.             this.before = this.after = null;
  1709.             this.Visible = false;
  1710.         }
  1711.         public void Finish(bool cancelled){
  1712.             if (cancelled){
  1713.                 Cancel();
  1714.             }
  1715.             this.Visible = false;
  1716.             if (this.treeView != null) this.treeView.dff = null;
  1717.         }
  1718.         public TreeNode Item {
  1719.             get { return this.start; }
  1720.             set { this.start = value; }
  1721.         }
  1722.         public TreeView TreeView {
  1723.             get { return this.treeView; }
  1724.             set { 
  1725.                 this.treeView = value;
  1726.                 this.treeView.dff = this;
  1727.                 this.indent = value.TreeIndent - 5;
  1728.                 int height = this.treeView.ItemHeight/2;
  1729.                 int width = 0;
  1730.                 if (this.treeView.Nodes.Count>0){
  1731.                     // todo: get the size of the item being dragged (from TreeData);
  1732.                     TreeNode n = this.treeView.Nodes[0];
  1733.                     Rectangle p = n.LabelBounds;
  1734.                     width = p.Width;
  1735.                 }
  1736.                 shape = new GraphicsPath();
  1737.                 int h = height/2;
  1738.                 int w = width;
  1739.                 Graphics g = value.CreateGraphics();
  1740.                 using (g) {
  1741.                     SizeF size = g.MeasureString(start.Label, this.treeView.Font);
  1742.                     h = (int)Math.Max(h, size.Height /2);
  1743.                     w = (int)size.Width;
  1744.                 }
  1745.                 shape.AddLines(
  1746.                     new Point[] {
  1747.                                     new Point(0, h/2), 
  1748.                                     new Point(indent, h/2),
  1749.                                     new Point(indent, 0),
  1750.                                     new Point(indent + w, 0),
  1751.                                     new Point(indent + w, h),
  1752.                                     new Point(indent, h),
  1753.                                     new Point(indent, h/2)                        
  1754.                                 });
  1755.                 RectangleF r = shape.GetBounds();
  1756.                 this.Bounds = new Rectangle(0, 0, (int)r.Width+1, (int)r.Height+1);                
  1757.             }
  1758.         }
  1759.         public void ResetToggleCount() {
  1760.             count = 0;
  1761.         }
  1762.         public virtual Point Position {
  1763.             get { return this.position; }
  1764.             set { 
  1765.                 if (lastPos == value){
  1766.                     count++;
  1767.                 } else {
  1768.                     count = 0;
  1769.                 }
  1770.                 lastPos = value;
  1771.                 if (value == new Point(0,0)){
  1772.                     this.position = value;
  1773.                     this.Visible = false;
  1774.                 } else if (this.treeView.Nodes.Count>0 ){
  1775.                     Point local = this.treeView.PointToClient(value);
  1776.                     Point pos = this.treeView.ApplyScrollOffset(local);
  1777.                     TreeNode node = this.treeView.FirstVisibleNode;
  1778.                     while (node != null){
  1779.                         Rectangle bounds = node.LabelBounds;
  1780.                         CheckToggle(node, pos);
  1781.                         TreeNode next = node.NextVisibleNode;
  1782.                         int h = (int)shape.GetBounds().Height;
  1783.                         int iconWidth = this.treeView.ImageList.ImageSize.Width;
  1784.                         if (next != null){
  1785.                             CheckToggle(next, pos);
  1786.                             Rectangle nb = next.LabelBounds;
  1787.                             int dy = pos.Y - (bounds.Top+bounds.Bottom)/2;
  1788.                             int dy2 = (nb.Top+nb.Bottom)/2 - pos.Y;
  1789.                             if (dy >= 0 && dy2 >= 0 ){
  1790.                                 if (!ContainsNode(start, node) && !ContainsNode(start, next)){
  1791.                                     Point midpt;
  1792.                                     if (dy < dy2) {
  1793.                                         this.before = null;
  1794.                                         this.after = node;
  1795.                                         midpt = new Point(bounds.Left-indent-iconWidth, bounds.Bottom-h/2);
  1796.                                     } else {
  1797.                                         this.after = null;
  1798.                                         this.before = next;
  1799.                                         midpt = new Point(nb.Left-indent-iconWidth, nb.Top-h/2);
  1800.                                     }
  1801.                                     if (midpt != this.position){
  1802.                                         this.position = midpt;                                    
  1803.                                         this.Location = this.position;  
  1804.                                         if (!this.Visible)
  1805.                                             this.Visible = true;
  1806.                                     }
  1807.                                 }
  1808.                                 break;
  1809.                             }
  1810.                         } else {
  1811.                             Point midpt = new Point(bounds.Left-indent-iconWidth, bounds.Bottom-h/2);
  1812.                             if (midpt != this.position && !ContainsNode(start,node)){
  1813.                                 this.after = node;
  1814.                                 this.before = null;
  1815.                                 this.position = midpt;
  1816.                                 this.Location = this.position;
  1817.                                 if (!this.Visible)
  1818.                                     this.Visible = true;
  1819.                             }
  1820.                         }
  1821.                         node = next;
  1822.                     }                  
  1823.                 }
  1824.             }
  1825.         }
  1826.         void CheckToggle(TreeNode node, Point pos) {
  1827.             if (node.LabelBounds.Contains(pos.X, pos.Y)) {
  1828.                 if (node != toggled){
  1829.                     if (count>10 && toggled != lastNode){
  1830.                         if (node.Nodes.Count>0){
  1831.                             node.Toggle();
  1832.                         }
  1833.                         count = 0;
  1834.                         toggled = node;
  1835.                     }                    
  1836.                 }
  1837.                 if (lastNode == toggled && node != toggled) {
  1838.                     if (toggled != null && !ContainsNode(toggled, node)) 
  1839.                         toggled.Toggle(); // revert back so we don't end up expanding the whole tree!
  1840.                     toggled = null;
  1841.                 }
  1842.                 lastNode = node;
  1843.             }
  1844.         }
  1845.         bool ContainsNode(TreeNode parent, TreeNode node) {
  1846.             if (node == null) return false;
  1847.             if (parent.Nodes.Count>0){
  1848.                 foreach (TreeNode n in parent.Nodes) {
  1849.                     if (n == node)
  1850.                         return true;
  1851.                     if (ContainsNode(n, node))
  1852.                         return true;
  1853.                 }
  1854.             }
  1855.             return false;
  1856.         }
  1857.         public void Draw(Graphics g) {
  1858.             if (this.shape != null) {
  1859.                 Matrix saved = g.Transform;
  1860.                 Matrix m = saved.Clone();
  1861.                 m.Translate(this.Bounds.Left, this.Bounds.Top);
  1862.                 g.Transform = m;
  1863.                 g.FillPath(this.brush, this.shape);
  1864.                 g.DrawPath(this.pen, this.shape);
  1865.                 g.Transform = saved;
  1866.             }
  1867.         }
  1868.     }
  1869.     public delegate void TypeToFindEventHandler(object sender, string toFind);
  1870.     public class TypeToFindHandler : IDisposable {
  1871.         int start;
  1872.         Control control;
  1873.         string typedSoFar;
  1874.         int resetDelay;
  1875.         TypeToFindEventHandler handler;
  1876.         bool started;
  1877.         Cursor cursor;
  1878.         public TypeToFindEventHandler FindString {
  1879.             get { return this.handler; }
  1880.             set { this.handler = value; }
  1881.         }
  1882.         public TypeToFindHandler(Control c, int resetDelayInMilliseconds) {
  1883.             this.control = c;
  1884.             this.resetDelay = resetDelayInMilliseconds;
  1885.             this.control.KeyPress += new KeyPressEventHandler(control_KeyPress);
  1886.             this.control.KeyDown += new KeyEventHandler(control_KeyDown);
  1887.         }
  1888.         ~TypeToFindHandler() {
  1889.             Dispose(false);
  1890.         }
  1891.         public bool Started {
  1892.             get {
  1893.                 if (Cursor.Current != this.cursor) started = false;
  1894.                 return started;
  1895.             }
  1896.         }
  1897.         void control_KeyDown(object sender, KeyEventArgs e) {
  1898.             switch (e.KeyCode) {
  1899.                 case Keys.I:
  1900.                     if ((e.Modifiers & Keys.Control) != 0) {
  1901.                         StartIncrementalSearch();
  1902.                     }
  1903.                     break;
  1904.                 case Keys.Escape:
  1905.                     if (started) {
  1906.                         StopIncrementalSearch();
  1907.                         e.Handled = true;
  1908.                     }
  1909.                     break;
  1910.                 case Keys.Enter:
  1911.                 case Keys.Home:
  1912.                 case Keys.End:
  1913.                 case Keys.Up:
  1914.                 case Keys.Down:
  1915.                 case Keys.Left:
  1916.                 case Keys.Right:
  1917.                     StopIncrementalSearch();
  1918.                     break;
  1919.                 default:
  1920.                     if (started && !e.Control && !e.Alt)
  1921.                         e.Handled = true;
  1922.                     break;
  1923.             }
  1924.         }
  1925.         public Cursor Cursor {
  1926.             get {
  1927.                 if (cursor == null) {
  1928.                     using (Stream stream = this.GetType().Assembly.GetManifestResourceStream("XmlNotepad.Resources.isearch.cur")) {
  1929.                         this.cursor = new Cursor(stream);
  1930.                     }
  1931.                 }
  1932.                 return this.cursor;
  1933.             }
  1934.         }
  1935.         public void StartIncrementalSearch() {
  1936.             Cursor.Current = this.Cursor;
  1937.             started = true;
  1938.         }
  1939.         public void StopIncrementalSearch() {
  1940.             Cursor.Current = Cursors.Arrow;
  1941.             started = false;
  1942.             typedSoFar = "";
  1943.         }
  1944.         void control_KeyPress(object sender, KeyPressEventArgs e) {
  1945.             if (started) {
  1946.                 char ch = e.KeyChar;
  1947.                 if (ch < 0x20) return; // don't process control characters
  1948.                 int tick = Environment.TickCount;
  1949.                 if (tick < start || tick < this.resetDelay || start < tick - this.resetDelay) {
  1950.                     typedSoFar = ch.ToString();
  1951.                 } else {
  1952.                     typedSoFar += ch.ToString();
  1953.                 }
  1954.                 start = tick;
  1955.                 if (FindString != null) FindString(this, typedSoFar);
  1956.             }
  1957.         }
  1958.         #region IDisposable Members
  1959.         public void Dispose() {
  1960.             Dispose(true);
  1961.         }
  1962.         #endregion
  1963.         protected virtual void Dispose(bool disposing){
  1964.             if (cursor != null) {
  1965.                 cursor.Dispose();
  1966.                 cursor = null;
  1967.             }
  1968.         }
  1969.     }
  1970. }